text: // Generated by CoffeeScript 2.0.1
  (function() {
    // The CoffeeScript parser is generated by [Jison](https://github.com/zaach/jison)
    // from this grammar file. Jison is a bottom-up parser generator, similar in
    // style to [Bison](http://www.gnu.org/software/bison), implemented in JavaScript.
    // It can recognize [LALR(1), LR(0), SLR(1), and LR(1)](https://en.wikipedia.org/wiki/LR_grammar)
    // type grammars. To create the Jison parser, we list the pattern to match
    // on the left-hand side, and the action to take (usually the creation of syntax
    // tree nodes) on the right. As the parser runs, it
    // shifts tokens from our token stream, from left to right, and
    // [attempts to match](https://en.wikipedia.org/wiki/Bottom-up_parsing)
    // the token sequence against the rules below. When a match can be made, it
    // reduces into the [nonterminal](https://en.wikipedia.org/wiki/Terminal_and_nonterminal_symbols)
    // (the enclosing name at the top), and we proceed from there.
  
    // If you run the `cake build:parser` command, Jison constructs a parse table
    // from our rules and saves it into `lib/parser.js`.
  
    // The only dependency is on the **Jison.Parser**.
    var Parser, alt, alternatives, grammar, name, o, operators, token, tokens, unwrap;
  
    ({Parser} = require('jison'));
  
    // Jison DSL
    // ---------
  
    // Since we're going to be wrapped in a function by Jison in any case, if our
    // action immediately returns a value, we can optimize by removing the function
    // wrapper and just returning the value directly.
    unwrap = /^function\s*\(\)\s*\{\s*return\s*([\s\S]*);\s*\}/;
  
    // Our handy DSL for Jison grammar generation, thanks to
    // [Tim Caswell](https://github.com/creationix). For every rule in the grammar,
    // we pass the pattern-defining string, the action to run, and extra options,
    // optionally. If no action is specified, we simply pass the value of the
    // previous nonterminal.
    o = function(patternString, action, options) {
      var getAddDataToNodeFunctionString, match, patternCount, performActionFunctionString;
      patternString = patternString.replace(/\s{2,}/g, ' ');
      patternCount = patternString.split(' ').length;
      if (action) {
        action = (match = unwrap.exec(action)) ? match[1] : `(${action}())`;
        // All runtime functions we need are defined on `yy`
        action = action.replace(/\bnew /g, '$&yy.');
        action = action.replace(/\b(?:Block\.wrap|extend)\b/g, 'yy.$&');
        // Returns strings of functions to add to `parser.js` which add extra data
        // that nodes may have, such as comments or location data. Location data
        // is added to the first parameter passed in, and the parameter is returned.
        // If the parameter is not a node, it will just be passed through unaffected.
        getAddDataToNodeFunctionString = function(first, last) {
          return `yy.addDataToNode(yy, @${first}${(last ? `, @${last}` : '')})`;
        };
        action = action.replace(/LOC\(([0-9]*)\)/g, getAddDataToNodeFunctionString('$1'));
        action = action.replace(/LOC\(([0-9]*),\s*([0-9]*)\)/g, getAddDataToNodeFunctionString('$1', '$2'));
        performActionFunctionString = `$$ = ${getAddDataToNodeFunctionString(1, patternCount)}(${action});`;
      } else {
        performActionFunctionString = '$$ = $1;';
      }
      return [patternString, performActionFunctionString, options];
    };
  
    // Grammatical Rules
    // -----------------
  
    // In all of the rules that follow, you'll see the name of the nonterminal as
    // the key to a list of alternative matches. With each match's action, the
    // dollar-sign variables are provided by Jison as references to the value of
    // their numeric position, so in this rule:
  
    //     'Expression UNLESS Expression'
  
    // `$1` would be the value of the first `Expression`, `$2` would be the token
    // for the `UNLESS` terminal, and `$3` would be the value of the second
    // `Expression`.
    grammar = {
      // The **Root** is the top-level node in the syntax tree. Since we parse bottom-up,
      // all parsing must end here.
      Root: [
        o('',
        function() {
          return new Block;
        }),
        o('Body')
      ],
      // Any list of statements and expressions, separated by line breaks or semicolons.
      Body: [
        o('Line',
        function() {
          return Block.wrap([$1]);
        }),
        o('Body TERMINATOR Line',
        function() {
          return $1.push($3);
        }),
        o('Body TERMINATOR')
      ],
      // Block and statements, which make up a line in a body. YieldReturn is a
      // statement, but not included in Statement because that results in an ambiguous
      // grammar.
      Line: [o('Expression'), o('Statement'), o('FuncDirective')],
      FuncDirective: [o('YieldReturn'), o('AwaitReturn')],
      // Pure statements which cannot be expressions.
      Statement: [
        o('Return'),
        o('STATEMENT',
        function() {
          return new StatementLiteral($1);
        }),
        o('Import'),
        o('Export')
      ],
      // All the different types of expressions in our language. The basic unit of
      // CoffeeScript is the **Expression** -- everything that can be an expression
      // is one. Blocks serve as the building blocks of many other rules, making
      // them somewhat circular.
      Expression: [o('Value'), o('Code'), o('Operation'), o('Assign'), o('If'), o('Try'), o('While'), o('For'), o('Switch'), o('Class'), o('Throw'), o('Yield')],
      Yield: [
        o('YIELD',
        function() {
          return new Op($1,
        new Value(new Literal('')));
        }),
        o('YIELD Expression',
        function() {
          return new Op($1,
        $2);
        }),
        o('YIELD FROM Expression',
        function() {
          return new Op($1.concat($2),
        $3);
        })
      ],
      // An indented block of expressions. Note that the [Rewriter](rewriter.html)
      // will convert some postfix forms into blocks for us, by adjusting the
      // token stream.
      Block: [
        o('INDENT OUTDENT',
        function() {
          return new Block;
        }),
        o('INDENT Body OUTDENT',
        function() {
          return $2;
        })
      ],
      Identifier: [
        o('IDENTIFIER',
        function() {
          return new IdentifierLiteral($1);
        }),
        o('CSX_TAG',
        function() {
          return new CSXTag($1);
        })
      ],
      Property: [
        o('PROPERTY',
        function() {
          return new PropertyName($1);
        })
      ],
      // Alphanumerics are separated from the other **Literal** matchers because
      // they can also serve as keys in object literals.
      AlphaNumeric: [
        o('NUMBER',
        function() {
          return new NumberLiteral($1);
        }),
        o('String')
      ],
      String: [
        o('STRING',
        function() {
          return new StringLiteral($1);
        }),
        o('STRING_START Body STRING_END',
        function() {
          return new StringWithInterpolations($2);
        })
      ],
      Regex: [
        o('REGEX',
        function() {
          return new RegexLiteral($1);
        }),
        o('REGEX_START Invocation REGEX_END',
        function() {
          return new RegexWithInterpolations($2.args);
        })
      ],
      // All of our immediate values. Generally these can be passed straight
      // through and printed to JavaScript.
      Literal: [
        o('AlphaNumeric'),
        o('JS',
        function() {
          return new PassthroughLiteral($1);
        }),
        o('Regex'),
        o('UNDEFINED',
        function() {
          return new UndefinedLiteral($1);
        }),
        o('NULL',
        function() {
          return new NullLiteral($1);
        }),
        o('BOOL',
        function() {
          return new BooleanLiteral($1);
        }),
        o('INFINITY',
        function() {
          return new InfinityLiteral($1);
        }),
        o('NAN',
        function() {
          return new NaNLiteral($1);
        })
      ],
      // Assignment of a variable, property, or index to a value.
      Assign: [
        o('Assignable = Expression',
        function() {
          return new Assign($1,
        $3);
        }),
        o('Assignable = TERMINATOR Expression',
        function() {
          return new Assign($1,
        $4);
        }),
        o('Assignable = INDENT Expression OUTDENT',
        function() {
          return new Assign($1,
        $4);
        })
      ],
      // Assignment when it happens within an object literal. The difference from
      // the ordinary **Assign** is that these allow numbers and strings as keys.
      AssignObj: [
        o('ObjAssignable',
        function() {
          return new Value($1);
        }),
        o('ObjRestValue'),
        o('ObjAssignable : Expression',
        function() {
          return new Assign(LOC(1)(new Value($1)),
        $3,
        'object',
        {
            operatorToken: LOC(2)(new Literal($2))
          });
        }),
        o('ObjAssignable : INDENT Expression OUTDENT',
        function() {
          return new Assign(LOC(1)(new Value($1)),
        $4,
        'object',
        {
            operatorToken: LOC(2)(new Literal($2))
          });
        }),
        o('SimpleObjAssignable = Expression',
        function() {
          return new Assign(LOC(1)(new Value($1)),
        $3,
        null,
        {
            operatorToken: LOC(2)(new Literal($2))
          });
        }),
        o('SimpleObjAssignable = INDENT Expression OUTDENT',
        function() {
          return new Assign(LOC(1)(new Value($1)),
        $4,
        null,
        {
            operatorToken: LOC(2)(new Literal($2))
          });
        })
      ],
      SimpleObjAssignable: [o('Identifier'), o('Property'), o('ThisProperty')],
      ObjAssignable: [o('SimpleObjAssignable'), o('AlphaNumeric')],
      // Object literal spread properties.
      ObjRestValue: [
        o('SimpleObjAssignable ...',
        function() {
          return new Splat(new Value($1));
        }),
        o('... SimpleObjAssignable',
        function() {
          return new Splat(new Value($2));
        }),
        o('ObjSpreadExpr ...',
        function() {
          return new Splat($1);
        }),
        o('... ObjSpreadExpr',
        function() {
          return new Splat($2);
        })
      ],
      ObjSpreadExpr: [
        o('ObjSpreadIdentifier'),
        o('Object'),
        o('Parenthetical'),
        o('Super'),
        o('This'),
        o('SUPER Arguments',
        function() {
          return new SuperCall(LOC(1)(new Super),
        $2,
        false,
        $1);
        }),
        o('SimpleObjAssignable Arguments',
        function() {
          return new Call(new Value($1),
        $2);
        }),
        o('ObjSpreadExpr Arguments',
        function() {
          return new Call($1,
        $2);
        })
      ],
      ObjSpreadIdentifier: [
        o('SimpleObjAssignable ObjSpreadAccessor',
        function() {
          return (new Value($1)).add($2);
        }),
        o('ObjSpreadExpr ObjSpreadAccessor',
        function() {
          return (new Value($1)).add($2);
        })
      ],
      ObjSpreadAccessor: [
        o('. Property',
        function() {
          return new Access($2);
        }),
        o('INDEX_START IndexValue INDEX_END',
        function() {
          return $2;
        })
      ],
      // A return statement from a function body.
      Return: [
        o('RETURN Expression',
        function() {
          return new Return($2);
        }),
        o('RETURN INDENT Object OUTDENT',
        function() {
          return new Return(new Value($3));
        }),
        o('RETURN',
        function() {
          return new Return;
        })
      ],
      YieldReturn: [
        o('YIELD RETURN Expression',
        function() {
          return new YieldReturn($3);
        }),
        o('YIELD RETURN',
        function() {
          return new YieldReturn;
        })
      ],
      AwaitReturn: [
        o('AWAIT RETURN Expression',
        function() {
          return new AwaitReturn($3);
        }),
        o('AWAIT RETURN',
        function() {
          return new AwaitReturn;
        })
      ],
      // The **Code** node is the function literal. It's defined by an indented block
      // of **Block** preceded by a function arrow, with an optional parameter list.
      Code: [
        o('PARAM_START ParamList PARAM_END FuncGlyph Block',
        function() {
          return new Code($2,
        $5,
        $4,
        LOC(1)(new Literal($1)));
        }),
        o('FuncGlyph Block',
        function() {
          return new Code([],
        $2,
        $1);
        })
      ],
      // CoffeeScript has two different symbols for functions. `->` is for ordinary
      // functions, and `=>` is for functions bound to the current value of *this*.
      FuncGlyph: [
        o('->',
        function() {
          return new FuncGlyph($1);
        }),
        o('=>',
        function() {
          return new FuncGlyph($1);
        })
      ],
      // An optional, trailing comma.
      OptComma: [o(''), o(',')],
      // The list of parameters that a function accepts can be of any length.
      ParamList: [
        o('',
        function() {
          return [];
        }),
        o('Param',
        function() {
          return [$1];
        }),
        o('ParamList , Param',
        function() {
          return $1.concat($3);
        }),
        o('ParamList OptComma TERMINATOR Param',
        function() {
          return $1.concat($4);
        }),
        o('ParamList OptComma INDENT ParamList OptComma OUTDENT',
        function() {
          return $1.concat($4);
        })
      ],
      // A single parameter in a function definition can be ordinary, or a splat
      // that hoovers up the remaining arguments.
      Param: [
        o('ParamVar',
        function() {
          return new Param($1);
        }),
        o('ParamVar ...',
        function() {
          return new Param($1,
        null,
        true);
        }),
        o('... ParamVar',
        function() {
          return new Param($2,
        null,
        true);
        }),
        o('ParamVar = Expression',
        function() {
          return new Param($1,
        $3);
        }),
        o('...',
        function() {
          return new Expansion;
        })
      ],
      // Function Parameters
      ParamVar: [o('Identifier'), o('ThisProperty'), o('Array'), o('Object')],
      // A splat that occurs outside of a parameter list.
      Splat: [
        o('Expression ...',
        function() {
          return new Splat($1);
        }),
        o('... Expression',
        function() {
          return new Splat($2);
        })
      ],
      // Variables and properties that can be assigned to.
      SimpleAssignable: [
        o('Identifier',
        function() {
          return new Value($1);
        }),
        o('Value Accessor',
        function() {
          return $1.add($2);
        }),
        o('Code Accessor',
        function() {
          return new Value($1).add($2);
        }),
        o('ThisProperty')
      ],
      // Everything that can be assigned to.
      Assignable: [
        o('SimpleAssignable'),
        o('Array',
        function() {
          return new Value($1);
        }),
        o('Object',
        function() {
          return new Value($1);
        })
      ],
      // The types of things that can be treated as values -- assigned to, invoked
      // as functions, indexed into, named as a class, etc.
      Value: [
        o('Assignable'),
        o('Literal',
        function() {
          return new Value($1);
        }),
        o('Parenthetical',
        function() {
          return new Value($1);
        }),
        o('Range',
        function() {
          return new Value($1);
        }),
        o('Invocation',
        function() {
          return new Value($1);
        }),
        o('This'),
        o('Super',
        function() {
          return new Value($1);
        })
      ],
      // A `super`-based expression that can be used as a value.
      Super: [
        o('SUPER . Property',
        function() {
          return new Super(LOC(3)(new Access($3)),
        [],
        false,
        $1);
        }),
        o('SUPER INDEX_START Expression INDEX_END',
        function() {
          return new Super(LOC(3)(new Index($3)),
        [],
        false,
        $1);
        })
      ],
      // The general group of accessors into an object, by property, by prototype
      // or by array index or slice.
      Accessor: [
        o('.  Property',
        function() {
          return new Access($2);
        }),
        o('?. Property',
        function() {
          return new Access($2,
        'soak');
        }),
        o(':: Property',
        function() {
          return [LOC(1)(new Access(new PropertyName('prototype'))),
        LOC(2)(new Access($2))];
        }),
        o('?:: Property',
        function() {
          return [LOC(1)(new Access(new PropertyName('prototype'),
        'soak')),
        LOC(2)(new Access($2))];
        }),
        o('::',
        function() {
          return new Access(new PropertyName('prototype'));
        }),
        o('Index')
      ],
      // Indexing into an object or array using bracket notation.
      Index: [
        o('INDEX_START IndexValue INDEX_END',
        function() {
          return $2;
        }),
        o('INDEX_SOAK  Index',
        function() {
          return extend($2,
        {
            soak: true
          });
        })
      ],
      IndexValue: [
        o('Expression',
        function() {
          return new Index($1);
        }),
        o('Slice',
        function() {
          return new Slice($1);
        })
      ],
      // In CoffeeScript, an object literal is simply a list of assignments.
      Object: [
        o('{ AssignList OptComma }',
        function() {
          return new Obj($2,
        $1.generated);
        })
      ],
      // Assignment of properties within an object literal can be separated by
      // comma, as in JavaScript, or simply by newline.
      AssignList: [
        o('',
        function() {
          return [];
        }),
        o('AssignObj',
        function() {
          return [$1];
        }),
        o('AssignList , AssignObj',
        function() {
          return $1.concat($3);
        }),
        o('AssignList OptComma TERMINATOR AssignObj',
        function() {
          return $1.concat($4);
        }),
        o('AssignList OptComma INDENT AssignList OptComma OUTDENT',
        function() {
          return $1.concat($4);
        })
      ],
      // Class definitions have optional bodies of prototype property assignments,
      // and optional references to the superclass.
      Class: [
        o('CLASS',
        function() {
          return new Class;
        }),
        o('CLASS Block',
        function() {
          return new Class(null,
        null,
        $2);
        }),
        o('CLASS EXTENDS Expression',
        function() {
          return new Class(null,
        $3);
        }),
        o('CLASS EXTENDS Expression Block',
        function() {
          return new Class(null,
        $3,
        $4);
        }),
        o('CLASS SimpleAssignable',
        function() {
          return new Class($2);
        }),
        o('CLASS SimpleAssignable Block',
        function() {
          return new Class($2,
        null,
        $3);
        }),
        o('CLASS SimpleAssignable EXTENDS Expression',
        function() {
          return new Class($2,
        $4);
        }),
        o('CLASS SimpleAssignable EXTENDS Expression Block',
        function() {
          return new Class($2,
        $4,
        $5);
        })
      ],
      Import: [
        o('IMPORT String',
        function() {
          return new ImportDeclaration(null,
        $2);
        }),
        o('IMPORT ImportDefaultSpecifier FROM String',
        function() {
          return new ImportDeclaration(new ImportClause($2,
        null),
        $4);
        }),
        o('IMPORT ImportNamespaceSpecifier FROM String',
        function() {
          return new ImportDeclaration(new ImportClause(null,
        $2),
        $4);
        }),
        o('IMPORT { } FROM String',
        function() {
          return new ImportDeclaration(new ImportClause(null,
        new ImportSpecifierList([])),
        $5);
        }),
        o('IMPORT { ImportSpecifierList OptComma } FROM String',
        function() {
          return new ImportDeclaration(new ImportClause(null,
        new ImportSpecifierList($3)),
        $7);
        }),
        o('IMPORT ImportDefaultSpecifier , ImportNamespaceSpecifier FROM String',
        function() {
          return new ImportDeclaration(new ImportClause($2,
        $4),
        $6);
        }),
        o('IMPORT ImportDefaultSpecifier , { ImportSpecifierList OptComma } FROM String',
        function() {
          return new ImportDeclaration(new ImportClause($2,
        new ImportSpecifierList($5)),
        $9);
        })
      ],
      ImportSpecifierList: [
        o('ImportSpecifier',
        function() {
          return [$1];
        }),
        o('ImportSpecifierList , ImportSpecifier',
        function() {
          return $1.concat($3);
        }),
        o('ImportSpecifierList OptComma TERMINATOR ImportSpecifier',
        function() {
          return $1.concat($4);
        }),
        o('INDENT ImportSpecifierList OptComma OUTDENT',
        function() {
          return $2;
        }),
        o('ImportSpecifierList OptComma INDENT ImportSpecifierList OptComma OUTDENT',
        function() {
          return $1.concat($4);
        })
      ],
      ImportSpecifier: [
        o('Identifier',
        function() {
          return new ImportSpecifier($1);
        }),
        o('Identifier AS Identifier',
        function() {
          return new ImportSpecifier($1,
        $3);
        }),
        o('DEFAULT',
        function() {
          return new ImportSpecifier(new Literal($1));
        }),
        o('DEFAULT AS Identifier',
        function() {
          return new ImportSpecifier(new Literal($1),
        $3);
        })
      ],
      ImportDefaultSpecifier: [
        o('Identifier',
        function() {
          return new ImportDefaultSpecifier($1);
        })
      ],
      ImportNamespaceSpecifier: [
        o('IMPORT_ALL AS Identifier',
        function() {
          return new ImportNamespaceSpecifier(new Literal($1),
        $3);
        })
      ],
      Export: [
        o('EXPORT { }',
        function() {
          return new ExportNamedDeclaration(new ExportSpecifierList([]));
        }),
        o('EXPORT { ExportSpecifierList OptComma }',
        function() {
          return new ExportNamedDeclaration(new ExportSpecifierList($3));
        }),
        o('EXPORT Class',
        function() {
          return new ExportNamedDeclaration($2);
        }),
        o('EXPORT Identifier = Expression',
        function() {
          return new ExportNamedDeclaration(new Assign($2,
        $4,
        null,
        {
            moduleDeclaration: 'export'
          }));
        }),
        o('EXPORT Identifier = TERMINATOR Expression',
        function() {
          return new ExportNamedDeclaration(new Assign($2,
        $5,
        null,
        {
            moduleDeclaration: 'export'
          }));
        }),
        o('EXPORT Identifier = INDENT Expression OUTDENT',
        function() {
          return new ExportNamedDeclaration(new Assign($2,
        $5,
        null,
        {
            moduleDeclaration: 'export'
          }));
        }),
        o('EXPORT DEFAULT Expression',
        function() {
          return new ExportDefaultDeclaration($3);
        }),
        o('EXPORT EXPORT_ALL FROM String',
        function() {
          return new ExportAllDeclaration(new Literal($2),
        $4);
        }),
        o('EXPORT { ExportSpecifierList OptComma } FROM String',
        function() {
          return new ExportNamedDeclaration(new ExportSpecifierList($3),
        $7);
        })
      ],
      ExportSpecifierList: [
        o('ExportSpecifier',
        function() {
          return [$1];
        }),
        o('ExportSpecifierList , ExportSpecifier',
        function() {
          return $1.concat($3);
        }),
        o('ExportSpecifierList OptComma TERMINATOR ExportSpecifier',
        function() {
          return $1.concat($4);
        }),
        o('INDENT ExportSpecifierList OptComma OUTDENT',
        function() {
          return $2;
        }),
        o('ExportSpecifierList OptComma INDENT ExportSpecifierList OptComma OUTDENT',
        function() {
          return $1.concat($4);
        })
      ],
      ExportSpecifier: [
        o('Identifier',
        function() {
          return new ExportSpecifier($1);
        }),
        o('Identifier AS Identifier',
        function() {
          return new ExportSpecifier($1,
        $3);
        }),
        o('Identifier AS DEFAULT',
        function() {
          return new ExportSpecifier($1,
        new Literal($3));
        }),
        o('DEFAULT',
        function() {
          return new ExportSpecifier(new Literal($1));
        }),
        o('DEFAULT AS Identifier',
        function() {
          return new ExportSpecifier(new Literal($1),
        $3);
        })
      ],
      // Ordinary function invocation, or a chained series of calls.
      Invocation: [
        o('Value OptFuncExist String',
        function() {
          return new TaggedTemplateCall($1,
        $3,
        $2);
        }),
        o('Value OptFuncExist Arguments',
        function() {
          return new Call($1,
        $3,
        $2);
        }),
        o('SUPER OptFuncExist Arguments',
        function() {
          return new SuperCall(LOC(1)(new Super),
        $3,
        $2,
        $1);
        })
      ],
      // 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 [];
        }),
        o('CALL_START ArgList OptComma CALL_END',
        function() {
          return $2;
        })
      ],
      // A reference to the *this* current object.
      This: [
        o('THIS',
        function() {
          return new Value(new ThisLiteral($1));
        }),
        o('@',
        function() {
          return new Value(new ThisLiteral($1));
        })
      ],
      // A reference to a property on *this*.
      ThisProperty: [
        o('@ Property',
        function() {
          return new Value(LOC(1)(new ThisLiteral($1)),
        [LOC(2)(new Access($2))],
        'this');
        })
      ],
      // The array literal.
      Array: [
        o('[ ]',
        function() {
          return new Arr([]);
        }),
        o('[ ArgList OptComma ]',
        function() {
          return new Arr($2);
        })
      ],
      // Inclusive and exclusive range dots.
      RangeDots: [
        o('..',
        function() {
          return 'inclusive';
        }),
        o('...',
        function() {
          return 'exclusive';
        })
      ],
      // The CoffeeScript range literal.
      Range: [
        o('[ Expression RangeDots Expression ]',
        function() {
          return new Range($2,
        $4,
        $3);
        })
      ],
      // Array slice literals.
      Slice: [
        o('Expression RangeDots Expression',
        function() {
          return new Range($1,
        $3,
        $2);
        }),
        o('Expression RangeDots',
        function() {
          return new Range($1,
        null,
        $2);
        }),
        o('RangeDots Expression',
        function() {
          return new Range(null,
        $2,
        $1);
        }),
        o('RangeDots',
        function() {
          return new Range(null,
        null,
        $1);
        })
      ],
      // 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 [$1];
        }),
        o('ArgList , Arg',
        function() {
          return $1.concat($3);
        }),
        o('ArgList OptComma TERMINATOR Arg',
        function() {
          return $1.concat($4);
        }),
        o('INDENT ArgList OptComma OUTDENT',
        function() {
          return $2;
        }),
        o('ArgList OptComma INDENT ArgList OptComma OUTDENT',
        function() {
          return $1.concat($4);
        })
      ],
      // Valid arguments are Blocks or Splats.
      Arg: [
        o('Expression'),
        o('Splat'),
        o('...',
        function() {
          return new Expansion;
        })
      ],
      // 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($1,
        $3);
        })
      ],
      // The variants of *try/catch/finally* exception handling blocks.
      Try: [
        o('TRY Block',
        function() {
          return new Try($2);
        }),
        o('TRY Block Catch',
        function() {
          return new Try($2,
        $3[0],
        $3[1]);
        }),
        o('TRY Block FINALLY Block',
        function() {
          return new Try($2,
        null,
        null,
        $4);
        }),
        o('TRY Block Catch FINALLY Block',
        function() {
          return new Try($2,
        $3[0],
        $3[1],
        $5);
        })
      ],
      // A catch clause names its error and runs a block of code.
      Catch: [
        o('CATCH Identifier Block',
        function() {
          return [$2,
        $3];
        }),
        o('CATCH Object Block',
        function() {
          return [LOC(2)(new Value($2)),
        $3];
        }),
        o('CATCH Block',
        function() {
          return [null,
        $2];
        })
      ],
      // Throw an exception object.
      Throw: [
        o('THROW Expression',
        function() {
          return new Throw($2);
        }),
        o('THROW INDENT Object OUTDENT',
        function() {
          return new Throw(new Value($3));
        })
      ],
      // Parenthetical expressions. Note that the **Parenthetical** is a **Value**,
      // not an **Expression**, so if you need to use an expression in a place
      // where only values are accepted, wrapping it in parentheses will always do
      // the trick.
      Parenthetical: [
        o('( Body )',
        function() {
          return new Parens($2);
        }),
        o('( INDENT Body OUTDENT )',
        function() {
          return new Parens($3);
        })
      ],
      // The condition portion of a while loop.
      WhileSource: [
        o('WHILE Expression',
        function() {
          return new While($2);
        }),
        o('WHILE Expression WHEN Expression',
        function() {
          return new While($2,
        {
            guard: $4
          });
        }),
        o('UNTIL Expression',
        function() {
          return new While($2,
        {
            invert: true
          });
        }),
        o('UNTIL Expression WHEN Expression',
        function() {
          return new While($2,
        {
            invert: true,
            guard: $4
          });
        })
      ],
      // The while loop can either be normal, with a block of expressions to execute,
      // or postfix, with a single expression. There is no do..while.
      While: [
        o('WhileSource Block',
        function() {
          return $1.addBody($2);
        }),
        o('Statement  WhileSource',
        function() {
          return $2.addBody(LOC(1)(Block.wrap([$1])));
        }),
        o('Expression WhileSource',
        function() {
          return $2.addBody(LOC(1)(Block.wrap([$1])));
        }),
        o('Loop',
        function() {
          return $1;
        })
      ],
      Loop: [
        o('LOOP Block',
        function() {
          return new While(LOC(1)(new BooleanLiteral('true'))).addBody($2);
        }),
        o('LOOP Expression',
        function() {
          return new While(LOC(1)(new BooleanLiteral('true'))).addBody(LOC(2)(Block.wrap([$2])));
        })
      ],
      // Array, object, and range comprehensions, at the most generic level.
      // Comprehensions can either be normal, with a block of expressions to execute,
      // or postfix, with a single expression.
      For: [
        o('Statement  ForBody',
        function() {
          return new For($1,
        $2);
        }),
        o('Expression ForBody',
        function() {
          return new For($1,
        $2);
        }),
        o('ForBody    Block',
        function() {
          return new For($2,
        $1);
        })
      ],
      ForBody: [
        o('FOR Range',
        function() {
          return {
            source: LOC(2)(new Value($2))
          };
        }),
        o('FOR Range BY Expression',
        function() {
          return {
            source: LOC(2)(new Value($2)),
            step: $4
          };
        }),
        o('ForStart ForSource',
        function() {
          $2.own = $1.own;
          $2.ownTag = $1.ownTag;
          $2.name = $1[0];
          $2.index = $1[1];
          return $2;
        })
      ],
      ForStart: [
        o('FOR ForVariables',
        function() {
          return $2;
        }),
        o('FOR OWN ForVariables',
        function() {
          $3.own = true;
          $3.ownTag = LOC(2)(new Literal($2));
          return $3;
        })
      ],
      // An array of all accepted values for a variable inside the loop.
      // This enables support for pattern matching.
      ForValue: [
        o('Identifier'),
        o('ThisProperty'),
        o('Array',
        function() {
          return new Value($1);
        }),
        o('Object',
        function() {
          return new Value($1);
        })
      ],
      // An array or range comprehension has variables for the current element
      // and (optional) reference to the current index. Or, *key, value*, in the case
      // of object comprehensions.
      ForVariables: [
        o('ForValue',
        function() {
          return [$1];
        }),
        o('ForValue , ForValue',
        function() {
          return [$1,
        $3];
        })
      ],
      // The source of a comprehension is an array or object with an optional guard
      // clause. If it's an array comprehension, you can also choose to step through
      // in fixed-size increments.
      ForSource: [
        o('FORIN Expression',
        function() {
          return {
            source: $2
          };
        }),
        o('FOROF Expression',
        function() {
          return {
            source: $2,
            object: true
          };
        }),
        o('FORIN Expression WHEN Expression',
        function() {
          return {
            source: $2,
            guard: $4
          };
        }),
        o('FOROF Expression WHEN Expression',
        function() {
          return {
            source: $2,
            guard: $4,
            object: true
          };
        }),
        o('FORIN Expression BY Expression',
        function() {
          return {
            source: $2,
            step: $4
          };
        }),
        o('FORIN Expression WHEN Expression BY Expression',
        function() {
          return {
            source: $2,
            guard: $4,
            step: $6
          };
        }),
        o('FORIN Expression BY Expression WHEN Expression',
        function() {
          return {
            source: $2,
            step: $4,
            guard: $6
          };
        }),
        o('FORFROM Expression',
        function() {
          return {
            source: $2,
            from: true
          };
        }),
        o('FORFROM Expression WHEN Expression',
        function() {
          return {
            source: $2,
            guard: $4,
            from: true
          };
        })
      ],
      Switch: [
        o('SWITCH Expression INDENT Whens OUTDENT',
        function() {
          return new Switch($2,
        $4);
        }),
        o('SWITCH Expression INDENT Whens ELSE Block OUTDENT',
        function() {
          return new Switch($2,
        $4,
        $6);
        }),
        o('SWITCH INDENT Whens OUTDENT',
        function() {
          return new Switch(null,
        $3);
        }),
        o('SWITCH INDENT Whens ELSE Block OUTDENT',
        function() {
          return new Switch(null,
        $3,
        $5);
        })
      ],
      Whens: [
        o('When'),
        o('Whens When',
        function() {
          return $1.concat($2);
        })
      ],
      // An individual **When** clause, with action.
      When: [
        o('LEADING_WHEN SimpleArgs Block',
        function() {
          return [[$2,
        $3]];
        }),
        o('LEADING_WHEN SimpleArgs Block TERMINATOR',
        function() {
          return [[$2,
        $3]];
        })
      ],
      // The most basic form of *if* is a condition and an action. The following
      // if-related rules are broken up along these lines in order to avoid
      // ambiguity.
      IfBlock: [
        o('IF Expression Block',
        function() {
          return new If($2,
        $3,
        {
            type: $1
          });
        }),
        o('IfBlock ELSE IF Expression Block',
        function() {
          return $1.addElse(LOC(3,
        5)(new If($4,
        $5,
        {
            type: $3
          })));
        })
      ],
      // The full complement of *if* expressions, including postfix one-liner
      // *if* and *unless*.
      If: [
        o('IfBlock'),
        o('IfBlock ELSE Block',
        function() {
          return $1.addElse($3);
        }),
        o('Statement  POST_IF Expression',
        function() {
          return new If($3,
        LOC(1)(Block.wrap([$1])),
        {
            type: $2,
            statement: true
          });
        }),
        o('Expression POST_IF Expression',
        function() {
          return new If($3,
        LOC(1)(Block.wrap([$1])),
        {
            type: $2,
            statement: true
          });
        })
      ],
      // Arithmetic and logical operators, working on one or more operands.
      // Here they are grouped by order of precedence. The actual precedence rules
      // are defined at the bottom of the page. It would be shorter if we could
      // combine most of these rules into a single generic *Operand OpSymbol Operand*
      // -type rule, but in order to make the precedence binding possible, separate
      // rules are necessary.
      Operation: [
        o('UNARY Expression',
        function() {
          return new Op($1,
        $2);
        }),
        o('UNARY_MATH Expression',
        function() {
          return new Op($1,
        $2);
        }),
        o('-     Expression',
        (function() {
          return new Op('-',
        $2);
        }),
        {
          prec: 'UNARY_MATH'
        }),
        o('+     Expression',
        (function() {
          return new Op('+',
        $2);
        }),
        {
          prec: 'UNARY_MATH'
        }),
        o('AWAIT Expression',
        function() {
          return new Op($1,
        $2);
        }),
        o('-- SimpleAssignable',
        function() {
          return new Op('--',
        $2);
        }),
        o('++ SimpleAssignable',
        function() {
          return new Op('++',
        $2);
        }),
        o('SimpleAssignable --',
        function() {
          return new Op('--',
        $1,
        null,
        true);
        }),
        o('SimpleAssignable ++',
        function() {
          return new Op('++',
        $1,
        null,
        true);
        }),
        // [The existential operator](http://coffeescript.org/#existential-operator).
        o('Expression ?',
        function() {
          return new Existence($1);
        }),
        o('Expression +  Expression',
        function() {
          return new Op('+',
        $1,
        $3);
        }),
        o('Expression -  Expression',
        function() {
          return new Op('-',
        $1,
        $3);
        }),
        o('Expression MATH     Expression',
        function() {
          return new Op($2,
        $1,
        $3);
        }),
        o('Expression **       Expression',
        function() {
          return new Op($2,
        $1,
        $3);
        }),
        o('Expression SHIFT    Expression',
        function() {
          return new Op($2,
        $1,
        $3);
        }),
        o('Expression COMPARE  Expression',
        function() {
          return new Op($2,
        $1,
        $3);
        }),
        o('Expression &        Expression',
        function() {
          return new Op($2,
        $1,
        $3);
        }),
        o('Expression ^        Expression',
        function() {
          return new Op($2,
        $1,
        $3);
        }),
        o('Expression |        Expression',
        function() {
          return new Op($2,
        $1,
        $3);
        }),
        o('Expression &&       Expression',
        function() {
          return new Op($2,
        $1,
        $3);
        }),
        o('Expression ||       Expression',
        function() {
          return new Op($2,
        $1,
        $3);
        }),
        o('Expression BIN?     Expression',
        function() {
          return new Op($2,
        $1,
        $3);
        }),
        o('Expression RELATION Expression',
        function() {
          if ($2.charAt(0) === '!') {
            return new Op($2.slice(1),
        $1,
        $3).invert();
          } else {
            return new Op($2,
        $1,
        $3);
          }
        }),
        o('SimpleAssignable COMPOUND_ASSIGN Expression',
        function() {
          return new Assign($1,
        $3,
        $2);
        }),
        o('SimpleAssignable COMPOUND_ASSIGN INDENT Expression OUTDENT',
        function() {
          return new Assign($1,
        $4,
        $2);
        }),
        o('SimpleAssignable COMPOUND_ASSIGN TERMINATOR Expression',
        function() {
          return new Assign($1,
        $4,
        $2);
        })
      ]
    };
  
    // Precedence
    // ----------
  
    // Operators at the top of this list have higher precedence than the ones lower
    // down. Following these rules is what makes `2 + 3 * 4` parse as:
  
    //     2 + (3 * 4)
  
    // And not:
  
    //     (2 + 3) * 4
    operators = [['left', '.', '?.', '::', '?::'], ['left', 'CALL_START', 'CALL_END'], ['nonassoc', '++', '--'], ['left', '?'], ['right', 'UNARY'], ['right', 'AWAIT'], ['right', '**'], ['right', 'UNARY_MATH'], ['left', 'MATH'], ['left', '+', '-'], ['left', 'SHIFT'], ['left', 'RELATION'], ['left', 'COMPARE'], ['left', '&'], ['left', '^'], ['left', '|'], ['left', '&&'], ['left', '||'], ['left', 'BIN?'], ['nonassoc', 'INDENT', 'OUTDENT'], ['right', 'YIELD'], ['right', '=', ':', 'COMPOUND_ASSIGN', 'RETURN', 'THROW', 'EXTENDS'], ['right', 'FORIN', 'FOROF', 'FORFROM', 'BY', 'WHEN'], ['right', 'IF', 'ELSE', 'FOR', 'WHILE', 'UNTIL', 'LOOP', 'SUPER', 'CLASS', 'IMPORT', 'EXPORT'], ['left', 'POST_IF']];
  
    // Wrapping Up
    // -----------
  
    // Finally, now that we have our **grammar** and our **operators**, we can create
    // our **Jison.Parser**. We do this by processing all of our rules, recording all
    // terminals (every symbol which does not appear as the name of a rule above)
    // as "tokens".
    tokens = [];
  
    for (name in grammar) {
      alternatives = grammar[name];
      grammar[name] = (function() {
        var i, j, len, len1, ref, results;
        results = [];
        for (i = 0, len = alternatives.length; i < len; i++) {
          alt = alternatives[i];
          ref = alt[0].split(' ');
          for (j = 0, len1 = ref.length; j < len1; j++) {
            token = ref[j];
            if (!grammar[token]) {
              tokens.push(token);
            }
          }
          if (name === 'Root') {
            alt[1] = `return ${alt[1]}`;
          }
          results.push(alt);
        }
        return results;
      })();
    }
  
    // Initialize the **Parser** with our list of terminal **tokens**, our **grammar**
    // rules, and the name of the root. Reverse the operators because Jison orders
    // precedence from low to high, and we have it high to low
    // (as in [Yacc](http://dinosaur.compilertools.net/yacc/index.html)).
    exports.parser = new Parser({
      tokens: tokens.join(' '),
      bnf: grammar,
      operators: operators.reverse(),
      startSymbol: 'Root'
    });
  
  }).call(this);
  