Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
View | Details | Raw Unified | Return to bug 423091
Collapse All | Expand All

(-)a/bundles/org.eclipse.orion.client.ui/web/esprima/esprima_tolerant.js (+4082 lines)
Added Link Here
1
/*
2
  Copyright (C) 2013 Ariya Hidayat <ariya.hidayat@gmail.com>
3
  Copyright (C) 2013 Thaddee Tyl <thaddee.tyl@gmail.com>
4
  Copyright (C) 2013 Mathias Bynens <mathias@qiwi.be>
5
  Copyright (C) 2012 Ariya Hidayat <ariya.hidayat@gmail.com>
6
  Copyright (C) 2012 Mathias Bynens <mathias@qiwi.be>
7
  Copyright (C) 2012 Joost-Wim Boekesteijn <joost-wim@boekesteijn.nl>
8
  Copyright (C) 2012 Kris Kowal <kris.kowal@cixar.com>
9
  Copyright (C) 2012 Yusuke Suzuki <utatane.tea@gmail.com>
10
  Copyright (C) 2012 Arpad Borsos <arpad.borsos@googlemail.com>
11
  Copyright (C) 2011 Ariya Hidayat <ariya.hidayat@gmail.com>
12
13
  Redistribution and use in source and binary forms, with or without
14
  modification, are permitted provided that the following conditions are met:
15
16
    * Redistributions of source code must retain the above copyright
17
      notice, this list of conditions and the following disclaimer.
18
    * Redistributions in binary form must reproduce the above copyright
19
      notice, this list of conditions and the following disclaimer in the
20
      documentation and/or other materials provided with the distribution.
21
22
  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23
  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
  ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
26
  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27
  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28
  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
29
  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31
  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32
*/
33
34
/*jslint bitwise:true plusplus:true */
35
/*global esprima:true, define:true, exports:true, window: true,
36
createLocationMarker: true,
37
throwError: true, generateStatement: true, peek: true,
38
parseAssignmentExpression: true, parseBlock: true, 
39
expectConditionCloseBracketWrapThrow: true, parseExpression: true,
40
parseFunctionDeclaration: true, parseFunctionExpression: true,
41
parseFunctionSourceElements: true, parseVariableIdentifier: true,
42
parseLeftHandSideExpression: true,
43
parseUnaryExpression: true,
44
parseStatement: true, parseSourceElement: true */
45
46
(function (root, factory) {
47
    'use strict';
48
49
    // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js,
50
    // Rhino, and plain browser loading.
51
    if (typeof define === 'function' && define.amd) {
52
        define(['exports'], factory);
53
    } else if (typeof exports !== 'undefined') {
54
        factory(exports);
55
    } else {
56
        factory((root.esprima = {}));
57
    }
58
}(this, function (exports) {
59
    'use strict';
60
61
    var Token,
62
        TokenName,
63
        FnExprTokens,
64
        Syntax,
65
        PropertyKind,
66
        Messages,
67
        Regex,
68
        SyntaxTreeDelegate,
69
        source,
70
        strict,
71
        index,
72
        lineNumber,
73
        lineStart,
74
        length,
75
        delegate,
76
        lookahead,
77
        state,
78
        extra;
79
80
    Token = {
81
        BooleanLiteral: 1,
82
        EOF: 2,
83
        Identifier: 3,
84
        Keyword: 4,
85
        NullLiteral: 5,
86
        NumericLiteral: 6,
87
        Punctuator: 7,
88
        StringLiteral: 8,
89
        RegularExpression: 9
90
    };
91
92
    TokenName = {};
93
    TokenName[Token.BooleanLiteral] = 'Boolean';
94
    TokenName[Token.EOF] = '<end>';
95
    TokenName[Token.Identifier] = 'Identifier';
96
    TokenName[Token.Keyword] = 'Keyword';
97
    TokenName[Token.NullLiteral] = 'Null';
98
    TokenName[Token.NumericLiteral] = 'Numeric';
99
    TokenName[Token.Punctuator] = 'Punctuator';
100
    TokenName[Token.StringLiteral] = 'String';
101
    TokenName[Token.RegularExpression] = 'RegularExpression';
102
103
    // A function following one of those tokens is an expression.
104
    FnExprTokens = ['(', '{', '[', 'in', 'typeof', 'instanceof', 'new',
105
                    'return', 'case', 'delete', 'throw', 'void',
106
                    // assignment operators
107
                    '=', '+=', '-=', '*=', '/=', '%=', '<<=', '>>=', '>>>=',
108
                    '&=', '|=', '^=', ',',
109
                    // binary/unary operators
110
                    '+', '-', '*', '/', '%', '++', '--', '<<', '>>', '>>>', '&',
111
                    '|', '^', '!', '~', '&&', '||', '?', ':', '===', '==', '>=',
112
                    '<=', '<', '>', '!=', '!=='];
113
114
    Syntax = {
115
        AssignmentExpression: 'AssignmentExpression',
116
        ArrayExpression: 'ArrayExpression',
117
        BlockStatement: 'BlockStatement',
118
        BinaryExpression: 'BinaryExpression',
119
        BreakStatement: 'BreakStatement',
120
        CallExpression: 'CallExpression',
121
        CatchClause: 'CatchClause',
122
        ConditionalExpression: 'ConditionalExpression',
123
        ContinueStatement: 'ContinueStatement',
124
        DoWhileStatement: 'DoWhileStatement',
125
        DebuggerStatement: 'DebuggerStatement',
126
        EmptyStatement: 'EmptyStatement',
127
        ExpressionStatement: 'ExpressionStatement',
128
        ForStatement: 'ForStatement',
129
        ForInStatement: 'ForInStatement',
130
        FunctionDeclaration: 'FunctionDeclaration',
131
        FunctionExpression: 'FunctionExpression',
132
        Identifier: 'Identifier',
133
        IfStatement: 'IfStatement',
134
        Literal: 'Literal',
135
        LabeledStatement: 'LabeledStatement',
136
        LogicalExpression: 'LogicalExpression',
137
        MemberExpression: 'MemberExpression',
138
        NewExpression: 'NewExpression',
139
        ObjectExpression: 'ObjectExpression',
140
        Program: 'Program',
141
        Property: 'Property',
142
        ReturnStatement: 'ReturnStatement',
143
        SequenceExpression: 'SequenceExpression',
144
        SwitchStatement: 'SwitchStatement',
145
        SwitchCase: 'SwitchCase',
146
        ThisExpression: 'ThisExpression',
147
        ThrowStatement: 'ThrowStatement',
148
        TryStatement: 'TryStatement',
149
        UnaryExpression: 'UnaryExpression',
150
        UpdateExpression: 'UpdateExpression',
151
        VariableDeclaration: 'VariableDeclaration',
152
        VariableDeclarator: 'VariableDeclarator',
153
        WhileStatement: 'WhileStatement',
154
        WithStatement: 'WithStatement'
155
    };
156
157
    PropertyKind = {
158
        Data: 1,
159
        Get: 2,
160
        Set: 4
161
    };
162
163
    // Error messages should be identical to V8.
164
    Messages = {
165
        UnexpectedToken:  'Unexpected token %0',
166
        UnexpectedNumber:  'Unexpected number',
167
        UnexpectedString:  'Unexpected string',
168
        UnexpectedIdentifier:  'Unexpected identifier',
169
        UnexpectedReserved:  'Unexpected reserved word',
170
        UnexpectedEOS:  'Unexpected end of input',
171
        NewlineAfterThrow:  'Illegal newline after throw',
172
        InvalidRegExp: 'Invalid regular expression',
173
        UnterminatedRegExp:  'Invalid regular expression: missing /',
174
        InvalidLHSInAssignment:  'Invalid left-hand side in assignment',
175
        InvalidLHSInForIn:  'Invalid left-hand side in for-in',
176
        MultipleDefaultsInSwitch: 'More than one default clause in switch statement',
177
        NoCatchOrFinally:  'Missing catch or finally after try',
178
        UnknownLabel: 'Undefined label \'%0\'',
179
        Redeclaration: '%0 \'%1\' has already been declared',
180
        IllegalContinue: 'Illegal continue statement',
181
        IllegalBreak: 'Illegal break statement',
182
        IllegalReturn: 'Illegal return statement',
183
        StrictModeWith:  'Strict mode code may not include a with statement',
184
        StrictCatchVariable:  'Catch variable may not be eval or arguments in strict mode',
185
        StrictVarName:  'Variable name may not be eval or arguments in strict mode',
186
        StrictParamName:  'Parameter name eval or arguments is not allowed in strict mode',
187
        StrictParamDupe: 'Strict mode function may not have duplicate parameter names',
188
        StrictFunctionName:  'Function name may not be eval or arguments in strict mode',
189
        StrictOctalLiteral:  'Octal literals are not allowed in strict mode.',
190
        StrictDelete:  'Delete of an unqualified identifier in strict mode.',
191
        StrictDuplicateProperty:  'Duplicate data property in object literal not allowed in strict mode',
192
        AccessorDataProperty:  'Object literal may not have data and accessor property with the same name',
193
        AccessorGetSet:  'Object literal may not have multiple get/set accessors with the same name',
194
        StrictLHSAssignment:  'Assignment to eval or arguments is not allowed in strict mode',
195
        StrictLHSPostfix:  'Postfix increment/decrement may not have eval or arguments operand in strict mode',
196
        StrictLHSPrefix:  'Prefix increment/decrement may not have eval or arguments operand in strict mode',
197
        StrictReservedWord:  'Use of future reserved word in strict mode'
198
    };
199
200
    // See also tools/generate-unicode-regex.py.
201
    Regex = {
202
        NonAsciiIdentifierStart: new RegExp('[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0\u08A2-\u08AC\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097F\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F0\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191C\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA697\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA793\uA7A0-\uA7AA\uA7F8-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA80-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]'),
203
        NonAsciiIdentifierPart: new RegExp('[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0300-\u0374\u0376\u0377\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u0483-\u0487\u048A-\u0527\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u05D0-\u05EA\u05F0-\u05F2\u0610-\u061A\u0620-\u0669\u066E-\u06D3\u06D5-\u06DC\u06DF-\u06E8\u06EA-\u06FC\u06FF\u0710-\u074A\u074D-\u07B1\u07C0-\u07F5\u07FA\u0800-\u082D\u0840-\u085B\u08A0\u08A2-\u08AC\u08E4-\u08FE\u0900-\u0963\u0966-\u096F\u0971-\u0977\u0979-\u097F\u0981-\u0983\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BC-\u09C4\u09C7\u09C8\u09CB-\u09CE\u09D7\u09DC\u09DD\u09DF-\u09E3\u09E6-\u09F1\u0A01-\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A59-\u0A5C\u0A5E\u0A66-\u0A75\u0A81-\u0A83\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABC-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AD0\u0AE0-\u0AE3\u0AE6-\u0AEF\u0B01-\u0B03\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3C-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B5C\u0B5D\u0B5F-\u0B63\u0B66-\u0B6F\u0B71\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD0\u0BD7\u0BE6-\u0BEF\u0C01-\u0C03\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C58\u0C59\u0C60-\u0C63\u0C66-\u0C6F\u0C82\u0C83\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBC-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CDE\u0CE0-\u0CE3\u0CE6-\u0CEF\u0CF1\u0CF2\u0D02\u0D03\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D-\u0D44\u0D46-\u0D48\u0D4A-\u0D4E\u0D57\u0D60-\u0D63\u0D66-\u0D6F\u0D7A-\u0D7F\u0D82\u0D83\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DF2\u0DF3\u0E01-\u0E3A\u0E40-\u0E4E\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB9\u0EBB-\u0EBD\u0EC0-\u0EC4\u0EC6\u0EC8-\u0ECD\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F18\u0F19\u0F20-\u0F29\u0F35\u0F37\u0F39\u0F3E-\u0F47\u0F49-\u0F6C\u0F71-\u0F84\u0F86-\u0F97\u0F99-\u0FBC\u0FC6\u1000-\u1049\u1050-\u109D\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u135D-\u135F\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F0\u1700-\u170C\u170E-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176C\u176E-\u1770\u1772\u1773\u1780-\u17D3\u17D7\u17DC\u17DD\u17E0-\u17E9\u180B-\u180D\u1810-\u1819\u1820-\u1877\u1880-\u18AA\u18B0-\u18F5\u1900-\u191C\u1920-\u192B\u1930-\u193B\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19D9\u1A00-\u1A1B\u1A20-\u1A5E\u1A60-\u1A7C\u1A7F-\u1A89\u1A90-\u1A99\u1AA7\u1B00-\u1B4B\u1B50-\u1B59\u1B6B-\u1B73\u1B80-\u1BF3\u1C00-\u1C37\u1C40-\u1C49\u1C4D-\u1C7D\u1CD0-\u1CD2\u1CD4-\u1CF6\u1D00-\u1DE6\u1DFC-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u200C\u200D\u203F\u2040\u2054\u2071\u207F\u2090-\u209C\u20D0-\u20DC\u20E1\u20E5-\u20F0\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D7F-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2DE0-\u2DFF\u2E2F\u3005-\u3007\u3021-\u302F\u3031-\u3035\u3038-\u303C\u3041-\u3096\u3099\u309A\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66F\uA674-\uA67D\uA67F-\uA697\uA69F-\uA6F1\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA793\uA7A0-\uA7AA\uA7F8-\uA827\uA840-\uA873\uA880-\uA8C4\uA8D0-\uA8D9\uA8E0-\uA8F7\uA8FB\uA900-\uA92D\uA930-\uA953\uA960-\uA97C\uA980-\uA9C0\uA9CF-\uA9D9\uAA00-\uAA36\uAA40-\uAA4D\uAA50-\uAA59\uAA60-\uAA76\uAA7A\uAA7B\uAA80-\uAAC2\uAADB-\uAADD\uAAE0-\uAAEF\uAAF2-\uAAF6\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uABC0-\uABEA\uABEC\uABED\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE00-\uFE0F\uFE20-\uFE26\uFE33\uFE34\uFE4D-\uFE4F\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF3F\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]')
204
    };
205
206
    // Ensure the condition is true, otherwise throw an error.
207
    // This is only to have a better contract semantic, i.e. another safety net
208
    // to catch a logic error. The condition shall be fulfilled in normal case.
209
    // Do NOT use this to enforce a certain condition on any user input.
210
211
    function assert(condition, message) {
212
        if (!condition) {
213
            throw new Error('ASSERT: ' + message);
214
        }
215
    }
216
217
    function isDecimalDigit(ch) {
218
        return (ch >= 48 && ch <= 57);   // 0..9
219
    }
220
221
    function isHexDigit(ch) {
222
        return '0123456789abcdefABCDEF'.indexOf(ch) >= 0;
223
    }
224
225
    function isOctalDigit(ch) {
226
        return '01234567'.indexOf(ch) >= 0;
227
    }
228
229
230
    // 7.2 White Space
231
232
    function isWhiteSpace(ch) {
233
        return (ch === 0x20) || (ch === 0x09) || (ch === 0x0B) || (ch === 0x0C) || (ch === 0xA0) ||
234
            (ch >= 0x1680 && [0x1680, 0x180E, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008, 0x2009, 0x200A, 0x202F, 0x205F, 0x3000, 0xFEFF].indexOf(ch) >= 0);
235
    }
236
237
    // 7.3 Line Terminators
238
239
    function isLineTerminator(ch) {
240
        return (ch === 0x0A) || (ch === 0x0D) || (ch === 0x2028) || (ch === 0x2029);
241
    }
242
243
    // 7.6 Identifier Names and Identifiers
244
245
    function isIdentifierStart(ch) {
246
        return (ch === 36) || (ch === 95) ||  // $ (dollar) and _ (underscore)
247
            (ch >= 65 && ch <= 90) ||         // A..Z
248
            (ch >= 97 && ch <= 122) ||        // a..z
249
            (ch === 92) ||                    // \ (backslash)
250
            ((ch >= 0x80) && Regex.NonAsciiIdentifierStart.test(String.fromCharCode(ch)));
251
    }
252
253
    function isIdentifierPart(ch) {
254
        return (ch === 36) || (ch === 95) ||  // $ (dollar) and _ (underscore)
255
            (ch >= 65 && ch <= 90) ||         // A..Z
256
            (ch >= 97 && ch <= 122) ||        // a..z
257
            (ch >= 48 && ch <= 57) ||         // 0..9
258
            (ch === 92) ||                    // \ (backslash)
259
            ((ch >= 0x80) && Regex.NonAsciiIdentifierPart.test(String.fromCharCode(ch)));
260
    }
261
262
    // 7.6.1.2 Future Reserved Words
263
264
    function isFutureReservedWord(id) {
265
        switch (id) {
266
        case 'class':
267
        case 'enum':
268
        case 'export':
269
        case 'extends':
270
        case 'import':
271
        case 'super':
272
            return true;
273
        default:
274
            return false;
275
        }
276
    }
277
278
    function isStrictModeReservedWord(id) {
279
        switch (id) {
280
        case 'implements':
281
        case 'interface':
282
        case 'package':
283
        case 'private':
284
        case 'protected':
285
        case 'public':
286
        case 'static':
287
        case 'yield':
288
        case 'let':
289
            return true;
290
        default:
291
            return false;
292
        }
293
    }
294
295
    function isRestrictedWord(id) {
296
        return id === 'eval' || id === 'arguments';
297
    }
298
299
    // 7.6.1.1 Keywords
300
301
    function isKeyword(id) {
302
        if (strict && isStrictModeReservedWord(id)) {
303
            return true;
304
        }
305
306
        // 'const' is specialized as Keyword in V8.
307
        // 'yield' and 'let' are for compatiblity with SpiderMonkey and ES.next.
308
        // Some others are from future reserved words.
309
310
        switch (id.length) {
311
        case 2:
312
            return (id === 'if') || (id === 'in') || (id === 'do');
313
        case 3:
314
            return (id === 'var') || (id === 'for') || (id === 'new') ||
315
                (id === 'try') || (id === 'let');
316
        case 4:
317
            return (id === 'this') || (id === 'else') || (id === 'case') ||
318
                (id === 'void') || (id === 'with') || (id === 'enum');
319
        case 5:
320
            return (id === 'while') || (id === 'break') || (id === 'catch') ||
321
                (id === 'throw') || (id === 'const') || (id === 'yield') ||
322
                (id === 'class') || (id === 'super');
323
        case 6:
324
            return (id === 'return') || (id === 'typeof') || (id === 'delete') ||
325
                (id === 'switch') || (id === 'export') || (id === 'import');
326
        case 7:
327
            return (id === 'default') || (id === 'finally') || (id === 'extends');
328
        case 8:
329
            return (id === 'function') || (id === 'continue') || (id === 'debugger');
330
        case 10:
331
            return (id === 'instanceof');
332
        default:
333
            return false;
334
        }
335
    }
336
337
    // 7.4 Comments
338
339
    function addComment(type, value, start, end, loc) {
340
        var comment, attacher;
341
342
        assert(typeof start === 'number', 'Comment must have valid position');
343
344
        // Because the way the actual token is scanned, often the comments
345
        // (if any) are skipped twice during the lexical analysis.
346
        // Thus, we need to skip adding a comment if the comment array already
347
        // handled it.
348
        if (state.lastCommentStart >= start) {
349
            return;
350
        }
351
        state.lastCommentStart = start;
352
353
        comment = {
354
            type: type,
355
            value: value
356
        };
357
        if (extra.range) {
358
            comment.range = [start, end];
359
        }
360
        if (extra.loc) {
361
            comment.loc = loc;
362
        }
363
        extra.comments.push(comment);
364
365
        if (extra.attachComment) {
366
            attacher = {
367
                comment: comment,
368
                leading: null,
369
                trailing: null,
370
                range: [start, end]
371
            };
372
            extra.pendingComments.push(attacher);
373
        }
374
    }
375
376
    function skipSingleLineComment() {
377
        var start, loc, ch, comment;
378
379
        start = index - 2;
380
        loc = {
381
            start: {
382
                line: lineNumber,
383
                column: index - lineStart - 2
384
            }
385
        };
386
387
        while (index < length) {
388
            ch = source.charCodeAt(index);
389
            ++index;
390
            if (isLineTerminator(ch)) {
391
                if (extra.comments) {
392
                    comment = source.slice(start + 2, index - 1);
393
                    loc.end = {
394
                        line: lineNumber,
395
                        column: index - lineStart - 1
396
                    };
397
                    addComment('Line', comment, start, index - 1, loc);
398
                }
399
                if (ch === 13 && source.charCodeAt(index) === 10) {
400
                    ++index;
401
                }
402
                ++lineNumber;
403
                lineStart = index;
404
                return;
405
            }
406
        }
407
408
        if (extra.comments) {
409
            comment = source.slice(start + 2, index);
410
            loc.end = {
411
                line: lineNumber,
412
                column: index - lineStart
413
            };
414
            addComment('Line', comment, start, index, loc);
415
        }
416
    }
417
418
    function skipMultiLineComment() {
419
        var start, loc, ch, comment;
420
421
        if (extra.comments) {
422
            start = index - 2;
423
            loc = {
424
                start: {
425
                    line: lineNumber,
426
                    column: index - lineStart - 2
427
                }
428
            };
429
        }
430
431
        while (index < length) {
432
            ch = source.charCodeAt(index);
433
            if (isLineTerminator(ch)) {
434
                if (ch === 13 && source.charCodeAt(index + 1) === 10) {
435
                    ++index;
436
                }
437
                ++lineNumber;
438
                ++index;
439
                lineStart = index;
440
                if (index >= length) {
441
                    throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
442
                }
443
            } else if (ch === 42) {
444
                // Block comment ends with '*/' (char #42, char #47).
445
                if (source.charCodeAt(index + 1) === 47) {
446
                    ++index;
447
                    ++index;
448
                    if (extra.comments) {
449
                        comment = source.slice(start + 2, index - 2);
450
                        loc.end = {
451
                            line: lineNumber,
452
                            column: index - lineStart
453
                        };
454
                        addComment('Block', comment, start, index, loc);
455
                    }
456
                    return;
457
                }
458
                ++index;
459
            } else {
460
                ++index;
461
            }
462
        }
463
464
        throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
465
    }
466
467
    function skipComment() {
468
        var ch, start;
469
470
        start = (index === 0);
471
        while (index < length) {
472
            ch = source.charCodeAt(index);
473
474
            if (isWhiteSpace(ch)) {
475
                ++index;
476
            } else if (isLineTerminator(ch)) {
477
                ++index;
478
                if (ch === 13 && source.charCodeAt(index) === 10) {
479
                    ++index;
480
                }
481
                ++lineNumber;
482
                lineStart = index;
483
                start = true;
484
            } else if (ch === 47) { // 47 is '/'
485
                ch = source.charCodeAt(index + 1);
486
                if (ch === 47) {
487
                    ++index;
488
                    ++index;
489
                    skipSingleLineComment();
490
                    start = true;
491
                } else if (ch === 42) {  // 42 is '*'
492
                    ++index;
493
                    ++index;
494
                    skipMultiLineComment();
495
                } else {
496
                    break;
497
                }
498
            } else if (start && ch === 45) { // 45 is '-'
499
                // 62 is '>'
500
                if ((source.charCodeAt(index + 1) === 45) && (source.charCodeAt(index + 2) === 62)) {
501
                    // '-->' is a single-line comment
502
                    index += 3;
503
                    skipSingleLineComment();
504
                } else {
505
                    break;
506
                }
507
            } else if (ch === 60) { // 60 is '<'
508
                if (source.slice(index + 1, index + 4) === '!--') {
509
                    ++index; // `<`
510
                    ++index; // `!`
511
                    ++index; // `-`
512
                    ++index; // `-`
513
                    skipSingleLineComment();
514
                } else {
515
                    break;
516
                }
517
            } else {
518
                break;
519
            }
520
        }
521
    }
522
523
    function scanHexEscape(prefix) {
524
        var i, len, ch, code = 0;
525
526
        len = (prefix === 'u') ? 4 : 2;
527
        for (i = 0; i < len; ++i) {
528
            if (index < length && isHexDigit(source[index])) {
529
                ch = source[index++];
530
                code = code * 16 + '0123456789abcdef'.indexOf(ch.toLowerCase());
531
            } else {
532
                return '';
533
            }
534
        }
535
        return String.fromCharCode(code);
536
    }
537
538
    function getEscapedIdentifier() {
539
        var ch, id;
540
541
        ch = source.charCodeAt(index++);
542
        id = String.fromCharCode(ch);
543
544
        // '\u' (char #92, char #117) denotes an escaped character.
545
        if (ch === 92) {
546
            if (source.charCodeAt(index) !== 117) {
547
                throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
548
            }
549
            ++index;
550
            ch = scanHexEscape('u');
551
            if (!ch || ch === '\\' || !isIdentifierStart(ch.charCodeAt(0))) {
552
                throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
553
            }
554
            id = ch;
555
        }
556
557
        while (index < length) {
558
            ch = source.charCodeAt(index);
559
            if (!isIdentifierPart(ch)) {
560
                break;
561
            }
562
            ++index;
563
            id += String.fromCharCode(ch);
564
565
            // '\u' (char #92, char #117) denotes an escaped character.
566
            if (ch === 92) {
567
                id = id.substr(0, id.length - 1);
568
                if (source.charCodeAt(index) !== 117) {
569
                    throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
570
                }
571
                ++index;
572
                ch = scanHexEscape('u');
573
                if (!ch || ch === '\\' || !isIdentifierPart(ch.charCodeAt(0))) {
574
                    throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
575
                }
576
                id += ch;
577
            }
578
        }
579
580
        return id;
581
    }
582
583
    function getIdentifier() {
584
        var start, ch;
585
586
        start = index++;
587
        while (index < length) {
588
            ch = source.charCodeAt(index);
589
            if (ch === 92) {
590
                // Blackslash (char #92) marks Unicode escape sequence.
591
                index = start;
592
                return getEscapedIdentifier();
593
            }
594
            if (isIdentifierPart(ch)) {
595
                ++index;
596
            } else {
597
                break;
598
            }
599
        }
600
601
        return source.slice(start, index);
602
    }
603
604
    function scanIdentifier() {
605
        var start, id, type;
606
607
        start = index;
608
609
        // Backslash (char #92) starts an escaped character.
610
        id = (source.charCodeAt(index) === 92) ? getEscapedIdentifier() : getIdentifier();
611
612
        // There is no keyword or literal with only one character.
613
        // Thus, it must be an identifier.
614
        if (id.length === 1) {
615
            type = Token.Identifier;
616
        } else if (isKeyword(id)) {
617
            type = Token.Keyword;
618
        } else if (id === 'null') {
619
            type = Token.NullLiteral;
620
        } else if (id === 'true' || id === 'false') {
621
            type = Token.BooleanLiteral;
622
        } else {
623
            type = Token.Identifier;
624
        }
625
626
        return {
627
            type: type,
628
            value: id,
629
            lineNumber: lineNumber,
630
            lineStart: lineStart,
631
            range: [start, index]
632
        };
633
    }
634
635
636
    // 7.7 Punctuators
637
638
    function scanPunctuator() {
639
        var start = index,
640
            code = source.charCodeAt(index),
641
            code2,
642
            ch1 = source[index],
643
            ch2,
644
            ch3,
645
            ch4;
646
647
        switch (code) {
648
649
        // Check for most common single-character punctuators.
650
        case 46:   // . dot
651
        case 40:   // ( open bracket
652
        case 41:   // ) close bracket
653
        case 59:   // ; semicolon
654
        case 44:   // , comma
655
        case 123:  // { open curly brace
656
        case 125:  // } close curly brace
657
        case 91:   // [
658
        case 93:   // ]
659
        case 58:   // :
660
        case 63:   // ?
661
        case 126:  // ~
662
            ++index;
663
            if (extra.tokenize) {
664
                if (code === 40) {
665
                    extra.openParenToken = extra.tokens.length;
666
                } else if (code === 123) {
667
                    extra.openCurlyToken = extra.tokens.length;
668
                }
669
            }
670
            return {
671
                type: Token.Punctuator,
672
                value: String.fromCharCode(code),
673
                lineNumber: lineNumber,
674
                lineStart: lineStart,
675
                range: [start, index]
676
            };
677
678
        default:
679
            code2 = source.charCodeAt(index + 1);
680
681
            // '=' (char #61) marks an assignment or comparison operator.
682
            if (code2 === 61) {
683
                switch (code) {
684
                case 37:  // %
685
                case 38:  // &
686
                case 42:  // *:
687
                case 43:  // +
688
                case 45:  // -
689
                case 47:  // /
690
                case 60:  // <
691
                case 62:  // >
692
                case 94:  // ^
693
                case 124: // |
694
                    index += 2;
695
                    return {
696
                        type: Token.Punctuator,
697
                        value: String.fromCharCode(code) + String.fromCharCode(code2),
698
                        lineNumber: lineNumber,
699
                        lineStart: lineStart,
700
                        range: [start, index]
701
                    };
702
703
                case 33: // !
704
                case 61: // =
705
                    index += 2;
706
707
                    // !== and ===
708
                    if (source.charCodeAt(index) === 61) {
709
                        ++index;
710
                    }
711
                    return {
712
                        type: Token.Punctuator,
713
                        value: source.slice(start, index),
714
                        lineNumber: lineNumber,
715
                        lineStart: lineStart,
716
                        range: [start, index]
717
                    };
718
                default:
719
                    break;
720
                }
721
            }
722
            break;
723
        }
724
725
        // Peek more characters.
726
727
        ch2 = source[index + 1];
728
        ch3 = source[index + 2];
729
        ch4 = source[index + 3];
730
731
        // 4-character punctuator: >>>=
732
733
        if (ch1 === '>' && ch2 === '>' && ch3 === '>') {
734
            if (ch4 === '=') {
735
                index += 4;
736
                return {
737
                    type: Token.Punctuator,
738
                    value: '>>>=',
739
                    lineNumber: lineNumber,
740
                    lineStart: lineStart,
741
                    range: [start, index]
742
                };
743
            }
744
        }
745
746
        // 3-character punctuators: === !== >>> <<= >>=
747
748
        if (ch1 === '>' && ch2 === '>' && ch3 === '>') {
749
            index += 3;
750
            return {
751
                type: Token.Punctuator,
752
                value: '>>>',
753
                lineNumber: lineNumber,
754
                lineStart: lineStart,
755
                range: [start, index]
756
            };
757
        }
758
759
        if (ch1 === '<' && ch2 === '<' && ch3 === '=') {
760
            index += 3;
761
            return {
762
                type: Token.Punctuator,
763
                value: '<<=',
764
                lineNumber: lineNumber,
765
                lineStart: lineStart,
766
                range: [start, index]
767
            };
768
        }
769
770
        if (ch1 === '>' && ch2 === '>' && ch3 === '=') {
771
            index += 3;
772
            return {
773
                type: Token.Punctuator,
774
                value: '>>=',
775
                lineNumber: lineNumber,
776
                lineStart: lineStart,
777
                range: [start, index]
778
            };
779
        }
780
781
        // Other 2-character punctuators: ++ -- << >> && ||
782
783
        if (ch1 === ch2 && ('+-<>&|'.indexOf(ch1) >= 0)) {
784
            index += 2;
785
            return {
786
                type: Token.Punctuator,
787
                value: ch1 + ch2,
788
                lineNumber: lineNumber,
789
                lineStart: lineStart,
790
                range: [start, index]
791
            };
792
        }
793
794
        if ('<>=!+-*%&|^/'.indexOf(ch1) >= 0) {
795
            ++index;
796
            return {
797
                type: Token.Punctuator,
798
                value: ch1,
799
                lineNumber: lineNumber,
800
                lineStart: lineStart,
801
                range: [start, index]
802
            };
803
        }
804
805
        throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
806
    }
807
808
    // 7.8.3 Numeric Literals
809
810
    function scanHexLiteral(start) {
811
        var number = '';
812
813
        while (index < length) {
814
            if (!isHexDigit(source[index])) {
815
                break;
816
            }
817
            number += source[index++];
818
        }
819
820
        if (number.length === 0) {
821
            throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
822
        }
823
824
        if (isIdentifierStart(source.charCodeAt(index))) {
825
            throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
826
        }
827
828
        return {
829
            type: Token.NumericLiteral,
830
            value: parseInt('0x' + number, 16),
831
            lineNumber: lineNumber,
832
            lineStart: lineStart,
833
            range: [start, index]
834
        };
835
    }
836
837
    function scanOctalLiteral(start) {
838
        var number = '0' + source[index++];
839
        while (index < length) {
840
            if (!isOctalDigit(source[index])) {
841
                break;
842
            }
843
            number += source[index++];
844
        }
845
846
        if (isIdentifierStart(source.charCodeAt(index)) || isDecimalDigit(source.charCodeAt(index))) {
847
            throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
848
        }
849
850
        return {
851
            type: Token.NumericLiteral,
852
            value: parseInt(number, 8),
853
            octal: true,
854
            lineNumber: lineNumber,
855
            lineStart: lineStart,
856
            range: [start, index]
857
        };
858
    }
859
860
    function scanNumericLiteral() {
861
        var number, start, ch;
862
863
        ch = source[index];
864
        assert(isDecimalDigit(ch.charCodeAt(0)) || (ch === '.'),
865
            'Numeric literal must start with a decimal digit or a decimal point');
866
867
        start = index;
868
        number = '';
869
        if (ch !== '.') {
870
            number = source[index++];
871
            ch = source[index];
872
873
            // Hex number starts with '0x'.
874
            // Octal number starts with '0'.
875
            if (number === '0') {
876
                if (ch === 'x' || ch === 'X') {
877
                    ++index;
878
                    return scanHexLiteral(start);
879
                }
880
                if (isOctalDigit(ch)) {
881
                    return scanOctalLiteral(start);
882
                }
883
884
                // decimal number starts with '0' such as '09' is illegal.
885
                if (ch && isDecimalDigit(ch.charCodeAt(0))) {
886
                    throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
887
                }
888
            }
889
890
            while (isDecimalDigit(source.charCodeAt(index))) {
891
                number += source[index++];
892
            }
893
            ch = source[index];
894
        }
895
896
        if (ch === '.') {
897
            number += source[index++];
898
            while (isDecimalDigit(source.charCodeAt(index))) {
899
                number += source[index++];
900
            }
901
            ch = source[index];
902
        }
903
904
        if (ch === 'e' || ch === 'E') {
905
            number += source[index++];
906
907
            ch = source[index];
908
            if (ch === '+' || ch === '-') {
909
                number += source[index++];
910
            }
911
            if (isDecimalDigit(source.charCodeAt(index))) {
912
                while (isDecimalDigit(source.charCodeAt(index))) {
913
                    number += source[index++];
914
                }
915
            } else {
916
                throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
917
            }
918
        }
919
920
        if (isIdentifierStart(source.charCodeAt(index))) {
921
            throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
922
        }
923
924
        return {
925
            type: Token.NumericLiteral,
926
            value: parseFloat(number),
927
            lineNumber: lineNumber,
928
            lineStart: lineStart,
929
            range: [start, index]
930
        };
931
    }
932
933
    // 7.8.4 String Literals
934
935
    function scanStringLiteral() {
936
        var str = '', quote, start, ch, code, unescaped, restore, octal = false;
937
938
        quote = source[index];
939
        assert((quote === '\'' || quote === '"'),
940
            'String literal must starts with a quote');
941
942
        start = index;
943
        ++index;
944
945
        while (index < length) {
946
            ch = source[index++];
947
948
            if (ch === quote) {
949
                quote = '';
950
                break;
951
            } else if (ch === '\\') {
952
                ch = source[index++];
953
                if (!ch || !isLineTerminator(ch.charCodeAt(0))) {
954
                    switch (ch) {
955
                    case 'n':
956
                        str += '\n';
957
                        break;
958
                    case 'r':
959
                        str += '\r';
960
                        break;
961
                    case 't':
962
                        str += '\t';
963
                        break;
964
                    case 'u':
965
                    case 'x':
966
                        restore = index;
967
                        unescaped = scanHexEscape(ch);
968
                        if (unescaped) {
969
                            str += unescaped;
970
                        } else {
971
                            index = restore;
972
                            str += ch;
973
                        }
974
                        break;
975
                    case 'b':
976
                        str += '\b';
977
                        break;
978
                    case 'f':
979
                        str += '\f';
980
                        break;
981
                    case 'v':
982
                        str += '\x0B';
983
                        break;
984
985
                    default:
986
                        if (isOctalDigit(ch)) {
987
                            code = '01234567'.indexOf(ch);
988
989
                            // \0 is not octal escape sequence
990
                            if (code !== 0) {
991
                                octal = true;
992
                            }
993
994
                            if (index < length && isOctalDigit(source[index])) {
995
                                octal = true;
996
                                code = code * 8 + '01234567'.indexOf(source[index++]);
997
998
                                // 3 digits are only allowed when string starts
999
                                // with 0, 1, 2, 3
1000
                                if ('0123'.indexOf(ch) >= 0 &&
1001
                                        index < length &&
1002
                                        isOctalDigit(source[index])) {
1003
                                    code = code * 8 + '01234567'.indexOf(source[index++]);
1004
                                }
1005
                            }
1006
                            str += String.fromCharCode(code);
1007
                        } else {
1008
                            str += ch;
1009
                        }
1010
                        break;
1011
                    }
1012
                } else {
1013
                    ++lineNumber;
1014
                    if (ch ===  '\r' && source[index] === '\n') {
1015
                        ++index;
1016
                    }
1017
                }
1018
            } else if (isLineTerminator(ch.charCodeAt(0))) {
1019
                break;
1020
            } else {
1021
                str += ch;
1022
            }
1023
        }
1024
1025
        if (quote !== '') {
1026
            throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
1027
        }
1028
1029
        return {
1030
            type: Token.StringLiteral,
1031
            value: str,
1032
            octal: octal,
1033
            lineNumber: lineNumber,
1034
            lineStart: lineStart,
1035
            range: [start, index]
1036
        };
1037
    }
1038
1039
    function scanRegExp() {
1040
        var str, ch, start, pattern, flags, value, classMarker = false, restore, terminated = false;
1041
1042
        lookahead = null;
1043
        skipComment();
1044
1045
        start = index;
1046
        ch = source[index];
1047
        assert(ch === '/', 'Regular expression literal must start with a slash');
1048
        str = source[index++];
1049
1050
        while (index < length) {
1051
            ch = source[index++];
1052
            str += ch;
1053
            if (ch === '\\') {
1054
                ch = source[index++];
1055
                // ECMA-262 7.8.5
1056
                if (isLineTerminator(ch.charCodeAt(0))) {
1057
                    throwError({}, Messages.UnterminatedRegExp);
1058
                }
1059
                str += ch;
1060
            } else if (isLineTerminator(ch.charCodeAt(0))) {
1061
                throwError({}, Messages.UnterminatedRegExp);
1062
            } else if (classMarker) {
1063
                if (ch === ']') {
1064
                    classMarker = false;
1065
                }
1066
            } else {
1067
                if (ch === '/') {
1068
                    terminated = true;
1069
                    break;
1070
                } else if (ch === '[') {
1071
                    classMarker = true;
1072
                }
1073
            }
1074
        }
1075
1076
        if (!terminated) {
1077
            throwError({}, Messages.UnterminatedRegExp);
1078
        }
1079
1080
        // Exclude leading and trailing slash.
1081
        pattern = str.substr(1, str.length - 2);
1082
1083
        flags = '';
1084
        while (index < length) {
1085
            ch = source[index];
1086
            if (!isIdentifierPart(ch.charCodeAt(0))) {
1087
                break;
1088
            }
1089
1090
            ++index;
1091
            if (ch === '\\' && index < length) {
1092
                ch = source[index];
1093
                if (ch === 'u') {
1094
                    ++index;
1095
                    restore = index;
1096
                    ch = scanHexEscape('u');
1097
                    if (ch) {
1098
                        flags += ch;
1099
                        for (str += '\\u'; restore < index; ++restore) {
1100
                            str += source[restore];
1101
                        }
1102
                    } else {
1103
                        index = restore;
1104
                        flags += 'u';
1105
                        str += '\\u';
1106
                    }
1107
                } else {
1108
                    str += '\\';
1109
                }
1110
            } else {
1111
                flags += ch;
1112
                str += ch;
1113
            }
1114
        }
1115
1116
        try {
1117
            value = new RegExp(pattern, flags);
1118
        } catch (e) {
1119
            throwError({}, Messages.InvalidRegExp);
1120
        }
1121
1122
1123
1124
        if (extra.tokenize) {
1125
            return {
1126
                type: Token.RegularExpression,
1127
                value: value,
1128
                lineNumber: lineNumber,
1129
                lineStart: lineStart,
1130
                range: [start, index]
1131
            };
1132
        }
1133
        return {
1134
            literal: str,
1135
            value: value,
1136
            range: [start, index]
1137
        };
1138
    }
1139
1140
    function collectRegex() {
1141
        var pos, loc, regex, token;
1142
1143
        skipComment();
1144
1145
        pos = index;
1146
        loc = {
1147
            start: {
1148
                line: lineNumber,
1149
                column: index - lineStart
1150
            }
1151
        };
1152
1153
        regex = scanRegExp();
1154
        loc.end = {
1155
            line: lineNumber,
1156
            column: index - lineStart
1157
        };
1158
1159
        if (!extra.tokenize) {
1160
            // Pop the previous token, which is likely '/' or '/='
1161
            if (extra.tokens.length > 0) {
1162
                token = extra.tokens[extra.tokens.length - 1];
1163
                if (token.range[0] === pos && token.type === 'Punctuator') {
1164
                    if (token.value === '/' || token.value === '/=') {
1165
                        extra.tokens.pop();
1166
                    }
1167
                }
1168
            }
1169
1170
            extra.tokens.push({
1171
                type: 'RegularExpression',
1172
                value: regex.literal,
1173
                range: [pos, index],
1174
                loc: loc
1175
            });
1176
        }
1177
1178
        return regex;
1179
    }
1180
1181
    function isIdentifierName(token) {
1182
        return token.type === Token.Identifier ||
1183
            token.type === Token.Keyword ||
1184
            token.type === Token.BooleanLiteral ||
1185
            token.type === Token.NullLiteral;
1186
    }
1187
1188
    function advanceSlash() {
1189
        var prevToken,
1190
            checkToken;
1191
        // Using the following algorithm:
1192
        // https://github.com/mozilla/sweet.js/wiki/design
1193
        prevToken = extra.tokens[extra.tokens.length - 1];
1194
        if (!prevToken) {
1195
            // Nothing before that: it cannot be a division.
1196
            return collectRegex();
1197
        }
1198
        if (prevToken.type === 'Punctuator') {
1199
            if (prevToken.value === ')') {
1200
                checkToken = extra.tokens[extra.openParenToken - 1];
1201
                if (checkToken &&
1202
                        checkToken.type === 'Keyword' &&
1203
                        (checkToken.value === 'if' ||
1204
                         checkToken.value === 'while' ||
1205
                         checkToken.value === 'for' ||
1206
                         checkToken.value === 'with')) {
1207
                    return collectRegex();
1208
                }
1209
                return scanPunctuator();
1210
            }
1211
            if (prevToken.value === '}') {
1212
                // Dividing a function by anything makes little sense,
1213
                // but we have to check for that.
1214
                if (extra.tokens[extra.openCurlyToken - 3] &&
1215
                        extra.tokens[extra.openCurlyToken - 3].type === 'Keyword') {
1216
                    // Anonymous function.
1217
                    checkToken = extra.tokens[extra.openCurlyToken - 4];
1218
                    if (!checkToken) {
1219
                        return scanPunctuator();
1220
                    }
1221
                } else if (extra.tokens[extra.openCurlyToken - 4] &&
1222
                        extra.tokens[extra.openCurlyToken - 4].type === 'Keyword') {
1223
                    // Named function.
1224
                    checkToken = extra.tokens[extra.openCurlyToken - 5];
1225
                    if (!checkToken) {
1226
                        return collectRegex();
1227
                    }
1228
                } else {
1229
                    return scanPunctuator();
1230
                }
1231
                // checkToken determines whether the function is
1232
                // a declaration or an expression.
1233
                if (FnExprTokens.indexOf(checkToken.value) >= 0) {
1234
                    // It is an expression.
1235
                    return scanPunctuator();
1236
                }
1237
                // It is a declaration.
1238
                return collectRegex();
1239
            }
1240
            return collectRegex();
1241
        }
1242
        if (prevToken.type === 'Keyword') {
1243
            return collectRegex();
1244
        }
1245
        return scanPunctuator();
1246
    }
1247
1248
    function advance() {
1249
        var ch;
1250
1251
        skipComment();
1252
1253
        if (index >= length) {
1254
            return {
1255
                type: Token.EOF,
1256
                lineNumber: lineNumber,
1257
                lineStart: lineStart,
1258
                range: [index, index]
1259
            };
1260
        }
1261
1262
        ch = source.charCodeAt(index);
1263
1264
        // Very common: ( and ) and ;
1265
        if (ch === 40 || ch === 41 || ch === 58) {
1266
            return scanPunctuator();
1267
        }
1268
1269
        // String literal starts with single quote (#39) or double quote (#34).
1270
        if (ch === 39 || ch === 34) {
1271
            return scanStringLiteral();
1272
        }
1273
1274
        if (isIdentifierStart(ch)) {
1275
            return scanIdentifier();
1276
        }
1277
1278
        // Dot (.) char #46 can also start a floating-point number, hence the need
1279
        // to check the next character.
1280
        if (ch === 46) {
1281
            if (isDecimalDigit(source.charCodeAt(index + 1))) {
1282
                return scanNumericLiteral();
1283
            }
1284
            return scanPunctuator();
1285
        }
1286
1287
        if (isDecimalDigit(ch)) {
1288
            return scanNumericLiteral();
1289
        }
1290
1291
        // Slash (/) char #47 can also start a regex.
1292
        if (extra.tokenize && ch === 47) {
1293
            return advanceSlash();
1294
        }
1295
1296
        return scanPunctuator();
1297
    }
1298
1299
    function collectToken() {
1300
        var start, loc, token, range, value;
1301
1302
        skipComment();
1303
        start = index;
1304
        loc = {
1305
            start: {
1306
                line: lineNumber,
1307
                column: index - lineStart
1308
            }
1309
        };
1310
1311
        token = advance();
1312
        loc.end = {
1313
            line: lineNumber,
1314
            column: index - lineStart
1315
        };
1316
1317
        if (token.type !== Token.EOF) {
1318
            range = [token.range[0], token.range[1]];
1319
            value = source.slice(token.range[0], token.range[1]);
1320
            extra.tokens.push({
1321
                type: TokenName[token.type],
1322
                value: value,
1323
                range: range,
1324
                loc: loc
1325
            });
1326
        }
1327
1328
        return token;
1329
    }
1330
1331
    function lex() {
1332
        var token;
1333
1334
        token = lookahead;
1335
        index = token.range[1];
1336
        lineNumber = token.lineNumber;
1337
        lineStart = token.lineStart;
1338
1339
        lookahead = (typeof extra.tokens !== 'undefined') ? collectToken() : advance();
1340
1341
        index = token.range[1];
1342
        lineNumber = token.lineNumber;
1343
        lineStart = token.lineStart;
1344
1345
        return token;
1346
    }
1347
1348
    function peek() {
1349
        var pos, line, start;
1350
1351
        pos = index;
1352
        line = lineNumber;
1353
        start = lineStart;
1354
        lookahead = (typeof extra.tokens !== 'undefined') ? collectToken() : advance();
1355
        index = pos;
1356
        lineNumber = line;
1357
        lineStart = start;
1358
    }
1359
1360
    SyntaxTreeDelegate = {
1361
1362
        name: 'SyntaxTree',
1363
1364
        markStart: function () {
1365
            if (extra.loc) {
1366
                state.markerStack.push(index - lineStart);
1367
                state.markerStack.push(lineNumber);
1368
            }
1369
            if (extra.range) {
1370
                state.markerStack.push(index);
1371
            }
1372
        },
1373
1374
        processComment: function (node) {
1375
            var i, attacher, pos, len, candidate;
1376
1377
            if (typeof node.type === 'undefined' || node.type === Syntax.Program) {
1378
                return;
1379
            }
1380
1381
            // Check for possible additional trailing comments.
1382
            peek();
1383
1384
            for (i = 0; i < extra.pendingComments.length; ++i) {
1385
                attacher = extra.pendingComments[i];
1386
                if (node.range[0] >= attacher.comment.range[1]) {
1387
                    candidate = attacher.leading;
1388
                    if (candidate) {
1389
                        pos = candidate.range[0];
1390
                        len = candidate.range[1] - pos;
1391
                        if (node.range[0] <= pos && (node.range[1] - node.range[0] >= len)) {
1392
                            attacher.leading = node;
1393
                        }
1394
                    } else {
1395
                        attacher.leading = node;
1396
                    }
1397
                }
1398
                if (node.range[1] <= attacher.comment.range[0]) {
1399
                    candidate = attacher.trailing;
1400
                    if (candidate) {
1401
                        pos = candidate.range[0];
1402
                        len = candidate.range[1] - pos;
1403
                        if (node.range[0] <= pos && (node.range[1] - node.range[0] >= len)) {
1404
                            attacher.trailing = node;
1405
                        }
1406
                    } else {
1407
                        attacher.trailing = node;
1408
                    }
1409
                }
1410
            }
1411
        },
1412
1413
        markEnd: function (node) {
1414
            if (extra.range) {
1415
                node.range = [state.markerStack.pop(), index];
1416
            }
1417
            if (extra.loc) {
1418
                node.loc = {
1419
                    start: {
1420
                        line: state.markerStack.pop(),
1421
                        column: state.markerStack.pop()
1422
                    },
1423
                    end: {
1424
                        line: lineNumber,
1425
                        column: index - lineStart
1426
                    }
1427
                };
1428
                this.postProcess(node);
1429
            }
1430
            if (extra.attachComment) {
1431
                this.processComment(node);
1432
            }
1433
            return node;
1434
        },
1435
1436
        markEndIf: function (node) {
1437
            if (node.range || node.loc) {
1438
                if (extra.loc) {
1439
                    state.markerStack.pop();
1440
                    state.markerStack.pop();
1441
                }
1442
                if (extra.range) {
1443
                    state.markerStack.pop();
1444
                }
1445
            } else {
1446
                this.markEnd(node);
1447
            }
1448
            return node;
1449
        },
1450
1451
        postProcess: function (node) {
1452
            if (extra.source) {
1453
                node.loc.source = extra.source;
1454
            }
1455
            return node;
1456
        },
1457
1458
        createArrayExpression: function (elements) {
1459
            return {
1460
                type: Syntax.ArrayExpression,
1461
                elements: elements
1462
            };
1463
        },
1464
1465
        createAssignmentExpression: function (operator, left, right) {
1466
            return {
1467
                type: Syntax.AssignmentExpression,
1468
                operator: operator,
1469
                left: left,
1470
                right: right
1471
            };
1472
        },
1473
1474
        createBinaryExpression: function (operator, left, right) {
1475
            var type = (operator === '||' || operator === '&&') ? Syntax.LogicalExpression :
1476
                        Syntax.BinaryExpression;
1477
            return {
1478
                type: type,
1479
                operator: operator,
1480
                left: left,
1481
                right: right
1482
            };
1483
        },
1484
1485
        createBlockStatement: function (body) {
1486
            return {
1487
                type: Syntax.BlockStatement,
1488
                body: body
1489
            };
1490
        },
1491
1492
        createBreakStatement: function (label) {
1493
            return {
1494
                type: Syntax.BreakStatement,
1495
                label: label
1496
            };
1497
        },
1498
1499
        createCallExpression: function (callee, args) {
1500
            return {
1501
                type: Syntax.CallExpression,
1502
                callee: callee,
1503
                'arguments': args
1504
            };
1505
        },
1506
1507
        createCatchClause: function (param, body) {
1508
            return {
1509
                type: Syntax.CatchClause,
1510
                param: param,
1511
                body: body
1512
            };
1513
        },
1514
1515
        createConditionalExpression: function (test, consequent, alternate) {
1516
            return {
1517
                type: Syntax.ConditionalExpression,
1518
                test: test,
1519
                consequent: consequent,
1520
                alternate: alternate
1521
            };
1522
        },
1523
1524
        createContinueStatement: function (label) {
1525
            return {
1526
                type: Syntax.ContinueStatement,
1527
                label: label
1528
            };
1529
        },
1530
1531
        createDebuggerStatement: function () {
1532
            return {
1533
                type: Syntax.DebuggerStatement
1534
            };
1535
        },
1536
1537
        createDoWhileStatement: function (body, test) {
1538
            return {
1539
                type: Syntax.DoWhileStatement,
1540
                body: body,
1541
                test: test
1542
            };
1543
        },
1544
1545
        createEmptyStatement: function () {
1546
            return {
1547
                type: Syntax.EmptyStatement
1548
            };
1549
        },
1550
1551
        createExpressionStatement: function (expression) {
1552
            return {
1553
                type: Syntax.ExpressionStatement,
1554
                expression: expression
1555
            };
1556
        },
1557
1558
        createForStatement: function (init, test, update, body) {
1559
            return {
1560
                type: Syntax.ForStatement,
1561
                init: init,
1562
                test: test,
1563
                update: update,
1564
                body: body
1565
            };
1566
        },
1567
1568
        createForInStatement: function (left, right, body) {
1569
            return {
1570
                type: Syntax.ForInStatement,
1571
                left: left,
1572
                right: right,
1573
                body: body,
1574
                each: false
1575
            };
1576
        },
1577
1578
        createFunctionDeclaration: function (id, params, defaults, body) {
1579
            return {
1580
                type: Syntax.FunctionDeclaration,
1581
                id: id,
1582
                params: params,
1583
                defaults: defaults,
1584
                body: body,
1585
                rest: null,
1586
                generator: false,
1587
                expression: false
1588
            };
1589
        },
1590
1591
        createFunctionExpression: function (id, params, defaults, body) {
1592
            return {
1593
                type: Syntax.FunctionExpression,
1594
                id: id,
1595
                params: params,
1596
                defaults: defaults,
1597
                body: body,
1598
                rest: null,
1599
                generator: false,
1600
                expression: false
1601
            };
1602
        },
1603
1604
        createIdentifier: function (name) {
1605
            return {
1606
                type: Syntax.Identifier,
1607
                name: name
1608
            };
1609
        },
1610
1611
        createIfStatement: function (test, consequent, alternate) {
1612
            return {
1613
                type: Syntax.IfStatement,
1614
                test: test,
1615
                consequent: consequent,
1616
                alternate: alternate
1617
            };
1618
        },
1619
1620
        createLabeledStatement: function (label, body) {
1621
            return {
1622
                type: Syntax.LabeledStatement,
1623
                label: label,
1624
                body: body
1625
            };
1626
        },
1627
1628
        createLiteral: function (token) {
1629
            return {
1630
                type: Syntax.Literal,
1631
                value: token.value,
1632
                raw: source.slice(token.range[0], token.range[1])
1633
            };
1634
        },
1635
1636
        createMemberExpression: function (accessor, object, property) {
1637
            return {
1638
                type: Syntax.MemberExpression,
1639
                computed: accessor === '[',
1640
                object: object,
1641
                property: property
1642
            };
1643
        },
1644
1645
        createNewExpression: function (callee, args) {
1646
            return {
1647
                type: Syntax.NewExpression,
1648
                callee: callee,
1649
                'arguments': args
1650
            };
1651
        },
1652
1653
        createObjectExpression: function (properties) {
1654
            return {
1655
                type: Syntax.ObjectExpression,
1656
                properties: properties
1657
            };
1658
        },
1659
1660
        createPostfixExpression: function (operator, argument) {
1661
            return {
1662
                type: Syntax.UpdateExpression,
1663
                operator: operator,
1664
                argument: argument,
1665
                prefix: false
1666
            };
1667
        },
1668
1669
        createProgram: function (body) {
1670
            return {
1671
                type: Syntax.Program,
1672
                body: body
1673
            };
1674
        },
1675
1676
        createProperty: function (kind, key, value) {
1677
            return {
1678
                type: Syntax.Property,
1679
                key: key,
1680
                value: value,
1681
                kind: kind
1682
            };
1683
        },
1684
1685
        createReturnStatement: function (argument) {
1686
            return {
1687
                type: Syntax.ReturnStatement,
1688
                argument: argument
1689
            };
1690
        },
1691
1692
        createSequenceExpression: function (expressions) {
1693
            return {
1694
                type: Syntax.SequenceExpression,
1695
                expressions: expressions
1696
            };
1697
        },
1698
1699
        createSwitchCase: function (test, consequent) {
1700
            return {
1701
                type: Syntax.SwitchCase,
1702
                test: test,
1703
                consequent: consequent
1704
            };
1705
        },
1706
1707
        createSwitchStatement: function (discriminant, cases) {
1708
            return {
1709
                type: Syntax.SwitchStatement,
1710
                discriminant: discriminant,
1711
                cases: cases
1712
            };
1713
        },
1714
1715
        createThisExpression: function () {
1716
            return {
1717
                type: Syntax.ThisExpression
1718
            };
1719
        },
1720
1721
        createThrowStatement: function (argument) {
1722
            return {
1723
                type: Syntax.ThrowStatement,
1724
                argument: argument
1725
            };
1726
        },
1727
1728
        createTryStatement: function (block, guardedHandlers, handlers, finalizer) {
1729
            return {
1730
                type: Syntax.TryStatement,
1731
                block: block,
1732
                guardedHandlers: guardedHandlers,
1733
                handlers: handlers,
1734
                finalizer: finalizer
1735
            };
1736
        },
1737
1738
        createUnaryExpression: function (operator, argument) {
1739
            if (operator === '++' || operator === '--') {
1740
                return {
1741
                    type: Syntax.UpdateExpression,
1742
                    operator: operator,
1743
                    argument: argument,
1744
                    prefix: true
1745
                };
1746
            }
1747
            return {
1748
                type: Syntax.UnaryExpression,
1749
                operator: operator,
1750
                argument: argument,
1751
                prefix: true
1752
            };
1753
        },
1754
1755
        createVariableDeclaration: function (declarations, kind) {
1756
            return {
1757
                type: Syntax.VariableDeclaration,
1758
                declarations: declarations,
1759
                kind: kind
1760
            };
1761
        },
1762
1763
        createVariableDeclarator: function (id, init) {
1764
            return {
1765
                type: Syntax.VariableDeclarator,
1766
                id: id,
1767
                init: init
1768
            };
1769
        },
1770
1771
        createWhileStatement: function (test, body) {
1772
            return {
1773
                type: Syntax.WhileStatement,
1774
                test: test,
1775
                body: body
1776
            };
1777
        },
1778
1779
        createWithStatement: function (object, body) {
1780
            return {
1781
                type: Syntax.WithStatement,
1782
                object: object,
1783
                body: body
1784
            };
1785
        }
1786
    };
1787
1788
    // Return true if there is a line terminator before the next token.
1789
1790
    function peekLineTerminator() {
1791
        var pos, line, start, found;
1792
1793
        pos = index;
1794
        line = lineNumber;
1795
        start = lineStart;
1796
        skipComment();
1797
        found = lineNumber !== line;
1798
        index = pos;
1799
        lineNumber = line;
1800
        lineStart = start;
1801
1802
        return found;
1803
    }
1804
1805
    // Throw an exception
1806
1807
    function throwError(token, messageFormat) {
1808
        var error,
1809
            args = Array.prototype.slice.call(arguments, 2),
1810
            msg = messageFormat.replace(
1811
                /%(\d)/g,
1812
                function (whole, index) {
1813
                    assert(index < args.length, 'Message reference must be in range');
1814
                    return args[index];
1815
                }
1816
            );
1817
1818
        if (typeof token.lineNumber === 'number') {
1819
            error = new Error('Line ' + token.lineNumber + ': ' + msg);
1820
            error.index = token.range[0];
1821
            error.lineNumber = token.lineNumber;
1822
            error.column = token.range[0] - lineStart + 1;
1823
        } else {
1824
            error = new Error('Line ' + lineNumber + ': ' + msg);
1825
            error.index = index;
1826
            error.lineNumber = lineNumber;
1827
            error.column = index - lineStart + 1;
1828
        }
1829
1830
        error.description = msg;
1831
        throw error;
1832
    }
1833
1834
    function throwErrorTolerant() {
1835
        try {
1836
            throwError.apply(null, arguments);
1837
        } catch (e) {
1838
            if (extra.errors) {
1839
                extra.errors.push(e);
1840
            } else {
1841
                throw e;
1842
            }
1843
        }
1844
    }
1845
1846
1847
    // Throw an exception because of the token.
1848
1849
    function throwUnexpected(token) {
1850
        if (token.type === Token.EOF) {
1851
            throwError(token, Messages.UnexpectedEOS);
1852
        }
1853
1854
        if (token.type === Token.NumericLiteral) {
1855
            throwError(token, Messages.UnexpectedNumber);
1856
        }
1857
1858
        if (token.type === Token.StringLiteral) {
1859
            throwError(token, Messages.UnexpectedString);
1860
        }
1861
1862
        if (token.type === Token.Identifier) {
1863
            throwError(token, Messages.UnexpectedIdentifier);
1864
        }
1865
1866
        if (token.type === Token.Keyword) {
1867
            if (isFutureReservedWord(token.value)) {
1868
                throwError(token, Messages.UnexpectedReserved);
1869
            } else if (strict && isStrictModeReservedWord(token.value)) {
1870
                throwErrorTolerant(token, Messages.StrictReservedWord);
1871
                return;
1872
            }
1873
            throwError(token, Messages.UnexpectedToken, token.value);
1874
        }
1875
1876
        // BooleanLiteral, NullLiteral, or Punctuator.
1877
        throwError(token, Messages.UnexpectedToken, token.value);
1878
    }
1879
1880
    // Expect the next token to match the specified punctuator.
1881
    // If not, an exception will be thrown.
1882
1883
    function expect(value) {
1884
        var token = lex();
1885
        if (token.type !== Token.Punctuator || token.value !== value) {
1886
            throwUnexpected(token);
1887
        }
1888
    }
1889
1890
    // Expect the next token to match the specified keyword.
1891
    // If not, an exception will be thrown.
1892
1893
    function expectKeyword(keyword) {
1894
        var token = lex();
1895
        if (token.type !== Token.Keyword || token.value !== keyword) {
1896
            throwUnexpected(token);
1897
        }
1898
    }
1899
1900
    // Return true if the next token matches the specified punctuator.
1901
1902
    function match(value) {
1903
        return lookahead.type === Token.Punctuator && lookahead.value === value;
1904
    }
1905
1906
    // Return true if the next token matches the specified keyword
1907
1908
    function matchKeyword(keyword) {
1909
        return lookahead.type === Token.Keyword && lookahead.value === keyword;
1910
    }
1911
1912
    // Return true if the next token is an assignment operator
1913
1914
    function matchAssign() {
1915
        var op;
1916
1917
        if (lookahead.type !== Token.Punctuator) {
1918
            return false;
1919
        }
1920
        op = lookahead.value;
1921
        return op === '=' ||
1922
            op === '*=' ||
1923
            op === '/=' ||
1924
            op === '%=' ||
1925
            op === '+=' ||
1926
            op === '-=' ||
1927
            op === '<<=' ||
1928
            op === '>>=' ||
1929
            op === '>>>=' ||
1930
            op === '&=' ||
1931
            op === '^=' ||
1932
            op === '|=';
1933
    }
1934
1935
    function consumeSemicolon() {
1936
        var line;
1937
1938
        // Catch the very common case first: immediately a semicolon (char #59).
1939
        if (source.charCodeAt(index) === 59) {
1940
            lex();
1941
            return;
1942
        }
1943
1944
        line = lineNumber;
1945
        skipComment();
1946
        if (lineNumber !== line) {
1947
            return;
1948
        }
1949
1950
        if (match(';')) {
1951
            lex();
1952
            return;
1953
        }
1954
1955
        if (lookahead.type !== Token.EOF && !match('}')) {
1956
        	if (extra.errors) {
1957
                rewind();
1958
            }
1959
            throwUnexpected(lookahead);
1960
        }
1961
    }
1962
1963
    // Return true if provided expression is LeftHandSideExpression
1964
1965
    function isLeftHandSide(expr) {
1966
        return expr.type === Syntax.Identifier || expr.type === Syntax.MemberExpression;
1967
    }
1968
1969
    // 11.1.4 Array Initialiser
1970
1971
    function parseArrayInitialiser() {
1972
        var elements = [];
1973
1974
        expect('[');
1975
1976
        while (!match(']')) {
1977
            if (match(',')) {
1978
                lex();
1979
                elements.push(null);
1980
            } else {
1981
                elements.push(parseAssignmentExpression());
1982
1983
                if (!match(']')) {
1984
                    expect(',');
1985
                }
1986
            }
1987
        }
1988
1989
        expect(']');
1990
1991
        return delegate.createArrayExpression(elements);
1992
    }
1993
1994
    // 11.1.5 Object Initialiser
1995
1996
    function parsePropertyFunction(param, first) {
1997
        var previousStrict, body;
1998
1999
        previousStrict = strict;
2000
        skipComment();
2001
        delegate.markStart();
2002
        body = parseFunctionSourceElements();
2003
        if (first && strict && isRestrictedWord(param[0].name)) {
2004
            throwErrorTolerant(first, Messages.StrictParamName);
2005
        }
2006
        strict = previousStrict;
2007
        return delegate.markEnd(delegate.createFunctionExpression(null, param, [], body));
2008
    }
2009
2010
    function parseObjectPropertyKey() {
2011
        var token;
2012
2013
        skipComment();
2014
        delegate.markStart();
2015
        token = lex();
2016
2017
        // Note: This function is called only from parseObjectProperty(), where
2018
        // EOF and Punctuator tokens are already filtered out.
2019
2020
        if (token.type === Token.StringLiteral || token.type === Token.NumericLiteral) {
2021
            if (strict && token.octal) {
2022
                throwErrorTolerant(token, Messages.StrictOctalLiteral);
2023
            }
2024
            return delegate.markEnd(delegate.createLiteral(token));
2025
        }
2026
2027
        return delegate.markEnd(delegate.createIdentifier(token.value));
2028
    }
2029
2030
    function parseObjectProperty() {
2031
        var token, key, id, value, param;
2032
2033
        token = lookahead;
2034
        skipComment();
2035
        delegate.markStart();
2036
2037
        if (token.type === Token.Identifier) {
2038
2039
            id = parseObjectPropertyKey();
2040
2041
            // Property Assignment: Getter and Setter.
2042
2043
            if (token.value === 'get' && !match(':')) {
2044
                key = parseObjectPropertyKey();
2045
                expect('(');
2046
                expect(')');
2047
                value = parsePropertyFunction([]);
2048
                return delegate.markEnd(delegate.createProperty('get', key, value));
2049
            }
2050
            if (token.value === 'set' && !match(':')) {
2051
                key = parseObjectPropertyKey();
2052
                expect('(');
2053
                token = lookahead;
2054
                if (token.type !== Token.Identifier) {
2055
                    expect(')');
2056
                    throwErrorTolerant(token, Messages.UnexpectedToken, token.value);
2057
                    value = parsePropertyFunction([]);
2058
                } else {
2059
                    param = [ parseVariableIdentifier() ];
2060
                    expect(')');
2061
                    value = parsePropertyFunction(param, token);
2062
                }
2063
                return delegate.markEnd(delegate.createProperty('set', key, value));
2064
            }
2065
            expect(':');
2066
            value = parseAssignmentExpression();
2067
            return delegate.markEnd(delegate.createProperty('init', id, value));
2068
        }
2069
        if (token.type === Token.EOF || token.type === Token.Punctuator) {
2070
            throwUnexpected(token);
2071
        } else {
2072
            key = parseObjectPropertyKey();
2073
            expect(':');
2074
            value = parseAssignmentExpression();
2075
            return delegate.markEnd(delegate.createProperty('init', key, value));
2076
        }
2077
    }
2078
2079
    function parseObjectInitialiser() {
2080
        var properties = [], property, name, key, kind, map = {}, toString = String;
2081
2082
        expect('{');
2083
2084
        while (!match('}')) {
2085
            property = parseObjectProperty();
2086
2087
            if (property.key.type === Syntax.Identifier) {
2088
                name = property.key.name;
2089
            } else {
2090
                name = toString(property.key.value);
2091
            }
2092
            kind = (property.kind === 'init') ? PropertyKind.Data : (property.kind === 'get') ? PropertyKind.Get : PropertyKind.Set;
2093
2094
            key = '$' + name;
2095
            if (Object.prototype.hasOwnProperty.call(map, key)) {
2096
                if (map[key] === PropertyKind.Data) {
2097
                    if (strict && kind === PropertyKind.Data) {
2098
                        throwErrorTolerant({}, Messages.StrictDuplicateProperty);
2099
                    } else if (kind !== PropertyKind.Data) {
2100
                        throwErrorTolerant({}, Messages.AccessorDataProperty);
2101
                    }
2102
                } else {
2103
                    if (kind === PropertyKind.Data) {
2104
                        throwErrorTolerant({}, Messages.AccessorDataProperty);
2105
                    } else if (map[key] & kind) {
2106
                        throwErrorTolerant({}, Messages.AccessorGetSet);
2107
                    }
2108
                }
2109
                map[key] |= kind;
2110
            } else {
2111
                map[key] = kind;
2112
            }
2113
2114
            properties.push(property);
2115
2116
            if (!match('}')) {
2117
                expect(',');
2118
            }
2119
        }
2120
2121
        expect('}');
2122
2123
        return delegate.createObjectExpression(properties);
2124
    }
2125
2126
    // 11.1.6 The Grouping Operator
2127
2128
    function parseGroupExpression() {
2129
        var expr;
2130
2131
        expect('(');
2132
2133
        expr = parseExpression();
2134
2135
        expect(')');
2136
2137
        return expr;
2138
    }
2139
2140
2141
    // 11.1 Primary Expressions
2142
2143
    function parsePrimaryExpression() {
2144
        var type, token, expr;
2145
2146
        if (match('(')) {
2147
            return parseGroupExpression();
2148
        }
2149
2150
        type = lookahead.type;
2151
        delegate.markStart();
2152
2153
        if (type === Token.Identifier) {
2154
            expr =  delegate.createIdentifier(lex().value);
2155
        } else if (type === Token.StringLiteral || type === Token.NumericLiteral) {
2156
            if (strict && lookahead.octal) {
2157
                throwErrorTolerant(lookahead, Messages.StrictOctalLiteral);
2158
            }
2159
            expr = delegate.createLiteral(lex());
2160
        } else if (type === Token.Keyword) {
2161
            if (matchKeyword('this')) {
2162
                lex();
2163
                expr = delegate.createThisExpression();
2164
            } else if (matchKeyword('function')) {
2165
                expr = parseFunctionExpression();
2166
            }
2167
        } else if (type === Token.BooleanLiteral) {
2168
            token = lex();
2169
            token.value = (token.value === 'true');
2170
            expr = delegate.createLiteral(token);
2171
        } else if (type === Token.NullLiteral) {
2172
            token = lex();
2173
            token.value = null;
2174
            expr = delegate.createLiteral(token);
2175
        } else if (match('[')) {
2176
            expr = parseArrayInitialiser();
2177
        } else if (match('{')) {
2178
            expr = parseObjectInitialiser();
2179
        } else if (match('/') || match('/=')) {
2180
            if (typeof extra.tokens !== 'undefined') {
2181
                expr = delegate.createLiteral(collectRegex());
2182
            } else {
2183
                expr = delegate.createLiteral(scanRegExp());
2184
            }
2185
            peek();
2186
        }
2187
2188
        if (expr) {
2189
            return delegate.markEnd(expr);
2190
        }
2191
2192
        throwUnexpected(lex());
2193
    }
2194
2195
    // 11.2 Left-Hand-Side Expressions
2196
2197
    function parseArguments() {
2198
        var args = [];
2199
2200
        expect('(');
2201
2202
        if (!match(')')) {
2203
            while (index < length) {
2204
                args.push(parseAssignmentExpression());
2205
                if (match(')')) {
2206
                    break;
2207
                }
2208
               try {
2209
                    expect(',');
2210
                } catch (e) {
2211
                    if (extra.errors) {
2212
                        // pretend the argument list is done
2213
                        pushError(e);
2214
                        break;
2215
                    } else {
2216
                        throw e;
2217
                    }
2218
                }
2219
            }
2220
        }
2221
2222
        //expect(')');
2223
        expectConditionCloseParenWrapThrow();
2224
2225
        return args;
2226
    }
2227
2228
    function parseNonComputedProperty() {
2229
        var token;
2230
2231
        delegate.markStart();
2232
        token = lex();
2233
2234
        if (!isIdentifierName(token)) {
2235
        	if (extra.errors) {
2236
                attemptRecoveryNonComputedProperty(token);
2237
            }
2238
            throwUnexpected(token);
2239
        }
2240
2241
        return delegate.markEnd(delegate.createIdentifier(token.value));
2242
    }
2243
2244
    function parseNonComputedMember() {
2245
        expect('.');
2246
2247
        return parseNonComputedProperty();
2248
    }
2249
2250
    function parseComputedMember() {
2251
        var expr;
2252
2253
        expect('[');
2254
2255
        expr = parseExpression();
2256
2257
        expect(']');
2258
2259
        return expr;
2260
    }
2261
2262
    function parseNewExpression() {
2263
        var callee, args;
2264
2265
        delegate.markStart();
2266
        expectKeyword('new');
2267
        callee = parseLeftHandSideExpression();
2268
        args = match('(') ? parseArguments() : [];
2269
2270
        return delegate.markEnd(delegate.createNewExpression(callee, args));
2271
    }
2272
2273
    function parseLeftHandSideExpressionAllowCall() {
2274
        var marker, previousAllowIn, expr, args, property;
2275
2276
        marker = createLocationMarker();
2277
2278
        previousAllowIn = state.allowIn;
2279
        state.allowIn = true;
2280
        expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression();
2281
        state.allowIn = previousAllowIn;
2282
2283
        while (match('.') || match('[') || match('(')) {
2284
            if (match('(')) {
2285
                args = parseArguments();
2286
                expr = delegate.createCallExpression(expr, args);
2287
            } else if (match('[')) {
2288
                property = parseComputedMember();
2289
                expr = delegate.createMemberExpression('[', expr, property);
2290
            } else {
2291
                property = parseNonComputedMember();
2292
                expr = delegate.createMemberExpression('.', expr, property);
2293
            }
2294
            if (marker) {
2295
                marker.end();
2296
                marker.apply(expr);
2297
            }
2298
        }
2299
2300
        return expr;
2301
    }
2302
2303
    function parseLeftHandSideExpression() {
2304
        var marker, previousAllowIn, expr, property;
2305
2306
        marker = createLocationMarker();
2307
2308
        previousAllowIn = state.allowIn;
2309
        expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression();
2310
        state.allowIn = previousAllowIn;
2311
2312
        while (match('.') || match('[')) {
2313
            if (match('[')) {
2314
                property = parseComputedMember();
2315
                expr = delegate.createMemberExpression('[', expr, property);
2316
            } else {
2317
                property = parseNonComputedMember();
2318
                expr = delegate.createMemberExpression('.', expr, property);
2319
            }
2320
            if (marker) {
2321
                marker.end();
2322
                marker.apply(expr);
2323
            }
2324
        }
2325
2326
        return expr;
2327
    }
2328
2329
    // 11.3 Postfix Expressions
2330
2331
    function parsePostfixExpression() {
2332
        var expr, token;
2333
2334
        delegate.markStart();
2335
        expr = parseLeftHandSideExpressionAllowCall();
2336
2337
        if (lookahead.type === Token.Punctuator) {
2338
            if ((match('++') || match('--')) && !peekLineTerminator()) {
2339
                // 11.3.1, 11.3.2
2340
                if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) {
2341
                    throwErrorTolerant({}, Messages.StrictLHSPostfix);
2342
                }
2343
2344
                if (!isLeftHandSide(expr)) {
2345
                    throwErrorTolerant({}, Messages.InvalidLHSInAssignment);
2346
                }
2347
2348
                token = lex();
2349
                expr = delegate.createPostfixExpression(token.value, expr);
2350
            }
2351
        }
2352
2353
        return delegate.markEndIf(expr);
2354
    }
2355
2356
    // 11.4 Unary Operators
2357
2358
    function parseUnaryExpression() {
2359
        var token, expr;
2360
2361
        delegate.markStart();
2362
2363
        if (lookahead.type !== Token.Punctuator && lookahead.type !== Token.Keyword) {
2364
            expr = parsePostfixExpression();
2365
        } else if (match('++') || match('--')) {
2366
            token = lex();
2367
            expr = parseUnaryExpression();
2368
            // 11.4.4, 11.4.5
2369
            if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) {
2370
                throwErrorTolerant({}, Messages.StrictLHSPrefix);
2371
            }
2372
2373
            if (!isLeftHandSide(expr)) {
2374
                throwErrorTolerant({}, Messages.InvalidLHSInAssignment);
2375
            }
2376
2377
            expr = delegate.createUnaryExpression(token.value, expr);
2378
        } else if (match('+') || match('-') || match('~') || match('!')) {
2379
            token = lex();
2380
            expr = parseUnaryExpression();
2381
            expr = delegate.createUnaryExpression(token.value, expr);
2382
        } else if (matchKeyword('delete') || matchKeyword('void') || matchKeyword('typeof')) {
2383
            token = lex();
2384
            expr = parseUnaryExpression();
2385
            expr = delegate.createUnaryExpression(token.value, expr);
2386
            if (strict && expr.operator === 'delete' && expr.argument.type === Syntax.Identifier) {
2387
                throwErrorTolerant({}, Messages.StrictDelete);
2388
            }
2389
        } else {
2390
            expr = parsePostfixExpression();
2391
        }
2392
2393
        return delegate.markEndIf(expr);
2394
    }
2395
2396
    function binaryPrecedence(token, allowIn) {
2397
        var prec = 0;
2398
2399
        if (token.type !== Token.Punctuator && token.type !== Token.Keyword) {
2400
            return 0;
2401
        }
2402
2403
        switch (token.value) {
2404
        case '||':
2405
            prec = 1;
2406
            break;
2407
2408
        case '&&':
2409
            prec = 2;
2410
            break;
2411
2412
        case '|':
2413
            prec = 3;
2414
            break;
2415
2416
        case '^':
2417
            prec = 4;
2418
            break;
2419
2420
        case '&':
2421
            prec = 5;
2422
            break;
2423
2424
        case '==':
2425
        case '!=':
2426
        case '===':
2427
        case '!==':
2428
            prec = 6;
2429
            break;
2430
2431
        case '<':
2432
        case '>':
2433
        case '<=':
2434
        case '>=':
2435
        case 'instanceof':
2436
            prec = 7;
2437
            break;
2438
2439
        case 'in':
2440
            prec = allowIn ? 7 : 0;
2441
            break;
2442
2443
        case '<<':
2444
        case '>>':
2445
        case '>>>':
2446
            prec = 8;
2447
            break;
2448
2449
        case '+':
2450
        case '-':
2451
            prec = 9;
2452
            break;
2453
2454
        case '*':
2455
        case '/':
2456
        case '%':
2457
            prec = 11;
2458
            break;
2459
2460
        default:
2461
            break;
2462
        }
2463
2464
        return prec;
2465
    }
2466
2467
    // 11.5 Multiplicative Operators
2468
    // 11.6 Additive Operators
2469
    // 11.7 Bitwise Shift Operators
2470
    // 11.8 Relational Operators
2471
    // 11.9 Equality Operators
2472
    // 11.10 Binary Bitwise Operators
2473
    // 11.11 Binary Logical Operators
2474
2475
    function parseBinaryExpression() {
2476
        var marker, markers, expr, token, prec, stack, right, operator, left, i;
2477
2478
        marker = createLocationMarker();
2479
        left = parseUnaryExpression();
2480
2481
        token = lookahead;
2482
        prec = binaryPrecedence(token, state.allowIn);
2483
        if (prec === 0) {
2484
            return left;
2485
        }
2486
        token.prec = prec;
2487
        lex();
2488
2489
        markers = [marker, createLocationMarker()];
2490
        right = parseUnaryExpression();
2491
2492
        stack = [left, token, right];
2493
2494
        while ((prec = binaryPrecedence(lookahead, state.allowIn)) > 0) {
2495
2496
            // Reduce: make a binary expression from the three topmost entries.
2497
            while ((stack.length > 2) && (prec <= stack[stack.length - 2].prec)) {
2498
                right = stack.pop();
2499
                operator = stack.pop().value;
2500
                left = stack.pop();
2501
                expr = delegate.createBinaryExpression(operator, left, right);
2502
                markers.pop();
2503
                marker = markers.pop();
2504
                if (marker) {
2505
                    marker.end();
2506
                    marker.apply(expr);
2507
                }
2508
                stack.push(expr);
2509
                markers.push(marker);
2510
            }
2511
2512
            // Shift.
2513
            token = lex();
2514
            token.prec = prec;
2515
            stack.push(token);
2516
            markers.push(createLocationMarker());
2517
            expr = parseUnaryExpression();
2518
            stack.push(expr);
2519
        }
2520
2521
        // Final reduce to clean-up the stack.
2522
        i = stack.length - 1;
2523
        expr = stack[i];
2524
        markers.pop();
2525
        while (i > 1) {
2526
            expr = delegate.createBinaryExpression(stack[i - 1].value, stack[i - 2], expr);
2527
            i -= 2;
2528
            marker = markers.pop();
2529
            if (marker) {
2530
                marker.end();
2531
                marker.apply(expr);
2532
            }
2533
        }
2534
2535
        return expr;
2536
    }
2537
2538
2539
    // 11.12 Conditional Operator
2540
2541
    function parseConditionalExpression() {
2542
        var expr, previousAllowIn, consequent, alternate;
2543
2544
        delegate.markStart();
2545
        expr = parseBinaryExpression();
2546
2547
        if (match('?')) {
2548
            lex();
2549
            previousAllowIn = state.allowIn;
2550
            state.allowIn = true;
2551
            consequent = parseAssignmentExpression();
2552
            state.allowIn = previousAllowIn;
2553
            expect(':');
2554
            alternate = parseAssignmentExpression();
2555
2556
            expr = delegate.markEnd(delegate.createConditionalExpression(expr, consequent, alternate));
2557
        } else {
2558
            delegate.markEnd({});
2559
        }
2560
2561
        return expr;
2562
    }
2563
2564
    // 11.13 Assignment Operators
2565
2566
    function parseAssignmentExpression() {
2567
        var token, left, right, node;
2568
2569
        token = lookahead;
2570
        delegate.markStart();
2571
        node = left = parseConditionalExpression();
2572
2573
        if (matchAssign()) {
2574
            // LeftHandSideExpression
2575
            if (!isLeftHandSide(left)) {
2576
                throwErrorTolerant({}, Messages.InvalidLHSInAssignment);
2577
            }
2578
2579
            // 11.13.1
2580
            if (strict && left.type === Syntax.Identifier && isRestrictedWord(left.name)) {
2581
                throwErrorTolerant(token, Messages.StrictLHSAssignment);
2582
            }
2583
2584
            token = lex();
2585
            right = parseAssignmentExpression();
2586
            node = delegate.createAssignmentExpression(token.value, left, right);
2587
        }
2588
2589
        return delegate.markEndIf(node);
2590
    }
2591
2592
    // 11.14 Comma Operator
2593
2594
    function parseExpression() {
2595
        var expr;
2596
2597
        delegate.markStart();
2598
        expr = parseAssignmentExpression();
2599
2600
        if (match(',')) {
2601
            expr = delegate.createSequenceExpression([ expr ]);
2602
2603
            while (index < length) {
2604
                if (!match(',')) {
2605
                    break;
2606
                }
2607
                lex();
2608
                expr.expressions.push(parseAssignmentExpression());
2609
            }
2610
        }
2611
2612
        return delegate.markEndIf(expr);
2613
    }
2614
2615
    // 12.1 Block
2616
2617
    function parseStatementList() {
2618
        var list = [],
2619
            statement;
2620
2621
        while (index < length) {
2622
            if (match('}')) {
2623
                break;
2624
            }
2625
            statement = parseSourceElement();
2626
            if (typeof statement === 'undefined') {
2627
                break;
2628
            }
2629
            list.push(statement);
2630
        }
2631
2632
        return list;
2633
    }
2634
2635
    function parseBlock() {
2636
        var block;
2637
2638
        skipComment();
2639
        delegate.markStart();
2640
        expect('{');
2641
2642
        block = parseStatementList();
2643
2644
        //expect('}');
2645
        expectConditionCloseBracketWrapThrow();
2646
2647
        return delegate.markEnd(delegate.createBlockStatement(block));
2648
    }
2649
2650
    // 12.2 Variable Statement
2651
2652
    function parseVariableIdentifier() {
2653
        var token;
2654
2655
        skipComment();
2656
        delegate.markStart();
2657
        token = lex();
2658
2659
        if (token.type !== Token.Identifier) {
2660
            throwUnexpected(token);
2661
        }
2662
2663
        return delegate.markEnd(delegate.createIdentifier(token.value));
2664
    }
2665
2666
    function parseVariableDeclaration(kind) {
2667
        var init = null, id;
2668
2669
        skipComment();
2670
        delegate.markStart();
2671
        id = parseVariableIdentifier();
2672
2673
        // 12.2.1
2674
        if (strict && isRestrictedWord(id.name)) {
2675
            throwErrorTolerant({}, Messages.StrictVarName);
2676
        }
2677
2678
        if (kind === 'const') {
2679
            expect('=');
2680
            init = parseAssignmentExpression();
2681
        } else if (match('=')) {
2682
            lex();
2683
            init = parseAssignmentExpression();
2684
        }
2685
2686
        return delegate.markEnd(delegate.createVariableDeclarator(id, init));
2687
    }
2688
2689
    function parseVariableDeclarationList(kind) {
2690
        var list = [];
2691
2692
        do {
2693
            list.push(parseVariableDeclaration(kind));
2694
            if (!match(',')) {
2695
                break;
2696
            }
2697
            lex();
2698
        } while (index < length);
2699
2700
        return list;
2701
    }
2702
2703
    function parseVariableStatement() {
2704
        var declarations;
2705
2706
        expectKeyword('var');
2707
2708
        declarations = parseVariableDeclarationList();
2709
2710
        consumeSemicolon();
2711
2712
        return delegate.createVariableDeclaration(declarations, 'var');
2713
    }
2714
2715
    // kind may be `const` or `let`
2716
    // Both are experimental and not in the specification yet.
2717
    // see http://wiki.ecmascript.org/doku.php?id=harmony:const
2718
    // and http://wiki.ecmascript.org/doku.php?id=harmony:let
2719
    function parseConstLetDeclaration(kind) {
2720
        var declarations;
2721
2722
        skipComment();
2723
        delegate.markStart();
2724
2725
        expectKeyword(kind);
2726
2727
        declarations = parseVariableDeclarationList(kind);
2728
2729
        consumeSemicolon();
2730
2731
        return delegate.markEnd(delegate.createVariableDeclaration(declarations, kind));
2732
    }
2733
2734
    // 12.3 Empty Statement
2735
2736
    function parseEmptyStatement() {
2737
        expect(';');
2738
        return delegate.createEmptyStatement();
2739
    }
2740
2741
    // 12.4 Expression Statement
2742
2743
    function parseExpressionStatement() {
2744
        var expr = parseExpression();
2745
        consumeSemicolon();
2746
        return delegate.createExpressionStatement(expr);
2747
    }
2748
2749
    // 12.5 If statement
2750
2751
    function parseIfStatement() {
2752
    	
2753
        var test, consequent, alternate;
2754
2755
        expectKeyword('if');
2756
2757
        expect('(');
2758
2759
        test = parseExpression();
2760
2761
        //expect(')');
2762
        expectConditionCloseParenWrapThrow();
2763
2764
        consequent = parseStatement();
2765
		// required because of the check in wrapTracking that returns nothing if node is undefined
2766
        if (!consequent) {
2767
            consequent = null;
2768
        }
2769
        if (matchKeyword('else')) {
2770
            lex();
2771
            alternate = parseStatement();
2772
        } else {
2773
            alternate = null;
2774
        }
2775
2776
        return delegate.createIfStatement(test, consequent, alternate);
2777
    }
2778
2779
    // 12.6 Iteration Statements
2780
2781
    function parseDoWhileStatement() {
2782
        var body, test, oldInIteration;
2783
2784
        expectKeyword('do');
2785
2786
        oldInIteration = state.inIteration;
2787
        state.inIteration = true;
2788
2789
        body = parseStatement();
2790
2791
        state.inIteration = oldInIteration;
2792
2793
        expectKeyword('while');
2794
2795
        expect('(');
2796
2797
        test = parseExpression();
2798
2799
        expect(')');
2800
2801
        if (match(';')) {
2802
            lex();
2803
        }
2804
2805
        return delegate.createDoWhileStatement(body, test);
2806
    }
2807
2808
    function parseWhileStatement() {
2809
        var test, body, oldInIteration;
2810
2811
        expectKeyword('while');
2812
2813
        expect('(');
2814
2815
        test = parseExpression();
2816
2817
        //expect(')');
2818
        expectConditionCloseParenWrapThrow();
2819
2820
        oldInIteration = state.inIteration;
2821
        state.inIteration = true;
2822
2823
        body = parseStatement();
2824
2825
        state.inIteration = oldInIteration;
2826
2827
        return delegate.createWhileStatement(test, body);
2828
    }
2829
2830
    function parseForVariableDeclaration() {
2831
        var token, declarations;
2832
2833
        delegate.markStart();
2834
        token = lex();
2835
        declarations = parseVariableDeclarationList();
2836
2837
        return delegate.markEnd(delegate.createVariableDeclaration(declarations, token.value));
2838
    }
2839
2840
    function parseForStatement() {
2841
        var init, test, update, left, right, body, oldInIteration;
2842
2843
        init = test = update = null;
2844
2845
        expectKeyword('for');
2846
2847
        expect('(');
2848
2849
        if (match(';')) {
2850
            lex();
2851
        } else {
2852
            if (matchKeyword('var') || matchKeyword('let')) {
2853
                state.allowIn = false;
2854
                init = parseForVariableDeclaration();
2855
                state.allowIn = true;
2856
2857
                if (init.declarations.length === 1 && matchKeyword('in')) {
2858
                    lex();
2859
                    left = init;
2860
                    right = parseExpression();
2861
                    init = null;
2862
                }
2863
            } else {
2864
                state.allowIn = false;
2865
                init = parseExpression();
2866
                state.allowIn = true;
2867
2868
                if (matchKeyword('in')) {
2869
                    // LeftHandSideExpression
2870
                    if (!isLeftHandSide(init)) {
2871
                        throwErrorTolerant({}, Messages.InvalidLHSInForIn);
2872
                    }
2873
2874
                    lex();
2875
                    left = init;
2876
                    right = parseExpression();
2877
                    init = null;
2878
                }
2879
            }
2880
2881
            if (typeof left === 'undefined') {
2882
                expect(';');
2883
            }
2884
        }
2885
2886
        if (typeof left === 'undefined') {
2887
2888
            if (!match(';')) {
2889
                test = parseExpression();
2890
            }
2891
            expect(';');
2892
2893
            if (!match(')')) {
2894
                update = parseExpression();
2895
            }
2896
        }
2897
2898
        //expect(')');
2899
        expectConditionCloseParenWrapThrow();
2900
2901
        oldInIteration = state.inIteration;
2902
        state.inIteration = true;
2903
2904
        body = parseStatement();
2905
2906
        state.inIteration = oldInIteration;
2907
2908
        return (typeof left === 'undefined') ?
2909
                delegate.createForStatement(init, test, update, body) :
2910
                delegate.createForInStatement(left, right, body);
2911
    }
2912
2913
    // 12.7 The continue statement
2914
2915
    function parseContinueStatement() {
2916
        var label = null, key;
2917
2918
        expectKeyword('continue');
2919
2920
        // Optimize the most common form: 'continue;'.
2921
        if (source.charCodeAt(index) === 59) {
2922
            lex();
2923
2924
            if (!state.inIteration) {
2925
                throwError({}, Messages.IllegalContinue);
2926
            }
2927
2928
            return delegate.createContinueStatement(null);
2929
        }
2930
2931
        if (peekLineTerminator()) {
2932
            if (!state.inIteration) {
2933
                throwError({}, Messages.IllegalContinue);
2934
            }
2935
2936
            return delegate.createContinueStatement(null);
2937
        }
2938
2939
        if (lookahead.type === Token.Identifier) {
2940
            label = parseVariableIdentifier();
2941
2942
            key = '$' + label.name;
2943
            if (!Object.prototype.hasOwnProperty.call(state.labelSet, key)) {
2944
                throwError({}, Messages.UnknownLabel, label.name);
2945
            }
2946
        }
2947
2948
        consumeSemicolon();
2949
2950
        if (label === null && !state.inIteration) {
2951
            throwError({}, Messages.IllegalContinue);
2952
        }
2953
2954
        return delegate.createContinueStatement(label);
2955
    }
2956
2957
    // 12.8 The break statement
2958
2959
    function parseBreakStatement() {
2960
        var label = null, key;
2961
2962
        expectKeyword('break');
2963
2964
        // Catch the very common case first: immediately a semicolon (char #59).
2965
        if (source.charCodeAt(index) === 59) {
2966
            lex();
2967
2968
            if (!(state.inIteration || state.inSwitch)) {
2969
                throwError({}, Messages.IllegalBreak);
2970
            }
2971
2972
            return delegate.createBreakStatement(null);
2973
        }
2974
2975
        if (peekLineTerminator()) {
2976
            if (!(state.inIteration || state.inSwitch)) {
2977
                throwError({}, Messages.IllegalBreak);
2978
            }
2979
2980
            return delegate.createBreakStatement(null);
2981
        }
2982
2983
        if (lookahead.type === Token.Identifier) {
2984
            label = parseVariableIdentifier();
2985
2986
            key = '$' + label.name;
2987
            if (!Object.prototype.hasOwnProperty.call(state.labelSet, key)) {
2988
                throwError({}, Messages.UnknownLabel, label.name);
2989
            }
2990
        }
2991
2992
        consumeSemicolon();
2993
2994
        if (label === null && !(state.inIteration || state.inSwitch)) {
2995
            throwError({}, Messages.IllegalBreak);
2996
        }
2997
2998
        return delegate.createBreakStatement(label);
2999
    }
3000
3001
    // 12.9 The return statement
3002
3003
    function parseReturnStatement() {
3004
        var argument = null;
3005
3006
        expectKeyword('return');
3007
3008
        if (!state.inFunctionBody) {
3009
            throwErrorTolerant({}, Messages.IllegalReturn);
3010
        }
3011
3012
        // 'return' followed by a space and an identifier is very common.
3013
        if (source.charCodeAt(index) === 32) {
3014
            if (isIdentifierStart(source.charCodeAt(index + 1))) {
3015
                argument = parseExpression();
3016
                consumeSemicolon();
3017
                return delegate.createReturnStatement(argument);
3018
            }
3019
        }
3020
3021
        if (peekLineTerminator()) {
3022
            return delegate.createReturnStatement(null);
3023
        }
3024
3025
        if (!match(';')) {
3026
            if (!match('}') && lookahead.type !== Token.EOF) {
3027
                argument = parseExpression();
3028
            }
3029
        }
3030
3031
        consumeSemicolon();
3032
3033
        return delegate.createReturnStatement(argument);
3034
    }
3035
3036
    // 12.10 The with statement
3037
3038
    function parseWithStatement() {
3039
        var object, body;
3040
3041
        if (strict) {
3042
            throwErrorTolerant({}, Messages.StrictModeWith);
3043
        }
3044
3045
        expectKeyword('with');
3046
3047
        expect('(');
3048
3049
        object = parseExpression();
3050
3051
        expect(')');
3052
3053
        body = parseStatement();
3054
3055
        return delegate.createWithStatement(object, body);
3056
    }
3057
3058
    // 12.10 The swith statement
3059
3060
    function parseSwitchCase() {
3061
        var test,
3062
            consequent = [],
3063
            statement;
3064
3065
        skipComment();
3066
        delegate.markStart();
3067
        if (matchKeyword('default')) {
3068
            lex();
3069
            test = null;
3070
        } else {
3071
            expectKeyword('case');
3072
            test = parseExpression();
3073
        }
3074
        expect(':');
3075
3076
        while (index < length) {
3077
            if (match('}') || matchKeyword('default') || matchKeyword('case')) {
3078
                break;
3079
            }
3080
            statement = parseStatement();
3081
            consequent.push(statement);
3082
        }
3083
3084
        return delegate.markEnd(delegate.createSwitchCase(test, consequent));
3085
    }
3086
3087
    function parseSwitchStatement() {
3088
        var discriminant, cases, clause, oldInSwitch, defaultFound;
3089
3090
        expectKeyword('switch');
3091
3092
        expect('(');
3093
3094
        discriminant = parseExpression();
3095
3096
        expect(')');
3097
3098
        expect('{');
3099
3100
        cases = [];
3101
3102
        if (match('}')) {
3103
            lex();
3104
            return delegate.createSwitchStatement(discriminant, cases);
3105
        }
3106
3107
        oldInSwitch = state.inSwitch;
3108
        state.inSwitch = true;
3109
        defaultFound = false;
3110
3111
        while (index < length) {
3112
            if (match('}')) {
3113
                break;
3114
            }
3115
            clause = parseSwitchCase();
3116
            if (clause.test === null) {
3117
                if (defaultFound) {
3118
                    throwError({}, Messages.MultipleDefaultsInSwitch);
3119
                }
3120
                defaultFound = true;
3121
            }
3122
            cases.push(clause);
3123
        }
3124
3125
        state.inSwitch = oldInSwitch;
3126
3127
        expect('}');
3128
3129
        return delegate.createSwitchStatement(discriminant, cases);
3130
    }
3131
3132
    // 12.13 The throw statement
3133
3134
    function parseThrowStatement() {
3135
        var argument;
3136
3137
        expectKeyword('throw');
3138
3139
        if (peekLineTerminator()) {
3140
            throwError({}, Messages.NewlineAfterThrow);
3141
        }
3142
3143
        argument = parseExpression();
3144
3145
        consumeSemicolon();
3146
3147
        return delegate.createThrowStatement(argument);
3148
    }
3149
3150
    // 12.14 The try statement
3151
3152
    function parseCatchClause() {
3153
        var param, body;
3154
3155
        skipComment();
3156
        delegate.markStart();
3157
        expectKeyword('catch');
3158
3159
        expect('(');
3160
        if (match(')')) {
3161
            throwUnexpected(lookahead);
3162
        }
3163
3164
        param = parseVariableIdentifier();
3165
        // 12.14.1
3166
        if (strict && isRestrictedWord(param.name)) {
3167
            throwErrorTolerant({}, Messages.StrictCatchVariable);
3168
        }
3169
3170
        expect(')');
3171
        body = parseBlock();
3172
        return delegate.markEnd(delegate.createCatchClause(param, body));
3173
    }
3174
3175
    function parseTryStatement() {
3176
        var block, handlers = [], finalizer = null;
3177
3178
        expectKeyword('try');
3179
3180
        block = parseBlock();
3181
3182
        if (matchKeyword('catch')) {
3183
            handlers.push(parseCatchClause());
3184
        }
3185
3186
        if (matchKeyword('finally')) {
3187
            lex();
3188
            finalizer = parseBlock();
3189
        }
3190
3191
        if (handlers.length === 0 && !finalizer) {
3192
            throwError({}, Messages.NoCatchOrFinally);
3193
        }
3194
3195
        return delegate.createTryStatement(block, [], handlers, finalizer);
3196
    }
3197
3198
    // 12.15 The debugger statement
3199
3200
    function parseDebuggerStatement() {
3201
        expectKeyword('debugger');
3202
3203
        consumeSemicolon();
3204
3205
        return delegate.createDebuggerStatement();
3206
    }
3207
3208
    // 12 Statements
3209
3210
    function parseStatement() {
3211
        var type = lookahead.type,
3212
            expr,
3213
            labeledBody,
3214
            key;
3215
3216
        if (type === Token.EOF) {
3217
            throwUnexpected(lookahead);
3218
        }
3219
3220
        skipComment();
3221
        delegate.markStart();
3222
3223
        if (type === Token.Punctuator) {
3224
            switch (lookahead.value) {
3225
            case ';':
3226
                return delegate.markEnd(parseEmptyStatement());
3227
            case '{':
3228
                return delegate.markEnd(parseBlock());
3229
            case '(':
3230
                return delegate.markEnd(parseExpressionStatement());
3231
            default:
3232
                break;
3233
            }
3234
        }
3235
3236
        if (type === Token.Keyword) {
3237
            switch (lookahead.value) {
3238
            case 'break':
3239
                return delegate.markEnd(parseBreakStatement());
3240
            case 'continue':
3241
                return delegate.markEnd(parseContinueStatement());
3242
            case 'debugger':
3243
                return delegate.markEnd(parseDebuggerStatement());
3244
            case 'do':
3245
                return delegate.markEnd(parseDoWhileStatement());
3246
            case 'for':
3247
                return delegate.markEnd(parseForStatement());
3248
            case 'function':
3249
                return delegate.markEnd(parseFunctionDeclaration());
3250
            case 'if':
3251
                return delegate.markEnd(parseIfStatement());
3252
            case 'return':
3253
                return delegate.markEnd(parseReturnStatement());
3254
            case 'switch':
3255
                return delegate.markEnd(parseSwitchStatement());
3256
            case 'throw':
3257
                return delegate.markEnd(parseThrowStatement());
3258
            case 'try':
3259
                return delegate.markEnd(parseTryStatement());
3260
            case 'var':
3261
                return delegate.markEnd(parseVariableStatement());
3262
            case 'while':
3263
                return delegate.markEnd(parseWhileStatement());
3264
            case 'with':
3265
                return delegate.markEnd(parseWithStatement());
3266
            default:
3267
                break;
3268
            }
3269
        }
3270
3271
        expr = parseExpression();
3272
3273
        // 12.12 Labelled Statements
3274
        if (expr && (expr.type === Syntax.Identifier) && match(':')) {
3275
            lex();
3276
3277
            key = '$' + expr.name;
3278
            if (Object.prototype.hasOwnProperty.call(state.labelSet, key)) {
3279
                throwError({}, Messages.Redeclaration, 'Label', expr.name);
3280
            }
3281
3282
            state.labelSet[key] = true;
3283
            labeledBody = parseStatement();
3284
            delete state.labelSet[key];
3285
            return delegate.markEnd(delegate.createLabeledStatement(expr, labeledBody));
3286
        }
3287
3288
        consumeSemicolon();
3289
3290
        return delegate.markEnd(delegate.createExpressionStatement(expr));
3291
    }
3292
3293
    // 13 Function Definition
3294
3295
    function parseFunctionSourceElements() {
3296
        var sourceElement, sourceElements = [], token, directive, firstRestricted,
3297
            oldLabelSet, oldInIteration, oldInSwitch, oldInFunctionBody;
3298
3299
        skipComment();
3300
        delegate.markStart();
3301
        expect('{');
3302
3303
        while (index < length) {
3304
            if (lookahead.type !== Token.StringLiteral) {
3305
                break;
3306
            }
3307
            token = lookahead;
3308
3309
            sourceElement = parseSourceElement();
3310
            sourceElements.push(sourceElement);
3311
            if (sourceElement.expression.type !== Syntax.Literal) {
3312
                // this is not directive
3313
                break;
3314
            }
3315
            directive = source.slice(token.range[0] + 1, token.range[1] - 1);
3316
            if (directive === 'use strict') {
3317
                strict = true;
3318
                if (firstRestricted) {
3319
                    throwErrorTolerant(firstRestricted, Messages.StrictOctalLiteral);
3320
                }
3321
            } else {
3322
                if (!firstRestricted && token.octal) {
3323
                    firstRestricted = token;
3324
                }
3325
            }
3326
        }
3327
3328
        oldLabelSet = state.labelSet;
3329
        oldInIteration = state.inIteration;
3330
        oldInSwitch = state.inSwitch;
3331
        oldInFunctionBody = state.inFunctionBody;
3332
3333
        state.labelSet = {};
3334
        state.inIteration = false;
3335
        state.inSwitch = false;
3336
        state.inFunctionBody = true;
3337
3338
        while (index < length) {
3339
            if (match('}')) {
3340
                break;
3341
            }
3342
            sourceElement = parseSourceElement();
3343
            if (typeof sourceElement === 'undefined') {
3344
                break;
3345
            }
3346
            sourceElements.push(sourceElement);
3347
        }
3348
3349
        //expect('}');
3350
        expectConditionCloseBracketWrapThrow();
3351
3352
        state.labelSet = oldLabelSet;
3353
        state.inIteration = oldInIteration;
3354
        state.inSwitch = oldInSwitch;
3355
        state.inFunctionBody = oldInFunctionBody;
3356
3357
        return delegate.markEnd(delegate.createBlockStatement(sourceElements));
3358
    }
3359
3360
    function parseParams(firstRestricted) {
3361
        var param, params = [], token, stricted, paramSet, key, message;
3362
        expect('(');
3363
3364
        if (!match(')')) {
3365
            paramSet = {};
3366
            while (index < length) {
3367
                token = lookahead;
3368
                param = parseVariableIdentifier();
3369
                key = '$' + token.value;
3370
                if (strict) {
3371
                    if (isRestrictedWord(token.value)) {
3372
                        stricted = token;
3373
                        message = Messages.StrictParamName;
3374
                    }
3375
                    if (Object.prototype.hasOwnProperty.call(paramSet, key)) {
3376
                        stricted = token;
3377
                        message = Messages.StrictParamDupe;
3378
                    }
3379
                } else if (!firstRestricted) {
3380
                    if (isRestrictedWord(token.value)) {
3381
                        firstRestricted = token;
3382
                        message = Messages.StrictParamName;
3383
                    } else if (isStrictModeReservedWord(token.value)) {
3384
                        firstRestricted = token;
3385
                        message = Messages.StrictReservedWord;
3386
                    } else if (Object.prototype.hasOwnProperty.call(paramSet, key)) {
3387
                        firstRestricted = token;
3388
                        message = Messages.StrictParamDupe;
3389
                    }
3390
                }
3391
                params.push(param);
3392
                paramSet[key] = true;
3393
                if (match(')')) {
3394
                    break;
3395
                }
3396
                expect(',');
3397
            }
3398
        }
3399
3400
        expect(')');
3401
3402
        return {
3403
            params: params,
3404
            stricted: stricted,
3405
            firstRestricted: firstRestricted,
3406
            message: message
3407
        };
3408
    }
3409
3410
    function parseFunctionDeclaration() {
3411
        var id, params = [], body, token, stricted, tmp, firstRestricted, message, previousStrict;
3412
3413
        skipComment();
3414
        delegate.markStart();
3415
3416
        expectKeyword('function');
3417
        token = lookahead;
3418
        id = parseVariableIdentifier();
3419
        if (strict) {
3420
            if (isRestrictedWord(token.value)) {
3421
                throwErrorTolerant(token, Messages.StrictFunctionName);
3422
            }
3423
        } else {
3424
            if (isRestrictedWord(token.value)) {
3425
                firstRestricted = token;
3426
                message = Messages.StrictFunctionName;
3427
            } else if (isStrictModeReservedWord(token.value)) {
3428
                firstRestricted = token;
3429
                message = Messages.StrictReservedWord;
3430
            }
3431
        }
3432
3433
        tmp = parseParams(firstRestricted);
3434
        params = tmp.params;
3435
        stricted = tmp.stricted;
3436
        firstRestricted = tmp.firstRestricted;
3437
        if (tmp.message) {
3438
            message = tmp.message;
3439
        }
3440
3441
        previousStrict = strict;
3442
        body = parseFunctionSourceElements();
3443
        if (strict && firstRestricted) {
3444
            throwError(firstRestricted, message);
3445
        }
3446
        if (strict && stricted) {
3447
            throwErrorTolerant(stricted, message);
3448
        }
3449
        strict = previousStrict;
3450
3451
        return delegate.markEnd(delegate.createFunctionDeclaration(id, params, [], body));
3452
    }
3453
3454
    function parseFunctionExpression() {
3455
        var token, id = null, stricted, firstRestricted, message, tmp, params = [], body, previousStrict;
3456
3457
        delegate.markStart();
3458
        expectKeyword('function');
3459
3460
        if (!match('(')) {
3461
            token = lookahead;
3462
            id = parseVariableIdentifier();
3463
            if (strict) {
3464
                if (isRestrictedWord(token.value)) {
3465
                    throwErrorTolerant(token, Messages.StrictFunctionName);
3466
                }
3467
            } else {
3468
                if (isRestrictedWord(token.value)) {
3469
                    firstRestricted = token;
3470
                    message = Messages.StrictFunctionName;
3471
                } else if (isStrictModeReservedWord(token.value)) {
3472
                    firstRestricted = token;
3473
                    message = Messages.StrictReservedWord;
3474
                }
3475
            }
3476
        }
3477
3478
        tmp = parseParams(firstRestricted);
3479
        params = tmp.params;
3480
        stricted = tmp.stricted;
3481
        firstRestricted = tmp.firstRestricted;
3482
        if (tmp.message) {
3483
            message = tmp.message;
3484
        }
3485
3486
        previousStrict = strict;
3487
        body = parseFunctionSourceElements();
3488
        if (strict && firstRestricted) {
3489
            throwError(firstRestricted, message);
3490
        }
3491
        if (strict && stricted) {
3492
            throwErrorTolerant(stricted, message);
3493
        }
3494
        strict = previousStrict;
3495
3496
        return delegate.markEnd(delegate.createFunctionExpression(id, params, [], body));
3497
    }
3498
3499
    // 14 Program
3500
3501
    function parseSourceElement() {
3502
        if (lookahead.type === Token.Keyword) {
3503
            switch (lookahead.value) {
3504
            case 'const':
3505
            case 'let':
3506
                return parseConstLetDeclaration(lookahead.value);
3507
            case 'function':
3508
                return parseFunctionDeclaration();
3509
            default:
3510
                return parseStatement();
3511
            }
3512
        }
3513
3514
        if (lookahead.type !== Token.EOF) {
3515
            return parseStatement();
3516
        }
3517
    }
3518
3519
    function parseSourceElements() {
3520
        var sourceElement, sourceElements = [], token, directive, firstRestricted;
3521
3522
        while (index < length) {
3523
            token = lookahead;
3524
            if (token.type !== Token.StringLiteral) {
3525
                break;
3526
            }
3527
3528
            sourceElement = parseSourceElement();
3529
            sourceElements.push(sourceElement);
3530
            if (sourceElement.expression.type !== Syntax.Literal) {
3531
                // this is not directive
3532
                break;
3533
            }
3534
            directive = source.slice(token.range[0] + 1, token.range[1] - 1);
3535
            if (directive === 'use strict') {
3536
                strict = true;
3537
                if (firstRestricted) {
3538
                    throwErrorTolerant(firstRestricted, Messages.StrictOctalLiteral);
3539
                }
3540
            } else {
3541
                if (!firstRestricted && token.octal) {
3542
                    firstRestricted = token;
3543
                }
3544
            }
3545
        }
3546
3547
        while (index < length) {
3548
            sourceElement = parseSourceElement();
3549
            if (typeof sourceElement === 'undefined') {
3550
                break;
3551
            }
3552
            sourceElements.push(sourceElement);
3553
        }
3554
        return sourceElements;
3555
    }
3556
3557
    function parseProgram() {
3558
        var body;
3559
3560
        skipComment();
3561
        delegate.markStart();
3562
        strict = false;
3563
        peek();
3564
        body = parseSourceElements();
3565
        return delegate.markEnd(delegate.createProgram(body));
3566
    }
3567
3568
    function attachComments() {
3569
        var i, attacher, comment, leading, trailing;
3570
3571
        for (i = 0; i < extra.pendingComments.length; ++i) {
3572
            attacher = extra.pendingComments[i];
3573
            comment = attacher.comment;
3574
            leading = attacher.leading;
3575
            if (leading) {
3576
                if (typeof leading.leadingComments === 'undefined') {
3577
                    leading.leadingComments = [];
3578
                }
3579
                leading.leadingComments.push(attacher.comment);
3580
            }
3581
            trailing = attacher.trailing;
3582
            if (trailing) {
3583
                if (typeof trailing.trailingComments === 'undefined') {
3584
                    trailing.trailingComments = [];
3585
                }
3586
                trailing.trailingComments.push(attacher.comment);
3587
            }
3588
        }
3589
        extra.pendingComments = [];
3590
    }
3591
3592
    function filterTokenLocation() {
3593
        var i, entry, token, tokens = [];
3594
3595
        for (i = 0; i < extra.tokens.length; ++i) {
3596
            entry = extra.tokens[i];
3597
            token = {
3598
                type: entry.type,
3599
                value: entry.value
3600
            };
3601
            if (extra.range) {
3602
                token.range = entry.range;
3603
            }
3604
            if (extra.loc) {
3605
                token.loc = entry.loc;
3606
            }
3607
            tokens.push(token);
3608
        }
3609
3610
        extra.tokens = tokens;
3611
    }
3612
3613
    function LocationMarker() {
3614
        this.marker = [index, lineNumber, index - lineStart, 0, 0, 0];
3615
    }
3616
3617
    LocationMarker.prototype = {
3618
        constructor: LocationMarker,
3619
3620
        end: function () {
3621
            this.marker[3] = index;
3622
            this.marker[4] = lineNumber;
3623
            this.marker[5] = index - lineStart;
3624
        },
3625
3626
        apply: function (node) {
3627
            if (extra.range) {
3628
                node.range = [this.marker[0], this.marker[3]];
3629
            }
3630
            if (extra.loc) {
3631
                node.loc = {
3632
                    start: {
3633
                        line: this.marker[1],
3634
                        column: this.marker[2]
3635
                    },
3636
                    end: {
3637
                        line: this.marker[4],
3638
                        column: this.marker[5]
3639
                    }
3640
                };
3641
                node = delegate.postProcess(node);
3642
            }
3643
            if (extra.attachComment) {
3644
                delegate.processComment(node);
3645
            }
3646
        }
3647
    };
3648
3649
    function createLocationMarker() {
3650
        if (!extra.loc && !extra.range) {
3651
            return null;
3652
        }
3653
3654
        skipComment();
3655
3656
        return new LocationMarker();
3657
    }
3658
3659
    function tokenize(code, options) {
3660
        var toString,
3661
            token,
3662
            tokens;
3663
3664
        toString = String;
3665
        if (typeof code !== 'string' && !(code instanceof String)) {
3666
            code = toString(code);
3667
        }
3668
3669
        delegate = SyntaxTreeDelegate;
3670
        source = code;
3671
        index = 0;
3672
        lineNumber = (source.length > 0) ? 1 : 0;
3673
        lineStart = 0;
3674
        length = source.length;
3675
        lookahead = null;
3676
        state = {
3677
            allowIn: true,
3678
            labelSet: {},
3679
            inFunctionBody: false,
3680
            inIteration: false,
3681
            inSwitch: false,
3682
            lastCommentStart: -1
3683
        };
3684
3685
        extra = {};
3686
3687
        // Options matching.
3688
        options = options || {};
3689
3690
        // Of course we collect tokens here.
3691
        options.tokens = true;
3692
        extra.tokens = [];
3693
        extra.tokenize = true;
3694
        // The following two fields are necessary to compute the Regex tokens.
3695
        extra.openParenToken = -1;
3696
        extra.openCurlyToken = -1;
3697
3698
        extra.range = (typeof options.range === 'boolean') && options.range;
3699
        extra.loc = (typeof options.loc === 'boolean') && options.loc;
3700
3701
        if (typeof options.comment === 'boolean' && options.comment) {
3702
            extra.comments = [];
3703
        }
3704
        if (typeof options.tolerant === 'boolean' && options.tolerant) {
3705
            extra.errors = [];
3706
        }
3707
3708
        if (length > 0) {
3709
            if (typeof source[0] === 'undefined') {
3710
                // Try first to convert to a string. This is good as fast path
3711
                // for old IE which understands string indexing for string
3712
                // literals only and not for string object.
3713
                if (code instanceof String) {
3714
                    source = code.valueOf();
3715
                }
3716
            }
3717
        }
3718
3719
        try {
3720
            peek();
3721
            if (lookahead.type === Token.EOF) {
3722
                return extra.tokens;
3723
            }
3724
3725
            token = lex();
3726
            while (lookahead.type !== Token.EOF) {
3727
                try {
3728
                    token = lex();
3729
                } catch (lexError) {
3730
                    token = lookahead;
3731
                    if (extra.errors) {
3732
                        extra.errors.push(lexError);
3733
                        // We have to break on the first error
3734
                        // to avoid infinite loops.
3735
                        break;
3736
                    } else {
3737
                        throw lexError;
3738
                    }
3739
                }
3740
            }
3741
3742
            filterTokenLocation();
3743
            tokens = extra.tokens;
3744
            if (typeof extra.comments !== 'undefined') {
3745
                tokens.comments = extra.comments;
3746
            }
3747
            if (typeof extra.errors !== 'undefined') {
3748
                tokens.errors = extra.errors;
3749
            }
3750
        } catch (e) {
3751
            throw e;
3752
        } finally {
3753
            extra = {};
3754
        }
3755
        return tokens;
3756
    }
3757
3758
    function parse(code, options) {
3759
        var program, toString;
3760
3761
        toString = String;
3762
        if (typeof code !== 'string' && !(code instanceof String)) {
3763
            code = toString(code);
3764
        }
3765
3766
        delegate = SyntaxTreeDelegate;
3767
        source = code;
3768
        index = 0;
3769
        lineNumber = (source.length > 0) ? 1 : 0;
3770
        lineStart = 0;
3771
        length = source.length;
3772
        lookahead = null;
3773
        state = {
3774
            allowIn: true,
3775
            labelSet: {},
3776
            inFunctionBody: false,
3777
            inIteration: false,
3778
            inSwitch: false,
3779
            lastCommentStart: -1,
3780
            markerStack: []
3781
        };
3782
3783
        extra = {};
3784
        if (typeof options !== 'undefined') {
3785
            extra.range = (typeof options.range === 'boolean') && options.range;
3786
            extra.loc = (typeof options.loc === 'boolean') && options.loc;
3787
            extra.attachComment = (typeof options.attachComment === 'boolean') && options.attachComment;
3788
3789
            if (extra.loc && options.source !== null && options.source !== undefined) {
3790
                extra.source = toString(options.source);
3791
            }
3792
3793
            if (typeof options.tokens === 'boolean' && options.tokens) {
3794
                extra.tokens = [];
3795
            }
3796
            if (typeof options.comment === 'boolean' && options.comment) {
3797
                extra.comments = [];
3798
            }
3799
            if (typeof options.tolerant === 'boolean' && options.tolerant) {
3800
                extra.errors = [];
3801
            }
3802
            if (extra.attachComment) {
3803
                extra.range = true;
3804
                extra.pendingComments = [];
3805
                extra.comments = [];
3806
            }
3807
        }
3808
3809
        if (length > 0) {
3810
            if (typeof source[0] === 'undefined') {
3811
                // Try first to convert to a string. This is good as fast path
3812
                // for old IE which understands string indexing for string
3813
                // literals only and not for string object.
3814
                if (code instanceof String) {
3815
                    source = code.valueOf();
3816
                }
3817
            }
3818
        }
3819
3820
        try {
3821
            program = parseProgram();
3822
            if (typeof extra.comments !== 'undefined') {
3823
                program.comments = extra.comments;
3824
            }
3825
            if (typeof extra.tokens !== 'undefined') {
3826
                filterTokenLocation();
3827
                program.tokens = extra.tokens;
3828
            }
3829
            if (typeof extra.errors !== 'undefined') {
3830
                program.errors = extra.errors;
3831
            }
3832
            if (extra.attachComment) {
3833
                attachComments();
3834
            }
3835
        } catch (e) {
3836
            throw e;
3837
        } finally {
3838
            extra = {};
3839
        }
3840
3841
        return program;
3842
    }
3843
3844
	/**
3845
	 * @name expectConditionCloseBracketWrapThrow
3846
	 * @description Gracefully handles a missing '}' if the mode is set to tolerant
3847
	 * @function
3848
	 * @private
3849
	 * @since 5.0
3850
	 */
3851
	function expectConditionCloseBracketWrapThrow() {
3852
		if (extra.errors) {
3853
			// continue parsing even with missing close
3854
			// brace.  This gives a better AST for the
3855
			// block, as information about
3856
			// the parsed statements remain
3857
			try {
3858
				expect('}');
3859
			} catch (e) {
3860
				pushError(e);
3861
	        }
3862
		} else {
3863
			expect('}');
3864
		}
3865
	}
3866
3867
	/**
3868
	 * @name expectConditionCloseParenWrapThrow
3869
	 * @description For statements like if, while, for, etc. check for the ')' on the condition. If
3870
	 * it is not present, catch the error, and backtrack if we see a '{' instead (to continue parsing the block)
3871
	 * @function
3872
	 * @private
3873
	 * @throws The original error from  trying to consume the ')' char if not in tolerant mode
3874
	 * @since 5.0
3875
	 */
3876
	function expectConditionCloseParenWrapThrow() {
3877
        // needs generalizing to a 'expect A but don't consume if you hit B or C'
3878
        try {
3879
            expect(')');
3880
        } catch (e) {
3881
            if (extra.errors) {
3882
	            pushError(e);
3883
	            // If a { was hit instead of a ) then don't consume it, let us assume a ')' was 
3884
	            // missed and the consequent block is OK
3885
	            if (source[e.index] === '{') {
3886
	              index=e.index;
3887
	              lookahead = null;
3888
	            // activating this block will mean the following statement is parsed as a consequent / body.
3889
	            // without it the statement is considered not at all part of the enclosing statement at all
3890
	            //} else {
3891
	            //  rewind();
3892
	            }
3893
            } else {
3894
                throw e;
3895
            }
3896
        }
3897
3898
	}
3899
3900
	/**
3901
	 * @name pushError
3902
     * @description Add the error if not already reported.
3903
     * @function
3904
     * @private
3905
     * @param {Object} error The error object to push
3906
     * @since 5.0
3907
     */
3908
    function pushError(error) {
3909
        var len = extra.errors.length;
3910
        for (var e=0; e < len; e++) {
3911
            var existingError = extra.errors[e];
3912
            if (existingError.index === error.index && existingError.message === error.message) {
3913
                return; // do not add duplicate
3914
            }
3915
        }
3916
        extra.errors.push(error);
3917
    }
3918
    
3919
    //Recovery
3920
    
3921
    /**
3922
     * @name isNewlineOrSemicolon
3923
     * @description If the given char is the new line char or a semicolon char
3924
     * @function
3925
     * @private
3926
     * @param {String} ch The character to check
3927
     * @returns {Boolean} <code>true</code> if the char is a new line or semicolon <code>false</code> otherwise
3928
     * @since 5.0
3929
     */
3930
    function isNewlineOrSemicolon(ch) {
3931
      return ch===';' || ch==='\n';
3932
    }
3933
    
3934
    /**
3935
     * @name rewind
3936
     * @descripton Rewind the lex position to the most recent newline or semicolon.  If that turns out
3937
     * to be the same position as the most recent parsing of a statement was attempted at, 
3938
     * don't rewind (because it will fail in the same way).  If it turns out to be the same
3939
     * position as where we last rewound to, don't do it.  Clears the buffer and sets the
3940
     * index in order to continue lexing from the new position.
3941
     * @function
3942
     * @private
3943
     * @since 5.0
3944
     */
3945
    function rewind() {
3946
        var idx = index;
3947
        while (idx>0 && !isNewlineOrSemicolon(source[idx])) {
3948
            idx--;
3949
        }
3950
        if (idx<=extra.statementStart) {
3951
            return;
3952
        }
3953
        var doRewind = false;
3954
        if (extra.lastRewindLocation) {
3955
            doRewind = true;
3956
        } else {
3957
            var v = extra.lastRewindLocation;
3958
            if (v!==idx) {
3959
              doRewind=true;
3960
            }
3961
        }	        
3962
        if (doRewind) {
3963
	        index = idx;
3964
	        lookahead = null;
3965
	        extra.lastRewindLocation = index;
3966
        }
3967
    }
3968
3969
	/**
3970
	 * @name rewindToInterestingChar
3971
     * @description From a position 'idx' in the source this function moves back through the source until
3972
     * it finds a non-whitespace (including newlines) character.  It will jump over block comments.
3973
     * Returns an object with properties: index - the index it rewound to.  lineChange - boolean indicating
3974
     * if a line was crossed during rewind.
3975
     * @function
3976
     * @private
3977
     * @param {Number} idx The index to rewind to
3978
     * @returns {Object} Returns the object with the index and line change to rewind to
3979
     * @since 5.0
3980
     */
3981
    function rewindToInterestingChar(idx) {
3982
        var done = false;
3983
        var lineChange=false;
3984
        var ch;
3985
        while (!done) {
3986
          ch = source[idx];
3987
          if (ch==='/') {
3988
            // possibly rewind over a block comment
3989
            if (idx>2 && source[idx-1]==='*') {
3990
                // it is, let's reverse over it
3991
                idx = idx - 2;
3992
                var skippedComment = false;
3993
                while (!skippedComment) {
3994
                    ch = source[idx];
3995
                    if (ch === '*') {
3996
                        if (idx>0 && source[idx-1]==='/') {
3997
                            skippedComment=true;
3998
                        }
3999
                    } else if (ch==='\n') {
4000
                        lineChange=true;
4001
                    }
4002
                    if (idx === 0) {
4003
                        skippedComment = true; // error scenario, hit front of array before finding /*
4004
                    }
4005
                    idx--;                
4006
                }
4007
            } else {
4008
              done=true;
4009
            }
4010
          } else 
4011
          if (ch==='\n') {
4012
              lineChange=true;
4013
          } else if (!isWhiteSpace(ch)) {
4014
              done=true;
4015
          }
4016
          if (!done) {
4017
              idx--;
4018
          }
4019
        }
4020
        return {"index":idx,"lineChange":lineChange};
4021
    }
4022
    
4023
    /**
4024
     * @name attemptRecoveryNonComputedProperty
4025
     * @description When a problem occurs in parseNonComputedProperty, attempt to reposition 
4026
     * the lexer to continue processing.
4027
     * Example: '(foo.)' we will hit the ')' instead of discovering a property and consuming the ')'
4028
     * will cause the parse of the paretheses to fail, so 'unconsume' it.
4029
     * Basically rewind by one token if punctuation (type 7) is hit and the char before it was
4030
     * a dot.  This will enable the enclosing parse rule to consume the punctuation.
4031
     * @function
4032
     * @private
4033
     * @param {String} token The token to try and recover from
4034
     * @since 5.0
4035
     */
4036
    function attemptRecoveryNonComputedProperty(token) {
4037
        if (token.value && token.type===Token.Punctuator) {
4038
            var rewindInfo = rewindToInterestingChar(index-token.value.length-1);
4039
            var idx = rewindInfo.index;
4040
            var ch= source[idx];
4041
            // Check if worth rewinding
4042
            // Special case:
4043
            // "foo.\n(foo())\n" - don't really want that to parse as "foo(foo())"
4044
            if (ch==='.' && rewindInfo.lineChange && token.value==='(') {
4045
                // do not recover in this case
4046
            } else if (ch==='.') {
4047
	            index = idx+1;
4048
	            lookahead=null;
4049
            }
4050
        }
4051
    }
4052
4053
    // Sync with *.json manifests.
4054
    exports.version = '1.1.0-dev';
4055
4056
    exports.tokenize = tokenize;
4057
4058
    exports.parse = parse;
4059
4060
    // Deep copy.
4061
    exports.Syntax = (function () {
4062
        var name, types = {};
4063
4064
        if (typeof Object.create === 'function') {
4065
            types = Object.create(null);
4066
        }
4067
4068
        for (name in Syntax) {
4069
            if (Syntax.hasOwnProperty(name)) {
4070
                types[name] = Syntax[name];
4071
            }
4072
        }
4073
4074
        if (typeof Object.freeze === 'function') {
4075
            Object.freeze(types);
4076
        }
4077
4078
        return types;
4079
    }());
4080
4081
}));
4082
/* vim: set sw=4 ts=4 et tw=80 : */

Return to bug 423091