jashkenas--coffeescript/lib/coffeescript/grammar.js

2497 lines
63 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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 wont 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. Its 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 its 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);