imba
Version:
1,290 lines (1,104 loc) • 55.8 kB
JavaScript
import jison from '../../vendor/jison/jison.js';
function iter$(a){ return a ? (a.toArray ? a.toArray() : a) : []; };
// The Imba parser is generated by [Jison](http://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)](http://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](http://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](http://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 = jison.Parser;
// 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.
var unwrap = /^function\s*\(\)\s*\{\s*return\s*([\s\S]*);\s*\}/;
// Our handy DSL for Jison grammar generation, thanks to
// [Tim Caswell](http://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.
var o = function(patternString,action,options) {
var match;
patternString = patternString.replace(/\s{2,}/g,' ');
var patternCount = patternString.split(' ').length;
if (!action) { return [patternString,'$$ = $1;',options] };
if (match = unwrap.exec(action)) {
action = match[1];
} else {
action = ("(" + action + "())");
};
action = action.replace(/\bA(\d+)/g,'$$$1');
action = action.replace(/\bnew /g,'$&yy.');
action = action.replace(/\b(?:Block\.wrap|extend)\b/g,'yy.$&');
action = action.replace(/\bAST\b/g,'yy');
// really?
// # should we always add locdata? does not work when statement)!
// return [patternString, "$$ = #{loc(1, patternCount)}(#{action});", options]
return [patternString,("$$ = " + action + ";"),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"
//
// `A1` would be the value of the first `Expression`, `A2` would be the token
// for the `UNLESS` terminal, and `A3` would be the value of the second
// `Expression`.
var 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([]); }),
o('Body',function() { return new Root(A1); }),
o('Block TERMINATOR')
],
// Any list of statements and expressions, separated by line breaks or semicolons.
Body: [
o('BODYSTART',function() { return new Block([]); }),
o('Line',function() { return new Block([]).add(A1); }),
// o 'HEADER Line' do Block.new([A2])
// o 'LeadingTerminator' do Block.new([Terminator.new(A1)])
o('Body Terminator Line',function() { return A1.break(A2).add(A3); }), // A3.prebreak(A2) # why not add as real nodes?!
o('Body Terminator',function() { return A1.break(A2); })
],
Terminator: [
o('TERMINATOR',function() { return new Terminator(A1); })
],
Type: [
o('TYPE',function() { return new TypeAnnotation(A1); }),
o('GENERICS',function() { return new Generics(A1); })
],
// 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('EMPTY_BLOCK',function() { return new Block([]); }),
o('INDENT OUTDENT',function() { return new Block([]).indented(A1,A2); }),
o('INDENT Body OUTDENT',function() { return A2.indented(A1,A3); }),
// hacky way to support terminators at the start of blocks
o('INDENT TERMINATOR Body OUTDENT',function() { return A3.prebreak(A2).indented(A1,A4); }),
o('INDENT TERMINATOR OUTDENT',function() { return new Block([]).indented(A1,A3); })
],
// Block and statements, which make up a line in a body.
Line: [
o('CSSDeclaration'),
o('Expression'),
// ?
o('VarDecl',function() { return A1.option('block',true); }),
o('Comment'),
o('Statement'),
o('Decorators'),
o('ImportDeclaration'),
o('ExportDeclaration'),
o('GLOBAL Line',function() { return AST.GLOBAL(A2,A1); }),
o('DECLARE Line',function() { return AST.DECLARE(A2,A1); })
// A2.set(declareOnly: A1)
],
// Pure statements which cannot be expressions.
Statement: [
o('Return'),
o('Yield'),
o('Throw'),
o('STATEMENT',function() { return new Literal(A1); }),
o('BREAK',function() { return new BreakStatement(A1); }),
o('BREAK CALL_START Expression CALL_END',function() { return new BreakStatement(A1,A3); }),
o('CONTINUE',function() { return new ContinueStatement(A1); }),
o('CONTINUE CALL_START Expression CALL_END',function() { return new ContinueStatement(A1,A3); }),
o('DEBUGGER',function() { return new DebuggerStatement(A1); })
],
ExtendObject: [
// o 'CLASS ClassName ClassBody' do ClassDeclaration.new(A2, null, A3).set(keyword: A1)
o('EXTEND Identifier ClassBody',function() {
return new ExtendDeclaration(A2,null,A3).set({instanceOnly: true,extension: A1});
})
],
ExportDeclaration: [
o('ENV_FLAG ExportDeclaration',function() {
return A2.addEnv(A1);
}),
o('EXPORT { ImportSpecifierList }',function() {
return new ExportNamedDeclaration(A1,[A3]).setEnds(A1,A4);
}),
o('EXPORT { ImportSpecifierList } FROM String',function() {
return new ExportNamedDeclaration(A1,[A3],A6).setEnds(A1,A6);
}),
o('EXPORT EXPORT_ALL FROM String',function() {
return new ExportAllDeclaration(A1,[new ExportAllSpecifier(A2)],A4).setEnds(A1,A4);
}),
o('EXPORT EXPORT_ALL AS Identifier FROM String',function() {
return new ExportAllDeclaration(A1,[new ExportAllSpecifier(A2,A4)],A6).setEnds(A1,A6);
}),
o('EXPORT Exportable',function() {
return new Export(A2).set({keyword: A1}).setEnds(A1,A2);
}),
o('EXPORT DEFAULT DefaultExportable',function() {
return new Export(A3).set({keyword: A1,'default': A2}).setEnds(A1,A3);
})
],
Exportable: [
o('MethodDeclaration'),
o('Class'),
o('CSSDeclaration'),
o('TagDeclaration'),
o('VarAssign'),
o('GLOBAL Exportable',function() { return AST.GLOBAL(A2,A1); })
],
DefaultExportable: [
o('Expression'),
o('GLOBAL Exportable',function() { return AST.GLOBAL(A2,A1); })
],
ImportOrExport: [
o('IMPORT'),
o('EXPORT')
],
ImportDefaultSpecifier: [
o('Identifier',function() { return new ImportDefaultSpecifier(A1); })
],
ImportDeclaration: [
o('ENV_FLAG ImportDeclaration',function() {
return A2.addEnv(A1);
}),
o('IMPORT String',function() {
return new ImportDeclaration(A1,null,A2);
}),
o('IMPORT ImportDefaultSpecifier FROM String',function() {
return new ImportDeclaration(A1,[A2],A4);
}),
o('IMPORT TYPEIMPORT ImportDefaultSpecifier FROM String',function() {
return new ImportTypeDeclaration(A1,[A3],A5);
}),
o('IMPORT ImportNamespaceSpecifier FROM String',function() {
return new ImportDeclaration(A1,[A2],A4);
}),
o('IMPORT { } FROM String',function() {
return new ImportDeclaration(A1,null,A5);
}),
o('IMPORT { ImportSpecifierList } FROM String',function() {
return new ImportDeclaration(A1,[A3],A6);
}),
o('IMPORT TYPEIMPORT { ImportSpecifierList } FROM String',function() {
return new ImportTypeDeclaration(A1,[A4],A7);
}),
o('IMPORT ImportDefaultSpecifier IMPORT_COMMA ImportNamespaceSpecifier FROM String',function() {
return new ImportDeclaration(A1,[A2,A4],A6);
}),
o('IMPORT ImportDefaultSpecifier IMPORT_COMMA { ImportSpecifierList } FROM String',function() {
return new ImportDeclaration(A1,[A2,A5],A8);
})
],
ImportFrom: [
o('STRING')
],
ImportNamespaceSpecifier: [
o('IMPORT_ALL AS Identifier',function() { return new ImportNamespaceSpecifier(new Literal(A1),A3); })
],
ImportSpecifierList: [
o('ImportSpecifier',function() { return new ESMSpecifierList([]).add(A1); }),
o('ImportSpecifierList , ImportSpecifier',function() { return A1.add(A3); }),
o('ImportSpecifierList OptComma TERMINATOR ImportSpecifier',function() { return A1.add(A4); }),
o('INDENT ImportSpecifierList OptComma OUTDENT',function() { return A2; }),
o('INDENT ImportSpecifierList OptComma TERMINATOR OUTDENT',function() { return A2; }),
o('ImportSpecifierList OptComma INDENT ImportSpecifierList OptComma OUTDENT',function() { return A1.concat(A4); })
],
ImportSpecifier: [
o('Identifier',function() { return new ImportSpecifier(A1); }),
o('DecoratorIdentifier',function() { return new ImportSpecifier(A1); }),
o('StyleMixinIdentifier',function() { return new ImportSpecifier(A1); }),
o('Identifier AS Identifier',function() { return new ImportSpecifier(A1,A3); }),
o('DEFAULT',function() { return new ImportSpecifier(new Literal(A1)); }),
o('DEFAULT AS Identifier',function() { return new ImportSpecifier(new Literal(A1),A3); })
],
Require: [
o('REQUIRE RequireArg',function() { return new Require(A2).set({keyword: A1}); })
],
RequireArg: [
o('Literal'),
o('Parenthetical'),
o('')
],
// All the different types of expressions in our language. The basic unit of
// Imba 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('Await'),
o('Value'),
o('Code'),
o('Operation'),
o('Assign'),
o('If'),
o('Ternary'),
o('Try'),
o('While'),
o('For'),
o('Switch'),
o('ExtendObject'),
o('Class'),
o('TagDeclaration'),
o('Tag')
],
ExpressionBlock: [
o('Expression'),
o('INDENT ExpressionBlock Outdent',function() { return A2.indented(A1,A3); })
],
// A literal identifier, a variable name or property.
Identifier: [
o('IDENTIFIER',function() { return new Identifier(A1); })
],
SymbolIdentifier: [
o('SYMBOLID',function() { return new SymbolIdentifier(A1); }),
o('# Interpolation',function() { return new InterpolatedSymbolIdentifier(A1,A2); })
],
DecoratorIdentifier: [
o('DECORATOR',function() { return new DecoratorIdentifier(A1); })
],
StyleMixinIdentifier: [
o('CSS_MIXIN',function() { return new MixinIdentifier(A1); })
],
Key: [
o('KEY',function() { return new Identifier(A1); })
],
Argvar: [
o('ARGVAR',function() { return new Argvar(A1).setEnds(A1,A1); })
],
Symbol: [
o('SYMBOL',function() { return new Symbol(A1); })
],
Decorator: [
o('DecoratorIdentifier',function() { return new Decorator(A1); }), // kinda hacky, should be defined as something else
o('DecoratorIdentifier Arguments',function() { return new Decorator(A1).set({params: A2}); }),
// o 'DecoratorIdentifier ( ArgList )' do Decorator.new(A1).set(params: A3)
o('Decorator . Identifier',function() { return A1.add(A3); })
],
Decorators: [
o('Decorator',function() { return [A1]; }),
o('Decorators Decorator',function() { return A1.concat(A2); })
],
// Alphanumerics are separated from the other **Literal** matchers because
// they can also serve as keys in object literals.
AlphaNumeric: [
o('NUMBER UNIT',function() { return new NumWithUnit(A1,A2); }),
o('NUMBER',function() { return new Num(A1); }),
o('STRING',function() { return new Str(A1); }),
o('Symbol'),
o('InterpolatedString')
],
String: [
o('STRING',function() { return new Str(A1); })
],
InterpolatedString: [
o('STRING_START',function() { return new InterpolatedString([],{open: A1}); }),
o('InterpolatedString NEOSTRING',function() { return A1.add(A2); }),
o('InterpolatedString Interpolation',function() { return A2 ? A1.add(A2) : A1; }),
o('InterpolatedString STRING_END',function() { return A1.option('close',A2); })
],
// The list of arguments to a function call.
Interpolation: [
o('{{ }}',function() { return null; }),
o('{{ Expression }}',function() { return A2; })
],
// All of our immediate values. Generally these can be passed straight
// through and printed to JavaScript.
Literal: [
o('AlphaNumeric'),
o('JS',function() { return new Literal(A1); }),
o('REGEX',function() { return new RegExp(A1); }),
o('BOOL',function() { return new Bool(A1); }),
o('TRUE',function() { return new True(A1); }), // AST.TRUE # should not cheat like this
o('FALSE',function() { return new False(A1); }), // AST.FALSE
o('NULL',function() { return new Nil(A1); }), // AST.NIL
o('UNDEFINED',function() { return new Undefined(A1); }) // AST.UNDEFINED
// we loose locations for these
],
// A return statement from a function body.
Return: [
o('RETURN Expression',function() { return new Return(A2).set({keyword: A1}); }),
o('RETURN Arguments',function() { return new Return(A2).set({keyword: A1}); }), // should probably force as array
o('RETURN',function() { return new Return().set({keyword: A1}); })
],
Yield: [
o('YIELD Expression',function() { return new Yield(A2).set({keyword: A1}); }),
o('YIELD Arguments',function() { return new Yield(A2).set({keyword: A1}); }), // should probably force as array
o('YIELD',function() { return new Yield().set({keyword: A1}); })
],
Selector: [
o('SELECTOR_START',function() { return new Selector([],{type: A1,open: A1}); }),
o('Selector SELECTOR_PART',function() { return A1.add(A2); }),
o('Selector { Expression }',function() { return A1.add(A3); }),
o('Selector SELECTOR_END',function() { return A1.option('close',A2); })
],
Tag: [
o('TAG_START TagOptions TAG_END',function() { return A2.setEnds({open: A1,close: A3}).setEnds(A1,A3); }),
o('TAG_START TagOptions TAG_END TagBody',function() { return A2.set({body: A4,open: A1,close: A3}); })
],
TagTypeName: [
o('Self',function() { return A1; }),
o('IDENTIFIER',function() { return new TagTypeIdentifier(A1); }),
o('TAG_TYPE',function() { return new TagTypeIdentifier(A1); }),
o('TagIdentifier',function() { return new ExpressionNode(A1); }),
o('',function() { return new TagTypeIdentifier('div'); })
],
StyleBlockDeclaration: [
o('CSS CSS_SEL StyleBody CSS_END',function() { return new StyleRuleSet(A2,A3).set({name: A1}); })
],
CSSDeclaration: [
// o 'GLOBAL CSS CSS_SEL StyleBody CSS_END' do StyleRuleSet.new(A3,A4).set(global: A1)
o('StyleBlockDeclaration',function() { return A1.set({toplevel: true}); }),
// o 'GLOBAL CSSDeclaration' do A2.set(global: A1)
o('LOCAL CSSDeclaration',function() { return A2.set({local: A1}); })
],
StyleBlockBody: [
o('INDENT Terminator OUTDENT',function() { return new StyleBody([]).indented(A1,A3); }),
o('INDENT StyleBody Outdent',function() { return A2.indented(A1,A3); })
],
OptStyleBody: [
o('',function() { return new StyleBody([]); }),
o('StyleBody')
],
StyleBody: [
o('StyleNode',function() { return new StyleBody([A1]); }),
o('StyleBody StyleDeclaration',function() { return A1.add(A2); }),
// o 'Style2Body , Style2Node' do A1.add A3
o('StyleBody Terminator StyleNode',function() { return A1.add(A3); }),
o('INDENT StyleBody Outdent',function() { return A2.indented(A1,A3); })
],
StyleNode: [
o('StyleDeclaration'),
o('CSS_SEL StyleBlockBody CSS_END',function() { return new StyleRuleSet(A1,A2); })
],
StyleDeclaration: [
o('StyleProperty : StyleExpressions',function() { return new StyleDeclaration(A1,A3.set({parens: false})); }),
o('StyleProperty = StyleExpressions',function() { return new StyleDeclaration(A1,A3.set({parens: false})); })
],
StyleProperty: [
o('CSSPROP',function() { return new StyleProperty([A1]); })
],
StyleOperator: [
o('MATH'),
o('+'),
o('-')
],
StyleExpressions: [
o('StyleExpression',function() { return new StyleExpressions([A1]); }),
o('StyleExpressions , StyleExpression',function() { return A1.add(A3); })
],
// the values
StyleExpression: [
o('StyleTerm',function() { return new StyleExpression().add(A1); }),
o('StyleExpression StyleOperator',function() { return A1.add(A2); }),
o('StyleExpression StyleTerm',function() { return A1.add(A2); }),
o('StyleExpression / StyleTerm',function() { return A1.addParam(A3,A2); })
],
StyleValue: [
o('StyleTerm'),
o('StyleOperation')
],
StyleOperation: [
o('StyleTerm StyleOperator StyleTerm',function() { return new StyleOperation([A1,A2,A3]); }),
o('StyleOperation StyleOperator StyleTerm',function() { return A1.add([A2,A3]); })
],
StyleFunctionArgs: [
o('StyleFunctionArg',function() { return new StyleExpressions([A1]); }),
o('StyleFunctionArgs , StyleFunctionArg',function() { return A1.add(A3); })
],
StyleFunctionArg: [
o('StyleTerm',function() { return new StyleExpression().add(A1); }),
o('StyleFunctionArg StyleOperator',function() { return A1.add(A2); }),
o('StyleFunctionArg StyleTerm',function() { return A1.add(A2); }),
o('StyleFunctionArg / StyleTerm',function() { return A1.addParam(A3,A2); })
],
StyleTermPlaceholder: [
o('{ Expression }',function() { return new StyleInterpolationExpression(A2).setEnds(A1,A3); }),
o('StyleTermPlaceholder CSSUNIT',function() { return A1.set({unit: A2}); })
],
StyleParens: [
o('( StyleValue )',function() { return new StyleParens(A2).setEnds(A1,A3); }),
o('StyleParens CSSUNIT',function() { return A1.set({unit: A2}); })
],
StyleColor: [
o('COLOR',function() { return new StyleColor(A1); }),
o('COLORMIX ( StyleFunctionArgs )',function() { return new StyleColorMix(A1,A3.setEnds(A2,A4)).set({params: A3}).setEnds(A1,A4); })
],
StyleTerm: [
o('StyleParens'),
o('CSSVAR',function() { return new StyleVar(A1); }),
o('DIMENSION',function() { return new StyleDimension(A1); }),
// o 'COLOR ( StyleFunctionArgs )' do StyleColor.new(A1,A3).set(params: A3)
o('StyleColor'),
o('PERCENTAGE',function() { return new StyleDimension(A1); }),
o('NUMBER',function() { return new StyleNumber(A1); }),
o('String',function() { return A1; }),
o('StyleTermPlaceholder',function() { return A1; }),
o('CSSURL',function() { return new StyleURL(A1); }),
o('CSSFUNCTION ( StyleFunctionArgs )',function() { return new StyleFunction(A1,A3.setEnds(A2,A4)).setEnds(A1,A4); }),
o('CSSIDENTIFIER',function() { return new StyleIdentifier(A1); }),
o('COMPARE StyleTerm',function() { return A2.set({op: A1}); })
],
TagOptions: [
o('TagTypeName TAG_REF',function() { return new Tag({type: A1,reference: A2}); }),
o('TagTypeName',function() { return new Tag({type: A1}); }),
o('TagOptions TAG_ID',function() { return A1.addPart(A2,AST.TagId); }),
o('TagOptions TAG_SYMBOL_ID',function() { return A1.addPart(new IdentifierExpression(A2.cloneSlice(1)),AST.TagId); }),
o('TagOptions SYMBOL_ID',function() { return A1.addPart(new IdentifierExpression(A2.cloneSlice(1)),AST.TagId); }),
o('TagOptions TAG_FLAG',function() { return A1.addPart(A2,AST.TagFlag); }),
o('TagOptions TAG_ATTR',function() { return A1.addPart(A2,AST.TagAttr); }),
o('TagOptions STYLE_START STYLE_END',function() { return A1; }),
o('TagOptions STYLE_START StyleBody STYLE_END',function() { return A1.addPart(new StyleRuleSet(null,A3),AST.TagFlag); }),
o('TagOptions T. STYLE_START StyleBody STYLE_END',function() { return A1.addPart(new StyleRuleSet(null,A4),AST.TagFlag); }),
o('TagOptions CSS_MIXIN',function() { return A1.addPart(new MixinIdentifier(A2),AST.TagFlag); }),
o('TagOptions T: TagIdentifier',function() { return A1.addPart(A3,AST.TagHandler); }),
o('TagOptions T@ TagIdentifier',function() { return A1.addPart(A3,AST.TagHandler); }),
o('TagOptions T. @ TAG_LITERAL',function() { return A1.addPart(A4.prepend('_'),AST.TagFlag); }), // not supported anymore
o('TagOptions T. UNARY TAG_LITERAL',function() { return A1.addPart(A4.prepend('!'),AST.TagFlag); }),
o('TagOptions T. TagIdentifier',function() { return A1.addPart(A3,AST.TagFlag); }),
o('TagOptions # TagIdentifier',function() { return A1.addPart(A3,AST.TagId); }),
o('TagOptions TAG_WS TagIdentifier',function() { return A1.addPart(A2,AST.TagSep).addPart(A3,AST.TagAttr); }),
o('TagOptions ( )',function() { return A1.addPart(new ArgList([]),AST.TagArgList); }),
o('TagOptions ( ArgList )',function() { return A1.addPart(A3,AST.TagArgList); }),
o('TagOptions CALL_START CALL_END',function() { return A1.addPart(null,AST.TagArgList); }),
o('TagOptions CALL_START ArgList CALL_END',function() { return A1.addPart(A3,AST.TagArgList); }),
o('TagOptions TAG_WS',function() { return A1.addPart(A2,AST.TagSep); }),
o('TagOptions Comment',function() { return A1; }),
o('TagOptions TERMINATOR',function() { return A1; }),
// o 'TagOptions TagFlag' do A1.addPart(A2)
o('TagOptions = TagAttrValue',function() { return A1.addPart(A3,AST.TagAttrValue,A2); })
],
TagIdentifier: [
o('TAG_LITERAL',function() { return new IdentifierExpression(A1); }),
o('{ Expression }',function() { return new IdentifierExpression(A2); }),
o('TagIdentifier TAG_LITERAL',function() { return A1.add(A2); }),
o('TagIdentifier { Expression }',function() { return A1.add(A3); })
// o '{ Expression }' do TagIdentifier.new(A2)
],
TagFlag: [
o('%',function() { return new TagFlag(); }),
o('TagFlag TagPartIdentifier',function() { return A1.add(A2); })
],
TagAttrValue: [
o('VALUE_START Expression VALUE_END',function() { return A2; })
],
TagBody: [
o('INDENT OUTDENT',function() { return new TagBody([]).indented(A1,A2); }),
o('INDENT TERMINATOR OUTDENT',function() { return new TagBody([]).indented(A1,A3); }),
o('INDENT TagBodyList OUTDENT',function() { return A2.indented(A1,A3); }),
o('CALL_START TagBodyList CALL_END',function() { return A2; }),
o('Tag',function() { return new TagBody([A1]); })
],
TagBodyList: [
o('TagBodyItem',function() { return new TagBody([]).add(A1); }),
o('TagBodyList , TagBodyItem',function() { return A1.add(A3); }),
o('TagBodyList OptComma Terminator TagBodyItem',function() { return A1.add(A3).add(A4); }),
o('TagBodyList OptComma TERMINATOR SEPARATOR Terminator TagBodyItem',function() { return A1.add(A5).add(A6); }),
o('INDENT TagBodyList OptComma Outdent',function() { return A2.indented(A1,A4); }),
o('TagBodyList OptComma INDENT TagBodyList OptComma Outdent',function() { return A1.concat(A4); })
],
// Valid arguments are Blocks or Splats.
TagBodyItem: [
o('Expression'),
o('... Expression',function() { return new Splat(A2).set({keyword: A1}); }),
o('Splat'),
o('LOGIC'),
o('Comment'),
o('StyleBlockDeclaration',function() { return A1.set({inTagTree: true}); })
],
// Class definitions have optional bodies of prototype property assignments,
// and optional references to the superclass.
TagDeclaration: [
o('TagDeclarationBlock',function() { return A1; }),
o('EXTEND TagDeclarationBlock',function() { return A2.set({extension: true}); }),
o('LOCAL TagDeclarationBlock',function() { return A2.set({local: true}); })
// o 'GLOBAL TagDeclarationBlock' do A2.set(global: A1)
],
TagDeclarationBlock: [
o('TAG TagType',function() { return new TagDeclaration(A2).set({keyword: A1}); }),
o('TAG TagType ClassBody',function() { return new TagDeclaration(A2,null,A3).set({keyword: A1}); }),
o('TAG TagType COMPARE TagType',function() { return new TagDeclaration(A2,A4).set({keyword: A1,extends: A3}); }),
o('TAG TagType COMPARE TagType ClassBody',function() { return new TagDeclaration(A2,A4,A5).set({keyword: A1,extends: A3}); })
],
// Going to move back to fewer custom tokens
TagType: [
o('TAG_TYPE',function() { return new TagTypeIdentifier(A1); })
],
TagId: [
o('# IDENTIFIER',function() { return new TagIdRef(A2); })
],
// Assignment of a variable, property, or index to a value.
Assign: [
o('VarAssign'),
o('Assignable = Expression',function() { return new Assign(A2,A1,A3).setEnds(A1,A3); }),
o('Assignable = INDENT Expression Outdent',function() { return new Assign(A2,A1,A4.indented(A3,A5)); })
],
// 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('... Expression',function() { return new ObjRestAttr(A2).set({spread: A1}); }),
o('MethodDeclaration',function() { return A1.set({inObject: true}); }),
o('ObjAssignable',function() { return new ObjAttr(A1); }),
o('ObjAssignable : Expression',function() { return new ObjAttr(A1,A3); }),
o('ObjAssignable : INDENT Expression Outdent',function() { return new ObjAttr(A1,A4.indented(A3,A5)); }),
o('SimpleObjAssignable = Expression',function() { return new ObjAttr(A1,null,A3); }),
o('SimpleObjAssignable = INDENT Expression Outdent',function() { return new ObjAttr(A1,null,A4.indented(A3,A5)); }),
o('Comment')
],
SimpleObjAssignable: [
o('Identifier'),
o('Identifier Type',function() { return AST.SETTYPE(A1,A2); }),
o('SymbolIdentifier'),
o('Key')
],
ObjAssignable: [
o('SimpleObjAssignable'),
// this is the interpolated string
o('[ Expression ]',function() { return new IdentifierExpression(A2); }),
o('( Expression )',function() { return new IdentifierExpression(A2); }),
o('AlphaNumeric')
],
// A block comment.
Comment: [
o('HERECOMMENT',function() { return new Comment(A1,true); }),
o('COMMENT',function() { return new Comment(A1,false); })
],
// 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('Method'),
o('Do'),
o('Begin')
],
Begin: [
o('BEGIN Block',function() { return new Begin(A2); })
],
Do: [
o('DO Block',function() { return new Lambda([],A2,null,null,{bound: true,keyword: A1}); }),
o('DO BLOCK_PARAM_START ParamList BLOCK_PARAM_END Block',function() { return new Lambda(A3,A5,null,null,{bound: true,keyword: A1}); })
],
// FIXME clean up method
Method: [
o('MethodDeclaration',function() { return A1; }),
// o 'GLOBAL MethodDeclaration' do A2.set(global: A1)
o('STATIC MethodDeclaration',function() { return A2.set({static: A1}); })
],
MethodDeclaration: [
o('DEF MethodScope MethodScopeType MethodIdentifier MethodParams MethodBody',function() {
return new MethodDeclaration(A5,A6,A4,A2,A3).set({def: A1,keyword: A1,datatype: A4.option('datatype')});
}),
o('DEF MethodIdentifier MethodParams MethodBody',function() {
return new MethodDeclaration(A3,A4,A2,null).set({def: A1,keyword: A1,datatype: A2.option('datatype')});
})
],
MethodParams: [
o('ParamList',function() { return A1; }),
o('CALL_START ParamList CALL_END',function() { return A2; })
],
MethodScopeType: [
o('.',function() { return {static: true}; }),
o('#',function() { return {}; })
],
MethodIdentifier: [
o('Identifier'),
o('DecoratorIdentifier'),
o('SymbolIdentifier',function() { return A1.set({as: 'property'}); }), // InterpolatedIdentifier.new(A1)
o('[ Expression ]',function() { return new InterpolatedIdentifier(A2); }),
o('MethodIdentifier Type',function() { return AST.SETTYPE(A1,A2); })
],
MethodBody: [
o('DEF_BODY Block',function() { return A2; }),
o('DEF_BODY DO Block',function() { return A3; }),
o('DEF_EMPTY',function() { return new Block([]).set({end: A1._loc}); })
],
// should support much more
MethodScope: [
o('MethodIdentifier'),
o('This'),
o('Self')
],
// An optional, trailing comma.
OptComma: [
o(''),
o(',')
],
OptSemicolon: [
o(''),
o(';')
],
// The list of parameters that a function accepts can be of any length.
ParamList: [
o('',function() { return []; }),
o('Param',function() { return [A1]; }),
o('ParamList , Param',function() { return A1.concat(A3); })
],
ParamExpression: [
o('Value'),
o('Code'),
o('Operation'),
o('Assign'),
o('Ternary'),
o('Tag')
],
ParamValue: [
o('Expression')
// o 'Expression'
// o 'Parenthetical'
// o 'Operation'
// o 'Assign'
// o 'Ternary'
// o 'Tag'
],
// A single parameter in a function definition can be ordinary, or a splat
// that hoovers up the remaining arguments.
Param: [
o('Object',function() { return new Param(A1); }),
o('Array',function() { return new Param(A1); }),
o('ParamVar'), // do RequiredParam.new A1
o('... ParamVar',function() { return A2.set({splat: A1}); }),
// BlockParam.new A2, null, A1
o('BLOCK_ARG ParamVar',function() { return A2.set({blk: A1}); }),
// BlockParam.new A2, null, A1
o('ParamVar = ParamValue',function() { return new Param(A1.value(),A3).set({datatype: A1.option('datatype')}); }),
o('Object = ParamValue',function() { return new Param(A1,A3); }),
o('Array = ParamValue',function() { return new Param(A1,A3); }),
o('...',function() { return new RestParam(A1); })
],
// Function Parameters
ParamVar: [
o('Identifier',function() { return new Param(A1); }),
o('Identifier Type',function() { return AST.SETTYPE(new Param(A1),A2); })
],
// A splat that occurs outside of a parameter list.
Splat: [
o('SPLAT Expression',function() { return AST.SPLAT(A2); })
],
GlobalDeclaration: [
o('GLOBAL GlobalAssignable = Expression',function() { return new GlobalDeclaration(A2,A4).set({keyword: A1,op: A3}); }),
o('GLOBAL GlobalAssignable',function() { return new GlobalDeclaration(A2).set({keyword: A1}); })
// o 'GlobalDeclaration = Expression' do A1.set(op: A2, value: A3)
],
GlobalAssignable: [
o('Identifier'),
o('Identifier Type',function() { return AST.SETTYPE(A1,A2); })
],
VarKeyword: [
o('VAR'),
o('LET'),
o('CONST')
],
VarAssignable: [
o('Identifier'),
o('Identifier Type',function() { return AST.SETTYPE(A1,A2); }),
o('Array'), // all kinds?
o('Object') // not supported anymore
],
VarDecl: [
o('VarKeyword VarAssignable',function() { return new VarReference(A2,A1); }),
o('STATIC VarDecl',function() { return A2.set({static: A1}); })
],
VarAssign: [
o('VarDecl = Expression',function() { return new Assign(A2,A1,A3); }),
o('VarDecl = INDENT Expression Outdent',function() { return new Assign(A2,A1,A4.indented(A3,A5)); })
],
// Variables and properties that can be assigned to.
SimpleAssignable: [
o('ENV_FLAG',function() { return new EnvFlag(A1); }),
o('Argvar'),
o('Self'), // not sure if self should be assignable really
o('Identifier',function() { return new VarOrAccess(A1); }), // LocalIdentifier.new(A1)
o('SymbolIdentifier',function() { return new Access('.',null,A1); }), // LocalIdentifier.new(A1)
o('Access'),
// FIXME this isn really assignable?
// o 'Value . NEW' do LegacyNew.new(A1).set(keyword: A3)
// o 'Value . Super' do SuperAccess.new('.',A1,A3)
o('SimpleAssignable Type',function() { return AST.SETTYPE(A1,A2); })
],
Access: [
o('Value SoakableOp Identifier',function() { return AST.OP(A2,A1,A3); }), // PropertyAccess.new(A2,A1,A3) # TODO change to regular access
o('Value SoakableOp SymbolIdentifier',function() { return new IndexAccess(A2,A1,A3); }), // AST.OP(A2,A1,A3) # PropertyAccess.new(A2,A1,A3) # TODO change to regular access
o('Value INDEX_START IndexValue INDEX_END',function() { return new IndexAccess('.',A1,A3.setEnds(A2,A4)); }),
o('Value ?. [ IndexValue ]',function() { return AST.OP(A2,A1,A4); })
],
SoakableOp: [
'.',
'?.'
],
Super: [
o('SUPER',function() { return new Super(A1); })
],
// Everything that can be assigned to.
Assignable: [
o('SimpleAssignable'),
o('Array'), // do A1
o('Object') // not supported anymore
],
TaggedTemplate: [
o('SimpleAssignable InterpolatedString',function() { return new TaggedTemplate(A1,A2); }),
o('SimpleAssignable String',function() { return new TaggedTemplate(A1,A2); })
],
Await: [
o('AWAIT Expression',function() { return new Await(A2).set({keyword: A1}); })
],
// 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('Super'),
o('Literal'),
o('Literal Type',function() { return AST.SETTYPE(A1,A2); }),
o('Parenthetical'),
o('Range'),
o('ARGUMENTS',function() { return AST.ARGUMENTS; }),
o('This'),
o('TagId'),
o('Selector'),
o('Invocation'),
o('TaggedTemplate'),
o('Require'),
o('AMPER_REF',function() { return new AmperRef(A1); }),
// TODO Makes no sense that this is not more specific
o('Value BANG',function() { return new BangCall(A1).set({keyword: A2}); })
],
IndexValue: [
o('Expression',function() { return new Index(A1); })
],
// In Imba, an object literal is simply a list of assignments.
Object: [
o('{ AssignList OptComma }',function() { return new Obj(A2,A1.generated).setEnds(A1,A4); })
],
// Assignment of properties within an object literal can be separated by
// comma, as in JavaScript, or simply by newline.
AssignList: [
o('',function() { return new AssignList([]); }),
o('AssignObj',function() { return new AssignList([A1]); }),
o('AssignList , AssignObj',function() { return A1.add(A3); }),
o('AssignList OptComma Terminator AssignObj',function() { return A1.add(A3).add(A4); }), // A4.prebreak(A3)
o('AssignList OptComma INDENT AssignList OptComma Outdent',function() { return A1.concat(A4.indented(A3,A6)); })
],
ExpressionList: [
o('Expression',function() { return new ExpressionList([]).add(A1); }),
o('ExpressionList , Expression',function() { return A1.add(A3); }),
o('ExpressionList OptComma Terminator Expression',function() { return A1.add(A3).add(A4); }),
o('INDENT ExpressionList OptComma Outdent',function() { return A2.indented(A1,A4); }),
o('ExpressionList OptComma INDENT ExpressionList OptComma Outdent',function() { return A1.concat(A4); })
],
// Class definitions have optional bodies of prototype property assignments,
// and optional references to the superclass.
// might as well handle this in the lexer instead
Class: [
o('ClassStart',function() { return A1; }),
o('ABSTRACT ClassStart',function() { return A2.set({abstract: A1}); }),
o('EXTEND ClassStart',function() { return A2.set({extension: A1}); })
],
ClassStart: [
// o 'CLASS ClassName ClassConstructorParams ClassBody' do ClassDeclaration.new(A2, null, A4).set(keyword: A1,params: A3)
// o 'CLASS ClassName ClassConstructorParams' do ClassDeclaration.new(A2, null, []).set(keyword: A1,params: A3)
o('CLASS ClassName ClassBody',function() { return new ClassDeclaration(A2,null,A3).set({keyword: A1}); }),
o('CLASS ClassName',function() { return new ClassDeclaration(A2,null,[]).set({keyword: A1}); }),
o('CLASS ClassBody',function() { return new ClassDeclaration(null,null,A2).set({keyword: A1}); }),
// o 'CLASS ClassName ClassConstructorParams COMPARE Expression ClassBody' do ClassDeclaration.new(A2, A5, A6).set(keyword: A1, params: A3)
// o 'CLASS ClassName ClassConstructorParams COMPARE Expression' do ClassDeclaration.new(A2, A6, []).set(keyword: A1, params: A3)
o('CLASS ClassName COMPARE Expression',function() { return new ClassDeclaration(A2,A4,[]).set({keyword: A1,extends: A3}); }),
o('CLASS ClassName COMPARE Expression ClassBody',function() { return new ClassDeclaration(A2,A4,A5).set({keyword: A1,extends: A3}); }),
o('CLASS COMPARE Expression ClassBody',function() { return new ClassDeclaration(null,A3,A4).set({keyword: A1,extends: A2}); })
],
Class2: [
o('CLASS ClassStart',function() { return A2.set({keyword: A1}); }),
o('ABSTRACT Class',function() { return A2.set({abstract: A1}); }),
o('EXTEND Class',function() { return A2.set({extension: A1}); })
],
ClassStart2: [
// o 'CLASS ClassName ClassConstructorParams ClassBody' do ClassDeclaration.new(A2, null, A4).set(keyword: A1,params: A3)
// o 'CLASS ClassName ClassConstructorParams' do ClassDeclaration.new(A2, null, []).set(keyword: A1,params: A3)
o('ClassName ClassBody',function() { return new ClassDeclaration(A1,null,A2); }),
o('ClassName',function() { return new ClassDeclaration(A1,null,[]); }),
o('ClassBody',function() { return new ClassDeclaration(null,null,A1); }),
// o 'CLASS ClassName ClassConstructorParams COMPARE Expression ClassBody' do ClassDeclaration.new(A2, A5, A6).set(keyword: A1, params: A3)
// o 'CLASS ClassName ClassConstructorParams COMPARE Expression' do ClassDeclaration.new(A2, A6, []).set(keyword: A1, params: A3)
o('ClassName COMPARE Expression',function() { return new ClassDeclaration(A1,A3,[]).set({extends: A2}); }),
o('ClassName COMPARE Expression ClassBody',function() { return new ClassDeclaration(A1,A3,A4).set({extends: A2}); }),
o('COMPARE Expression ClassBody',function() { return new ClassDeclaration(null,A2,A3).set({extends: A1}); })
],
ClassName: [
o('DecoratorIdentifier'),
o('Identifier',function() { return new VarOrAccess(A1); }), // do ClassName.new(A1)
o('SymbolIdentifier',function() { return new Access('.',null,A1); }), // IndexAccess.new(A2,A1,A3) # AST.OP(A2,A1,A3)
o('ClassName . Identifier',function() { return AST.OP(A2,A1,A3); }),
o('ClassName . SymbolIdentifier',function() { return new IndexAccess(A2,A1,A3); }), // AST.OP(A2,A1,A3)
o('ClassName Type',function() { return AST.SETTYPE(A1,A2); })
],
ClassBody: [
o('INDENT OUTDENT',function() { return new ClassBody([]).indented(A1,A2); }),
o('INDENT ClassBodyBlock OUTDENT',function() { return A2.indented(A1,A3); }),
o('INDENT TERMINATOR ClassBodyBlock OUTDENT',function() { return A3.prebreak(A2).indented(A1,A4); }),
o('INDENT TERMINATOR OUTDENT',function() { return new ClassBody([]).indented(A1,A3); })
],
ClassBodyBlock: [
o('ClassBodyLine',function() { return new ClassBody([]).add(A1); }),
o('ClassBodyBlock Terminator ClassBodyLine',function() { return A1.break(A2).add(A3); }),
o('ClassBodyBlock Terminator',function() { return A1.break(A2); })
],
ClassBodyLine: [
o('Decorators'),
o('ClassDeclLine'),
o('Decorators ClassDeclLine',function() { return A1.concat([A2]); }),
o('CSSDeclaration'),
o('RELATION ClassName',function() { return new ClassRelation(A2).set({keyword: A1}); }),
o('Comment'),
o('Tag')
],
ClassDeclLine: [
o('STATIC ClassFieldDeclaration',function() { return A2.set({static: A1}); }),
o('STATIC MethodDeclaration',function() { return A2.set({static: A1}); }),
o('MethodDeclaration'),
o('ClassFieldDeclaration'),
o('PROTECTED ClassDeclLine',function() { return A2.set({protected: A1}); }),
o('DECLARE ClassDeclLine',function() { return AST.DECLARE(A2,A1); }),
o('ENV_FLAG ClassDeclLine',function() { return A2.addEnv(A1); })
],
ClassFieldDeclaration: [
o('ClassField ClassFieldOp Expression',function() { return A1.set({value: A3,op: A2}); }), // ClassField.new(A1, A3)
o('ClassField',function() { return A1; }),
o('ClassFieldDeclaration AS AccessorBody',function() { return A1.set({wrapper: A3}); }),
o('ClassFieldDeclaration FieldDescriptorFull',function() { return A1.set({wrapper: A2}); })
],
FieldDescriptor: [
o('DECORATOR',function() { return new Descriptor(A1); }), // kinda hacky, should be defined as something else
o('@ CALL_START Expression CALL_END',function() { return new Descriptor(A3); }),
// o 'FieldDescriptor ( )' do A1.add(ArgList.new([]))
// o 'FieldDescriptor ( ArgList )' do A1.add(A3,'!')
o('FieldDescriptor Arguments',function() { return A1.add(A2,'!'); }),
o('FieldDescriptor INDEX_START ArgList INDEX_END',function() { return A1.add(A3,'='); }),
o('FieldDescriptor . Identifier',function() { return A1.add(A3); })
// o 'FieldDescriptor = Value' do A1.add(A3,'value')
// o 'FieldDescriptor = DescriptorValue' do A1.add(A3,'value')
],
FieldDescriptorFull: [
o('FieldDescriptor'),
o('FieldDescriptor = Expression',function() { return A1.set({'default': A3}); }),
o('FieldDescriptor Do',function() { return A1.set({callback: A2}); })
],
AccessorBody: [
'FieldDescriptorFull',
'Value'
],
ClassFieldDecoration: [
o('ClassFieldDeclaration @ WatchBody',function() { return A1.set({watch: A3}); })
],
WatchBody: [
o('Block'),
o('Expression')
],
ClassFieldOp: [
'=',
'COMPOUND_ASSIGN'
],
ClassField: [
o('ClassFieldIdentifier',function() { return new ClassField(A1); }),
o('PROP ClassFieldIdentifier',function() { return new ClassProperty(A2).set({keyword: A1}); }),
o('ATTR ClassFieldIdentifier',function() { return new ClassAttribute(A2).set({keyword: A1}); }),
o('ClassField Type',function() { return AST.SETTYPE(A1,A2); }),
o('ClassField CALL_START CALL_END',function() { return A1.set({controller: A2}); })
],
ClassFieldIdentifier: [
o('Identifier'),
o('REGEX',function() { return new RegExpIdentifier(A1); }),
o('SymbolIdentifier')
],
ClassFieldBody: [
o('WATCH Expression Terminator',function() { return [A1,A2]; })
],
// Ordinary function invocation, or a chained series of calls.
Invocation: [
o('Value OptFuncExist Arguments',function() { return new Call(A1,A3,A2); }),
o('Value Do',function() { return A1.addBlock(A2); })
],
// An optional existence check on a function.
OptFuncExist: [
o('',function() { return false; }),
o('FUNC_EXIST',function() { return true; })
],
// The list of arguments to a function call.
Arguments: [
o('CALL_START CALL_END',function() { return new ArgList([]).setEnds(A1,A2); }),
o('CALL_START ArgList OptComma CALL_END',function() { return A2.setEnds(A1,A4); })
],
// A reference to the *this* current object.
This: [
o('THIS',function() { return new This(A1); }) // Value.new Literal.new 'this'
],
Self: [
o('SELF',function() { return new Self(A1); })
],
// The array literal.
Array: [
o('[ ]',function() { return new Arr(new ArgList([])).setEnds(A1,A2); }),
o('[ ArgList OptComma ]',function() { return new Arr(A2).setEnds(A1,A4); }),
o('Array Type',function() { return AST.SETTYPE(A1,A2); })
],
// Inclusive and exclusive range dots.
// should return the tokens instead
RangeDots: [
o('..',function() { return '..'; }),
o('...',function() { return '...'; })
],
Range: [
o('[ Expression RangeDots Expression ]',function() { return AST.OP(A3,A2,A4); }) // Range.new A2, A4, A3
],
// The **ArgList** is both the list of objects passed into a function call,
// as well as the contents of an array literal
// (i.e. comma-separated expressions). Newlines work as well.
ArgList: [
o('Arg',function() { return new ArgList([A1]); }),
o('ArgList , Arg',function() { return A1.add(A3); }),
o('ArgList OptComma Terminator Arg',function() { return A1.add(A3).add(A4); }),
o('ArgList OptComma TERMINATOR SEPARATOR Terminator Arg',function() { return A1.add(A5).add(A6); }),
o('INDENT ArgList OptComma Outdent',function() { return A2.indented(A1,A4); }),
o('ArgList OptComma INDENT ArgList OptComma Outdent',function() { return A1.concat(A4); })
],
Outdent: [
o('Terminator OUTDENT',function() { return A1; }), // we are going to change how this works
o('OUTDENT',function() { return A1; })
],
// Valid arguments are Blocks or Splats.
Arg: [
o('Expression'),
o('... Expression',function() { return new Splat(A2).set({keyword: A1}); }),
o('Splat'),
o('DO_PLACEHOLDER',function() { return new DoPlaceholder(A1); }),
o('Comment')
],
// 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('SimpleArgs , Expression',function() { return [].concat(A1,A3); })
],
// The variants of *try/catch/finally* exception handling blocks.
Try: [
o('TRY Block',function() { return new Try(A2); }),
o('TRY Block Catch',function() { return new Try(A2,A3); }),
o('TRY Block Finally',function() { return new Try(A2,null,A3); }),
o('TRY Block Catch Finally',function() { return new Try(A2,A3,A4); })
],
Finally: [
o('FINALLY Block',function() { return new Finally(A2); })
],
// A catch clause names its error and runs a block of code.
Catch: [
o('CATCH CATCH_VAR Block',function() { return new Catch(A3,A2); }),
o('CATCH Block',function() { return new Catch(A2,null); })
// o 'CATCH CATCH_VAR Expression' do Catch.new(A3,A2)
],
// Throw an exception object.
Throw: [
o('THROW Expression',function() { return new Throw(A2); })
],
// 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('( ExpressionList )',function() { return new Parens(A2,A1,A3); }),
o('( ExpressionList ) UNIT',function() { return new ExpressionWithUnit(new Parens(A2,A1,A3),A4); }),
o('Parenthetical Type',function() { return AST.SETTYPE(A1,A2); })
// o '( INDENT ExpressionList OUTDENT )' do Parens.new(A3,A1,A5)
],
// The condition portion of a while loop.
WhileSource: [
o('WHILE Expression',function() { return new While(A2,{keyword: A1}); }),
o('WHILE Expression WHEN Expression',function() { return new While(A2,{guard: A4,keyword: A1}); }),
o('UNTIL Expression',function() { return new While(A2,{invert: true,keyword: A1}); }),
o('UNTIL Expression WHEN Expression',function() { return new While(A2,{invert: true,guard: A4,keyword: A1}); })
],
// 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.
// should be solved by POST_WHILE instead
While: [
o('WhileSource Block',function() { return A1.addBody(A2); }),
o('Statement WhileSource',function() { return A2.addBody(Block.wrap([A1])); }),
o('Expression WhileSource',function() { return A2.addBody(Block.wrap([A1])); }),
o('Loop',function() { return A1; })
],
// should deprecate
Loop: [
o('LOOP Block',function() { return new While(new Literal('true',{keyword: A1})).addBody(A2); }),
o('LOOP Expression',function() { return new While(new Literal('true',{keyword: A1})).addBody(Block.wrap([A2])); })
],
// 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() { return A2.addBody([A1]); }),
o('Expression ForBody',function() { return A2.addBody([A1]); }),
o('ForBody Block',function() { return A1.addBody(A2); }),
o('ForBody Block ELSE Block',function() { return A1.addBody(A2).addElse(A4); })
],
ForKeyword: [
o('FOR'),
o('POST_FOR')
],
ForBody: [
o('ForKeyword Range',function() { return {source: new ValueNode(A2)}; }),
o('ForStart ForSource',function() { return A2.configure({own: A1.own,await: (A1.await),name: A1[0],index: A1[1],keyword: A1.keyword,params: A1}); })
],
ForStart: [
o('ForKeyword ForVariables',function() { return (A2.keyword = A1) && A2; }),
// should link to the actual keyword instead
o('ForKeyword AWAIT ForVariables',function() { return (A3.await = A2) && (A3.keyword = A1) && A3; }),
o('ForKeyword OWN ForVariables',function() { return (A3.own = true) && (A3.keyword = A1) && A3; })
],
// An array of all accepted values for a variable inside the loop.
// This enables support for pattern matching.
ForValue: [
o('Identifier'),
o('Identifier Type',function() { return AST.SETTYPE(A1,A2); }),
o('Array'), // do ValueNode.new A1
o('Object') // do ValueNode.new A1
],
// 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 [A1]; }),
o('ForValue , ForValue',function() { return [A1,A3]; }),
o('ForValue , ForValue , ForValue',function() { return [A1,A3,A5]; })
],
// 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 new ForIn({source: A2}); }),
o('FOROF Expression',function() { return new ForOf({source: A2,object: true}); }),
o('FORIN Expression WHEN Expression',function() { return new ForIn({source: A2,guard: A4}); }),
o('FOROF Expression WHEN Expression',function() { return new ForOf({source: A2,guard: A4,object: true}); }),
o('FORIN Expression BY Expression',function() { return new ForIn({source: A2,step: A4}); }),
o('FORIN Expression WHEN Expression BY Expression',function() { return new ForIn({source: A2,guard: A4,step: A6}); }),
o('FORIN Expression BY Expression WHEN Expression',function() { return new ForIn({source: A2,step: A4,guard: A6}); })
],
Switch: [
o('SWITCH Expression INDENT Whens OUTDENT',function() { return new Switch(A2,A4); }),
o('SWITCH Expression INDENT Whens ELSE Block Outdent',function() { return new Switch(A2,A4,A6); }),
o('SWITCH INDENT Whens OUTDENT',function() { return new Switch(null,A3); }),
o('SWITCH INDENT Whens ELSE Block OUTDENT',function() { return new Switch(null,A3,A5); })
],
Whens: [
o('When'),
o('Whens When',function() { return A1.concat(A2); })
],
// An individual **When** clause, with action.
When: [
o('LEADI