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