Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
80681 views
1
/*
2
Copyright (C) 2013 Ariya Hidayat <[email protected]>
3
Copyright (C) 2013 Thaddee Tyl <[email protected]>
4
Copyright (C) 2013 Mathias Bynens <[email protected]>
5
Copyright (C) 2012 Ariya Hidayat <[email protected]>
6
Copyright (C) 2012 Mathias Bynens <[email protected]>
7
Copyright (C) 2012 Joost-Wim Boekesteijn <[email protected]>
8
Copyright (C) 2012 Kris Kowal <[email protected]>
9
Copyright (C) 2012 Yusuke Suzuki <[email protected]>
10
Copyright (C) 2012 Arpad Borsos <[email protected]>
11
Copyright (C) 2011 Ariya Hidayat <[email protected]>
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
(function (root, factory) {
35
'use strict';
36
37
// Universal Module Definition (UMD) to support AMD, CommonJS/Node.js,
38
// Rhino, and plain browser loading.
39
40
/* istanbul ignore next */
41
if (typeof define === 'function' && define.amd) {
42
define(['exports'], factory);
43
} else if (typeof exports !== 'undefined') {
44
factory(exports);
45
} else {
46
factory((root.esprima = {}));
47
}
48
}(this, function (exports) {
49
'use strict';
50
51
var Token,
52
TokenName,
53
FnExprTokens,
54
Syntax,
55
PlaceHolders,
56
Messages,
57
Regex,
58
source,
59
strict,
60
index,
61
lineNumber,
62
lineStart,
63
hasLineTerminator,
64
lastIndex,
65
lastLineNumber,
66
lastLineStart,
67
startIndex,
68
startLineNumber,
69
startLineStart,
70
scanning,
71
length,
72
lookahead,
73
state,
74
extra;
75
76
Token = {
77
BooleanLiteral: 1,
78
EOF: 2,
79
Identifier: 3,
80
Keyword: 4,
81
NullLiteral: 5,
82
NumericLiteral: 6,
83
Punctuator: 7,
84
StringLiteral: 8,
85
RegularExpression: 9
86
};
87
88
TokenName = {};
89
TokenName[Token.BooleanLiteral] = 'Boolean';
90
TokenName[Token.EOF] = '<end>';
91
TokenName[Token.Identifier] = 'Identifier';
92
TokenName[Token.Keyword] = 'Keyword';
93
TokenName[Token.NullLiteral] = 'Null';
94
TokenName[Token.NumericLiteral] = 'Numeric';
95
TokenName[Token.Punctuator] = 'Punctuator';
96
TokenName[Token.StringLiteral] = 'String';
97
TokenName[Token.RegularExpression] = 'RegularExpression';
98
99
// A function following one of those tokens is an expression.
100
FnExprTokens = ['(', '{', '[', 'in', 'typeof', 'instanceof', 'new',
101
'return', 'case', 'delete', 'throw', 'void',
102
// assignment operators
103
'=', '+=', '-=', '*=', '/=', '%=', '<<=', '>>=', '>>>=',
104
'&=', '|=', '^=', ',',
105
// binary/unary operators
106
'+', '-', '*', '/', '%', '++', '--', '<<', '>>', '>>>', '&',
107
'|', '^', '!', '~', '&&', '||', '?', ':', '===', '==', '>=',
108
'<=', '<', '>', '!=', '!=='];
109
110
Syntax = {
111
AssignmentExpression: 'AssignmentExpression',
112
ArrayExpression: 'ArrayExpression',
113
ArrowFunctionExpression: 'ArrowFunctionExpression',
114
BlockStatement: 'BlockStatement',
115
BinaryExpression: 'BinaryExpression',
116
BreakStatement: 'BreakStatement',
117
CallExpression: 'CallExpression',
118
CatchClause: 'CatchClause',
119
ClassBody: 'ClassBody',
120
ClassDeclaration: 'ClassDeclaration',
121
ClassExpression: 'ClassExpression',
122
ConditionalExpression: 'ConditionalExpression',
123
ContinueStatement: 'ContinueStatement',
124
DoWhileStatement: 'DoWhileStatement',
125
DebuggerStatement: 'DebuggerStatement',
126
EmptyStatement: 'EmptyStatement',
127
ExpressionStatement: 'ExpressionStatement',
128
ForStatement: 'ForStatement',
129
ForInStatement: 'ForInStatement',
130
FunctionDeclaration: 'FunctionDeclaration',
131
FunctionExpression: 'FunctionExpression',
132
Identifier: 'Identifier',
133
IfStatement: 'IfStatement',
134
Literal: 'Literal',
135
LabeledStatement: 'LabeledStatement',
136
LogicalExpression: 'LogicalExpression',
137
MemberExpression: 'MemberExpression',
138
MethodDefinition: 'MethodDefinition',
139
NewExpression: 'NewExpression',
140
ObjectExpression: 'ObjectExpression',
141
Program: 'Program',
142
Property: 'Property',
143
RestElement: 'RestElement',
144
ReturnStatement: 'ReturnStatement',
145
SequenceExpression: 'SequenceExpression',
146
SwitchStatement: 'SwitchStatement',
147
SwitchCase: 'SwitchCase',
148
ThisExpression: 'ThisExpression',
149
ThrowStatement: 'ThrowStatement',
150
TryStatement: 'TryStatement',
151
UnaryExpression: 'UnaryExpression',
152
UpdateExpression: 'UpdateExpression',
153
VariableDeclaration: 'VariableDeclaration',
154
VariableDeclarator: 'VariableDeclarator',
155
WhileStatement: 'WhileStatement',
156
WithStatement: 'WithStatement'
157
};
158
159
PlaceHolders = {
160
ArrowParameterPlaceHolder: 'ArrowParameterPlaceHolder'
161
};
162
163
// Error messages should be identical to V8.
164
Messages = {
165
UnexpectedToken: 'Unexpected token %0',
166
UnexpectedNumber: 'Unexpected number',
167
UnexpectedString: 'Unexpected string',
168
UnexpectedIdentifier: 'Unexpected identifier',
169
UnexpectedReserved: 'Unexpected reserved word',
170
UnexpectedEOS: 'Unexpected end of input',
171
NewlineAfterThrow: 'Illegal newline after throw',
172
InvalidRegExp: 'Invalid regular expression',
173
UnterminatedRegExp: 'Invalid regular expression: missing /',
174
InvalidLHSInAssignment: 'Invalid left-hand side in assignment',
175
InvalidLHSInForIn: 'Invalid left-hand side in for-in',
176
MultipleDefaultsInSwitch: 'More than one default clause in switch statement',
177
NoCatchOrFinally: 'Missing catch or finally after try',
178
UnknownLabel: 'Undefined label \'%0\'',
179
Redeclaration: '%0 \'%1\' has already been declared',
180
IllegalContinue: 'Illegal continue statement',
181
IllegalBreak: 'Illegal break statement',
182
IllegalReturn: 'Illegal return statement',
183
StrictModeWith: 'Strict mode code may not include a with statement',
184
StrictCatchVariable: 'Catch variable may not be eval or arguments in strict mode',
185
StrictVarName: 'Variable name may not be eval or arguments in strict mode',
186
StrictParamName: 'Parameter name eval or arguments is not allowed in strict mode',
187
StrictParamDupe: 'Strict mode function may not have duplicate parameter names',
188
StrictFunctionName: 'Function name may not be eval or arguments in strict mode',
189
StrictOctalLiteral: 'Octal literals are not allowed in strict mode.',
190
StrictDelete: 'Delete of an unqualified identifier in strict mode.',
191
StrictLHSAssignment: 'Assignment to eval or arguments is not allowed in strict mode',
192
StrictLHSPostfix: 'Postfix increment/decrement may not have eval or arguments operand in strict mode',
193
StrictLHSPrefix: 'Prefix increment/decrement may not have eval or arguments operand in strict mode',
194
StrictReservedWord: 'Use of future reserved word in strict mode',
195
ParameterAfterRestParameter: 'Rest parameter must be last formal parameter',
196
DefaultRestParameter: 'Unexpected token =',
197
ObjectPatternAsRestParameter: 'Unexpected token {',
198
DuplicateProtoProperty: 'Duplicate __proto__ fields are not allowed in object literals',
199
ConstructorSpecialMethod: 'Class constructor may not be an accessor',
200
DuplicateConstructor: 'A class may only have one constructor',
201
StaticPrototype: 'Classes may not have static property named prototype'
202
};
203
204
// See also tools/generate-unicode-regex.py.
205
Regex = {
206
NonAsciiIdentifierStart: new RegExp('[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\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-\u08B2\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\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-\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-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\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-\uA69D\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA7AD\uA7B0\uA7B1\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB5F\uAB64\uAB65\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]'),
207
NonAsciiIdentifierPart: new RegExp('[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0300-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u0483-\u0487\u048A-\u052F\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-\u08B2\u08E4-\u0963\u0966-\u096F\u0971-\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\u0C00-\u0C03\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C58\u0C59\u0C60-\u0C63\u0C66-\u0C6F\u0C81-\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\u0D01-\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\u0DE6-\u0DEF\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-\u16F8\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-\u191E\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\u1AB0-\u1ABD\u1B00-\u1B4B\u1B50-\u1B59\u1B6B-\u1B73\u1B80-\u1BF3\u1C00-\u1C37\u1C40-\u1C49\u1C4D-\u1C7D\u1CD0-\u1CD2\u1CD4-\u1CF6\u1CF8\u1CF9\u1D00-\u1DF5\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-\uA69D\uA69F-\uA6F1\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA7AD\uA7B0\uA7B1\uA7F7-\uA827\uA840-\uA873\uA880-\uA8C4\uA8D0-\uA8D9\uA8E0-\uA8F7\uA8FB\uA900-\uA92D\uA930-\uA953\uA960-\uA97C\uA980-\uA9C0\uA9CF-\uA9D9\uA9E0-\uA9FE\uAA00-\uAA36\uAA40-\uAA4D\uAA50-\uAA59\uAA60-\uAA76\uAA7A-\uAAC2\uAADB-\uAADD\uAAE0-\uAAEF\uAAF2-\uAAF6\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB5F\uAB64\uAB65\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-\uFE2D\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]')
208
};
209
210
// Ensure the condition is true, otherwise throw an error.
211
// This is only to have a better contract semantic, i.e. another safety net
212
// to catch a logic error. The condition shall be fulfilled in normal case.
213
// Do NOT use this to enforce a certain condition on any user input.
214
215
function assert(condition, message) {
216
/* istanbul ignore if */
217
if (!condition) {
218
throw new Error('ASSERT: ' + message);
219
}
220
}
221
222
function isDecimalDigit(ch) {
223
return (ch >= 0x30 && ch <= 0x39); // 0..9
224
}
225
226
function isHexDigit(ch) {
227
return '0123456789abcdefABCDEF'.indexOf(ch) >= 0;
228
}
229
230
function isOctalDigit(ch) {
231
return '01234567'.indexOf(ch) >= 0;
232
}
233
234
235
// 7.2 White Space
236
237
function isWhiteSpace(ch) {
238
return (ch === 0x20) || (ch === 0x09) || (ch === 0x0B) || (ch === 0x0C) || (ch === 0xA0) ||
239
(ch >= 0x1680 && [0x1680, 0x180E, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008, 0x2009, 0x200A, 0x202F, 0x205F, 0x3000, 0xFEFF].indexOf(ch) >= 0);
240
}
241
242
// 7.3 Line Terminators
243
244
function isLineTerminator(ch) {
245
return (ch === 0x0A) || (ch === 0x0D) || (ch === 0x2028) || (ch === 0x2029);
246
}
247
248
// 7.6 Identifier Names and Identifiers
249
250
function isIdentifierStart(ch) {
251
return (ch === 0x24) || (ch === 0x5F) || // $ (dollar) and _ (underscore)
252
(ch >= 0x41 && ch <= 0x5A) || // A..Z
253
(ch >= 0x61 && ch <= 0x7A) || // a..z
254
(ch === 0x5C) || // \ (backslash)
255
((ch >= 0x80) && Regex.NonAsciiIdentifierStart.test(String.fromCharCode(ch)));
256
}
257
258
function isIdentifierPart(ch) {
259
return (ch === 0x24) || (ch === 0x5F) || // $ (dollar) and _ (underscore)
260
(ch >= 0x41 && ch <= 0x5A) || // A..Z
261
(ch >= 0x61 && ch <= 0x7A) || // a..z
262
(ch >= 0x30 && ch <= 0x39) || // 0..9
263
(ch === 0x5C) || // \ (backslash)
264
((ch >= 0x80) && Regex.NonAsciiIdentifierPart.test(String.fromCharCode(ch)));
265
}
266
267
// 7.6.1.2 Future Reserved Words
268
269
function isFutureReservedWord(id) {
270
switch (id) {
271
case 'enum':
272
case 'export':
273
case 'import':
274
case 'super':
275
return true;
276
default:
277
return false;
278
}
279
}
280
281
// 11.6.2.2 Future Reserved Words
282
283
function isStrictModeReservedWord(id) {
284
switch (id) {
285
case 'implements':
286
case 'interface':
287
case 'package':
288
case 'private':
289
case 'protected':
290
case 'public':
291
case 'static':
292
case 'yield':
293
case 'let':
294
return true;
295
default:
296
return false;
297
}
298
}
299
300
function isRestrictedWord(id) {
301
return id === 'eval' || id === 'arguments';
302
}
303
304
// 7.6.1.1 Keywords
305
306
function isKeyword(id) {
307
if (strict && isStrictModeReservedWord(id)) {
308
return true;
309
}
310
311
// 'const' is specialized as Keyword in V8.
312
// 'yield' and 'let' are for compatibility with SpiderMonkey and ES.next.
313
// Some others are from future reserved words.
314
315
switch (id.length) {
316
case 2:
317
return (id === 'if') || (id === 'in') || (id === 'do');
318
case 3:
319
return (id === 'var') || (id === 'for') || (id === 'new') ||
320
(id === 'try') || (id === 'let');
321
case 4:
322
return (id === 'this') || (id === 'else') || (id === 'case') ||
323
(id === 'void') || (id === 'with') || (id === 'enum');
324
case 5:
325
return (id === 'while') || (id === 'break') || (id === 'catch') ||
326
(id === 'throw') || (id === 'const') || (id === 'yield') ||
327
(id === 'class') || (id === 'super');
328
case 6:
329
return (id === 'return') || (id === 'typeof') || (id === 'delete') ||
330
(id === 'switch') || (id === 'export') || (id === 'import');
331
case 7:
332
return (id === 'default') || (id === 'finally') || (id === 'extends');
333
case 8:
334
return (id === 'function') || (id === 'continue') || (id === 'debugger');
335
case 10:
336
return (id === 'instanceof');
337
default:
338
return false;
339
}
340
}
341
342
// 7.4 Comments
343
344
function addComment(type, value, start, end, loc) {
345
var comment;
346
347
assert(typeof start === 'number', 'Comment must have valid position');
348
349
state.lastCommentStart = start;
350
351
comment = {
352
type: type,
353
value: value
354
};
355
if (extra.range) {
356
comment.range = [start, end];
357
}
358
if (extra.loc) {
359
comment.loc = loc;
360
}
361
extra.comments.push(comment);
362
if (extra.attachComment) {
363
extra.leadingComments.push(comment);
364
extra.trailingComments.push(comment);
365
}
366
}
367
368
function skipSingleLineComment(offset) {
369
var start, loc, ch, comment;
370
371
start = index - offset;
372
loc = {
373
start: {
374
line: lineNumber,
375
column: index - lineStart - offset
376
}
377
};
378
379
while (index < length) {
380
ch = source.charCodeAt(index);
381
++index;
382
if (isLineTerminator(ch)) {
383
hasLineTerminator = true;
384
if (extra.comments) {
385
comment = source.slice(start + offset, index - 1);
386
loc.end = {
387
line: lineNumber,
388
column: index - lineStart - 1
389
};
390
addComment('Line', comment, start, index - 1, loc);
391
}
392
if (ch === 13 && source.charCodeAt(index) === 10) {
393
++index;
394
}
395
++lineNumber;
396
lineStart = index;
397
return;
398
}
399
}
400
401
if (extra.comments) {
402
comment = source.slice(start + offset, index);
403
loc.end = {
404
line: lineNumber,
405
column: index - lineStart
406
};
407
addComment('Line', comment, start, index, loc);
408
}
409
}
410
411
function skipMultiLineComment() {
412
var start, loc, ch, comment;
413
414
if (extra.comments) {
415
start = index - 2;
416
loc = {
417
start: {
418
line: lineNumber,
419
column: index - lineStart - 2
420
}
421
};
422
}
423
424
while (index < length) {
425
ch = source.charCodeAt(index);
426
if (isLineTerminator(ch)) {
427
if (ch === 0x0D && source.charCodeAt(index + 1) === 0x0A) {
428
++index;
429
}
430
hasLineTerminator = true;
431
++lineNumber;
432
++index;
433
lineStart = index;
434
} else if (ch === 0x2A) {
435
// Block comment ends with '*/'.
436
if (source.charCodeAt(index + 1) === 0x2F) {
437
++index;
438
++index;
439
if (extra.comments) {
440
comment = source.slice(start + 2, index - 2);
441
loc.end = {
442
line: lineNumber,
443
column: index - lineStart
444
};
445
addComment('Block', comment, start, index, loc);
446
}
447
return;
448
}
449
++index;
450
} else {
451
++index;
452
}
453
}
454
455
if (extra.errors && index >= length) {
456
//ran off the end of the file - the whole thing is a comment
457
if (extra.comments) {
458
loc.end = {
459
line: lineNumber,
460
column: index - lineStart
461
};
462
comment = source.slice(start + 2, index);
463
addComment('Block', comment, start, index, loc);
464
}
465
tolerateUnexpectedToken();
466
} else {
467
throwUnexpectedToken();
468
}
469
}
470
471
function skipComment() {
472
var ch, start;
473
hasLineTerminator = false;
474
475
start = (index === 0);
476
while (index < length) {
477
ch = source.charCodeAt(index);
478
479
if (isWhiteSpace(ch)) {
480
++index;
481
} else if (isLineTerminator(ch)) {
482
hasLineTerminator = true;
483
++index;
484
if (ch === 0x0D && source.charCodeAt(index) === 0x0A) {
485
++index;
486
}
487
++lineNumber;
488
lineStart = index;
489
start = true;
490
} else if (ch === 0x2F) { // U+002F is '/'
491
ch = source.charCodeAt(index + 1);
492
if (ch === 0x2F) {
493
++index;
494
++index;
495
skipSingleLineComment(2);
496
start = true;
497
} else if (ch === 0x2A) { // U+002A is '*'
498
++index;
499
++index;
500
skipMultiLineComment();
501
} else {
502
break;
503
}
504
} else if (start && ch === 0x2D) { // U+002D is '-'
505
// U+003E is '>'
506
if ((source.charCodeAt(index + 1) === 0x2D) && (source.charCodeAt(index + 2) === 0x3E)) {
507
// '-->' is a single-line comment
508
index += 3;
509
skipSingleLineComment(3);
510
} else {
511
break;
512
}
513
} else if (ch === 0x3C) { // U+003C is '<'
514
if (source.slice(index + 1, index + 4) === '!--') {
515
++index; // `<`
516
++index; // `!`
517
++index; // `-`
518
++index; // `-`
519
skipSingleLineComment(4);
520
} else {
521
break;
522
}
523
} else {
524
break;
525
}
526
}
527
}
528
529
function scanHexEscape(prefix) {
530
var i, len, ch, code = 0;
531
532
len = (prefix === 'u') ? 4 : 2;
533
for (i = 0; i < len; ++i) {
534
if (index < length && isHexDigit(source[index])) {
535
ch = source[index++];
536
code = code * 16 + '0123456789abcdef'.indexOf(ch.toLowerCase());
537
} else {
538
return '';
539
}
540
}
541
return String.fromCharCode(code);
542
}
543
544
function scanUnicodeCodePointEscape() {
545
var ch, code, cu1, cu2;
546
547
ch = source[index];
548
code = 0;
549
550
// At least, one hex digit is required.
551
if (ch === '}') {
552
throwUnexpectedToken();
553
}
554
555
while (index < length) {
556
ch = source[index++];
557
if (!isHexDigit(ch)) {
558
break;
559
}
560
code = code * 16 + '0123456789abcdef'.indexOf(ch.toLowerCase());
561
}
562
563
if (code > 0x10FFFF || ch !== '}') {
564
throwUnexpectedToken();
565
}
566
567
// UTF-16 Encoding
568
if (code <= 0xFFFF) {
569
return String.fromCharCode(code);
570
}
571
cu1 = ((code - 0x10000) >> 10) + 0xD800;
572
cu2 = ((code - 0x10000) & 1023) + 0xDC00;
573
return String.fromCharCode(cu1, cu2);
574
}
575
576
function getEscapedIdentifier() {
577
var ch, id;
578
579
ch = source.charCodeAt(index++);
580
id = String.fromCharCode(ch);
581
582
// '\u' (U+005C, U+0075) denotes an escaped character.
583
if (ch === 0x5C) {
584
if (source.charCodeAt(index) !== 0x75) {
585
throwUnexpectedToken();
586
}
587
++index;
588
ch = scanHexEscape('u');
589
if (!ch || ch === '\\' || !isIdentifierStart(ch.charCodeAt(0))) {
590
throwUnexpectedToken();
591
}
592
id = ch;
593
}
594
595
while (index < length) {
596
ch = source.charCodeAt(index);
597
if (!isIdentifierPart(ch)) {
598
break;
599
}
600
++index;
601
id += String.fromCharCode(ch);
602
603
// '\u' (U+005C, U+0075) denotes an escaped character.
604
if (ch === 0x5C) {
605
id = id.substr(0, id.length - 1);
606
if (source.charCodeAt(index) !== 0x75) {
607
throwUnexpectedToken();
608
}
609
++index;
610
ch = scanHexEscape('u');
611
if (!ch || ch === '\\' || !isIdentifierPart(ch.charCodeAt(0))) {
612
throwUnexpectedToken();
613
}
614
id += ch;
615
}
616
}
617
618
return id;
619
}
620
621
function getIdentifier() {
622
var start, ch;
623
624
start = index++;
625
while (index < length) {
626
ch = source.charCodeAt(index);
627
if (ch === 0x5C) {
628
// Blackslash (U+005C) marks Unicode escape sequence.
629
index = start;
630
return getEscapedIdentifier();
631
}
632
if (isIdentifierPart(ch)) {
633
++index;
634
} else {
635
break;
636
}
637
}
638
639
return source.slice(start, index);
640
}
641
642
function scanIdentifier() {
643
var start, id, type;
644
645
start = index;
646
647
// Backslash (U+005C) starts an escaped character.
648
id = (source.charCodeAt(index) === 0x5C) ? getEscapedIdentifier() : getIdentifier();
649
650
// There is no keyword or literal with only one character.
651
// Thus, it must be an identifier.
652
if (id.length === 1) {
653
type = Token.Identifier;
654
} else if (isKeyword(id)) {
655
type = Token.Keyword;
656
} else if (id === 'null') {
657
type = Token.NullLiteral;
658
} else if (id === 'true' || id === 'false') {
659
type = Token.BooleanLiteral;
660
} else {
661
type = Token.Identifier;
662
}
663
664
return {
665
type: type,
666
value: id,
667
lineNumber: lineNumber,
668
lineStart: lineStart,
669
start: start,
670
end: index
671
};
672
}
673
674
675
// 7.7 Punctuators
676
677
function scanPunctuator() {
678
var token, str;
679
680
token = {
681
type: Token.Punctuator,
682
value: '',
683
lineNumber: lineNumber,
684
lineStart: lineStart,
685
start: index,
686
end: index
687
};
688
689
// Check for most common single-character punctuators.
690
str = source[index];
691
switch (str) {
692
693
case '(':
694
if (extra.tokenize) {
695
extra.openParenToken = extra.tokens.length;
696
}
697
++index;
698
break;
699
700
case '{':
701
if (extra.tokenize) {
702
extra.openCurlyToken = extra.tokens.length;
703
}
704
++index;
705
break;
706
707
case '.':
708
++index;
709
if (source[index] === '.' && source[index + 1] === '.') {
710
// Spread operator: ...
711
index += 2;
712
str = '...';
713
}
714
break;
715
716
case ')':
717
case ';':
718
case ',':
719
case '}':
720
case '[':
721
case ']':
722
case ':':
723
case '?':
724
case '~':
725
++index;
726
break;
727
728
default:
729
// 4-character punctuator.
730
str = source.substr(index, 4);
731
if (str === '>>>=') {
732
index += 4;
733
} else {
734
735
// 3-character punctuators.
736
str = str.substr(0, 3);
737
if (str === '===' || str === '!==' || str === '>>>' ||
738
str === '<<=' || str === '>>=') {
739
index += 3;
740
} else {
741
742
// 2-character punctuators.
743
str = str.substr(0, 2);
744
if (str === '&&' || str === '||' || str === '==' || str === '!=' ||
745
str === '+=' || str === '-=' || str === '*=' || str === '/=' ||
746
str === '++' || str === '--' || str === '<<' || str === '>>' ||
747
str === '&=' || str === '|=' || str === '^=' || str === '%=' ||
748
str === '<=' || str === '>=' || str === '=>') {
749
index += 2;
750
} else {
751
752
// 1-character punctuators.
753
str = source[index];
754
if ('<>=!+-*%&|^/'.indexOf(str) >= 0) {
755
++index;
756
}
757
}
758
}
759
}
760
}
761
762
if (index === token.start) {
763
throwUnexpectedToken();
764
}
765
766
token.end = index;
767
token.value = str;
768
return token;
769
}
770
771
// 7.8.3 Numeric Literals
772
773
function scanHexLiteral(start) {
774
var number = '';
775
776
while (index < length) {
777
if (!isHexDigit(source[index])) {
778
break;
779
}
780
number += source[index++];
781
}
782
783
if (number.length === 0) {
784
throwUnexpectedToken();
785
}
786
787
if (isIdentifierStart(source.charCodeAt(index))) {
788
throwUnexpectedToken();
789
}
790
791
return {
792
type: Token.NumericLiteral,
793
value: parseInt('0x' + number, 16),
794
lineNumber: lineNumber,
795
lineStart: lineStart,
796
start: start,
797
end: index
798
};
799
}
800
801
function scanBinaryLiteral(start) {
802
var ch, number;
803
804
number = '';
805
806
while (index < length) {
807
ch = source[index];
808
if (ch !== '0' && ch !== '1') {
809
break;
810
}
811
number += source[index++];
812
}
813
814
if (number.length === 0) {
815
// only 0b or 0B
816
throwUnexpectedToken();
817
}
818
819
if (index < length) {
820
ch = source.charCodeAt(index);
821
/* istanbul ignore else */
822
if (isIdentifierStart(ch) || isDecimalDigit(ch)) {
823
throwUnexpectedToken();
824
}
825
}
826
827
return {
828
type: Token.NumericLiteral,
829
value: parseInt(number, 2),
830
lineNumber: lineNumber,
831
lineStart: lineStart,
832
start: start,
833
end: index
834
};
835
}
836
837
function scanOctalLiteral(prefix, start) {
838
var number, octal;
839
840
if (isOctalDigit(prefix)) {
841
octal = true;
842
number = '0' + source[index++];
843
} else {
844
octal = false;
845
++index;
846
number = '';
847
}
848
849
while (index < length) {
850
if (!isOctalDigit(source[index])) {
851
break;
852
}
853
number += source[index++];
854
}
855
856
if (!octal && number.length === 0) {
857
// only 0o or 0O
858
throwUnexpectedToken();
859
}
860
861
if (isIdentifierStart(source.charCodeAt(index)) || isDecimalDigit(source.charCodeAt(index))) {
862
throwUnexpectedToken();
863
}
864
865
return {
866
type: Token.NumericLiteral,
867
value: parseInt(number, 8),
868
octal: octal,
869
lineNumber: lineNumber,
870
lineStart: lineStart,
871
start: start,
872
end: index
873
};
874
}
875
876
function isImplicitOctalLiteral() {
877
var i, ch;
878
879
// Implicit octal, unless there is a non-octal digit.
880
// (Annex B.1.1 on Numeric Literals)
881
for (i = index + 1; i < length; ++i) {
882
ch = source[i];
883
if (ch === '8' || ch === '9') {
884
return false;
885
}
886
if (!isOctalDigit(ch)) {
887
return true;
888
}
889
}
890
891
return true;
892
}
893
894
function scanNumericLiteral() {
895
var number, start, ch;
896
897
ch = source[index];
898
assert(isDecimalDigit(ch.charCodeAt(0)) || (ch === '.'),
899
'Numeric literal must start with a decimal digit or a decimal point');
900
901
start = index;
902
number = '';
903
if (ch !== '.') {
904
number = source[index++];
905
ch = source[index];
906
907
// Hex number starts with '0x'.
908
// Octal number starts with '0'.
909
// Octal number in ES6 starts with '0o'.
910
// Binary number in ES6 starts with '0b'.
911
if (number === '0') {
912
if (ch === 'x' || ch === 'X') {
913
++index;
914
return scanHexLiteral(start);
915
}
916
if (ch === 'b' || ch === 'B') {
917
++index;
918
return scanBinaryLiteral(start);
919
}
920
if (ch === 'o' || ch === 'O') {
921
return scanOctalLiteral(ch, start);
922
}
923
924
if (isOctalDigit(ch)) {
925
if (isImplicitOctalLiteral()) {
926
return scanOctalLiteral(ch, start);
927
}
928
}
929
}
930
931
while (isDecimalDigit(source.charCodeAt(index))) {
932
number += source[index++];
933
}
934
ch = source[index];
935
}
936
937
if (ch === '.') {
938
number += source[index++];
939
while (isDecimalDigit(source.charCodeAt(index))) {
940
number += source[index++];
941
}
942
ch = source[index];
943
}
944
945
if (ch === 'e' || ch === 'E') {
946
number += source[index++];
947
948
ch = source[index];
949
if (ch === '+' || ch === '-') {
950
number += source[index++];
951
}
952
if (isDecimalDigit(source.charCodeAt(index))) {
953
while (isDecimalDigit(source.charCodeAt(index))) {
954
number += source[index++];
955
}
956
} else {
957
throwUnexpectedToken();
958
}
959
}
960
961
if (isIdentifierStart(source.charCodeAt(index))) {
962
throwUnexpectedToken();
963
}
964
965
return {
966
type: Token.NumericLiteral,
967
value: parseFloat(number),
968
lineNumber: lineNumber,
969
lineStart: lineStart,
970
start: start,
971
end: index
972
};
973
}
974
975
// 7.8.4 String Literals
976
977
function scanStringLiteral() {
978
var str = '', quote, start, ch, code, unescaped, restore, octal = false;
979
980
quote = source[index];
981
assert((quote === '\'' || quote === '"'),
982
'String literal must starts with a quote');
983
984
start = index;
985
++index;
986
987
while (index < length) {
988
ch = source[index++];
989
990
if (ch === quote) {
991
quote = '';
992
break;
993
} else if (ch === '\\') {
994
ch = source[index++];
995
if (!ch || !isLineTerminator(ch.charCodeAt(0))) {
996
switch (ch) {
997
case 'u':
998
case 'x':
999
if (source[index] === '{') {
1000
++index;
1001
str += scanUnicodeCodePointEscape();
1002
} else {
1003
restore = index;
1004
unescaped = scanHexEscape(ch);
1005
if (unescaped) {
1006
str += unescaped;
1007
} else {
1008
index = restore;
1009
str += ch;
1010
}
1011
}
1012
break;
1013
case 'n':
1014
str += '\n';
1015
break;
1016
case 'r':
1017
str += '\r';
1018
break;
1019
case 't':
1020
str += '\t';
1021
break;
1022
case 'b':
1023
str += '\b';
1024
break;
1025
case 'f':
1026
str += '\f';
1027
break;
1028
case 'v':
1029
str += '\x0B';
1030
break;
1031
1032
default:
1033
if (isOctalDigit(ch)) {
1034
code = '01234567'.indexOf(ch);
1035
1036
// \0 is not octal escape sequence
1037
if (code !== 0) {
1038
octal = true;
1039
}
1040
1041
if (index < length && isOctalDigit(source[index])) {
1042
octal = true;
1043
code = code * 8 + '01234567'.indexOf(source[index++]);
1044
1045
// 3 digits are only allowed when string starts
1046
// with 0, 1, 2, 3
1047
if ('0123'.indexOf(ch) >= 0 &&
1048
index < length &&
1049
isOctalDigit(source[index])) {
1050
code = code * 8 + '01234567'.indexOf(source[index++]);
1051
}
1052
}
1053
str += String.fromCharCode(code);
1054
} else {
1055
str += ch;
1056
}
1057
break;
1058
}
1059
} else {
1060
++lineNumber;
1061
if (ch === '\r' && source[index] === '\n') {
1062
++index;
1063
}
1064
lineStart = index;
1065
}
1066
} else if (isLineTerminator(ch.charCodeAt(0))) {
1067
break;
1068
} else {
1069
str += ch;
1070
}
1071
}
1072
1073
if (quote !== '') {
1074
throwUnexpectedToken();
1075
}
1076
1077
return {
1078
type: Token.StringLiteral,
1079
value: str,
1080
octal: octal,
1081
lineNumber: startLineNumber,
1082
lineStart: startLineStart,
1083
start: start,
1084
end: index
1085
};
1086
}
1087
1088
function testRegExp(pattern, flags) {
1089
var tmp = pattern;
1090
1091
if (flags.indexOf('u') >= 0) {
1092
// Replace each astral symbol and every Unicode code point
1093
// escape sequence with a single ASCII symbol to avoid throwing on
1094
// regular expressions that are only valid in combination with the
1095
// `/u` flag.
1096
// Note: replacing with the ASCII symbol `x` might cause false
1097
// negatives in unlikely scenarios. For example, `[\u{61}-b]` is a
1098
// perfectly valid pattern that is equivalent to `[a-b]`, but it
1099
// would be replaced by `[x-b]` which throws an error.
1100
tmp = tmp
1101
.replace(/\\u\{([0-9a-fA-F]+)\}/g, function ($0, $1) {
1102
if (parseInt($1, 16) <= 0x10FFFF) {
1103
return 'x';
1104
}
1105
throwUnexpectedToken(null, Messages.InvalidRegExp);
1106
})
1107
.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g, 'x');
1108
}
1109
1110
// First, detect invalid regular expressions.
1111
try {
1112
RegExp(tmp);
1113
} catch (e) {
1114
throwUnexpectedToken(null, Messages.InvalidRegExp);
1115
}
1116
1117
// Return a regular expression object for this pattern-flag pair, or
1118
// `null` in case the current environment doesn't support the flags it
1119
// uses.
1120
try {
1121
return new RegExp(pattern, flags);
1122
} catch (exception) {
1123
return null;
1124
}
1125
}
1126
1127
function scanRegExpBody() {
1128
var ch, str, classMarker, terminated, body;
1129
1130
ch = source[index];
1131
assert(ch === '/', 'Regular expression literal must start with a slash');
1132
str = source[index++];
1133
1134
classMarker = false;
1135
terminated = false;
1136
while (index < length) {
1137
ch = source[index++];
1138
str += ch;
1139
if (ch === '\\') {
1140
ch = source[index++];
1141
// ECMA-262 7.8.5
1142
if (isLineTerminator(ch.charCodeAt(0))) {
1143
throwUnexpectedToken(null, Messages.UnterminatedRegExp);
1144
}
1145
str += ch;
1146
} else if (isLineTerminator(ch.charCodeAt(0))) {
1147
throwUnexpectedToken(null, Messages.UnterminatedRegExp);
1148
} else if (classMarker) {
1149
if (ch === ']') {
1150
classMarker = false;
1151
}
1152
} else {
1153
if (ch === '/') {
1154
terminated = true;
1155
break;
1156
} else if (ch === '[') {
1157
classMarker = true;
1158
}
1159
}
1160
}
1161
1162
if (!terminated) {
1163
throwUnexpectedToken(null, Messages.UnterminatedRegExp);
1164
}
1165
1166
// Exclude leading and trailing slash.
1167
body = str.substr(1, str.length - 2);
1168
return {
1169
value: body,
1170
literal: str
1171
};
1172
}
1173
1174
function scanRegExpFlags() {
1175
var ch, str, flags, restore;
1176
1177
str = '';
1178
flags = '';
1179
while (index < length) {
1180
ch = source[index];
1181
if (!isIdentifierPart(ch.charCodeAt(0))) {
1182
break;
1183
}
1184
1185
++index;
1186
if (ch === '\\' && index < length) {
1187
ch = source[index];
1188
if (ch === 'u') {
1189
++index;
1190
restore = index;
1191
ch = scanHexEscape('u');
1192
if (ch) {
1193
flags += ch;
1194
for (str += '\\u'; restore < index; ++restore) {
1195
str += source[restore];
1196
}
1197
} else {
1198
index = restore;
1199
flags += 'u';
1200
str += '\\u';
1201
}
1202
tolerateUnexpectedToken();
1203
} else {
1204
str += '\\';
1205
tolerateUnexpectedToken();
1206
}
1207
} else {
1208
flags += ch;
1209
str += ch;
1210
}
1211
}
1212
1213
return {
1214
value: flags,
1215
literal: str
1216
};
1217
}
1218
1219
function scanRegExp() {
1220
scanning = true;
1221
var start, body, flags, value;
1222
1223
lookahead = null;
1224
skipComment();
1225
start = index;
1226
1227
body = scanRegExpBody();
1228
flags = scanRegExpFlags();
1229
value = testRegExp(body.value, flags.value);
1230
scanning = false;
1231
if (extra.tokenize) {
1232
return {
1233
type: Token.RegularExpression,
1234
value: value,
1235
regex: {
1236
pattern: body.value,
1237
flags: flags.value
1238
},
1239
lineNumber: lineNumber,
1240
lineStart: lineStart,
1241
start: start,
1242
end: index
1243
};
1244
}
1245
1246
return {
1247
literal: body.literal + flags.literal,
1248
value: value,
1249
regex: {
1250
pattern: body.value,
1251
flags: flags.value
1252
},
1253
start: start,
1254
end: index
1255
};
1256
}
1257
1258
function collectRegex() {
1259
var pos, loc, regex, token;
1260
1261
skipComment();
1262
1263
pos = index;
1264
loc = {
1265
start: {
1266
line: lineNumber,
1267
column: index - lineStart
1268
}
1269
};
1270
1271
regex = scanRegExp();
1272
1273
loc.end = {
1274
line: lineNumber,
1275
column: index - lineStart
1276
};
1277
1278
/* istanbul ignore next */
1279
if (!extra.tokenize) {
1280
// Pop the previous token, which is likely '/' or '/='
1281
if (extra.tokens.length > 0) {
1282
token = extra.tokens[extra.tokens.length - 1];
1283
if (token.range[0] === pos && token.type === 'Punctuator') {
1284
if (token.value === '/' || token.value === '/=') {
1285
extra.tokens.pop();
1286
}
1287
}
1288
}
1289
1290
extra.tokens.push({
1291
type: 'RegularExpression',
1292
value: regex.literal,
1293
regex: regex.regex,
1294
range: [pos, index],
1295
loc: loc
1296
});
1297
}
1298
1299
return regex;
1300
}
1301
1302
function isIdentifierName(token) {
1303
return token.type === Token.Identifier ||
1304
token.type === Token.Keyword ||
1305
token.type === Token.BooleanLiteral ||
1306
token.type === Token.NullLiteral;
1307
}
1308
1309
function advanceSlash() {
1310
var prevToken,
1311
checkToken;
1312
// Using the following algorithm:
1313
// https://github.com/mozilla/sweet.js/wiki/design
1314
prevToken = extra.tokens[extra.tokens.length - 1];
1315
if (!prevToken) {
1316
// Nothing before that: it cannot be a division.
1317
return collectRegex();
1318
}
1319
if (prevToken.type === 'Punctuator') {
1320
if (prevToken.value === ']') {
1321
return scanPunctuator();
1322
}
1323
if (prevToken.value === ')') {
1324
checkToken = extra.tokens[extra.openParenToken - 1];
1325
if (checkToken &&
1326
checkToken.type === 'Keyword' &&
1327
(checkToken.value === 'if' ||
1328
checkToken.value === 'while' ||
1329
checkToken.value === 'for' ||
1330
checkToken.value === 'with')) {
1331
return collectRegex();
1332
}
1333
return scanPunctuator();
1334
}
1335
if (prevToken.value === '}') {
1336
// Dividing a function by anything makes little sense,
1337
// but we have to check for that.
1338
if (extra.tokens[extra.openCurlyToken - 3] &&
1339
extra.tokens[extra.openCurlyToken - 3].type === 'Keyword') {
1340
// Anonymous function.
1341
checkToken = extra.tokens[extra.openCurlyToken - 4];
1342
if (!checkToken) {
1343
return scanPunctuator();
1344
}
1345
} else if (extra.tokens[extra.openCurlyToken - 4] &&
1346
extra.tokens[extra.openCurlyToken - 4].type === 'Keyword') {
1347
// Named function.
1348
checkToken = extra.tokens[extra.openCurlyToken - 5];
1349
if (!checkToken) {
1350
return collectRegex();
1351
}
1352
} else {
1353
return scanPunctuator();
1354
}
1355
// checkToken determines whether the function is
1356
// a declaration or an expression.
1357
if (FnExprTokens.indexOf(checkToken.value) >= 0) {
1358
// It is an expression.
1359
return scanPunctuator();
1360
}
1361
// It is a declaration.
1362
return collectRegex();
1363
}
1364
return collectRegex();
1365
}
1366
if (prevToken.type === 'Keyword' && prevToken.value !== 'this') {
1367
return collectRegex();
1368
}
1369
return scanPunctuator();
1370
}
1371
1372
function advance() {
1373
var ch;
1374
1375
if (index >= length) {
1376
return {
1377
type: Token.EOF,
1378
lineNumber: lineNumber,
1379
lineStart: lineStart,
1380
start: index,
1381
end: index
1382
};
1383
}
1384
1385
ch = source.charCodeAt(index);
1386
1387
if (isIdentifierStart(ch)) {
1388
return scanIdentifier();
1389
}
1390
1391
// Very common: ( and ) and ;
1392
if (ch === 0x28 || ch === 0x29 || ch === 0x3B) {
1393
return scanPunctuator();
1394
}
1395
1396
// String literal starts with single quote (U+0027) or double quote (U+0022).
1397
if (ch === 0x27 || ch === 0x22) {
1398
return scanStringLiteral();
1399
}
1400
1401
1402
// Dot (.) U+002E can also start a floating-point number, hence the need
1403
// to check the next character.
1404
if (ch === 0x2E) {
1405
if (isDecimalDigit(source.charCodeAt(index + 1))) {
1406
return scanNumericLiteral();
1407
}
1408
return scanPunctuator();
1409
}
1410
1411
if (isDecimalDigit(ch)) {
1412
return scanNumericLiteral();
1413
}
1414
1415
// Slash (/) U+002F can also start a regex.
1416
if (extra.tokenize && ch === 0x2F) {
1417
return advanceSlash();
1418
}
1419
1420
return scanPunctuator();
1421
}
1422
1423
function collectToken() {
1424
var loc, token, value, entry;
1425
1426
loc = {
1427
start: {
1428
line: lineNumber,
1429
column: index - lineStart
1430
}
1431
};
1432
1433
token = advance();
1434
loc.end = {
1435
line: lineNumber,
1436
column: index - lineStart
1437
};
1438
1439
if (token.type !== Token.EOF) {
1440
value = source.slice(token.start, token.end);
1441
entry = {
1442
type: TokenName[token.type],
1443
value: value,
1444
range: [token.start, token.end],
1445
loc: loc
1446
};
1447
if (token.regex) {
1448
entry.regex = {
1449
pattern: token.regex.pattern,
1450
flags: token.regex.flags
1451
};
1452
}
1453
extra.tokens.push(entry);
1454
}
1455
1456
return token;
1457
}
1458
1459
function lex() {
1460
var token;
1461
scanning = true;
1462
1463
lastIndex = index;
1464
lastLineNumber = lineNumber;
1465
lastLineStart = lineStart;
1466
1467
skipComment();
1468
1469
token = lookahead;
1470
1471
startIndex = index;
1472
startLineNumber = lineNumber;
1473
startLineStart = lineStart;
1474
1475
lookahead = (typeof extra.tokens !== 'undefined') ? collectToken() : advance();
1476
scanning = false;
1477
return token;
1478
}
1479
1480
function peek() {
1481
scanning = true;
1482
1483
skipComment();
1484
1485
lastIndex = index;
1486
lastLineNumber = lineNumber;
1487
lastLineStart = lineStart;
1488
1489
startIndex = index;
1490
startLineNumber = lineNumber;
1491
startLineStart = lineStart;
1492
1493
lookahead = (typeof extra.tokens !== 'undefined') ? collectToken() : advance();
1494
scanning = false;
1495
}
1496
1497
function Position() {
1498
this.line = startLineNumber;
1499
this.column = startIndex - startLineStart;
1500
}
1501
1502
function SourceLocation() {
1503
this.start = new Position();
1504
this.end = null;
1505
}
1506
1507
function WrappingSourceLocation(startToken) {
1508
this.start = {
1509
line: startToken.lineNumber,
1510
column: startToken.start - startToken.lineStart
1511
};
1512
this.end = null;
1513
}
1514
1515
function Node() {
1516
if (extra.range) {
1517
this.range = [startIndex, 0];
1518
}
1519
if (extra.loc) {
1520
this.loc = new SourceLocation();
1521
}
1522
}
1523
1524
function WrappingNode(startToken) {
1525
if (extra.range) {
1526
this.range = [startToken.start, 0];
1527
}
1528
if (extra.loc) {
1529
this.loc = new WrappingSourceLocation(startToken);
1530
}
1531
}
1532
1533
WrappingNode.prototype = Node.prototype = {
1534
1535
processComment: function () {
1536
var lastChild,
1537
leadingComments,
1538
trailingComments,
1539
bottomRight = extra.bottomRightStack,
1540
i,
1541
comment,
1542
last = bottomRight[bottomRight.length - 1];
1543
1544
if (this.type === Syntax.Program) {
1545
if (this.body.length > 0) {
1546
return;
1547
}
1548
}
1549
1550
if (extra.trailingComments.length > 0) {
1551
trailingComments = [];
1552
for (i = extra.trailingComments.length - 1; i >= 0; --i) {
1553
comment = extra.trailingComments[i];
1554
if (comment.range[0] >= this.range[1]) {
1555
trailingComments.unshift(comment);
1556
extra.trailingComments.splice(i, 1);
1557
}
1558
}
1559
extra.trailingComments = [];
1560
} else {
1561
if (last && last.trailingComments && last.trailingComments[0].range[0] >= this.range[1]) {
1562
trailingComments = last.trailingComments;
1563
delete last.trailingComments;
1564
}
1565
}
1566
1567
// Eating the stack.
1568
if (last) {
1569
while (last && last.range[0] >= this.range[0]) {
1570
lastChild = last;
1571
last = bottomRight.pop();
1572
}
1573
}
1574
1575
if (lastChild) {
1576
if (lastChild.leadingComments && lastChild.leadingComments[lastChild.leadingComments.length - 1].range[1] <= this.range[0]) {
1577
this.leadingComments = lastChild.leadingComments;
1578
lastChild.leadingComments = undefined;
1579
}
1580
} else if (extra.leadingComments.length > 0) {
1581
leadingComments = [];
1582
for (i = extra.leadingComments.length - 1; i >= 0; --i) {
1583
comment = extra.leadingComments[i];
1584
if (comment.range[1] <= this.range[0]) {
1585
leadingComments.unshift(comment);
1586
extra.leadingComments.splice(i, 1);
1587
}
1588
}
1589
}
1590
1591
1592
if (leadingComments && leadingComments.length > 0) {
1593
this.leadingComments = leadingComments;
1594
}
1595
if (trailingComments && trailingComments.length > 0) {
1596
this.trailingComments = trailingComments;
1597
}
1598
1599
bottomRight.push(this);
1600
},
1601
1602
finish: function () {
1603
if (extra.range) {
1604
this.range[1] = lastIndex;
1605
}
1606
if (extra.loc) {
1607
this.loc.end = {
1608
line: lastLineNumber,
1609
column: lastIndex - lastLineStart
1610
};
1611
if (extra.source) {
1612
this.loc.source = extra.source;
1613
}
1614
}
1615
1616
if (extra.attachComment) {
1617
this.processComment();
1618
}
1619
},
1620
1621
finishArrayExpression: function (elements) {
1622
this.type = Syntax.ArrayExpression;
1623
this.elements = elements;
1624
this.finish();
1625
return this;
1626
},
1627
1628
finishArrowFunctionExpression: function (params, defaults, body, expression) {
1629
this.type = Syntax.ArrowFunctionExpression;
1630
this.id = null;
1631
this.params = params;
1632
this.defaults = defaults;
1633
this.body = body;
1634
this.generator = false;
1635
this.expression = expression;
1636
this.finish();
1637
return this;
1638
},
1639
1640
finishAssignmentExpression: function (operator, left, right) {
1641
this.type = Syntax.AssignmentExpression;
1642
this.operator = operator;
1643
this.left = left;
1644
this.right = right;
1645
this.finish();
1646
return this;
1647
},
1648
1649
finishBinaryExpression: function (operator, left, right) {
1650
this.type = (operator === '||' || operator === '&&') ? Syntax.LogicalExpression : Syntax.BinaryExpression;
1651
this.operator = operator;
1652
this.left = left;
1653
this.right = right;
1654
this.finish();
1655
return this;
1656
},
1657
1658
finishBlockStatement: function (body) {
1659
this.type = Syntax.BlockStatement;
1660
this.body = body;
1661
this.finish();
1662
return this;
1663
},
1664
1665
finishBreakStatement: function (label) {
1666
this.type = Syntax.BreakStatement;
1667
this.label = label;
1668
this.finish();
1669
return this;
1670
},
1671
1672
finishCallExpression: function (callee, args) {
1673
this.type = Syntax.CallExpression;
1674
this.callee = callee;
1675
this.arguments = args;
1676
this.finish();
1677
return this;
1678
},
1679
1680
finishCatchClause: function (param, body) {
1681
this.type = Syntax.CatchClause;
1682
this.param = param;
1683
this.body = body;
1684
this.finish();
1685
return this;
1686
},
1687
1688
finishClassBody: function (body) {
1689
this.type = Syntax.ClassBody;
1690
this.body = body;
1691
this.finish();
1692
return this;
1693
},
1694
1695
finishClassDeclaration: function (id, superClass, body) {
1696
this.type = Syntax.ClassDeclaration;
1697
this.id = id;
1698
this.superClass = superClass;
1699
this.body = body;
1700
this.finish();
1701
return this;
1702
},
1703
1704
finishClassExpression: function (id, superClass, body) {
1705
this.type = Syntax.ClassExpression;
1706
this.id = id;
1707
this.superClass = superClass;
1708
this.body = body;
1709
this.finish();
1710
return this;
1711
},
1712
1713
finishConditionalExpression: function (test, consequent, alternate) {
1714
this.type = Syntax.ConditionalExpression;
1715
this.test = test;
1716
this.consequent = consequent;
1717
this.alternate = alternate;
1718
this.finish();
1719
return this;
1720
},
1721
1722
finishContinueStatement: function (label) {
1723
this.type = Syntax.ContinueStatement;
1724
this.label = label;
1725
this.finish();
1726
return this;
1727
},
1728
1729
finishDebuggerStatement: function () {
1730
this.type = Syntax.DebuggerStatement;
1731
this.finish();
1732
return this;
1733
},
1734
1735
finishDoWhileStatement: function (body, test) {
1736
this.type = Syntax.DoWhileStatement;
1737
this.body = body;
1738
this.test = test;
1739
this.finish();
1740
return this;
1741
},
1742
1743
finishEmptyStatement: function () {
1744
this.type = Syntax.EmptyStatement;
1745
this.finish();
1746
return this;
1747
},
1748
1749
finishExpressionStatement: function (expression) {
1750
this.type = Syntax.ExpressionStatement;
1751
this.expression = expression;
1752
this.finish();
1753
return this;
1754
},
1755
1756
finishForStatement: function (init, test, update, body) {
1757
this.type = Syntax.ForStatement;
1758
this.init = init;
1759
this.test = test;
1760
this.update = update;
1761
this.body = body;
1762
this.finish();
1763
return this;
1764
},
1765
1766
finishForInStatement: function (left, right, body) {
1767
this.type = Syntax.ForInStatement;
1768
this.left = left;
1769
this.right = right;
1770
this.body = body;
1771
this.each = false;
1772
this.finish();
1773
return this;
1774
},
1775
1776
finishFunctionDeclaration: function (id, params, defaults, body) {
1777
this.type = Syntax.FunctionDeclaration;
1778
this.id = id;
1779
this.params = params;
1780
this.defaults = defaults;
1781
this.body = body;
1782
this.generator = false;
1783
this.expression = false;
1784
this.finish();
1785
return this;
1786
},
1787
1788
finishFunctionExpression: function (id, params, defaults, body) {
1789
this.type = Syntax.FunctionExpression;
1790
this.id = id;
1791
this.params = params;
1792
this.defaults = defaults;
1793
this.body = body;
1794
this.generator = false;
1795
this.expression = false;
1796
this.finish();
1797
return this;
1798
},
1799
1800
finishIdentifier: function (name) {
1801
this.type = Syntax.Identifier;
1802
this.name = name;
1803
this.finish();
1804
return this;
1805
},
1806
1807
finishIfStatement: function (test, consequent, alternate) {
1808
this.type = Syntax.IfStatement;
1809
this.test = test;
1810
this.consequent = consequent;
1811
this.alternate = alternate;
1812
this.finish();
1813
return this;
1814
},
1815
1816
finishLabeledStatement: function (label, body) {
1817
this.type = Syntax.LabeledStatement;
1818
this.label = label;
1819
this.body = body;
1820
this.finish();
1821
return this;
1822
},
1823
1824
finishLiteral: function (token) {
1825
this.type = Syntax.Literal;
1826
this.value = token.value;
1827
this.raw = source.slice(token.start, token.end);
1828
if (token.regex) {
1829
this.regex = token.regex;
1830
}
1831
this.finish();
1832
return this;
1833
},
1834
1835
finishMemberExpression: function (accessor, object, property) {
1836
this.type = Syntax.MemberExpression;
1837
this.computed = accessor === '[';
1838
this.object = object;
1839
this.property = property;
1840
this.finish();
1841
return this;
1842
},
1843
1844
finishNewExpression: function (callee, args) {
1845
this.type = Syntax.NewExpression;
1846
this.callee = callee;
1847
this.arguments = args;
1848
this.finish();
1849
return this;
1850
},
1851
1852
finishObjectExpression: function (properties) {
1853
this.type = Syntax.ObjectExpression;
1854
this.properties = properties;
1855
this.finish();
1856
return this;
1857
},
1858
1859
finishPostfixExpression: function (operator, argument) {
1860
this.type = Syntax.UpdateExpression;
1861
this.operator = operator;
1862
this.argument = argument;
1863
this.prefix = false;
1864
this.finish();
1865
return this;
1866
},
1867
1868
finishProgram: function (body) {
1869
this.type = Syntax.Program;
1870
this.body = body;
1871
this.finish();
1872
return this;
1873
},
1874
1875
finishProperty: function (kind, key, computed, value, method, shorthand) {
1876
this.type = Syntax.Property;
1877
this.key = key;
1878
this.computed = computed;
1879
this.value = value;
1880
this.kind = kind;
1881
this.method = method;
1882
this.shorthand = shorthand;
1883
this.finish();
1884
return this;
1885
},
1886
1887
finishRestElement: function (argument) {
1888
this.type = Syntax.RestElement;
1889
this.argument = argument;
1890
this.finish();
1891
return this;
1892
},
1893
1894
finishReturnStatement: function (argument) {
1895
this.type = Syntax.ReturnStatement;
1896
this.argument = argument;
1897
this.finish();
1898
return this;
1899
},
1900
1901
finishSequenceExpression: function (expressions) {
1902
this.type = Syntax.SequenceExpression;
1903
this.expressions = expressions;
1904
this.finish();
1905
return this;
1906
},
1907
1908
finishSwitchCase: function (test, consequent) {
1909
this.type = Syntax.SwitchCase;
1910
this.test = test;
1911
this.consequent = consequent;
1912
this.finish();
1913
return this;
1914
},
1915
1916
finishSwitchStatement: function (discriminant, cases) {
1917
this.type = Syntax.SwitchStatement;
1918
this.discriminant = discriminant;
1919
this.cases = cases;
1920
this.finish();
1921
return this;
1922
},
1923
1924
finishThisExpression: function () {
1925
this.type = Syntax.ThisExpression;
1926
this.finish();
1927
return this;
1928
},
1929
1930
finishThrowStatement: function (argument) {
1931
this.type = Syntax.ThrowStatement;
1932
this.argument = argument;
1933
this.finish();
1934
return this;
1935
},
1936
1937
finishTryStatement: function (block, handler, finalizer) {
1938
this.type = Syntax.TryStatement;
1939
this.block = block;
1940
this.guardedHandlers = [];
1941
this.handlers = handler ? [ handler ] : [];
1942
this.handler = handler;
1943
this.finalizer = finalizer;
1944
this.finish();
1945
return this;
1946
},
1947
1948
finishUnaryExpression: function (operator, argument) {
1949
this.type = (operator === '++' || operator === '--') ? Syntax.UpdateExpression : Syntax.UnaryExpression;
1950
this.operator = operator;
1951
this.argument = argument;
1952
this.prefix = true;
1953
this.finish();
1954
return this;
1955
},
1956
1957
finishVariableDeclaration: function (declarations) {
1958
this.type = Syntax.VariableDeclaration;
1959
this.declarations = declarations;
1960
this.kind = 'var';
1961
this.finish();
1962
return this;
1963
},
1964
1965
finishLexicalDeclaration: function (declarations, kind) {
1966
this.type = Syntax.VariableDeclaration;
1967
this.declarations = declarations;
1968
this.kind = kind;
1969
this.finish();
1970
return this;
1971
},
1972
1973
finishVariableDeclarator: function (id, init) {
1974
this.type = Syntax.VariableDeclarator;
1975
this.id = id;
1976
this.init = init;
1977
this.finish();
1978
return this;
1979
},
1980
1981
finishWhileStatement: function (test, body) {
1982
this.type = Syntax.WhileStatement;
1983
this.test = test;
1984
this.body = body;
1985
this.finish();
1986
return this;
1987
},
1988
1989
finishWithStatement: function (object, body) {
1990
this.type = Syntax.WithStatement;
1991
this.object = object;
1992
this.body = body;
1993
this.finish();
1994
return this;
1995
}
1996
};
1997
1998
1999
function recordError(error) {
2000
var e, existing;
2001
2002
for (e = 0; e < extra.errors.length; e++) {
2003
existing = extra.errors[e];
2004
// Prevent duplicated error.
2005
/* istanbul ignore next */
2006
if (existing.index === error.index && existing.message === error.message) {
2007
return;
2008
}
2009
}
2010
2011
extra.errors.push(error);
2012
}
2013
2014
function createError(line, pos, description) {
2015
var error = new Error('Line ' + line + ': ' + description);
2016
error.index = pos;
2017
error.lineNumber = line;
2018
error.column = pos - (scanning ? lineStart : lastLineStart) + 1;
2019
error.description = description;
2020
return error;
2021
}
2022
2023
// Throw an exception
2024
2025
function throwError(messageFormat) {
2026
var args, msg;
2027
2028
args = Array.prototype.slice.call(arguments, 1);
2029
msg = messageFormat.replace(/%(\d)/g,
2030
function (whole, idx) {
2031
assert(idx < args.length, 'Message reference must be in range');
2032
return args[idx];
2033
}
2034
);
2035
2036
throw createError(lastLineNumber, lastIndex, msg);
2037
}
2038
2039
function tolerateError(messageFormat) {
2040
var args, msg, error;
2041
2042
args = Array.prototype.slice.call(arguments, 1);
2043
/* istanbul ignore next */
2044
msg = messageFormat.replace(/%(\d)/g,
2045
function (whole, idx) {
2046
assert(idx < args.length, 'Message reference must be in range');
2047
return args[idx];
2048
}
2049
);
2050
2051
error = createError(lineNumber, lastIndex, msg);
2052
if (extra.errors) {
2053
recordError(error);
2054
} else {
2055
throw error;
2056
}
2057
}
2058
2059
// Throw an exception because of the token.
2060
2061
function unexpectedTokenError(token, message) {
2062
var msg = message || Messages.UnexpectedToken;
2063
2064
if (token && !message) {
2065
msg = (token.type === Token.EOF) ? Messages.UnexpectedEOS :
2066
(token.type === Token.Identifier) ? Messages.UnexpectedIdentifier :
2067
(token.type === Token.NumericLiteral) ? Messages.UnexpectedNumber :
2068
(token.type === Token.StringLiteral) ? Messages.UnexpectedString :
2069
Messages.UnexpectedToken;
2070
2071
if (token.type === Token.Keyword) {
2072
if (isFutureReservedWord(token.value)) {
2073
msg = Messages.UnexpectedReserved;
2074
} else if (strict && isStrictModeReservedWord(token.value)) {
2075
msg = Messages.StrictReservedWord;
2076
}
2077
}
2078
}
2079
2080
msg = msg.replace('%0', token ? token.value : 'ILLEGAL');
2081
2082
return (token && typeof token.lineNumber === 'number') ?
2083
createError(token.lineNumber, token.start, msg) :
2084
createError(scanning ? lineNumber : lastLineNumber, scanning ? index : lastIndex, msg);
2085
}
2086
2087
function throwUnexpectedToken(token, message) {
2088
throw unexpectedTokenError(token, message);
2089
}
2090
2091
function tolerateUnexpectedToken(token, message) {
2092
var error = unexpectedTokenError(token, message);
2093
if (extra.errors) {
2094
recordError(error);
2095
} else {
2096
throw error;
2097
}
2098
}
2099
2100
// Expect the next token to match the specified punctuator.
2101
// If not, an exception will be thrown.
2102
2103
function expect(value) {
2104
var token = lex();
2105
if (token.type !== Token.Punctuator || token.value !== value) {
2106
throwUnexpectedToken(token);
2107
}
2108
}
2109
2110
/**
2111
* @name expectCommaSeparator
2112
* @description Quietly expect a comma when in tolerant mode, otherwise delegates
2113
* to <code>expect(value)</code>
2114
* @since 2.0
2115
*/
2116
function expectCommaSeparator() {
2117
var token;
2118
2119
if (extra.errors) {
2120
token = lookahead;
2121
if (token.type === Token.Punctuator && token.value === ',') {
2122
lex();
2123
} else if (token.type === Token.Punctuator && token.value === ';') {
2124
lex();
2125
tolerateUnexpectedToken(token);
2126
} else {
2127
tolerateUnexpectedToken(token, Messages.UnexpectedToken);
2128
}
2129
} else {
2130
expect(',');
2131
}
2132
}
2133
2134
// Expect the next token to match the specified keyword.
2135
// If not, an exception will be thrown.
2136
2137
function expectKeyword(keyword) {
2138
var token = lex();
2139
if (token.type !== Token.Keyword || token.value !== keyword) {
2140
throwUnexpectedToken(token);
2141
}
2142
}
2143
2144
// Return true if the next token matches the specified punctuator.
2145
2146
function match(value) {
2147
return lookahead.type === Token.Punctuator && lookahead.value === value;
2148
}
2149
2150
// Return true if the next token matches the specified keyword
2151
2152
function matchKeyword(keyword) {
2153
return lookahead.type === Token.Keyword && lookahead.value === keyword;
2154
}
2155
2156
// Return true if the next token is an assignment operator
2157
2158
function matchAssign() {
2159
var op;
2160
2161
if (lookahead.type !== Token.Punctuator) {
2162
return false;
2163
}
2164
op = lookahead.value;
2165
return op === '=' ||
2166
op === '*=' ||
2167
op === '/=' ||
2168
op === '%=' ||
2169
op === '+=' ||
2170
op === '-=' ||
2171
op === '<<=' ||
2172
op === '>>=' ||
2173
op === '>>>=' ||
2174
op === '&=' ||
2175
op === '^=' ||
2176
op === '|=';
2177
}
2178
2179
function consumeSemicolon() {
2180
// Catch the very common case first: immediately a semicolon (U+003B).
2181
if (source.charCodeAt(startIndex) === 0x3B || match(';')) {
2182
lex();
2183
return;
2184
}
2185
2186
if (hasLineTerminator) {
2187
return;
2188
}
2189
2190
// FIXME(ikarienator): this is seemingly an issue in the previous location info convention.
2191
lastIndex = startIndex;
2192
lastLineNumber = startLineNumber;
2193
lastLineStart = startLineStart;
2194
2195
if (lookahead.type !== Token.EOF && !match('}')) {
2196
throwUnexpectedToken(lookahead);
2197
}
2198
}
2199
2200
// Return true if provided expression is LeftHandSideExpression
2201
2202
function isLeftHandSide(expr) {
2203
return expr.type === Syntax.Identifier || expr.type === Syntax.MemberExpression;
2204
}
2205
2206
// 11.1.4 Array Initialiser
2207
2208
function parseArrayInitialiser() {
2209
var elements = [], node = new Node();
2210
2211
expect('[');
2212
2213
while (!match(']')) {
2214
if (match(',')) {
2215
lex();
2216
elements.push(null);
2217
} else {
2218
elements.push(parseAssignmentExpression());
2219
2220
if (!match(']')) {
2221
expect(',');
2222
}
2223
}
2224
}
2225
2226
lex();
2227
2228
return node.finishArrayExpression(elements);
2229
}
2230
2231
// 11.1.5 Object Initialiser
2232
2233
function parsePropertyFunction(node, paramInfo) {
2234
var previousStrict, body;
2235
2236
previousStrict = strict;
2237
body = parseFunctionSourceElements();
2238
2239
if (strict && paramInfo.firstRestricted) {
2240
tolerateUnexpectedToken(paramInfo.firstRestricted, paramInfo.message);
2241
}
2242
if (strict && paramInfo.stricted) {
2243
tolerateUnexpectedToken(paramInfo.stricted, paramInfo.message);
2244
}
2245
2246
strict = previousStrict;
2247
return node.finishFunctionExpression(null, paramInfo.params, paramInfo.defaults, body);
2248
}
2249
2250
function parsePropertyMethodFunction() {
2251
var params, method, node = new Node();
2252
2253
params = parseParams();
2254
method = parsePropertyFunction(node, params);
2255
2256
return method;
2257
}
2258
2259
// This function returns a tuple `[PropertyName, boolean]` where the PropertyName is the key being consumed and the second
2260
// element indicate whether its a computed PropertyName or a static PropertyName.
2261
function parseObjectPropertyKey() {
2262
var token, node = new Node(), expr;
2263
2264
token = lex();
2265
2266
// Note: This function is called only from parseObjectProperty(), where
2267
// EOF and Punctuator tokens are already filtered out.
2268
2269
switch (token.type) {
2270
case Token.StringLiteral:
2271
case Token.NumericLiteral:
2272
if (strict && token.octal) {
2273
tolerateUnexpectedToken(token, Messages.StrictOctalLiteral);
2274
}
2275
return node.finishLiteral(token);
2276
case Token.Identifier:
2277
case Token.BooleanLiteral:
2278
case Token.NullLiteral:
2279
case Token.Keyword:
2280
return node.finishIdentifier(token.value);
2281
case Token.Punctuator:
2282
if (token.value === '[') {
2283
expr = parseAssignmentExpression();
2284
expect(']');
2285
return expr;
2286
}
2287
break;
2288
}
2289
throwUnexpectedToken(token);
2290
}
2291
2292
function lookaheadPropertyName() {
2293
switch (lookahead.type) {
2294
case Token.Identifier:
2295
case Token.StringLiteral:
2296
case Token.BooleanLiteral:
2297
case Token.NullLiteral:
2298
case Token.NumericLiteral:
2299
case Token.Keyword:
2300
return true;
2301
case Token.Punctuator:
2302
return lookahead.value === '[';
2303
}
2304
return false;
2305
}
2306
2307
// This function is to try to parse a MethodDefinition as defined in 14.3. But in the case of object literals,
2308
// it might be called at a position where there is in fact a short hand identifier pattern or a data property.
2309
// This can only be determined after we consumed up to the left parentheses.
2310
//
2311
// In order to avoid back tracking, it returns `null` if the position is not a MethodDefinition and the caller
2312
// is responsible to visit other options.
2313
function tryParseMethodDefinition(token, key, computed, node) {
2314
var value, options, methodNode;
2315
2316
if (token.type === Token.Identifier) {
2317
// check for `get` and `set`;
2318
2319
if (token.value === 'get' && lookaheadPropertyName()) {
2320
computed = match('[');
2321
key = parseObjectPropertyKey();
2322
methodNode = new Node();
2323
expect('(');
2324
expect(')');
2325
value = parsePropertyFunction(methodNode, {
2326
params: [],
2327
defaults: [],
2328
stricted: null,
2329
firstRestricted: null,
2330
message: null
2331
});
2332
return node.finishProperty('get', key, computed, value, false, false);
2333
} else if (token.value === 'set' && lookaheadPropertyName()) {
2334
computed = match('[');
2335
key = parseObjectPropertyKey();
2336
methodNode = new Node();
2337
expect('(');
2338
2339
options = {
2340
params: [],
2341
defaultCount: 0,
2342
defaults: [],
2343
firstRestricted: null,
2344
paramSet: {}
2345
};
2346
if (match(')')) {
2347
tolerateUnexpectedToken(lookahead);
2348
} else {
2349
parseParam(options);
2350
if (options.defaultCount === 0) {
2351
options.defaults = [];
2352
}
2353
}
2354
expect(')');
2355
2356
value = parsePropertyFunction(methodNode, options);
2357
return node.finishProperty('set', key, computed, value, false, false);
2358
}
2359
}
2360
2361
if (match('(')) {
2362
value = parsePropertyMethodFunction();
2363
return node.finishProperty('init', key, computed, value, true, false);
2364
}
2365
2366
// Not a MethodDefinition.
2367
return null;
2368
}
2369
2370
function checkProto(key, computed, hasProto) {
2371
if (computed === false && (key.type === Syntax.Identifier && key.name === '__proto__' ||
2372
key.type === Syntax.Literal && key.value === '__proto__')) {
2373
if (hasProto.value) {
2374
tolerateError(Messages.DuplicateProtoProperty);
2375
} else {
2376
hasProto.value = true;
2377
}
2378
}
2379
}
2380
2381
function parseObjectProperty(hasProto) {
2382
var token = lookahead, node = new Node(), computed, key, maybeMethod, value;
2383
2384
computed = match('[');
2385
key = parseObjectPropertyKey();
2386
maybeMethod = tryParseMethodDefinition(token, key, computed, node);
2387
2388
if (maybeMethod) {
2389
checkProto(maybeMethod.key, maybeMethod.computed, hasProto);
2390
// finished
2391
return maybeMethod;
2392
}
2393
2394
// init property or short hand property.
2395
checkProto(key, computed, hasProto);
2396
2397
if (match(':')) {
2398
lex();
2399
value = parseAssignmentExpression();
2400
return node.finishProperty('init', key, computed, value, false, false);
2401
}
2402
2403
if (token.type === Token.Identifier) {
2404
return node.finishProperty('init', key, computed, key, false, true);
2405
}
2406
2407
throwUnexpectedToken(lookahead);
2408
}
2409
2410
function parseObjectInitialiser() {
2411
var properties = [], hasProto = {value: false}, node = new Node();
2412
2413
expect('{');
2414
2415
while (!match('}')) {
2416
properties.push(parseObjectProperty(hasProto));
2417
2418
if (!match('}')) {
2419
expectCommaSeparator();
2420
}
2421
}
2422
2423
expect('}');
2424
2425
return node.finishObjectExpression(properties);
2426
}
2427
2428
// 11.1.6 The Grouping Operator
2429
2430
function parseGroupExpression() {
2431
var expr, expressions, startToken, isValidArrowParameter = true;
2432
2433
expect('(');
2434
2435
if (match(')')) {
2436
lex();
2437
if (!match('=>')) {
2438
expect('=>');
2439
}
2440
return {
2441
type: PlaceHolders.ArrowParameterPlaceHolder,
2442
params: []
2443
};
2444
}
2445
2446
startToken = lookahead;
2447
if (match('...')) {
2448
expr = parseRestElement();
2449
expect(')');
2450
if (!match('=>')) {
2451
expect('=>');
2452
}
2453
return {
2454
type: PlaceHolders.ArrowParameterPlaceHolder,
2455
params: [expr]
2456
};
2457
}
2458
2459
if (match('(')) {
2460
isValidArrowParameter = false;
2461
}
2462
2463
expr = parseAssignmentExpression();
2464
2465
if (match(',')) {
2466
expressions = [expr];
2467
2468
while (startIndex < length) {
2469
if (!match(',')) {
2470
break;
2471
}
2472
lex();
2473
2474
if (match('...')) {
2475
if (!isValidArrowParameter) {
2476
throwUnexpectedToken(lookahead);
2477
}
2478
expressions.push(parseRestElement());
2479
expect(')');
2480
if (!match('=>')) {
2481
expect('=>');
2482
}
2483
return {
2484
type: PlaceHolders.ArrowParameterPlaceHolder,
2485
params: expressions
2486
};
2487
} else if (match('(')) {
2488
isValidArrowParameter = false;
2489
}
2490
2491
expressions.push(parseAssignmentExpression());
2492
}
2493
2494
expr = new WrappingNode(startToken).finishSequenceExpression(expressions);
2495
}
2496
2497
2498
expect(')');
2499
2500
if (match('=>') && !isValidArrowParameter) {
2501
throwUnexpectedToken(lookahead);
2502
}
2503
2504
return expr;
2505
}
2506
2507
2508
// 11.1 Primary Expressions
2509
2510
function parsePrimaryExpression() {
2511
var type, token, expr, node;
2512
2513
if (match('(')) {
2514
return parseGroupExpression();
2515
}
2516
2517
if (match('[')) {
2518
return parseArrayInitialiser();
2519
}
2520
2521
if (match('{')) {
2522
return parseObjectInitialiser();
2523
}
2524
2525
type = lookahead.type;
2526
node = new Node();
2527
2528
if (type === Token.Identifier) {
2529
expr = node.finishIdentifier(lex().value);
2530
} else if (type === Token.StringLiteral || type === Token.NumericLiteral) {
2531
if (strict && lookahead.octal) {
2532
tolerateUnexpectedToken(lookahead, Messages.StrictOctalLiteral);
2533
}
2534
expr = node.finishLiteral(lex());
2535
} else if (type === Token.Keyword) {
2536
if (matchKeyword('function')) {
2537
return parseFunctionExpression();
2538
}
2539
if (matchKeyword('this')) {
2540
lex();
2541
return node.finishThisExpression();
2542
}
2543
if (matchKeyword('class')) {
2544
return parseClassExpression();
2545
}
2546
throwUnexpectedToken(lex());
2547
} else if (type === Token.BooleanLiteral) {
2548
token = lex();
2549
token.value = (token.value === 'true');
2550
expr = node.finishLiteral(token);
2551
} else if (type === Token.NullLiteral) {
2552
token = lex();
2553
token.value = null;
2554
expr = node.finishLiteral(token);
2555
} else if (match('/') || match('/=')) {
2556
index = startIndex;
2557
2558
if (typeof extra.tokens !== 'undefined') {
2559
token = collectRegex();
2560
} else {
2561
token = scanRegExp();
2562
}
2563
lex();
2564
expr = node.finishLiteral(token);
2565
} else {
2566
throwUnexpectedToken(lex());
2567
}
2568
2569
return expr;
2570
}
2571
2572
// 11.2 Left-Hand-Side Expressions
2573
2574
function parseArguments() {
2575
var args = [];
2576
2577
expect('(');
2578
2579
if (!match(')')) {
2580
while (startIndex < length) {
2581
args.push(parseAssignmentExpression());
2582
if (match(')')) {
2583
break;
2584
}
2585
expectCommaSeparator();
2586
}
2587
}
2588
2589
expect(')');
2590
2591
return args;
2592
}
2593
2594
function parseNonComputedProperty() {
2595
var token, node = new Node();
2596
2597
token = lex();
2598
2599
if (!isIdentifierName(token)) {
2600
throwUnexpectedToken(token);
2601
}
2602
2603
return node.finishIdentifier(token.value);
2604
}
2605
2606
function parseNonComputedMember() {
2607
expect('.');
2608
2609
return parseNonComputedProperty();
2610
}
2611
2612
function parseComputedMember() {
2613
var expr;
2614
2615
expect('[');
2616
2617
expr = parseExpression();
2618
2619
expect(']');
2620
2621
return expr;
2622
}
2623
2624
function parseNewExpression() {
2625
var callee, args, node = new Node();
2626
2627
expectKeyword('new');
2628
callee = parseLeftHandSideExpression();
2629
args = match('(') ? parseArguments() : [];
2630
2631
return node.finishNewExpression(callee, args);
2632
}
2633
2634
function parseLeftHandSideExpressionAllowCall() {
2635
var expr, args, property, startToken, previousAllowIn = state.allowIn;
2636
2637
startToken = lookahead;
2638
state.allowIn = true;
2639
expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression();
2640
2641
for (;;) {
2642
if (match('.')) {
2643
property = parseNonComputedMember();
2644
expr = new WrappingNode(startToken).finishMemberExpression('.', expr, property);
2645
} else if (match('(')) {
2646
args = parseArguments();
2647
expr = new WrappingNode(startToken).finishCallExpression(expr, args);
2648
} else if (match('[')) {
2649
property = parseComputedMember();
2650
expr = new WrappingNode(startToken).finishMemberExpression('[', expr, property);
2651
} else {
2652
break;
2653
}
2654
}
2655
state.allowIn = previousAllowIn;
2656
2657
return expr;
2658
}
2659
2660
function parseLeftHandSideExpression() {
2661
var expr, property, startToken;
2662
assert(state.allowIn, 'callee of new expression always allow in keyword.');
2663
2664
startToken = lookahead;
2665
2666
expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression();
2667
2668
for (;;) {
2669
if (match('[')) {
2670
property = parseComputedMember();
2671
expr = new WrappingNode(startToken).finishMemberExpression('[', expr, property);
2672
} else if (match('.')) {
2673
property = parseNonComputedMember();
2674
expr = new WrappingNode(startToken).finishMemberExpression('.', expr, property);
2675
} else {
2676
break;
2677
}
2678
}
2679
return expr;
2680
}
2681
2682
// 11.3 Postfix Expressions
2683
2684
function parsePostfixExpression() {
2685
var expr, token, startToken = lookahead;
2686
2687
expr = parseLeftHandSideExpressionAllowCall();
2688
2689
if (!hasLineTerminator && lookahead.type === Token.Punctuator) {
2690
if (match('++') || match('--')) {
2691
// 11.3.1, 11.3.2
2692
if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) {
2693
tolerateError(Messages.StrictLHSPostfix);
2694
}
2695
2696
if (!isLeftHandSide(expr)) {
2697
tolerateError(Messages.InvalidLHSInAssignment);
2698
}
2699
2700
token = lex();
2701
expr = new WrappingNode(startToken).finishPostfixExpression(token.value, expr);
2702
}
2703
}
2704
2705
return expr;
2706
}
2707
2708
// 11.4 Unary Operators
2709
2710
function parseUnaryExpression() {
2711
var token, expr, startToken;
2712
2713
if (lookahead.type !== Token.Punctuator && lookahead.type !== Token.Keyword) {
2714
expr = parsePostfixExpression();
2715
} else if (match('++') || match('--')) {
2716
startToken = lookahead;
2717
token = lex();
2718
expr = parseUnaryExpression();
2719
// 11.4.4, 11.4.5
2720
if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) {
2721
tolerateError(Messages.StrictLHSPrefix);
2722
}
2723
2724
if (!isLeftHandSide(expr)) {
2725
tolerateError(Messages.InvalidLHSInAssignment);
2726
}
2727
2728
expr = new WrappingNode(startToken).finishUnaryExpression(token.value, expr);
2729
} else if (match('+') || match('-') || match('~') || match('!')) {
2730
startToken = lookahead;
2731
token = lex();
2732
expr = parseUnaryExpression();
2733
expr = new WrappingNode(startToken).finishUnaryExpression(token.value, expr);
2734
} else if (matchKeyword('delete') || matchKeyword('void') || matchKeyword('typeof')) {
2735
startToken = lookahead;
2736
token = lex();
2737
expr = parseUnaryExpression();
2738
expr = new WrappingNode(startToken).finishUnaryExpression(token.value, expr);
2739
if (strict && expr.operator === 'delete' && expr.argument.type === Syntax.Identifier) {
2740
tolerateError(Messages.StrictDelete);
2741
}
2742
} else {
2743
expr = parsePostfixExpression();
2744
}
2745
2746
return expr;
2747
}
2748
2749
function binaryPrecedence(token, allowIn) {
2750
var prec = 0;
2751
2752
if (token.type !== Token.Punctuator && token.type !== Token.Keyword) {
2753
return 0;
2754
}
2755
2756
switch (token.value) {
2757
case '||':
2758
prec = 1;
2759
break;
2760
2761
case '&&':
2762
prec = 2;
2763
break;
2764
2765
case '|':
2766
prec = 3;
2767
break;
2768
2769
case '^':
2770
prec = 4;
2771
break;
2772
2773
case '&':
2774
prec = 5;
2775
break;
2776
2777
case '==':
2778
case '!=':
2779
case '===':
2780
case '!==':
2781
prec = 6;
2782
break;
2783
2784
case '<':
2785
case '>':
2786
case '<=':
2787
case '>=':
2788
case 'instanceof':
2789
prec = 7;
2790
break;
2791
2792
case 'in':
2793
prec = allowIn ? 7 : 0;
2794
break;
2795
2796
case '<<':
2797
case '>>':
2798
case '>>>':
2799
prec = 8;
2800
break;
2801
2802
case '+':
2803
case '-':
2804
prec = 9;
2805
break;
2806
2807
case '*':
2808
case '/':
2809
case '%':
2810
prec = 11;
2811
break;
2812
2813
default:
2814
break;
2815
}
2816
2817
return prec;
2818
}
2819
2820
// 11.5 Multiplicative Operators
2821
// 11.6 Additive Operators
2822
// 11.7 Bitwise Shift Operators
2823
// 11.8 Relational Operators
2824
// 11.9 Equality Operators
2825
// 11.10 Binary Bitwise Operators
2826
// 11.11 Binary Logical Operators
2827
2828
function parseBinaryExpression() {
2829
var marker, markers, expr, token, prec, stack, right, operator, left, i;
2830
2831
marker = lookahead;
2832
left = parseUnaryExpression();
2833
2834
token = lookahead;
2835
prec = binaryPrecedence(token, state.allowIn);
2836
if (prec === 0) {
2837
return left;
2838
}
2839
token.prec = prec;
2840
lex();
2841
2842
markers = [marker, lookahead];
2843
right = parseUnaryExpression();
2844
2845
stack = [left, token, right];
2846
2847
while ((prec = binaryPrecedence(lookahead, state.allowIn)) > 0) {
2848
2849
// Reduce: make a binary expression from the three topmost entries.
2850
while ((stack.length > 2) && (prec <= stack[stack.length - 2].prec)) {
2851
right = stack.pop();
2852
operator = stack.pop().value;
2853
left = stack.pop();
2854
markers.pop();
2855
expr = new WrappingNode(markers[markers.length - 1]).finishBinaryExpression(operator, left, right);
2856
stack.push(expr);
2857
}
2858
2859
// Shift.
2860
token = lex();
2861
token.prec = prec;
2862
stack.push(token);
2863
markers.push(lookahead);
2864
expr = parseUnaryExpression();
2865
stack.push(expr);
2866
}
2867
2868
// Final reduce to clean-up the stack.
2869
i = stack.length - 1;
2870
expr = stack[i];
2871
markers.pop();
2872
while (i > 1) {
2873
expr = new WrappingNode(markers.pop()).finishBinaryExpression(stack[i - 1].value, stack[i - 2], expr);
2874
i -= 2;
2875
}
2876
2877
return expr;
2878
}
2879
2880
2881
// 11.12 Conditional Operator
2882
2883
function parseConditionalExpression() {
2884
var expr, previousAllowIn, consequent, alternate, startToken;
2885
2886
startToken = lookahead;
2887
2888
expr = parseBinaryExpression();
2889
if (match('?')) {
2890
lex();
2891
previousAllowIn = state.allowIn;
2892
state.allowIn = true;
2893
consequent = parseAssignmentExpression();
2894
state.allowIn = previousAllowIn;
2895
expect(':');
2896
alternate = parseAssignmentExpression();
2897
2898
expr = new WrappingNode(startToken).finishConditionalExpression(expr, consequent, alternate);
2899
}
2900
2901
return expr;
2902
}
2903
2904
// [ES6] 14.2 Arrow Function
2905
2906
function parseConciseBody() {
2907
if (match('{')) {
2908
return parseFunctionSourceElements();
2909
}
2910
return parseAssignmentExpression();
2911
}
2912
2913
function reinterpretAsCoverFormalsList(expr) {
2914
var i, len, param, params, defaults, defaultCount, options, token;
2915
2916
defaults = [];
2917
defaultCount = 0;
2918
params = [expr];
2919
2920
switch (expr.type) {
2921
case Syntax.Identifier:
2922
case Syntax.AssignmentExpression:
2923
break;
2924
case Syntax.SequenceExpression:
2925
params = expr.expressions;
2926
break;
2927
case PlaceHolders.ArrowParameterPlaceHolder:
2928
params = expr.params;
2929
break;
2930
default:
2931
return null;
2932
}
2933
2934
options = {
2935
paramSet: {}
2936
};
2937
2938
for (i = 0, len = params.length; i < len; i += 1) {
2939
param = params[i];
2940
if (param.type === Syntax.Identifier) {
2941
params[i] = param;
2942
defaults.push(null);
2943
validateParam(options, param, param.name);
2944
} else if (param.type === Syntax.RestElement) {
2945
params[i] = param;
2946
defaults.push(null);
2947
validateParam(options, param.argument, param.argument.name);
2948
} else if (param.type === Syntax.AssignmentExpression) {
2949
params[i] = param.left;
2950
defaults.push(param.right);
2951
++defaultCount;
2952
validateParam(options, param.left, param.left.name);
2953
} else {
2954
return null;
2955
}
2956
}
2957
2958
if (options.message === Messages.StrictParamDupe) {
2959
token = strict ? options.stricted : options.firstRestricted;
2960
throwUnexpectedToken(token, options.message);
2961
}
2962
2963
if (defaultCount === 0) {
2964
defaults = [];
2965
}
2966
2967
return {
2968
params: params,
2969
defaults: defaults,
2970
stricted: options.stricted,
2971
firstRestricted: options.firstRestricted,
2972
message: options.message
2973
};
2974
}
2975
2976
function parseArrowFunctionExpression(options, node) {
2977
var previousStrict, body;
2978
2979
expect('=>');
2980
previousStrict = strict;
2981
2982
body = parseConciseBody();
2983
2984
if (strict && options.firstRestricted) {
2985
throwUnexpectedToken(options.firstRestricted, options.message);
2986
}
2987
if (strict && options.stricted) {
2988
tolerateUnexpectedToken(options.stricted, options.message);
2989
}
2990
2991
strict = previousStrict;
2992
2993
return node.finishArrowFunctionExpression(options.params, options.defaults, body, body.type !== Syntax.BlockStatement);
2994
}
2995
2996
// 11.13 Assignment Operators
2997
2998
function parseAssignmentExpression() {
2999
var token, expr, right, list, startToken;
3000
3001
startToken = lookahead;
3002
token = lookahead;
3003
3004
expr = parseConditionalExpression();
3005
3006
if (expr.type === PlaceHolders.ArrowParameterPlaceHolder || match('=>')) {
3007
list = reinterpretAsCoverFormalsList(expr);
3008
3009
if (list) {
3010
return parseArrowFunctionExpression(list, new WrappingNode(startToken));
3011
}
3012
}
3013
3014
if (matchAssign()) {
3015
// LeftHandSideExpression
3016
if (!isLeftHandSide(expr)) {
3017
tolerateError(Messages.InvalidLHSInAssignment);
3018
}
3019
3020
// 11.13.1
3021
if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) {
3022
tolerateUnexpectedToken(token, Messages.StrictLHSAssignment);
3023
}
3024
3025
token = lex();
3026
right = parseAssignmentExpression();
3027
expr = new WrappingNode(startToken).finishAssignmentExpression(token.value, expr, right);
3028
}
3029
3030
return expr;
3031
}
3032
3033
// 11.14 Comma Operator
3034
3035
function parseExpression() {
3036
var expr, startToken = lookahead, expressions;
3037
3038
expr = parseAssignmentExpression();
3039
3040
if (match(',')) {
3041
expressions = [expr];
3042
3043
while (startIndex < length) {
3044
if (!match(',')) {
3045
break;
3046
}
3047
lex();
3048
expressions.push(parseAssignmentExpression());
3049
}
3050
3051
expr = new WrappingNode(startToken).finishSequenceExpression(expressions);
3052
}
3053
3054
return expr;
3055
}
3056
3057
// 12.1 Block
3058
3059
function parseStatementListItem() {
3060
if (lookahead.type === Token.Keyword) {
3061
switch (lookahead.value) {
3062
case 'const':
3063
case 'let':
3064
return parseLexicalDeclaration();
3065
case 'function':
3066
return parseFunctionDeclaration(new Node());
3067
case 'class':
3068
return parseClassDeclaration();
3069
}
3070
}
3071
3072
return parseStatement();
3073
}
3074
3075
function parseStatementList() {
3076
var list = [];
3077
while (startIndex < length) {
3078
if (match('}')) {
3079
break;
3080
}
3081
list.push(parseStatementListItem());
3082
}
3083
3084
return list;
3085
}
3086
3087
function parseBlock() {
3088
var block, node = new Node();
3089
3090
expect('{');
3091
3092
block = parseStatementList();
3093
3094
expect('}');
3095
3096
return node.finishBlockStatement(block);
3097
}
3098
3099
// 12.2 Variable Statement
3100
3101
function parseVariableIdentifier() {
3102
var token, node = new Node();
3103
3104
token = lex();
3105
3106
if (token.type !== Token.Identifier) {
3107
if (strict && token.type === Token.Keyword && isStrictModeReservedWord(token.value)) {
3108
tolerateUnexpectedToken(token, Messages.StrictReservedWord);
3109
} else {
3110
throwUnexpectedToken(token);
3111
}
3112
}
3113
3114
return node.finishIdentifier(token.value);
3115
}
3116
3117
function parseVariableDeclaration() {
3118
var init = null, id, node = new Node();
3119
3120
id = parseVariableIdentifier();
3121
3122
// 12.2.1
3123
if (strict && isRestrictedWord(id.name)) {
3124
tolerateError(Messages.StrictVarName);
3125
}
3126
3127
if (match('=')) {
3128
lex();
3129
init = parseAssignmentExpression();
3130
}
3131
3132
return node.finishVariableDeclarator(id, init);
3133
}
3134
3135
function parseVariableDeclarationList() {
3136
var list = [];
3137
3138
do {
3139
list.push(parseVariableDeclaration());
3140
if (!match(',')) {
3141
break;
3142
}
3143
lex();
3144
} while (startIndex < length);
3145
3146
return list;
3147
}
3148
3149
function parseVariableStatement(node) {
3150
var declarations;
3151
3152
expectKeyword('var');
3153
3154
declarations = parseVariableDeclarationList();
3155
3156
consumeSemicolon();
3157
3158
return node.finishVariableDeclaration(declarations);
3159
}
3160
3161
function parseLexicalBinding(kind) {
3162
var init = null, id, node = new Node();
3163
3164
id = parseVariableIdentifier();
3165
3166
// 12.2.1
3167
if (strict && isRestrictedWord(id.name)) {
3168
tolerateError(Messages.StrictVarName);
3169
}
3170
3171
if (kind === 'const') {
3172
if (!matchKeyword('in')) {
3173
expect('=');
3174
init = parseAssignmentExpression();
3175
}
3176
} else if (match('=')) {
3177
lex();
3178
init = parseAssignmentExpression();
3179
}
3180
3181
return node.finishVariableDeclarator(id, init);
3182
}
3183
3184
function parseBindingList(kind) {
3185
var list = [];
3186
3187
do {
3188
list.push(parseLexicalBinding(kind));
3189
if (!match(',')) {
3190
break;
3191
}
3192
lex();
3193
} while (startIndex < length);
3194
3195
return list;
3196
}
3197
3198
function parseLexicalDeclaration() {
3199
var kind, declarations, node = new Node();
3200
3201
kind = lex().value;
3202
assert(kind === 'let' || kind === 'const', 'Lexical declaration must be either let or const');
3203
3204
declarations = parseBindingList(kind);
3205
3206
consumeSemicolon();
3207
3208
return node.finishLexicalDeclaration(declarations, kind);
3209
}
3210
3211
function parseRestElement() {
3212
var param, node = new Node();
3213
3214
lex();
3215
3216
if (match('{')) {
3217
throwError(Messages.ObjectPatternAsRestParameter);
3218
}
3219
3220
param = parseVariableIdentifier();
3221
3222
if (match('=')) {
3223
throwError(Messages.DefaultRestParameter);
3224
}
3225
3226
if (!match(')')) {
3227
throwError(Messages.ParameterAfterRestParameter);
3228
}
3229
3230
return node.finishRestElement(param);
3231
}
3232
3233
// 12.3 Empty Statement
3234
3235
function parseEmptyStatement(node) {
3236
expect(';');
3237
return node.finishEmptyStatement();
3238
}
3239
3240
// 12.4 Expression Statement
3241
3242
function parseExpressionStatement(node) {
3243
var expr = parseExpression();
3244
consumeSemicolon();
3245
return node.finishExpressionStatement(expr);
3246
}
3247
3248
// 12.5 If statement
3249
3250
function parseIfStatement(node) {
3251
var test, consequent, alternate;
3252
3253
expectKeyword('if');
3254
3255
expect('(');
3256
3257
test = parseExpression();
3258
3259
expect(')');
3260
3261
consequent = parseStatement();
3262
3263
if (matchKeyword('else')) {
3264
lex();
3265
alternate = parseStatement();
3266
} else {
3267
alternate = null;
3268
}
3269
3270
return node.finishIfStatement(test, consequent, alternate);
3271
}
3272
3273
// 12.6 Iteration Statements
3274
3275
function parseDoWhileStatement(node) {
3276
var body, test, oldInIteration;
3277
3278
expectKeyword('do');
3279
3280
oldInIteration = state.inIteration;
3281
state.inIteration = true;
3282
3283
body = parseStatement();
3284
3285
state.inIteration = oldInIteration;
3286
3287
expectKeyword('while');
3288
3289
expect('(');
3290
3291
test = parseExpression();
3292
3293
expect(')');
3294
3295
if (match(';')) {
3296
lex();
3297
}
3298
3299
return node.finishDoWhileStatement(body, test);
3300
}
3301
3302
function parseWhileStatement(node) {
3303
var test, body, oldInIteration;
3304
3305
expectKeyword('while');
3306
3307
expect('(');
3308
3309
test = parseExpression();
3310
3311
expect(')');
3312
3313
oldInIteration = state.inIteration;
3314
state.inIteration = true;
3315
3316
body = parseStatement();
3317
3318
state.inIteration = oldInIteration;
3319
3320
return node.finishWhileStatement(test, body);
3321
}
3322
3323
function parseForStatement(node) {
3324
var init, test, update, left, right, kind, declarations,
3325
body, oldInIteration, previousAllowIn = state.allowIn;
3326
3327
init = test = update = null;
3328
3329
expectKeyword('for');
3330
3331
expect('(');
3332
3333
if (match(';')) {
3334
lex();
3335
} else {
3336
if (matchKeyword('var')) {
3337
init = new Node();
3338
lex();
3339
3340
state.allowIn = false;
3341
init = init.finishVariableDeclaration(parseVariableDeclarationList());
3342
state.allowIn = previousAllowIn;
3343
3344
if (init.declarations.length === 1 && matchKeyword('in')) {
3345
lex();
3346
left = init;
3347
right = parseExpression();
3348
init = null;
3349
} else {
3350
expect(';');
3351
}
3352
} else if (matchKeyword('const') || matchKeyword('let')) {
3353
init = new Node();
3354
kind = lex().value;
3355
3356
state.allowIn = false;
3357
declarations = parseBindingList(kind);
3358
state.allowIn = previousAllowIn;
3359
3360
if (declarations.length === 1 && declarations[0].init === null && matchKeyword('in')) {
3361
init = init.finishLexicalDeclaration(declarations, kind);
3362
lex();
3363
left = init;
3364
right = parseExpression();
3365
init = null;
3366
} else {
3367
consumeSemicolon();
3368
init = init.finishLexicalDeclaration(declarations, kind);
3369
}
3370
} else {
3371
state.allowIn = false;
3372
init = parseExpression();
3373
state.allowIn = previousAllowIn;
3374
3375
if (matchKeyword('in')) {
3376
// LeftHandSideExpression
3377
if (!isLeftHandSide(init)) {
3378
tolerateError(Messages.InvalidLHSInForIn);
3379
}
3380
3381
lex();
3382
left = init;
3383
right = parseExpression();
3384
init = null;
3385
} else {
3386
expect(';');
3387
}
3388
}
3389
}
3390
3391
if (typeof left === 'undefined') {
3392
3393
if (!match(';')) {
3394
test = parseExpression();
3395
}
3396
expect(';');
3397
3398
if (!match(')')) {
3399
update = parseExpression();
3400
}
3401
}
3402
3403
expect(')');
3404
3405
oldInIteration = state.inIteration;
3406
state.inIteration = true;
3407
3408
body = parseStatement();
3409
3410
state.inIteration = oldInIteration;
3411
3412
return (typeof left === 'undefined') ?
3413
node.finishForStatement(init, test, update, body) :
3414
node.finishForInStatement(left, right, body);
3415
}
3416
3417
// 12.7 The continue statement
3418
3419
function parseContinueStatement(node) {
3420
var label = null, key;
3421
3422
expectKeyword('continue');
3423
3424
// Optimize the most common form: 'continue;'.
3425
if (source.charCodeAt(startIndex) === 0x3B) {
3426
lex();
3427
3428
if (!state.inIteration) {
3429
throwError(Messages.IllegalContinue);
3430
}
3431
3432
return node.finishContinueStatement(null);
3433
}
3434
3435
if (hasLineTerminator) {
3436
if (!state.inIteration) {
3437
throwError(Messages.IllegalContinue);
3438
}
3439
3440
return node.finishContinueStatement(null);
3441
}
3442
3443
if (lookahead.type === Token.Identifier) {
3444
label = parseVariableIdentifier();
3445
3446
key = '$' + label.name;
3447
if (!Object.prototype.hasOwnProperty.call(state.labelSet, key)) {
3448
throwError(Messages.UnknownLabel, label.name);
3449
}
3450
}
3451
3452
consumeSemicolon();
3453
3454
if (label === null && !state.inIteration) {
3455
throwError(Messages.IllegalContinue);
3456
}
3457
3458
return node.finishContinueStatement(label);
3459
}
3460
3461
// 12.8 The break statement
3462
3463
function parseBreakStatement(node) {
3464
var label = null, key;
3465
3466
expectKeyword('break');
3467
3468
// Catch the very common case first: immediately a semicolon (U+003B).
3469
if (source.charCodeAt(lastIndex) === 0x3B) {
3470
lex();
3471
3472
if (!(state.inIteration || state.inSwitch)) {
3473
throwError(Messages.IllegalBreak);
3474
}
3475
3476
return node.finishBreakStatement(null);
3477
}
3478
3479
if (hasLineTerminator) {
3480
if (!(state.inIteration || state.inSwitch)) {
3481
throwError(Messages.IllegalBreak);
3482
}
3483
3484
return node.finishBreakStatement(null);
3485
}
3486
3487
if (lookahead.type === Token.Identifier) {
3488
label = parseVariableIdentifier();
3489
3490
key = '$' + label.name;
3491
if (!Object.prototype.hasOwnProperty.call(state.labelSet, key)) {
3492
throwError(Messages.UnknownLabel, label.name);
3493
}
3494
}
3495
3496
consumeSemicolon();
3497
3498
if (label === null && !(state.inIteration || state.inSwitch)) {
3499
throwError(Messages.IllegalBreak);
3500
}
3501
3502
return node.finishBreakStatement(label);
3503
}
3504
3505
// 12.9 The return statement
3506
3507
function parseReturnStatement(node) {
3508
var argument = null;
3509
3510
expectKeyword('return');
3511
3512
if (!state.inFunctionBody) {
3513
tolerateError(Messages.IllegalReturn);
3514
}
3515
3516
// 'return' followed by a space and an identifier is very common.
3517
if (source.charCodeAt(lastIndex) === 0x20) {
3518
if (isIdentifierStart(source.charCodeAt(lastIndex + 1))) {
3519
argument = parseExpression();
3520
consumeSemicolon();
3521
return node.finishReturnStatement(argument);
3522
}
3523
}
3524
3525
if (hasLineTerminator) {
3526
// HACK
3527
return node.finishReturnStatement(null);
3528
}
3529
3530
if (!match(';')) {
3531
if (!match('}') && lookahead.type !== Token.EOF) {
3532
argument = parseExpression();
3533
}
3534
}
3535
3536
consumeSemicolon();
3537
3538
return node.finishReturnStatement(argument);
3539
}
3540
3541
// 12.10 The with statement
3542
3543
function parseWithStatement(node) {
3544
var object, body;
3545
3546
if (strict) {
3547
tolerateError(Messages.StrictModeWith);
3548
}
3549
3550
expectKeyword('with');
3551
3552
expect('(');
3553
3554
object = parseExpression();
3555
3556
expect(')');
3557
3558
body = parseStatement();
3559
3560
return node.finishWithStatement(object, body);
3561
}
3562
3563
// 12.10 The swith statement
3564
3565
function parseSwitchCase() {
3566
var test, consequent = [], statement, node = new Node();
3567
3568
if (matchKeyword('default')) {
3569
lex();
3570
test = null;
3571
} else {
3572
expectKeyword('case');
3573
test = parseExpression();
3574
}
3575
expect(':');
3576
3577
while (startIndex < length) {
3578
if (match('}') || matchKeyword('default') || matchKeyword('case')) {
3579
break;
3580
}
3581
statement = parseStatementListItem();
3582
consequent.push(statement);
3583
}
3584
3585
return node.finishSwitchCase(test, consequent);
3586
}
3587
3588
function parseSwitchStatement(node) {
3589
var discriminant, cases, clause, oldInSwitch, defaultFound;
3590
3591
expectKeyword('switch');
3592
3593
expect('(');
3594
3595
discriminant = parseExpression();
3596
3597
expect(')');
3598
3599
expect('{');
3600
3601
cases = [];
3602
3603
if (match('}')) {
3604
lex();
3605
return node.finishSwitchStatement(discriminant, cases);
3606
}
3607
3608
oldInSwitch = state.inSwitch;
3609
state.inSwitch = true;
3610
defaultFound = false;
3611
3612
while (startIndex < length) {
3613
if (match('}')) {
3614
break;
3615
}
3616
clause = parseSwitchCase();
3617
if (clause.test === null) {
3618
if (defaultFound) {
3619
throwError(Messages.MultipleDefaultsInSwitch);
3620
}
3621
defaultFound = true;
3622
}
3623
cases.push(clause);
3624
}
3625
3626
state.inSwitch = oldInSwitch;
3627
3628
expect('}');
3629
3630
return node.finishSwitchStatement(discriminant, cases);
3631
}
3632
3633
// 12.13 The throw statement
3634
3635
function parseThrowStatement(node) {
3636
var argument;
3637
3638
expectKeyword('throw');
3639
3640
if (hasLineTerminator) {
3641
throwError(Messages.NewlineAfterThrow);
3642
}
3643
3644
argument = parseExpression();
3645
3646
consumeSemicolon();
3647
3648
return node.finishThrowStatement(argument);
3649
}
3650
3651
// 12.14 The try statement
3652
3653
function parseCatchClause() {
3654
var param, body, node = new Node();
3655
3656
expectKeyword('catch');
3657
3658
expect('(');
3659
if (match(')')) {
3660
throwUnexpectedToken(lookahead);
3661
}
3662
3663
param = parseVariableIdentifier();
3664
// 12.14.1
3665
if (strict && isRestrictedWord(param.name)) {
3666
tolerateError(Messages.StrictCatchVariable);
3667
}
3668
3669
expect(')');
3670
body = parseBlock();
3671
return node.finishCatchClause(param, body);
3672
}
3673
3674
function parseTryStatement(node) {
3675
var block, handler = null, finalizer = null;
3676
3677
expectKeyword('try');
3678
3679
block = parseBlock();
3680
3681
if (matchKeyword('catch')) {
3682
handler = parseCatchClause();
3683
}
3684
3685
if (matchKeyword('finally')) {
3686
lex();
3687
finalizer = parseBlock();
3688
}
3689
3690
if (!handler && !finalizer) {
3691
throwError(Messages.NoCatchOrFinally);
3692
}
3693
3694
return node.finishTryStatement(block, handler, finalizer);
3695
}
3696
3697
// 12.15 The debugger statement
3698
3699
function parseDebuggerStatement(node) {
3700
expectKeyword('debugger');
3701
3702
consumeSemicolon();
3703
3704
return node.finishDebuggerStatement();
3705
}
3706
3707
// 12 Statements
3708
3709
function parseStatement() {
3710
var type = lookahead.type,
3711
expr,
3712
labeledBody,
3713
key,
3714
node;
3715
3716
if (type === Token.EOF) {
3717
throwUnexpectedToken(lookahead);
3718
}
3719
3720
if (type === Token.Punctuator && lookahead.value === '{') {
3721
return parseBlock();
3722
}
3723
3724
node = new Node();
3725
3726
if (type === Token.Punctuator) {
3727
switch (lookahead.value) {
3728
case ';':
3729
return parseEmptyStatement(node);
3730
case '(':
3731
return parseExpressionStatement(node);
3732
default:
3733
break;
3734
}
3735
} else if (type === Token.Keyword) {
3736
switch (lookahead.value) {
3737
case 'break':
3738
return parseBreakStatement(node);
3739
case 'continue':
3740
return parseContinueStatement(node);
3741
case 'debugger':
3742
return parseDebuggerStatement(node);
3743
case 'do':
3744
return parseDoWhileStatement(node);
3745
case 'for':
3746
return parseForStatement(node);
3747
case 'function':
3748
return parseFunctionDeclaration(node);
3749
case 'if':
3750
return parseIfStatement(node);
3751
case 'return':
3752
return parseReturnStatement(node);
3753
case 'switch':
3754
return parseSwitchStatement(node);
3755
case 'throw':
3756
return parseThrowStatement(node);
3757
case 'try':
3758
return parseTryStatement(node);
3759
case 'var':
3760
return parseVariableStatement(node);
3761
case 'while':
3762
return parseWhileStatement(node);
3763
case 'with':
3764
return parseWithStatement(node);
3765
default:
3766
break;
3767
}
3768
}
3769
3770
expr = parseExpression();
3771
3772
// 12.12 Labelled Statements
3773
if ((expr.type === Syntax.Identifier) && match(':')) {
3774
lex();
3775
3776
key = '$' + expr.name;
3777
if (Object.prototype.hasOwnProperty.call(state.labelSet, key)) {
3778
throwError(Messages.Redeclaration, 'Label', expr.name);
3779
}
3780
3781
state.labelSet[key] = true;
3782
labeledBody = parseStatement();
3783
delete state.labelSet[key];
3784
return node.finishLabeledStatement(expr, labeledBody);
3785
}
3786
3787
consumeSemicolon();
3788
3789
return node.finishExpressionStatement(expr);
3790
}
3791
3792
// 13 Function Definition
3793
3794
function parseFunctionSourceElements() {
3795
var statement, body = [], token, directive, firstRestricted,
3796
oldLabelSet, oldInIteration, oldInSwitch, oldInFunctionBody, oldParenthesisCount,
3797
node = new Node();
3798
3799
expect('{');
3800
3801
while (startIndex < length) {
3802
if (lookahead.type !== Token.StringLiteral) {
3803
break;
3804
}
3805
token = lookahead;
3806
3807
statement = parseStatementListItem();
3808
body.push(statement);
3809
if (statement.expression.type !== Syntax.Literal) {
3810
// this is not directive
3811
break;
3812
}
3813
directive = source.slice(token.start + 1, token.end - 1);
3814
if (directive === 'use strict') {
3815
strict = true;
3816
if (firstRestricted) {
3817
tolerateUnexpectedToken(firstRestricted, Messages.StrictOctalLiteral);
3818
}
3819
} else {
3820
if (!firstRestricted && token.octal) {
3821
firstRestricted = token;
3822
}
3823
}
3824
}
3825
3826
oldLabelSet = state.labelSet;
3827
oldInIteration = state.inIteration;
3828
oldInSwitch = state.inSwitch;
3829
oldInFunctionBody = state.inFunctionBody;
3830
oldParenthesisCount = state.parenthesizedCount;
3831
3832
state.labelSet = {};
3833
state.inIteration = false;
3834
state.inSwitch = false;
3835
state.inFunctionBody = true;
3836
state.parenthesizedCount = 0;
3837
3838
while (startIndex < length) {
3839
if (match('}')) {
3840
break;
3841
}
3842
body.push(parseStatementListItem());
3843
}
3844
3845
expect('}');
3846
3847
state.labelSet = oldLabelSet;
3848
state.inIteration = oldInIteration;
3849
state.inSwitch = oldInSwitch;
3850
state.inFunctionBody = oldInFunctionBody;
3851
state.parenthesizedCount = oldParenthesisCount;
3852
3853
return node.finishBlockStatement(body);
3854
}
3855
3856
function validateParam(options, param, name) {
3857
var key = '$' + name;
3858
if (strict) {
3859
if (isRestrictedWord(name)) {
3860
options.stricted = param;
3861
options.message = Messages.StrictParamName;
3862
}
3863
if (Object.prototype.hasOwnProperty.call(options.paramSet, key)) {
3864
options.stricted = param;
3865
options.message = Messages.StrictParamDupe;
3866
}
3867
} else if (!options.firstRestricted) {
3868
if (isRestrictedWord(name)) {
3869
options.firstRestricted = param;
3870
options.message = Messages.StrictParamName;
3871
} else if (isStrictModeReservedWord(name)) {
3872
options.firstRestricted = param;
3873
options.message = Messages.StrictReservedWord;
3874
} else if (Object.prototype.hasOwnProperty.call(options.paramSet, key)) {
3875
options.firstRestricted = param;
3876
options.message = Messages.StrictParamDupe;
3877
}
3878
}
3879
options.paramSet[key] = true;
3880
}
3881
3882
function parseParam(options) {
3883
var token, param, def;
3884
3885
token = lookahead;
3886
if (token.value === '...') {
3887
param = parseRestElement();
3888
validateParam(options, param.argument, param.argument.name);
3889
options.params.push(param);
3890
options.defaults.push(null);
3891
return false;
3892
}
3893
3894
param = parseVariableIdentifier();
3895
validateParam(options, token, token.value);
3896
3897
if (match('=')) {
3898
lex();
3899
def = parseAssignmentExpression();
3900
++options.defaultCount;
3901
}
3902
3903
options.params.push(param);
3904
options.defaults.push(def);
3905
3906
return !match(')');
3907
}
3908
3909
function parseParams(firstRestricted) {
3910
var options;
3911
3912
options = {
3913
params: [],
3914
defaultCount: 0,
3915
defaults: [],
3916
firstRestricted: firstRestricted
3917
};
3918
3919
expect('(');
3920
3921
if (!match(')')) {
3922
options.paramSet = {};
3923
while (startIndex < length) {
3924
if (!parseParam(options)) {
3925
break;
3926
}
3927
expect(',');
3928
}
3929
}
3930
3931
expect(')');
3932
3933
if (options.defaultCount === 0) {
3934
options.defaults = [];
3935
}
3936
3937
return {
3938
params: options.params,
3939
defaults: options.defaults,
3940
stricted: options.stricted,
3941
firstRestricted: options.firstRestricted,
3942
message: options.message
3943
};
3944
}
3945
3946
function parseFunctionDeclaration(node) {
3947
var id, params = [], defaults = [], body, token, stricted, tmp, firstRestricted, message, previousStrict;
3948
3949
expectKeyword('function');
3950
token = lookahead;
3951
id = parseVariableIdentifier();
3952
if (strict) {
3953
if (isRestrictedWord(token.value)) {
3954
tolerateUnexpectedToken(token, Messages.StrictFunctionName);
3955
}
3956
} else {
3957
if (isRestrictedWord(token.value)) {
3958
firstRestricted = token;
3959
message = Messages.StrictFunctionName;
3960
} else if (isStrictModeReservedWord(token.value)) {
3961
firstRestricted = token;
3962
message = Messages.StrictReservedWord;
3963
}
3964
}
3965
3966
tmp = parseParams(firstRestricted);
3967
params = tmp.params;
3968
defaults = tmp.defaults;
3969
stricted = tmp.stricted;
3970
firstRestricted = tmp.firstRestricted;
3971
if (tmp.message) {
3972
message = tmp.message;
3973
}
3974
3975
previousStrict = strict;
3976
body = parseFunctionSourceElements();
3977
if (strict && firstRestricted) {
3978
throwUnexpectedToken(firstRestricted, message);
3979
}
3980
if (strict && stricted) {
3981
tolerateUnexpectedToken(stricted, message);
3982
}
3983
strict = previousStrict;
3984
3985
return node.finishFunctionDeclaration(id, params, defaults, body);
3986
}
3987
3988
function parseFunctionExpression() {
3989
var token, id = null, stricted, firstRestricted, message, tmp,
3990
params = [], defaults = [], body, previousStrict, node = new Node();
3991
3992
expectKeyword('function');
3993
3994
if (!match('(')) {
3995
token = lookahead;
3996
id = parseVariableIdentifier();
3997
if (strict) {
3998
if (isRestrictedWord(token.value)) {
3999
tolerateUnexpectedToken(token, Messages.StrictFunctionName);
4000
}
4001
} else {
4002
if (isRestrictedWord(token.value)) {
4003
firstRestricted = token;
4004
message = Messages.StrictFunctionName;
4005
} else if (isStrictModeReservedWord(token.value)) {
4006
firstRestricted = token;
4007
message = Messages.StrictReservedWord;
4008
}
4009
}
4010
}
4011
4012
tmp = parseParams(firstRestricted);
4013
params = tmp.params;
4014
defaults = tmp.defaults;
4015
stricted = tmp.stricted;
4016
firstRestricted = tmp.firstRestricted;
4017
if (tmp.message) {
4018
message = tmp.message;
4019
}
4020
4021
previousStrict = strict;
4022
body = parseFunctionSourceElements();
4023
if (strict && firstRestricted) {
4024
throwUnexpectedToken(firstRestricted, message);
4025
}
4026
if (strict && stricted) {
4027
tolerateUnexpectedToken(stricted, message);
4028
}
4029
strict = previousStrict;
4030
4031
return node.finishFunctionExpression(id, params, defaults, body);
4032
}
4033
4034
4035
function parseClassBody() {
4036
var classBody, token, isStatic, hasConstructor = false, body, method, computed, key;
4037
4038
classBody = new Node();
4039
4040
expect('{');
4041
body = [];
4042
while (!match('}')) {
4043
if (match(';')) {
4044
lex();
4045
} else {
4046
method = new Node();
4047
token = lookahead;
4048
isStatic = false;
4049
computed = match('[');
4050
key = parseObjectPropertyKey();
4051
if (key.name === 'static' && lookaheadPropertyName()) {
4052
token = lookahead;
4053
isStatic = true;
4054
computed = match('[');
4055
key = parseObjectPropertyKey();
4056
}
4057
method = tryParseMethodDefinition(token, key, computed, method);
4058
if (method) {
4059
method.static = isStatic;
4060
if (method.kind === 'init') {
4061
method.kind = 'method';
4062
}
4063
if (!isStatic) {
4064
if (!method.computed && (method.key.name || method.key.value.toString()) === 'constructor') {
4065
if (method.kind !== 'method' || !method.method || method.value.generator) {
4066
throwUnexpectedToken(token, Messages.ConstructorSpecialMethod);
4067
}
4068
if (hasConstructor) {
4069
throwUnexpectedToken(token, Messages.DuplicateConstructor);
4070
} else {
4071
hasConstructor = true;
4072
}
4073
method.kind = 'constructor';
4074
}
4075
} else {
4076
if (!method.computed && (method.key.name || method.key.value.toString()) === 'prototype') {
4077
throwUnexpectedToken(token, Messages.StaticPrototype);
4078
}
4079
}
4080
method.type = Syntax.MethodDefinition;
4081
delete method.method;
4082
delete method.shorthand;
4083
body.push(method);
4084
} else {
4085
throwUnexpectedToken(lookahead);
4086
}
4087
}
4088
}
4089
lex();
4090
return classBody.finishClassBody(body);
4091
}
4092
4093
function parseClassDeclaration() {
4094
var id = null, superClass = null, classNode = new Node(), classBody, previousStrict = strict;
4095
strict = true;
4096
4097
expectKeyword('class');
4098
4099
id = parseVariableIdentifier();
4100
4101
if (matchKeyword('extends')) {
4102
lex();
4103
superClass = parseLeftHandSideExpressionAllowCall();
4104
}
4105
classBody = parseClassBody();
4106
strict = previousStrict;
4107
4108
return classNode.finishClassDeclaration(id, superClass, classBody);
4109
}
4110
4111
function parseClassExpression() {
4112
var id = null, superClass = null, classNode = new Node(), classBody, previousStrict = strict;
4113
strict = true;
4114
4115
expectKeyword('class');
4116
4117
if (lookahead.type === Token.Identifier) {
4118
id = parseVariableIdentifier();
4119
}
4120
4121
if (matchKeyword('extends')) {
4122
lex();
4123
superClass = parseLeftHandSideExpressionAllowCall();
4124
}
4125
classBody = parseClassBody();
4126
strict = previousStrict;
4127
4128
return classNode.finishClassExpression(id, superClass, classBody);
4129
}
4130
4131
// 14 Program
4132
4133
function parseScriptBody() {
4134
var statement, body = [], token, directive, firstRestricted;
4135
4136
while (startIndex < length) {
4137
token = lookahead;
4138
if (token.type !== Token.StringLiteral) {
4139
break;
4140
}
4141
4142
statement = parseStatementListItem();
4143
body.push(statement);
4144
if (statement.expression.type !== Syntax.Literal) {
4145
// this is not directive
4146
break;
4147
}
4148
directive = source.slice(token.start + 1, token.end - 1);
4149
if (directive === 'use strict') {
4150
strict = true;
4151
if (firstRestricted) {
4152
tolerateUnexpectedToken(firstRestricted, Messages.StrictOctalLiteral);
4153
}
4154
} else {
4155
if (!firstRestricted && token.octal) {
4156
firstRestricted = token;
4157
}
4158
}
4159
}
4160
4161
while (startIndex < length) {
4162
statement = parseStatementListItem();
4163
/* istanbul ignore if */
4164
if (typeof statement === 'undefined') {
4165
break;
4166
}
4167
body.push(statement);
4168
}
4169
return body;
4170
}
4171
4172
function parseProgram() {
4173
var body, node;
4174
4175
peek();
4176
node = new Node();
4177
strict = false;
4178
4179
body = parseScriptBody();
4180
return node.finishProgram(body);
4181
}
4182
4183
function filterTokenLocation() {
4184
var i, entry, token, tokens = [];
4185
4186
for (i = 0; i < extra.tokens.length; ++i) {
4187
entry = extra.tokens[i];
4188
token = {
4189
type: entry.type,
4190
value: entry.value
4191
};
4192
if (entry.regex) {
4193
token.regex = {
4194
pattern: entry.regex.pattern,
4195
flags: entry.regex.flags
4196
};
4197
}
4198
if (extra.range) {
4199
token.range = entry.range;
4200
}
4201
if (extra.loc) {
4202
token.loc = entry.loc;
4203
}
4204
tokens.push(token);
4205
}
4206
4207
extra.tokens = tokens;
4208
}
4209
4210
function tokenize(code, options) {
4211
var toString,
4212
tokens;
4213
4214
toString = String;
4215
if (typeof code !== 'string' && !(code instanceof String)) {
4216
code = toString(code);
4217
}
4218
4219
source = code;
4220
index = 0;
4221
lineNumber = (source.length > 0) ? 1 : 0;
4222
lineStart = 0;
4223
startIndex = index;
4224
startLineNumber = lineNumber;
4225
startLineStart = lineStart;
4226
length = source.length;
4227
lookahead = null;
4228
state = {
4229
allowIn: true,
4230
labelSet: {},
4231
inFunctionBody: false,
4232
inIteration: false,
4233
inSwitch: false,
4234
lastCommentStart: -1
4235
};
4236
4237
extra = {};
4238
4239
// Options matching.
4240
options = options || {};
4241
4242
// Of course we collect tokens here.
4243
options.tokens = true;
4244
extra.tokens = [];
4245
extra.tokenize = true;
4246
// The following two fields are necessary to compute the Regex tokens.
4247
extra.openParenToken = -1;
4248
extra.openCurlyToken = -1;
4249
4250
extra.range = (typeof options.range === 'boolean') && options.range;
4251
extra.loc = (typeof options.loc === 'boolean') && options.loc;
4252
4253
if (typeof options.comment === 'boolean' && options.comment) {
4254
extra.comments = [];
4255
}
4256
if (typeof options.tolerant === 'boolean' && options.tolerant) {
4257
extra.errors = [];
4258
}
4259
4260
try {
4261
peek();
4262
if (lookahead.type === Token.EOF) {
4263
return extra.tokens;
4264
}
4265
4266
lex();
4267
while (lookahead.type !== Token.EOF) {
4268
try {
4269
lex();
4270
} catch (lexError) {
4271
if (extra.errors) {
4272
recordError(lexError);
4273
// We have to break on the first error
4274
// to avoid infinite loops.
4275
break;
4276
} else {
4277
throw lexError;
4278
}
4279
}
4280
}
4281
4282
filterTokenLocation();
4283
tokens = extra.tokens;
4284
if (typeof extra.comments !== 'undefined') {
4285
tokens.comments = extra.comments;
4286
}
4287
if (typeof extra.errors !== 'undefined') {
4288
tokens.errors = extra.errors;
4289
}
4290
} catch (e) {
4291
throw e;
4292
} finally {
4293
extra = {};
4294
}
4295
return tokens;
4296
}
4297
4298
function parse(code, options) {
4299
var program, toString;
4300
4301
toString = String;
4302
if (typeof code !== 'string' && !(code instanceof String)) {
4303
code = toString(code);
4304
}
4305
4306
source = code;
4307
index = 0;
4308
lineNumber = (source.length > 0) ? 1 : 0;
4309
lineStart = 0;
4310
startIndex = index;
4311
startLineNumber = lineNumber;
4312
startLineStart = lineStart;
4313
length = source.length;
4314
lookahead = null;
4315
state = {
4316
allowIn: true,
4317
labelSet: {},
4318
inFunctionBody: false,
4319
inIteration: false,
4320
inSwitch: false,
4321
lastCommentStart: -1
4322
};
4323
4324
extra = {};
4325
if (typeof options !== 'undefined') {
4326
extra.range = (typeof options.range === 'boolean') && options.range;
4327
extra.loc = (typeof options.loc === 'boolean') && options.loc;
4328
extra.attachComment = (typeof options.attachComment === 'boolean') && options.attachComment;
4329
4330
if (extra.loc && options.source !== null && options.source !== undefined) {
4331
extra.source = toString(options.source);
4332
}
4333
4334
if (typeof options.tokens === 'boolean' && options.tokens) {
4335
extra.tokens = [];
4336
}
4337
if (typeof options.comment === 'boolean' && options.comment) {
4338
extra.comments = [];
4339
}
4340
if (typeof options.tolerant === 'boolean' && options.tolerant) {
4341
extra.errors = [];
4342
}
4343
if (extra.attachComment) {
4344
extra.range = true;
4345
extra.comments = [];
4346
extra.bottomRightStack = [];
4347
extra.trailingComments = [];
4348
extra.leadingComments = [];
4349
}
4350
}
4351
4352
try {
4353
program = parseProgram();
4354
if (typeof extra.comments !== 'undefined') {
4355
program.comments = extra.comments;
4356
}
4357
if (typeof extra.tokens !== 'undefined') {
4358
filterTokenLocation();
4359
program.tokens = extra.tokens;
4360
}
4361
if (typeof extra.errors !== 'undefined') {
4362
program.errors = extra.errors;
4363
}
4364
} catch (e) {
4365
throw e;
4366
} finally {
4367
extra = {};
4368
}
4369
4370
return program;
4371
}
4372
4373
// Sync with *.json manifests.
4374
exports.version = '2.1.0';
4375
4376
exports.tokenize = tokenize;
4377
4378
exports.parse = parse;
4379
4380
// Deep copy.
4381
/* istanbul ignore next */
4382
exports.Syntax = (function () {
4383
var name, types = {};
4384
4385
if (typeof Object.create === 'function') {
4386
types = Object.create(null);
4387
}
4388
4389
for (name in Syntax) {
4390
if (Syntax.hasOwnProperty(name)) {
4391
types[name] = Syntax[name];
4392
}
4393
}
4394
4395
if (typeof Object.freeze === 'function') {
4396
Object.freeze(types);
4397
}
4398
4399
return types;
4400
}());
4401
4402
}));
4403
/* vim: set sw=4 ts=4 et tw=80 : */
4404
4405