2497 lines
63 KiB
JavaScript
2497 lines
63 KiB
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,
|
||
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);
|