Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
80699 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
sourceType,
61
index,
62
lineNumber,
63
lineStart,
64
hasLineTerminator,
65
lastIndex,
66
lastLineNumber,
67
lastLineStart,
68
startIndex,
69
startLineNumber,
70
startLineStart,
71
scanning,
72
length,
73
lookahead,
74
state,
75
extra,
76
isBindingElement,
77
isAssignmentTarget,
78
firstCoverInitializedNameError;
79
80
Token = {
81
BooleanLiteral: 1,
82
EOF: 2,
83
Identifier: 3,
84
Keyword: 4,
85
NullLiteral: 5,
86
NumericLiteral: 6,
87
Punctuator: 7,
88
StringLiteral: 8,
89
RegularExpression: 9,
90
Template: 10
91
};
92
93
TokenName = {};
94
TokenName[Token.BooleanLiteral] = 'Boolean';
95
TokenName[Token.EOF] = '<end>';
96
TokenName[Token.Identifier] = 'Identifier';
97
TokenName[Token.Keyword] = 'Keyword';
98
TokenName[Token.NullLiteral] = 'Null';
99
TokenName[Token.NumericLiteral] = 'Numeric';
100
TokenName[Token.Punctuator] = 'Punctuator';
101
TokenName[Token.StringLiteral] = 'String';
102
TokenName[Token.RegularExpression] = 'RegularExpression';
103
TokenName[Token.Template] = 'Template';
104
105
// A function following one of those tokens is an expression.
106
FnExprTokens = ['(', '{', '[', 'in', 'typeof', 'instanceof', 'new',
107
'return', 'case', 'delete', 'throw', 'void',
108
// assignment operators
109
'=', '+=', '-=', '*=', '/=', '%=', '<<=', '>>=', '>>>=',
110
'&=', '|=', '^=', ',',
111
// binary/unary operators
112
'+', '-', '*', '/', '%', '++', '--', '<<', '>>', '>>>', '&',
113
'|', '^', '!', '~', '&&', '||', '?', ':', '===', '==', '>=',
114
'<=', '<', '>', '!=', '!=='];
115
116
Syntax = {
117
AssignmentExpression: 'AssignmentExpression',
118
AssignmentPattern: 'AssignmentPattern',
119
ArrayExpression: 'ArrayExpression',
120
ArrayPattern: 'ArrayPattern',
121
ArrowFunctionExpression: 'ArrowFunctionExpression',
122
BlockStatement: 'BlockStatement',
123
BinaryExpression: 'BinaryExpression',
124
BreakStatement: 'BreakStatement',
125
CallExpression: 'CallExpression',
126
CatchClause: 'CatchClause',
127
ClassBody: 'ClassBody',
128
ClassDeclaration: 'ClassDeclaration',
129
ClassExpression: 'ClassExpression',
130
ConditionalExpression: 'ConditionalExpression',
131
ContinueStatement: 'ContinueStatement',
132
DoWhileStatement: 'DoWhileStatement',
133
DebuggerStatement: 'DebuggerStatement',
134
EmptyStatement: 'EmptyStatement',
135
ExportAllDeclaration: 'ExportAllDeclaration',
136
ExportDefaultDeclaration: 'ExportDefaultDeclaration',
137
ExportNamedDeclaration: 'ExportNamedDeclaration',
138
ExportSpecifier: 'ExportSpecifier',
139
ExpressionStatement: 'ExpressionStatement',
140
ForStatement: 'ForStatement',
141
ForInStatement: 'ForInStatement',
142
FunctionDeclaration: 'FunctionDeclaration',
143
FunctionExpression: 'FunctionExpression',
144
Identifier: 'Identifier',
145
IfStatement: 'IfStatement',
146
ImportDeclaration: 'ImportDeclaration',
147
ImportDefaultSpecifier: 'ImportDefaultSpecifier',
148
ImportNamespaceSpecifier: 'ImportNamespaceSpecifier',
149
ImportSpecifier: 'ImportSpecifier',
150
Literal: 'Literal',
151
LabeledStatement: 'LabeledStatement',
152
LogicalExpression: 'LogicalExpression',
153
MemberExpression: 'MemberExpression',
154
MethodDefinition: 'MethodDefinition',
155
NewExpression: 'NewExpression',
156
ObjectExpression: 'ObjectExpression',
157
ObjectPattern: 'ObjectPattern',
158
Program: 'Program',
159
Property: 'Property',
160
RestElement: 'RestElement',
161
ReturnStatement: 'ReturnStatement',
162
SequenceExpression: 'SequenceExpression',
163
SpreadElement: 'SpreadElement',
164
Super: 'Super',
165
SwitchCase: 'SwitchCase',
166
SwitchStatement: 'SwitchStatement',
167
TaggedTemplateExpression: 'TaggedTemplateExpression',
168
TemplateElement: 'TemplateElement',
169
TemplateLiteral: 'TemplateLiteral',
170
ThisExpression: 'ThisExpression',
171
ThrowStatement: 'ThrowStatement',
172
TryStatement: 'TryStatement',
173
UnaryExpression: 'UnaryExpression',
174
UpdateExpression: 'UpdateExpression',
175
VariableDeclaration: 'VariableDeclaration',
176
VariableDeclarator: 'VariableDeclarator',
177
WhileStatement: 'WhileStatement',
178
WithStatement: 'WithStatement'
179
};
180
181
PlaceHolders = {
182
ArrowParameterPlaceHolder: 'ArrowParameterPlaceHolder'
183
};
184
185
// Error messages should be identical to V8.
186
Messages = {
187
UnexpectedToken: 'Unexpected token %0',
188
UnexpectedNumber: 'Unexpected number',
189
UnexpectedString: 'Unexpected string',
190
UnexpectedIdentifier: 'Unexpected identifier',
191
UnexpectedReserved: 'Unexpected reserved word',
192
UnexpectedTemplate: 'Unexpected quasi %0',
193
UnexpectedEOS: 'Unexpected end of input',
194
NewlineAfterThrow: 'Illegal newline after throw',
195
InvalidRegExp: 'Invalid regular expression',
196
UnterminatedRegExp: 'Invalid regular expression: missing /',
197
InvalidLHSInAssignment: 'Invalid left-hand side in assignment',
198
InvalidLHSInForIn: 'Invalid left-hand side in for-in',
199
MultipleDefaultsInSwitch: 'More than one default clause in switch statement',
200
NoCatchOrFinally: 'Missing catch or finally after try',
201
UnknownLabel: 'Undefined label \'%0\'',
202
Redeclaration: '%0 \'%1\' has already been declared',
203
IllegalContinue: 'Illegal continue statement',
204
IllegalBreak: 'Illegal break statement',
205
IllegalReturn: 'Illegal return statement',
206
StrictModeWith: 'Strict mode code may not include a with statement',
207
StrictCatchVariable: 'Catch variable may not be eval or arguments in strict mode',
208
StrictVarName: 'Variable name may not be eval or arguments in strict mode',
209
StrictParamName: 'Parameter name eval or arguments is not allowed in strict mode',
210
StrictParamDupe: 'Strict mode function may not have duplicate parameter names',
211
StrictFunctionName: 'Function name may not be eval or arguments in strict mode',
212
StrictOctalLiteral: 'Octal literals are not allowed in strict mode.',
213
StrictDelete: 'Delete of an unqualified identifier in strict mode.',
214
StrictLHSAssignment: 'Assignment to eval or arguments is not allowed in strict mode',
215
StrictLHSPostfix: 'Postfix increment/decrement may not have eval or arguments operand in strict mode',
216
StrictLHSPrefix: 'Prefix increment/decrement may not have eval or arguments operand in strict mode',
217
StrictReservedWord: 'Use of future reserved word in strict mode',
218
TemplateOctalLiteral: 'Octal literals are not allowed in template strings.',
219
ParameterAfterRestParameter: 'Rest parameter must be last formal parameter',
220
DefaultRestParameter: 'Unexpected token =',
221
ObjectPatternAsRestParameter: 'Unexpected token {',
222
DuplicateProtoProperty: 'Duplicate __proto__ fields are not allowed in object literals',
223
ConstructorSpecialMethod: 'Class constructor may not be an accessor',
224
DuplicateConstructor: 'A class may only have one constructor',
225
StaticPrototype: 'Classes may not have static property named prototype',
226
MissingFromClause: 'Unexpected token',
227
NoAsAfterImportNamespace: 'Unexpected token',
228
InvalidModuleSpecifier: 'Unexpected token',
229
IllegalImportDeclaration: 'Unexpected token',
230
IllegalExportDeclaration: 'Unexpected token'
231
};
232
233
// See also tools/generate-unicode-regex.py.
234
Regex = {
235
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]'),
236
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]')
237
};
238
239
// Ensure the condition is true, otherwise throw an error.
240
// This is only to have a better contract semantic, i.e. another safety net
241
// to catch a logic error. The condition shall be fulfilled in normal case.
242
// Do NOT use this to enforce a certain condition on any user input.
243
244
function assert(condition, message) {
245
/* istanbul ignore if */
246
if (!condition) {
247
throw new Error('ASSERT: ' + message);
248
}
249
}
250
251
function isDecimalDigit(ch) {
252
return (ch >= 0x30 && ch <= 0x39); // 0..9
253
}
254
255
function isHexDigit(ch) {
256
return '0123456789abcdefABCDEF'.indexOf(ch) >= 0;
257
}
258
259
function isOctalDigit(ch) {
260
return '01234567'.indexOf(ch) >= 0;
261
}
262
263
function octalToDecimal(ch) {
264
// \0 is not octal escape sequence
265
var octal = (ch !== '0'), code = '01234567'.indexOf(ch);
266
267
if (index < length && isOctalDigit(source[index])) {
268
octal = true;
269
code = code * 8 + '01234567'.indexOf(source[index++]);
270
271
// 3 digits are only allowed when string starts
272
// with 0, 1, 2, 3
273
if ('0123'.indexOf(ch) >= 0 &&
274
index < length &&
275
isOctalDigit(source[index])) {
276
code = code * 8 + '01234567'.indexOf(source[index++]);
277
}
278
}
279
280
return {
281
code: code,
282
octal: octal
283
};
284
}
285
286
// 7.2 White Space
287
288
function isWhiteSpace(ch) {
289
return (ch === 0x20) || (ch === 0x09) || (ch === 0x0B) || (ch === 0x0C) || (ch === 0xA0) ||
290
(ch >= 0x1680 && [0x1680, 0x180E, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008, 0x2009, 0x200A, 0x202F, 0x205F, 0x3000, 0xFEFF].indexOf(ch) >= 0);
291
}
292
293
// 7.3 Line Terminators
294
295
function isLineTerminator(ch) {
296
return (ch === 0x0A) || (ch === 0x0D) || (ch === 0x2028) || (ch === 0x2029);
297
}
298
299
// 7.6 Identifier Names and Identifiers
300
301
function isIdentifierStart(ch) {
302
return (ch === 0x24) || (ch === 0x5F) || // $ (dollar) and _ (underscore)
303
(ch >= 0x41 && ch <= 0x5A) || // A..Z
304
(ch >= 0x61 && ch <= 0x7A) || // a..z
305
(ch === 0x5C) || // \ (backslash)
306
((ch >= 0x80) && Regex.NonAsciiIdentifierStart.test(String.fromCharCode(ch)));
307
}
308
309
function isIdentifierPart(ch) {
310
return (ch === 0x24) || (ch === 0x5F) || // $ (dollar) and _ (underscore)
311
(ch >= 0x41 && ch <= 0x5A) || // A..Z
312
(ch >= 0x61 && ch <= 0x7A) || // a..z
313
(ch >= 0x30 && ch <= 0x39) || // 0..9
314
(ch === 0x5C) || // \ (backslash)
315
((ch >= 0x80) && Regex.NonAsciiIdentifierPart.test(String.fromCharCode(ch)));
316
}
317
318
// 7.6.1.2 Future Reserved Words
319
320
function isFutureReservedWord(id) {
321
switch (id) {
322
case 'enum':
323
case 'export':
324
case 'import':
325
case 'super':
326
return true;
327
default:
328
return false;
329
}
330
}
331
332
// 11.6.2.2 Future Reserved Words
333
334
function isStrictModeReservedWord(id) {
335
switch (id) {
336
case 'implements':
337
case 'interface':
338
case 'package':
339
case 'private':
340
case 'protected':
341
case 'public':
342
case 'static':
343
case 'yield':
344
case 'let':
345
return true;
346
default:
347
return false;
348
}
349
}
350
351
function isRestrictedWord(id) {
352
return id === 'eval' || id === 'arguments';
353
}
354
355
// 7.6.1.1 Keywords
356
357
function isKeyword(id) {
358
359
// 'const' is specialized as Keyword in V8.
360
// 'yield' and 'let' are for compatibility with SpiderMonkey and ES.next.
361
// Some others are from future reserved words.
362
363
switch (id.length) {
364
case 2:
365
return (id === 'if') || (id === 'in') || (id === 'do');
366
case 3:
367
return (id === 'var') || (id === 'for') || (id === 'new') ||
368
(id === 'try') || (id === 'let');
369
case 4:
370
return (id === 'this') || (id === 'else') || (id === 'case') ||
371
(id === 'void') || (id === 'with') || (id === 'enum');
372
case 5:
373
return (id === 'while') || (id === 'break') || (id === 'catch') ||
374
(id === 'throw') || (id === 'const') || (id === 'yield') ||
375
(id === 'class') || (id === 'super');
376
case 6:
377
return (id === 'return') || (id === 'typeof') || (id === 'delete') ||
378
(id === 'switch') || (id === 'export') || (id === 'import');
379
case 7:
380
return (id === 'default') || (id === 'finally') || (id === 'extends');
381
case 8:
382
return (id === 'function') || (id === 'continue') || (id === 'debugger');
383
case 10:
384
return (id === 'instanceof');
385
default:
386
return false;
387
}
388
}
389
390
// 7.4 Comments
391
392
function addComment(type, value, start, end, loc) {
393
var comment;
394
395
assert(typeof start === 'number', 'Comment must have valid position');
396
397
state.lastCommentStart = start;
398
399
comment = {
400
type: type,
401
value: value
402
};
403
if (extra.range) {
404
comment.range = [start, end];
405
}
406
if (extra.loc) {
407
comment.loc = loc;
408
}
409
extra.comments.push(comment);
410
if (extra.attachComment) {
411
extra.leadingComments.push(comment);
412
extra.trailingComments.push(comment);
413
}
414
}
415
416
function skipSingleLineComment(offset) {
417
var start, loc, ch, comment;
418
419
start = index - offset;
420
loc = {
421
start: {
422
line: lineNumber,
423
column: index - lineStart - offset
424
}
425
};
426
427
while (index < length) {
428
ch = source.charCodeAt(index);
429
++index;
430
if (isLineTerminator(ch)) {
431
hasLineTerminator = true;
432
if (extra.comments) {
433
comment = source.slice(start + offset, index - 1);
434
loc.end = {
435
line: lineNumber,
436
column: index - lineStart - 1
437
};
438
addComment('Line', comment, start, index - 1, loc);
439
}
440
if (ch === 13 && source.charCodeAt(index) === 10) {
441
++index;
442
}
443
++lineNumber;
444
lineStart = index;
445
return;
446
}
447
}
448
449
if (extra.comments) {
450
comment = source.slice(start + offset, index);
451
loc.end = {
452
line: lineNumber,
453
column: index - lineStart
454
};
455
addComment('Line', comment, start, index, loc);
456
}
457
}
458
459
function skipMultiLineComment() {
460
var start, loc, ch, comment;
461
462
if (extra.comments) {
463
start = index - 2;
464
loc = {
465
start: {
466
line: lineNumber,
467
column: index - lineStart - 2
468
}
469
};
470
}
471
472
while (index < length) {
473
ch = source.charCodeAt(index);
474
if (isLineTerminator(ch)) {
475
if (ch === 0x0D && source.charCodeAt(index + 1) === 0x0A) {
476
++index;
477
}
478
hasLineTerminator = true;
479
++lineNumber;
480
++index;
481
lineStart = index;
482
} else if (ch === 0x2A) {
483
// Block comment ends with '*/'.
484
if (source.charCodeAt(index + 1) === 0x2F) {
485
++index;
486
++index;
487
if (extra.comments) {
488
comment = source.slice(start + 2, index - 2);
489
loc.end = {
490
line: lineNumber,
491
column: index - lineStart
492
};
493
addComment('Block', comment, start, index, loc);
494
}
495
return;
496
}
497
++index;
498
} else {
499
++index;
500
}
501
}
502
503
// Ran off the end of the file - the whole thing is a comment
504
if (extra.comments) {
505
loc.end = {
506
line: lineNumber,
507
column: index - lineStart
508
};
509
comment = source.slice(start + 2, index);
510
addComment('Block', comment, start, index, loc);
511
}
512
tolerateUnexpectedToken();
513
}
514
515
function skipComment() {
516
var ch, start;
517
hasLineTerminator = false;
518
519
start = (index === 0);
520
while (index < length) {
521
ch = source.charCodeAt(index);
522
523
if (isWhiteSpace(ch)) {
524
++index;
525
} else if (isLineTerminator(ch)) {
526
hasLineTerminator = true;
527
++index;
528
if (ch === 0x0D && source.charCodeAt(index) === 0x0A) {
529
++index;
530
}
531
++lineNumber;
532
lineStart = index;
533
start = true;
534
} else if (ch === 0x2F) { // U+002F is '/'
535
ch = source.charCodeAt(index + 1);
536
if (ch === 0x2F) {
537
++index;
538
++index;
539
skipSingleLineComment(2);
540
start = true;
541
} else if (ch === 0x2A) { // U+002A is '*'
542
++index;
543
++index;
544
skipMultiLineComment();
545
} else {
546
break;
547
}
548
} else if (start && ch === 0x2D) { // U+002D is '-'
549
// U+003E is '>'
550
if ((source.charCodeAt(index + 1) === 0x2D) && (source.charCodeAt(index + 2) === 0x3E)) {
551
// '-->' is a single-line comment
552
index += 3;
553
skipSingleLineComment(3);
554
} else {
555
break;
556
}
557
} else if (ch === 0x3C) { // U+003C is '<'
558
if (source.slice(index + 1, index + 4) === '!--') {
559
++index; // `<`
560
++index; // `!`
561
++index; // `-`
562
++index; // `-`
563
skipSingleLineComment(4);
564
} else {
565
break;
566
}
567
} else {
568
break;
569
}
570
}
571
}
572
573
function scanHexEscape(prefix) {
574
var i, len, ch, code = 0;
575
576
len = (prefix === 'u') ? 4 : 2;
577
for (i = 0; i < len; ++i) {
578
if (index < length && isHexDigit(source[index])) {
579
ch = source[index++];
580
code = code * 16 + '0123456789abcdef'.indexOf(ch.toLowerCase());
581
} else {
582
return '';
583
}
584
}
585
return String.fromCharCode(code);
586
}
587
588
function scanUnicodeCodePointEscape() {
589
var ch, code, cu1, cu2;
590
591
ch = source[index];
592
code = 0;
593
594
// At least, one hex digit is required.
595
if (ch === '}') {
596
throwUnexpectedToken();
597
}
598
599
while (index < length) {
600
ch = source[index++];
601
if (!isHexDigit(ch)) {
602
break;
603
}
604
code = code * 16 + '0123456789abcdef'.indexOf(ch.toLowerCase());
605
}
606
607
if (code > 0x10FFFF || ch !== '}') {
608
throwUnexpectedToken();
609
}
610
611
// UTF-16 Encoding
612
if (code <= 0xFFFF) {
613
return String.fromCharCode(code);
614
}
615
cu1 = ((code - 0x10000) >> 10) + 0xD800;
616
cu2 = ((code - 0x10000) & 1023) + 0xDC00;
617
return String.fromCharCode(cu1, cu2);
618
}
619
620
function getEscapedIdentifier() {
621
var ch, id;
622
623
ch = source.charCodeAt(index++);
624
id = String.fromCharCode(ch);
625
626
// '\u' (U+005C, U+0075) denotes an escaped character.
627
if (ch === 0x5C) {
628
if (source.charCodeAt(index) !== 0x75) {
629
throwUnexpectedToken();
630
}
631
++index;
632
ch = scanHexEscape('u');
633
if (!ch || ch === '\\' || !isIdentifierStart(ch.charCodeAt(0))) {
634
throwUnexpectedToken();
635
}
636
id = ch;
637
}
638
639
while (index < length) {
640
ch = source.charCodeAt(index);
641
if (!isIdentifierPart(ch)) {
642
break;
643
}
644
++index;
645
id += String.fromCharCode(ch);
646
647
// '\u' (U+005C, U+0075) denotes an escaped character.
648
if (ch === 0x5C) {
649
id = id.substr(0, id.length - 1);
650
if (source.charCodeAt(index) !== 0x75) {
651
throwUnexpectedToken();
652
}
653
++index;
654
ch = scanHexEscape('u');
655
if (!ch || ch === '\\' || !isIdentifierPart(ch.charCodeAt(0))) {
656
throwUnexpectedToken();
657
}
658
id += ch;
659
}
660
}
661
662
return id;
663
}
664
665
function getIdentifier() {
666
var start, ch;
667
668
start = index++;
669
while (index < length) {
670
ch = source.charCodeAt(index);
671
if (ch === 0x5C) {
672
// Blackslash (U+005C) marks Unicode escape sequence.
673
index = start;
674
return getEscapedIdentifier();
675
}
676
if (isIdentifierPart(ch)) {
677
++index;
678
} else {
679
break;
680
}
681
}
682
683
return source.slice(start, index);
684
}
685
686
function scanIdentifier() {
687
var start, id, type;
688
689
start = index;
690
691
// Backslash (U+005C) starts an escaped character.
692
id = (source.charCodeAt(index) === 0x5C) ? getEscapedIdentifier() : getIdentifier();
693
694
// There is no keyword or literal with only one character.
695
// Thus, it must be an identifier.
696
if (id.length === 1) {
697
type = Token.Identifier;
698
} else if (isKeyword(id)) {
699
type = Token.Keyword;
700
} else if (id === 'null') {
701
type = Token.NullLiteral;
702
} else if (id === 'true' || id === 'false') {
703
type = Token.BooleanLiteral;
704
} else {
705
type = Token.Identifier;
706
}
707
708
return {
709
type: type,
710
value: id,
711
lineNumber: lineNumber,
712
lineStart: lineStart,
713
start: start,
714
end: index
715
};
716
}
717
718
719
// 7.7 Punctuators
720
721
function scanPunctuator() {
722
var token, str;
723
724
token = {
725
type: Token.Punctuator,
726
value: '',
727
lineNumber: lineNumber,
728
lineStart: lineStart,
729
start: index,
730
end: index
731
};
732
733
// Check for most common single-character punctuators.
734
str = source[index];
735
switch (str) {
736
737
case '(':
738
if (extra.tokenize) {
739
extra.openParenToken = extra.tokens.length;
740
}
741
++index;
742
break;
743
744
case '{':
745
if (extra.tokenize) {
746
extra.openCurlyToken = extra.tokens.length;
747
}
748
state.curlyStack.push('{');
749
++index;
750
break;
751
752
case '.':
753
++index;
754
if (source[index] === '.' && source[index + 1] === '.') {
755
// Spread operator: ...
756
index += 2;
757
str = '...';
758
}
759
break;
760
761
case '}':
762
++index;
763
state.curlyStack.pop();
764
break;
765
case ')':
766
case ';':
767
case ',':
768
case '[':
769
case ']':
770
case ':':
771
case '?':
772
case '~':
773
++index;
774
break;
775
776
default:
777
// 4-character punctuator.
778
str = source.substr(index, 4);
779
if (str === '>>>=') {
780
index += 4;
781
} else {
782
783
// 3-character punctuators.
784
str = str.substr(0, 3);
785
if (str === '===' || str === '!==' || str === '>>>' ||
786
str === '<<=' || str === '>>=') {
787
index += 3;
788
} else {
789
790
// 2-character punctuators.
791
str = str.substr(0, 2);
792
if (str === '&&' || str === '||' || str === '==' || str === '!=' ||
793
str === '+=' || str === '-=' || str === '*=' || str === '/=' ||
794
str === '++' || str === '--' || str === '<<' || str === '>>' ||
795
str === '&=' || str === '|=' || str === '^=' || str === '%=' ||
796
str === '<=' || str === '>=' || str === '=>') {
797
index += 2;
798
} else {
799
800
// 1-character punctuators.
801
str = source[index];
802
if ('<>=!+-*%&|^/'.indexOf(str) >= 0) {
803
++index;
804
}
805
}
806
}
807
}
808
}
809
810
if (index === token.start) {
811
throwUnexpectedToken();
812
}
813
814
token.end = index;
815
token.value = str;
816
return token;
817
}
818
819
// 7.8.3 Numeric Literals
820
821
function scanHexLiteral(start) {
822
var number = '';
823
824
while (index < length) {
825
if (!isHexDigit(source[index])) {
826
break;
827
}
828
number += source[index++];
829
}
830
831
if (number.length === 0) {
832
throwUnexpectedToken();
833
}
834
835
if (isIdentifierStart(source.charCodeAt(index))) {
836
throwUnexpectedToken();
837
}
838
839
return {
840
type: Token.NumericLiteral,
841
value: parseInt('0x' + number, 16),
842
lineNumber: lineNumber,
843
lineStart: lineStart,
844
start: start,
845
end: index
846
};
847
}
848
849
function scanBinaryLiteral(start) {
850
var ch, number;
851
852
number = '';
853
854
while (index < length) {
855
ch = source[index];
856
if (ch !== '0' && ch !== '1') {
857
break;
858
}
859
number += source[index++];
860
}
861
862
if (number.length === 0) {
863
// only 0b or 0B
864
throwUnexpectedToken();
865
}
866
867
if (index < length) {
868
ch = source.charCodeAt(index);
869
/* istanbul ignore else */
870
if (isIdentifierStart(ch) || isDecimalDigit(ch)) {
871
throwUnexpectedToken();
872
}
873
}
874
875
return {
876
type: Token.NumericLiteral,
877
value: parseInt(number, 2),
878
lineNumber: lineNumber,
879
lineStart: lineStart,
880
start: start,
881
end: index
882
};
883
}
884
885
function scanOctalLiteral(prefix, start) {
886
var number, octal;
887
888
if (isOctalDigit(prefix)) {
889
octal = true;
890
number = '0' + source[index++];
891
} else {
892
octal = false;
893
++index;
894
number = '';
895
}
896
897
while (index < length) {
898
if (!isOctalDigit(source[index])) {
899
break;
900
}
901
number += source[index++];
902
}
903
904
if (!octal && number.length === 0) {
905
// only 0o or 0O
906
throwUnexpectedToken();
907
}
908
909
if (isIdentifierStart(source.charCodeAt(index)) || isDecimalDigit(source.charCodeAt(index))) {
910
throwUnexpectedToken();
911
}
912
913
return {
914
type: Token.NumericLiteral,
915
value: parseInt(number, 8),
916
octal: octal,
917
lineNumber: lineNumber,
918
lineStart: lineStart,
919
start: start,
920
end: index
921
};
922
}
923
924
function isImplicitOctalLiteral() {
925
var i, ch;
926
927
// Implicit octal, unless there is a non-octal digit.
928
// (Annex B.1.1 on Numeric Literals)
929
for (i = index + 1; i < length; ++i) {
930
ch = source[i];
931
if (ch === '8' || ch === '9') {
932
return false;
933
}
934
if (!isOctalDigit(ch)) {
935
return true;
936
}
937
}
938
939
return true;
940
}
941
942
function scanNumericLiteral() {
943
var number, start, ch;
944
945
ch = source[index];
946
assert(isDecimalDigit(ch.charCodeAt(0)) || (ch === '.'),
947
'Numeric literal must start with a decimal digit or a decimal point');
948
949
start = index;
950
number = '';
951
if (ch !== '.') {
952
number = source[index++];
953
ch = source[index];
954
955
// Hex number starts with '0x'.
956
// Octal number starts with '0'.
957
// Octal number in ES6 starts with '0o'.
958
// Binary number in ES6 starts with '0b'.
959
if (number === '0') {
960
if (ch === 'x' || ch === 'X') {
961
++index;
962
return scanHexLiteral(start);
963
}
964
if (ch === 'b' || ch === 'B') {
965
++index;
966
return scanBinaryLiteral(start);
967
}
968
if (ch === 'o' || ch === 'O') {
969
return scanOctalLiteral(ch, start);
970
}
971
972
if (isOctalDigit(ch)) {
973
if (isImplicitOctalLiteral()) {
974
return scanOctalLiteral(ch, start);
975
}
976
}
977
}
978
979
while (isDecimalDigit(source.charCodeAt(index))) {
980
number += source[index++];
981
}
982
ch = source[index];
983
}
984
985
if (ch === '.') {
986
number += source[index++];
987
while (isDecimalDigit(source.charCodeAt(index))) {
988
number += source[index++];
989
}
990
ch = source[index];
991
}
992
993
if (ch === 'e' || ch === 'E') {
994
number += source[index++];
995
996
ch = source[index];
997
if (ch === '+' || ch === '-') {
998
number += source[index++];
999
}
1000
if (isDecimalDigit(source.charCodeAt(index))) {
1001
while (isDecimalDigit(source.charCodeAt(index))) {
1002
number += source[index++];
1003
}
1004
} else {
1005
throwUnexpectedToken();
1006
}
1007
}
1008
1009
if (isIdentifierStart(source.charCodeAt(index))) {
1010
throwUnexpectedToken();
1011
}
1012
1013
return {
1014
type: Token.NumericLiteral,
1015
value: parseFloat(number),
1016
lineNumber: lineNumber,
1017
lineStart: lineStart,
1018
start: start,
1019
end: index
1020
};
1021
}
1022
1023
// 7.8.4 String Literals
1024
1025
function scanStringLiteral() {
1026
var str = '', quote, start, ch, unescaped, octToDec, octal = false;
1027
1028
quote = source[index];
1029
assert((quote === '\'' || quote === '"'),
1030
'String literal must starts with a quote');
1031
1032
start = index;
1033
++index;
1034
1035
while (index < length) {
1036
ch = source[index++];
1037
1038
if (ch === quote) {
1039
quote = '';
1040
break;
1041
} else if (ch === '\\') {
1042
ch = source[index++];
1043
if (!ch || !isLineTerminator(ch.charCodeAt(0))) {
1044
switch (ch) {
1045
case 'u':
1046
case 'x':
1047
if (source[index] === '{') {
1048
++index;
1049
str += scanUnicodeCodePointEscape();
1050
} else {
1051
unescaped = scanHexEscape(ch);
1052
if (!unescaped) {
1053
throw throwUnexpectedToken();
1054
}
1055
str += unescaped;
1056
}
1057
break;
1058
case 'n':
1059
str += '\n';
1060
break;
1061
case 'r':
1062
str += '\r';
1063
break;
1064
case 't':
1065
str += '\t';
1066
break;
1067
case 'b':
1068
str += '\b';
1069
break;
1070
case 'f':
1071
str += '\f';
1072
break;
1073
case 'v':
1074
str += '\x0B';
1075
break;
1076
case '8':
1077
case '9':
1078
throw throwUnexpectedToken();
1079
1080
default:
1081
if (isOctalDigit(ch)) {
1082
octToDec = octalToDecimal(ch);
1083
1084
octal = octToDec.octal || octal;
1085
str += String.fromCharCode(octToDec.code);
1086
} else {
1087
str += ch;
1088
}
1089
break;
1090
}
1091
} else {
1092
++lineNumber;
1093
if (ch === '\r' && source[index] === '\n') {
1094
++index;
1095
}
1096
lineStart = index;
1097
}
1098
} else if (isLineTerminator(ch.charCodeAt(0))) {
1099
break;
1100
} else {
1101
str += ch;
1102
}
1103
}
1104
1105
if (quote !== '') {
1106
throwUnexpectedToken();
1107
}
1108
1109
return {
1110
type: Token.StringLiteral,
1111
value: str,
1112
octal: octal,
1113
lineNumber: startLineNumber,
1114
lineStart: startLineStart,
1115
start: start,
1116
end: index
1117
};
1118
}
1119
1120
function scanTemplate() {
1121
var cooked = '', ch, start, rawOffset, terminated, head, tail, restore, unescaped;
1122
1123
terminated = false;
1124
tail = false;
1125
start = index;
1126
head = (source[index] === '`');
1127
rawOffset = 2;
1128
1129
++index;
1130
1131
while (index < length) {
1132
ch = source[index++];
1133
if (ch === '`') {
1134
rawOffset = 1;
1135
tail = true;
1136
terminated = true;
1137
break;
1138
} else if (ch === '$') {
1139
if (source[index] === '{') {
1140
state.curlyStack.push('${');
1141
++index;
1142
terminated = true;
1143
break;
1144
}
1145
cooked += ch;
1146
} else if (ch === '\\') {
1147
ch = source[index++];
1148
if (!isLineTerminator(ch.charCodeAt(0))) {
1149
switch (ch) {
1150
case 'n':
1151
cooked += '\n';
1152
break;
1153
case 'r':
1154
cooked += '\r';
1155
break;
1156
case 't':
1157
cooked += '\t';
1158
break;
1159
case 'u':
1160
case 'x':
1161
if (source[index] === '{') {
1162
++index;
1163
cooked += scanUnicodeCodePointEscape();
1164
} else {
1165
restore = index;
1166
unescaped = scanHexEscape(ch);
1167
if (unescaped) {
1168
cooked += unescaped;
1169
} else {
1170
index = restore;
1171
cooked += ch;
1172
}
1173
}
1174
break;
1175
case 'b':
1176
cooked += '\b';
1177
break;
1178
case 'f':
1179
cooked += '\f';
1180
break;
1181
case 'v':
1182
cooked += '\v';
1183
break;
1184
1185
default:
1186
if (ch === '0') {
1187
if (isDecimalDigit(source.charCodeAt(index))) {
1188
// Illegal: \01 \02 and so on
1189
throwError(Messages.TemplateOctalLiteral);
1190
}
1191
cooked += '\0';
1192
} else if (isOctalDigit(ch)) {
1193
// Illegal: \1 \2
1194
throwError(Messages.TemplateOctalLiteral);
1195
} else {
1196
cooked += ch;
1197
}
1198
break;
1199
}
1200
} else {
1201
++lineNumber;
1202
if (ch === '\r' && source[index] === '\n') {
1203
++index;
1204
}
1205
lineStart = index;
1206
}
1207
} else if (isLineTerminator(ch.charCodeAt(0))) {
1208
++lineNumber;
1209
if (ch === '\r' && source[index] === '\n') {
1210
++index;
1211
}
1212
lineStart = index;
1213
cooked += '\n';
1214
} else {
1215
cooked += ch;
1216
}
1217
}
1218
1219
if (!terminated) {
1220
throwUnexpectedToken();
1221
}
1222
1223
if (!head) {
1224
state.curlyStack.pop();
1225
}
1226
1227
return {
1228
type: Token.Template,
1229
value: {
1230
cooked: cooked,
1231
raw: source.slice(start + 1, index - rawOffset)
1232
},
1233
head: head,
1234
tail: tail,
1235
lineNumber: lineNumber,
1236
lineStart: lineStart,
1237
start: start,
1238
end: index
1239
};
1240
}
1241
1242
function testRegExp(pattern, flags) {
1243
var tmp = pattern;
1244
1245
if (flags.indexOf('u') >= 0) {
1246
// Replace each astral symbol and every Unicode escape sequence
1247
// that possibly represents an astral symbol or a paired surrogate
1248
// with a single ASCII symbol to avoid throwing on regular
1249
// expressions that are only valid in combination with the `/u`
1250
// flag.
1251
// Note: replacing with the ASCII symbol `x` might cause false
1252
// negatives in unlikely scenarios. For example, `[\u{61}-b]` is a
1253
// perfectly valid pattern that is equivalent to `[a-b]`, but it
1254
// would be replaced by `[x-b]` which throws an error.
1255
tmp = tmp
1256
.replace(/\\u\{([0-9a-fA-F]+)\}/g, function ($0, $1) {
1257
if (parseInt($1, 16) <= 0x10FFFF) {
1258
return 'x';
1259
}
1260
throwUnexpectedToken(null, Messages.InvalidRegExp);
1261
})
1262
.replace(
1263
/\\u([a-fA-F0-9]{4})|[\uD800-\uDBFF][\uDC00-\uDFFF]/g,
1264
'x'
1265
);
1266
}
1267
1268
// First, detect invalid regular expressions.
1269
try {
1270
RegExp(tmp);
1271
} catch (e) {
1272
throwUnexpectedToken(null, Messages.InvalidRegExp);
1273
}
1274
1275
// Return a regular expression object for this pattern-flag pair, or
1276
// `null` in case the current environment doesn't support the flags it
1277
// uses.
1278
try {
1279
return new RegExp(pattern, flags);
1280
} catch (exception) {
1281
return null;
1282
}
1283
}
1284
1285
function scanRegExpBody() {
1286
var ch, str, classMarker, terminated, body;
1287
1288
ch = source[index];
1289
assert(ch === '/', 'Regular expression literal must start with a slash');
1290
str = source[index++];
1291
1292
classMarker = false;
1293
terminated = false;
1294
while (index < length) {
1295
ch = source[index++];
1296
str += ch;
1297
if (ch === '\\') {
1298
ch = source[index++];
1299
// ECMA-262 7.8.5
1300
if (isLineTerminator(ch.charCodeAt(0))) {
1301
throwUnexpectedToken(null, Messages.UnterminatedRegExp);
1302
}
1303
str += ch;
1304
} else if (isLineTerminator(ch.charCodeAt(0))) {
1305
throwUnexpectedToken(null, Messages.UnterminatedRegExp);
1306
} else if (classMarker) {
1307
if (ch === ']') {
1308
classMarker = false;
1309
}
1310
} else {
1311
if (ch === '/') {
1312
terminated = true;
1313
break;
1314
} else if (ch === '[') {
1315
classMarker = true;
1316
}
1317
}
1318
}
1319
1320
if (!terminated) {
1321
throwUnexpectedToken(null, Messages.UnterminatedRegExp);
1322
}
1323
1324
// Exclude leading and trailing slash.
1325
body = str.substr(1, str.length - 2);
1326
return {
1327
value: body,
1328
literal: str
1329
};
1330
}
1331
1332
function scanRegExpFlags() {
1333
var ch, str, flags, restore;
1334
1335
str = '';
1336
flags = '';
1337
while (index < length) {
1338
ch = source[index];
1339
if (!isIdentifierPart(ch.charCodeAt(0))) {
1340
break;
1341
}
1342
1343
++index;
1344
if (ch === '\\' && index < length) {
1345
ch = source[index];
1346
if (ch === 'u') {
1347
++index;
1348
restore = index;
1349
ch = scanHexEscape('u');
1350
if (ch) {
1351
flags += ch;
1352
for (str += '\\u'; restore < index; ++restore) {
1353
str += source[restore];
1354
}
1355
} else {
1356
index = restore;
1357
flags += 'u';
1358
str += '\\u';
1359
}
1360
tolerateUnexpectedToken();
1361
} else {
1362
str += '\\';
1363
tolerateUnexpectedToken();
1364
}
1365
} else {
1366
flags += ch;
1367
str += ch;
1368
}
1369
}
1370
1371
return {
1372
value: flags,
1373
literal: str
1374
};
1375
}
1376
1377
function scanRegExp() {
1378
scanning = true;
1379
var start, body, flags, value;
1380
1381
lookahead = null;
1382
skipComment();
1383
start = index;
1384
1385
body = scanRegExpBody();
1386
flags = scanRegExpFlags();
1387
value = testRegExp(body.value, flags.value);
1388
scanning = false;
1389
if (extra.tokenize) {
1390
return {
1391
type: Token.RegularExpression,
1392
value: value,
1393
regex: {
1394
pattern: body.value,
1395
flags: flags.value
1396
},
1397
lineNumber: lineNumber,
1398
lineStart: lineStart,
1399
start: start,
1400
end: index
1401
};
1402
}
1403
1404
return {
1405
literal: body.literal + flags.literal,
1406
value: value,
1407
regex: {
1408
pattern: body.value,
1409
flags: flags.value
1410
},
1411
start: start,
1412
end: index
1413
};
1414
}
1415
1416
function collectRegex() {
1417
var pos, loc, regex, token;
1418
1419
skipComment();
1420
1421
pos = index;
1422
loc = {
1423
start: {
1424
line: lineNumber,
1425
column: index - lineStart
1426
}
1427
};
1428
1429
regex = scanRegExp();
1430
1431
loc.end = {
1432
line: lineNumber,
1433
column: index - lineStart
1434
};
1435
1436
/* istanbul ignore next */
1437
if (!extra.tokenize) {
1438
// Pop the previous token, which is likely '/' or '/='
1439
if (extra.tokens.length > 0) {
1440
token = extra.tokens[extra.tokens.length - 1];
1441
if (token.range[0] === pos && token.type === 'Punctuator') {
1442
if (token.value === '/' || token.value === '/=') {
1443
extra.tokens.pop();
1444
}
1445
}
1446
}
1447
1448
extra.tokens.push({
1449
type: 'RegularExpression',
1450
value: regex.literal,
1451
regex: regex.regex,
1452
range: [pos, index],
1453
loc: loc
1454
});
1455
}
1456
1457
return regex;
1458
}
1459
1460
function isIdentifierName(token) {
1461
return token.type === Token.Identifier ||
1462
token.type === Token.Keyword ||
1463
token.type === Token.BooleanLiteral ||
1464
token.type === Token.NullLiteral;
1465
}
1466
1467
function advanceSlash() {
1468
var prevToken,
1469
checkToken;
1470
// Using the following algorithm:
1471
// https://github.com/mozilla/sweet.js/wiki/design
1472
prevToken = extra.tokens[extra.tokens.length - 1];
1473
if (!prevToken) {
1474
// Nothing before that: it cannot be a division.
1475
return collectRegex();
1476
}
1477
if (prevToken.type === 'Punctuator') {
1478
if (prevToken.value === ']') {
1479
return scanPunctuator();
1480
}
1481
if (prevToken.value === ')') {
1482
checkToken = extra.tokens[extra.openParenToken - 1];
1483
if (checkToken &&
1484
checkToken.type === 'Keyword' &&
1485
(checkToken.value === 'if' ||
1486
checkToken.value === 'while' ||
1487
checkToken.value === 'for' ||
1488
checkToken.value === 'with')) {
1489
return collectRegex();
1490
}
1491
return scanPunctuator();
1492
}
1493
if (prevToken.value === '}') {
1494
// Dividing a function by anything makes little sense,
1495
// but we have to check for that.
1496
if (extra.tokens[extra.openCurlyToken - 3] &&
1497
extra.tokens[extra.openCurlyToken - 3].type === 'Keyword') {
1498
// Anonymous function.
1499
checkToken = extra.tokens[extra.openCurlyToken - 4];
1500
if (!checkToken) {
1501
return scanPunctuator();
1502
}
1503
} else if (extra.tokens[extra.openCurlyToken - 4] &&
1504
extra.tokens[extra.openCurlyToken - 4].type === 'Keyword') {
1505
// Named function.
1506
checkToken = extra.tokens[extra.openCurlyToken - 5];
1507
if (!checkToken) {
1508
return collectRegex();
1509
}
1510
} else {
1511
return scanPunctuator();
1512
}
1513
// checkToken determines whether the function is
1514
// a declaration or an expression.
1515
if (FnExprTokens.indexOf(checkToken.value) >= 0) {
1516
// It is an expression.
1517
return scanPunctuator();
1518
}
1519
// It is a declaration.
1520
return collectRegex();
1521
}
1522
return collectRegex();
1523
}
1524
if (prevToken.type === 'Keyword' && prevToken.value !== 'this') {
1525
return collectRegex();
1526
}
1527
return scanPunctuator();
1528
}
1529
1530
function advance() {
1531
var ch, token;
1532
1533
if (index >= length) {
1534
return {
1535
type: Token.EOF,
1536
lineNumber: lineNumber,
1537
lineStart: lineStart,
1538
start: index,
1539
end: index
1540
};
1541
}
1542
1543
ch = source.charCodeAt(index);
1544
1545
if (isIdentifierStart(ch)) {
1546
token = scanIdentifier();
1547
if (strict && isStrictModeReservedWord(token.value)) {
1548
token.type = Token.Keyword;
1549
}
1550
return token;
1551
}
1552
1553
// Very common: ( and ) and ;
1554
if (ch === 0x28 || ch === 0x29 || ch === 0x3B) {
1555
return scanPunctuator();
1556
}
1557
1558
// String literal starts with single quote (U+0027) or double quote (U+0022).
1559
if (ch === 0x27 || ch === 0x22) {
1560
return scanStringLiteral();
1561
}
1562
1563
// Dot (.) U+002E can also start a floating-point number, hence the need
1564
// to check the next character.
1565
if (ch === 0x2E) {
1566
if (isDecimalDigit(source.charCodeAt(index + 1))) {
1567
return scanNumericLiteral();
1568
}
1569
return scanPunctuator();
1570
}
1571
1572
if (isDecimalDigit(ch)) {
1573
return scanNumericLiteral();
1574
}
1575
1576
// Slash (/) U+002F can also start a regex.
1577
if (extra.tokenize && ch === 0x2F) {
1578
return advanceSlash();
1579
}
1580
1581
// Template literals start with ` (U+0060) for template head
1582
// or } (U+007D) for template middle or template tail.
1583
if (ch === 0x60 || (ch === 0x7D && state.curlyStack[state.curlyStack.length - 1] === '${')) {
1584
return scanTemplate();
1585
}
1586
1587
return scanPunctuator();
1588
}
1589
1590
function collectToken() {
1591
var loc, token, value, entry;
1592
1593
loc = {
1594
start: {
1595
line: lineNumber,
1596
column: index - lineStart
1597
}
1598
};
1599
1600
token = advance();
1601
loc.end = {
1602
line: lineNumber,
1603
column: index - lineStart
1604
};
1605
1606
if (token.type !== Token.EOF) {
1607
value = source.slice(token.start, token.end);
1608
entry = {
1609
type: TokenName[token.type],
1610
value: value,
1611
range: [token.start, token.end],
1612
loc: loc
1613
};
1614
if (token.regex) {
1615
entry.regex = {
1616
pattern: token.regex.pattern,
1617
flags: token.regex.flags
1618
};
1619
}
1620
extra.tokens.push(entry);
1621
}
1622
1623
return token;
1624
}
1625
1626
function lex() {
1627
var token;
1628
scanning = true;
1629
1630
lastIndex = index;
1631
lastLineNumber = lineNumber;
1632
lastLineStart = lineStart;
1633
1634
skipComment();
1635
1636
token = lookahead;
1637
1638
startIndex = index;
1639
startLineNumber = lineNumber;
1640
startLineStart = lineStart;
1641
1642
lookahead = (typeof extra.tokens !== 'undefined') ? collectToken() : advance();
1643
scanning = false;
1644
return token;
1645
}
1646
1647
function peek() {
1648
scanning = true;
1649
1650
skipComment();
1651
1652
lastIndex = index;
1653
lastLineNumber = lineNumber;
1654
lastLineStart = lineStart;
1655
1656
startIndex = index;
1657
startLineNumber = lineNumber;
1658
startLineStart = lineStart;
1659
1660
lookahead = (typeof extra.tokens !== 'undefined') ? collectToken() : advance();
1661
scanning = false;
1662
}
1663
1664
function Position() {
1665
this.line = startLineNumber;
1666
this.column = startIndex - startLineStart;
1667
}
1668
1669
function SourceLocation() {
1670
this.start = new Position();
1671
this.end = null;
1672
}
1673
1674
function WrappingSourceLocation(startToken) {
1675
this.start = {
1676
line: startToken.lineNumber,
1677
column: startToken.start - startToken.lineStart
1678
};
1679
this.end = null;
1680
}
1681
1682
function Node() {
1683
if (extra.range) {
1684
this.range = [startIndex, 0];
1685
}
1686
if (extra.loc) {
1687
this.loc = new SourceLocation();
1688
}
1689
}
1690
1691
function WrappingNode(startToken) {
1692
if (extra.range) {
1693
this.range = [startToken.start, 0];
1694
}
1695
if (extra.loc) {
1696
this.loc = new WrappingSourceLocation(startToken);
1697
}
1698
}
1699
1700
WrappingNode.prototype = Node.prototype = {
1701
1702
processComment: function () {
1703
var lastChild,
1704
leadingComments,
1705
trailingComments,
1706
bottomRight = extra.bottomRightStack,
1707
i,
1708
comment,
1709
last = bottomRight[bottomRight.length - 1];
1710
1711
if (this.type === Syntax.Program) {
1712
if (this.body.length > 0) {
1713
return;
1714
}
1715
}
1716
1717
if (extra.trailingComments.length > 0) {
1718
trailingComments = [];
1719
for (i = extra.trailingComments.length - 1; i >= 0; --i) {
1720
comment = extra.trailingComments[i];
1721
if (comment.range[0] >= this.range[1]) {
1722
trailingComments.unshift(comment);
1723
extra.trailingComments.splice(i, 1);
1724
}
1725
}
1726
extra.trailingComments = [];
1727
} else {
1728
if (last && last.trailingComments && last.trailingComments[0].range[0] >= this.range[1]) {
1729
trailingComments = last.trailingComments;
1730
delete last.trailingComments;
1731
}
1732
}
1733
1734
// Eating the stack.
1735
if (last) {
1736
while (last && last.range[0] >= this.range[0]) {
1737
lastChild = last;
1738
last = bottomRight.pop();
1739
}
1740
}
1741
1742
if (lastChild) {
1743
if (lastChild.leadingComments && lastChild.leadingComments[lastChild.leadingComments.length - 1].range[1] <= this.range[0]) {
1744
this.leadingComments = lastChild.leadingComments;
1745
lastChild.leadingComments = undefined;
1746
}
1747
} else if (extra.leadingComments.length > 0) {
1748
leadingComments = [];
1749
for (i = extra.leadingComments.length - 1; i >= 0; --i) {
1750
comment = extra.leadingComments[i];
1751
if (comment.range[1] <= this.range[0]) {
1752
leadingComments.unshift(comment);
1753
extra.leadingComments.splice(i, 1);
1754
}
1755
}
1756
}
1757
1758
1759
if (leadingComments && leadingComments.length > 0) {
1760
this.leadingComments = leadingComments;
1761
}
1762
if (trailingComments && trailingComments.length > 0) {
1763
this.trailingComments = trailingComments;
1764
}
1765
1766
bottomRight.push(this);
1767
},
1768
1769
finish: function () {
1770
if (extra.range) {
1771
this.range[1] = lastIndex;
1772
}
1773
if (extra.loc) {
1774
this.loc.end = {
1775
line: lastLineNumber,
1776
column: lastIndex - lastLineStart
1777
};
1778
if (extra.source) {
1779
this.loc.source = extra.source;
1780
}
1781
}
1782
1783
if (extra.attachComment) {
1784
this.processComment();
1785
}
1786
},
1787
1788
finishArrayExpression: function (elements) {
1789
this.type = Syntax.ArrayExpression;
1790
this.elements = elements;
1791
this.finish();
1792
return this;
1793
},
1794
1795
finishArrayPattern: function (elements) {
1796
this.type = Syntax.ArrayPattern;
1797
this.elements = elements;
1798
this.finish();
1799
return this;
1800
},
1801
1802
finishArrowFunctionExpression: function (params, defaults, body, expression) {
1803
this.type = Syntax.ArrowFunctionExpression;
1804
this.id = null;
1805
this.params = params;
1806
this.defaults = defaults;
1807
this.body = body;
1808
this.generator = false;
1809
this.expression = expression;
1810
this.finish();
1811
return this;
1812
},
1813
1814
finishAssignmentExpression: function (operator, left, right) {
1815
this.type = Syntax.AssignmentExpression;
1816
this.operator = operator;
1817
this.left = left;
1818
this.right = right;
1819
this.finish();
1820
return this;
1821
},
1822
1823
finishAssignmentPattern: function (left, right) {
1824
this.type = Syntax.AssignmentPattern;
1825
this.left = left;
1826
this.right = right;
1827
this.finish();
1828
return this;
1829
},
1830
1831
finishBinaryExpression: function (operator, left, right) {
1832
this.type = (operator === '||' || operator === '&&') ? Syntax.LogicalExpression : Syntax.BinaryExpression;
1833
this.operator = operator;
1834
this.left = left;
1835
this.right = right;
1836
this.finish();
1837
return this;
1838
},
1839
1840
finishBlockStatement: function (body) {
1841
this.type = Syntax.BlockStatement;
1842
this.body = body;
1843
this.finish();
1844
return this;
1845
},
1846
1847
finishBreakStatement: function (label) {
1848
this.type = Syntax.BreakStatement;
1849
this.label = label;
1850
this.finish();
1851
return this;
1852
},
1853
1854
finishCallExpression: function (callee, args) {
1855
this.type = Syntax.CallExpression;
1856
this.callee = callee;
1857
this.arguments = args;
1858
this.finish();
1859
return this;
1860
},
1861
1862
finishCatchClause: function (param, body) {
1863
this.type = Syntax.CatchClause;
1864
this.param = param;
1865
this.body = body;
1866
this.finish();
1867
return this;
1868
},
1869
1870
finishClassBody: function (body) {
1871
this.type = Syntax.ClassBody;
1872
this.body = body;
1873
this.finish();
1874
return this;
1875
},
1876
1877
finishClassDeclaration: function (id, superClass, body) {
1878
this.type = Syntax.ClassDeclaration;
1879
this.id = id;
1880
this.superClass = superClass;
1881
this.body = body;
1882
this.finish();
1883
return this;
1884
},
1885
1886
finishClassExpression: function (id, superClass, body) {
1887
this.type = Syntax.ClassExpression;
1888
this.id = id;
1889
this.superClass = superClass;
1890
this.body = body;
1891
this.finish();
1892
return this;
1893
},
1894
1895
finishConditionalExpression: function (test, consequent, alternate) {
1896
this.type = Syntax.ConditionalExpression;
1897
this.test = test;
1898
this.consequent = consequent;
1899
this.alternate = alternate;
1900
this.finish();
1901
return this;
1902
},
1903
1904
finishContinueStatement: function (label) {
1905
this.type = Syntax.ContinueStatement;
1906
this.label = label;
1907
this.finish();
1908
return this;
1909
},
1910
1911
finishDebuggerStatement: function () {
1912
this.type = Syntax.DebuggerStatement;
1913
this.finish();
1914
return this;
1915
},
1916
1917
finishDoWhileStatement: function (body, test) {
1918
this.type = Syntax.DoWhileStatement;
1919
this.body = body;
1920
this.test = test;
1921
this.finish();
1922
return this;
1923
},
1924
1925
finishEmptyStatement: function () {
1926
this.type = Syntax.EmptyStatement;
1927
this.finish();
1928
return this;
1929
},
1930
1931
finishExpressionStatement: function (expression) {
1932
this.type = Syntax.ExpressionStatement;
1933
this.expression = expression;
1934
this.finish();
1935
return this;
1936
},
1937
1938
finishForStatement: function (init, test, update, body) {
1939
this.type = Syntax.ForStatement;
1940
this.init = init;
1941
this.test = test;
1942
this.update = update;
1943
this.body = body;
1944
this.finish();
1945
return this;
1946
},
1947
1948
finishForInStatement: function (left, right, body) {
1949
this.type = Syntax.ForInStatement;
1950
this.left = left;
1951
this.right = right;
1952
this.body = body;
1953
this.each = false;
1954
this.finish();
1955
return this;
1956
},
1957
1958
finishFunctionDeclaration: function (id, params, defaults, body) {
1959
this.type = Syntax.FunctionDeclaration;
1960
this.id = id;
1961
this.params = params;
1962
this.defaults = defaults;
1963
this.body = body;
1964
this.generator = false;
1965
this.expression = false;
1966
this.finish();
1967
return this;
1968
},
1969
1970
finishFunctionExpression: function (id, params, defaults, body) {
1971
this.type = Syntax.FunctionExpression;
1972
this.id = id;
1973
this.params = params;
1974
this.defaults = defaults;
1975
this.body = body;
1976
this.generator = false;
1977
this.expression = false;
1978
this.finish();
1979
return this;
1980
},
1981
1982
finishIdentifier: function (name) {
1983
this.type = Syntax.Identifier;
1984
this.name = name;
1985
this.finish();
1986
return this;
1987
},
1988
1989
finishIfStatement: function (test, consequent, alternate) {
1990
this.type = Syntax.IfStatement;
1991
this.test = test;
1992
this.consequent = consequent;
1993
this.alternate = alternate;
1994
this.finish();
1995
return this;
1996
},
1997
1998
finishLabeledStatement: function (label, body) {
1999
this.type = Syntax.LabeledStatement;
2000
this.label = label;
2001
this.body = body;
2002
this.finish();
2003
return this;
2004
},
2005
2006
finishLiteral: function (token) {
2007
this.type = Syntax.Literal;
2008
this.value = token.value;
2009
this.raw = source.slice(token.start, token.end);
2010
if (token.regex) {
2011
this.regex = token.regex;
2012
}
2013
this.finish();
2014
return this;
2015
},
2016
2017
finishMemberExpression: function (accessor, object, property) {
2018
this.type = Syntax.MemberExpression;
2019
this.computed = accessor === '[';
2020
this.object = object;
2021
this.property = property;
2022
this.finish();
2023
return this;
2024
},
2025
2026
finishNewExpression: function (callee, args) {
2027
this.type = Syntax.NewExpression;
2028
this.callee = callee;
2029
this.arguments = args;
2030
this.finish();
2031
return this;
2032
},
2033
2034
finishObjectExpression: function (properties) {
2035
this.type = Syntax.ObjectExpression;
2036
this.properties = properties;
2037
this.finish();
2038
return this;
2039
},
2040
2041
finishObjectPattern: function (properties) {
2042
this.type = Syntax.ObjectPattern;
2043
this.properties = properties;
2044
this.finish();
2045
return this;
2046
},
2047
2048
finishPostfixExpression: function (operator, argument) {
2049
this.type = Syntax.UpdateExpression;
2050
this.operator = operator;
2051
this.argument = argument;
2052
this.prefix = false;
2053
this.finish();
2054
return this;
2055
},
2056
2057
finishProgram: function (body) {
2058
this.type = Syntax.Program;
2059
this.body = body;
2060
if (sourceType === 'module') {
2061
// very restrictive for now
2062
this.sourceType = sourceType;
2063
}
2064
this.finish();
2065
return this;
2066
},
2067
2068
finishProperty: function (kind, key, computed, value, method, shorthand) {
2069
this.type = Syntax.Property;
2070
this.key = key;
2071
this.computed = computed;
2072
this.value = value;
2073
this.kind = kind;
2074
this.method = method;
2075
this.shorthand = shorthand;
2076
this.finish();
2077
return this;
2078
},
2079
2080
finishRestElement: function (argument) {
2081
this.type = Syntax.RestElement;
2082
this.argument = argument;
2083
this.finish();
2084
return this;
2085
},
2086
2087
finishReturnStatement: function (argument) {
2088
this.type = Syntax.ReturnStatement;
2089
this.argument = argument;
2090
this.finish();
2091
return this;
2092
},
2093
2094
finishSequenceExpression: function (expressions) {
2095
this.type = Syntax.SequenceExpression;
2096
this.expressions = expressions;
2097
this.finish();
2098
return this;
2099
},
2100
2101
finishSpreadElement: function (argument) {
2102
this.type = Syntax.SpreadElement;
2103
this.argument = argument;
2104
this.finish();
2105
return this;
2106
},
2107
2108
finishSwitchCase: function (test, consequent) {
2109
this.type = Syntax.SwitchCase;
2110
this.test = test;
2111
this.consequent = consequent;
2112
this.finish();
2113
return this;
2114
},
2115
2116
finishSuper: function () {
2117
this.type = Syntax.Super;
2118
this.finish();
2119
return this;
2120
},
2121
2122
finishSwitchStatement: function (discriminant, cases) {
2123
this.type = Syntax.SwitchStatement;
2124
this.discriminant = discriminant;
2125
this.cases = cases;
2126
this.finish();
2127
return this;
2128
},
2129
2130
finishTaggedTemplateExpression: function (tag, quasi) {
2131
this.type = Syntax.TaggedTemplateExpression;
2132
this.tag = tag;
2133
this.quasi = quasi;
2134
this.finish();
2135
return this;
2136
},
2137
2138
finishTemplateElement: function (value, tail) {
2139
this.type = Syntax.TemplateElement;
2140
this.value = value;
2141
this.tail = tail;
2142
this.finish();
2143
return this;
2144
},
2145
2146
finishTemplateLiteral: function (quasis, expressions) {
2147
this.type = Syntax.TemplateLiteral;
2148
this.quasis = quasis;
2149
this.expressions = expressions;
2150
this.finish();
2151
return this;
2152
},
2153
2154
finishThisExpression: function () {
2155
this.type = Syntax.ThisExpression;
2156
this.finish();
2157
return this;
2158
},
2159
2160
finishThrowStatement: function (argument) {
2161
this.type = Syntax.ThrowStatement;
2162
this.argument = argument;
2163
this.finish();
2164
return this;
2165
},
2166
2167
finishTryStatement: function (block, handler, finalizer) {
2168
this.type = Syntax.TryStatement;
2169
this.block = block;
2170
this.guardedHandlers = [];
2171
this.handlers = handler ? [ handler ] : [];
2172
this.handler = handler;
2173
this.finalizer = finalizer;
2174
this.finish();
2175
return this;
2176
},
2177
2178
finishUnaryExpression: function (operator, argument) {
2179
this.type = (operator === '++' || operator === '--') ? Syntax.UpdateExpression : Syntax.UnaryExpression;
2180
this.operator = operator;
2181
this.argument = argument;
2182
this.prefix = true;
2183
this.finish();
2184
return this;
2185
},
2186
2187
finishVariableDeclaration: function (declarations) {
2188
this.type = Syntax.VariableDeclaration;
2189
this.declarations = declarations;
2190
this.kind = 'var';
2191
this.finish();
2192
return this;
2193
},
2194
2195
finishLexicalDeclaration: function (declarations, kind) {
2196
this.type = Syntax.VariableDeclaration;
2197
this.declarations = declarations;
2198
this.kind = kind;
2199
this.finish();
2200
return this;
2201
},
2202
2203
finishVariableDeclarator: function (id, init) {
2204
this.type = Syntax.VariableDeclarator;
2205
this.id = id;
2206
this.init = init;
2207
this.finish();
2208
return this;
2209
},
2210
2211
finishWhileStatement: function (test, body) {
2212
this.type = Syntax.WhileStatement;
2213
this.test = test;
2214
this.body = body;
2215
this.finish();
2216
return this;
2217
},
2218
2219
finishWithStatement: function (object, body) {
2220
this.type = Syntax.WithStatement;
2221
this.object = object;
2222
this.body = body;
2223
this.finish();
2224
return this;
2225
},
2226
2227
finishExportSpecifier: function (local, exported) {
2228
this.type = Syntax.ExportSpecifier;
2229
this.exported = exported || local;
2230
this.local = local;
2231
this.finish();
2232
return this;
2233
},
2234
2235
finishImportDefaultSpecifier: function (local) {
2236
this.type = Syntax.ImportDefaultSpecifier;
2237
this.local = local;
2238
this.finish();
2239
return this;
2240
},
2241
2242
finishImportNamespaceSpecifier: function (local) {
2243
this.type = Syntax.ImportNamespaceSpecifier;
2244
this.local = local;
2245
this.finish();
2246
return this;
2247
},
2248
2249
finishExportNamedDeclaration: function (declaration, specifiers, src) {
2250
this.type = Syntax.ExportNamedDeclaration;
2251
this.declaration = declaration;
2252
this.specifiers = specifiers;
2253
this.source = src;
2254
this.finish();
2255
return this;
2256
},
2257
2258
finishExportDefaultDeclaration: function (declaration) {
2259
this.type = Syntax.ExportDefaultDeclaration;
2260
this.declaration = declaration;
2261
this.finish();
2262
return this;
2263
},
2264
2265
finishExportAllDeclaration: function (src) {
2266
this.type = Syntax.ExportAllDeclaration;
2267
this.source = src;
2268
this.finish();
2269
return this;
2270
},
2271
2272
finishImportSpecifier: function (local, imported) {
2273
this.type = Syntax.ImportSpecifier;
2274
this.local = local || imported;
2275
this.imported = imported;
2276
this.finish();
2277
return this;
2278
},
2279
2280
finishImportDeclaration: function (specifiers, src) {
2281
this.type = Syntax.ImportDeclaration;
2282
this.specifiers = specifiers;
2283
this.source = src;
2284
this.finish();
2285
return this;
2286
}
2287
};
2288
2289
2290
function recordError(error) {
2291
var e, existing;
2292
2293
for (e = 0; e < extra.errors.length; e++) {
2294
existing = extra.errors[e];
2295
// Prevent duplicated error.
2296
/* istanbul ignore next */
2297
if (existing.index === error.index && existing.message === error.message) {
2298
return;
2299
}
2300
}
2301
2302
extra.errors.push(error);
2303
}
2304
2305
function createError(line, pos, description) {
2306
var error = new Error('Line ' + line + ': ' + description);
2307
error.index = pos;
2308
error.lineNumber = line;
2309
error.column = pos - (scanning ? lineStart : lastLineStart) + 1;
2310
error.description = description;
2311
return error;
2312
}
2313
2314
// Throw an exception
2315
2316
function throwError(messageFormat) {
2317
var args, msg;
2318
2319
args = Array.prototype.slice.call(arguments, 1);
2320
msg = messageFormat.replace(/%(\d)/g,
2321
function (whole, idx) {
2322
assert(idx < args.length, 'Message reference must be in range');
2323
return args[idx];
2324
}
2325
);
2326
2327
throw createError(lastLineNumber, lastIndex, msg);
2328
}
2329
2330
function tolerateError(messageFormat) {
2331
var args, msg, error;
2332
2333
args = Array.prototype.slice.call(arguments, 1);
2334
/* istanbul ignore next */
2335
msg = messageFormat.replace(/%(\d)/g,
2336
function (whole, idx) {
2337
assert(idx < args.length, 'Message reference must be in range');
2338
return args[idx];
2339
}
2340
);
2341
2342
error = createError(lineNumber, lastIndex, msg);
2343
if (extra.errors) {
2344
recordError(error);
2345
} else {
2346
throw error;
2347
}
2348
}
2349
2350
// Throw an exception because of the token.
2351
2352
function unexpectedTokenError(token, message) {
2353
var value, msg = message || Messages.UnexpectedToken;
2354
2355
if (token) {
2356
if (!message) {
2357
msg = (token.type === Token.EOF) ? Messages.UnexpectedEOS :
2358
(token.type === Token.Identifier) ? Messages.UnexpectedIdentifier :
2359
(token.type === Token.NumericLiteral) ? Messages.UnexpectedNumber :
2360
(token.type === Token.StringLiteral) ? Messages.UnexpectedString :
2361
(token.type === Token.Template) ? Messages.UnexpectedTemplate :
2362
Messages.UnexpectedToken;
2363
2364
if (token.type === Token.Keyword) {
2365
if (isFutureReservedWord(token.value)) {
2366
msg = Messages.UnexpectedReserved;
2367
} else if (strict && isStrictModeReservedWord(token.value)) {
2368
msg = Messages.StrictReservedWord;
2369
}
2370
}
2371
}
2372
2373
value = (token.type === Token.Template) ? token.value.raw : token.value;
2374
} else {
2375
value = 'ILLEGAL';
2376
}
2377
2378
msg = msg.replace('%0', value);
2379
2380
return (token && typeof token.lineNumber === 'number') ?
2381
createError(token.lineNumber, token.start, msg) :
2382
createError(scanning ? lineNumber : lastLineNumber, scanning ? index : lastIndex, msg);
2383
}
2384
2385
function throwUnexpectedToken(token, message) {
2386
throw unexpectedTokenError(token, message);
2387
}
2388
2389
function tolerateUnexpectedToken(token, message) {
2390
var error = unexpectedTokenError(token, message);
2391
if (extra.errors) {
2392
recordError(error);
2393
} else {
2394
throw error;
2395
}
2396
}
2397
2398
// Expect the next token to match the specified punctuator.
2399
// If not, an exception will be thrown.
2400
2401
function expect(value) {
2402
var token = lex();
2403
if (token.type !== Token.Punctuator || token.value !== value) {
2404
throwUnexpectedToken(token);
2405
}
2406
}
2407
2408
/**
2409
* @name expectCommaSeparator
2410
* @description Quietly expect a comma when in tolerant mode, otherwise delegates
2411
* to <code>expect(value)</code>
2412
* @since 2.0
2413
*/
2414
function expectCommaSeparator() {
2415
var token;
2416
2417
if (extra.errors) {
2418
token = lookahead;
2419
if (token.type === Token.Punctuator && token.value === ',') {
2420
lex();
2421
} else if (token.type === Token.Punctuator && token.value === ';') {
2422
lex();
2423
tolerateUnexpectedToken(token);
2424
} else {
2425
tolerateUnexpectedToken(token, Messages.UnexpectedToken);
2426
}
2427
} else {
2428
expect(',');
2429
}
2430
}
2431
2432
// Expect the next token to match the specified keyword.
2433
// If not, an exception will be thrown.
2434
2435
function expectKeyword(keyword) {
2436
var token = lex();
2437
if (token.type !== Token.Keyword || token.value !== keyword) {
2438
throwUnexpectedToken(token);
2439
}
2440
}
2441
2442
// Return true if the next token matches the specified punctuator.
2443
2444
function match(value) {
2445
return lookahead.type === Token.Punctuator && lookahead.value === value;
2446
}
2447
2448
// Return true if the next token matches the specified keyword
2449
2450
function matchKeyword(keyword) {
2451
return lookahead.type === Token.Keyword && lookahead.value === keyword;
2452
}
2453
2454
// Return true if the next token matches the specified contextual keyword
2455
// (where an identifier is sometimes a keyword depending on the context)
2456
2457
function matchContextualKeyword(keyword) {
2458
return lookahead.type === Token.Identifier && lookahead.value === keyword;
2459
}
2460
2461
// Return true if the next token is an assignment operator
2462
2463
function matchAssign() {
2464
var op;
2465
2466
if (lookahead.type !== Token.Punctuator) {
2467
return false;
2468
}
2469
op = lookahead.value;
2470
return op === '=' ||
2471
op === '*=' ||
2472
op === '/=' ||
2473
op === '%=' ||
2474
op === '+=' ||
2475
op === '-=' ||
2476
op === '<<=' ||
2477
op === '>>=' ||
2478
op === '>>>=' ||
2479
op === '&=' ||
2480
op === '^=' ||
2481
op === '|=';
2482
}
2483
2484
function consumeSemicolon() {
2485
// Catch the very common case first: immediately a semicolon (U+003B).
2486
if (source.charCodeAt(startIndex) === 0x3B || match(';')) {
2487
lex();
2488
return;
2489
}
2490
2491
if (hasLineTerminator) {
2492
return;
2493
}
2494
2495
// FIXME(ikarienator): this is seemingly an issue in the previous location info convention.
2496
lastIndex = startIndex;
2497
lastLineNumber = startLineNumber;
2498
lastLineStart = startLineStart;
2499
2500
if (lookahead.type !== Token.EOF && !match('}')) {
2501
throwUnexpectedToken(lookahead);
2502
}
2503
}
2504
2505
// Cover grammar support.
2506
//
2507
// When an assignment expression position starts with an left parenthesis, the determination of the type
2508
// of the syntax is to be deferred arbitrarily long until the end of the parentheses pair (plus a lookahead)
2509
// or the first comma. This situation also defers the determination of all the expressions nested in the pair.
2510
//
2511
// There are three productions that can be parsed in a parentheses pair that needs to be determined
2512
// after the outermost pair is closed. They are:
2513
//
2514
// 1. AssignmentExpression
2515
// 2. BindingElements
2516
// 3. AssignmentTargets
2517
//
2518
// In order to avoid exponential backtracking, we use two flags to denote if the production can be
2519
// binding element or assignment target.
2520
//
2521
// The three productions have the relationship:
2522
//
2523
// BindingElements ⊆ AssignmentTargets ⊆ AssignmentExpression
2524
//
2525
// with a single exception that CoverInitializedName when used directly in an Expression, generates
2526
// an early error. Therefore, we need the third state, firstCoverInitializedNameError, to track the
2527
// first usage of CoverInitializedName and report it when we reached the end of the parentheses pair.
2528
//
2529
// isolateCoverGrammar function runs the given parser function with a new cover grammar context, and it does not
2530
// effect the current flags. This means the production the parser parses is only used as an expression. Therefore
2531
// the CoverInitializedName check is conducted.
2532
//
2533
// inheritCoverGrammar function runs the given parse function with a new cover grammar context, and it propagates
2534
// the flags outside of the parser. This means the production the parser parses is used as a part of a potential
2535
// pattern. The CoverInitializedName check is deferred.
2536
function isolateCoverGrammar(parser) {
2537
var oldIsBindingElement = isBindingElement,
2538
oldIsAssignmentTarget = isAssignmentTarget,
2539
oldFirstCoverInitializedNameError = firstCoverInitializedNameError,
2540
result;
2541
isBindingElement = true;
2542
isAssignmentTarget = true;
2543
firstCoverInitializedNameError = null;
2544
result = parser();
2545
if (firstCoverInitializedNameError !== null) {
2546
throwUnexpectedToken(firstCoverInitializedNameError);
2547
}
2548
isBindingElement = oldIsBindingElement;
2549
isAssignmentTarget = oldIsAssignmentTarget;
2550
firstCoverInitializedNameError = oldFirstCoverInitializedNameError;
2551
return result;
2552
}
2553
2554
function inheritCoverGrammar(parser) {
2555
var oldIsBindingElement = isBindingElement,
2556
oldIsAssignmentTarget = isAssignmentTarget,
2557
oldFirstCoverInitializedNameError = firstCoverInitializedNameError,
2558
result;
2559
isBindingElement = true;
2560
isAssignmentTarget = true;
2561
firstCoverInitializedNameError = null;
2562
result = parser();
2563
isBindingElement = isBindingElement && oldIsBindingElement;
2564
isAssignmentTarget = isAssignmentTarget && oldIsAssignmentTarget;
2565
firstCoverInitializedNameError = oldFirstCoverInitializedNameError || firstCoverInitializedNameError;
2566
return result;
2567
}
2568
2569
function parseArrayPattern() {
2570
var node = new Node(), elements = [], rest, restNode;
2571
expect('[');
2572
2573
while (!match(']')) {
2574
if (match(',')) {
2575
lex();
2576
elements.push(null);
2577
} else {
2578
if (match('...')) {
2579
restNode = new Node();
2580
lex();
2581
rest = parseVariableIdentifier();
2582
elements.push(restNode.finishRestElement(rest));
2583
break;
2584
} else {
2585
elements.push(parsePatternWithDefault());
2586
}
2587
if (!match(']')) {
2588
expect(',');
2589
}
2590
}
2591
2592
}
2593
2594
expect(']');
2595
2596
return node.finishArrayPattern(elements);
2597
}
2598
2599
function parsePropertyPattern() {
2600
var node = new Node(), key, computed = match('['), init;
2601
if (lookahead.type === Token.Identifier) {
2602
key = parseVariableIdentifier();
2603
if (match('=')) {
2604
lex();
2605
init = parseAssignmentExpression();
2606
return node.finishProperty(
2607
'init', key, false,
2608
new WrappingNode(key).finishAssignmentPattern(key, init), false, false);
2609
} else if (!match(':')) {
2610
return node.finishProperty('init', key, false, key, false, true);
2611
}
2612
} else {
2613
key = parseObjectPropertyKey();
2614
}
2615
expect(':');
2616
init = parsePatternWithDefault();
2617
return node.finishProperty('init', key, computed, init, false, false);
2618
}
2619
2620
function parseObjectPattern() {
2621
var node = new Node(), properties = [];
2622
2623
expect('{');
2624
2625
while (!match('}')) {
2626
properties.push(parsePropertyPattern());
2627
if (!match('}')) {
2628
expect(',');
2629
}
2630
}
2631
2632
lex();
2633
2634
return node.finishObjectPattern(properties);
2635
}
2636
2637
function parsePattern() {
2638
if (lookahead.type === Token.Identifier) {
2639
return parseVariableIdentifier();
2640
} else if (match('[')) {
2641
return parseArrayPattern();
2642
} else if (match('{')) {
2643
return parseObjectPattern();
2644
}
2645
throwUnexpectedToken(lookahead);
2646
}
2647
2648
function parsePatternWithDefault() {
2649
var startToken = lookahead, pattern, right;
2650
pattern = parsePattern();
2651
if (match('=')) {
2652
lex();
2653
right = isolateCoverGrammar(parseAssignmentExpression);
2654
pattern = new WrappingNode(startToken).finishAssignmentPattern(pattern, right);
2655
}
2656
return pattern;
2657
}
2658
2659
// 11.1.4 Array Initialiser
2660
2661
function parseArrayInitialiser() {
2662
var elements = [], node = new Node(), restSpread;
2663
2664
expect('[');
2665
2666
while (!match(']')) {
2667
if (match(',')) {
2668
lex();
2669
elements.push(null);
2670
} else if (match('...')) {
2671
restSpread = new Node();
2672
lex();
2673
restSpread.finishSpreadElement(inheritCoverGrammar(parseAssignmentExpression));
2674
2675
if (!match(']')) {
2676
isAssignmentTarget = isBindingElement = false;
2677
expect(',');
2678
}
2679
elements.push(restSpread);
2680
} else {
2681
elements.push(inheritCoverGrammar(parseAssignmentExpression));
2682
2683
if (!match(']')) {
2684
expect(',');
2685
}
2686
}
2687
}
2688
2689
lex();
2690
2691
return node.finishArrayExpression(elements);
2692
}
2693
2694
// 11.1.5 Object Initialiser
2695
2696
function parsePropertyFunction(node, paramInfo) {
2697
var previousStrict, body;
2698
2699
isAssignmentTarget = isBindingElement = false;
2700
2701
previousStrict = strict;
2702
body = isolateCoverGrammar(parseFunctionSourceElements);
2703
2704
if (strict && paramInfo.firstRestricted) {
2705
tolerateUnexpectedToken(paramInfo.firstRestricted, paramInfo.message);
2706
}
2707
if (strict && paramInfo.stricted) {
2708
tolerateUnexpectedToken(paramInfo.stricted, paramInfo.message);
2709
}
2710
2711
strict = previousStrict;
2712
return node.finishFunctionExpression(null, paramInfo.params, paramInfo.defaults, body);
2713
}
2714
2715
function parsePropertyMethodFunction() {
2716
var params, method, node = new Node();
2717
2718
params = parseParams();
2719
method = parsePropertyFunction(node, params);
2720
2721
return method;
2722
}
2723
2724
function parseObjectPropertyKey() {
2725
var token, node = new Node(), expr;
2726
2727
token = lex();
2728
2729
// Note: This function is called only from parseObjectProperty(), where
2730
// EOF and Punctuator tokens are already filtered out.
2731
2732
switch (token.type) {
2733
case Token.StringLiteral:
2734
case Token.NumericLiteral:
2735
if (strict && token.octal) {
2736
tolerateUnexpectedToken(token, Messages.StrictOctalLiteral);
2737
}
2738
return node.finishLiteral(token);
2739
case Token.Identifier:
2740
case Token.BooleanLiteral:
2741
case Token.NullLiteral:
2742
case Token.Keyword:
2743
return node.finishIdentifier(token.value);
2744
case Token.Punctuator:
2745
if (token.value === '[') {
2746
expr = isolateCoverGrammar(parseAssignmentExpression);
2747
expect(']');
2748
return expr;
2749
}
2750
break;
2751
}
2752
throwUnexpectedToken(token);
2753
}
2754
2755
function lookaheadPropertyName() {
2756
switch (lookahead.type) {
2757
case Token.Identifier:
2758
case Token.StringLiteral:
2759
case Token.BooleanLiteral:
2760
case Token.NullLiteral:
2761
case Token.NumericLiteral:
2762
case Token.Keyword:
2763
return true;
2764
case Token.Punctuator:
2765
return lookahead.value === '[';
2766
}
2767
return false;
2768
}
2769
2770
// This function is to try to parse a MethodDefinition as defined in 14.3. But in the case of object literals,
2771
// it might be called at a position where there is in fact a short hand identifier pattern or a data property.
2772
// This can only be determined after we consumed up to the left parentheses.
2773
//
2774
// In order to avoid back tracking, it returns `null` if the position is not a MethodDefinition and the caller
2775
// is responsible to visit other options.
2776
function tryParseMethodDefinition(token, key, computed, node) {
2777
var value, options, methodNode;
2778
2779
if (token.type === Token.Identifier) {
2780
// check for `get` and `set`;
2781
2782
if (token.value === 'get' && lookaheadPropertyName()) {
2783
computed = match('[');
2784
key = parseObjectPropertyKey();
2785
methodNode = new Node();
2786
expect('(');
2787
expect(')');
2788
value = parsePropertyFunction(methodNode, {
2789
params: [],
2790
defaults: [],
2791
stricted: null,
2792
firstRestricted: null,
2793
message: null
2794
});
2795
return node.finishProperty('get', key, computed, value, false, false);
2796
} else if (token.value === 'set' && lookaheadPropertyName()) {
2797
computed = match('[');
2798
key = parseObjectPropertyKey();
2799
methodNode = new Node();
2800
expect('(');
2801
2802
options = {
2803
params: [],
2804
defaultCount: 0,
2805
defaults: [],
2806
firstRestricted: null,
2807
paramSet: {}
2808
};
2809
if (match(')')) {
2810
tolerateUnexpectedToken(lookahead);
2811
} else {
2812
parseParam(options);
2813
if (options.defaultCount === 0) {
2814
options.defaults = [];
2815
}
2816
}
2817
expect(')');
2818
2819
value = parsePropertyFunction(methodNode, options);
2820
return node.finishProperty('set', key, computed, value, false, false);
2821
}
2822
}
2823
2824
if (match('(')) {
2825
value = parsePropertyMethodFunction();
2826
return node.finishProperty('init', key, computed, value, true, false);
2827
}
2828
2829
// Not a MethodDefinition.
2830
return null;
2831
}
2832
2833
function checkProto(key, computed, hasProto) {
2834
if (computed === false && (key.type === Syntax.Identifier && key.name === '__proto__' ||
2835
key.type === Syntax.Literal && key.value === '__proto__')) {
2836
if (hasProto.value) {
2837
tolerateError(Messages.DuplicateProtoProperty);
2838
} else {
2839
hasProto.value = true;
2840
}
2841
}
2842
}
2843
2844
function parseObjectProperty(hasProto) {
2845
var token = lookahead, node = new Node(), computed, key, maybeMethod, value;
2846
2847
computed = match('[');
2848
key = parseObjectPropertyKey();
2849
maybeMethod = tryParseMethodDefinition(token, key, computed, node);
2850
2851
if (maybeMethod) {
2852
checkProto(maybeMethod.key, maybeMethod.computed, hasProto);
2853
// finished
2854
return maybeMethod;
2855
}
2856
2857
// init property or short hand property.
2858
checkProto(key, computed, hasProto);
2859
2860
if (match(':')) {
2861
lex();
2862
value = inheritCoverGrammar(parseAssignmentExpression);
2863
return node.finishProperty('init', key, computed, value, false, false);
2864
}
2865
2866
if (token.type === Token.Identifier) {
2867
if (match('=')) {
2868
firstCoverInitializedNameError = lookahead;
2869
lex();
2870
value = isolateCoverGrammar(parseAssignmentExpression);
2871
return node.finishProperty('init', key, computed,
2872
new WrappingNode(token).finishAssignmentPattern(key, value), false, true);
2873
}
2874
return node.finishProperty('init', key, computed, key, false, true);
2875
}
2876
2877
throwUnexpectedToken(lookahead);
2878
}
2879
2880
function parseObjectInitialiser() {
2881
var properties = [], hasProto = {value: false}, node = new Node();
2882
2883
expect('{');
2884
2885
while (!match('}')) {
2886
properties.push(parseObjectProperty(hasProto));
2887
2888
if (!match('}')) {
2889
expectCommaSeparator();
2890
}
2891
}
2892
2893
expect('}');
2894
2895
return node.finishObjectExpression(properties);
2896
}
2897
2898
function reinterpretExpressionAsPattern(expr) {
2899
var i;
2900
switch (expr.type) {
2901
case Syntax.Identifier:
2902
case Syntax.MemberExpression:
2903
case Syntax.RestElement:
2904
case Syntax.AssignmentPattern:
2905
break;
2906
case Syntax.SpreadElement:
2907
expr.type = Syntax.RestElement;
2908
reinterpretExpressionAsPattern(expr.argument);
2909
break;
2910
case Syntax.ArrayExpression:
2911
expr.type = Syntax.ArrayPattern;
2912
for (i = 0; i < expr.elements.length; i++) {
2913
if (expr.elements[i] !== null) {
2914
reinterpretExpressionAsPattern(expr.elements[i]);
2915
}
2916
}
2917
break;
2918
case Syntax.ObjectExpression:
2919
expr.type = Syntax.ObjectPattern;
2920
for (i = 0; i < expr.properties.length; i++) {
2921
reinterpretExpressionAsPattern(expr.properties[i].value);
2922
}
2923
break;
2924
case Syntax.AssignmentExpression:
2925
expr.type = Syntax.AssignmentPattern;
2926
reinterpretExpressionAsPattern(expr.left);
2927
break;
2928
default:
2929
// Allow other node type for tolerant parsing.
2930
break;
2931
}
2932
}
2933
2934
function parseTemplateElement(option) {
2935
var node, token;
2936
2937
if (lookahead.type !== Token.Template || (option.head && !lookahead.head)) {
2938
throwUnexpectedToken();
2939
}
2940
2941
node = new Node();
2942
token = lex();
2943
2944
return node.finishTemplateElement({ raw: token.value.raw, cooked: token.value.cooked }, token.tail);
2945
}
2946
2947
function parseTemplateLiteral() {
2948
var quasi, quasis, expressions, node = new Node();
2949
2950
quasi = parseTemplateElement({ head: true });
2951
quasis = [ quasi ];
2952
expressions = [];
2953
2954
while (!quasi.tail) {
2955
expressions.push(parseExpression());
2956
quasi = parseTemplateElement({ head: false });
2957
quasis.push(quasi);
2958
}
2959
2960
return node.finishTemplateLiteral(quasis, expressions);
2961
}
2962
2963
// 11.1.6 The Grouping Operator
2964
2965
function parseGroupExpression() {
2966
var expr, expressions, startToken, i;
2967
2968
expect('(');
2969
2970
if (match(')')) {
2971
lex();
2972
if (!match('=>')) {
2973
expect('=>');
2974
}
2975
return {
2976
type: PlaceHolders.ArrowParameterPlaceHolder,
2977
params: []
2978
};
2979
}
2980
2981
startToken = lookahead;
2982
if (match('...')) {
2983
expr = parseRestElement();
2984
expect(')');
2985
if (!match('=>')) {
2986
expect('=>');
2987
}
2988
return {
2989
type: PlaceHolders.ArrowParameterPlaceHolder,
2990
params: [expr]
2991
};
2992
}
2993
2994
isBindingElement = true;
2995
expr = inheritCoverGrammar(parseAssignmentExpression);
2996
2997
if (match(',')) {
2998
isAssignmentTarget = false;
2999
expressions = [expr];
3000
3001
while (startIndex < length) {
3002
if (!match(',')) {
3003
break;
3004
}
3005
lex();
3006
3007
if (match('...')) {
3008
if (!isBindingElement) {
3009
throwUnexpectedToken(lookahead);
3010
}
3011
expressions.push(parseRestElement());
3012
expect(')');
3013
if (!match('=>')) {
3014
expect('=>');
3015
}
3016
isBindingElement = false;
3017
for (i = 0; i < expressions.length; i++) {
3018
reinterpretExpressionAsPattern(expressions[i]);
3019
}
3020
return {
3021
type: PlaceHolders.ArrowParameterPlaceHolder,
3022
params: expressions
3023
};
3024
}
3025
3026
expressions.push(inheritCoverGrammar(parseAssignmentExpression));
3027
}
3028
3029
expr = new WrappingNode(startToken).finishSequenceExpression(expressions);
3030
}
3031
3032
3033
expect(')');
3034
3035
if (match('=>')) {
3036
if (!isBindingElement) {
3037
throwUnexpectedToken(lookahead);
3038
}
3039
3040
if (expr.type === Syntax.SequenceExpression) {
3041
for (i = 0; i < expr.expressions.length; i++) {
3042
reinterpretExpressionAsPattern(expr.expressions[i]);
3043
}
3044
} else {
3045
reinterpretExpressionAsPattern(expr);
3046
}
3047
3048
expr = {
3049
type: PlaceHolders.ArrowParameterPlaceHolder,
3050
params: expr.type === Syntax.SequenceExpression ? expr.expressions : [expr]
3051
};
3052
}
3053
isBindingElement = false;
3054
return expr;
3055
}
3056
3057
3058
// 11.1 Primary Expressions
3059
3060
function parsePrimaryExpression() {
3061
var type, token, expr, node;
3062
3063
if (match('(')) {
3064
isBindingElement = false;
3065
return inheritCoverGrammar(parseGroupExpression);
3066
}
3067
3068
if (match('[')) {
3069
return inheritCoverGrammar(parseArrayInitialiser);
3070
}
3071
3072
if (match('{')) {
3073
return inheritCoverGrammar(parseObjectInitialiser);
3074
}
3075
3076
type = lookahead.type;
3077
node = new Node();
3078
3079
if (type === Token.Identifier) {
3080
expr = node.finishIdentifier(lex().value);
3081
} else if (type === Token.StringLiteral || type === Token.NumericLiteral) {
3082
isAssignmentTarget = isBindingElement = false;
3083
if (strict && lookahead.octal) {
3084
tolerateUnexpectedToken(lookahead, Messages.StrictOctalLiteral);
3085
}
3086
expr = node.finishLiteral(lex());
3087
} else if (type === Token.Keyword) {
3088
isAssignmentTarget = isBindingElement = false;
3089
if (matchKeyword('function')) {
3090
return parseFunctionExpression();
3091
}
3092
if (matchKeyword('this')) {
3093
lex();
3094
return node.finishThisExpression();
3095
}
3096
if (matchKeyword('class')) {
3097
return parseClassExpression();
3098
}
3099
throwUnexpectedToken(lex());
3100
} else if (type === Token.BooleanLiteral) {
3101
isAssignmentTarget = isBindingElement = false;
3102
token = lex();
3103
token.value = (token.value === 'true');
3104
expr = node.finishLiteral(token);
3105
} else if (type === Token.NullLiteral) {
3106
isAssignmentTarget = isBindingElement = false;
3107
token = lex();
3108
token.value = null;
3109
expr = node.finishLiteral(token);
3110
} else if (match('/') || match('/=')) {
3111
isAssignmentTarget = isBindingElement = false;
3112
index = startIndex;
3113
3114
if (typeof extra.tokens !== 'undefined') {
3115
token = collectRegex();
3116
} else {
3117
token = scanRegExp();
3118
}
3119
lex();
3120
expr = node.finishLiteral(token);
3121
} else if (type === Token.Template) {
3122
expr = parseTemplateLiteral();
3123
} else {
3124
throwUnexpectedToken(lex());
3125
}
3126
3127
return expr;
3128
}
3129
3130
// 11.2 Left-Hand-Side Expressions
3131
3132
function parseArguments() {
3133
var args = [];
3134
3135
expect('(');
3136
3137
if (!match(')')) {
3138
while (startIndex < length) {
3139
args.push(isolateCoverGrammar(parseAssignmentExpression));
3140
if (match(')')) {
3141
break;
3142
}
3143
expectCommaSeparator();
3144
}
3145
}
3146
3147
expect(')');
3148
3149
return args;
3150
}
3151
3152
function parseNonComputedProperty() {
3153
var token, node = new Node();
3154
3155
token = lex();
3156
3157
if (!isIdentifierName(token)) {
3158
throwUnexpectedToken(token);
3159
}
3160
3161
return node.finishIdentifier(token.value);
3162
}
3163
3164
function parseNonComputedMember() {
3165
expect('.');
3166
3167
return parseNonComputedProperty();
3168
}
3169
3170
function parseComputedMember() {
3171
var expr;
3172
3173
expect('[');
3174
3175
expr = isolateCoverGrammar(parseExpression);
3176
3177
expect(']');
3178
3179
return expr;
3180
}
3181
3182
function parseNewExpression() {
3183
var callee, args, node = new Node();
3184
3185
expectKeyword('new');
3186
callee = isolateCoverGrammar(parseLeftHandSideExpression);
3187
args = match('(') ? parseArguments() : [];
3188
3189
isAssignmentTarget = isBindingElement = false;
3190
3191
return node.finishNewExpression(callee, args);
3192
}
3193
3194
function parseLeftHandSideExpressionAllowCall() {
3195
var quasi, expr, args, property, startToken, previousAllowIn = state.allowIn;
3196
3197
startToken = lookahead;
3198
state.allowIn = true;
3199
3200
if (matchKeyword('super') && state.inFunctionBody) {
3201
expr = new Node();
3202
lex();
3203
expr = expr.finishSuper();
3204
if (!match('(') && !match('.') && !match('[')) {
3205
throwUnexpectedToken(lookahead);
3206
}
3207
} else {
3208
expr = inheritCoverGrammar(matchKeyword('new') ? parseNewExpression : parsePrimaryExpression);
3209
}
3210
3211
for (;;) {
3212
if (match('.')) {
3213
isBindingElement = false;
3214
isAssignmentTarget = true;
3215
property = parseNonComputedMember();
3216
expr = new WrappingNode(startToken).finishMemberExpression('.', expr, property);
3217
} else if (match('(')) {
3218
isBindingElement = false;
3219
isAssignmentTarget = false;
3220
args = parseArguments();
3221
expr = new WrappingNode(startToken).finishCallExpression(expr, args);
3222
} else if (match('[')) {
3223
isBindingElement = false;
3224
isAssignmentTarget = true;
3225
property = parseComputedMember();
3226
expr = new WrappingNode(startToken).finishMemberExpression('[', expr, property);
3227
} else if (lookahead.type === Token.Template && lookahead.head) {
3228
quasi = parseTemplateLiteral();
3229
expr = new WrappingNode(startToken).finishTaggedTemplateExpression(expr, quasi);
3230
} else {
3231
break;
3232
}
3233
}
3234
state.allowIn = previousAllowIn;
3235
3236
return expr;
3237
}
3238
3239
function parseLeftHandSideExpression() {
3240
var quasi, expr, property, startToken;
3241
assert(state.allowIn, 'callee of new expression always allow in keyword.');
3242
3243
startToken = lookahead;
3244
3245
if (matchKeyword('super') && state.inFunctionBody) {
3246
expr = new Node();
3247
lex();
3248
expr = expr.finishSuper();
3249
if (!match('[') && !match('.')) {
3250
throwUnexpectedToken(lookahead);
3251
}
3252
} else {
3253
expr = inheritCoverGrammar(matchKeyword('new') ? parseNewExpression : parsePrimaryExpression);
3254
}
3255
3256
for (;;) {
3257
if (match('[')) {
3258
isBindingElement = false;
3259
isAssignmentTarget = true;
3260
property = parseComputedMember();
3261
expr = new WrappingNode(startToken).finishMemberExpression('[', expr, property);
3262
} else if (match('.')) {
3263
isBindingElement = false;
3264
isAssignmentTarget = true;
3265
property = parseNonComputedMember();
3266
expr = new WrappingNode(startToken).finishMemberExpression('.', expr, property);
3267
} else if (lookahead.type === Token.Template && lookahead.head) {
3268
quasi = parseTemplateLiteral();
3269
expr = new WrappingNode(startToken).finishTaggedTemplateExpression(expr, quasi);
3270
} else {
3271
break;
3272
}
3273
}
3274
return expr;
3275
}
3276
3277
// 11.3 Postfix Expressions
3278
3279
function parsePostfixExpression() {
3280
var expr, token, startToken = lookahead;
3281
3282
expr = inheritCoverGrammar(parseLeftHandSideExpressionAllowCall);
3283
3284
if (!hasLineTerminator && lookahead.type === Token.Punctuator) {
3285
if (match('++') || match('--')) {
3286
// 11.3.1, 11.3.2
3287
if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) {
3288
tolerateError(Messages.StrictLHSPostfix);
3289
}
3290
3291
if (!isAssignmentTarget) {
3292
tolerateError(Messages.InvalidLHSInAssignment);
3293
}
3294
3295
isAssignmentTarget = isBindingElement = false;
3296
3297
token = lex();
3298
expr = new WrappingNode(startToken).finishPostfixExpression(token.value, expr);
3299
}
3300
}
3301
3302
return expr;
3303
}
3304
3305
// 11.4 Unary Operators
3306
3307
function parseUnaryExpression() {
3308
var token, expr, startToken;
3309
3310
if (lookahead.type !== Token.Punctuator && lookahead.type !== Token.Keyword) {
3311
expr = parsePostfixExpression();
3312
} else if (match('++') || match('--')) {
3313
startToken = lookahead;
3314
token = lex();
3315
expr = inheritCoverGrammar(parseUnaryExpression);
3316
// 11.4.4, 11.4.5
3317
if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) {
3318
tolerateError(Messages.StrictLHSPrefix);
3319
}
3320
3321
if (!isAssignmentTarget) {
3322
tolerateError(Messages.InvalidLHSInAssignment);
3323
}
3324
expr = new WrappingNode(startToken).finishUnaryExpression(token.value, expr);
3325
isAssignmentTarget = isBindingElement = false;
3326
} else if (match('+') || match('-') || match('~') || match('!')) {
3327
startToken = lookahead;
3328
token = lex();
3329
expr = inheritCoverGrammar(parseUnaryExpression);
3330
expr = new WrappingNode(startToken).finishUnaryExpression(token.value, expr);
3331
isAssignmentTarget = isBindingElement = false;
3332
} else if (matchKeyword('delete') || matchKeyword('void') || matchKeyword('typeof')) {
3333
startToken = lookahead;
3334
token = lex();
3335
expr = inheritCoverGrammar(parseUnaryExpression);
3336
expr = new WrappingNode(startToken).finishUnaryExpression(token.value, expr);
3337
if (strict && expr.operator === 'delete' && expr.argument.type === Syntax.Identifier) {
3338
tolerateError(Messages.StrictDelete);
3339
}
3340
isAssignmentTarget = isBindingElement = false;
3341
} else {
3342
expr = parsePostfixExpression();
3343
}
3344
3345
return expr;
3346
}
3347
3348
function binaryPrecedence(token, allowIn) {
3349
var prec = 0;
3350
3351
if (token.type !== Token.Punctuator && token.type !== Token.Keyword) {
3352
return 0;
3353
}
3354
3355
switch (token.value) {
3356
case '||':
3357
prec = 1;
3358
break;
3359
3360
case '&&':
3361
prec = 2;
3362
break;
3363
3364
case '|':
3365
prec = 3;
3366
break;
3367
3368
case '^':
3369
prec = 4;
3370
break;
3371
3372
case '&':
3373
prec = 5;
3374
break;
3375
3376
case '==':
3377
case '!=':
3378
case '===':
3379
case '!==':
3380
prec = 6;
3381
break;
3382
3383
case '<':
3384
case '>':
3385
case '<=':
3386
case '>=':
3387
case 'instanceof':
3388
prec = 7;
3389
break;
3390
3391
case 'in':
3392
prec = allowIn ? 7 : 0;
3393
break;
3394
3395
case '<<':
3396
case '>>':
3397
case '>>>':
3398
prec = 8;
3399
break;
3400
3401
case '+':
3402
case '-':
3403
prec = 9;
3404
break;
3405
3406
case '*':
3407
case '/':
3408
case '%':
3409
prec = 11;
3410
break;
3411
3412
default:
3413
break;
3414
}
3415
3416
return prec;
3417
}
3418
3419
// 11.5 Multiplicative Operators
3420
// 11.6 Additive Operators
3421
// 11.7 Bitwise Shift Operators
3422
// 11.8 Relational Operators
3423
// 11.9 Equality Operators
3424
// 11.10 Binary Bitwise Operators
3425
// 11.11 Binary Logical Operators
3426
3427
function parseBinaryExpression() {
3428
var marker, markers, expr, token, prec, stack, right, operator, left, i;
3429
3430
marker = lookahead;
3431
left = inheritCoverGrammar(parseUnaryExpression);
3432
3433
token = lookahead;
3434
prec = binaryPrecedence(token, state.allowIn);
3435
if (prec === 0) {
3436
return left;
3437
}
3438
isAssignmentTarget = isBindingElement = false;
3439
token.prec = prec;
3440
lex();
3441
3442
markers = [marker, lookahead];
3443
right = isolateCoverGrammar(parseUnaryExpression);
3444
3445
stack = [left, token, right];
3446
3447
while ((prec = binaryPrecedence(lookahead, state.allowIn)) > 0) {
3448
3449
// Reduce: make a binary expression from the three topmost entries.
3450
while ((stack.length > 2) && (prec <= stack[stack.length - 2].prec)) {
3451
right = stack.pop();
3452
operator = stack.pop().value;
3453
left = stack.pop();
3454
markers.pop();
3455
expr = new WrappingNode(markers[markers.length - 1]).finishBinaryExpression(operator, left, right);
3456
stack.push(expr);
3457
}
3458
3459
// Shift.
3460
token = lex();
3461
token.prec = prec;
3462
stack.push(token);
3463
markers.push(lookahead);
3464
expr = isolateCoverGrammar(parseUnaryExpression);
3465
stack.push(expr);
3466
}
3467
3468
// Final reduce to clean-up the stack.
3469
i = stack.length - 1;
3470
expr = stack[i];
3471
markers.pop();
3472
while (i > 1) {
3473
expr = new WrappingNode(markers.pop()).finishBinaryExpression(stack[i - 1].value, stack[i - 2], expr);
3474
i -= 2;
3475
}
3476
3477
return expr;
3478
}
3479
3480
3481
// 11.12 Conditional Operator
3482
3483
function parseConditionalExpression() {
3484
var expr, previousAllowIn, consequent, alternate, startToken;
3485
3486
startToken = lookahead;
3487
3488
expr = inheritCoverGrammar(parseBinaryExpression);
3489
if (match('?')) {
3490
lex();
3491
previousAllowIn = state.allowIn;
3492
state.allowIn = true;
3493
consequent = isolateCoverGrammar(parseAssignmentExpression);
3494
state.allowIn = previousAllowIn;
3495
expect(':');
3496
alternate = isolateCoverGrammar(parseAssignmentExpression);
3497
3498
expr = new WrappingNode(startToken).finishConditionalExpression(expr, consequent, alternate);
3499
isAssignmentTarget = isBindingElement = false;
3500
}
3501
3502
return expr;
3503
}
3504
3505
// [ES6] 14.2 Arrow Function
3506
3507
function parseConciseBody() {
3508
if (match('{')) {
3509
return parseFunctionSourceElements();
3510
}
3511
return isolateCoverGrammar(parseAssignmentExpression);
3512
}
3513
3514
function checkPatternParam(options, param) {
3515
var i;
3516
switch (param.type) {
3517
case Syntax.Identifier:
3518
validateParam(options, param, param.name);
3519
break;
3520
case Syntax.RestElement:
3521
checkPatternParam(options, param.argument);
3522
break;
3523
case Syntax.AssignmentPattern:
3524
checkPatternParam(options, param.left);
3525
break;
3526
case Syntax.ArrayPattern:
3527
for (i = 0; i < param.elements.length; i++) {
3528
if (param.elements[i] !== null) {
3529
checkPatternParam(options, param.elements[i]);
3530
}
3531
}
3532
break;
3533
default:
3534
assert(param.type === Syntax.ObjectPattern, 'Invalid type');
3535
for (i = 0; i < param.properties.length; i++) {
3536
checkPatternParam(options, param.properties[i].value);
3537
}
3538
break;
3539
}
3540
}
3541
function reinterpretAsCoverFormalsList(expr) {
3542
var i, len, param, params, defaults, defaultCount, options, token;
3543
3544
defaults = [];
3545
defaultCount = 0;
3546
params = [expr];
3547
3548
switch (expr.type) {
3549
case Syntax.Identifier:
3550
break;
3551
case PlaceHolders.ArrowParameterPlaceHolder:
3552
params = expr.params;
3553
break;
3554
default:
3555
return null;
3556
}
3557
3558
options = {
3559
paramSet: {}
3560
};
3561
3562
for (i = 0, len = params.length; i < len; i += 1) {
3563
param = params[i];
3564
switch (param.type) {
3565
case Syntax.AssignmentPattern:
3566
params[i] = param.left;
3567
defaults.push(param.right);
3568
++defaultCount;
3569
checkPatternParam(options, param.left);
3570
break;
3571
default:
3572
checkPatternParam(options, param);
3573
params[i] = param;
3574
defaults.push(null);
3575
break;
3576
}
3577
}
3578
3579
if (options.message === Messages.StrictParamDupe) {
3580
token = strict ? options.stricted : options.firstRestricted;
3581
throwUnexpectedToken(token, options.message);
3582
}
3583
3584
if (defaultCount === 0) {
3585
defaults = [];
3586
}
3587
3588
return {
3589
params: params,
3590
defaults: defaults,
3591
stricted: options.stricted,
3592
firstRestricted: options.firstRestricted,
3593
message: options.message
3594
};
3595
}
3596
3597
function parseArrowFunctionExpression(options, node) {
3598
var previousStrict, body;
3599
3600
if (hasLineTerminator) {
3601
tolerateUnexpectedToken(lookahead);
3602
}
3603
expect('=>');
3604
previousStrict = strict;
3605
3606
body = parseConciseBody();
3607
3608
if (strict && options.firstRestricted) {
3609
throwUnexpectedToken(options.firstRestricted, options.message);
3610
}
3611
if (strict && options.stricted) {
3612
tolerateUnexpectedToken(options.stricted, options.message);
3613
}
3614
3615
strict = previousStrict;
3616
3617
return node.finishArrowFunctionExpression(options.params, options.defaults, body, body.type !== Syntax.BlockStatement);
3618
}
3619
3620
// 11.13 Assignment Operators
3621
3622
function parseAssignmentExpression() {
3623
var token, expr, right, list, startToken;
3624
3625
startToken = lookahead;
3626
token = lookahead;
3627
3628
expr = parseConditionalExpression();
3629
3630
if (expr.type === PlaceHolders.ArrowParameterPlaceHolder || match('=>')) {
3631
isAssignmentTarget = isBindingElement = false;
3632
list = reinterpretAsCoverFormalsList(expr);
3633
3634
if (list) {
3635
firstCoverInitializedNameError = null;
3636
return parseArrowFunctionExpression(list, new WrappingNode(startToken));
3637
}
3638
3639
return expr;
3640
}
3641
3642
if (matchAssign()) {
3643
if (!isAssignmentTarget) {
3644
tolerateError(Messages.InvalidLHSInAssignment);
3645
}
3646
3647
// 11.13.1
3648
if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) {
3649
tolerateUnexpectedToken(token, Messages.StrictLHSAssignment);
3650
}
3651
3652
if (!match('=')) {
3653
isAssignmentTarget = isBindingElement = false;
3654
} else {
3655
reinterpretExpressionAsPattern(expr);
3656
}
3657
3658
token = lex();
3659
right = isolateCoverGrammar(parseAssignmentExpression);
3660
expr = new WrappingNode(startToken).finishAssignmentExpression(token.value, expr, right);
3661
firstCoverInitializedNameError = null;
3662
}
3663
3664
return expr;
3665
}
3666
3667
// 11.14 Comma Operator
3668
3669
function parseExpression() {
3670
var expr, startToken = lookahead, expressions;
3671
3672
expr = isolateCoverGrammar(parseAssignmentExpression);
3673
3674
if (match(',')) {
3675
expressions = [expr];
3676
3677
while (startIndex < length) {
3678
if (!match(',')) {
3679
break;
3680
}
3681
lex();
3682
expressions.push(isolateCoverGrammar(parseAssignmentExpression));
3683
}
3684
3685
expr = new WrappingNode(startToken).finishSequenceExpression(expressions);
3686
}
3687
3688
return expr;
3689
}
3690
3691
// 12.1 Block
3692
3693
function parseStatementListItem() {
3694
if (lookahead.type === Token.Keyword) {
3695
switch (lookahead.value) {
3696
case 'export':
3697
if (sourceType !== 'module') {
3698
tolerateUnexpectedToken(lookahead, Messages.IllegalExportDeclaration);
3699
}
3700
return parseExportDeclaration();
3701
case 'import':
3702
if (sourceType !== 'module') {
3703
tolerateUnexpectedToken(lookahead, Messages.IllegalImportDeclaration);
3704
}
3705
return parseImportDeclaration();
3706
case 'const':
3707
case 'let':
3708
return parseLexicalDeclaration({inFor: false});
3709
case 'function':
3710
return parseFunctionDeclaration(new Node());
3711
case 'class':
3712
return parseClassDeclaration();
3713
}
3714
}
3715
3716
return parseStatement();
3717
}
3718
3719
function parseStatementList() {
3720
var list = [];
3721
while (startIndex < length) {
3722
if (match('}')) {
3723
break;
3724
}
3725
list.push(parseStatementListItem());
3726
}
3727
3728
return list;
3729
}
3730
3731
function parseBlock() {
3732
var block, node = new Node();
3733
3734
expect('{');
3735
3736
block = parseStatementList();
3737
3738
expect('}');
3739
3740
return node.finishBlockStatement(block);
3741
}
3742
3743
// 12.2 Variable Statement
3744
3745
function parseVariableIdentifier() {
3746
var token, node = new Node();
3747
3748
token = lex();
3749
3750
if (token.type !== Token.Identifier) {
3751
if (strict && token.type === Token.Keyword && isStrictModeReservedWord(token.value)) {
3752
tolerateUnexpectedToken(token, Messages.StrictReservedWord);
3753
} else {
3754
throwUnexpectedToken(token);
3755
}
3756
}
3757
3758
return node.finishIdentifier(token.value);
3759
}
3760
3761
function parseVariableDeclaration() {
3762
var init = null, id, node = new Node();
3763
3764
id = parsePattern();
3765
3766
// 12.2.1
3767
if (strict && isRestrictedWord(id.name)) {
3768
tolerateError(Messages.StrictVarName);
3769
}
3770
3771
if (match('=')) {
3772
lex();
3773
init = isolateCoverGrammar(parseAssignmentExpression);
3774
} else if (id.type !== Syntax.Identifier) {
3775
expect('=');
3776
}
3777
3778
return node.finishVariableDeclarator(id, init);
3779
}
3780
3781
function parseVariableDeclarationList() {
3782
var list = [];
3783
3784
do {
3785
list.push(parseVariableDeclaration());
3786
if (!match(',')) {
3787
break;
3788
}
3789
lex();
3790
} while (startIndex < length);
3791
3792
return list;
3793
}
3794
3795
function parseVariableStatement(node) {
3796
var declarations;
3797
3798
expectKeyword('var');
3799
3800
declarations = parseVariableDeclarationList();
3801
3802
consumeSemicolon();
3803
3804
return node.finishVariableDeclaration(declarations);
3805
}
3806
3807
function parseLexicalBinding(kind, options) {
3808
var init = null, id, node = new Node();
3809
3810
id = parsePattern();
3811
3812
// 12.2.1
3813
if (strict && id.type === Syntax.Identifier && isRestrictedWord(id.name)) {
3814
tolerateError(Messages.StrictVarName);
3815
}
3816
3817
if (kind === 'const') {
3818
if (!matchKeyword('in')) {
3819
expect('=');
3820
init = isolateCoverGrammar(parseAssignmentExpression);
3821
}
3822
} else if ((!options.inFor && id.type !== Syntax.Identifier) || match('=')) {
3823
expect('=');
3824
init = isolateCoverGrammar(parseAssignmentExpression);
3825
}
3826
3827
return node.finishVariableDeclarator(id, init);
3828
}
3829
3830
function parseBindingList(kind, options) {
3831
var list = [];
3832
3833
do {
3834
list.push(parseLexicalBinding(kind, options));
3835
if (!match(',')) {
3836
break;
3837
}
3838
lex();
3839
} while (startIndex < length);
3840
3841
return list;
3842
}
3843
3844
function parseLexicalDeclaration(options) {
3845
var kind, declarations, node = new Node();
3846
3847
kind = lex().value;
3848
assert(kind === 'let' || kind === 'const', 'Lexical declaration must be either let or const');
3849
3850
declarations = parseBindingList(kind, options);
3851
3852
consumeSemicolon();
3853
3854
return node.finishLexicalDeclaration(declarations, kind);
3855
}
3856
3857
function parseRestElement() {
3858
var param, node = new Node();
3859
3860
lex();
3861
3862
if (match('{')) {
3863
throwError(Messages.ObjectPatternAsRestParameter);
3864
}
3865
3866
param = parseVariableIdentifier();
3867
3868
if (match('=')) {
3869
throwError(Messages.DefaultRestParameter);
3870
}
3871
3872
if (!match(')')) {
3873
throwError(Messages.ParameterAfterRestParameter);
3874
}
3875
3876
return node.finishRestElement(param);
3877
}
3878
3879
// 12.3 Empty Statement
3880
3881
function parseEmptyStatement(node) {
3882
expect(';');
3883
return node.finishEmptyStatement();
3884
}
3885
3886
// 12.4 Expression Statement
3887
3888
function parseExpressionStatement(node) {
3889
var expr = parseExpression();
3890
consumeSemicolon();
3891
return node.finishExpressionStatement(expr);
3892
}
3893
3894
// 12.5 If statement
3895
3896
function parseIfStatement(node) {
3897
var test, consequent, alternate;
3898
3899
expectKeyword('if');
3900
3901
expect('(');
3902
3903
test = parseExpression();
3904
3905
expect(')');
3906
3907
consequent = parseStatement();
3908
3909
if (matchKeyword('else')) {
3910
lex();
3911
alternate = parseStatement();
3912
} else {
3913
alternate = null;
3914
}
3915
3916
return node.finishIfStatement(test, consequent, alternate);
3917
}
3918
3919
// 12.6 Iteration Statements
3920
3921
function parseDoWhileStatement(node) {
3922
var body, test, oldInIteration;
3923
3924
expectKeyword('do');
3925
3926
oldInIteration = state.inIteration;
3927
state.inIteration = true;
3928
3929
body = parseStatement();
3930
3931
state.inIteration = oldInIteration;
3932
3933
expectKeyword('while');
3934
3935
expect('(');
3936
3937
test = parseExpression();
3938
3939
expect(')');
3940
3941
if (match(';')) {
3942
lex();
3943
}
3944
3945
return node.finishDoWhileStatement(body, test);
3946
}
3947
3948
function parseWhileStatement(node) {
3949
var test, body, oldInIteration;
3950
3951
expectKeyword('while');
3952
3953
expect('(');
3954
3955
test = parseExpression();
3956
3957
expect(')');
3958
3959
oldInIteration = state.inIteration;
3960
state.inIteration = true;
3961
3962
body = parseStatement();
3963
3964
state.inIteration = oldInIteration;
3965
3966
return node.finishWhileStatement(test, body);
3967
}
3968
3969
function parseForStatement(node) {
3970
var init, initSeq, initStartToken, test, update, left, right, kind, declarations,
3971
body, oldInIteration, previousAllowIn = state.allowIn;
3972
3973
init = test = update = null;
3974
3975
expectKeyword('for');
3976
3977
expect('(');
3978
3979
if (match(';')) {
3980
lex();
3981
} else {
3982
if (matchKeyword('var')) {
3983
init = new Node();
3984
lex();
3985
3986
state.allowIn = false;
3987
init = init.finishVariableDeclaration(parseVariableDeclarationList());
3988
state.allowIn = previousAllowIn;
3989
3990
if (init.declarations.length === 1 && matchKeyword('in')) {
3991
lex();
3992
left = init;
3993
right = parseExpression();
3994
init = null;
3995
} else {
3996
expect(';');
3997
}
3998
} else if (matchKeyword('const') || matchKeyword('let')) {
3999
init = new Node();
4000
kind = lex().value;
4001
4002
state.allowIn = false;
4003
declarations = parseBindingList(kind, {inFor: true});
4004
state.allowIn = previousAllowIn;
4005
4006
if (declarations.length === 1 && declarations[0].init === null && matchKeyword('in')) {
4007
init = init.finishLexicalDeclaration(declarations, kind);
4008
lex();
4009
left = init;
4010
right = parseExpression();
4011
init = null;
4012
} else {
4013
consumeSemicolon();
4014
init = init.finishLexicalDeclaration(declarations, kind);
4015
}
4016
} else {
4017
initStartToken = lookahead;
4018
state.allowIn = false;
4019
init = inheritCoverGrammar(parseAssignmentExpression);
4020
state.allowIn = previousAllowIn;
4021
4022
if (matchKeyword('in')) {
4023
if (!isAssignmentTarget) {
4024
tolerateError(Messages.InvalidLHSInForIn);
4025
}
4026
4027
lex();
4028
reinterpretExpressionAsPattern(init);
4029
left = init;
4030
right = parseExpression();
4031
init = null;
4032
} else {
4033
if (match(',')) {
4034
initSeq = [init];
4035
while (match(',')) {
4036
lex();
4037
initSeq.push(isolateCoverGrammar(parseAssignmentExpression));
4038
}
4039
init = new WrappingNode(initStartToken).finishSequenceExpression(initSeq);
4040
}
4041
expect(';');
4042
}
4043
}
4044
}
4045
4046
if (typeof left === 'undefined') {
4047
4048
if (!match(';')) {
4049
test = parseExpression();
4050
}
4051
expect(';');
4052
4053
if (!match(')')) {
4054
update = parseExpression();
4055
}
4056
}
4057
4058
expect(')');
4059
4060
oldInIteration = state.inIteration;
4061
state.inIteration = true;
4062
4063
body = isolateCoverGrammar(parseStatement);
4064
4065
state.inIteration = oldInIteration;
4066
4067
return (typeof left === 'undefined') ?
4068
node.finishForStatement(init, test, update, body) :
4069
node.finishForInStatement(left, right, body);
4070
}
4071
4072
// 12.7 The continue statement
4073
4074
function parseContinueStatement(node) {
4075
var label = null, key;
4076
4077
expectKeyword('continue');
4078
4079
// Optimize the most common form: 'continue;'.
4080
if (source.charCodeAt(startIndex) === 0x3B) {
4081
lex();
4082
4083
if (!state.inIteration) {
4084
throwError(Messages.IllegalContinue);
4085
}
4086
4087
return node.finishContinueStatement(null);
4088
}
4089
4090
if (hasLineTerminator) {
4091
if (!state.inIteration) {
4092
throwError(Messages.IllegalContinue);
4093
}
4094
4095
return node.finishContinueStatement(null);
4096
}
4097
4098
if (lookahead.type === Token.Identifier) {
4099
label = parseVariableIdentifier();
4100
4101
key = '$' + label.name;
4102
if (!Object.prototype.hasOwnProperty.call(state.labelSet, key)) {
4103
throwError(Messages.UnknownLabel, label.name);
4104
}
4105
}
4106
4107
consumeSemicolon();
4108
4109
if (label === null && !state.inIteration) {
4110
throwError(Messages.IllegalContinue);
4111
}
4112
4113
return node.finishContinueStatement(label);
4114
}
4115
4116
// 12.8 The break statement
4117
4118
function parseBreakStatement(node) {
4119
var label = null, key;
4120
4121
expectKeyword('break');
4122
4123
// Catch the very common case first: immediately a semicolon (U+003B).
4124
if (source.charCodeAt(lastIndex) === 0x3B) {
4125
lex();
4126
4127
if (!(state.inIteration || state.inSwitch)) {
4128
throwError(Messages.IllegalBreak);
4129
}
4130
4131
return node.finishBreakStatement(null);
4132
}
4133
4134
if (hasLineTerminator) {
4135
if (!(state.inIteration || state.inSwitch)) {
4136
throwError(Messages.IllegalBreak);
4137
}
4138
4139
return node.finishBreakStatement(null);
4140
}
4141
4142
if (lookahead.type === Token.Identifier) {
4143
label = parseVariableIdentifier();
4144
4145
key = '$' + label.name;
4146
if (!Object.prototype.hasOwnProperty.call(state.labelSet, key)) {
4147
throwError(Messages.UnknownLabel, label.name);
4148
}
4149
}
4150
4151
consumeSemicolon();
4152
4153
if (label === null && !(state.inIteration || state.inSwitch)) {
4154
throwError(Messages.IllegalBreak);
4155
}
4156
4157
return node.finishBreakStatement(label);
4158
}
4159
4160
// 12.9 The return statement
4161
4162
function parseReturnStatement(node) {
4163
var argument = null;
4164
4165
expectKeyword('return');
4166
4167
if (!state.inFunctionBody) {
4168
tolerateError(Messages.IllegalReturn);
4169
}
4170
4171
// 'return' followed by a space and an identifier is very common.
4172
if (source.charCodeAt(lastIndex) === 0x20) {
4173
if (isIdentifierStart(source.charCodeAt(lastIndex + 1))) {
4174
argument = parseExpression();
4175
consumeSemicolon();
4176
return node.finishReturnStatement(argument);
4177
}
4178
}
4179
4180
if (hasLineTerminator) {
4181
// HACK
4182
return node.finishReturnStatement(null);
4183
}
4184
4185
if (!match(';')) {
4186
if (!match('}') && lookahead.type !== Token.EOF) {
4187
argument = parseExpression();
4188
}
4189
}
4190
4191
consumeSemicolon();
4192
4193
return node.finishReturnStatement(argument);
4194
}
4195
4196
// 12.10 The with statement
4197
4198
function parseWithStatement(node) {
4199
var object, body;
4200
4201
if (strict) {
4202
tolerateError(Messages.StrictModeWith);
4203
}
4204
4205
expectKeyword('with');
4206
4207
expect('(');
4208
4209
object = parseExpression();
4210
4211
expect(')');
4212
4213
body = parseStatement();
4214
4215
return node.finishWithStatement(object, body);
4216
}
4217
4218
// 12.10 The swith statement
4219
4220
function parseSwitchCase() {
4221
var test, consequent = [], statement, node = new Node();
4222
4223
if (matchKeyword('default')) {
4224
lex();
4225
test = null;
4226
} else {
4227
expectKeyword('case');
4228
test = parseExpression();
4229
}
4230
expect(':');
4231
4232
while (startIndex < length) {
4233
if (match('}') || matchKeyword('default') || matchKeyword('case')) {
4234
break;
4235
}
4236
statement = parseStatementListItem();
4237
consequent.push(statement);
4238
}
4239
4240
return node.finishSwitchCase(test, consequent);
4241
}
4242
4243
function parseSwitchStatement(node) {
4244
var discriminant, cases, clause, oldInSwitch, defaultFound;
4245
4246
expectKeyword('switch');
4247
4248
expect('(');
4249
4250
discriminant = parseExpression();
4251
4252
expect(')');
4253
4254
expect('{');
4255
4256
cases = [];
4257
4258
if (match('}')) {
4259
lex();
4260
return node.finishSwitchStatement(discriminant, cases);
4261
}
4262
4263
oldInSwitch = state.inSwitch;
4264
state.inSwitch = true;
4265
defaultFound = false;
4266
4267
while (startIndex < length) {
4268
if (match('}')) {
4269
break;
4270
}
4271
clause = parseSwitchCase();
4272
if (clause.test === null) {
4273
if (defaultFound) {
4274
throwError(Messages.MultipleDefaultsInSwitch);
4275
}
4276
defaultFound = true;
4277
}
4278
cases.push(clause);
4279
}
4280
4281
state.inSwitch = oldInSwitch;
4282
4283
expect('}');
4284
4285
return node.finishSwitchStatement(discriminant, cases);
4286
}
4287
4288
// 12.13 The throw statement
4289
4290
function parseThrowStatement(node) {
4291
var argument;
4292
4293
expectKeyword('throw');
4294
4295
if (hasLineTerminator) {
4296
throwError(Messages.NewlineAfterThrow);
4297
}
4298
4299
argument = parseExpression();
4300
4301
consumeSemicolon();
4302
4303
return node.finishThrowStatement(argument);
4304
}
4305
4306
// 12.14 The try statement
4307
4308
function parseCatchClause() {
4309
var param, body, node = new Node();
4310
4311
expectKeyword('catch');
4312
4313
expect('(');
4314
if (match(')')) {
4315
throwUnexpectedToken(lookahead);
4316
}
4317
4318
param = parsePattern();
4319
4320
// 12.14.1
4321
if (strict && isRestrictedWord(param.name)) {
4322
tolerateError(Messages.StrictCatchVariable);
4323
}
4324
4325
expect(')');
4326
body = parseBlock();
4327
return node.finishCatchClause(param, body);
4328
}
4329
4330
function parseTryStatement(node) {
4331
var block, handler = null, finalizer = null;
4332
4333
expectKeyword('try');
4334
4335
block = parseBlock();
4336
4337
if (matchKeyword('catch')) {
4338
handler = parseCatchClause();
4339
}
4340
4341
if (matchKeyword('finally')) {
4342
lex();
4343
finalizer = parseBlock();
4344
}
4345
4346
if (!handler && !finalizer) {
4347
throwError(Messages.NoCatchOrFinally);
4348
}
4349
4350
return node.finishTryStatement(block, handler, finalizer);
4351
}
4352
4353
// 12.15 The debugger statement
4354
4355
function parseDebuggerStatement(node) {
4356
expectKeyword('debugger');
4357
4358
consumeSemicolon();
4359
4360
return node.finishDebuggerStatement();
4361
}
4362
4363
// 12 Statements
4364
4365
function parseStatement() {
4366
var type = lookahead.type,
4367
expr,
4368
labeledBody,
4369
key,
4370
node;
4371
4372
if (type === Token.EOF) {
4373
throwUnexpectedToken(lookahead);
4374
}
4375
4376
if (type === Token.Punctuator && lookahead.value === '{') {
4377
return parseBlock();
4378
}
4379
isAssignmentTarget = isBindingElement = true;
4380
node = new Node();
4381
4382
if (type === Token.Punctuator) {
4383
switch (lookahead.value) {
4384
case ';':
4385
return parseEmptyStatement(node);
4386
case '(':
4387
return parseExpressionStatement(node);
4388
default:
4389
break;
4390
}
4391
} else if (type === Token.Keyword) {
4392
switch (lookahead.value) {
4393
case 'break':
4394
return parseBreakStatement(node);
4395
case 'continue':
4396
return parseContinueStatement(node);
4397
case 'debugger':
4398
return parseDebuggerStatement(node);
4399
case 'do':
4400
return parseDoWhileStatement(node);
4401
case 'for':
4402
return parseForStatement(node);
4403
case 'function':
4404
return parseFunctionDeclaration(node);
4405
case 'if':
4406
return parseIfStatement(node);
4407
case 'return':
4408
return parseReturnStatement(node);
4409
case 'switch':
4410
return parseSwitchStatement(node);
4411
case 'throw':
4412
return parseThrowStatement(node);
4413
case 'try':
4414
return parseTryStatement(node);
4415
case 'var':
4416
return parseVariableStatement(node);
4417
case 'while':
4418
return parseWhileStatement(node);
4419
case 'with':
4420
return parseWithStatement(node);
4421
default:
4422
break;
4423
}
4424
}
4425
4426
expr = parseExpression();
4427
4428
// 12.12 Labelled Statements
4429
if ((expr.type === Syntax.Identifier) && match(':')) {
4430
lex();
4431
4432
key = '$' + expr.name;
4433
if (Object.prototype.hasOwnProperty.call(state.labelSet, key)) {
4434
throwError(Messages.Redeclaration, 'Label', expr.name);
4435
}
4436
4437
state.labelSet[key] = true;
4438
labeledBody = parseStatement();
4439
delete state.labelSet[key];
4440
return node.finishLabeledStatement(expr, labeledBody);
4441
}
4442
4443
consumeSemicolon();
4444
4445
return node.finishExpressionStatement(expr);
4446
}
4447
4448
// 13 Function Definition
4449
4450
function parseFunctionSourceElements() {
4451
var statement, body = [], token, directive, firstRestricted,
4452
oldLabelSet, oldInIteration, oldInSwitch, oldInFunctionBody, oldParenthesisCount,
4453
node = new Node();
4454
4455
expect('{');
4456
4457
while (startIndex < length) {
4458
if (lookahead.type !== Token.StringLiteral) {
4459
break;
4460
}
4461
token = lookahead;
4462
4463
statement = parseStatementListItem();
4464
body.push(statement);
4465
if (statement.expression.type !== Syntax.Literal) {
4466
// this is not directive
4467
break;
4468
}
4469
directive = source.slice(token.start + 1, token.end - 1);
4470
if (directive === 'use strict') {
4471
strict = true;
4472
if (firstRestricted) {
4473
tolerateUnexpectedToken(firstRestricted, Messages.StrictOctalLiteral);
4474
}
4475
} else {
4476
if (!firstRestricted && token.octal) {
4477
firstRestricted = token;
4478
}
4479
}
4480
}
4481
4482
oldLabelSet = state.labelSet;
4483
oldInIteration = state.inIteration;
4484
oldInSwitch = state.inSwitch;
4485
oldInFunctionBody = state.inFunctionBody;
4486
oldParenthesisCount = state.parenthesizedCount;
4487
4488
state.labelSet = {};
4489
state.inIteration = false;
4490
state.inSwitch = false;
4491
state.inFunctionBody = true;
4492
state.parenthesizedCount = 0;
4493
4494
while (startIndex < length) {
4495
if (match('}')) {
4496
break;
4497
}
4498
body.push(parseStatementListItem());
4499
}
4500
4501
expect('}');
4502
4503
state.labelSet = oldLabelSet;
4504
state.inIteration = oldInIteration;
4505
state.inSwitch = oldInSwitch;
4506
state.inFunctionBody = oldInFunctionBody;
4507
state.parenthesizedCount = oldParenthesisCount;
4508
4509
return node.finishBlockStatement(body);
4510
}
4511
4512
function validateParam(options, param, name) {
4513
var key = '$' + name;
4514
if (strict) {
4515
if (isRestrictedWord(name)) {
4516
options.stricted = param;
4517
options.message = Messages.StrictParamName;
4518
}
4519
if (Object.prototype.hasOwnProperty.call(options.paramSet, key)) {
4520
options.stricted = param;
4521
options.message = Messages.StrictParamDupe;
4522
}
4523
} else if (!options.firstRestricted) {
4524
if (isRestrictedWord(name)) {
4525
options.firstRestricted = param;
4526
options.message = Messages.StrictParamName;
4527
} else if (isStrictModeReservedWord(name)) {
4528
options.firstRestricted = param;
4529
options.message = Messages.StrictReservedWord;
4530
} else if (Object.prototype.hasOwnProperty.call(options.paramSet, key)) {
4531
options.firstRestricted = param;
4532
options.message = Messages.StrictParamDupe;
4533
}
4534
}
4535
options.paramSet[key] = true;
4536
}
4537
4538
function parseParam(options) {
4539
var token, param, def;
4540
4541
token = lookahead;
4542
if (token.value === '...') {
4543
param = parseRestElement();
4544
validateParam(options, param.argument, param.argument.name);
4545
options.params.push(param);
4546
options.defaults.push(null);
4547
return false;
4548
}
4549
4550
param = parsePatternWithDefault();
4551
validateParam(options, token, token.value);
4552
4553
if (param.type === Syntax.AssignmentPattern) {
4554
def = param.right;
4555
param = param.left;
4556
++options.defaultCount;
4557
}
4558
4559
options.params.push(param);
4560
options.defaults.push(def);
4561
4562
return !match(')');
4563
}
4564
4565
function parseParams(firstRestricted) {
4566
var options;
4567
4568
options = {
4569
params: [],
4570
defaultCount: 0,
4571
defaults: [],
4572
firstRestricted: firstRestricted
4573
};
4574
4575
expect('(');
4576
4577
if (!match(')')) {
4578
options.paramSet = {};
4579
while (startIndex < length) {
4580
if (!parseParam(options)) {
4581
break;
4582
}
4583
expect(',');
4584
}
4585
}
4586
4587
expect(')');
4588
4589
if (options.defaultCount === 0) {
4590
options.defaults = [];
4591
}
4592
4593
return {
4594
params: options.params,
4595
defaults: options.defaults,
4596
stricted: options.stricted,
4597
firstRestricted: options.firstRestricted,
4598
message: options.message
4599
};
4600
}
4601
4602
function parseFunctionDeclaration(node, identifierIsOptional) {
4603
var id = null, params = [], defaults = [], body, token, stricted, tmp, firstRestricted, message, previousStrict;
4604
4605
expectKeyword('function');
4606
if (!identifierIsOptional || !match('(')) {
4607
token = lookahead;
4608
id = parseVariableIdentifier();
4609
if (strict) {
4610
if (isRestrictedWord(token.value)) {
4611
tolerateUnexpectedToken(token, Messages.StrictFunctionName);
4612
}
4613
} else {
4614
if (isRestrictedWord(token.value)) {
4615
firstRestricted = token;
4616
message = Messages.StrictFunctionName;
4617
} else if (isStrictModeReservedWord(token.value)) {
4618
firstRestricted = token;
4619
message = Messages.StrictReservedWord;
4620
}
4621
}
4622
}
4623
4624
tmp = parseParams(firstRestricted);
4625
params = tmp.params;
4626
defaults = tmp.defaults;
4627
stricted = tmp.stricted;
4628
firstRestricted = tmp.firstRestricted;
4629
if (tmp.message) {
4630
message = tmp.message;
4631
}
4632
4633
previousStrict = strict;
4634
body = parseFunctionSourceElements();
4635
if (strict && firstRestricted) {
4636
throwUnexpectedToken(firstRestricted, message);
4637
}
4638
if (strict && stricted) {
4639
tolerateUnexpectedToken(stricted, message);
4640
}
4641
strict = previousStrict;
4642
4643
return node.finishFunctionDeclaration(id, params, defaults, body);
4644
}
4645
4646
function parseFunctionExpression() {
4647
var token, id = null, stricted, firstRestricted, message, tmp,
4648
params = [], defaults = [], body, previousStrict, node = new Node();
4649
4650
expectKeyword('function');
4651
4652
if (!match('(')) {
4653
token = lookahead;
4654
id = parseVariableIdentifier();
4655
if (strict) {
4656
if (isRestrictedWord(token.value)) {
4657
tolerateUnexpectedToken(token, Messages.StrictFunctionName);
4658
}
4659
} else {
4660
if (isRestrictedWord(token.value)) {
4661
firstRestricted = token;
4662
message = Messages.StrictFunctionName;
4663
} else if (isStrictModeReservedWord(token.value)) {
4664
firstRestricted = token;
4665
message = Messages.StrictReservedWord;
4666
}
4667
}
4668
}
4669
4670
tmp = parseParams(firstRestricted);
4671
params = tmp.params;
4672
defaults = tmp.defaults;
4673
stricted = tmp.stricted;
4674
firstRestricted = tmp.firstRestricted;
4675
if (tmp.message) {
4676
message = tmp.message;
4677
}
4678
4679
previousStrict = strict;
4680
body = parseFunctionSourceElements();
4681
if (strict && firstRestricted) {
4682
throwUnexpectedToken(firstRestricted, message);
4683
}
4684
if (strict && stricted) {
4685
tolerateUnexpectedToken(stricted, message);
4686
}
4687
strict = previousStrict;
4688
4689
return node.finishFunctionExpression(id, params, defaults, body);
4690
}
4691
4692
4693
function parseClassBody() {
4694
var classBody, token, isStatic, hasConstructor = false, body, method, computed, key;
4695
4696
classBody = new Node();
4697
4698
expect('{');
4699
body = [];
4700
while (!match('}')) {
4701
if (match(';')) {
4702
lex();
4703
} else {
4704
method = new Node();
4705
token = lookahead;
4706
isStatic = false;
4707
computed = match('[');
4708
key = parseObjectPropertyKey();
4709
if (key.name === 'static' && lookaheadPropertyName()) {
4710
token = lookahead;
4711
isStatic = true;
4712
computed = match('[');
4713
key = parseObjectPropertyKey();
4714
}
4715
method = tryParseMethodDefinition(token, key, computed, method);
4716
if (method) {
4717
method['static'] = isStatic;
4718
if (method.kind === 'init') {
4719
method.kind = 'method';
4720
}
4721
if (!isStatic) {
4722
if (!method.computed && (method.key.name || method.key.value.toString()) === 'constructor') {
4723
if (method.kind !== 'method' || !method.method || method.value.generator) {
4724
throwUnexpectedToken(token, Messages.ConstructorSpecialMethod);
4725
}
4726
if (hasConstructor) {
4727
throwUnexpectedToken(token, Messages.DuplicateConstructor);
4728
} else {
4729
hasConstructor = true;
4730
}
4731
method.kind = 'constructor';
4732
}
4733
} else {
4734
if (!method.computed && (method.key.name || method.key.value.toString()) === 'prototype') {
4735
throwUnexpectedToken(token, Messages.StaticPrototype);
4736
}
4737
}
4738
method.type = Syntax.MethodDefinition;
4739
delete method.method;
4740
delete method.shorthand;
4741
body.push(method);
4742
} else {
4743
throwUnexpectedToken(lookahead);
4744
}
4745
}
4746
}
4747
lex();
4748
return classBody.finishClassBody(body);
4749
}
4750
4751
function parseClassDeclaration(identifierIsOptional) {
4752
var id = null, superClass = null, classNode = new Node(), classBody, previousStrict = strict;
4753
strict = true;
4754
4755
expectKeyword('class');
4756
4757
if (!identifierIsOptional || lookahead.type === Token.Identifier) {
4758
id = parseVariableIdentifier();
4759
}
4760
4761
if (matchKeyword('extends')) {
4762
lex();
4763
superClass = isolateCoverGrammar(parseLeftHandSideExpressionAllowCall);
4764
}
4765
classBody = parseClassBody();
4766
strict = previousStrict;
4767
4768
return classNode.finishClassDeclaration(id, superClass, classBody);
4769
}
4770
4771
function parseClassExpression() {
4772
var id = null, superClass = null, classNode = new Node(), classBody, previousStrict = strict;
4773
strict = true;
4774
4775
expectKeyword('class');
4776
4777
if (lookahead.type === Token.Identifier) {
4778
id = parseVariableIdentifier();
4779
}
4780
4781
if (matchKeyword('extends')) {
4782
lex();
4783
superClass = isolateCoverGrammar(parseLeftHandSideExpressionAllowCall);
4784
}
4785
classBody = parseClassBody();
4786
strict = previousStrict;
4787
4788
return classNode.finishClassExpression(id, superClass, classBody);
4789
}
4790
4791
// Modules grammar from:
4792
// people.mozilla.org/~jorendorff/es6-draft.html
4793
4794
function parseModuleSpecifier() {
4795
var node = new Node();
4796
4797
if (lookahead.type !== Token.StringLiteral) {
4798
throwError(Messages.InvalidModuleSpecifier);
4799
}
4800
return node.finishLiteral(lex());
4801
}
4802
4803
function parseExportSpecifier() {
4804
var exported, local, node = new Node(), def;
4805
if (matchKeyword('default')) {
4806
// export {default} from 'something';
4807
def = new Node();
4808
lex();
4809
local = def.finishIdentifier('default');
4810
} else {
4811
local = parseVariableIdentifier();
4812
}
4813
if (matchContextualKeyword('as')) {
4814
lex();
4815
exported = parseNonComputedProperty();
4816
}
4817
return node.finishExportSpecifier(local, exported);
4818
}
4819
4820
function parseExportNamedDeclaration(node) {
4821
var declaration = null,
4822
isExportFromIdentifier,
4823
src = null, specifiers = [];
4824
4825
// non-default export
4826
if (lookahead.type === Token.Keyword) {
4827
// covers:
4828
// export var f = 1;
4829
switch (lookahead.value) {
4830
case 'let':
4831
case 'const':
4832
case 'var':
4833
case 'class':
4834
case 'function':
4835
declaration = parseStatementListItem();
4836
return node.finishExportNamedDeclaration(declaration, specifiers, null);
4837
}
4838
}
4839
4840
expect('{');
4841
if (!match('}')) {
4842
do {
4843
isExportFromIdentifier = isExportFromIdentifier || matchKeyword('default');
4844
specifiers.push(parseExportSpecifier());
4845
} while (match(',') && lex());
4846
}
4847
expect('}');
4848
4849
if (matchContextualKeyword('from')) {
4850
// covering:
4851
// export {default} from 'foo';
4852
// export {foo} from 'foo';
4853
lex();
4854
src = parseModuleSpecifier();
4855
consumeSemicolon();
4856
} else if (isExportFromIdentifier) {
4857
// covering:
4858
// export {default}; // missing fromClause
4859
throwError(lookahead.value ?
4860
Messages.UnexpectedToken : Messages.MissingFromClause, lookahead.value);
4861
} else {
4862
// cover
4863
// export {foo};
4864
consumeSemicolon();
4865
}
4866
return node.finishExportNamedDeclaration(declaration, specifiers, src);
4867
}
4868
4869
function parseExportDefaultDeclaration(node) {
4870
var declaration = null,
4871
expression = null;
4872
4873
// covers:
4874
// export default ...
4875
expectKeyword('default');
4876
4877
if (matchKeyword('function')) {
4878
// covers:
4879
// export default function foo () {}
4880
// export default function () {}
4881
declaration = parseFunctionDeclaration(new Node(), true);
4882
return node.finishExportDefaultDeclaration(declaration);
4883
}
4884
if (matchKeyword('class')) {
4885
declaration = parseClassDeclaration(true);
4886
return node.finishExportDefaultDeclaration(declaration);
4887
}
4888
4889
if (matchContextualKeyword('from')) {
4890
throwError(Messages.UnexpectedToken, lookahead.value);
4891
}
4892
4893
// covers:
4894
// export default {};
4895
// export default [];
4896
// export default (1 + 2);
4897
if (match('{')) {
4898
expression = parseObjectInitialiser();
4899
} else if (match('[')) {
4900
expression = parseArrayInitialiser();
4901
} else {
4902
expression = parseAssignmentExpression();
4903
}
4904
consumeSemicolon();
4905
return node.finishExportDefaultDeclaration(expression);
4906
}
4907
4908
function parseExportAllDeclaration(node) {
4909
var src;
4910
4911
// covers:
4912
// export * from 'foo';
4913
expect('*');
4914
if (!matchContextualKeyword('from')) {
4915
throwError(lookahead.value ?
4916
Messages.UnexpectedToken : Messages.MissingFromClause, lookahead.value);
4917
}
4918
lex();
4919
src = parseModuleSpecifier();
4920
consumeSemicolon();
4921
4922
return node.finishExportAllDeclaration(src);
4923
}
4924
4925
function parseExportDeclaration() {
4926
var node = new Node();
4927
if (state.inFunctionBody) {
4928
throwError(Messages.IllegalExportDeclaration);
4929
}
4930
4931
expectKeyword('export');
4932
4933
if (matchKeyword('default')) {
4934
return parseExportDefaultDeclaration(node);
4935
}
4936
if (match('*')) {
4937
return parseExportAllDeclaration(node);
4938
}
4939
return parseExportNamedDeclaration(node);
4940
}
4941
4942
function parseImportSpecifier() {
4943
// import {<foo as bar>} ...;
4944
var local, imported, node = new Node();
4945
4946
imported = parseNonComputedProperty();
4947
if (matchContextualKeyword('as')) {
4948
lex();
4949
local = parseVariableIdentifier();
4950
}
4951
4952
return node.finishImportSpecifier(local, imported);
4953
}
4954
4955
function parseNamedImports() {
4956
var specifiers = [];
4957
// {foo, bar as bas}
4958
expect('{');
4959
if (!match('}')) {
4960
do {
4961
specifiers.push(parseImportSpecifier());
4962
} while (match(',') && lex());
4963
}
4964
expect('}');
4965
return specifiers;
4966
}
4967
4968
function parseImportDefaultSpecifier() {
4969
// import <foo> ...;
4970
var local, node = new Node();
4971
4972
local = parseNonComputedProperty();
4973
4974
return node.finishImportDefaultSpecifier(local);
4975
}
4976
4977
function parseImportNamespaceSpecifier() {
4978
// import <* as foo> ...;
4979
var local, node = new Node();
4980
4981
expect('*');
4982
if (!matchContextualKeyword('as')) {
4983
throwError(Messages.NoAsAfterImportNamespace);
4984
}
4985
lex();
4986
local = parseNonComputedProperty();
4987
4988
return node.finishImportNamespaceSpecifier(local);
4989
}
4990
4991
function parseImportDeclaration() {
4992
var specifiers, src, node = new Node();
4993
4994
if (state.inFunctionBody) {
4995
throwError(Messages.IllegalImportDeclaration);
4996
}
4997
4998
expectKeyword('import');
4999
specifiers = [];
5000
5001
if (lookahead.type === Token.StringLiteral) {
5002
// covers:
5003
// import 'foo';
5004
src = parseModuleSpecifier();
5005
consumeSemicolon();
5006
return node.finishImportDeclaration(specifiers, src);
5007
}
5008
5009
if (!matchKeyword('default') && isIdentifierName(lookahead)) {
5010
// covers:
5011
// import foo
5012
// import foo, ...
5013
specifiers.push(parseImportDefaultSpecifier());
5014
if (match(',')) {
5015
lex();
5016
}
5017
}
5018
if (match('*')) {
5019
// covers:
5020
// import foo, * as foo
5021
// import * as foo
5022
specifiers.push(parseImportNamespaceSpecifier());
5023
} else if (match('{')) {
5024
// covers:
5025
// import foo, {bar}
5026
// import {bar}
5027
specifiers = specifiers.concat(parseNamedImports());
5028
}
5029
5030
if (!matchContextualKeyword('from')) {
5031
throwError(lookahead.value ?
5032
Messages.UnexpectedToken : Messages.MissingFromClause, lookahead.value);
5033
}
5034
lex();
5035
src = parseModuleSpecifier();
5036
consumeSemicolon();
5037
5038
return node.finishImportDeclaration(specifiers, src);
5039
}
5040
5041
// 14 Program
5042
5043
function parseScriptBody() {
5044
var statement, body = [], token, directive, firstRestricted;
5045
5046
while (startIndex < length) {
5047
token = lookahead;
5048
if (token.type !== Token.StringLiteral) {
5049
break;
5050
}
5051
5052
statement = parseStatementListItem();
5053
body.push(statement);
5054
if (statement.expression.type !== Syntax.Literal) {
5055
// this is not directive
5056
break;
5057
}
5058
directive = source.slice(token.start + 1, token.end - 1);
5059
if (directive === 'use strict') {
5060
strict = true;
5061
if (firstRestricted) {
5062
tolerateUnexpectedToken(firstRestricted, Messages.StrictOctalLiteral);
5063
}
5064
} else {
5065
if (!firstRestricted && token.octal) {
5066
firstRestricted = token;
5067
}
5068
}
5069
}
5070
5071
while (startIndex < length) {
5072
statement = parseStatementListItem();
5073
/* istanbul ignore if */
5074
if (typeof statement === 'undefined') {
5075
break;
5076
}
5077
body.push(statement);
5078
}
5079
return body;
5080
}
5081
5082
function parseProgram() {
5083
var body, node;
5084
5085
peek();
5086
node = new Node();
5087
5088
body = parseScriptBody();
5089
return node.finishProgram(body);
5090
}
5091
5092
function filterTokenLocation() {
5093
var i, entry, token, tokens = [];
5094
5095
for (i = 0; i < extra.tokens.length; ++i) {
5096
entry = extra.tokens[i];
5097
token = {
5098
type: entry.type,
5099
value: entry.value
5100
};
5101
if (entry.regex) {
5102
token.regex = {
5103
pattern: entry.regex.pattern,
5104
flags: entry.regex.flags
5105
};
5106
}
5107
if (extra.range) {
5108
token.range = entry.range;
5109
}
5110
if (extra.loc) {
5111
token.loc = entry.loc;
5112
}
5113
tokens.push(token);
5114
}
5115
5116
extra.tokens = tokens;
5117
}
5118
5119
function tokenize(code, options) {
5120
var toString,
5121
tokens;
5122
5123
toString = String;
5124
if (typeof code !== 'string' && !(code instanceof String)) {
5125
code = toString(code);
5126
}
5127
5128
source = code;
5129
index = 0;
5130
lineNumber = (source.length > 0) ? 1 : 0;
5131
lineStart = 0;
5132
startIndex = index;
5133
startLineNumber = lineNumber;
5134
startLineStart = lineStart;
5135
length = source.length;
5136
lookahead = null;
5137
state = {
5138
allowIn: true,
5139
labelSet: {},
5140
inFunctionBody: false,
5141
inIteration: false,
5142
inSwitch: false,
5143
lastCommentStart: -1,
5144
curlyStack: []
5145
};
5146
5147
extra = {};
5148
5149
// Options matching.
5150
options = options || {};
5151
5152
// Of course we collect tokens here.
5153
options.tokens = true;
5154
extra.tokens = [];
5155
extra.tokenize = true;
5156
// The following two fields are necessary to compute the Regex tokens.
5157
extra.openParenToken = -1;
5158
extra.openCurlyToken = -1;
5159
5160
extra.range = (typeof options.range === 'boolean') && options.range;
5161
extra.loc = (typeof options.loc === 'boolean') && options.loc;
5162
5163
if (typeof options.comment === 'boolean' && options.comment) {
5164
extra.comments = [];
5165
}
5166
if (typeof options.tolerant === 'boolean' && options.tolerant) {
5167
extra.errors = [];
5168
}
5169
5170
try {
5171
peek();
5172
if (lookahead.type === Token.EOF) {
5173
return extra.tokens;
5174
}
5175
5176
lex();
5177
while (lookahead.type !== Token.EOF) {
5178
try {
5179
lex();
5180
} catch (lexError) {
5181
if (extra.errors) {
5182
recordError(lexError);
5183
// We have to break on the first error
5184
// to avoid infinite loops.
5185
break;
5186
} else {
5187
throw lexError;
5188
}
5189
}
5190
}
5191
5192
filterTokenLocation();
5193
tokens = extra.tokens;
5194
if (typeof extra.comments !== 'undefined') {
5195
tokens.comments = extra.comments;
5196
}
5197
if (typeof extra.errors !== 'undefined') {
5198
tokens.errors = extra.errors;
5199
}
5200
} catch (e) {
5201
throw e;
5202
} finally {
5203
extra = {};
5204
}
5205
return tokens;
5206
}
5207
5208
function parse(code, options) {
5209
var program, toString;
5210
5211
toString = String;
5212
if (typeof code !== 'string' && !(code instanceof String)) {
5213
code = toString(code);
5214
}
5215
5216
source = code;
5217
index = 0;
5218
lineNumber = (source.length > 0) ? 1 : 0;
5219
lineStart = 0;
5220
startIndex = index;
5221
startLineNumber = lineNumber;
5222
startLineStart = lineStart;
5223
length = source.length;
5224
lookahead = null;
5225
state = {
5226
allowIn: true,
5227
labelSet: {},
5228
inFunctionBody: false,
5229
inIteration: false,
5230
inSwitch: false,
5231
lastCommentStart: -1,
5232
curlyStack: []
5233
};
5234
sourceType = 'script';
5235
strict = false;
5236
5237
extra = {};
5238
if (typeof options !== 'undefined') {
5239
extra.range = (typeof options.range === 'boolean') && options.range;
5240
extra.loc = (typeof options.loc === 'boolean') && options.loc;
5241
extra.attachComment = (typeof options.attachComment === 'boolean') && options.attachComment;
5242
5243
if (extra.loc && options.source !== null && options.source !== undefined) {
5244
extra.source = toString(options.source);
5245
}
5246
5247
if (typeof options.tokens === 'boolean' && options.tokens) {
5248
extra.tokens = [];
5249
}
5250
if (typeof options.comment === 'boolean' && options.comment) {
5251
extra.comments = [];
5252
}
5253
if (typeof options.tolerant === 'boolean' && options.tolerant) {
5254
extra.errors = [];
5255
}
5256
if (extra.attachComment) {
5257
extra.range = true;
5258
extra.comments = [];
5259
extra.bottomRightStack = [];
5260
extra.trailingComments = [];
5261
extra.leadingComments = [];
5262
}
5263
if (options.sourceType === 'module') {
5264
// very restrictive condition for now
5265
sourceType = options.sourceType;
5266
strict = true;
5267
}
5268
}
5269
5270
try {
5271
program = parseProgram();
5272
if (typeof extra.comments !== 'undefined') {
5273
program.comments = extra.comments;
5274
}
5275
if (typeof extra.tokens !== 'undefined') {
5276
filterTokenLocation();
5277
program.tokens = extra.tokens;
5278
}
5279
if (typeof extra.errors !== 'undefined') {
5280
program.errors = extra.errors;
5281
}
5282
} catch (e) {
5283
throw e;
5284
} finally {
5285
extra = {};
5286
}
5287
5288
return program;
5289
}
5290
5291
// Sync with *.json manifests.
5292
exports.version = '2.2.0';
5293
5294
exports.tokenize = tokenize;
5295
5296
exports.parse = parse;
5297
5298
// Deep copy.
5299
/* istanbul ignore next */
5300
exports.Syntax = (function () {
5301
var name, types = {};
5302
5303
if (typeof Object.create === 'function') {
5304
types = Object.create(null);
5305
}
5306
5307
for (name in Syntax) {
5308
if (Syntax.hasOwnProperty(name)) {
5309
types[name] = Syntax[name];
5310
}
5311
}
5312
5313
if (typeof Object.freeze === 'function') {
5314
Object.freeze(types);
5315
}
5316
5317
return types;
5318
}());
5319
5320
}));
5321
/* vim: set sw=4 ts=4 et tw=80 : */
5322
5323