UNPKG

imba

Version:

Intuitive and powerful language for building webapps that fly

1,290 lines (1,104 loc) 55.8 kB
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