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