// Generated by CoffeeScript 2.7.0 (function() { // The CoffeeScript parser is generated by [Jison](https://github.com/zaach/jison) // from this grammar file. Jison is a bottom-up parser generator, similar in // style to [Bison](http://www.gnu.org/software/bison), implemented in JavaScript. // It can recognize [LALR(1), LR(0), SLR(1), and LR(1)](https://en.wikipedia.org/wiki/LR_grammar) // type grammars. To create the Jison parser, we list the pattern to match // on the left-hand side, and the action to take (usually the creation of syntax // tree nodes) on the right. As the parser runs, it // shifts tokens from our token stream, from left to right, and // [attempts to match](https://en.wikipedia.org/wiki/Bottom-up_parsing) // the token sequence against the rules below. When a match can be made, it // reduces into the [nonterminal](https://en.wikipedia.org/wiki/Terminal_and_nonterminal_symbols) // (the enclosing name at the top), and we proceed from there. // If you run the `cake build:parser` command, Jison constructs a parse table // from our rules and saves it into `lib/parser.js`. // The only dependency is on the **Jison.Parser**. var Parser, alt, alternatives, grammar, name, o, operators, token, tokens, unwrap; ({Parser} = require('jison')); // Jison DSL // --------- // Since we're going to be wrapped in a function by Jison in any case, if our // action immediately returns a value, we can optimize by removing the function // wrapper and just returning the value directly. unwrap = /^function\s*\(\)\s*\{\s*return\s*([\s\S]*);\s*\}/; // Our handy DSL for Jison grammar generation, thanks to // [Tim Caswell](https://github.com/creationix). For every rule in the grammar, // we pass the pattern-defining string, the action to run, and extra options, // optionally. If no action is specified, we simply pass the value of the // previous nonterminal. o = function(patternString, action, options) { var getAddDataToNodeFunctionString, match, patternCount, performActionFunctionString, returnsLoc; patternString = patternString.replace(/\s{2,}/g, ' '); patternCount = patternString.split(' ').length; if (action) { // This code block does string replacements in the generated `parser.js` // file, replacing the calls to the `LOC` function and other strings as // listed below. action = (match = unwrap.exec(action)) ? match[1] : `(${action}())`; // All runtime functions we need are defined on `yy` action = action.replace(/\bnew /g, '$&yy.'); action = action.replace(/\b(?:Block\.wrap|extend)\b/g, 'yy.$&'); // Returns strings of functions to add to `parser.js` which add extra data // that nodes may have, such as comments or location data. Location data // is added to the first parameter passed in, and the parameter is returned. // If the parameter is not a node, it will just be passed through unaffected. getAddDataToNodeFunctionString = function(first, last, forceUpdateLocation = true) { return `yy.addDataToNode(yy, @${first}, ${first[0] === '$' ? '$$' : '$'}${first}, ${last ? `@${last}, ${last[0] === '$' ? '$$' : '$'}${last}` : 'null, null'}, ${forceUpdateLocation ? 'true' : 'false'})`; }; // This code replaces the calls to `LOC` with the `yy.addDataToNode` string // defined above. The `LOC` function, when used below in the grammar rules, // is used to make sure that newly created node class objects get correct // location data assigned to them. By default, the grammar will assign the // location data spanned by *all* of the tokens on the left (e.g. a string // such as `'Body TERMINATOR Line'`) to the “top-level” node returned by // the grammar rule (the function on the right). But for “inner” node class // objects created by grammar rules, they won’t get correct location data // assigned to them without adding `LOC`. // For example, consider the grammar rule `'NEW_TARGET . Property'`, which // is handled by a function that returns // `new MetaProperty LOC(1)(new IdentifierLiteral $1), LOC(3)(new Access $3)`. // The `1` in `LOC(1)` refers to the first token (`NEW_TARGET`) and the `3` // in `LOC(3)` refers to the third token (`Property`). In order for the // `new IdentifierLiteral` to get assigned the location data corresponding // to `new` in the source code, we use // `LOC(1)(new IdentifierLiteral ...)` to mean “assign the location data of // the *first* token of this grammar rule (`NEW_TARGET`) to this // `new IdentifierLiteral`”. The `LOC(3)` means “assign the location data of // the *third* token of this grammar rule (`Property`) to this // `new Access`”. returnsLoc = /^LOC/.test(action); action = action.replace(/LOC\(([0-9]*)\)/g, getAddDataToNodeFunctionString('$1')); // A call to `LOC` with two arguments, e.g. `LOC(2,4)`, sets the location // data for the generated node on both of the referenced tokens (the second // and fourth in this example). action = action.replace(/LOC\(([0-9]*),\s*([0-9]*)\)/g, getAddDataToNodeFunctionString('$1', '$2')); performActionFunctionString = `$$ = ${getAddDataToNodeFunctionString(1, patternCount, !returnsLoc)}(${action});`; } else { performActionFunctionString = '$$ = $1;'; } return [patternString, performActionFunctionString, options]; }; // Grammatical Rules // ----------------- // In all of the rules that follow, you'll see the name of the nonterminal as // the key to a list of alternative matches. With each match's action, the // dollar-sign variables are provided by Jison as references to the value of // their numeric position, so in this rule: // 'Expression UNLESS Expression' // `$1` would be the value of the first `Expression`, `$2` would be the token // for the `UNLESS` terminal, and `$3` would be the value of the second // `Expression`. grammar = { // The **Root** is the top-level node in the syntax tree. Since we parse bottom-up, // all parsing must end here. Root: [ o('', function() { return new Root(new Block()); }), o('Body', function() { return new Root($1); }) ], // Any list of statements and expressions, separated by line breaks or semicolons. Body: [ o('Line', function() { return Block.wrap([$1]); }), o('Body TERMINATOR Line', function() { return $1.push($3); }), o('Body TERMINATOR') ], // Block and statements, which make up a line in a body. FuncDirective is a // statement, but not included in Statement because that results in an ambiguous // grammar. Line: [o('Expression'), o('ExpressionLine'), o('Statement'), o('FuncDirective')], FuncDirective: [o('YieldReturn'), o('AwaitReturn')], // Pure statements which cannot be expressions. Statement: [ o('Return'), o('STATEMENT', function() { return new StatementLiteral($1); }), o('Import'), o('Export') ], // All the different types of expressions in our language. The basic unit of // CoffeeScript is the **Expression** -- everything that can be an expression // is one. Blocks serve as the building blocks of many other rules, making // them somewhat circular. 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')], // Expressions which are written in single line and would otherwise require being // wrapped in braces: E.g `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', function() { return new Op($1, new Value(new Literal(''))); }), o('YIELD Expression', function() { return new Op($1, $2); }), o('YIELD INDENT Object OUTDENT', function() { return new Op($1, $3); }), o('YIELD FROM Expression', function() { return new Op($1.concat($2), $3); }) ], // An indented block of expressions. Note that the [Rewriter](rewriter.html) // will convert some postfix forms into blocks for us, by adjusting the // token stream. Block: [ o('INDENT OUTDENT', function() { return new Block(); }), o('INDENT Body OUTDENT', function() { return $2; }) ], Identifier: [ o('IDENTIFIER', function() { return new IdentifierLiteral($1); }), o('JSX_TAG', function() { var ref, ref1, ref2, ref3; return new JSXTag($1.toString(), { tagNameLocationData: $1.tagNameToken[2], closingTagOpeningBracketLocationData: (ref = $1.closingTagOpeningBracketToken) != null ? ref[2] : void 0, closingTagSlashLocationData: (ref1 = $1.closingTagSlashToken) != null ? ref1[2] : void 0, closingTagNameLocationData: (ref2 = $1.closingTagNameToken) != null ? ref2[2] : void 0, closingTagClosingBracketLocationData: (ref3 = $1.closingTagClosingBracketToken) != null ? ref3[2] : void 0 }); }) ], Property: [ o('PROPERTY', function() { return new PropertyName($1.toString()); }) ], // Alphanumerics are separated from the other **Literal** matchers because // they can also serve as keys in object literals. AlphaNumeric: [ o('NUMBER', function() { return new NumberLiteral($1.toString(), { parsedValue: $1.parsedValue }); }), o('String') ], String: [ o('STRING', function() { return 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', function() { return new StringWithInterpolations(Block.wrap($2), { quote: $1.quote, startQuote: LOC(1)(new Literal($1.toString())) }); }) ], Interpolations: [ o('InterpolationChunk', function() { return [$1]; }), o('Interpolations InterpolationChunk', function() { return $1.concat($2); }) ], InterpolationChunk: [ o('INTERPOLATION_START Body INTERPOLATION_END', function() { return new Interpolation($2); }), o('INTERPOLATION_START INDENT Body OUTDENT INTERPOLATION_END', function() { return new Interpolation($3); }), o('INTERPOLATION_START INTERPOLATION_END', function() { return new Interpolation(); }), o('String', function() { return $1; }) ], // The .toString() calls here and elsewhere are to convert `String` objects // back to primitive strings now that we've retrieved stowaway extra properties Regex: [ o('REGEX', function() { return new RegexLiteral($1.toString(), { delimiter: $1.delimiter, heregexCommentTokens: $1.heregexCommentTokens }); }), o('REGEX_START Invocation REGEX_END', function() { return new RegexWithInterpolations($2, { heregexCommentTokens: $3.heregexCommentTokens }); }) ], // All of our immediate values. Generally these can be passed straight // through and printed to JavaScript. Literal: [ o('AlphaNumeric'), o('JS', function() { return new PassthroughLiteral($1.toString(), { here: $1.here, generated: $1.generated }); }), o('Regex'), o('UNDEFINED', function() { return new UndefinedLiteral($1); }), o('NULL', function() { return new NullLiteral($1); }), o('BOOL', function() { return new BooleanLiteral($1.toString(), { originalValue: $1.original }); }), o('INFINITY', function() { return new InfinityLiteral($1.toString(), { originalValue: $1.original }); }), o('NAN', function() { return new NaNLiteral($1); }) ], // Assignment of a variable, property, or index to a value. Assign: [ o('Assignable = Expression', function() { return new Assign($1, $3); }), o('Assignable = TERMINATOR Expression', function() { return new Assign($1, $4); }), o('Assignable = INDENT Expression OUTDENT', function() { return new Assign($1, $4); }) ], // Assignment when it happens within an object literal. The difference from // the ordinary **Assign** is that these allow numbers and strings as keys. AssignObj: [ o('ObjAssignable', function() { return new Value($1); }), o('ObjRestValue'), o('ObjAssignable : Expression', function() { return new Assign(LOC(1)(new Value($1)), $3, 'object', { operatorToken: LOC(2)(new Literal($2)) }); }), o('ObjAssignable : INDENT Expression OUTDENT', function() { return new Assign(LOC(1)(new Value($1)), $4, 'object', { operatorToken: LOC(2)(new Literal($2)) }); }), o('SimpleObjAssignable = Expression', function() { return new Assign(LOC(1)(new Value($1)), $3, null, { operatorToken: LOC(2)(new Literal($2)) }); }), o('SimpleObjAssignable = INDENT Expression OUTDENT', function() { return 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 ]', function() { return new Value(new ComputedPropertyName($2)); }), o('@ [ Expression ]', function() { return new Value(LOC(1)(new ThisLiteral($1)), [LOC(3)(new ComputedPropertyName($3))], 'this'); }), o('AlphaNumeric') ], // Object literal spread properties. ObjRestValue: [ o('SimpleObjAssignable ...', function() { return new Splat(new Value($1)); }), o('... SimpleObjAssignable', function() { return new Splat(new Value($2), { postfix: false }); }), o('ObjSpreadExpr ...', function() { return new Splat($1); }), o('... ObjSpreadExpr', function() { return new Splat($2, { postfix: false }); }) ], ObjSpreadExpr: [ o('ObjSpreadIdentifier'), o('Object'), o('Parenthetical'), o('Super'), o('This'), o('SUPER OptFuncExist Arguments', function() { return new SuperCall(LOC(1)(new Super()), $3, $2.soak, $1); }), o('DYNAMIC_IMPORT Arguments', function() { return new DynamicImportCall(LOC(1)(new DynamicImport()), $2); }), o('SimpleObjAssignable OptFuncExist Arguments', function() { return new Call(new Value($1), $3, $2.soak); }), o('ObjSpreadExpr OptFuncExist Arguments', function() { return new Call($1, $3, $2.soak); }) ], ObjSpreadIdentifier: [ o('SimpleObjAssignable Accessor', function() { return (new Value($1)).add($2); }), o('ObjSpreadExpr Accessor', function() { return (new Value($1)).add($2); }) ], // A return statement from a function body. Return: [ o('RETURN Expression', function() { return new Return($2); }), o('RETURN INDENT Object OUTDENT', function() { return new Return(new Value($3)); }), o('RETURN', function() { return new Return(); }) ], YieldReturn: [ o('YIELD RETURN Expression', function() { return new YieldReturn($3, { returnKeyword: LOC(2)(new Literal($2)) }); }), o('YIELD RETURN', function() { return new YieldReturn(null, { returnKeyword: LOC(2)(new Literal($2)) }); }) ], AwaitReturn: [ o('AWAIT RETURN Expression', function() { return new AwaitReturn($3, { returnKeyword: LOC(2)(new Literal($2)) }); }), o('AWAIT RETURN', function() { return new AwaitReturn(null, { returnKeyword: LOC(2)(new Literal($2)) }); }) ], // The **Code** node is the function literal. It’s defined by an indented block // of **Block** preceded by a function arrow, with an optional parameter list. Code: [ o('PARAM_START ParamList PARAM_END FuncGlyph Block', function() { return new Code($2, $5, $4, LOC(1)(new Literal($1))); }), o('FuncGlyph Block', function() { return new Code([], $2, $1); }) ], // The Codeline is the **Code** node with **Line** instead of indented **Block**. CodeLine: [ o('PARAM_START ParamList PARAM_END FuncGlyph Line', function() { return new Code($2, LOC(5)(Block.wrap([$5])), $4, LOC(1)(new Literal($1))); }), o('FuncGlyph Line', function() { return new Code([], LOC(2)(Block.wrap([$2])), $1); }) ], // CoffeeScript has two different symbols for functions. `->` is for ordinary // functions, and `=>` is for functions bound to the current value of *this*. FuncGlyph: [ o('->', function() { return new FuncGlyph($1); }), o('=>', function() { return new FuncGlyph($1); }) ], // An optional, trailing comma. OptComma: [o(''), o(',')], // The list of parameters that a function accepts can be of any length. ParamList: [ o('', function() { return []; }), o('Param', function() { return [$1]; }), o('ParamList , Param', function() { return $1.concat($3); }), o('ParamList OptComma TERMINATOR Param', function() { return $1.concat($4); }), o('ParamList OptComma INDENT ParamList OptComma OUTDENT', function() { return $1.concat($4); }) ], // A single parameter in a function definition can be ordinary, or a splat // that hoovers up the remaining arguments. Param: [ o('ParamVar', function() { return new Param($1); }), o('ParamVar ...', function() { return new Param($1, null, true); }), o('... ParamVar', function() { return new Param($2, null, { postfix: false }); }), o('ParamVar = Expression', function() { return new Param($1, $3); }), o('...', function() { return new Expansion(); }) ], // Function Parameters ParamVar: [o('Identifier'), o('ThisProperty'), o('Array'), o('Object')], // A splat that occurs outside of a parameter list. Splat: [ o('Expression ...', function() { return new Splat($1); }), o('... Expression', function() { return new Splat($2, { postfix: false }); }) ], // Variables and properties that can be assigned to. SimpleAssignable: [ o('Identifier', function() { return new Value($1); }), o('Value Accessor', function() { return $1.add($2); }), o('Code Accessor', function() { return new Value($1).add($2); }), o('ThisProperty') ], // Everything that can be assigned to. Assignable: [ o('SimpleAssignable'), o('Array', function() { return new Value($1); }), o('Object', function() { return new Value($1); }) ], // The types of things that can be treated as values -- assigned to, invoked // as functions, indexed into, named as a class, etc. Value: [ o('Assignable'), o('Literal', function() { return new Value($1); }), o('Parenthetical', function() { return new Value($1); }), o('Range', function() { return new Value($1); }), o('Invocation', function() { return new Value($1); }), o('DoIife', function() { return new Value($1); }), o('This'), o('Super', function() { return new Value($1); }), o('MetaProperty', function() { return new Value($1); }) ], // A `super`-based expression that can be used as a value. Super: [ o('SUPER . Property', function() { return new Super(LOC(3)(new Access($3)), LOC(1)(new Literal($1))); }), o('SUPER INDEX_START Expression INDEX_END', function() { return new Super(LOC(3)(new Index($3)), LOC(1)(new Literal($1))); }), o('SUPER INDEX_START INDENT Expression OUTDENT INDEX_END', function() { return new Super(LOC(4)(new Index($4)), LOC(1)(new Literal($1))); }) ], // A “meta-property” access e.g. `new.target` or `import.meta`, where // something that looks like a property is referenced on a keyword. MetaProperty: [ o('NEW_TARGET . Property', function() { return new MetaProperty(LOC(1)(new IdentifierLiteral($1)), LOC(3)(new Access($3))); }), o('IMPORT_META . Property', function() { return new MetaProperty(LOC(1)(new IdentifierLiteral($1)), LOC(3)(new Access($3))); }) ], // The general group of accessors into an object, by property, by prototype // or by array index or slice. Accessor: [ o('. Property', function() { return new Access($2); }), o('?. Property', function() { return new Access($2, { soak: true }); }), o(':: Property', function() { return [ LOC(1)(new Access(new PropertyName('prototype'), { shorthand: true })), LOC(2)(new Access($2)) ]; }), o('?:: Property', function() { return [ LOC(1)(new Access(new PropertyName('prototype'), { shorthand: true, soak: true })), LOC(2)(new Access($2)) ]; }), o('::', function() { return new Access(new PropertyName('prototype'), { shorthand: true }); }), o('?::', function() { return new Access(new PropertyName('prototype'), { shorthand: true, soak: true }); }), o('Index') ], // Indexing into an object or array using bracket notation. Index: [ o('INDEX_START IndexValue INDEX_END', function() { return $2; }), o('INDEX_START INDENT IndexValue OUTDENT INDEX_END', function() { return $3; }), o('INDEX_SOAK Index', function() { return extend($2, { soak: true }); }) ], IndexValue: [ o('Expression', function() { return new Index($1); }), o('Slice', function() { return new Slice($1); }) ], // In CoffeeScript, an object literal is simply a list of assignments. Object: [ o('{ AssignList OptComma }', function() { return new Obj($2, $1.generated); }) ], // Assignment of properties within an object literal can be separated by // comma, as in JavaScript, or simply by newline. AssignList: [ o('', function() { return []; }), o('AssignObj', function() { return [$1]; }), o('AssignList , AssignObj', function() { return $1.concat($3); }), o('AssignList OptComma TERMINATOR AssignObj', function() { return $1.concat($4); }), o('AssignList OptComma INDENT AssignList OptComma OUTDENT', function() { return $1.concat($4); }) ], // Class definitions have optional bodies of prototype property assignments, // and optional references to the superclass. Class: [ o('CLASS', function() { return new Class(); }), o('CLASS Block', function() { return new Class(null, null, $2); }), o('CLASS EXTENDS Expression', function() { return new Class(null, $3); }), o('CLASS EXTENDS Expression Block', function() { return new Class(null, $3, $4); }), o('CLASS SimpleAssignable', function() { return new Class($2); }), o('CLASS SimpleAssignable Block', function() { return new Class($2, null, $3); }), o('CLASS SimpleAssignable EXTENDS Expression', function() { return new Class($2, $4); }), o('CLASS SimpleAssignable EXTENDS Expression Block', function() { return new Class($2, $4, $5); }) ], Import: [ o('IMPORT String', function() { return new ImportDeclaration(null, $2); }), o('IMPORT String ASSERT Object', function() { return new ImportDeclaration(null, $2, $4); }), o('IMPORT ImportDefaultSpecifier FROM String', function() { return new ImportDeclaration(new ImportClause($2, null), $4); }), o('IMPORT ImportDefaultSpecifier FROM String ASSERT Object', function() { return new ImportDeclaration(new ImportClause($2, null), $4, $6); }), o('IMPORT ImportNamespaceSpecifier FROM String', function() { return new ImportDeclaration(new ImportClause(null, $2), $4); }), o('IMPORT ImportNamespaceSpecifier FROM String ASSERT Object', function() { return new ImportDeclaration(new ImportClause(null, $2), $4, $6); }), o('IMPORT { } FROM String', function() { return new ImportDeclaration(new ImportClause(null, new ImportSpecifierList([])), $5); }), o('IMPORT { } FROM String ASSERT Object', function() { return new ImportDeclaration(new ImportClause(null, new ImportSpecifierList([])), $5, $7); }), o('IMPORT { ImportSpecifierList OptComma } FROM String', function() { return new ImportDeclaration(new ImportClause(null, new ImportSpecifierList($3)), $7); }), o('IMPORT { ImportSpecifierList OptComma } FROM String ASSERT Object', function() { return new ImportDeclaration(new ImportClause(null, new ImportSpecifierList($3)), $7, $9); }), o('IMPORT ImportDefaultSpecifier , ImportNamespaceSpecifier FROM String', function() { return new ImportDeclaration(new ImportClause($2, $4), $6); }), o('IMPORT ImportDefaultSpecifier , ImportNamespaceSpecifier FROM String ASSERT Object', function() { return new ImportDeclaration(new ImportClause($2, $4), $6, $8); }), o('IMPORT ImportDefaultSpecifier , { ImportSpecifierList OptComma } FROM String', function() { return new ImportDeclaration(new ImportClause($2, new ImportSpecifierList($5)), $9); }), o('IMPORT ImportDefaultSpecifier , { ImportSpecifierList OptComma } FROM String ASSERT Object', function() { return new ImportDeclaration(new ImportClause($2, new ImportSpecifierList($5)), $9, $11); }) ], ImportSpecifierList: [ o('ImportSpecifier', function() { return [$1]; }), o('ImportSpecifierList , ImportSpecifier', function() { return $1.concat($3); }), o('ImportSpecifierList OptComma TERMINATOR ImportSpecifier', function() { return $1.concat($4); }), o('INDENT ImportSpecifierList OptComma OUTDENT', function() { return $2; }), o('ImportSpecifierList OptComma INDENT ImportSpecifierList OptComma OUTDENT', function() { return $1.concat($4); }) ], ImportSpecifier: [ o('Identifier', function() { return new ImportSpecifier($1); }), o('Identifier AS Identifier', function() { return new ImportSpecifier($1, $3); }), o('DEFAULT', function() { return new ImportSpecifier(LOC(1)(new DefaultLiteral($1))); }), o('DEFAULT AS Identifier', function() { return new ImportSpecifier(LOC(1)(new DefaultLiteral($1)), $3); }) ], ImportDefaultSpecifier: [ o('Identifier', function() { return new ImportDefaultSpecifier($1); }) ], ImportNamespaceSpecifier: [ o('IMPORT_ALL AS Identifier', function() { return new ImportNamespaceSpecifier(new Literal($1), $3); }) ], Export: [ o('EXPORT { }', function() { return new ExportNamedDeclaration(new ExportSpecifierList([])); }), o('EXPORT { ExportSpecifierList OptComma }', function() { return new ExportNamedDeclaration(new ExportSpecifierList($3)); }), o('EXPORT Class', function() { return new ExportNamedDeclaration($2); }), o('EXPORT Identifier = Expression', function() { return new ExportNamedDeclaration(LOC(2, 4)(new Assign($2, $4, null, { moduleDeclaration: 'export' }))); }), o('EXPORT Identifier = TERMINATOR Expression', function() { return new ExportNamedDeclaration(LOC(2, 5)(new Assign($2, $5, null, { moduleDeclaration: 'export' }))); }), o('EXPORT Identifier = INDENT Expression OUTDENT', function() { return new ExportNamedDeclaration(LOC(2, 6)(new Assign($2, $5, null, { moduleDeclaration: 'export' }))); }), o('EXPORT DEFAULT Expression', function() { return new ExportDefaultDeclaration($3); }), o('EXPORT DEFAULT INDENT Object OUTDENT', function() { return new ExportDefaultDeclaration(new Value($4)); }), o('EXPORT EXPORT_ALL FROM String', function() { return new ExportAllDeclaration(new Literal($2), $4); }), o('EXPORT EXPORT_ALL FROM String ASSERT Object', function() { return new ExportAllDeclaration(new Literal($2), $4, $6); }), o('EXPORT { } FROM String', function() { return new ExportNamedDeclaration(new ExportSpecifierList([]), $5); }), o('EXPORT { } FROM String ASSERT Object', function() { return new ExportNamedDeclaration(new ExportSpecifierList([]), $5, $7); }), o('EXPORT { ExportSpecifierList OptComma } FROM String', function() { return new ExportNamedDeclaration(new ExportSpecifierList($3), $7); }), o('EXPORT { ExportSpecifierList OptComma } FROM String ASSERT Object', function() { return new ExportNamedDeclaration(new ExportSpecifierList($3), $7, $9); }) ], ExportSpecifierList: [ o('ExportSpecifier', function() { return [$1]; }), o('ExportSpecifierList , ExportSpecifier', function() { return $1.concat($3); }), o('ExportSpecifierList OptComma TERMINATOR ExportSpecifier', function() { return $1.concat($4); }), o('INDENT ExportSpecifierList OptComma OUTDENT', function() { return $2; }), o('ExportSpecifierList OptComma INDENT ExportSpecifierList OptComma OUTDENT', function() { return $1.concat($4); }) ], ExportSpecifier: [ o('Identifier', function() { return new ExportSpecifier($1); }), o('Identifier AS Identifier', function() { return new ExportSpecifier($1, $3); }), o('Identifier AS DEFAULT', function() { return new ExportSpecifier($1, LOC(3)(new DefaultLiteral($3))); }), o('DEFAULT', function() { return new ExportSpecifier(LOC(1)(new DefaultLiteral($1))); }), o('DEFAULT AS Identifier', function() { return new ExportSpecifier(LOC(1)(new DefaultLiteral($1)), $3); }) ], // Ordinary function invocation, or a chained series of calls. Invocation: [ o('Value OptFuncExist String', function() { return new TaggedTemplateCall($1, $3, $2.soak); }), o('Value OptFuncExist Arguments', function() { return new Call($1, $3, $2.soak); }), o('SUPER OptFuncExist Arguments', function() { return new SuperCall(LOC(1)(new Super()), $3, $2.soak, $1); }), o('DYNAMIC_IMPORT Arguments', function() { return new DynamicImportCall(LOC(1)(new DynamicImport()), $2); }) ], // An optional existence check on a function. OptFuncExist: [ o('', function() { return { soak: false }; }), o('FUNC_EXIST', function() { return { soak: true }; }) ], // The list of arguments to a function call. Arguments: [ o('CALL_START CALL_END', function() { return []; }), o('CALL_START ArgList OptComma CALL_END', function() { $2.implicit = $1.generated; return $2; }) ], // A reference to the *this* current object. This: [ o('THIS', function() { return new Value(new ThisLiteral($1)); }), o('@', function() { return new Value(new ThisLiteral($1)); }) ], // A reference to a property on *this*. ThisProperty: [ o('@ Property', function() { return new Value(LOC(1)(new ThisLiteral($1)), [LOC(2)(new Access($2))], 'this'); }) ], // The array literal. Array: [ o('[ ]', function() { return new Arr([]); }), o('[ Elisions ]', function() { return new Arr($2); }), o('[ ArgElisionList OptElisions ]', function() { return new Arr([].concat($2, $3)); }) ], // Inclusive and exclusive range dots. RangeDots: [ o('..', function() { return { exclusive: false }; }), o('...', function() { return { exclusive: true }; }) ], // The CoffeeScript range literal. Range: [ o('[ Expression RangeDots Expression ]', function() { return new Range($2, $4, $3.exclusive ? 'exclusive' : 'inclusive'); }), o('[ ExpressionLine RangeDots Expression ]', function() { return new Range($2, $4, $3.exclusive ? 'exclusive' : 'inclusive'); }) ], // Array slice literals. Slice: [ o('Expression RangeDots Expression', function() { return new Range($1, $3, $2.exclusive ? 'exclusive' : 'inclusive'); }), o('Expression RangeDots', function() { return new Range($1, null, $2.exclusive ? 'exclusive' : 'inclusive'); }), o('ExpressionLine RangeDots Expression', function() { return new Range($1, $3, $2.exclusive ? 'exclusive' : 'inclusive'); }), o('ExpressionLine RangeDots', function() { return new Range($1, null, $2.exclusive ? 'exclusive' : 'inclusive'); }), o('RangeDots Expression', function() { return new Range(null, $2, $1.exclusive ? 'exclusive' : 'inclusive'); }), o('RangeDots', function() { return new Range(null, null, $1.exclusive ? 'exclusive' : 'inclusive'); }) ], // The **ArgList** is the list of objects passed into a function call // (i.e. comma-separated expressions). Newlines work as well. ArgList: [ o('Arg', function() { return [$1]; }), o('ArgList , Arg', function() { return $1.concat($3); }), o('ArgList OptComma TERMINATOR Arg', function() { return $1.concat($4); }), o('INDENT ArgList OptComma OUTDENT', function() { return $2; }), o('ArgList OptComma INDENT ArgList OptComma OUTDENT', function() { return $1.concat($4); }) ], // Valid arguments are Blocks or Splats. Arg: [ o('Expression'), o('ExpressionLine'), o('Splat'), o('...', function() { return new Expansion(); }) ], // The **ArgElisionList** is the list of objects, contents of an array literal // (i.e. comma-separated expressions and elisions). Newlines work as well. ArgElisionList: [ o('ArgElision'), o('ArgElisionList , ArgElision', function() { return $1.concat($3); }), o('ArgElisionList OptComma TERMINATOR ArgElision', function() { return $1.concat($4); }), o('INDENT ArgElisionList OptElisions OUTDENT', function() { return $2.concat($3); }), o('ArgElisionList OptElisions INDENT ArgElisionList OptElisions OUTDENT', function() { return $1.concat($2, $4, $5); }) ], ArgElision: [ o('Arg', function() { return [$1]; }), o('Elisions Arg', function() { return $1.concat($2); }) ], OptElisions: [ o('OptComma', function() { return []; }), o(', Elisions', function() { return [].concat($2); }) ], Elisions: [ o('Elision', function() { return [$1]; }), o('Elisions Elision', function() { return $1.concat($2); }) ], Elision: [ o(',', function() { return new Elision(); }), o('Elision TERMINATOR', function() { return $1; }) ], // Just simple, comma-separated, required arguments (no fancy syntax). We need // this to be separate from the **ArgList** for use in **Switch** blocks, where // having the newlines wouldn't make sense. SimpleArgs: [ o('Expression'), o('ExpressionLine'), o('SimpleArgs , Expression', function() { return [].concat($1, $3); }), o('SimpleArgs , ExpressionLine', function() { return [].concat($1, $3); }) ], // The variants of *try/catch/finally* exception handling blocks. Try: [ o('TRY Block', function() { return new Try($2); }), o('TRY Block Catch', function() { return new Try($2, $3); }), o('TRY Block FINALLY Block', function() { return new Try($2, null, $4, LOC(3)(new Literal($3))); }), o('TRY Block Catch FINALLY Block', function() { return new Try($2, $3, $5, LOC(4)(new Literal($4))); }) ], // A catch clause names its error and runs a block of code. Catch: [ o('CATCH Identifier Block', function() { return new Catch($3, $2); }), o('CATCH Object Block', function() { return new Catch($3, LOC(2)(new Value($2))); }), o('CATCH Block', function() { return new Catch($2); }) ], // Throw an exception object. Throw: [ o('THROW Expression', function() { return new Throw($2); }), o('THROW INDENT Object OUTDENT', function() { return new Throw(new Value($3)); }) ], // Parenthetical expressions. Note that the **Parenthetical** is a **Value**, // not an **Expression**, so if you need to use an expression in a place // where only values are accepted, wrapping it in parentheses will always do // the trick. Parenthetical: [ o('( Body )', function() { return new Parens($2); }), o('( INDENT Body OUTDENT )', function() { return new Parens($3); }) ], // The condition portion of a while loop. WhileLineSource: [ o('WHILE ExpressionLine', function() { return new While($2); }), o('WHILE ExpressionLine WHEN ExpressionLine', function() { return new While($2, { guard: $4 }); }), o('UNTIL ExpressionLine', function() { return new While($2, { invert: true }); }), o('UNTIL ExpressionLine WHEN ExpressionLine', function() { return new While($2, { invert: true, guard: $4 }); }) ], WhileSource: [ o('WHILE Expression', function() { return new While($2); }), o('WHILE Expression WHEN Expression', function() { return new While($2, { guard: $4 }); }), o('WHILE ExpressionLine WHEN Expression', function() { return new While($2, { guard: $4 }); }), o('UNTIL Expression', function() { return new While($2, { invert: true }); }), o('UNTIL Expression WHEN Expression', function() { return new While($2, { invert: true, guard: $4 }); }), o('UNTIL ExpressionLine WHEN Expression', function() { return new While($2, { invert: true, guard: $4 }); }) ], // The while loop can either be normal, with a block of expressions to execute, // or postfix, with a single expression. There is no do..while. While: [ o('WhileSource Block', function() { return $1.addBody($2); }), o('WhileLineSource Block', function() { return $1.addBody($2); }), o('Statement WhileSource', function() { return (Object.assign($2, { postfix: true })).addBody(LOC(1)(Block.wrap([$1]))); }), o('Expression WhileSource', function() { return (Object.assign($2, { postfix: true })).addBody(LOC(1)(Block.wrap([$1]))); }), o('Loop', function() { return $1; }) ], Loop: [ o('LOOP Block', function() { return new While(LOC(1)(new BooleanLiteral('true')), { isLoop: true }).addBody($2); }), o('LOOP Expression', function() { return new While(LOC(1)(new BooleanLiteral('true')), { isLoop: true }).addBody(LOC(2)(Block.wrap([$2]))); }) ], // Array, object, and range comprehensions, at the most generic level. // Comprehensions can either be normal, with a block of expressions to execute, // or postfix, with a single expression. For: [ o('Statement ForBody', function() { $2.postfix = true; return $2.addBody($1); }), o('Expression ForBody', function() { $2.postfix = true; return $2.addBody($1); }), o('ForBody Block', function() { return $1.addBody($2); }), o('ForLineBody Block', function() { return $1.addBody($2); }) ], ForBody: [ o('FOR Range', function() { return new For([], { source: LOC(2)(new Value($2)) }); }), o('FOR Range BY Expression', function() { return new For([], { source: LOC(2)(new Value($2)), step: $4 }); }), o('ForStart ForSource', function() { return $1.addSource($2); }) ], ForLineBody: [ o('FOR Range BY ExpressionLine', function() { return new For([], { source: LOC(2)(new Value($2)), step: $4 }); }), o('ForStart ForLineSource', function() { return $1.addSource($2); }) ], ForStart: [ o('FOR ForVariables', function() { return new For([], { name: $2[0], index: $2[1] }); }), o('FOR AWAIT ForVariables', function() { var index, name; [name, index] = $3; return new For([], { name, index, await: true, awaitTag: LOC(2)(new Literal($2)) }); }), o('FOR OWN ForVariables', function() { var index, name; [name, index] = $3; return new For([], { name, index, own: true, ownTag: LOC(2)(new Literal($2)) }); }) ], // An array of all accepted values for a variable inside the loop. // This enables support for pattern matching. ForValue: [ o('Identifier'), o('ThisProperty'), o('Array', function() { return new Value($1); }), o('Object', function() { return new Value($1); }) ], // An array or range comprehension has variables for the current element // and (optional) reference to the current index. Or, *key, value*, in the case // of object comprehensions. ForVariables: [ o('ForValue', function() { return [$1]; }), o('ForValue , ForValue', function() { return [$1, $3]; }) ], // The source of a comprehension is an array or object with an optional guard // clause. If it’s an array comprehension, you can also choose to step through // in fixed-size increments. ForSource: [ o('FORIN Expression', function() { return { source: $2 }; }), o('FOROF Expression', function() { return { source: $2, object: true }; }), o('FORIN Expression WHEN Expression', function() { return { source: $2, guard: $4 }; }), o('FORIN ExpressionLine WHEN Expression', function() { return { source: $2, guard: $4 }; }), o('FOROF Expression WHEN Expression', function() { return { source: $2, guard: $4, object: true }; }), o('FOROF ExpressionLine WHEN Expression', function() { return { source: $2, guard: $4, object: true }; }), o('FORIN Expression BY Expression', function() { return { source: $2, step: $4 }; }), o('FORIN ExpressionLine BY Expression', function() { return { source: $2, step: $4 }; }), o('FORIN Expression WHEN Expression BY Expression', function() { return { source: $2, guard: $4, step: $6 }; }), o('FORIN ExpressionLine WHEN Expression BY Expression', function() { return { source: $2, guard: $4, step: $6 }; }), o('FORIN Expression WHEN ExpressionLine BY Expression', function() { return { source: $2, guard: $4, step: $6 }; }), o('FORIN ExpressionLine WHEN ExpressionLine BY Expression', function() { return { source: $2, guard: $4, step: $6 }; }), o('FORIN Expression BY Expression WHEN Expression', function() { return { source: $2, step: $4, guard: $6 }; }), o('FORIN ExpressionLine BY Expression WHEN Expression', function() { return { source: $2, step: $4, guard: $6 }; }), o('FORIN Expression BY ExpressionLine WHEN Expression', function() { return { source: $2, step: $4, guard: $6 }; }), o('FORIN ExpressionLine BY ExpressionLine WHEN Expression', function() { return { source: $2, step: $4, guard: $6 }; }), o('FORFROM Expression', function() { return { source: $2, from: true }; }), o('FORFROM Expression WHEN Expression', function() { return { source: $2, guard: $4, from: true }; }), o('FORFROM ExpressionLine WHEN Expression', function() { return { source: $2, guard: $4, from: true }; }) ], ForLineSource: [ o('FORIN ExpressionLine', function() { return { source: $2 }; }), o('FOROF ExpressionLine', function() { return { source: $2, object: true }; }), o('FORIN Expression WHEN ExpressionLine', function() { return { source: $2, guard: $4 }; }), o('FORIN ExpressionLine WHEN ExpressionLine', function() { return { source: $2, guard: $4 }; }), o('FOROF Expression WHEN ExpressionLine', function() { return { source: $2, guard: $4, object: true }; }), o('FOROF ExpressionLine WHEN ExpressionLine', function() { return { source: $2, guard: $4, object: true }; }), o('FORIN Expression BY ExpressionLine', function() { return { source: $2, step: $4 }; }), o('FORIN ExpressionLine BY ExpressionLine', function() { return { source: $2, step: $4 }; }), o('FORIN Expression WHEN Expression BY ExpressionLine', function() { return { source: $2, guard: $4, step: $6 }; }), o('FORIN ExpressionLine WHEN Expression BY ExpressionLine', function() { return { source: $2, guard: $4, step: $6 }; }), o('FORIN Expression WHEN ExpressionLine BY ExpressionLine', function() { return { source: $2, guard: $4, step: $6 }; }), o('FORIN ExpressionLine WHEN ExpressionLine BY ExpressionLine', function() { return { source: $2, guard: $4, step: $6 }; }), o('FORIN Expression BY Expression WHEN ExpressionLine', function() { return { source: $2, step: $4, guard: $6 }; }), o('FORIN ExpressionLine BY Expression WHEN ExpressionLine', function() { return { source: $2, step: $4, guard: $6 }; }), o('FORIN Expression BY ExpressionLine WHEN ExpressionLine', function() { return { source: $2, step: $4, guard: $6 }; }), o('FORIN ExpressionLine BY ExpressionLine WHEN ExpressionLine', function() { return { source: $2, step: $4, guard: $6 }; }), o('FORFROM ExpressionLine', function() { return { source: $2, from: true }; }), o('FORFROM Expression WHEN ExpressionLine', function() { return { source: $2, guard: $4, from: true }; }), o('FORFROM ExpressionLine WHEN ExpressionLine', function() { return { source: $2, guard: $4, from: true }; }) ], Switch: [ o('SWITCH Expression INDENT Whens OUTDENT', function() { return new Switch($2, $4); }), o('SWITCH ExpressionLine INDENT Whens OUTDENT', function() { return new Switch($2, $4); }), o('SWITCH Expression INDENT Whens ELSE Block OUTDENT', function() { return new Switch($2, $4, LOC(5, 6)($6)); }), o('SWITCH ExpressionLine INDENT Whens ELSE Block OUTDENT', function() { return new Switch($2, $4, LOC(5, 6)($6)); }), o('SWITCH INDENT Whens OUTDENT', function() { return new Switch(null, $3); }), o('SWITCH INDENT Whens ELSE Block OUTDENT', function() { return new Switch(null, $3, LOC(4, 5)($5)); }) ], Whens: [ o('When', function() { return [$1]; }), o('Whens When', function() { return $1.concat($2); }) ], // An individual **When** clause, with action. When: [ o('LEADING_WHEN SimpleArgs Block', function() { return new SwitchWhen($2, $3); }), o('LEADING_WHEN SimpleArgs Block TERMINATOR', function() { return LOC(1, 3)(new SwitchWhen($2, $3)); }) ], // The most basic form of *if* is a condition and an action. The following // if-related rules are broken up along these lines in order to avoid // ambiguity. IfBlock: [ o('IF Expression Block', function() { return new If($2, $3, { type: $1 }); }), o('IfBlock ELSE IF Expression Block', function() { return $1.addElse(LOC(3, 5)(new If($4, $5, { type: $3 }))); }) ], // The full complement of *if* expressions, including postfix one-liner // *if* and *unless*. If: [ o('IfBlock'), o('IfBlock ELSE Block', function() { return $1.addElse($3); }), o('Statement POST_IF Expression', function() { return new If($3, LOC(1)(Block.wrap([$1])), { type: $2, postfix: true }); }), o('Expression POST_IF Expression', function() { return new If($3, LOC(1)(Block.wrap([$1])), { type: $2, postfix: true }); }) ], IfBlockLine: [ o('IF ExpressionLine Block', function() { return new If($2, $3, { type: $1 }); }), o('IfBlockLine ELSE IF ExpressionLine Block', function() { return $1.addElse(LOC(3, 5)(new If($4, $5, { type: $3 }))); }) ], IfLine: [ o('IfBlockLine'), o('IfBlockLine ELSE Block', function() { return $1.addElse($3); }), o('Statement POST_IF ExpressionLine', function() { return new If($3, LOC(1)(Block.wrap([$1])), { type: $2, postfix: true }); }), o('Expression POST_IF ExpressionLine', function() { return new If($3, LOC(1)(Block.wrap([$1])), { type: $2, postfix: true }); }) ], // Arithmetic and logical operators, working on one or more operands. // Here they are grouped by order of precedence. The actual precedence rules // are defined at the bottom of the page. It would be shorter if we could // combine most of these rules into a single generic *Operand OpSymbol Operand* // -type rule, but in order to make the precedence binding possible, separate // rules are necessary. OperationLine: [ o('UNARY ExpressionLine', function() { return new Op($1, $2); }), o('DO ExpressionLine', function() { return new Op($1, $2); }), o('DO_IIFE CodeLine', function() { return new Op($1, $2); }) ], Operation: [ o('UNARY Expression', function() { return new Op($1.toString(), $2, void 0, void 0, { originalOperator: $1.original }); }), o('DO Expression', function() { return new Op($1, $2); }), o('UNARY_MATH Expression', function() { return new Op($1, $2); }), o('- Expression', (function() { return new Op('-', $2); }), { prec: 'UNARY_MATH' }), o('+ Expression', (function() { return new Op('+', $2); }), { prec: 'UNARY_MATH' }), o('AWAIT Expression', function() { return new Op($1, $2); }), o('AWAIT INDENT Object OUTDENT', function() { return new Op($1, $3); }), o('-- SimpleAssignable', function() { return new Op('--', $2); }), o('++ SimpleAssignable', function() { return new Op('++', $2); }), o('SimpleAssignable --', function() { return new Op('--', $1, null, true); }), o('SimpleAssignable ++', function() { return new Op('++', $1, null, true); }), // [The existential operator](https://coffeescript.org/#existential-operator). o('Expression ?', function() { return new Existence($1); }), o('Expression + Expression', function() { return new Op('+', $1, $3); }), o('Expression - Expression', function() { return new Op('-', $1, $3); }), o('Expression MATH Expression', function() { return new Op($2, $1, $3); }), o('Expression ** Expression', function() { return new Op($2, $1, $3); }), o('Expression SHIFT Expression', function() { return new Op($2, $1, $3); }), o('Expression COMPARE Expression', function() { return new Op($2.toString(), $1, $3, void 0, { originalOperator: $2.original }); }), o('Expression & Expression', function() { return new Op($2, $1, $3); }), o('Expression ^ Expression', function() { return new Op($2, $1, $3); }), o('Expression | Expression', function() { return new Op($2, $1, $3); }), o('Expression && Expression', function() { return new Op($2.toString(), $1, $3, void 0, { originalOperator: $2.original }); }), o('Expression || Expression', function() { return new Op($2.toString(), $1, $3, void 0, { originalOperator: $2.original }); }), o('Expression BIN? Expression', function() { return new Op($2, $1, $3); }), o('Expression RELATION Expression', function() { var ref, ref1; return new Op($2.toString(), $1, $3, void 0, { invertOperator: (ref = (ref1 = $2.invert) != null ? ref1.original : void 0) != null ? ref : $2.invert }); }), o('SimpleAssignable COMPOUND_ASSIGN Expression', function() { return new Assign($1, $3, $2.toString(), { originalContext: $2.original }); }), o('SimpleAssignable COMPOUND_ASSIGN INDENT Expression OUTDENT', function() { return new Assign($1, $4, $2.toString(), { originalContext: $2.original }); }), o('SimpleAssignable COMPOUND_ASSIGN TERMINATOR Expression', function() { return new Assign($1, $4, $2.toString(), { originalContext: $2.original }); }) ], DoIife: [ o('DO_IIFE Code', function() { return new Op($1, $2); }) ] }; // Precedence // ---------- // Operators at the top of this list have higher precedence than the ones lower // down. Following these rules is what makes `2 + 3 * 4` parse as: // 2 + (3 * 4) // And not: // (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']]; // Wrapping Up // ----------- // Finally, now that we have our **grammar** and our **operators**, we can create // our **Jison.Parser**. We do this by processing all of our rules, recording all // terminals (every symbol which does not appear as the name of a rule above) // as "tokens". tokens = []; for (name in grammar) { alternatives = grammar[name]; grammar[name] = (function() { var i, j, len, len1, ref, results; results = []; for (i = 0, len = alternatives.length; i < len; i++) { alt = alternatives[i]; ref = alt[0].split(' '); for (j = 0, len1 = ref.length; j < len1; j++) { token = ref[j]; if (!grammar[token]) { tokens.push(token); } } if (name === 'Root') { alt[1] = `return ${alt[1]}`; } results.push(alt); } return results; })(); } // Initialize the **Parser** with our list of terminal **tokens**, our **grammar** // rules, and the name of the root. Reverse the operators because Jison orders // precedence from low to high, and we have it high to low // (as in [Yacc](http://dinosaur.compilertools.net/yacc/index.html)). exports.parser = new Parser({ tokens: tokens.join(' '), bnf: grammar, operators: operators.reverse(), startSymbol: 'Root' }); }).call(this);