coffeescript
Version:
Unfancy JavaScript
1,880 lines (1,868 loc) • 64.4 kB
JavaScript
// 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,