• 跳到… +
    browser.coffee cake.coffee coffeescript.coffee command.coffee grammar.coffee helpers.coffee index.coffee lexer.coffee nodes.coffee optparse.coffee register.coffee repl.coffee rewriter.coffee scope.litcoffee sourcemap.litcoffee
  • grammar.coffee

  • §

    CoffeeScript 解析器是由 Jison 從這個語法檔案產生。Jison 是一個自下而上的解析器產生器,風格類似於 Bison,並以 JavaScript 實作。它可以辨識 LALR(1)、LR(0)、SLR(1) 和 LR(1) 類型的語法。為了建立 Jison 解析器,我們在左側列出要比對的模式,以及在右側要執行的動作(通常是建立語法樹節點)。當解析器執行時,它會從我們的代幣串流中從左到右移動代幣,並 嘗試比對 代幣序列與下列規則。當可以比對時,它會縮減成 非終端(頂端的括號名稱),然後我們從那裡繼續。

    如果你執行 cake build:parser 指令,Jison 會從我們的規則建構一個解析表,並將它儲存到 lib/parser.js 中。

  • §

    唯一的相依性是 Jison.Parser。

    {Parser} = require 'jison'
  • §

    Jison DSL

  • §
  • §

    由於我們在任何情況下都會被 Jison 包裝在一個函式中,如果我們的動作立即傳回一個值,我們可以透過移除函式包裝器並直接傳回值來最佳化。

    unwrap = /^function\s*\(\)\s*\{\s*return\s*([\s\S]*);\s*\}/
  • §

    我們方便的 Jison 語法產生 DSL,感謝 Tim Caswell。對於語法中的每個規則,我們傳遞模式定義字串、要執行的動作,以及額外的選項(如果有的話)。如果未指定動作,我們會簡單地傳遞前一個非終端的數值。

    o = (patternString, action, options) ->
      patternString = patternString.replace /\s{2,}/g, ' '
      patternCount = patternString.split(' ').length
      if action
  • §

    此程式碼區塊會在產生的 parser.js 檔案中執行字串替換,替換對 LOC 函式的呼叫以及下方列出的其他字串。

        action = if match = unwrap.exec action then match[1] else "(#{action}())"
  • §

    我們需要的所有執行時期函式都定義在 yy 上

        action = action.replace /\bnew /g, '$&yy.'
        action = action.replace /\b(?:Block\.wrap|extend)\b/g, 'yy.$&'
  • §

    傳回要新增到 parser.js 的函式字串,這些函式會新增節點可能具有的額外資料,例如註解或位置資料。位置資料會新增到傳入的第一個參數,並傳回該參數。如果參數不是節點,它只會不受影響地傳遞。

        getAddDataToNodeFunctionString = (first, last, forceUpdateLocation = yes) ->
          "yy.addDataToNode(yy, @#{first}, #{if first[0] is '$' then '$$' else '$'}#{first}, #{if last then "@#{last}, #{if last[0] is '$' then '$$' else '$'}#{last}" else 'null, null'}, #{if forceUpdateLocation then 'true' else 'false'})"
  • §

    此程式碼會使用上方定義的 yy.addDataToNode 字串替換對 LOC 的呼叫。當在語法規則中使用 LOC 函式時,會用來確保新建立的節點類別物件會指派正確的位置資料給它們。語法預設會將所有左側代幣所跨越的位置資料(例如字串 'Body TERMINATOR Line')指派給語法規則傳回的「頂層」節點(右側的函式)。但對於語法規則建立的「內部」節點類別物件,它們不會在未新增 LOC 的情況下指派正確的位置資料給它們。

  • §

    例如,考慮語法規則 'NEW_TARGET . Property',它由一個函數處理,該函數傳回 new MetaProperty LOC(1)(new IdentifierLiteral $1), LOC(3)(new Access $3)。LOC(1) 中的 1 指的是第一個代幣 (NEW_TARGET),LOC(3) 中的 3 指的是第三個代幣 (Property)。為了讓 new IdentifierLiteral 取得與原始碼中 new 相應的位置資料,我們使用 LOC(1)(new IdentifierLiteral ...) 表示「將此語法規則(NEW_TARGET)的第一個代幣的位置資料指定給此 new IdentifierLiteral」。LOC(3) 表示「將此語法規則(Property)的第三個代幣的位置資料指定給此 new Access」。

        returnsLoc = /^LOC/.test action
        action = action.replace /LOC\(([0-9]*)\)/g, getAddDataToNodeFunctionString('$1')
  • §

    呼叫具有兩個參數的 LOC,例如 LOC(2,4),會在兩個參照代幣(此範例中的第二個和第四個)上設定已產生節點的位置資料。

        action = action.replace /LOC\(([0-9]*),\s*([0-9]*)\)/g, getAddDataToNodeFunctionString('$1', '$2')
        performActionFunctionString = "$$ = #{getAddDataToNodeFunctionString(1, patternCount, not returnsLoc)}(#{action});"
      else
        performActionFunctionString = '$$ = $1;'
    
      [patternString, performActionFunctionString, options]
  • §

    語法規則

  • §
  • §

    在以下所有規則中,您會看到非終結符號的名稱作為替代比對清單的關鍵字。在每個比對的動作中,美元符號變數由 Jison 提供,作為其數字位置值的參考,因此在此規則中

    'Expression UNLESS Expression'
    

    $1 會是第一個 Expression 的值,$2 會是 UNLESS 終端的 token,而 $3 會是第二個 Expression 的值。

    grammar =
  • §

    Root 是語法樹中的頂層節點。由於我們是由下往上分析,所以所有分析都必須在此結束。

      Root: [
        o '',                                       -> new Root new Block
        o 'Body',                                   -> new Root $1
      ]
  • §

    任何陳述式和表達式的清單,由換行或分號分隔。

      Body: [
        o 'Line',                                   -> Block.wrap [$1]
        o 'Body TERMINATOR Line',                   -> $1.push $3
        o 'Body TERMINATOR'
      ]
  • §

    區塊和陳述式,組成主體中的一行。FuncDirective 是一個陳述式,但未包含在 Statement 中,因為那會導致模稜兩可的語法。

      Line: [
        o 'Expression'
        o 'ExpressionLine'
        o 'Statement'
        o 'FuncDirective'
      ]
    
      FuncDirective: [
        o 'YieldReturn'
        o 'AwaitReturn'
      ]
  • §

    純粹的陳述式,不能是表達式。

      Statement: [
        o 'Return'
        o 'STATEMENT',                              -> new StatementLiteral $1
        o 'Import'
        o 'Export'
      ]
  • §

    我們語言中所有不同類型的表達式。CoffeeScript 的基本單位是 Expression – 任何可以是表達式的事物都是一個表達式。區塊用作許多其他規則的組成部分,讓它們有點循環。

      Expression: [
        o 'Value'
        o 'Code'
        o 'Operation'
        o 'Assign'
        o 'If'
        o 'Try'
        o 'While'
        o 'For'
        o 'Switch'
        o 'Class'
        o 'Throw'
        o 'Yield'
      ]
  • §

    寫在單行中的表達式,否則需要用大括號包起來:例如 a = b if do -> f a is 1、if f (a) -> a*2 then ...、for x in do (obj) -> f obj when x > 8 then f x

      ExpressionLine: [
        o 'CodeLine'
        o 'IfLine'
        o 'OperationLine'
      ]
    
      Yield: [
        o 'YIELD',                                  -> new Op $1, new Value new Literal ''
        o 'YIELD Expression',                       -> new Op $1, $2
        o 'YIELD INDENT Object OUTDENT',            -> new Op $1, $3
        o 'YIELD FROM Expression',                  -> new Op $1.concat($2), $3
      ]
  • §

    表達式的縮排區塊。請注意,Rewriter 會透過調整 token 串流,將一些後綴形式轉換成區塊給我們。

      Block: [
        o 'INDENT OUTDENT',                         -> new Block
        o 'INDENT Body OUTDENT',                    -> $2
      ]
    
      Identifier: [
        o 'IDENTIFIER',                             -> new IdentifierLiteral $1
        o 'JSX_TAG',                                -> new JSXTag $1.toString(),
                                                         tagNameLocationData:                  $1.tagNameToken[2]
                                                         closingTagOpeningBracketLocationData: $1.closingTagOpeningBracketToken?[2]
                                                         closingTagSlashLocationData:          $1.closingTagSlashToken?[2]
                                                         closingTagNameLocationData:           $1.closingTagNameToken?[2]
                                                         closingTagClosingBracketLocationData: $1.closingTagClosingBracketToken?[2]
      ]
    
      Property: [
        o 'PROPERTY',                               -> new PropertyName $1.toString()
      ]
  • §

    字母數字與其他 Literal 比對器分開,因為它們也可以作為物件文字中的鍵值。

      AlphaNumeric: [
        o 'NUMBER',                                 -> new NumberLiteral $1.toString(), parsedValue: $1.parsedValue
        o 'String'
      ]
    
      String: [
        o 'STRING', ->
          new StringLiteral(
            $1.slice 1, -1 # strip artificial quotes and unwrap to primitive string
            quote:        $1.quote
            initialChunk: $1.initialChunk
            finalChunk:   $1.finalChunk
            indent:       $1.indent
            double:       $1.double
            heregex:      $1.heregex
          )
        o 'STRING_START Interpolations STRING_END', -> new StringWithInterpolations Block.wrap($2), quote: $1.quote, startQuote: LOC(1)(new Literal $1.toString())
      ]
    
      Interpolations: [
        o 'InterpolationChunk',                     -> [$1]
        o 'Interpolations InterpolationChunk',      -> $1.concat $2
      ]
    
      InterpolationChunk: [
        o 'INTERPOLATION_START Body INTERPOLATION_END',                -> new Interpolation $2
        o 'INTERPOLATION_START INDENT Body OUTDENT INTERPOLATION_END', -> new Interpolation $3
        o 'INTERPOLATION_START INTERPOLATION_END',                     -> new Interpolation
        o 'String',                                                    -> $1
      ]
  • §

    此處和其他地方的 .toString() 呼叫是用於將 String 物件轉換回原始字串,因為我們已經擷取了額外的屬性

      Regex: [
        o 'REGEX',                                  -> new RegexLiteral $1.toString(), delimiter: $1.delimiter, heregexCommentTokens: $1.heregexCommentTokens
        o 'REGEX_START Invocation REGEX_END',       -> new RegexWithInterpolations $2, heregexCommentTokens: $3.heregexCommentTokens
      ]
  • §

    我們所有的立即值。一般來說,這些值可以直接傳遞並列印到 JavaScript。

      Literal: [
        o 'AlphaNumeric'
        o 'JS',                                     -> new PassthroughLiteral $1.toString(), here: $1.here, generated: $1.generated
        o 'Regex'
        o 'UNDEFINED',                              -> new UndefinedLiteral $1
        o 'NULL',                                   -> new NullLiteral $1
        o 'BOOL',                                   -> new BooleanLiteral $1.toString(), originalValue: $1.original
        o 'INFINITY',                               -> new InfinityLiteral $1.toString(), originalValue: $1.original
        o 'NAN',                                    -> new NaNLiteral $1
      ]
  • §

    將變數、屬性或索引指派給值。

      Assign: [
        o 'Assignable = Expression',                -> new Assign $1, $3
        o 'Assignable = TERMINATOR Expression',     -> new Assign $1, $4
        o 'Assignable = INDENT Expression OUTDENT', -> new Assign $1, $4
      ]
  • §

    在物件文字中發生指派時。與一般 指派 的差異在於,這些允許數字和字串作為鍵。

      AssignObj: [
        o 'ObjAssignable',                          -> new Value $1
        o 'ObjRestValue'
        o 'ObjAssignable : Expression',             -> new Assign LOC(1)(new Value $1), $3, 'object',
                                                                  operatorToken: LOC(2)(new Literal $2)
        o 'ObjAssignable :
           INDENT Expression OUTDENT',              -> new Assign LOC(1)(new Value $1), $4, 'object',
                                                                  operatorToken: LOC(2)(new Literal $2)
        o 'SimpleObjAssignable = Expression',       -> new Assign LOC(1)(new Value $1), $3, null,
                                                                  operatorToken: LOC(2)(new Literal $2)
        o 'SimpleObjAssignable =
           INDENT Expression OUTDENT',              -> new Assign LOC(1)(new Value $1), $4, null,
                                                                  operatorToken: LOC(2)(new Literal $2)
      ]
    
      SimpleObjAssignable: [
        o 'Identifier'
        o 'Property'
        o 'ThisProperty'
      ]
    
      ObjAssignable: [
        o 'SimpleObjAssignable'
        o '[ Expression ]',          -> new Value new ComputedPropertyName $2
        o '@ [ Expression ]',        -> new Value LOC(1)(new ThisLiteral $1), [LOC(3)(new ComputedPropertyName($3))], 'this'
        o 'AlphaNumeric'
      ]
  • §

    物件文字散佈屬性。

      ObjRestValue: [
        o 'SimpleObjAssignable ...', -> new Splat new Value $1
        o '... SimpleObjAssignable', -> new Splat new Value($2), postfix: no
        o 'ObjSpreadExpr ...',       -> new Splat $1
        o '... ObjSpreadExpr',       -> new Splat $2, postfix: no
      ]
    
      ObjSpreadExpr: [
        o 'ObjSpreadIdentifier'
        o 'Object'
        o 'Parenthetical'
        o 'Super'
        o 'This'
        o 'SUPER OptFuncExist Arguments',               -> new SuperCall LOC(1)(new Super), $3, $2.soak, $1
        o 'DYNAMIC_IMPORT Arguments',                   -> new DynamicImportCall LOC(1)(new DynamicImport), $2
        o 'SimpleObjAssignable OptFuncExist Arguments', -> new Call (new Value $1), $3, $2.soak
        o 'ObjSpreadExpr OptFuncExist Arguments',       -> new Call $1, $3, $2.soak
      ]
    
      ObjSpreadIdentifier: [
        o 'SimpleObjAssignable Accessor', -> (new Value $1).add $2
        o 'ObjSpreadExpr Accessor',       -> (new Value $1).add $2
      ]
  • §

    從函式主體傳回的陳述式。

      Return: [
        o 'RETURN Expression',                      -> new Return $2
        o 'RETURN INDENT Object OUTDENT',           -> new Return new Value $3
        o 'RETURN',                                 -> new Return
      ]
    
      YieldReturn: [
        o 'YIELD RETURN Expression',                -> new YieldReturn $3,   returnKeyword: LOC(2)(new Literal $2)
        o 'YIELD RETURN',                           -> new YieldReturn null, returnKeyword: LOC(2)(new Literal $2)
      ]
    
      AwaitReturn: [
        o 'AWAIT RETURN Expression',                -> new AwaitReturn $3,   returnKeyword: LOC(2)(new Literal $2)
        o 'AWAIT RETURN',                           -> new AwaitReturn null, returnKeyword: LOC(2)(new Literal $2)
      ]
  • §

    程式碼 節點是函式文字。它是由帶有函式箭頭的縮排 區塊 定義的,並帶有選用的參數清單。

      Code: [
        o 'PARAM_START ParamList PARAM_END FuncGlyph Block', -> new Code $2, $5, $4, LOC(1)(new Literal $1)
        o 'FuncGlyph Block',                                 -> new Code [], $2, $1
      ]
  • §

    程式碼行是 程式碼 節點,其中 行 取代了縮排的 區塊。

      CodeLine: [
        o 'PARAM_START ParamList PARAM_END FuncGlyph Line', -> new Code $2, LOC(5)(Block.wrap [$5]), $4,
                                                                  LOC(1)(new Literal $1)
        o 'FuncGlyph Line',                                 -> new Code [], LOC(2)(Block.wrap [$2]), $1
      ]
  • §

    CoffeeScript 有兩個不同的函式符號。-> 用於一般函式,而 => 用於繫結到 this 的目前值的函式。

      FuncGlyph: [
        o '->',                                     -> new FuncGlyph $1
        o '=>',                                     -> new FuncGlyph $1
      ]
  • §

    一個選用的尾隨逗號。

      OptComma: [
        o ''
        o ','
      ]
  • §

    函式接受的參數清單可以是任何長度。

      ParamList: [
        o '',                                       -> []
        o 'Param',                                  -> [$1]
        o 'ParamList , Param',                      -> $1.concat $3
        o 'ParamList OptComma TERMINATOR Param',    -> $1.concat $4
        o 'ParamList OptComma INDENT ParamList OptComma OUTDENT', -> $1.concat $4
      ]
  • §

    函式定義中的單一參數可以是一般的,也可以是吸收剩餘引數的 splat。

      Param: [
        o 'ParamVar',                               -> new Param $1
        o 'ParamVar ...',                           -> new Param $1, null, on
        o '... ParamVar',                           -> new Param $2, null, postfix: no
        o 'ParamVar = Expression',                  -> new Param $1, $3
        o '...',                                    -> new Expansion
      ]
  • §

    函式參數

      ParamVar: [
        o 'Identifier'
        o 'ThisProperty'
        o 'Array'
        o 'Object'
      ]
  • §

    出現在參數清單之外的 splat。

      Splat: [
        o 'Expression ...',                         -> new Splat $1
        o '... Expression',                         -> new Splat $2, {postfix: no}
      ]
  • §

    可以指派給的變數和屬性。

      SimpleAssignable: [
        o 'Identifier',                             -> new Value $1
        o 'Value Accessor',                         -> $1.add $2
        o 'Code Accessor',                          -> new Value($1).add $2
        o 'ThisProperty'
      ]
  • §

    所有可以指派給的內容。

      Assignable: [
        o 'SimpleAssignable'
        o 'Array',                                  -> new Value $1
        o 'Object',                                 -> new Value $1
      ]
  • §

    可以視為值的內容類型 - 指派給、呼叫為函式、編入索引、命名為類別等。

      Value: [
        o 'Assignable'
        o 'Literal',                                -> new Value $1
        o 'Parenthetical',                          -> new Value $1
        o 'Range',                                  -> new Value $1
        o 'Invocation',                             -> new Value $1
        o 'DoIife',                                 -> new Value $1
        o 'This'
        o 'Super',                                  -> new Value $1
        o 'MetaProperty',                           -> new Value $1
      ]
  • §

    一個 super 為基礎的表達式,可以用作值。

      Super: [
        o 'SUPER . Property',                                      -> new Super LOC(3)(new Access $3), LOC(1)(new Literal $1)
        o 'SUPER INDEX_START Expression INDEX_END',                -> new Super LOC(3)(new Index $3),  LOC(1)(new Literal $1)
        o 'SUPER INDEX_START INDENT Expression OUTDENT INDEX_END', -> new Super LOC(4)(new Index $4),  LOC(1)(new Literal $1)
      ]
  • §

    「元屬性」存取,例如 new.target 或 import.meta,其中類似屬性的內容會在關鍵字上被參照。

      MetaProperty: [
        o 'NEW_TARGET . Property',                  -> new MetaProperty LOC(1)(new IdentifierLiteral $1), LOC(3)(new Access $3)
        o 'IMPORT_META . Property',                 -> new MetaProperty LOC(1)(new IdentifierLiteral $1), LOC(3)(new Access $3)
      ]
  • §

    一般存取器群組,依屬性、原型或陣列索引或區段存取物件。

      Accessor: [
        o '.  Property',                            -> new Access $2
        o '?. Property',                            -> new Access $2, soak: yes
        o ':: Property',                            -> [LOC(1)(new Access new PropertyName('prototype'), shorthand: yes), LOC(2)(new Access $2)]
        o '?:: Property',                           -> [LOC(1)(new Access new PropertyName('prototype'), shorthand: yes, soak: yes), LOC(2)(new Access $2)]
        o '::',                                     -> new Access new PropertyName('prototype'), shorthand: yes
        o '?::',                                    -> new Access new PropertyName('prototype'), shorthand: yes, soak: yes
        o 'Index'
      ]
  • §

    使用方括號表示法索引陣列或物件。

      Index: [
        o 'INDEX_START IndexValue INDEX_END',                -> $2
        o 'INDEX_START INDENT IndexValue OUTDENT INDEX_END', -> $3
        o 'INDEX_SOAK  Index',                               -> extend $2, soak: yes
      ]
    
      IndexValue: [
        o 'Expression',                             -> new Index $1
        o 'Slice',                                  -> new Slice $1
      ]
  • §

    在 CoffeeScript 中,物件文字只是一個指派清單。

      Object: [
        o '{ AssignList OptComma }',                -> new Obj $2, $1.generated
      ]
  • §

    物件文字中的屬性指派可以用逗號分隔,如同 JavaScript,或僅用換行符號分隔。

      AssignList: [
        o '',                                                       -> []
        o 'AssignObj',                                              -> [$1]
        o 'AssignList , AssignObj',                                 -> $1.concat $3
        o 'AssignList OptComma TERMINATOR AssignObj',               -> $1.concat $4
        o 'AssignList OptComma INDENT AssignList OptComma OUTDENT', -> $1.concat $4
      ]
  • §

    類別定義具有原型屬性指派選用主體,以及選用父類別參考。

      Class: [
        o 'CLASS',                                           -> new Class
        o 'CLASS Block',                                     -> new Class null, null, $2
        o 'CLASS EXTENDS Expression',                        -> new Class null, $3
        o 'CLASS EXTENDS Expression Block',                  -> new Class null, $3, $4
        o 'CLASS SimpleAssignable',                          -> new Class $2
        o 'CLASS SimpleAssignable Block',                    -> new Class $2, null, $3
        o 'CLASS SimpleAssignable EXTENDS Expression',       -> new Class $2, $4
        o 'CLASS SimpleAssignable EXTENDS Expression Block', -> new Class $2, $4, $5
      ]
    
      Import: [
        o 'IMPORT String',                                                                              -> new ImportDeclaration null, $2
        o 'IMPORT String ASSERT Object',                                                                -> new ImportDeclaration null, $2, $4
        o 'IMPORT ImportDefaultSpecifier FROM String',                                                  -> new ImportDeclaration new ImportClause($2, null), $4
        o 'IMPORT ImportDefaultSpecifier FROM String ASSERT Object',                                    -> new ImportDeclaration new ImportClause($2, null), $4, $6
        o 'IMPORT ImportNamespaceSpecifier FROM String',                                                -> new ImportDeclaration new ImportClause(null, $2), $4
        o 'IMPORT ImportNamespaceSpecifier FROM String ASSERT Object',                                  -> new ImportDeclaration new ImportClause(null, $2), $4, $6
        o 'IMPORT { } FROM String',                                                                     -> new ImportDeclaration new ImportClause(null, new ImportSpecifierList []), $5
        o 'IMPORT { } FROM String ASSERT Object',                                                       -> new ImportDeclaration new ImportClause(null, new ImportSpecifierList []), $5, $7
        o 'IMPORT { ImportSpecifierList OptComma } FROM String',                                        -> new ImportDeclaration new ImportClause(null, new ImportSpecifierList $3), $7
        o 'IMPORT { ImportSpecifierList OptComma } FROM String ASSERT Object',                          -> new ImportDeclaration new ImportClause(null, new ImportSpecifierList $3), $7, $9
        o 'IMPORT ImportDefaultSpecifier , ImportNamespaceSpecifier FROM String',                       -> new ImportDeclaration new ImportClause($2, $4), $6
        o 'IMPORT ImportDefaultSpecifier , ImportNamespaceSpecifier FROM String ASSERT Object',         -> new ImportDeclaration new ImportClause($2, $4), $6, $8
        o 'IMPORT ImportDefaultSpecifier , { ImportSpecifierList OptComma } FROM String',               -> new ImportDeclaration new ImportClause($2, new ImportSpecifierList $5), $9
        o 'IMPORT ImportDefaultSpecifier , { ImportSpecifierList OptComma } FROM String ASSERT Object', -> new ImportDeclaration new ImportClause($2, new ImportSpecifierList $5), $9, $11
      ]
    
      ImportSpecifierList: [
        o 'ImportSpecifier',                                                          -> [$1]
        o 'ImportSpecifierList , ImportSpecifier',                                    -> $1.concat $3
        o 'ImportSpecifierList OptComma TERMINATOR ImportSpecifier',                  -> $1.concat $4
        o 'INDENT ImportSpecifierList OptComma OUTDENT',                              -> $2
        o 'ImportSpecifierList OptComma INDENT ImportSpecifierList OptComma OUTDENT', -> $1.concat $4
      ]
    
      ImportSpecifier: [
        o 'Identifier',                             -> new ImportSpecifier $1
        o 'Identifier AS Identifier',               -> new ImportSpecifier $1, $3
        o 'DEFAULT',                                -> new ImportSpecifier LOC(1)(new DefaultLiteral $1)
        o 'DEFAULT AS Identifier',                  -> new ImportSpecifier LOC(1)(new DefaultLiteral($1)), $3
      ]
    
      ImportDefaultSpecifier: [
        o 'Identifier',                             -> new ImportDefaultSpecifier $1
      ]
    
      ImportNamespaceSpecifier: [
        o 'IMPORT_ALL AS Identifier',               -> new ImportNamespaceSpecifier new Literal($1), $3
      ]
    
      Export: [
        o 'EXPORT { }',                                                        -> new ExportNamedDeclaration new ExportSpecifierList []
        o 'EXPORT { ExportSpecifierList OptComma }',                           -> new ExportNamedDeclaration new ExportSpecifierList $3
        o 'EXPORT Class',                                                      -> new ExportNamedDeclaration $2
        o 'EXPORT Identifier = Expression',                                    -> new ExportNamedDeclaration LOC(2,4)(new Assign $2, $4, null,
                                                                                                          moduleDeclaration: 'export')
        o 'EXPORT Identifier = TERMINATOR Expression',                         -> new ExportNamedDeclaration LOC(2,5)(new Assign $2, $5, null,
                                                                                                          moduleDeclaration: 'export')
        o 'EXPORT Identifier = INDENT Expression OUTDENT',                     -> new ExportNamedDeclaration LOC(2,6)(new Assign $2, $5, null,
                                                                                                          moduleDeclaration: 'export')
        o 'EXPORT DEFAULT Expression',                                         -> new ExportDefaultDeclaration $3
        o 'EXPORT DEFAULT INDENT Object OUTDENT',                              -> new ExportDefaultDeclaration new Value $4
        o 'EXPORT EXPORT_ALL FROM String',                                     -> new ExportAllDeclaration new Literal($2), $4
        o 'EXPORT EXPORT_ALL FROM String ASSERT Object',                       -> new ExportAllDeclaration new Literal($2), $4, $6
        o 'EXPORT { } FROM String',                                            -> new ExportNamedDeclaration new ExportSpecifierList([]), $5
        o 'EXPORT { } FROM String ASSERT Object',                              -> new ExportNamedDeclaration new ExportSpecifierList([]), $5, $7
        o 'EXPORT { ExportSpecifierList OptComma } FROM String',               -> new ExportNamedDeclaration new ExportSpecifierList($3), $7
        o 'EXPORT { ExportSpecifierList OptComma } FROM String ASSERT Object', -> new ExportNamedDeclaration new ExportSpecifierList($3), $7, $9
      ]
    
      ExportSpecifierList: [
        o 'ExportSpecifier',                                                          -> [$1]
        o 'ExportSpecifierList , ExportSpecifier',                                    -> $1.concat $3
        o 'ExportSpecifierList OptComma TERMINATOR ExportSpecifier',                  -> $1.concat $4
        o 'INDENT ExportSpecifierList OptComma OUTDENT',                              -> $2
        o 'ExportSpecifierList OptComma INDENT ExportSpecifierList OptComma OUTDENT', -> $1.concat $4
      ]
    
      ExportSpecifier: [
        o 'Identifier',                             -> new ExportSpecifier $1
        o 'Identifier AS Identifier',               -> new ExportSpecifier $1, $3
        o 'Identifier AS DEFAULT',                  -> new ExportSpecifier $1, LOC(3)(new DefaultLiteral $3)
        o 'DEFAULT',                                -> new ExportSpecifier LOC(1)(new DefaultLiteral $1)
        o 'DEFAULT AS Identifier',                  -> new ExportSpecifier LOC(1)(new DefaultLiteral($1)), $3
      ]
  • §

    一般函式呼叫,或一連串的呼叫。

      Invocation: [
        o 'Value OptFuncExist String',              -> new TaggedTemplateCall $1, $3, $2.soak
        o 'Value OptFuncExist Arguments',           -> new Call $1, $3, $2.soak
        o 'SUPER OptFuncExist Arguments',           -> new SuperCall LOC(1)(new Super), $3, $2.soak, $1
        o 'DYNAMIC_IMPORT Arguments',               -> new DynamicImportCall LOC(1)(new DynamicImport), $2
      ]
  • §

    函式選用存在檢查。

      OptFuncExist: [
        o '',                                       -> soak: no
        o 'FUNC_EXIST',                             -> soak: yes
      ]
  • §

    函式呼叫的引數清單。

      Arguments: [
        o 'CALL_START CALL_END',                    -> []
        o 'CALL_START ArgList OptComma CALL_END',   -> $2.implicit = $1.generated; $2
      ]
  • §

    對目前 this 物件的參考。

      This: [
        o 'THIS',                                   -> new Value new ThisLiteral $1
        o '@',                                      -> new Value new ThisLiteral $1
      ]
  • §

    對 this 上屬性的參考。

      ThisProperty: [
        o '@ Property',                             -> new Value LOC(1)(new ThisLiteral $1), [LOC(2)(new Access($2))], 'this'
      ]
  • §

    陣列文字。

      Array: [
        o '[ ]',                                    -> new Arr []
        o '[ Elisions ]',                           -> new Arr $2
        o '[ ArgElisionList OptElisions ]',         -> new Arr [].concat $2, $3
      ]
  • §

    包含和不包含範圍點。

      RangeDots: [
        o '..',                                     -> exclusive: no
        o '...',                                    -> exclusive: yes
      ]
  • §

    CoffeeScript 範圍文字。

      Range: [
        o '[ Expression RangeDots Expression ]',      -> new Range $2, $4, if $3.exclusive then 'exclusive' else 'inclusive'
        o '[ ExpressionLine RangeDots Expression ]',  -> new Range $2, $4, if $3.exclusive then 'exclusive' else 'inclusive'
      ]
  • §

    陣列區段文字。

      Slice: [
        o 'Expression RangeDots Expression',        -> new Range $1, $3, if $2.exclusive then 'exclusive' else 'inclusive'
        o 'Expression RangeDots',                   -> new Range $1, null, if $2.exclusive then 'exclusive' else 'inclusive'
        o 'ExpressionLine RangeDots Expression',    -> new Range $1, $3, if $2.exclusive then 'exclusive' else 'inclusive'
        o 'ExpressionLine RangeDots',               -> new Range $1, null, if $2.exclusive then 'exclusive' else 'inclusive'
        o 'RangeDots Expression',                   -> new Range null, $2, if $1.exclusive then 'exclusive' else 'inclusive'
        o 'RangeDots',                              -> new Range null, null, if $1.exclusive then 'exclusive' else 'inclusive'
      ]
  • §

    ArgList 是傳遞到函式呼叫的物件清單(即逗號分隔的表達式)。換行符號也可用。

      ArgList: [
        o 'Arg',                                              -> [$1]
        o 'ArgList , Arg',                                    -> $1.concat $3
        o 'ArgList OptComma TERMINATOR Arg',                  -> $1.concat $4
        o 'INDENT ArgList OptComma OUTDENT',                  -> $2
        o 'ArgList OptComma INDENT ArgList OptComma OUTDENT', -> $1.concat $4
      ]
  • §

    有效引數為區塊或展開。

      Arg: [
        o 'Expression'
        o 'ExpressionLine'
        o 'Splat'
        o '...',                                     -> new Expansion
      ]
  • §

    ArgElisionList 是陣列文字內容的物件清單(即逗號分隔的表達式和省略)。換行符號也可用。

      ArgElisionList: [
        o 'ArgElision'
        o 'ArgElisionList , ArgElision',                                          -> $1.concat $3
        o 'ArgElisionList OptComma TERMINATOR ArgElision',                        -> $1.concat $4
        o 'INDENT ArgElisionList OptElisions OUTDENT',                            -> $2.concat $3
        o 'ArgElisionList OptElisions INDENT ArgElisionList OptElisions OUTDENT', -> $1.concat $2, $4, $5
      ]
    
      ArgElision: [
        o 'Arg',                  -> [$1]
        o 'Elisions Arg',         -> $1.concat $2
      ]
    
      OptElisions: [
        o 'OptComma',             -> []
        o ', Elisions',           -> [].concat $2
      ]
    
      Elisions: [
        o 'Elision',              -> [$1]
        o 'Elisions Elision',     -> $1.concat $2
      ]
    
      Elision: [
        o ',',                    -> new Elision
        o 'Elision TERMINATOR',   -> $1
      ]
  • §

    只要簡單的、以逗號分隔的必要引數(沒有花俏的語法)。我們需要將這個與 ArgList 分開,以便在 Switch 區塊中使用,因為在區塊中換行沒有意義。

      SimpleArgs: [
        o 'Expression'
        o 'ExpressionLine'
        o 'SimpleArgs , Expression',                -> [].concat $1, $3
        o 'SimpleArgs , ExpressionLine',            -> [].concat $1, $3
      ]
  • §

    try/catch/finally 例外處理區塊的變體。

      Try: [
        o 'TRY Block',                              -> new Try $2
        o 'TRY Block Catch',                        -> new Try $2, $3
        o 'TRY Block FINALLY Block',                -> new Try $2, null, $4, LOC(3)(new Literal $3)
        o 'TRY Block Catch FINALLY Block',          -> new Try $2, $3, $5, LOC(4)(new Literal $4)
      ]
  • §

    捕獲子句命名其錯誤並執行一段程式碼區塊。

      Catch: [
        o 'CATCH Identifier Block',                 -> new Catch $3, $2
        o 'CATCH Object Block',                     -> new Catch $3, LOC(2)(new Value($2))
        o 'CATCH Block',                            -> new Catch $2
      ]
  • §

    擲回一個例外物件。

      Throw: [
        o 'THROW Expression',                       -> new Throw $2
        o 'THROW INDENT Object OUTDENT',            -> new Throw new Value $3
      ]
  • §

    括號表達式。請注意,Parenthetical 是 Value,而不是 Expression,因此如果你需要在僅接受值的場合使用表達式,將其括在括號中永遠都能奏效。

      Parenthetical: [
        o '( Body )',                               -> new Parens $2
        o '( INDENT Body OUTDENT )',                -> new Parens $3
      ]
  • §

    while 迴圈的條件部分。

      WhileLineSource: [
        o 'WHILE ExpressionLine',                       -> new While $2
        o 'WHILE ExpressionLine WHEN ExpressionLine',   -> new While $2, guard: $4
        o 'UNTIL ExpressionLine',                       -> new While $2, invert: true
        o 'UNTIL ExpressionLine WHEN ExpressionLine',   -> new While $2, invert: true, guard: $4
      ]
    
      WhileSource: [
        o 'WHILE Expression',                       -> new While $2
        o 'WHILE Expression WHEN Expression',       -> new While $2, guard: $4
        o 'WHILE ExpressionLine WHEN Expression',   -> new While $2, guard: $4
        o 'UNTIL Expression',                       -> new While $2, invert: true
        o 'UNTIL Expression WHEN Expression',       -> new While $2, invert: true, guard: $4
        o 'UNTIL ExpressionLine WHEN Expression',   -> new While $2, invert: true, guard: $4
      ]
  • §

    while 迴圈可以是正常的,包含要執行的表達式區塊,也可以是後置的,包含單一表達式。沒有 do..while。

      While: [
        o 'WhileSource Block',                      -> $1.addBody $2
        o 'WhileLineSource Block',                  -> $1.addBody $2
        o 'Statement  WhileSource',                 -> (Object.assign $2, postfix: yes).addBody LOC(1) Block.wrap([$1])
        o 'Expression WhileSource',                 -> (Object.assign $2, postfix: yes).addBody LOC(1) Block.wrap([$1])
        o 'Loop',                                   -> $1
      ]
    
      Loop: [
        o 'LOOP Block',                             -> new While(LOC(1)(new BooleanLiteral 'true'), isLoop: yes).addBody $2
        o 'LOOP Expression',                        -> new While(LOC(1)(new BooleanLiteral 'true'), isLoop: yes).addBody LOC(2) Block.wrap [$2]
      ]
  • §

    陣列、物件和範圍理解,在最通用的層級。理解可以是正常的,包含要執行的表達式區塊,也可以是後置的,包含單一表達式。

      For: [
        o 'Statement    ForBody',  -> $2.postfix = yes; $2.addBody $1
        o 'Expression   ForBody',  -> $2.postfix = yes; $2.addBody $1
        o 'ForBody      Block',    -> $1.addBody $2
        o 'ForLineBody  Block',    -> $1.addBody $2
      ]
    
      ForBody: [
        o 'FOR Range',                -> new For [], source: (LOC(2) new Value($2))
        o 'FOR Range BY Expression',  -> new For [], source: (LOC(2) new Value($2)), step: $4
        o 'ForStart ForSource',       -> $1.addSource $2
      ]
    
      ForLineBody: [
        o 'FOR Range BY ExpressionLine',  -> new For [], source: (LOC(2) new Value($2)), step: $4
        o 'ForStart ForLineSource',       -> $1.addSource $2
      ]
    
      ForStart: [
        o 'FOR ForVariables',        -> new For [], name: $2[0], index: $2[1]
        o 'FOR AWAIT ForVariables',  ->
            [name, index] = $3
            new For [], {name, index, await: yes, awaitTag: (LOC(2) new Literal($2))}
        o 'FOR OWN ForVariables',    ->
            [name, index] = $3
            new For [], {name, index, own: yes, ownTag: (LOC(2) new Literal($2))}
      ]
  • §

    迴圈內部變數的所有可接受值的陣列。這啟用了對模式比對的支持。

      ForValue: [
        o 'Identifier'
        o 'ThisProperty'
        o 'Array',                                  -> new Value $1
        o 'Object',                                 -> new Value $1
      ]
  • §

    陣列或範圍理解有變數表示目前的元素和(選擇性的)目前索引的參考。或者,在物件理解的情況下,鍵、值。

      ForVariables: [
        o 'ForValue',                               -> [$1]
        o 'ForValue , ForValue',                    -> [$1, $3]
      ]
  • §

    理解的來源是一個陣列或物件,帶有可選的防護子句。如果是陣列理解,您也可以選擇以固定大小的增量逐步執行。

      ForSource: [
        o 'FORIN Expression',                                           -> source: $2
        o 'FOROF Expression',                                           -> source: $2, object: yes
        o 'FORIN Expression WHEN Expression',                           -> source: $2, guard: $4
        o 'FORIN ExpressionLine WHEN Expression',                       -> source: $2, guard: $4
        o 'FOROF Expression WHEN Expression',                           -> source: $2, guard: $4, object: yes
        o 'FOROF ExpressionLine WHEN Expression',                       -> source: $2, guard: $4, object: yes
        o 'FORIN Expression BY Expression',                             -> source: $2, step:  $4
        o 'FORIN ExpressionLine BY Expression',                         -> source: $2, step:  $4
        o 'FORIN Expression WHEN Expression BY Expression',             -> source: $2, guard: $4, step: $6
        o 'FORIN ExpressionLine WHEN Expression BY Expression',         -> source: $2, guard: $4, step: $6
        o 'FORIN Expression WHEN ExpressionLine BY Expression',         -> source: $2, guard: $4, step: $6
        o 'FORIN ExpressionLine WHEN ExpressionLine BY Expression',     -> source: $2, guard: $4, step: $6
        o 'FORIN Expression BY Expression WHEN Expression',             -> source: $2, step:  $4, guard: $6
        o 'FORIN ExpressionLine BY Expression WHEN Expression',         -> source: $2, step:  $4, guard: $6
        o 'FORIN Expression BY ExpressionLine WHEN Expression',         -> source: $2, step:  $4, guard: $6
        o 'FORIN ExpressionLine BY ExpressionLine WHEN Expression',     -> source: $2, step:  $4, guard: $6
        o 'FORFROM Expression',                                         -> source: $2, from: yes
        o 'FORFROM Expression WHEN Expression',                         -> source: $2, guard: $4, from: yes
        o 'FORFROM ExpressionLine WHEN Expression',                     -> source: $2, guard: $4, from: yes
      ]
    
      ForLineSource: [
        o 'FORIN ExpressionLine',                                       -> source: $2
        o 'FOROF ExpressionLine',                                       -> source: $2, object: yes
        o 'FORIN Expression WHEN ExpressionLine',                       -> source: $2, guard: $4
        o 'FORIN ExpressionLine WHEN ExpressionLine',                   -> source: $2, guard: $4
        o 'FOROF Expression WHEN ExpressionLine',                       -> source: $2, guard: $4, object: yes
        o 'FOROF ExpressionLine WHEN ExpressionLine',                   -> source: $2, guard: $4, object: yes
        o 'FORIN Expression BY ExpressionLine',                         -> source: $2, step:  $4
        o 'FORIN ExpressionLine BY ExpressionLine',                     -> source: $2, step:  $4
        o 'FORIN Expression WHEN Expression BY ExpressionLine',         -> source: $2, guard: $4, step: $6
        o 'FORIN ExpressionLine WHEN Expression BY ExpressionLine',     -> source: $2, guard: $4, step: $6
        o 'FORIN Expression WHEN ExpressionLine BY ExpressionLine',     -> source: $2, guard: $4, step: $6
        o 'FORIN ExpressionLine WHEN ExpressionLine BY ExpressionLine', -> source: $2, guard: $4, step: $6
        o 'FORIN Expression BY Expression WHEN ExpressionLine',         -> source: $2, step:  $4, guard: $6
        o 'FORIN ExpressionLine BY Expression WHEN ExpressionLine',     -> source: $2, step:  $4, guard: $6
        o 'FORIN Expression BY ExpressionLine WHEN ExpressionLine',     -> source: $2, step:  $4, guard: $6
        o 'FORIN ExpressionLine BY ExpressionLine WHEN ExpressionLine', -> source: $2, step:  $4, guard: $6
        o 'FORFROM ExpressionLine',                                     -> source: $2, from: yes
        o 'FORFROM Expression WHEN ExpressionLine',                     -> source: $2, guard: $4, from: yes
        o 'FORFROM ExpressionLine WHEN ExpressionLine',                 -> source: $2, guard: $4, from: yes
      ]
    
      Switch: [
        o 'SWITCH Expression INDENT Whens OUTDENT',                -> new Switch $2, $4
        o 'SWITCH ExpressionLine INDENT Whens OUTDENT',            -> new Switch $2, $4
        o 'SWITCH Expression INDENT Whens ELSE Block OUTDENT',     -> new Switch $2, $4, LOC(5,6) $6
        o 'SWITCH ExpressionLine INDENT Whens ELSE Block OUTDENT', -> new Switch $2, $4, LOC(5,6) $6
        o 'SWITCH INDENT Whens OUTDENT',                           -> new Switch null, $3
        o 'SWITCH INDENT Whens ELSE Block OUTDENT',                -> new Switch null, $3, LOC(4,5) $5
      ]
    
      Whens: [
        o 'When',                                   -> [$1]
        o 'Whens When',                             -> $1.concat $2
      ]
  • §

    一個單獨的 When 子句,帶有動作。

      When: [
        o 'LEADING_WHEN SimpleArgs Block',            -> new SwitchWhen $2, $3
        o 'LEADING_WHEN SimpleArgs Block TERMINATOR', -> LOC(1, 3) new SwitchWhen $2, $3
      ]
  • §

    if 最基本的形式是條件和動作。以下與 if 相關的規則會沿著這些行中斷,以避免歧義。

      IfBlock: [
        o 'IF Expression Block',                    -> new If $2, $3, type: $1
        o 'IfBlock ELSE IF Expression Block',       -> $1.addElse LOC(3,5) new If $4, $5, type: $3
      ]
  • §

    if 表達式的完整補充,包括後綴單行 if 和 unless。

      If: [
        o 'IfBlock'
        o 'IfBlock ELSE Block',                     -> $1.addElse $3
        o 'Statement  POST_IF Expression',          -> new If $3, LOC(1)(Block.wrap [$1]), type: $2, postfix: true
        o 'Expression POST_IF Expression',          -> new If $3, LOC(1)(Block.wrap [$1]), type: $2, postfix: true
      ]
    
      IfBlockLine: [
        o 'IF ExpressionLine Block',                  -> new If $2, $3, type: $1
        o 'IfBlockLine ELSE IF ExpressionLine Block', -> $1.addElse LOC(3,5) new If $4, $5, type: $3
      ]
    
      IfLine: [
        o 'IfBlockLine'
        o 'IfBlockLine ELSE Block',               -> $1.addElse $3
        o 'Statement  POST_IF ExpressionLine',    -> new If $3, LOC(1)(Block.wrap [$1]), type: $2, postfix: true
        o 'Expression POST_IF ExpressionLine',    -> new If $3, LOC(1)(Block.wrap [$1]), type: $2, postfix: true
      ]
  • §

    算術和邏輯運算子,對一個或多個運算元執行運算。它們在此按優先順序分組。實際的優先順序規則定義在頁面底部。如果我們能將這些規則中的大多數組合成單一的通用 Operand OpSymbol Operand 型別規則,會更簡短,但為了使優先順序約束成為可能,需要有單獨的規則。

      OperationLine: [
        o 'UNARY ExpressionLine',                   -> new Op $1, $2
        o 'DO ExpressionLine',                      -> new Op $1, $2
        o 'DO_IIFE CodeLine',                       -> new Op $1, $2
      ]
    
      Operation: [
        o 'UNARY Expression',                       -> new Op $1.toString(), $2, undefined, undefined, originalOperator: $1.original
        o 'DO Expression',                          -> new Op $1, $2
        o 'UNARY_MATH Expression',                  -> new Op $1, $2
        o '-     Expression',                      (-> new Op '-', $2), prec: 'UNARY_MATH'
        o '+     Expression',                      (-> new Op '+', $2), prec: 'UNARY_MATH'
    
        o 'AWAIT Expression',                       -> new Op $1, $2
        o 'AWAIT INDENT Object OUTDENT',            -> new Op $1, $3
    
        o '-- SimpleAssignable',                    -> new Op '--', $2
        o '++ SimpleAssignable',                    -> new Op '++', $2
        o 'SimpleAssignable --',                    -> new Op '--', $1, null, true
        o 'SimpleAssignable ++',                    -> new Op '++', $1, null, true
  • §

    存在運算子.

        o 'Expression ?',                           -> new Existence $1
    
        o 'Expression +  Expression',               -> new Op '+' , $1, $3
        o 'Expression -  Expression',               -> new Op '-' , $1, $3
    
        o 'Expression MATH     Expression',         -> new Op $2, $1, $3
        o 'Expression **       Expression',         -> new Op $2, $1, $3
        o 'Expression SHIFT    Expression',         -> new Op $2, $1, $3
        o 'Expression COMPARE  Expression',         -> new Op $2.toString(), $1, $3, undefined, originalOperator: $2.original
        o 'Expression &        Expression',         -> new Op $2, $1, $3
        o 'Expression ^        Expression',         -> new Op $2, $1, $3
        o 'Expression |        Expression',         -> new Op $2, $1, $3
        o 'Expression &&       Expression',         -> new Op $2.toString(), $1, $3, undefined, originalOperator: $2.original
        o 'Expression ||       Expression',         -> new Op $2.toString(), $1, $3, undefined, originalOperator: $2.original
        o 'Expression BIN?     Expression',         -> new Op $2, $1, $3
        o 'Expression RELATION Expression',         -> new Op $2.toString(), $1, $3, undefined, invertOperator: $2.invert?.original ? $2.invert
    
        o 'SimpleAssignable COMPOUND_ASSIGN
           Expression',                             -> new Assign $1, $3, $2.toString(), originalContext: $2.original
        o 'SimpleAssignable COMPOUND_ASSIGN
           INDENT Expression OUTDENT',              -> new Assign $1, $4, $2.toString(), originalContext: $2.original
        o 'SimpleAssignable COMPOUND_ASSIGN TERMINATOR
           Expression',                             -> new Assign $1, $4, $2.toString(), originalContext: $2.original
      ]
    
      DoIife: [
        o 'DO_IIFE Code',                           -> new Op $1 , $2
      ]
  • §

    優先順序

  • §
  • §

    此清單頂端的運算子優先順序高於較低位置的運算子。遵循這些規則,2 + 3 * 4 會分析為

    2 + (3 * 4)
    

    並且不

    (2 + 3) * 4
    
    operators = [
      ['right',     'DO_IIFE']
      ['left',      '.', '?.', '::', '?::']
      ['left',      'CALL_START', 'CALL_END']
      ['nonassoc',  '++', '--']
      ['left',      '?']
      ['right',     'UNARY', 'DO']
      ['right',     'AWAIT']
      ['right',     '**']
      ['right',     'UNARY_MATH']
      ['left',      'MATH']
      ['left',      '+', '-']
      ['left',      'SHIFT']
      ['left',      'RELATION']
      ['left',      'COMPARE']
      ['left',      '&']
      ['left',      '^']
      ['left',      '|']
      ['left',      '&&']
      ['left',      '||']
      ['left',      'BIN?']
      ['nonassoc',  'INDENT', 'OUTDENT']
      ['right',     'YIELD']
      ['right',     '=', ':', 'COMPOUND_ASSIGN', 'RETURN', 'THROW', 'EXTENDS']
      ['right',     'FORIN', 'FOROF', 'FORFROM', 'BY', 'WHEN']
      ['right',     'IF', 'ELSE', 'FOR', 'WHILE', 'UNTIL', 'LOOP', 'SUPER', 'CLASS', 'IMPORT', 'EXPORT', 'DYNAMIC_IMPORT']
      ['left',      'POST_IF']
    ]
  • §

    總結

  • §
  • §

    最後,現在我們有了文法和運算子,我們可以建立我們的Jison.Parser。我們透過處理所有規則,記錄所有終端符號(任何不作為上方規則名稱出現的符號)做為「代碼」。

    tokens = []
    for name, alternatives of grammar
      grammar[name] = for alt in alternatives
        for token in alt[0].split ' '
          tokens.push token unless grammar[token]
        alt[1] = "return #{alt[1]}" if name is 'Root'
        alt
  • §

    使用我們的終端代碼清單、文法規則和根的名稱初始化Parser。反轉運算子,因為 Jison 從低到高排序優先順序,而我們從高到低排序(如同 Yacc)。

    exports.parser = new Parser
      tokens      : tokens.join ' '
      bnf         : grammar
      operators   : operators.reverse()
      startSymbol : 'Root'