]> code.delx.au - gnu-emacs-elpa/blob - lib/esprima.js
Include external libraries.
[gnu-emacs-elpa] / lib / esprima.js
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 throwErrorTolerant: true,
37 throwError: true, generateStatement: true, peek: true,
38 parseAssignmentExpression: true, parseBlock: true, parseExpression: true,
39 parseFunctionDeclaration: true, parseFunctionExpression: true,
40 parseFunctionSourceElements: true, parseVariableIdentifier: true,
41 parseLeftHandSideExpression: true,
42 parseUnaryExpression: true,
43 parseStatement: true, parseSourceElement: true */
44
45 (function (root, factory) {
46 'use strict';
47
48 // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js,
49 // Rhino, and plain browser loading.
50
51 /* istanbul ignore next */
52 if (typeof define === 'function' && define.amd) {
53 define(['exports'], factory);
54 } else if (typeof exports !== 'undefined') {
55 factory(exports);
56 } else {
57 factory((root.esprima = {}));
58 }
59 }(this, function (exports) {
60 'use strict';
61
62 var Token,
63 TokenName,
64 FnExprTokens,
65 Syntax,
66 PropertyKind,
67 Messages,
68 Regex,
69 SyntaxTreeDelegate,
70 source,
71 strict,
72 index,
73 lineNumber,
74 lineStart,
75 length,
76 delegate,
77 lookahead,
78 state,
79 extra;
80
81 Token = {
82 BooleanLiteral: 1,
83 EOF: 2,
84 Identifier: 3,
85 Keyword: 4,
86 NullLiteral: 5,
87 NumericLiteral: 6,
88 Punctuator: 7,
89 StringLiteral: 8,
90 RegularExpression: 9
91 };
92
93 TokenName = {};
94 TokenName[Token.BooleanLiteral] = 'Boolean';
95 TokenName[Token.EOF] = '<end>';
96 TokenName[Token.Identifier] = 'Identifier';
97 TokenName[Token.Keyword] = 'Keyword';
98 TokenName[Token.NullLiteral] = 'Null';
99 TokenName[Token.NumericLiteral] = 'Numeric';
100 TokenName[Token.Punctuator] = 'Punctuator';
101 TokenName[Token.StringLiteral] = 'String';
102 TokenName[Token.RegularExpression] = 'RegularExpression';
103
104 // A function following one of those tokens is an expression.
105 FnExprTokens = ['(', '{', '[', 'in', 'typeof', 'instanceof', 'new',
106 'return', 'case', 'delete', 'throw', 'void',
107 // assignment operators
108 '=', '+=', '-=', '*=', '/=', '%=', '<<=', '>>=', '>>>=',
109 '&=', '|=', '^=', ',',
110 // binary/unary operators
111 '+', '-', '*', '/', '%', '++', '--', '<<', '>>', '>>>', '&',
112 '|', '^', '!', '~', '&&', '||', '?', ':', '===', '==', '>=',
113 '<=', '<', '>', '!=', '!=='];
114
115 Syntax = {
116 AssignmentExpression: 'AssignmentExpression',
117 ArrayExpression: 'ArrayExpression',
118 BlockStatement: 'BlockStatement',
119 BinaryExpression: 'BinaryExpression',
120 BreakStatement: 'BreakStatement',
121 CallExpression: 'CallExpression',
122 CatchClause: 'CatchClause',
123 ConditionalExpression: 'ConditionalExpression',
124 ContinueStatement: 'ContinueStatement',
125 DoWhileStatement: 'DoWhileStatement',
126 DebuggerStatement: 'DebuggerStatement',
127 EmptyStatement: 'EmptyStatement',
128 ExpressionStatement: 'ExpressionStatement',
129 ForStatement: 'ForStatement',
130 ForInStatement: 'ForInStatement',
131 FunctionDeclaration: 'FunctionDeclaration',
132 FunctionExpression: 'FunctionExpression',
133 Identifier: 'Identifier',
134 IfStatement: 'IfStatement',
135 Literal: 'Literal',
136 LabeledStatement: 'LabeledStatement',
137 LogicalExpression: 'LogicalExpression',
138 MemberExpression: 'MemberExpression',
139 NewExpression: 'NewExpression',
140 ObjectExpression: 'ObjectExpression',
141 Program: 'Program',
142 Property: 'Property',
143 ReturnStatement: 'ReturnStatement',
144 SequenceExpression: 'SequenceExpression',
145 SwitchStatement: 'SwitchStatement',
146 SwitchCase: 'SwitchCase',
147 ThisExpression: 'ThisExpression',
148 ThrowStatement: 'ThrowStatement',
149 TryStatement: 'TryStatement',
150 UnaryExpression: 'UnaryExpression',
151 UpdateExpression: 'UpdateExpression',
152 VariableDeclaration: 'VariableDeclaration',
153 VariableDeclarator: 'VariableDeclarator',
154 WhileStatement: 'WhileStatement',
155 WithStatement: 'WithStatement'
156 };
157
158 PropertyKind = {
159 Data: 1,
160 Get: 2,
161 Set: 4
162 };
163
164 // Error messages should be identical to V8.
165 Messages = {
166 UnexpectedToken: 'Unexpected token %0',
167 UnexpectedNumber: 'Unexpected number',
168 UnexpectedString: 'Unexpected string',
169 UnexpectedIdentifier: 'Unexpected identifier',
170 UnexpectedReserved: 'Unexpected reserved word',
171 UnexpectedEOS: 'Unexpected end of input',
172 NewlineAfterThrow: 'Illegal newline after throw',
173 InvalidRegExp: 'Invalid regular expression',
174 UnterminatedRegExp: 'Invalid regular expression: missing /',
175 InvalidLHSInAssignment: 'Invalid left-hand side in assignment',
176 InvalidLHSInForIn: 'Invalid left-hand side in for-in',
177 MultipleDefaultsInSwitch: 'More than one default clause in switch statement',
178 NoCatchOrFinally: 'Missing catch or finally after try',
179 UnknownLabel: 'Undefined label \'%0\'',
180 Redeclaration: '%0 \'%1\' has already been declared',
181 IllegalContinue: 'Illegal continue statement',
182 IllegalBreak: 'Illegal break statement',
183 IllegalReturn: 'Illegal return statement',
184 StrictModeWith: 'Strict mode code may not include a with statement',
185 StrictCatchVariable: 'Catch variable may not be eval or arguments in strict mode',
186 StrictVarName: 'Variable name may not be eval or arguments in strict mode',
187 StrictParamName: 'Parameter name eval or arguments is not allowed in strict mode',
188 StrictParamDupe: 'Strict mode function may not have duplicate parameter names',
189 StrictFunctionName: 'Function name may not be eval or arguments in strict mode',
190 StrictOctalLiteral: 'Octal literals are not allowed in strict mode.',
191 StrictDelete: 'Delete of an unqualified identifier in strict mode.',
192 StrictDuplicateProperty: 'Duplicate data property in object literal not allowed in strict mode',
193 AccessorDataProperty: 'Object literal may not have data and accessor property with the same name',
194 AccessorGetSet: 'Object literal may not have multiple get/set accessors with the same name',
195 StrictLHSAssignment: 'Assignment to eval or arguments is not allowed in strict mode',
196 StrictLHSPostfix: 'Postfix increment/decrement may not have eval or arguments operand in strict mode',
197 StrictLHSPrefix: 'Prefix increment/decrement may not have eval or arguments operand in strict mode',
198 StrictReservedWord: 'Use of future reserved word in strict mode'
199 };
200
201 // See also tools/generate-unicode-regex.py.
202 Regex = {
203 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]'),
204 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]')
205 };
206
207 // Ensure the condition is true, otherwise throw an error.
208 // This is only to have a better contract semantic, i.e. another safety net
209 // to catch a logic error. The condition shall be fulfilled in normal case.
210 // Do NOT use this to enforce a certain condition on any user input.
211
212 function assert(condition, message) {
213 /* istanbul ignore if */
214 if (!condition) {
215 throw new Error('ASSERT: ' + message);
216 }
217 }
218
219 function isDecimalDigit(ch) {
220 return (ch >= 48 && ch <= 57); // 0..9
221 }
222
223 function isHexDigit(ch) {
224 return '0123456789abcdefABCDEF'.indexOf(ch) >= 0;
225 }
226
227 function isOctalDigit(ch) {
228 return '01234567'.indexOf(ch) >= 0;
229 }
230
231
232 // 7.2 White Space
233
234 function isWhiteSpace(ch) {
235 return (ch === 0x20) || (ch === 0x09) || (ch === 0x0B) || (ch === 0x0C) || (ch === 0xA0) ||
236 (ch >= 0x1680 && [0x1680, 0x180E, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008, 0x2009, 0x200A, 0x202F, 0x205F, 0x3000, 0xFEFF].indexOf(ch) >= 0);
237 }
238
239 // 7.3 Line Terminators
240
241 function isLineTerminator(ch) {
242 return (ch === 0x0A) || (ch === 0x0D) || (ch === 0x2028) || (ch === 0x2029);
243 }
244
245 // 7.6 Identifier Names and Identifiers
246
247 function isIdentifierStart(ch) {
248 return (ch === 0x24) || (ch === 0x5F) || // $ (dollar) and _ (underscore)
249 (ch >= 0x41 && ch <= 0x5A) || // A..Z
250 (ch >= 0x61 && ch <= 0x7A) || // a..z
251 (ch === 0x5C) || // \ (backslash)
252 ((ch >= 0x80) && Regex.NonAsciiIdentifierStart.test(String.fromCharCode(ch)));
253 }
254
255 function isIdentifierPart(ch) {
256 return (ch === 0x24) || (ch === 0x5F) || // $ (dollar) and _ (underscore)
257 (ch >= 0x41 && ch <= 0x5A) || // A..Z
258 (ch >= 0x61 && ch <= 0x7A) || // a..z
259 (ch >= 0x30 && ch <= 0x39) || // 0..9
260 (ch === 0x5C) || // \ (backslash)
261 ((ch >= 0x80) && Regex.NonAsciiIdentifierPart.test(String.fromCharCode(ch)));
262 }
263
264 // 7.6.1.2 Future Reserved Words
265
266 function isFutureReservedWord(id) {
267 switch (id) {
268 case 'class':
269 case 'enum':
270 case 'export':
271 case 'extends':
272 case 'import':
273 case 'super':
274 return true;
275 default:
276 return false;
277 }
278 }
279
280 function isStrictModeReservedWord(id) {
281 switch (id) {
282 case 'implements':
283 case 'interface':
284 case 'package':
285 case 'private':
286 case 'protected':
287 case 'public':
288 case 'static':
289 case 'yield':
290 case 'let':
291 return true;
292 default:
293 return false;
294 }
295 }
296
297 function isRestrictedWord(id) {
298 return id === 'eval' || id === 'arguments';
299 }
300
301 // 7.6.1.1 Keywords
302
303 function isKeyword(id) {
304 if (strict && isStrictModeReservedWord(id)) {
305 return true;
306 }
307
308 // 'const' is specialized as Keyword in V8.
309 // 'yield' and 'let' are for compatiblity with SpiderMonkey and ES.next.
310 // Some others are from future reserved words.
311
312 switch (id.length) {
313 case 2:
314 return (id === 'if') || (id === 'in') || (id === 'do');
315 case 3:
316 return (id === 'var') || (id === 'for') || (id === 'new') ||
317 (id === 'try') || (id === 'let');
318 case 4:
319 return (id === 'this') || (id === 'else') || (id === 'case') ||
320 (id === 'void') || (id === 'with') || (id === 'enum');
321 case 5:
322 return (id === 'while') || (id === 'break') || (id === 'catch') ||
323 (id === 'throw') || (id === 'const') || (id === 'yield') ||
324 (id === 'class') || (id === 'super');
325 case 6:
326 return (id === 'return') || (id === 'typeof') || (id === 'delete') ||
327 (id === 'switch') || (id === 'export') || (id === 'import');
328 case 7:
329 return (id === 'default') || (id === 'finally') || (id === 'extends');
330 case 8:
331 return (id === 'function') || (id === 'continue') || (id === 'debugger');
332 case 10:
333 return (id === 'instanceof');
334 default:
335 return false;
336 }
337 }
338
339 // 7.4 Comments
340
341 function addComment(type, value, start, end, loc) {
342 var comment, attacher;
343
344 assert(typeof start === 'number', 'Comment must have valid position');
345
346 // Because the way the actual token is scanned, often the comments
347 // (if any) are skipped twice during the lexical analysis.
348 // Thus, we need to skip adding a comment if the comment array already
349 // handled it.
350 if (state.lastCommentStart >= start) {
351 return;
352 }
353 state.lastCommentStart = start;
354
355 comment = {
356 type: type,
357 value: value
358 };
359 if (extra.range) {
360 comment.range = [start, end];
361 }
362 if (extra.loc) {
363 comment.loc = loc;
364 }
365 extra.comments.push(comment);
366 if (extra.attachComment) {
367 extra.leadingComments.push(comment);
368 extra.trailingComments.push(comment);
369 }
370 }
371
372 function skipSingleLineComment(offset) {
373 var start, loc, ch, comment;
374
375 start = index - offset;
376 loc = {
377 start: {
378 line: lineNumber,
379 column: index - lineStart - offset
380 }
381 };
382
383 while (index < length) {
384 ch = source.charCodeAt(index);
385 ++index;
386 if (isLineTerminator(ch)) {
387 if (extra.comments) {
388 comment = source.slice(start + offset, index - 1);
389 loc.end = {
390 line: lineNumber,
391 column: index - lineStart - 1
392 };
393 addComment('Line', comment, start, index - 1, loc);
394 }
395 if (ch === 13 && source.charCodeAt(index) === 10) {
396 ++index;
397 }
398 ++lineNumber;
399 lineStart = index;
400 return;
401 }
402 }
403
404 if (extra.comments) {
405 comment = source.slice(start + offset, index);
406 loc.end = {
407 line: lineNumber,
408 column: index - lineStart
409 };
410 addComment('Line', comment, start, index, loc);
411 }
412 }
413
414 function skipMultiLineComment() {
415 var start, loc, ch, comment;
416
417 if (extra.comments) {
418 start = index - 2;
419 loc = {
420 start: {
421 line: lineNumber,
422 column: index - lineStart - 2
423 }
424 };
425 }
426
427 while (index < length) {
428 ch = source.charCodeAt(index);
429 if (isLineTerminator(ch)) {
430 if (ch === 0x0D && source.charCodeAt(index + 1) === 0x0A) {
431 ++index;
432 }
433 ++lineNumber;
434 ++index;
435 lineStart = index;
436 if (index >= length) {
437 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
438 }
439 } else if (ch === 0x2A) {
440 // Block comment ends with '*/'.
441 if (source.charCodeAt(index + 1) === 0x2F) {
442 ++index;
443 ++index;
444 if (extra.comments) {
445 comment = source.slice(start + 2, index - 2);
446 loc.end = {
447 line: lineNumber,
448 column: index - lineStart
449 };
450 addComment('Block', comment, start, index, loc);
451 }
452 return;
453 }
454 ++index;
455 } else {
456 ++index;
457 }
458 }
459
460 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
461 }
462
463 function skipComment() {
464 var ch, start;
465
466 start = (index === 0);
467 while (index < length) {
468 ch = source.charCodeAt(index);
469
470 if (isWhiteSpace(ch)) {
471 ++index;
472 } else if (isLineTerminator(ch)) {
473 ++index;
474 if (ch === 0x0D && source.charCodeAt(index) === 0x0A) {
475 ++index;
476 }
477 ++lineNumber;
478 lineStart = index;
479 start = true;
480 } else if (ch === 0x2F) { // U+002F is '/'
481 ch = source.charCodeAt(index + 1);
482 if (ch === 0x2F) {
483 ++index;
484 ++index;
485 skipSingleLineComment(2);
486 start = true;
487 } else if (ch === 0x2A) { // U+002A is '*'
488 ++index;
489 ++index;
490 skipMultiLineComment();
491 } else {
492 break;
493 }
494 } else if (start && ch === 0x2D) { // U+002D is '-'
495 // U+003E is '>'
496 if ((source.charCodeAt(index + 1) === 0x2D) && (source.charCodeAt(index + 2) === 0x3E)) {
497 // '-->' is a single-line comment
498 index += 3;
499 skipSingleLineComment(3);
500 } else {
501 break;
502 }
503 } else if (ch === 0x3C) { // U+003C is '<'
504 if (source.slice(index + 1, index + 4) === '!--') {
505 ++index; // `<`
506 ++index; // `!`
507 ++index; // `-`
508 ++index; // `-`
509 skipSingleLineComment(4);
510 } else {
511 break;
512 }
513 } else {
514 break;
515 }
516 }
517 }
518
519 function scanHexEscape(prefix) {
520 var i, len, ch, code = 0;
521
522 len = (prefix === 'u') ? 4 : 2;
523 for (i = 0; i < len; ++i) {
524 if (index < length && isHexDigit(source[index])) {
525 ch = source[index++];
526 code = code * 16 + '0123456789abcdef'.indexOf(ch.toLowerCase());
527 } else {
528 return '';
529 }
530 }
531 return String.fromCharCode(code);
532 }
533
534 function getEscapedIdentifier() {
535 var ch, id;
536
537 ch = source.charCodeAt(index++);
538 id = String.fromCharCode(ch);
539
540 // '\u' (U+005C, U+0075) denotes an escaped character.
541 if (ch === 0x5C) {
542 if (source.charCodeAt(index) !== 0x75) {
543 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
544 }
545 ++index;
546 ch = scanHexEscape('u');
547 if (!ch || ch === '\\' || !isIdentifierStart(ch.charCodeAt(0))) {
548 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
549 }
550 id = ch;
551 }
552
553 while (index < length) {
554 ch = source.charCodeAt(index);
555 if (!isIdentifierPart(ch)) {
556 break;
557 }
558 ++index;
559 id += String.fromCharCode(ch);
560
561 // '\u' (U+005C, U+0075) denotes an escaped character.
562 if (ch === 0x5C) {
563 id = id.substr(0, id.length - 1);
564 if (source.charCodeAt(index) !== 0x75) {
565 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
566 }
567 ++index;
568 ch = scanHexEscape('u');
569 if (!ch || ch === '\\' || !isIdentifierPart(ch.charCodeAt(0))) {
570 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
571 }
572 id += ch;
573 }
574 }
575
576 return id;
577 }
578
579 function getIdentifier() {
580 var start, ch;
581
582 start = index++;
583 while (index < length) {
584 ch = source.charCodeAt(index);
585 if (ch === 0x5C) {
586 // Blackslash (U+005C) marks Unicode escape sequence.
587 index = start;
588 return getEscapedIdentifier();
589 }
590 if (isIdentifierPart(ch)) {
591 ++index;
592 } else {
593 break;
594 }
595 }
596
597 return source.slice(start, index);
598 }
599
600 function scanIdentifier() {
601 var start, id, type;
602
603 start = index;
604
605 // Backslash (U+005C) starts an escaped character.
606 id = (source.charCodeAt(index) === 0x5C) ? getEscapedIdentifier() : getIdentifier();
607
608 // There is no keyword or literal with only one character.
609 // Thus, it must be an identifier.
610 if (id.length === 1) {
611 type = Token.Identifier;
612 } else if (isKeyword(id)) {
613 type = Token.Keyword;
614 } else if (id === 'null') {
615 type = Token.NullLiteral;
616 } else if (id === 'true' || id === 'false') {
617 type = Token.BooleanLiteral;
618 } else {
619 type = Token.Identifier;
620 }
621
622 return {
623 type: type,
624 value: id,
625 lineNumber: lineNumber,
626 lineStart: lineStart,
627 start: start,
628 end: index
629 };
630 }
631
632
633 // 7.7 Punctuators
634
635 function scanPunctuator() {
636 var start = index,
637 code = source.charCodeAt(index),
638 code2,
639 ch1 = source[index],
640 ch2,
641 ch3,
642 ch4;
643
644 switch (code) {
645
646 // Check for most common single-character punctuators.
647 case 0x2E: // . dot
648 case 0x28: // ( open bracket
649 case 0x29: // ) close bracket
650 case 0x3B: // ; semicolon
651 case 0x2C: // , comma
652 case 0x7B: // { open curly brace
653 case 0x7D: // } close curly brace
654 case 0x5B: // [
655 case 0x5D: // ]
656 case 0x3A: // :
657 case 0x3F: // ?
658 case 0x7E: // ~
659 ++index;
660 if (extra.tokenize) {
661 if (code === 0x28) {
662 extra.openParenToken = extra.tokens.length;
663 } else if (code === 0x7B) {
664 extra.openCurlyToken = extra.tokens.length;
665 }
666 }
667 return {
668 type: Token.Punctuator,
669 value: String.fromCharCode(code),
670 lineNumber: lineNumber,
671 lineStart: lineStart,
672 start: start,
673 end: index
674 };
675
676 default:
677 code2 = source.charCodeAt(index + 1);
678
679 // '=' (U+003D) marks an assignment or comparison operator.
680 if (code2 === 0x3D) {
681 switch (code) {
682 case 0x2B: // +
683 case 0x2D: // -
684 case 0x2F: // /
685 case 0x3C: // <
686 case 0x3E: // >
687 case 0x5E: // ^
688 case 0x7C: // |
689 case 0x25: // %
690 case 0x26: // &
691 case 0x2A: // *
692 index += 2;
693 return {
694 type: Token.Punctuator,
695 value: String.fromCharCode(code) + String.fromCharCode(code2),
696 lineNumber: lineNumber,
697 lineStart: lineStart,
698 start: start,
699 end: index
700 };
701
702 case 0x21: // !
703 case 0x3D: // =
704 index += 2;
705
706 // !== and ===
707 if (source.charCodeAt(index) === 0x3D) {
708 ++index;
709 }
710 return {
711 type: Token.Punctuator,
712 value: source.slice(start, index),
713 lineNumber: lineNumber,
714 lineStart: lineStart,
715 start: start,
716 end: index
717 };
718 }
719 }
720 }
721
722 // 4-character punctuator: >>>=
723
724 ch4 = source.substr(index, 4);
725
726 if (ch4 === '>>>=') {
727 index += 4;
728 return {
729 type: Token.Punctuator,
730 value: ch4,
731 lineNumber: lineNumber,
732 lineStart: lineStart,
733 start: start,
734 end: index
735 };
736 }
737
738 // 3-character punctuators: === !== >>> <<= >>=
739
740 ch3 = ch4.substr(0, 3);
741
742 if (ch3 === '>>>' || ch3 === '<<=' || ch3 === '>>=') {
743 index += 3;
744 return {
745 type: Token.Punctuator,
746 value: ch3,
747 lineNumber: lineNumber,
748 lineStart: lineStart,
749 start: start,
750 end: index
751 };
752 }
753
754 // Other 2-character punctuators: ++ -- << >> && ||
755 ch2 = ch3.substr(0, 2);
756
757 if ((ch1 === ch2[1] && ('+-<>&|'.indexOf(ch1) >= 0)) || ch2 === '=>') {
758 index += 2;
759 return {
760 type: Token.Punctuator,
761 value: ch2,
762 lineNumber: lineNumber,
763 lineStart: lineStart,
764 start: start,
765 end: index
766 };
767 }
768
769 // 1-character punctuators: < > = ! + - * % & | ^ /
770 if ('<>=!+-*%&|^/'.indexOf(ch1) >= 0) {
771 ++index;
772 return {
773 type: Token.Punctuator,
774 value: ch1,
775 lineNumber: lineNumber,
776 lineStart: lineStart,
777 start: start,
778 end: index
779 };
780 }
781
782 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
783 }
784
785 // 7.8.3 Numeric Literals
786
787 function scanHexLiteral(start) {
788 var number = '';
789
790 while (index < length) {
791 if (!isHexDigit(source[index])) {
792 break;
793 }
794 number += source[index++];
795 }
796
797 if (number.length === 0) {
798 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
799 }
800
801 if (isIdentifierStart(source.charCodeAt(index))) {
802 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
803 }
804
805 return {
806 type: Token.NumericLiteral,
807 value: parseInt('0x' + number, 16),
808 lineNumber: lineNumber,
809 lineStart: lineStart,
810 start: start,
811 end: index
812 };
813 }
814
815 function scanOctalLiteral(start) {
816 var number = '0' + source[index++];
817 while (index < length) {
818 if (!isOctalDigit(source[index])) {
819 break;
820 }
821 number += source[index++];
822 }
823
824 if (isIdentifierStart(source.charCodeAt(index)) || isDecimalDigit(source.charCodeAt(index))) {
825 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
826 }
827
828 return {
829 type: Token.NumericLiteral,
830 value: parseInt(number, 8),
831 octal: true,
832 lineNumber: lineNumber,
833 lineStart: lineStart,
834 start: start,
835 end: index
836 };
837 }
838
839 function scanNumericLiteral() {
840 var number, start, ch;
841
842 ch = source[index];
843 assert(isDecimalDigit(ch.charCodeAt(0)) || (ch === '.'),
844 'Numeric literal must start with a decimal digit or a decimal point');
845
846 start = index;
847 number = '';
848 if (ch !== '.') {
849 number = source[index++];
850 ch = source[index];
851
852 // Hex number starts with '0x'.
853 // Octal number starts with '0'.
854 if (number === '0') {
855 if (ch === 'x' || ch === 'X') {
856 ++index;
857 return scanHexLiteral(start);
858 }
859 if (isOctalDigit(ch)) {
860 return scanOctalLiteral(start);
861 }
862
863 // decimal number starts with '0' such as '09' is illegal.
864 if (ch && isDecimalDigit(ch.charCodeAt(0))) {
865 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
866 }
867 }
868
869 while (isDecimalDigit(source.charCodeAt(index))) {
870 number += source[index++];
871 }
872 ch = source[index];
873 }
874
875 if (ch === '.') {
876 number += source[index++];
877 while (isDecimalDigit(source.charCodeAt(index))) {
878 number += source[index++];
879 }
880 ch = source[index];
881 }
882
883 if (ch === 'e' || ch === 'E') {
884 number += source[index++];
885
886 ch = source[index];
887 if (ch === '+' || ch === '-') {
888 number += source[index++];
889 }
890 if (isDecimalDigit(source.charCodeAt(index))) {
891 while (isDecimalDigit(source.charCodeAt(index))) {
892 number += source[index++];
893 }
894 } else {
895 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
896 }
897 }
898
899 if (isIdentifierStart(source.charCodeAt(index))) {
900 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
901 }
902
903 return {
904 type: Token.NumericLiteral,
905 value: parseFloat(number),
906 lineNumber: lineNumber,
907 lineStart: lineStart,
908 start: start,
909 end: index
910 };
911 }
912
913 // 7.8.4 String Literals
914
915 function scanStringLiteral() {
916 var str = '', quote, start, ch, code, unescaped, restore, octal = false, startLineNumber, startLineStart;
917 startLineNumber = lineNumber;
918 startLineStart = lineStart;
919
920 quote = source[index];
921 assert((quote === '\'' || quote === '"'),
922 'String literal must starts with a quote');
923
924 start = index;
925 ++index;
926
927 while (index < length) {
928 ch = source[index++];
929
930 if (ch === quote) {
931 quote = '';
932 break;
933 } else if (ch === '\\') {
934 ch = source[index++];
935 if (!ch || !isLineTerminator(ch.charCodeAt(0))) {
936 switch (ch) {
937 case 'u':
938 case 'x':
939 restore = index;
940 unescaped = scanHexEscape(ch);
941 if (unescaped) {
942 str += unescaped;
943 } else {
944 index = restore;
945 str += ch;
946 }
947 break;
948 case 'n':
949 str += '\n';
950 break;
951 case 'r':
952 str += '\r';
953 break;
954 case 't':
955 str += '\t';
956 break;
957 case 'b':
958 str += '\b';
959 break;
960 case 'f':
961 str += '\f';
962 break;
963 case 'v':
964 str += '\x0B';
965 break;
966
967 default:
968 if (isOctalDigit(ch)) {
969 code = '01234567'.indexOf(ch);
970
971 // \0 is not octal escape sequence
972 if (code !== 0) {
973 octal = true;
974 }
975
976 if (index < length && isOctalDigit(source[index])) {
977 octal = true;
978 code = code * 8 + '01234567'.indexOf(source[index++]);
979
980 // 3 digits are only allowed when string starts
981 // with 0, 1, 2, 3
982 if ('0123'.indexOf(ch) >= 0 &&
983 index < length &&
984 isOctalDigit(source[index])) {
985 code = code * 8 + '01234567'.indexOf(source[index++]);
986 }
987 }
988 str += String.fromCharCode(code);
989 } else {
990 str += ch;
991 }
992 break;
993 }
994 } else {
995 ++lineNumber;
996 if (ch === '\r' && source[index] === '\n') {
997 ++index;
998 }
999 lineStart = index;
1000 }
1001 } else if (isLineTerminator(ch.charCodeAt(0))) {
1002 break;
1003 } else {
1004 str += ch;
1005 }
1006 }
1007
1008 if (quote !== '') {
1009 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
1010 }
1011
1012 return {
1013 type: Token.StringLiteral,
1014 value: str,
1015 octal: octal,
1016 startLineNumber: startLineNumber,
1017 startLineStart: startLineStart,
1018 lineNumber: lineNumber,
1019 lineStart: lineStart,
1020 start: start,
1021 end: index
1022 };
1023 }
1024
1025 function testRegExp(pattern, flags) {
1026 var value;
1027 try {
1028 value = new RegExp(pattern, flags);
1029 } catch (e) {
1030 throwError({}, Messages.InvalidRegExp);
1031 }
1032 return value;
1033 }
1034
1035 function scanRegExpBody() {
1036 var ch, str, classMarker, terminated, body;
1037
1038 ch = source[index];
1039 assert(ch === '/', 'Regular expression literal must start with a slash');
1040 str = source[index++];
1041
1042 classMarker = false;
1043 terminated = false;
1044 while (index < length) {
1045 ch = source[index++];
1046 str += ch;
1047 if (ch === '\\') {
1048 ch = source[index++];
1049 // ECMA-262 7.8.5
1050 if (isLineTerminator(ch.charCodeAt(0))) {
1051 throwError({}, Messages.UnterminatedRegExp);
1052 }
1053 str += ch;
1054 } else if (isLineTerminator(ch.charCodeAt(0))) {
1055 throwError({}, Messages.UnterminatedRegExp);
1056 } else if (classMarker) {
1057 if (ch === ']') {
1058 classMarker = false;
1059 }
1060 } else {
1061 if (ch === '/') {
1062 terminated = true;
1063 break;
1064 } else if (ch === '[') {
1065 classMarker = true;
1066 }
1067 }
1068 }
1069
1070 if (!terminated) {
1071 throwError({}, Messages.UnterminatedRegExp);
1072 }
1073
1074 // Exclude leading and trailing slash.
1075 body = str.substr(1, str.length - 2);
1076 return {
1077 value: body,
1078 literal: str
1079 };
1080 }
1081
1082 function scanRegExpFlags() {
1083 var ch, str, flags, restore;
1084
1085 str = '';
1086 flags = '';
1087 while (index < length) {
1088 ch = source[index];
1089 if (!isIdentifierPart(ch.charCodeAt(0))) {
1090 break;
1091 }
1092
1093 ++index;
1094 if (ch === '\\' && index < length) {
1095 ch = source[index];
1096 if (ch === 'u') {
1097 ++index;
1098 restore = index;
1099 ch = scanHexEscape('u');
1100 if (ch) {
1101 flags += ch;
1102 for (str += '\\u'; restore < index; ++restore) {
1103 str += source[restore];
1104 }
1105 } else {
1106 index = restore;
1107 flags += 'u';
1108 str += '\\u';
1109 }
1110 throwErrorTolerant({}, Messages.UnexpectedToken, 'ILLEGAL');
1111 } else {
1112 str += '\\';
1113 throwErrorTolerant({}, Messages.UnexpectedToken, 'ILLEGAL');
1114 }
1115 } else {
1116 flags += ch;
1117 str += ch;
1118 }
1119 }
1120
1121 return {
1122 value: flags,
1123 literal: str
1124 };
1125 }
1126
1127 function scanRegExp() {
1128 var start, body, flags, pattern, value;
1129
1130 lookahead = null;
1131 skipComment();
1132 start = index;
1133
1134 body = scanRegExpBody();
1135 flags = scanRegExpFlags();
1136 value = testRegExp(body.value, flags.value);
1137
1138 if (extra.tokenize) {
1139 return {
1140 type: Token.RegularExpression,
1141 value: value,
1142 lineNumber: lineNumber,
1143 lineStart: lineStart,
1144 start: start,
1145 end: index
1146 };
1147 }
1148
1149 return {
1150 literal: body.literal + flags.literal,
1151 value: value,
1152 start: start,
1153 end: index
1154 };
1155 }
1156
1157 function collectRegex() {
1158 var pos, loc, regex, token;
1159
1160 skipComment();
1161
1162 pos = index;
1163 loc = {
1164 start: {
1165 line: lineNumber,
1166 column: index - lineStart
1167 }
1168 };
1169
1170 regex = scanRegExp();
1171 loc.end = {
1172 line: lineNumber,
1173 column: index - lineStart
1174 };
1175
1176 /* istanbul ignore next */
1177 if (!extra.tokenize) {
1178 // Pop the previous token, which is likely '/' or '/='
1179 if (extra.tokens.length > 0) {
1180 token = extra.tokens[extra.tokens.length - 1];
1181 if (token.range[0] === pos && token.type === 'Punctuator') {
1182 if (token.value === '/' || token.value === '/=') {
1183 extra.tokens.pop();
1184 }
1185 }
1186 }
1187
1188 extra.tokens.push({
1189 type: 'RegularExpression',
1190 value: regex.literal,
1191 range: [pos, index],
1192 loc: loc
1193 });
1194 }
1195
1196 return regex;
1197 }
1198
1199 function isIdentifierName(token) {
1200 return token.type === Token.Identifier ||
1201 token.type === Token.Keyword ||
1202 token.type === Token.BooleanLiteral ||
1203 token.type === Token.NullLiteral;
1204 }
1205
1206 function advanceSlash() {
1207 var prevToken,
1208 checkToken;
1209 // Using the following algorithm:
1210 // https://github.com/mozilla/sweet.js/wiki/design
1211 prevToken = extra.tokens[extra.tokens.length - 1];
1212 if (!prevToken) {
1213 // Nothing before that: it cannot be a division.
1214 return collectRegex();
1215 }
1216 if (prevToken.type === 'Punctuator') {
1217 if (prevToken.value === ']') {
1218 return scanPunctuator();
1219 }
1220 if (prevToken.value === ')') {
1221 checkToken = extra.tokens[extra.openParenToken - 1];
1222 if (checkToken &&
1223 checkToken.type === 'Keyword' &&
1224 (checkToken.value === 'if' ||
1225 checkToken.value === 'while' ||
1226 checkToken.value === 'for' ||
1227 checkToken.value === 'with')) {
1228 return collectRegex();
1229 }
1230 return scanPunctuator();
1231 }
1232 if (prevToken.value === '}') {
1233 // Dividing a function by anything makes little sense,
1234 // but we have to check for that.
1235 if (extra.tokens[extra.openCurlyToken - 3] &&
1236 extra.tokens[extra.openCurlyToken - 3].type === 'Keyword') {
1237 // Anonymous function.
1238 checkToken = extra.tokens[extra.openCurlyToken - 4];
1239 if (!checkToken) {
1240 return scanPunctuator();
1241 }
1242 } else if (extra.tokens[extra.openCurlyToken - 4] &&
1243 extra.tokens[extra.openCurlyToken - 4].type === 'Keyword') {
1244 // Named function.
1245 checkToken = extra.tokens[extra.openCurlyToken - 5];
1246 if (!checkToken) {
1247 return collectRegex();
1248 }
1249 } else {
1250 return scanPunctuator();
1251 }
1252 // checkToken determines whether the function is
1253 // a declaration or an expression.
1254 if (FnExprTokens.indexOf(checkToken.value) >= 0) {
1255 // It is an expression.
1256 return scanPunctuator();
1257 }
1258 // It is a declaration.
1259 return collectRegex();
1260 }
1261 return collectRegex();
1262 }
1263 if (prevToken.type === 'Keyword') {
1264 return collectRegex();
1265 }
1266 return scanPunctuator();
1267 }
1268
1269 function advance() {
1270 var ch;
1271
1272 skipComment();
1273
1274 if (index >= length) {
1275 return {
1276 type: Token.EOF,
1277 lineNumber: lineNumber,
1278 lineStart: lineStart,
1279 start: index,
1280 end: index
1281 };
1282 }
1283
1284 ch = source.charCodeAt(index);
1285
1286 if (isIdentifierStart(ch)) {
1287 return scanIdentifier();
1288 }
1289
1290 // Very common: ( and ) and ;
1291 if (ch === 0x28 || ch === 0x29 || ch === 0x3B) {
1292 return scanPunctuator();
1293 }
1294
1295 // String literal starts with single quote (U+0027) or double quote (U+0022).
1296 if (ch === 0x27 || ch === 0x22) {
1297 return scanStringLiteral();
1298 }
1299
1300
1301 // Dot (.) U+002E can also start a floating-point number, hence the need
1302 // to check the next character.
1303 if (ch === 0x2E) {
1304 if (isDecimalDigit(source.charCodeAt(index + 1))) {
1305 return scanNumericLiteral();
1306 }
1307 return scanPunctuator();
1308 }
1309
1310 if (isDecimalDigit(ch)) {
1311 return scanNumericLiteral();
1312 }
1313
1314 // Slash (/) U+002F can also start a regex.
1315 if (extra.tokenize && ch === 0x2F) {
1316 return advanceSlash();
1317 }
1318
1319 return scanPunctuator();
1320 }
1321
1322 function collectToken() {
1323 var loc, token, range, value;
1324
1325 skipComment();
1326 loc = {
1327 start: {
1328 line: lineNumber,
1329 column: index - lineStart
1330 }
1331 };
1332
1333 token = advance();
1334 loc.end = {
1335 line: lineNumber,
1336 column: index - lineStart
1337 };
1338
1339 if (token.type !== Token.EOF) {
1340 value = source.slice(token.start, token.end);
1341 extra.tokens.push({
1342 type: TokenName[token.type],
1343 value: value,
1344 range: [token.start, token.end],
1345 loc: loc
1346 });
1347 }
1348
1349 return token;
1350 }
1351
1352 function lex() {
1353 var token;
1354
1355 token = lookahead;
1356 index = token.end;
1357 lineNumber = token.lineNumber;
1358 lineStart = token.lineStart;
1359
1360 lookahead = (typeof extra.tokens !== 'undefined') ? collectToken() : advance();
1361
1362 index = token.end;
1363 lineNumber = token.lineNumber;
1364 lineStart = token.lineStart;
1365
1366 return token;
1367 }
1368
1369 function peek() {
1370 var pos, line, start;
1371
1372 pos = index;
1373 line = lineNumber;
1374 start = lineStart;
1375 lookahead = (typeof extra.tokens !== 'undefined') ? collectToken() : advance();
1376 index = pos;
1377 lineNumber = line;
1378 lineStart = start;
1379 }
1380
1381 function Position(line, column) {
1382 this.line = line;
1383 this.column = column;
1384 }
1385
1386 function SourceLocation(startLine, startColumn, line, column) {
1387 this.start = new Position(startLine, startColumn);
1388 this.end = new Position(line, column);
1389 }
1390
1391 SyntaxTreeDelegate = {
1392
1393 name: 'SyntaxTree',
1394
1395 processComment: function (node) {
1396 var lastChild, trailingComments;
1397
1398 if (node.type === Syntax.Program) {
1399 if (node.body.length > 0) {
1400 return;
1401 }
1402 }
1403
1404 if (extra.trailingComments.length > 0) {
1405 if (extra.trailingComments[0].range[0] >= node.range[1]) {
1406 trailingComments = extra.trailingComments;
1407 extra.trailingComments = [];
1408 } else {
1409 extra.trailingComments.length = 0;
1410 }
1411 } else {
1412 if (extra.bottomRightStack.length > 0 &&
1413 extra.bottomRightStack[extra.bottomRightStack.length - 1].trailingComments &&
1414 extra.bottomRightStack[extra.bottomRightStack.length - 1].trailingComments[0].range[0] >= node.range[1]) {
1415 trailingComments = extra.bottomRightStack[extra.bottomRightStack.length - 1].trailingComments;
1416 delete extra.bottomRightStack[extra.bottomRightStack.length - 1].trailingComments;
1417 }
1418 }
1419
1420 // Eating the stack.
1421 while (extra.bottomRightStack.length > 0 && extra.bottomRightStack[extra.bottomRightStack.length - 1].range[0] >= node.range[0]) {
1422 lastChild = extra.bottomRightStack.pop();
1423 }
1424
1425 if (lastChild) {
1426 if (lastChild.leadingComments && lastChild.leadingComments[lastChild.leadingComments.length - 1].range[1] <= node.range[0]) {
1427 node.leadingComments = lastChild.leadingComments;
1428 delete lastChild.leadingComments;
1429 }
1430 } else if (extra.leadingComments.length > 0 && extra.leadingComments[extra.leadingComments.length - 1].range[1] <= node.range[0]) {
1431 node.leadingComments = extra.leadingComments;
1432 extra.leadingComments = [];
1433 }
1434
1435
1436 if (trailingComments) {
1437 node.trailingComments = trailingComments;
1438 }
1439
1440 extra.bottomRightStack.push(node);
1441 },
1442
1443 markEnd: function (node, startToken) {
1444 if (extra.range) {
1445 node.range = [startToken.start, index];
1446 }
1447 if (extra.loc) {
1448 node.loc = new SourceLocation(
1449 startToken.startLineNumber === undefined ? startToken.lineNumber : startToken.startLineNumber,
1450 startToken.start - (startToken.startLineStart === undefined ? startToken.lineStart : startToken.startLineStart),
1451 lineNumber,
1452 index - lineStart
1453 );
1454 this.postProcess(node);
1455 }
1456
1457 if (extra.attachComment) {
1458 this.processComment(node);
1459 }
1460 return node;
1461 },
1462
1463 postProcess: function (node) {
1464 if (extra.source) {
1465 node.loc.source = extra.source;
1466 }
1467 return node;
1468 },
1469
1470 createArrayExpression: function (elements) {
1471 return {
1472 type: Syntax.ArrayExpression,
1473 elements: elements
1474 };
1475 },
1476
1477 createAssignmentExpression: function (operator, left, right) {
1478 return {
1479 type: Syntax.AssignmentExpression,
1480 operator: operator,
1481 left: left,
1482 right: right
1483 };
1484 },
1485
1486 createBinaryExpression: function (operator, left, right) {
1487 var type = (operator === '||' || operator === '&&') ? Syntax.LogicalExpression :
1488 Syntax.BinaryExpression;
1489 return {
1490 type: type,
1491 operator: operator,
1492 left: left,
1493 right: right
1494 };
1495 },
1496
1497 createBlockStatement: function (body) {
1498 return {
1499 type: Syntax.BlockStatement,
1500 body: body
1501 };
1502 },
1503
1504 createBreakStatement: function (label) {
1505 return {
1506 type: Syntax.BreakStatement,
1507 label: label
1508 };
1509 },
1510
1511 createCallExpression: function (callee, args) {
1512 return {
1513 type: Syntax.CallExpression,
1514 callee: callee,
1515 'arguments': args
1516 };
1517 },
1518
1519 createCatchClause: function (param, body) {
1520 return {
1521 type: Syntax.CatchClause,
1522 param: param,
1523 body: body
1524 };
1525 },
1526
1527 createConditionalExpression: function (test, consequent, alternate) {
1528 return {
1529 type: Syntax.ConditionalExpression,
1530 test: test,
1531 consequent: consequent,
1532 alternate: alternate
1533 };
1534 },
1535
1536 createContinueStatement: function (label) {
1537 return {
1538 type: Syntax.ContinueStatement,
1539 label: label
1540 };
1541 },
1542
1543 createDebuggerStatement: function () {
1544 return {
1545 type: Syntax.DebuggerStatement
1546 };
1547 },
1548
1549 createDoWhileStatement: function (body, test) {
1550 return {
1551 type: Syntax.DoWhileStatement,
1552 body: body,
1553 test: test
1554 };
1555 },
1556
1557 createEmptyStatement: function () {
1558 return {
1559 type: Syntax.EmptyStatement
1560 };
1561 },
1562
1563 createExpressionStatement: function (expression) {
1564 return {
1565 type: Syntax.ExpressionStatement,
1566 expression: expression
1567 };
1568 },
1569
1570 createForStatement: function (init, test, update, body) {
1571 return {
1572 type: Syntax.ForStatement,
1573 init: init,
1574 test: test,
1575 update: update,
1576 body: body
1577 };
1578 },
1579
1580 createForInStatement: function (left, right, body) {
1581 return {
1582 type: Syntax.ForInStatement,
1583 left: left,
1584 right: right,
1585 body: body,
1586 each: false
1587 };
1588 },
1589
1590 createFunctionDeclaration: function (id, params, defaults, body) {
1591 return {
1592 type: Syntax.FunctionDeclaration,
1593 id: id,
1594 params: params,
1595 defaults: defaults,
1596 body: body,
1597 rest: null,
1598 generator: false,
1599 expression: false
1600 };
1601 },
1602
1603 createFunctionExpression: function (id, params, defaults, body) {
1604 return {
1605 type: Syntax.FunctionExpression,
1606 id: id,
1607 params: params,
1608 defaults: defaults,
1609 body: body,
1610 rest: null,
1611 generator: false,
1612 expression: false
1613 };
1614 },
1615
1616 createIdentifier: function (name) {
1617 return {
1618 type: Syntax.Identifier,
1619 name: name
1620 };
1621 },
1622
1623 createIfStatement: function (test, consequent, alternate) {
1624 return {
1625 type: Syntax.IfStatement,
1626 test: test,
1627 consequent: consequent,
1628 alternate: alternate
1629 };
1630 },
1631
1632 createLabeledStatement: function (label, body) {
1633 return {
1634 type: Syntax.LabeledStatement,
1635 label: label,
1636 body: body
1637 };
1638 },
1639
1640 createLiteral: function (token) {
1641 return {
1642 type: Syntax.Literal,
1643 value: token.value,
1644 raw: source.slice(token.start, token.end)
1645 };
1646 },
1647
1648 createMemberExpression: function (accessor, object, property) {
1649 return {
1650 type: Syntax.MemberExpression,
1651 computed: accessor === '[',
1652 object: object,
1653 property: property
1654 };
1655 },
1656
1657 createNewExpression: function (callee, args) {
1658 return {
1659 type: Syntax.NewExpression,
1660 callee: callee,
1661 'arguments': args
1662 };
1663 },
1664
1665 createObjectExpression: function (properties) {
1666 return {
1667 type: Syntax.ObjectExpression,
1668 properties: properties
1669 };
1670 },
1671
1672 createPostfixExpression: function (operator, argument) {
1673 return {
1674 type: Syntax.UpdateExpression,
1675 operator: operator,
1676 argument: argument,
1677 prefix: false
1678 };
1679 },
1680
1681 createProgram: function (body) {
1682 return {
1683 type: Syntax.Program,
1684 body: body
1685 };
1686 },
1687
1688 createProperty: function (kind, key, value) {
1689 return {
1690 type: Syntax.Property,
1691 key: key,
1692 value: value,
1693 kind: kind
1694 };
1695 },
1696
1697 createReturnStatement: function (argument) {
1698 return {
1699 type: Syntax.ReturnStatement,
1700 argument: argument
1701 };
1702 },
1703
1704 createSequenceExpression: function (expressions) {
1705 return {
1706 type: Syntax.SequenceExpression,
1707 expressions: expressions
1708 };
1709 },
1710
1711 createSwitchCase: function (test, consequent) {
1712 return {
1713 type: Syntax.SwitchCase,
1714 test: test,
1715 consequent: consequent
1716 };
1717 },
1718
1719 createSwitchStatement: function (discriminant, cases) {
1720 return {
1721 type: Syntax.SwitchStatement,
1722 discriminant: discriminant,
1723 cases: cases
1724 };
1725 },
1726
1727 createThisExpression: function () {
1728 return {
1729 type: Syntax.ThisExpression
1730 };
1731 },
1732
1733 createThrowStatement: function (argument) {
1734 return {
1735 type: Syntax.ThrowStatement,
1736 argument: argument
1737 };
1738 },
1739
1740 createTryStatement: function (block, guardedHandlers, handlers, finalizer) {
1741 return {
1742 type: Syntax.TryStatement,
1743 block: block,
1744 guardedHandlers: guardedHandlers,
1745 handlers: handlers,
1746 finalizer: finalizer
1747 };
1748 },
1749
1750 createUnaryExpression: function (operator, argument) {
1751 if (operator === '++' || operator === '--') {
1752 return {
1753 type: Syntax.UpdateExpression,
1754 operator: operator,
1755 argument: argument,
1756 prefix: true
1757 };
1758 }
1759 return {
1760 type: Syntax.UnaryExpression,
1761 operator: operator,
1762 argument: argument,
1763 prefix: true
1764 };
1765 },
1766
1767 createVariableDeclaration: function (declarations, kind) {
1768 return {
1769 type: Syntax.VariableDeclaration,
1770 declarations: declarations,
1771 kind: kind
1772 };
1773 },
1774
1775 createVariableDeclarator: function (id, init) {
1776 return {
1777 type: Syntax.VariableDeclarator,
1778 id: id,
1779 init: init
1780 };
1781 },
1782
1783 createWhileStatement: function (test, body) {
1784 return {
1785 type: Syntax.WhileStatement,
1786 test: test,
1787 body: body
1788 };
1789 },
1790
1791 createWithStatement: function (object, body) {
1792 return {
1793 type: Syntax.WithStatement,
1794 object: object,
1795 body: body
1796 };
1797 }
1798 };
1799
1800 // Return true if there is a line terminator before the next token.
1801
1802 function peekLineTerminator() {
1803 var pos, line, start, found;
1804
1805 pos = index;
1806 line = lineNumber;
1807 start = lineStart;
1808 skipComment();
1809 found = lineNumber !== line;
1810 index = pos;
1811 lineNumber = line;
1812 lineStart = start;
1813
1814 return found;
1815 }
1816
1817 // Throw an exception
1818
1819 function throwError(token, messageFormat) {
1820 var error,
1821 args = Array.prototype.slice.call(arguments, 2),
1822 msg = messageFormat.replace(
1823 /%(\d)/g,
1824 function (whole, index) {
1825 assert(index < args.length, 'Message reference must be in range');
1826 return args[index];
1827 }
1828 );
1829
1830 if (typeof token.lineNumber === 'number') {
1831 error = new Error('Line ' + token.lineNumber + ': ' + msg);
1832 error.index = token.start;
1833 error.lineNumber = token.lineNumber;
1834 error.column = token.start - lineStart + 1;
1835 } else {
1836 error = new Error('Line ' + lineNumber + ': ' + msg);
1837 error.index = index;
1838 error.lineNumber = lineNumber;
1839 error.column = index - lineStart + 1;
1840 }
1841
1842 error.description = msg;
1843 throw error;
1844 }
1845
1846 function throwErrorTolerant() {
1847 try {
1848 throwError.apply(null, arguments);
1849 } catch (e) {
1850 if (extra.errors) {
1851 extra.errors.push(e);
1852 } else {
1853 throw e;
1854 }
1855 }
1856 }
1857
1858
1859 // Throw an exception because of the token.
1860
1861 function throwUnexpected(token) {
1862 if (token.type === Token.EOF) {
1863 throwError(token, Messages.UnexpectedEOS);
1864 }
1865
1866 if (token.type === Token.NumericLiteral) {
1867 throwError(token, Messages.UnexpectedNumber);
1868 }
1869
1870 if (token.type === Token.StringLiteral) {
1871 throwError(token, Messages.UnexpectedString);
1872 }
1873
1874 if (token.type === Token.Identifier) {
1875 throwError(token, Messages.UnexpectedIdentifier);
1876 }
1877
1878 if (token.type === Token.Keyword) {
1879 if (isFutureReservedWord(token.value)) {
1880 throwError(token, Messages.UnexpectedReserved);
1881 } else if (strict && isStrictModeReservedWord(token.value)) {
1882 throwErrorTolerant(token, Messages.StrictReservedWord);
1883 return;
1884 }
1885 throwError(token, Messages.UnexpectedToken, token.value);
1886 }
1887
1888 // BooleanLiteral, NullLiteral, or Punctuator.
1889 throwError(token, Messages.UnexpectedToken, token.value);
1890 }
1891
1892 // Expect the next token to match the specified punctuator.
1893 // If not, an exception will be thrown.
1894
1895 function expect(value) {
1896 var token = lex();
1897 if (token.type !== Token.Punctuator || token.value !== value) {
1898 throwUnexpected(token);
1899 }
1900 }
1901
1902 // Expect the next token to match the specified keyword.
1903 // If not, an exception will be thrown.
1904
1905 function expectKeyword(keyword) {
1906 var token = lex();
1907 if (token.type !== Token.Keyword || token.value !== keyword) {
1908 throwUnexpected(token);
1909 }
1910 }
1911
1912 // Return true if the next token matches the specified punctuator.
1913
1914 function match(value) {
1915 return lookahead.type === Token.Punctuator && lookahead.value === value;
1916 }
1917
1918 // Return true if the next token matches the specified keyword
1919
1920 function matchKeyword(keyword) {
1921 return lookahead.type === Token.Keyword && lookahead.value === keyword;
1922 }
1923
1924 // Return true if the next token is an assignment operator
1925
1926 function matchAssign() {
1927 var op;
1928
1929 if (lookahead.type !== Token.Punctuator) {
1930 return false;
1931 }
1932 op = lookahead.value;
1933 return op === '=' ||
1934 op === '*=' ||
1935 op === '/=' ||
1936 op === '%=' ||
1937 op === '+=' ||
1938 op === '-=' ||
1939 op === '<<=' ||
1940 op === '>>=' ||
1941 op === '>>>=' ||
1942 op === '&=' ||
1943 op === '^=' ||
1944 op === '|=';
1945 }
1946
1947 function consumeSemicolon() {
1948 var line;
1949
1950 // Catch the very common case first: immediately a semicolon (U+003B).
1951 if (source.charCodeAt(index) === 0x3B || match(';')) {
1952 lex();
1953 return;
1954 }
1955
1956 line = lineNumber;
1957 skipComment();
1958 if (lineNumber !== line) {
1959 return;
1960 }
1961
1962 if (lookahead.type !== Token.EOF && !match('}')) {
1963 throwUnexpected(lookahead);
1964 }
1965 }
1966
1967 // Return true if provided expression is LeftHandSideExpression
1968
1969 function isLeftHandSide(expr) {
1970 return expr.type === Syntax.Identifier || expr.type === Syntax.MemberExpression;
1971 }
1972
1973 // 11.1.4 Array Initialiser
1974
1975 function parseArrayInitialiser() {
1976 var elements = [], startToken;
1977
1978 startToken = lookahead;
1979 expect('[');
1980
1981 while (!match(']')) {
1982 if (match(',')) {
1983 lex();
1984 elements.push(null);
1985 } else {
1986 elements.push(parseAssignmentExpression());
1987
1988 if (!match(']')) {
1989 expect(',');
1990 }
1991 }
1992 }
1993
1994 lex();
1995
1996 return delegate.markEnd(delegate.createArrayExpression(elements), startToken);
1997 }
1998
1999 // 11.1.5 Object Initialiser
2000
2001 function parsePropertyFunction(param, first) {
2002 var previousStrict, body, startToken;
2003
2004 previousStrict = strict;
2005 startToken = lookahead;
2006 body = parseFunctionSourceElements();
2007 if (first && strict && isRestrictedWord(param[0].name)) {
2008 throwErrorTolerant(first, Messages.StrictParamName);
2009 }
2010 strict = previousStrict;
2011 return delegate.markEnd(delegate.createFunctionExpression(null, param, [], body), startToken);
2012 }
2013
2014 function parseObjectPropertyKey() {
2015 var token, startToken;
2016
2017 startToken = lookahead;
2018 token = lex();
2019
2020 // Note: This function is called only from parseObjectProperty(), where
2021 // EOF and Punctuator tokens are already filtered out.
2022
2023 if (token.type === Token.StringLiteral || token.type === Token.NumericLiteral) {
2024 if (strict && token.octal) {
2025 throwErrorTolerant(token, Messages.StrictOctalLiteral);
2026 }
2027 return delegate.markEnd(delegate.createLiteral(token), startToken);
2028 }
2029
2030 return delegate.markEnd(delegate.createIdentifier(token.value), startToken);
2031 }
2032
2033 function parseObjectProperty() {
2034 var token, key, id, value, param, startToken;
2035
2036 token = lookahead;
2037 startToken = lookahead;
2038
2039 if (token.type === Token.Identifier) {
2040
2041 id = parseObjectPropertyKey();
2042
2043 // Property Assignment: Getter and Setter.
2044
2045 if (token.value === 'get' && !match(':')) {
2046 key = parseObjectPropertyKey();
2047 expect('(');
2048 expect(')');
2049 value = parsePropertyFunction([]);
2050 return delegate.markEnd(delegate.createProperty('get', key, value), startToken);
2051 }
2052 if (token.value === 'set' && !match(':')) {
2053 key = parseObjectPropertyKey();
2054 expect('(');
2055 token = lookahead;
2056 if (token.type !== Token.Identifier) {
2057 expect(')');
2058 throwErrorTolerant(token, Messages.UnexpectedToken, token.value);
2059 value = parsePropertyFunction([]);
2060 } else {
2061 param = [ parseVariableIdentifier() ];
2062 expect(')');
2063 value = parsePropertyFunction(param, token);
2064 }
2065 return delegate.markEnd(delegate.createProperty('set', key, value), startToken);
2066 }
2067 expect(':');
2068 value = parseAssignmentExpression();
2069 return delegate.markEnd(delegate.createProperty('init', id, value), startToken);
2070 }
2071 if (token.type === Token.EOF || token.type === Token.Punctuator) {
2072 throwUnexpected(token);
2073 } else {
2074 key = parseObjectPropertyKey();
2075 expect(':');
2076 value = parseAssignmentExpression();
2077 return delegate.markEnd(delegate.createProperty('init', key, value), startToken);
2078 }
2079 }
2080
2081 function parseObjectInitialiser() {
2082 var properties = [], property, name, key, kind, map = {}, toString = String, startToken;
2083
2084 startToken = lookahead;
2085
2086 expect('{');
2087
2088 while (!match('}')) {
2089 property = parseObjectProperty();
2090
2091 if (property.key.type === Syntax.Identifier) {
2092 name = property.key.name;
2093 } else {
2094 name = toString(property.key.value);
2095 }
2096 kind = (property.kind === 'init') ? PropertyKind.Data : (property.kind === 'get') ? PropertyKind.Get : PropertyKind.Set;
2097
2098 key = '$' + name;
2099 if (Object.prototype.hasOwnProperty.call(map, key)) {
2100 if (map[key] === PropertyKind.Data) {
2101 if (strict && kind === PropertyKind.Data) {
2102 throwErrorTolerant({}, Messages.StrictDuplicateProperty);
2103 } else if (kind !== PropertyKind.Data) {
2104 throwErrorTolerant({}, Messages.AccessorDataProperty);
2105 }
2106 } else {
2107 if (kind === PropertyKind.Data) {
2108 throwErrorTolerant({}, Messages.AccessorDataProperty);
2109 } else if (map[key] & kind) {
2110 throwErrorTolerant({}, Messages.AccessorGetSet);
2111 }
2112 }
2113 map[key] |= kind;
2114 } else {
2115 map[key] = kind;
2116 }
2117
2118 properties.push(property);
2119
2120 if (!match('}')) {
2121 expect(',');
2122 }
2123 }
2124
2125 expect('}');
2126
2127 return delegate.markEnd(delegate.createObjectExpression(properties), startToken);
2128 }
2129
2130 // 11.1.6 The Grouping Operator
2131
2132 function parseGroupExpression() {
2133 var expr;
2134
2135 expect('(');
2136
2137 expr = parseExpression();
2138
2139 expect(')');
2140
2141 return expr;
2142 }
2143
2144
2145 // 11.1 Primary Expressions
2146
2147 function parsePrimaryExpression() {
2148 var type, token, expr, startToken;
2149
2150 if (match('(')) {
2151 return parseGroupExpression();
2152 }
2153
2154 if (match('[')) {
2155 return parseArrayInitialiser();
2156 }
2157
2158 if (match('{')) {
2159 return parseObjectInitialiser();
2160 }
2161
2162 type = lookahead.type;
2163 startToken = lookahead;
2164
2165 if (type === Token.Identifier) {
2166 expr = delegate.createIdentifier(lex().value);
2167 } else if (type === Token.StringLiteral || type === Token.NumericLiteral) {
2168 if (strict && lookahead.octal) {
2169 throwErrorTolerant(lookahead, Messages.StrictOctalLiteral);
2170 }
2171 expr = delegate.createLiteral(lex());
2172 } else if (type === Token.Keyword) {
2173 if (matchKeyword('function')) {
2174 return parseFunctionExpression();
2175 }
2176 if (matchKeyword('this')) {
2177 lex();
2178 expr = delegate.createThisExpression();
2179 } else {
2180 throwUnexpected(lex());
2181 }
2182 } else if (type === Token.BooleanLiteral) {
2183 token = lex();
2184 token.value = (token.value === 'true');
2185 expr = delegate.createLiteral(token);
2186 } else if (type === Token.NullLiteral) {
2187 token = lex();
2188 token.value = null;
2189 expr = delegate.createLiteral(token);
2190 } else if (match('/') || match('/=')) {
2191 if (typeof extra.tokens !== 'undefined') {
2192 expr = delegate.createLiteral(collectRegex());
2193 } else {
2194 expr = delegate.createLiteral(scanRegExp());
2195 }
2196 peek();
2197 } else {
2198 throwUnexpected(lex());
2199 }
2200
2201 return delegate.markEnd(expr, startToken);
2202 }
2203
2204 // 11.2 Left-Hand-Side Expressions
2205
2206 function parseArguments() {
2207 var args = [];
2208
2209 expect('(');
2210
2211 if (!match(')')) {
2212 while (index < length) {
2213 args.push(parseAssignmentExpression());
2214 if (match(')')) {
2215 break;
2216 }
2217 expect(',');
2218 }
2219 }
2220
2221 expect(')');
2222
2223 return args;
2224 }
2225
2226 function parseNonComputedProperty() {
2227 var token, startToken;
2228
2229 startToken = lookahead;
2230 token = lex();
2231
2232 if (!isIdentifierName(token)) {
2233 throwUnexpected(token);
2234 }
2235
2236 return delegate.markEnd(delegate.createIdentifier(token.value), startToken);
2237 }
2238
2239 function parseNonComputedMember() {
2240 expect('.');
2241
2242 return parseNonComputedProperty();
2243 }
2244
2245 function parseComputedMember() {
2246 var expr;
2247
2248 expect('[');
2249
2250 expr = parseExpression();
2251
2252 expect(']');
2253
2254 return expr;
2255 }
2256
2257 function parseNewExpression() {
2258 var callee, args, startToken;
2259
2260 startToken = lookahead;
2261 expectKeyword('new');
2262 callee = parseLeftHandSideExpression();
2263 args = match('(') ? parseArguments() : [];
2264
2265 return delegate.markEnd(delegate.createNewExpression(callee, args), startToken);
2266 }
2267
2268 function parseLeftHandSideExpressionAllowCall() {
2269 var previousAllowIn, expr, args, property, startToken;
2270
2271 startToken = lookahead;
2272
2273 previousAllowIn = state.allowIn;
2274 state.allowIn = true;
2275 expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression();
2276 state.allowIn = previousAllowIn;
2277
2278 for (;;) {
2279 if (match('.')) {
2280 property = parseNonComputedMember();
2281 expr = delegate.createMemberExpression('.', expr, property);
2282 } else if (match('(')) {
2283 args = parseArguments();
2284 expr = delegate.createCallExpression(expr, args);
2285 } else if (match('[')) {
2286 property = parseComputedMember();
2287 expr = delegate.createMemberExpression('[', expr, property);
2288 } else {
2289 break;
2290 }
2291 delegate.markEnd(expr, startToken);
2292 }
2293
2294 return expr;
2295 }
2296
2297 function parseLeftHandSideExpression() {
2298 var previousAllowIn, expr, property, startToken;
2299
2300 startToken = lookahead;
2301
2302 previousAllowIn = state.allowIn;
2303 expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression();
2304 state.allowIn = previousAllowIn;
2305
2306 while (match('.') || match('[')) {
2307 if (match('[')) {
2308 property = parseComputedMember();
2309 expr = delegate.createMemberExpression('[', expr, property);
2310 } else {
2311 property = parseNonComputedMember();
2312 expr = delegate.createMemberExpression('.', expr, property);
2313 }
2314 delegate.markEnd(expr, startToken);
2315 }
2316
2317 return expr;
2318 }
2319
2320 // 11.3 Postfix Expressions
2321
2322 function parsePostfixExpression() {
2323 var expr, token, startToken = lookahead;
2324
2325 expr = parseLeftHandSideExpressionAllowCall();
2326
2327 if (lookahead.type === Token.Punctuator) {
2328 if ((match('++') || match('--')) && !peekLineTerminator()) {
2329 // 11.3.1, 11.3.2
2330 if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) {
2331 throwErrorTolerant({}, Messages.StrictLHSPostfix);
2332 }
2333
2334 if (!isLeftHandSide(expr)) {
2335 throwErrorTolerant({}, Messages.InvalidLHSInAssignment);
2336 }
2337
2338 token = lex();
2339 expr = delegate.markEnd(delegate.createPostfixExpression(token.value, expr), startToken);
2340 }
2341 }
2342
2343 return expr;
2344 }
2345
2346 // 11.4 Unary Operators
2347
2348 function parseUnaryExpression() {
2349 var token, expr, startToken;
2350
2351 if (lookahead.type !== Token.Punctuator && lookahead.type !== Token.Keyword) {
2352 expr = parsePostfixExpression();
2353 } else if (match('++') || match('--')) {
2354 startToken = lookahead;
2355 token = lex();
2356 expr = parseUnaryExpression();
2357 // 11.4.4, 11.4.5
2358 if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) {
2359 throwErrorTolerant({}, Messages.StrictLHSPrefix);
2360 }
2361
2362 if (!isLeftHandSide(expr)) {
2363 throwErrorTolerant({}, Messages.InvalidLHSInAssignment);
2364 }
2365
2366 expr = delegate.createUnaryExpression(token.value, expr);
2367 expr = delegate.markEnd(expr, startToken);
2368 } else if (match('+') || match('-') || match('~') || match('!')) {
2369 startToken = lookahead;
2370 token = lex();
2371 expr = parseUnaryExpression();
2372 expr = delegate.createUnaryExpression(token.value, expr);
2373 expr = delegate.markEnd(expr, startToken);
2374 } else if (matchKeyword('delete') || matchKeyword('void') || matchKeyword('typeof')) {
2375 startToken = lookahead;
2376 token = lex();
2377 expr = parseUnaryExpression();
2378 expr = delegate.createUnaryExpression(token.value, expr);
2379 expr = delegate.markEnd(expr, startToken);
2380 if (strict && expr.operator === 'delete' && expr.argument.type === Syntax.Identifier) {
2381 throwErrorTolerant({}, Messages.StrictDelete);
2382 }
2383 } else {
2384 expr = parsePostfixExpression();
2385 }
2386
2387 return expr;
2388 }
2389
2390 function binaryPrecedence(token, allowIn) {
2391 var prec = 0;
2392
2393 if (token.type !== Token.Punctuator && token.type !== Token.Keyword) {
2394 return 0;
2395 }
2396
2397 switch (token.value) {
2398 case '||':
2399 prec = 1;
2400 break;
2401
2402 case '&&':
2403 prec = 2;
2404 break;
2405
2406 case '|':
2407 prec = 3;
2408 break;
2409
2410 case '^':
2411 prec = 4;
2412 break;
2413
2414 case '&':
2415 prec = 5;
2416 break;
2417
2418 case '==':
2419 case '!=':
2420 case '===':
2421 case '!==':
2422 prec = 6;
2423 break;
2424
2425 case '<':
2426 case '>':
2427 case '<=':
2428 case '>=':
2429 case 'instanceof':
2430 prec = 7;
2431 break;
2432
2433 case 'in':
2434 prec = allowIn ? 7 : 0;
2435 break;
2436
2437 case '<<':
2438 case '>>':
2439 case '>>>':
2440 prec = 8;
2441 break;
2442
2443 case '+':
2444 case '-':
2445 prec = 9;
2446 break;
2447
2448 case '*':
2449 case '/':
2450 case '%':
2451 prec = 11;
2452 break;
2453
2454 default:
2455 break;
2456 }
2457
2458 return prec;
2459 }
2460
2461 // 11.5 Multiplicative Operators
2462 // 11.6 Additive Operators
2463 // 11.7 Bitwise Shift Operators
2464 // 11.8 Relational Operators
2465 // 11.9 Equality Operators
2466 // 11.10 Binary Bitwise Operators
2467 // 11.11 Binary Logical Operators
2468
2469 function parseBinaryExpression() {
2470 var marker, markers, expr, token, prec, stack, right, operator, left, i;
2471
2472 marker = lookahead;
2473 left = parseUnaryExpression();
2474
2475 token = lookahead;
2476 prec = binaryPrecedence(token, state.allowIn);
2477 if (prec === 0) {
2478 return left;
2479 }
2480 token.prec = prec;
2481 lex();
2482
2483 markers = [marker, lookahead];
2484 right = parseUnaryExpression();
2485
2486 stack = [left, token, right];
2487
2488 while ((prec = binaryPrecedence(lookahead, state.allowIn)) > 0) {
2489
2490 // Reduce: make a binary expression from the three topmost entries.
2491 while ((stack.length > 2) && (prec <= stack[stack.length - 2].prec)) {
2492 right = stack.pop();
2493 operator = stack.pop().value;
2494 left = stack.pop();
2495 expr = delegate.createBinaryExpression(operator, left, right);
2496 markers.pop();
2497 marker = markers[markers.length - 1];
2498 delegate.markEnd(expr, marker);
2499 stack.push(expr);
2500 }
2501
2502 // Shift.
2503 token = lex();
2504 token.prec = prec;
2505 stack.push(token);
2506 markers.push(lookahead);
2507 expr = parseUnaryExpression();
2508 stack.push(expr);
2509 }
2510
2511 // Final reduce to clean-up the stack.
2512 i = stack.length - 1;
2513 expr = stack[i];
2514 markers.pop();
2515 while (i > 1) {
2516 expr = delegate.createBinaryExpression(stack[i - 1].value, stack[i - 2], expr);
2517 i -= 2;
2518 marker = markers.pop();
2519 delegate.markEnd(expr, marker);
2520 }
2521
2522 return expr;
2523 }
2524
2525
2526 // 11.12 Conditional Operator
2527
2528 function parseConditionalExpression() {
2529 var expr, previousAllowIn, consequent, alternate, startToken;
2530
2531 startToken = lookahead;
2532
2533 expr = parseBinaryExpression();
2534
2535 if (match('?')) {
2536 lex();
2537 previousAllowIn = state.allowIn;
2538 state.allowIn = true;
2539 consequent = parseAssignmentExpression();
2540 state.allowIn = previousAllowIn;
2541 expect(':');
2542 alternate = parseAssignmentExpression();
2543
2544 expr = delegate.createConditionalExpression(expr, consequent, alternate);
2545 delegate.markEnd(expr, startToken);
2546 }
2547
2548 return expr;
2549 }
2550
2551 // 11.13 Assignment Operators
2552
2553 function parseAssignmentExpression() {
2554 var token, left, right, node, startToken;
2555
2556 token = lookahead;
2557 startToken = lookahead;
2558
2559 node = left = parseConditionalExpression();
2560
2561 if (matchAssign()) {
2562 // LeftHandSideExpression
2563 if (!isLeftHandSide(left)) {
2564 throwErrorTolerant({}, Messages.InvalidLHSInAssignment);
2565 }
2566
2567 // 11.13.1
2568 if (strict && left.type === Syntax.Identifier && isRestrictedWord(left.name)) {
2569 throwErrorTolerant(token, Messages.StrictLHSAssignment);
2570 }
2571
2572 token = lex();
2573 right = parseAssignmentExpression();
2574 node = delegate.markEnd(delegate.createAssignmentExpression(token.value, left, right), startToken);
2575 }
2576
2577 return node;
2578 }
2579
2580 // 11.14 Comma Operator
2581
2582 function parseExpression() {
2583 var expr, startToken = lookahead;
2584
2585 expr = parseAssignmentExpression();
2586
2587 if (match(',')) {
2588 expr = delegate.createSequenceExpression([ expr ]);
2589
2590 while (index < length) {
2591 if (!match(',')) {
2592 break;
2593 }
2594 lex();
2595 expr.expressions.push(parseAssignmentExpression());
2596 }
2597
2598 delegate.markEnd(expr, startToken);
2599 }
2600
2601 return expr;
2602 }
2603
2604 // 12.1 Block
2605
2606 function parseStatementList() {
2607 var list = [],
2608 statement;
2609
2610 while (index < length) {
2611 if (match('}')) {
2612 break;
2613 }
2614 statement = parseSourceElement();
2615 if (typeof statement === 'undefined') {
2616 break;
2617 }
2618 list.push(statement);
2619 }
2620
2621 return list;
2622 }
2623
2624 function parseBlock() {
2625 var block, startToken;
2626
2627 startToken = lookahead;
2628 expect('{');
2629
2630 block = parseStatementList();
2631
2632 expect('}');
2633
2634 return delegate.markEnd(delegate.createBlockStatement(block), startToken);
2635 }
2636
2637 // 12.2 Variable Statement
2638
2639 function parseVariableIdentifier() {
2640 var token, startToken;
2641
2642 startToken = lookahead;
2643 token = lex();
2644
2645 if (token.type !== Token.Identifier) {
2646 throwUnexpected(token);
2647 }
2648
2649 return delegate.markEnd(delegate.createIdentifier(token.value), startToken);
2650 }
2651
2652 function parseVariableDeclaration(kind) {
2653 var init = null, id, startToken;
2654
2655 startToken = lookahead;
2656 id = parseVariableIdentifier();
2657
2658 // 12.2.1
2659 if (strict && isRestrictedWord(id.name)) {
2660 throwErrorTolerant({}, Messages.StrictVarName);
2661 }
2662
2663 if (kind === 'const') {
2664 expect('=');
2665 init = parseAssignmentExpression();
2666 } else if (match('=')) {
2667 lex();
2668 init = parseAssignmentExpression();
2669 }
2670
2671 return delegate.markEnd(delegate.createVariableDeclarator(id, init), startToken);
2672 }
2673
2674 function parseVariableDeclarationList(kind) {
2675 var list = [];
2676
2677 do {
2678 list.push(parseVariableDeclaration(kind));
2679 if (!match(',')) {
2680 break;
2681 }
2682 lex();
2683 } while (index < length);
2684
2685 return list;
2686 }
2687
2688 function parseVariableStatement() {
2689 var declarations;
2690
2691 expectKeyword('var');
2692
2693 declarations = parseVariableDeclarationList();
2694
2695 consumeSemicolon();
2696
2697 return delegate.createVariableDeclaration(declarations, 'var');
2698 }
2699
2700 // kind may be `const` or `let`
2701 // Both are experimental and not in the specification yet.
2702 // see http://wiki.ecmascript.org/doku.php?id=harmony:const
2703 // and http://wiki.ecmascript.org/doku.php?id=harmony:let
2704 function parseConstLetDeclaration(kind) {
2705 var declarations, startToken;
2706
2707 startToken = lookahead;
2708
2709 expectKeyword(kind);
2710
2711 declarations = parseVariableDeclarationList(kind);
2712
2713 consumeSemicolon();
2714
2715 return delegate.markEnd(delegate.createVariableDeclaration(declarations, kind), startToken);
2716 }
2717
2718 // 12.3 Empty Statement
2719
2720 function parseEmptyStatement() {
2721 expect(';');
2722 return delegate.createEmptyStatement();
2723 }
2724
2725 // 12.4 Expression Statement
2726
2727 function parseExpressionStatement() {
2728 var expr = parseExpression();
2729 consumeSemicolon();
2730 return delegate.createExpressionStatement(expr);
2731 }
2732
2733 // 12.5 If statement
2734
2735 function parseIfStatement() {
2736 var test, consequent, alternate;
2737
2738 expectKeyword('if');
2739
2740 expect('(');
2741
2742 test = parseExpression();
2743
2744 expect(')');
2745
2746 consequent = parseStatement();
2747
2748 if (matchKeyword('else')) {
2749 lex();
2750 alternate = parseStatement();
2751 } else {
2752 alternate = null;
2753 }
2754
2755 return delegate.createIfStatement(test, consequent, alternate);
2756 }
2757
2758 // 12.6 Iteration Statements
2759
2760 function parseDoWhileStatement() {
2761 var body, test, oldInIteration;
2762
2763 expectKeyword('do');
2764
2765 oldInIteration = state.inIteration;
2766 state.inIteration = true;
2767
2768 body = parseStatement();
2769
2770 state.inIteration = oldInIteration;
2771
2772 expectKeyword('while');
2773
2774 expect('(');
2775
2776 test = parseExpression();
2777
2778 expect(')');
2779
2780 if (match(';')) {
2781 lex();
2782 }
2783
2784 return delegate.createDoWhileStatement(body, test);
2785 }
2786
2787 function parseWhileStatement() {
2788 var test, body, oldInIteration;
2789
2790 expectKeyword('while');
2791
2792 expect('(');
2793
2794 test = parseExpression();
2795
2796 expect(')');
2797
2798 oldInIteration = state.inIteration;
2799 state.inIteration = true;
2800
2801 body = parseStatement();
2802
2803 state.inIteration = oldInIteration;
2804
2805 return delegate.createWhileStatement(test, body);
2806 }
2807
2808 function parseForVariableDeclaration() {
2809 var token, declarations, startToken;
2810
2811 startToken = lookahead;
2812 token = lex();
2813 declarations = parseVariableDeclarationList();
2814
2815 return delegate.markEnd(delegate.createVariableDeclaration(declarations, token.value), startToken);
2816 }
2817
2818 function parseForStatement() {
2819 var init, test, update, left, right, body, oldInIteration;
2820
2821 init = test = update = null;
2822
2823 expectKeyword('for');
2824
2825 expect('(');
2826
2827 if (match(';')) {
2828 lex();
2829 } else {
2830 if (matchKeyword('var') || matchKeyword('let')) {
2831 state.allowIn = false;
2832 init = parseForVariableDeclaration();
2833 state.allowIn = true;
2834
2835 if (init.declarations.length === 1 && matchKeyword('in')) {
2836 lex();
2837 left = init;
2838 right = parseExpression();
2839 init = null;
2840 }
2841 } else {
2842 state.allowIn = false;
2843 init = parseExpression();
2844 state.allowIn = true;
2845
2846 if (matchKeyword('in')) {
2847 // LeftHandSideExpression
2848 if (!isLeftHandSide(init)) {
2849 throwErrorTolerant({}, Messages.InvalidLHSInForIn);
2850 }
2851
2852 lex();
2853 left = init;
2854 right = parseExpression();
2855 init = null;
2856 }
2857 }
2858
2859 if (typeof left === 'undefined') {
2860 expect(';');
2861 }
2862 }
2863
2864 if (typeof left === 'undefined') {
2865
2866 if (!match(';')) {
2867 test = parseExpression();
2868 }
2869 expect(';');
2870
2871 if (!match(')')) {
2872 update = parseExpression();
2873 }
2874 }
2875
2876 expect(')');
2877
2878 oldInIteration = state.inIteration;
2879 state.inIteration = true;
2880
2881 body = parseStatement();
2882
2883 state.inIteration = oldInIteration;
2884
2885 return (typeof left === 'undefined') ?
2886 delegate.createForStatement(init, test, update, body) :
2887 delegate.createForInStatement(left, right, body);
2888 }
2889
2890 // 12.7 The continue statement
2891
2892 function parseContinueStatement() {
2893 var label = null, key;
2894
2895 expectKeyword('continue');
2896
2897 // Optimize the most common form: 'continue;'.
2898 if (source.charCodeAt(index) === 0x3B) {
2899 lex();
2900
2901 if (!state.inIteration) {
2902 throwError({}, Messages.IllegalContinue);
2903 }
2904
2905 return delegate.createContinueStatement(null);
2906 }
2907
2908 if (peekLineTerminator()) {
2909 if (!state.inIteration) {
2910 throwError({}, Messages.IllegalContinue);
2911 }
2912
2913 return delegate.createContinueStatement(null);
2914 }
2915
2916 if (lookahead.type === Token.Identifier) {
2917 label = parseVariableIdentifier();
2918
2919 key = '$' + label.name;
2920 if (!Object.prototype.hasOwnProperty.call(state.labelSet, key)) {
2921 throwError({}, Messages.UnknownLabel, label.name);
2922 }
2923 }
2924
2925 consumeSemicolon();
2926
2927 if (label === null && !state.inIteration) {
2928 throwError({}, Messages.IllegalContinue);
2929 }
2930
2931 return delegate.createContinueStatement(label);
2932 }
2933
2934 // 12.8 The break statement
2935
2936 function parseBreakStatement() {
2937 var label = null, key;
2938
2939 expectKeyword('break');
2940
2941 // Catch the very common case first: immediately a semicolon (U+003B).
2942 if (source.charCodeAt(index) === 0x3B) {
2943 lex();
2944
2945 if (!(state.inIteration || state.inSwitch)) {
2946 throwError({}, Messages.IllegalBreak);
2947 }
2948
2949 return delegate.createBreakStatement(null);
2950 }
2951
2952 if (peekLineTerminator()) {
2953 if (!(state.inIteration || state.inSwitch)) {
2954 throwError({}, Messages.IllegalBreak);
2955 }
2956
2957 return delegate.createBreakStatement(null);
2958 }
2959
2960 if (lookahead.type === Token.Identifier) {
2961 label = parseVariableIdentifier();
2962
2963 key = '$' + label.name;
2964 if (!Object.prototype.hasOwnProperty.call(state.labelSet, key)) {
2965 throwError({}, Messages.UnknownLabel, label.name);
2966 }
2967 }
2968
2969 consumeSemicolon();
2970
2971 if (label === null && !(state.inIteration || state.inSwitch)) {
2972 throwError({}, Messages.IllegalBreak);
2973 }
2974
2975 return delegate.createBreakStatement(label);
2976 }
2977
2978 // 12.9 The return statement
2979
2980 function parseReturnStatement() {
2981 var argument = null;
2982
2983 expectKeyword('return');
2984
2985 if (!state.inFunctionBody) {
2986 throwErrorTolerant({}, Messages.IllegalReturn);
2987 }
2988
2989 // 'return' followed by a space and an identifier is very common.
2990 if (source.charCodeAt(index) === 0x20) {
2991 if (isIdentifierStart(source.charCodeAt(index + 1))) {
2992 argument = parseExpression();
2993 consumeSemicolon();
2994 return delegate.createReturnStatement(argument);
2995 }
2996 }
2997
2998 if (peekLineTerminator()) {
2999 return delegate.createReturnStatement(null);
3000 }
3001
3002 if (!match(';')) {
3003 if (!match('}') && lookahead.type !== Token.EOF) {
3004 argument = parseExpression();
3005 }
3006 }
3007
3008 consumeSemicolon();
3009
3010 return delegate.createReturnStatement(argument);
3011 }
3012
3013 // 12.10 The with statement
3014
3015 function parseWithStatement() {
3016 var object, body;
3017
3018 if (strict) {
3019 // TODO(ikarienator): Should we update the test cases instead?
3020 skipComment();
3021 throwErrorTolerant({}, Messages.StrictModeWith);
3022 }
3023
3024 expectKeyword('with');
3025
3026 expect('(');
3027
3028 object = parseExpression();
3029
3030 expect(')');
3031
3032 body = parseStatement();
3033
3034 return delegate.createWithStatement(object, body);
3035 }
3036
3037 // 12.10 The swith statement
3038
3039 function parseSwitchCase() {
3040 var test, consequent = [], statement, startToken;
3041
3042 startToken = lookahead;
3043 if (matchKeyword('default')) {
3044 lex();
3045 test = null;
3046 } else {
3047 expectKeyword('case');
3048 test = parseExpression();
3049 }
3050 expect(':');
3051
3052 while (index < length) {
3053 if (match('}') || matchKeyword('default') || matchKeyword('case')) {
3054 break;
3055 }
3056 statement = parseStatement();
3057 consequent.push(statement);
3058 }
3059
3060 return delegate.markEnd(delegate.createSwitchCase(test, consequent), startToken);
3061 }
3062
3063 function parseSwitchStatement() {
3064 var discriminant, cases, clause, oldInSwitch, defaultFound;
3065
3066 expectKeyword('switch');
3067
3068 expect('(');
3069
3070 discriminant = parseExpression();
3071
3072 expect(')');
3073
3074 expect('{');
3075
3076 cases = [];
3077
3078 if (match('}')) {
3079 lex();
3080 return delegate.createSwitchStatement(discriminant, cases);
3081 }
3082
3083 oldInSwitch = state.inSwitch;
3084 state.inSwitch = true;
3085 defaultFound = false;
3086
3087 while (index < length) {
3088 if (match('}')) {
3089 break;
3090 }
3091 clause = parseSwitchCase();
3092 if (clause.test === null) {
3093 if (defaultFound) {
3094 throwError({}, Messages.MultipleDefaultsInSwitch);
3095 }
3096 defaultFound = true;
3097 }
3098 cases.push(clause);
3099 }
3100
3101 state.inSwitch = oldInSwitch;
3102
3103 expect('}');
3104
3105 return delegate.createSwitchStatement(discriminant, cases);
3106 }
3107
3108 // 12.13 The throw statement
3109
3110 function parseThrowStatement() {
3111 var argument;
3112
3113 expectKeyword('throw');
3114
3115 if (peekLineTerminator()) {
3116 throwError({}, Messages.NewlineAfterThrow);
3117 }
3118
3119 argument = parseExpression();
3120
3121 consumeSemicolon();
3122
3123 return delegate.createThrowStatement(argument);
3124 }
3125
3126 // 12.14 The try statement
3127
3128 function parseCatchClause() {
3129 var param, body, startToken;
3130
3131 startToken = lookahead;
3132 expectKeyword('catch');
3133
3134 expect('(');
3135 if (match(')')) {
3136 throwUnexpected(lookahead);
3137 }
3138
3139 param = parseVariableIdentifier();
3140 // 12.14.1
3141 if (strict && isRestrictedWord(param.name)) {
3142 throwErrorTolerant({}, Messages.StrictCatchVariable);
3143 }
3144
3145 expect(')');
3146 body = parseBlock();
3147 return delegate.markEnd(delegate.createCatchClause(param, body), startToken);
3148 }
3149
3150 function parseTryStatement() {
3151 var block, handlers = [], finalizer = null;
3152
3153 expectKeyword('try');
3154
3155 block = parseBlock();
3156
3157 if (matchKeyword('catch')) {
3158 handlers.push(parseCatchClause());
3159 }
3160
3161 if (matchKeyword('finally')) {
3162 lex();
3163 finalizer = parseBlock();
3164 }
3165
3166 if (handlers.length === 0 && !finalizer) {
3167 throwError({}, Messages.NoCatchOrFinally);
3168 }
3169
3170 return delegate.createTryStatement(block, [], handlers, finalizer);
3171 }
3172
3173 // 12.15 The debugger statement
3174
3175 function parseDebuggerStatement() {
3176 expectKeyword('debugger');
3177
3178 consumeSemicolon();
3179
3180 return delegate.createDebuggerStatement();
3181 }
3182
3183 // 12 Statements
3184
3185 function parseStatement() {
3186 var type = lookahead.type,
3187 expr,
3188 labeledBody,
3189 key,
3190 startToken;
3191
3192 if (type === Token.EOF) {
3193 throwUnexpected(lookahead);
3194 }
3195
3196 if (type === Token.Punctuator && lookahead.value === '{') {
3197 return parseBlock();
3198 }
3199
3200 startToken = lookahead;
3201
3202 if (type === Token.Punctuator) {
3203 switch (lookahead.value) {
3204 case ';':
3205 return delegate.markEnd(parseEmptyStatement(), startToken);
3206 case '(':
3207 return delegate.markEnd(parseExpressionStatement(), startToken);
3208 default:
3209 break;
3210 }
3211 }
3212
3213 if (type === Token.Keyword) {
3214 switch (lookahead.value) {
3215 case 'break':
3216 return delegate.markEnd(parseBreakStatement(), startToken);
3217 case 'continue':
3218 return delegate.markEnd(parseContinueStatement(), startToken);
3219 case 'debugger':
3220 return delegate.markEnd(parseDebuggerStatement(), startToken);
3221 case 'do':
3222 return delegate.markEnd(parseDoWhileStatement(), startToken);
3223 case 'for':
3224 return delegate.markEnd(parseForStatement(), startToken);
3225 case 'function':
3226 return delegate.markEnd(parseFunctionDeclaration(), startToken);
3227 case 'if':
3228 return delegate.markEnd(parseIfStatement(), startToken);
3229 case 'return':
3230 return delegate.markEnd(parseReturnStatement(), startToken);
3231 case 'switch':
3232 return delegate.markEnd(parseSwitchStatement(), startToken);
3233 case 'throw':
3234 return delegate.markEnd(parseThrowStatement(), startToken);
3235 case 'try':
3236 return delegate.markEnd(parseTryStatement(), startToken);
3237 case 'var':
3238 return delegate.markEnd(parseVariableStatement(), startToken);
3239 case 'while':
3240 return delegate.markEnd(parseWhileStatement(), startToken);
3241 case 'with':
3242 return delegate.markEnd(parseWithStatement(), startToken);
3243 default:
3244 break;
3245 }
3246 }
3247
3248 expr = parseExpression();
3249
3250 // 12.12 Labelled Statements
3251 if ((expr.type === Syntax.Identifier) && match(':')) {
3252 lex();
3253
3254 key = '$' + expr.name;
3255 if (Object.prototype.hasOwnProperty.call(state.labelSet, key)) {
3256 throwError({}, Messages.Redeclaration, 'Label', expr.name);
3257 }
3258
3259 state.labelSet[key] = true;
3260 labeledBody = parseStatement();
3261 delete state.labelSet[key];
3262 return delegate.markEnd(delegate.createLabeledStatement(expr, labeledBody), startToken);
3263 }
3264
3265 consumeSemicolon();
3266
3267 return delegate.markEnd(delegate.createExpressionStatement(expr), startToken);
3268 }
3269
3270 // 13 Function Definition
3271
3272 function parseFunctionSourceElements() {
3273 var sourceElement, sourceElements = [], token, directive, firstRestricted,
3274 oldLabelSet, oldInIteration, oldInSwitch, oldInFunctionBody, startToken;
3275
3276 startToken = lookahead;
3277 expect('{');
3278
3279 while (index < length) {
3280 if (lookahead.type !== Token.StringLiteral) {
3281 break;
3282 }
3283 token = lookahead;
3284
3285 sourceElement = parseSourceElement();
3286 sourceElements.push(sourceElement);
3287 if (sourceElement.expression.type !== Syntax.Literal) {
3288 // this is not directive
3289 break;
3290 }
3291 directive = source.slice(token.start + 1, token.end - 1);
3292 if (directive === 'use strict') {
3293 strict = true;
3294 if (firstRestricted) {
3295 throwErrorTolerant(firstRestricted, Messages.StrictOctalLiteral);
3296 }
3297 } else {
3298 if (!firstRestricted && token.octal) {
3299 firstRestricted = token;
3300 }
3301 }
3302 }
3303
3304 oldLabelSet = state.labelSet;
3305 oldInIteration = state.inIteration;
3306 oldInSwitch = state.inSwitch;
3307 oldInFunctionBody = state.inFunctionBody;
3308
3309 state.labelSet = {};
3310 state.inIteration = false;
3311 state.inSwitch = false;
3312 state.inFunctionBody = true;
3313
3314 while (index < length) {
3315 if (match('}')) {
3316 break;
3317 }
3318 sourceElement = parseSourceElement();
3319 if (typeof sourceElement === 'undefined') {
3320 break;
3321 }
3322 sourceElements.push(sourceElement);
3323 }
3324
3325 expect('}');
3326
3327 state.labelSet = oldLabelSet;
3328 state.inIteration = oldInIteration;
3329 state.inSwitch = oldInSwitch;
3330 state.inFunctionBody = oldInFunctionBody;
3331
3332 return delegate.markEnd(delegate.createBlockStatement(sourceElements), startToken);
3333 }
3334
3335 function parseParams(firstRestricted) {
3336 var param, params = [], token, stricted, paramSet, key, message;
3337 expect('(');
3338
3339 if (!match(')')) {
3340 paramSet = {};
3341 while (index < length) {
3342 token = lookahead;
3343 param = parseVariableIdentifier();
3344 key = '$' + token.value;
3345 if (strict) {
3346 if (isRestrictedWord(token.value)) {
3347 stricted = token;
3348 message = Messages.StrictParamName;
3349 }
3350 if (Object.prototype.hasOwnProperty.call(paramSet, key)) {
3351 stricted = token;
3352 message = Messages.StrictParamDupe;
3353 }
3354 } else if (!firstRestricted) {
3355 if (isRestrictedWord(token.value)) {
3356 firstRestricted = token;
3357 message = Messages.StrictParamName;
3358 } else if (isStrictModeReservedWord(token.value)) {
3359 firstRestricted = token;
3360 message = Messages.StrictReservedWord;
3361 } else if (Object.prototype.hasOwnProperty.call(paramSet, key)) {
3362 firstRestricted = token;
3363 message = Messages.StrictParamDupe;
3364 }
3365 }
3366 params.push(param);
3367 paramSet[key] = true;
3368 if (match(')')) {
3369 break;
3370 }
3371 expect(',');
3372 }
3373 }
3374
3375 expect(')');
3376
3377 return {
3378 params: params,
3379 stricted: stricted,
3380 firstRestricted: firstRestricted,
3381 message: message
3382 };
3383 }
3384
3385 function parseFunctionDeclaration() {
3386 var id, params = [], body, token, stricted, tmp, firstRestricted, message, previousStrict, startToken;
3387
3388 startToken = lookahead;
3389
3390 expectKeyword('function');
3391 token = lookahead;
3392 id = parseVariableIdentifier();
3393 if (strict) {
3394 if (isRestrictedWord(token.value)) {
3395 throwErrorTolerant(token, Messages.StrictFunctionName);
3396 }
3397 } else {
3398 if (isRestrictedWord(token.value)) {
3399 firstRestricted = token;
3400 message = Messages.StrictFunctionName;
3401 } else if (isStrictModeReservedWord(token.value)) {
3402 firstRestricted = token;
3403 message = Messages.StrictReservedWord;
3404 }
3405 }
3406
3407 tmp = parseParams(firstRestricted);
3408 params = tmp.params;
3409 stricted = tmp.stricted;
3410 firstRestricted = tmp.firstRestricted;
3411 if (tmp.message) {
3412 message = tmp.message;
3413 }
3414
3415 previousStrict = strict;
3416 body = parseFunctionSourceElements();
3417 if (strict && firstRestricted) {
3418 throwError(firstRestricted, message);
3419 }
3420 if (strict && stricted) {
3421 throwErrorTolerant(stricted, message);
3422 }
3423 strict = previousStrict;
3424
3425 return delegate.markEnd(delegate.createFunctionDeclaration(id, params, [], body), startToken);
3426 }
3427
3428 function parseFunctionExpression() {
3429 var token, id = null, stricted, firstRestricted, message, tmp, params = [], body, previousStrict, startToken;
3430
3431 startToken = lookahead;
3432 expectKeyword('function');
3433
3434 if (!match('(')) {
3435 token = lookahead;
3436 id = parseVariableIdentifier();
3437 if (strict) {
3438 if (isRestrictedWord(token.value)) {
3439 throwErrorTolerant(token, Messages.StrictFunctionName);
3440 }
3441 } else {
3442 if (isRestrictedWord(token.value)) {
3443 firstRestricted = token;
3444 message = Messages.StrictFunctionName;
3445 } else if (isStrictModeReservedWord(token.value)) {
3446 firstRestricted = token;
3447 message = Messages.StrictReservedWord;
3448 }
3449 }
3450 }
3451
3452 tmp = parseParams(firstRestricted);
3453 params = tmp.params;
3454 stricted = tmp.stricted;
3455 firstRestricted = tmp.firstRestricted;
3456 if (tmp.message) {
3457 message = tmp.message;
3458 }
3459
3460 previousStrict = strict;
3461 body = parseFunctionSourceElements();
3462 if (strict && firstRestricted) {
3463 throwError(firstRestricted, message);
3464 }
3465 if (strict && stricted) {
3466 throwErrorTolerant(stricted, message);
3467 }
3468 strict = previousStrict;
3469
3470 return delegate.markEnd(delegate.createFunctionExpression(id, params, [], body), startToken);
3471 }
3472
3473 // 14 Program
3474
3475 function parseSourceElement() {
3476 if (lookahead.type === Token.Keyword) {
3477 switch (lookahead.value) {
3478 case 'const':
3479 case 'let':
3480 return parseConstLetDeclaration(lookahead.value);
3481 case 'function':
3482 return parseFunctionDeclaration();
3483 default:
3484 return parseStatement();
3485 }
3486 }
3487
3488 if (lookahead.type !== Token.EOF) {
3489 return parseStatement();
3490 }
3491 }
3492
3493 function parseSourceElements() {
3494 var sourceElement, sourceElements = [], token, directive, firstRestricted;
3495
3496 while (index < length) {
3497 token = lookahead;
3498 if (token.type !== Token.StringLiteral) {
3499 break;
3500 }
3501
3502 sourceElement = parseSourceElement();
3503 sourceElements.push(sourceElement);
3504 if (sourceElement.expression.type !== Syntax.Literal) {
3505 // this is not directive
3506 break;
3507 }
3508 directive = source.slice(token.start + 1, token.end - 1);
3509 if (directive === 'use strict') {
3510 strict = true;
3511 if (firstRestricted) {
3512 throwErrorTolerant(firstRestricted, Messages.StrictOctalLiteral);
3513 }
3514 } else {
3515 if (!firstRestricted && token.octal) {
3516 firstRestricted = token;
3517 }
3518 }
3519 }
3520
3521 while (index < length) {
3522 sourceElement = parseSourceElement();
3523 /* istanbul ignore if */
3524 if (typeof sourceElement === 'undefined') {
3525 break;
3526 }
3527 sourceElements.push(sourceElement);
3528 }
3529 return sourceElements;
3530 }
3531
3532 function parseProgram() {
3533 var body, startToken;
3534
3535 skipComment();
3536 peek();
3537 startToken = lookahead;
3538 strict = false;
3539
3540 body = parseSourceElements();
3541 return delegate.markEnd(delegate.createProgram(body), startToken);
3542 }
3543
3544 function filterTokenLocation() {
3545 var i, entry, token, tokens = [];
3546
3547 for (i = 0; i < extra.tokens.length; ++i) {
3548 entry = extra.tokens[i];
3549 token = {
3550 type: entry.type,
3551 value: entry.value
3552 };
3553 if (extra.range) {
3554 token.range = entry.range;
3555 }
3556 if (extra.loc) {
3557 token.loc = entry.loc;
3558 }
3559 tokens.push(token);
3560 }
3561
3562 extra.tokens = tokens;
3563 }
3564
3565 function tokenize(code, options) {
3566 var toString,
3567 token,
3568 tokens;
3569
3570 toString = String;
3571 if (typeof code !== 'string' && !(code instanceof String)) {
3572 code = toString(code);
3573 }
3574
3575 delegate = SyntaxTreeDelegate;
3576 source = code;
3577 index = 0;
3578 lineNumber = (source.length > 0) ? 1 : 0;
3579 lineStart = 0;
3580 length = source.length;
3581 lookahead = null;
3582 state = {
3583 allowIn: true,
3584 labelSet: {},
3585 inFunctionBody: false,
3586 inIteration: false,
3587 inSwitch: false,
3588 lastCommentStart: -1
3589 };
3590
3591 extra = {};
3592
3593 // Options matching.
3594 options = options || {};
3595
3596 // Of course we collect tokens here.
3597 options.tokens = true;
3598 extra.tokens = [];
3599 extra.tokenize = true;
3600 // The following two fields are necessary to compute the Regex tokens.
3601 extra.openParenToken = -1;
3602 extra.openCurlyToken = -1;
3603
3604 extra.range = (typeof options.range === 'boolean') && options.range;
3605 extra.loc = (typeof options.loc === 'boolean') && options.loc;
3606
3607 if (typeof options.comment === 'boolean' && options.comment) {
3608 extra.comments = [];
3609 }
3610 if (typeof options.tolerant === 'boolean' && options.tolerant) {
3611 extra.errors = [];
3612 }
3613
3614 try {
3615 peek();
3616 if (lookahead.type === Token.EOF) {
3617 return extra.tokens;
3618 }
3619
3620 token = lex();
3621 while (lookahead.type !== Token.EOF) {
3622 try {
3623 token = lex();
3624 } catch (lexError) {
3625 token = lookahead;
3626 if (extra.errors) {
3627 extra.errors.push(lexError);
3628 // We have to break on the first error
3629 // to avoid infinite loops.
3630 break;
3631 } else {
3632 throw lexError;
3633 }
3634 }
3635 }
3636
3637 filterTokenLocation();
3638 tokens = extra.tokens;
3639 if (typeof extra.comments !== 'undefined') {
3640 tokens.comments = extra.comments;
3641 }
3642 if (typeof extra.errors !== 'undefined') {
3643 tokens.errors = extra.errors;
3644 }
3645 } catch (e) {
3646 throw e;
3647 } finally {
3648 extra = {};
3649 }
3650 return tokens;
3651 }
3652
3653 function parse(code, options) {
3654 var program, toString;
3655
3656 toString = String;
3657 if (typeof code !== 'string' && !(code instanceof String)) {
3658 code = toString(code);
3659 }
3660
3661 delegate = SyntaxTreeDelegate;
3662 source = code;
3663 index = 0;
3664 lineNumber = (source.length > 0) ? 1 : 0;
3665 lineStart = 0;
3666 length = source.length;
3667 lookahead = null;
3668 state = {
3669 allowIn: true,
3670 labelSet: {},
3671 inFunctionBody: false,
3672 inIteration: false,
3673 inSwitch: false,
3674 lastCommentStart: -1
3675 };
3676
3677 extra = {};
3678 if (typeof options !== 'undefined') {
3679 extra.range = (typeof options.range === 'boolean') && options.range;
3680 extra.loc = (typeof options.loc === 'boolean') && options.loc;
3681 extra.attachComment = (typeof options.attachComment === 'boolean') && options.attachComment;
3682
3683 if (extra.loc && options.source !== null && options.source !== undefined) {
3684 extra.source = toString(options.source);
3685 }
3686
3687 if (typeof options.tokens === 'boolean' && options.tokens) {
3688 extra.tokens = [];
3689 }
3690 if (typeof options.comment === 'boolean' && options.comment) {
3691 extra.comments = [];
3692 }
3693 if (typeof options.tolerant === 'boolean' && options.tolerant) {
3694 extra.errors = [];
3695 }
3696 if (extra.attachComment) {
3697 extra.range = true;
3698 extra.comments = [];
3699 extra.bottomRightStack = [];
3700 extra.trailingComments = [];
3701 extra.leadingComments = [];
3702 }
3703 }
3704
3705 try {
3706 program = parseProgram();
3707 if (typeof extra.comments !== 'undefined') {
3708 program.comments = extra.comments;
3709 }
3710 if (typeof extra.tokens !== 'undefined') {
3711 filterTokenLocation();
3712 program.tokens = extra.tokens;
3713 }
3714 if (typeof extra.errors !== 'undefined') {
3715 program.errors = extra.errors;
3716 }
3717 } catch (e) {
3718 throw e;
3719 } finally {
3720 extra = {};
3721 }
3722
3723 return program;
3724 }
3725
3726 // Sync with *.json manifests.
3727 exports.version = '1.2.2';
3728
3729 exports.tokenize = tokenize;
3730
3731 exports.parse = parse;
3732
3733 // Deep copy.
3734 /* istanbul ignore next */
3735 exports.Syntax = (function () {
3736 var name, types = {};
3737
3738 if (typeof Object.create === 'function') {
3739 types = Object.create(null);
3740 }
3741
3742 for (name in Syntax) {
3743 if (Syntax.hasOwnProperty(name)) {
3744 types[name] = Syntax[name];
3745 }
3746 }
3747
3748 if (typeof Object.freeze === 'function') {
3749 Object.freeze(types);
3750 }
3751
3752 return types;
3753 }());
3754
3755 }));
3756 /* vim: set sw=4 ts=4 et tw=80 : */