UNPKG

204 kBJavaScriptView Raw
1/*
2 Copyright (C) 2013 Ariya Hidayat <ariya.hidayat@gmail.com>
3 Copyright (C) 2013 Thaddee Tyl <thaddee.tyl@gmail.com>
4 Copyright (C) 2012 Ariya Hidayat <ariya.hidayat@gmail.com>
5 Copyright (C) 2012 Mathias Bynens <mathias@qiwi.be>
6 Copyright (C) 2012 Joost-Wim Boekesteijn <joost-wim@boekesteijn.nl>
7 Copyright (C) 2012 Kris Kowal <kris.kowal@cixar.com>
8 Copyright (C) 2012 Yusuke Suzuki <utatane.tea@gmail.com>
9 Copyright (C) 2012 Arpad Borsos <arpad.borsos@googlemail.com>
10 Copyright (C) 2011 Ariya Hidayat <ariya.hidayat@gmail.com>
11
12 Redistribution and use in source and binary forms, with or without
13 modification, are permitted provided that the following conditions are met:
14
15 * Redistributions of source code must retain the above copyright
16 notice, this list of conditions and the following disclaimer.
17 * Redistributions in binary form must reproduce the above copyright
18 notice, this list of conditions and the following disclaimer in the
19 documentation and/or other materials provided with the distribution.
20
21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
25 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
28 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31*/
32
33/*jslint bitwise:true plusplus:true */
34/*global esprima:true, define:true, exports:true, window: true,
35throwError: true, generateStatement: true, peek: true,
36parseAssignmentExpression: true, parseBlock: true,
37parseClassExpression: true, parseClassDeclaration: true, parseExpression: true,
38parseForStatement: true,
39parseFunctionDeclaration: true, parseFunctionExpression: true,
40parseFunctionSourceElements: true, parseVariableIdentifier: true,
41parseImportSpecifier: true,
42parseLeftHandSideExpression: true, parseParams: true, validateParam: true,
43parseSpreadOrAssignmentExpression: true,
44parseStatement: true, parseSourceElement: true, parseModuleBlock: true, parseConciseBody: true,
45advanceXJSChild: true, isXJSIdentifierStart: true, isXJSIdentifierPart: true,
46scanXJSStringLiteral: true, scanXJSIdentifier: true,
47parseXJSAttributeValue: true, parseXJSChild: true, parseXJSElement: true, parseXJSExpressionContainer: true, parseXJSEmptyExpression: true,
48parseTypeAnnotation: true, parseTypeAnnotatableIdentifier: true,
49parseYieldExpression: true
50*/
51
52(function (root, factory) {
53 'use strict';
54
55 // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js,
56 // Rhino, and plain browser loading.
57 if (typeof define === 'function' && define.amd) {
58 define(['exports'], factory);
59 } else if (typeof exports !== 'undefined') {
60 factory(exports);
61 } else {
62 factory((root.esprima = {}));
63 }
64}(this, function (exports) {
65 'use strict';
66
67 var Token,
68 TokenName,
69 FnExprTokens,
70 Syntax,
71 PropertyKind,
72 Messages,
73 Regex,
74 SyntaxTreeDelegate,
75 XHTMLEntities,
76 ClassPropertyType,
77 source,
78 strict,
79 index,
80 lineNumber,
81 lineStart,
82 length,
83 delegate,
84 lookahead,
85 state,
86 extra;
87
88 Token = {
89 BooleanLiteral: 1,
90 EOF: 2,
91 Identifier: 3,
92 Keyword: 4,
93 NullLiteral: 5,
94 NumericLiteral: 6,
95 Punctuator: 7,
96 StringLiteral: 8,
97 RegularExpression: 9,
98 Template: 10,
99 XJSIdentifier: 11,
100 XJSText: 12
101 };
102
103 TokenName = {};
104 TokenName[Token.BooleanLiteral] = 'Boolean';
105 TokenName[Token.EOF] = '<end>';
106 TokenName[Token.Identifier] = 'Identifier';
107 TokenName[Token.Keyword] = 'Keyword';
108 TokenName[Token.NullLiteral] = 'Null';
109 TokenName[Token.NumericLiteral] = 'Numeric';
110 TokenName[Token.Punctuator] = 'Punctuator';
111 TokenName[Token.StringLiteral] = 'String';
112 TokenName[Token.XJSIdentifier] = 'XJSIdentifier';
113 TokenName[Token.XJSText] = 'XJSText';
114 TokenName[Token.RegularExpression] = 'RegularExpression';
115
116 // A function following one of those tokens is an expression.
117 FnExprTokens = ['(', '{', '[', 'in', 'typeof', 'instanceof', 'new',
118 'return', 'case', 'delete', 'throw', 'void',
119 // assignment operators
120 '=', '+=', '-=', '*=', '/=', '%=', '<<=', '>>=', '>>>=',
121 '&=', '|=', '^=', ',',
122 // binary/unary operators
123 '+', '-', '*', '/', '%', '++', '--', '<<', '>>', '>>>', '&',
124 '|', '^', '!', '~', '&&', '||', '?', ':', '===', '==', '>=',
125 '<=', '<', '>', '!=', '!=='];
126
127 Syntax = {
128 ArrayExpression: 'ArrayExpression',
129 ArrayPattern: 'ArrayPattern',
130 ArrowFunctionExpression: 'ArrowFunctionExpression',
131 AssignmentExpression: 'AssignmentExpression',
132 BinaryExpression: 'BinaryExpression',
133 BlockStatement: 'BlockStatement',
134 BreakStatement: 'BreakStatement',
135 CallExpression: 'CallExpression',
136 CatchClause: 'CatchClause',
137 ClassBody: 'ClassBody',
138 ClassDeclaration: 'ClassDeclaration',
139 ClassExpression: 'ClassExpression',
140 ClassProperty: 'ClassProperty',
141 ComprehensionBlock: 'ComprehensionBlock',
142 ComprehensionExpression: 'ComprehensionExpression',
143 ConditionalExpression: 'ConditionalExpression',
144 ContinueStatement: 'ContinueStatement',
145 DebuggerStatement: 'DebuggerStatement',
146 DoWhileStatement: 'DoWhileStatement',
147 EmptyStatement: 'EmptyStatement',
148 ExportDeclaration: 'ExportDeclaration',
149 ExportBatchSpecifier: 'ExportBatchSpecifier',
150 ExportSpecifier: 'ExportSpecifier',
151 ExpressionStatement: 'ExpressionStatement',
152 ForInStatement: 'ForInStatement',
153 ForOfStatement: 'ForOfStatement',
154 ForStatement: 'ForStatement',
155 FunctionDeclaration: 'FunctionDeclaration',
156 FunctionExpression: 'FunctionExpression',
157 Identifier: 'Identifier',
158 IfStatement: 'IfStatement',
159 ImportDeclaration: 'ImportDeclaration',
160 ImportSpecifier: 'ImportSpecifier',
161 LabeledStatement: 'LabeledStatement',
162 Literal: 'Literal',
163 LogicalExpression: 'LogicalExpression',
164 MemberExpression: 'MemberExpression',
165 MethodDefinition: 'MethodDefinition',
166 ModuleDeclaration: 'ModuleDeclaration',
167 NewExpression: 'NewExpression',
168 ObjectExpression: 'ObjectExpression',
169 ObjectPattern: 'ObjectPattern',
170 ObjectTypeAnnotation: 'ObjectTypeAnnotation',
171 OptionalParameter: 'OptionalParameter',
172 ParametricTypeAnnotation: 'ParametricTypeAnnotation',
173 ParametricallyTypedIdentifier: 'ParametricallyTypedIdentifier',
174 Program: 'Program',
175 Property: 'Property',
176 ReturnStatement: 'ReturnStatement',
177 SequenceExpression: 'SequenceExpression',
178 SpreadElement: 'SpreadElement',
179 SpreadProperty: 'SpreadProperty',
180 SwitchCase: 'SwitchCase',
181 SwitchStatement: 'SwitchStatement',
182 TaggedTemplateExpression: 'TaggedTemplateExpression',
183 TemplateElement: 'TemplateElement',
184 TemplateLiteral: 'TemplateLiteral',
185 ThisExpression: 'ThisExpression',
186 ThrowStatement: 'ThrowStatement',
187 TryStatement: 'TryStatement',
188 TypeAnnotatedIdentifier: 'TypeAnnotatedIdentifier',
189 TypeAnnotation: 'TypeAnnotation',
190 UnaryExpression: 'UnaryExpression',
191 UpdateExpression: 'UpdateExpression',
192 VariableDeclaration: 'VariableDeclaration',
193 VariableDeclarator: 'VariableDeclarator',
194 VoidTypeAnnotation: 'VoidTypeAnnotation',
195 WhileStatement: 'WhileStatement',
196 WithStatement: 'WithStatement',
197 XJSIdentifier: 'XJSIdentifier',
198 XJSNamespacedName: 'XJSNamespacedName',
199 XJSMemberExpression: 'XJSMemberExpression',
200 XJSEmptyExpression: 'XJSEmptyExpression',
201 XJSExpressionContainer: 'XJSExpressionContainer',
202 XJSElement: 'XJSElement',
203 XJSClosingElement: 'XJSClosingElement',
204 XJSOpeningElement: 'XJSOpeningElement',
205 XJSAttribute: 'XJSAttribute',
206 XJSSpreadAttribute: 'XJSSpreadAttribute',
207 XJSText: 'XJSText',
208 YieldExpression: 'YieldExpression'
209 };
210
211 PropertyKind = {
212 Data: 1,
213 Get: 2,
214 Set: 4
215 };
216
217 ClassPropertyType = {
218 'static': 'static',
219 prototype: 'prototype'
220 };
221
222 // Error messages should be identical to V8.
223 Messages = {
224 UnexpectedToken: 'Unexpected token %0',
225 UnexpectedNumber: 'Unexpected number',
226 UnexpectedString: 'Unexpected string',
227 UnexpectedIdentifier: 'Unexpected identifier',
228 UnexpectedReserved: 'Unexpected reserved word',
229 UnexpectedTemplate: 'Unexpected quasi %0',
230 UnexpectedEOS: 'Unexpected end of input',
231 NewlineAfterThrow: 'Illegal newline after throw',
232 InvalidRegExp: 'Invalid regular expression',
233 UnterminatedRegExp: 'Invalid regular expression: missing /',
234 InvalidLHSInAssignment: 'Invalid left-hand side in assignment',
235 InvalidLHSInFormalsList: 'Invalid left-hand side in formals list',
236 InvalidLHSInForIn: 'Invalid left-hand side in for-in',
237 MultipleDefaultsInSwitch: 'More than one default clause in switch statement',
238 NoCatchOrFinally: 'Missing catch or finally after try',
239 UnknownLabel: 'Undefined label \'%0\'',
240 Redeclaration: '%0 \'%1\' has already been declared',
241 IllegalContinue: 'Illegal continue statement',
242 IllegalBreak: 'Illegal break statement',
243 IllegalDuplicateClassProperty: 'Illegal duplicate property in class definition',
244 IllegalReturn: 'Illegal return statement',
245 IllegalYield: 'Illegal yield expression',
246 IllegalSpread: 'Illegal spread element',
247 StrictModeWith: 'Strict mode code may not include a with statement',
248 StrictCatchVariable: 'Catch variable may not be eval or arguments in strict mode',
249 StrictVarName: 'Variable name may not be eval or arguments in strict mode',
250 StrictParamName: 'Parameter name eval or arguments is not allowed in strict mode',
251 StrictParamDupe: 'Strict mode function may not have duplicate parameter names',
252 ParameterAfterRestParameter: 'Rest parameter must be final parameter of an argument list',
253 DefaultRestParameter: 'Rest parameter can not have a default value',
254 ElementAfterSpreadElement: 'Spread must be the final element of an element list',
255 PropertyAfterSpreadProperty: 'A rest property must be the final property of an object literal',
256 ObjectPatternAsRestParameter: 'Invalid rest parameter',
257 ObjectPatternAsSpread: 'Invalid spread argument',
258 StrictFunctionName: 'Function name may not be eval or arguments in strict mode',
259 StrictOctalLiteral: 'Octal literals are not allowed in strict mode.',
260 StrictDelete: 'Delete of an unqualified identifier in strict mode.',
261 StrictDuplicateProperty: 'Duplicate data property in object literal not allowed in strict mode',
262 AccessorDataProperty: 'Object literal may not have data and accessor property with the same name',
263 AccessorGetSet: 'Object literal may not have multiple get/set accessors with the same name',
264 StrictLHSAssignment: 'Assignment to eval or arguments is not allowed in strict mode',
265 StrictLHSPostfix: 'Postfix increment/decrement may not have eval or arguments operand in strict mode',
266 StrictLHSPrefix: 'Prefix increment/decrement may not have eval or arguments operand in strict mode',
267 StrictReservedWord: 'Use of future reserved word in strict mode',
268 NewlineAfterModule: 'Illegal newline after module',
269 NoFromAfterImport: 'Missing from after import',
270 InvalidModuleSpecifier: 'Invalid module specifier',
271 NestedModule: 'Module declaration can not be nested',
272 NoUnintializedConst: 'Const must be initialized',
273 ComprehensionRequiresBlock: 'Comprehension must have at least one block',
274 ComprehensionError: 'Comprehension Error',
275 EachNotAllowed: 'Each is not supported',
276 InvalidXJSAttributeValue: 'XJS value should be either an expression or a quoted XJS text',
277 ExpectedXJSClosingTag: 'Expected corresponding XJS closing tag for %0',
278 AdjacentXJSElements: 'Adjacent XJS elements must be wrapped in an enclosing tag'
279 };
280
281 // See also tools/generate-unicode-regex.py.
282 Regex = {
283 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]'),
284 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]')
285 };
286
287 // Ensure the condition is true, otherwise throw an error.
288 // This is only to have a better contract semantic, i.e. another safety net
289 // to catch a logic error. The condition shall be fulfilled in normal case.
290 // Do NOT use this to enforce a certain condition on any user input.
291
292 function assert(condition, message) {
293 if (!condition) {
294 throw new Error('ASSERT: ' + message);
295 }
296 }
297
298 function isDecimalDigit(ch) {
299 return (ch >= 48 && ch <= 57); // 0..9
300 }
301
302 function isHexDigit(ch) {
303 return '0123456789abcdefABCDEF'.indexOf(ch) >= 0;
304 }
305
306 function isOctalDigit(ch) {
307 return '01234567'.indexOf(ch) >= 0;
308 }
309
310
311 // 7.2 White Space
312
313 function isWhiteSpace(ch) {
314 return (ch === 32) || // space
315 (ch === 9) || // tab
316 (ch === 0xB) ||
317 (ch === 0xC) ||
318 (ch === 0xA0) ||
319 (ch >= 0x1680 && '\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\uFEFF'.indexOf(String.fromCharCode(ch)) > 0);
320 }
321
322 // 7.3 Line Terminators
323
324 function isLineTerminator(ch) {
325 return (ch === 10) || (ch === 13) || (ch === 0x2028) || (ch === 0x2029);
326 }
327
328 // 7.6 Identifier Names and Identifiers
329
330 function isIdentifierStart(ch) {
331 return (ch === 36) || (ch === 95) || // $ (dollar) and _ (underscore)
332 (ch >= 65 && ch <= 90) || // A..Z
333 (ch >= 97 && ch <= 122) || // a..z
334 (ch === 92) || // \ (backslash)
335 ((ch >= 0x80) && Regex.NonAsciiIdentifierStart.test(String.fromCharCode(ch)));
336 }
337
338 function isIdentifierPart(ch) {
339 return (ch === 36) || (ch === 95) || // $ (dollar) and _ (underscore)
340 (ch >= 65 && ch <= 90) || // A..Z
341 (ch >= 97 && ch <= 122) || // a..z
342 (ch >= 48 && ch <= 57) || // 0..9
343 (ch === 92) || // \ (backslash)
344 ((ch >= 0x80) && Regex.NonAsciiIdentifierPart.test(String.fromCharCode(ch)));
345 }
346
347 // 7.6.1.2 Future Reserved Words
348
349 function isFutureReservedWord(id) {
350 switch (id) {
351 case 'class':
352 case 'enum':
353 case 'export':
354 case 'extends':
355 case 'import':
356 case 'super':
357 return true;
358 default:
359 return false;
360 }
361 }
362
363 function isStrictModeReservedWord(id) {
364 switch (id) {
365 case 'implements':
366 case 'interface':
367 case 'package':
368 case 'private':
369 case 'protected':
370 case 'public':
371 case 'static':
372 case 'yield':
373 case 'let':
374 return true;
375 default:
376 return false;
377 }
378 }
379
380 function isRestrictedWord(id) {
381 return id === 'eval' || id === 'arguments';
382 }
383
384 // 7.6.1.1 Keywords
385
386 function isKeyword(id) {
387 if (strict && isStrictModeReservedWord(id)) {
388 return true;
389 }
390
391 // 'const' is specialized as Keyword in V8.
392 // 'yield' is only treated as a keyword in strict mode.
393 // 'let' is for compatiblity with SpiderMonkey and ES.next.
394 // Some others are from future reserved words.
395
396 switch (id.length) {
397 case 2:
398 return (id === 'if') || (id === 'in') || (id === 'do');
399 case 3:
400 return (id === 'var') || (id === 'for') || (id === 'new') ||
401 (id === 'try') || (id === 'let');
402 case 4:
403 return (id === 'this') || (id === 'else') || (id === 'case') ||
404 (id === 'void') || (id === 'with') || (id === 'enum');
405 case 5:
406 return (id === 'while') || (id === 'break') || (id === 'catch') ||
407 (id === 'throw') || (id === 'const') ||
408 (id === 'class') || (id === 'super');
409 case 6:
410 return (id === 'return') || (id === 'typeof') || (id === 'delete') ||
411 (id === 'switch') || (id === 'export') || (id === 'import');
412 case 7:
413 return (id === 'default') || (id === 'finally') || (id === 'extends');
414 case 8:
415 return (id === 'function') || (id === 'continue') || (id === 'debugger');
416 case 10:
417 return (id === 'instanceof');
418 default:
419 return false;
420 }
421 }
422
423 // 7.4 Comments
424
425 function skipComment() {
426 var ch, blockComment, lineComment;
427
428 blockComment = false;
429 lineComment = false;
430
431 while (index < length) {
432 ch = source.charCodeAt(index);
433
434 if (lineComment) {
435 ++index;
436 if (isLineTerminator(ch)) {
437 lineComment = false;
438 if (ch === 13 && source.charCodeAt(index) === 10) {
439 ++index;
440 }
441 ++lineNumber;
442 lineStart = index;
443 }
444 } else if (blockComment) {
445 if (isLineTerminator(ch)) {
446 if (ch === 13 && source.charCodeAt(index + 1) === 10) {
447 ++index;
448 }
449 ++lineNumber;
450 ++index;
451 lineStart = index;
452 if (index >= length) {
453 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
454 }
455 } else {
456 ch = source.charCodeAt(index++);
457 if (index >= length) {
458 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
459 }
460 // Block comment ends with '*/' (char #42, char #47).
461 if (ch === 42) {
462 ch = source.charCodeAt(index);
463 if (ch === 47) {
464 ++index;
465 blockComment = false;
466 }
467 }
468 }
469 } else if (ch === 47) {
470 ch = source.charCodeAt(index + 1);
471 // Line comment starts with '//' (char #47, char #47).
472 if (ch === 47) {
473 index += 2;
474 lineComment = true;
475 } else if (ch === 42) {
476 // Block comment starts with '/*' (char #47, char #42).
477 index += 2;
478 blockComment = true;
479 if (index >= length) {
480 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
481 }
482 } else {
483 break;
484 }
485 } else if (isWhiteSpace(ch)) {
486 ++index;
487 } else if (isLineTerminator(ch)) {
488 ++index;
489 if (ch === 13 && source.charCodeAt(index) === 10) {
490 ++index;
491 }
492 ++lineNumber;
493 lineStart = index;
494 } else {
495 break;
496 }
497 }
498 }
499
500 function scanHexEscape(prefix) {
501 var i, len, ch, code = 0;
502
503 len = (prefix === 'u') ? 4 : 2;
504 for (i = 0; i < len; ++i) {
505 if (index < length && isHexDigit(source[index])) {
506 ch = source[index++];
507 code = code * 16 + '0123456789abcdef'.indexOf(ch.toLowerCase());
508 } else {
509 return '';
510 }
511 }
512 return String.fromCharCode(code);
513 }
514
515 function scanUnicodeCodePointEscape() {
516 var ch, code, cu1, cu2;
517
518 ch = source[index];
519 code = 0;
520
521 // At least, one hex digit is required.
522 if (ch === '}') {
523 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
524 }
525
526 while (index < length) {
527 ch = source[index++];
528 if (!isHexDigit(ch)) {
529 break;
530 }
531 code = code * 16 + '0123456789abcdef'.indexOf(ch.toLowerCase());
532 }
533
534 if (code > 0x10FFFF || ch !== '}') {
535 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
536 }
537
538 // UTF-16 Encoding
539 if (code <= 0xFFFF) {
540 return String.fromCharCode(code);
541 }
542 cu1 = ((code - 0x10000) >> 10) + 0xD800;
543 cu2 = ((code - 0x10000) & 1023) + 0xDC00;
544 return String.fromCharCode(cu1, cu2);
545 }
546
547 function getEscapedIdentifier() {
548 var ch, id;
549
550 ch = source.charCodeAt(index++);
551 id = String.fromCharCode(ch);
552
553 // '\u' (char #92, char #117) denotes an escaped character.
554 if (ch === 92) {
555 if (source.charCodeAt(index) !== 117) {
556 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
557 }
558 ++index;
559 ch = scanHexEscape('u');
560 if (!ch || ch === '\\' || !isIdentifierStart(ch.charCodeAt(0))) {
561 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
562 }
563 id = ch;
564 }
565
566 while (index < length) {
567 ch = source.charCodeAt(index);
568 if (!isIdentifierPart(ch)) {
569 break;
570 }
571 ++index;
572 id += String.fromCharCode(ch);
573
574 // '\u' (char #92, char #117) denotes an escaped character.
575 if (ch === 92) {
576 id = id.substr(0, id.length - 1);
577 if (source.charCodeAt(index) !== 117) {
578 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
579 }
580 ++index;
581 ch = scanHexEscape('u');
582 if (!ch || ch === '\\' || !isIdentifierPart(ch.charCodeAt(0))) {
583 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
584 }
585 id += ch;
586 }
587 }
588
589 return id;
590 }
591
592 function getIdentifier() {
593 var start, ch;
594
595 start = index++;
596 while (index < length) {
597 ch = source.charCodeAt(index);
598 if (ch === 92) {
599 // Blackslash (char #92) marks Unicode escape sequence.
600 index = start;
601 return getEscapedIdentifier();
602 }
603 if (isIdentifierPart(ch)) {
604 ++index;
605 } else {
606 break;
607 }
608 }
609
610 return source.slice(start, index);
611 }
612
613 function scanIdentifier() {
614 var start, id, type;
615
616 start = index;
617
618 // Backslash (char #92) starts an escaped character.
619 id = (source.charCodeAt(index) === 92) ? getEscapedIdentifier() : getIdentifier();
620
621 // There is no keyword or literal with only one character.
622 // Thus, it must be an identifier.
623 if (id.length === 1) {
624 type = Token.Identifier;
625 } else if (isKeyword(id)) {
626 type = Token.Keyword;
627 } else if (id === 'null') {
628 type = Token.NullLiteral;
629 } else if (id === 'true' || id === 'false') {
630 type = Token.BooleanLiteral;
631 } else {
632 type = Token.Identifier;
633 }
634
635 return {
636 type: type,
637 value: id,
638 lineNumber: lineNumber,
639 lineStart: lineStart,
640 range: [start, index]
641 };
642 }
643
644
645 // 7.7 Punctuators
646
647 function scanPunctuator() {
648 var start = index,
649 code = source.charCodeAt(index),
650 code2,
651 ch1 = source[index],
652 ch2,
653 ch3,
654 ch4;
655
656 switch (code) {
657 // Check for most common single-character punctuators.
658 case 40: // ( open bracket
659 case 41: // ) close bracket
660 case 59: // ; semicolon
661 case 44: // , comma
662 case 123: // { open curly brace
663 case 125: // } close curly brace
664 case 91: // [
665 case 93: // ]
666 case 58: // :
667 case 63: // ?
668 case 126: // ~
669 ++index;
670 if (extra.tokenize) {
671 if (code === 40) {
672 extra.openParenToken = extra.tokens.length;
673 } else if (code === 123) {
674 extra.openCurlyToken = extra.tokens.length;
675 }
676 }
677 return {
678 type: Token.Punctuator,
679 value: String.fromCharCode(code),
680 lineNumber: lineNumber,
681 lineStart: lineStart,
682 range: [start, index]
683 };
684
685 default:
686 code2 = source.charCodeAt(index + 1);
687
688 // '=' (char #61) marks an assignment or comparison operator.
689 if (code2 === 61) {
690 switch (code) {
691 case 37: // %
692 case 38: // &
693 case 42: // *:
694 case 43: // +
695 case 45: // -
696 case 47: // /
697 case 60: // <
698 case 62: // >
699 case 94: // ^
700 case 124: // |
701 index += 2;
702 return {
703 type: Token.Punctuator,
704 value: String.fromCharCode(code) + String.fromCharCode(code2),
705 lineNumber: lineNumber,
706 lineStart: lineStart,
707 range: [start, index]
708 };
709
710 case 33: // !
711 case 61: // =
712 index += 2;
713
714 // !== and ===
715 if (source.charCodeAt(index) === 61) {
716 ++index;
717 }
718 return {
719 type: Token.Punctuator,
720 value: source.slice(start, index),
721 lineNumber: lineNumber,
722 lineStart: lineStart,
723 range: [start, index]
724 };
725 default:
726 break;
727 }
728 }
729 break;
730 }
731
732 // Peek more characters.
733
734 ch2 = source[index + 1];
735 ch3 = source[index + 2];
736 ch4 = source[index + 3];
737
738 // 4-character punctuator: >>>=
739
740 if (ch1 === '>' && ch2 === '>' && ch3 === '>') {
741 if (ch4 === '=') {
742 index += 4;
743 return {
744 type: Token.Punctuator,
745 value: '>>>=',
746 lineNumber: lineNumber,
747 lineStart: lineStart,
748 range: [start, index]
749 };
750 }
751 }
752
753 // 3-character punctuators: === !== >>> <<= >>=
754
755 if (ch1 === '>' && ch2 === '>' && ch3 === '>') {
756 index += 3;
757 return {
758 type: Token.Punctuator,
759 value: '>>>',
760 lineNumber: lineNumber,
761 lineStart: lineStart,
762 range: [start, index]
763 };
764 }
765
766 if (ch1 === '<' && ch2 === '<' && ch3 === '=') {
767 index += 3;
768 return {
769 type: Token.Punctuator,
770 value: '<<=',
771 lineNumber: lineNumber,
772 lineStart: lineStart,
773 range: [start, index]
774 };
775 }
776
777 if (ch1 === '>' && ch2 === '>' && ch3 === '=') {
778 index += 3;
779 return {
780 type: Token.Punctuator,
781 value: '>>=',
782 lineNumber: lineNumber,
783 lineStart: lineStart,
784 range: [start, index]
785 };
786 }
787
788 if (ch1 === '.' && ch2 === '.' && ch3 === '.') {
789 index += 3;
790 return {
791 type: Token.Punctuator,
792 value: '...',
793 lineNumber: lineNumber,
794 lineStart: lineStart,
795 range: [start, index]
796 };
797 }
798
799 // Other 2-character punctuators: ++ -- << >> && ||
800
801 if (ch1 === ch2 && ('+-<>&|'.indexOf(ch1) >= 0)) {
802 index += 2;
803 return {
804 type: Token.Punctuator,
805 value: ch1 + ch2,
806 lineNumber: lineNumber,
807 lineStart: lineStart,
808 range: [start, index]
809 };
810 }
811
812 if (ch1 === '=' && ch2 === '>') {
813 index += 2;
814 return {
815 type: Token.Punctuator,
816 value: '=>',
817 lineNumber: lineNumber,
818 lineStart: lineStart,
819 range: [start, index]
820 };
821 }
822
823 if ('<>=!+-*%&|^/'.indexOf(ch1) >= 0) {
824 ++index;
825 return {
826 type: Token.Punctuator,
827 value: ch1,
828 lineNumber: lineNumber,
829 lineStart: lineStart,
830 range: [start, index]
831 };
832 }
833
834 if (ch1 === '.') {
835 ++index;
836 return {
837 type: Token.Punctuator,
838 value: ch1,
839 lineNumber: lineNumber,
840 lineStart: lineStart,
841 range: [start, index]
842 };
843 }
844
845 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
846 }
847
848 // 7.8.3 Numeric Literals
849
850 function scanHexLiteral(start) {
851 var number = '';
852
853 while (index < length) {
854 if (!isHexDigit(source[index])) {
855 break;
856 }
857 number += source[index++];
858 }
859
860 if (number.length === 0) {
861 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
862 }
863
864 if (isIdentifierStart(source.charCodeAt(index))) {
865 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
866 }
867
868 return {
869 type: Token.NumericLiteral,
870 value: parseInt('0x' + number, 16),
871 lineNumber: lineNumber,
872 lineStart: lineStart,
873 range: [start, index]
874 };
875 }
876
877 function scanOctalLiteral(prefix, start) {
878 var number, octal;
879
880 if (isOctalDigit(prefix)) {
881 octal = true;
882 number = '0' + source[index++];
883 } else {
884 octal = false;
885 ++index;
886 number = '';
887 }
888
889 while (index < length) {
890 if (!isOctalDigit(source[index])) {
891 break;
892 }
893 number += source[index++];
894 }
895
896 if (!octal && number.length === 0) {
897 // only 0o or 0O
898 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
899 }
900
901 if (isIdentifierStart(source.charCodeAt(index)) || isDecimalDigit(source.charCodeAt(index))) {
902 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
903 }
904
905 return {
906 type: Token.NumericLiteral,
907 value: parseInt(number, 8),
908 octal: octal,
909 lineNumber: lineNumber,
910 lineStart: lineStart,
911 range: [start, index]
912 };
913 }
914
915 function scanNumericLiteral() {
916 var number, start, ch, octal;
917
918 ch = source[index];
919 assert(isDecimalDigit(ch.charCodeAt(0)) || (ch === '.'),
920 'Numeric literal must start with a decimal digit or a decimal point');
921
922 start = index;
923 number = '';
924 if (ch !== '.') {
925 number = source[index++];
926 ch = source[index];
927
928 // Hex number starts with '0x'.
929 // Octal number starts with '0'.
930 // Octal number in ES6 starts with '0o'.
931 // Binary number in ES6 starts with '0b'.
932 if (number === '0') {
933 if (ch === 'x' || ch === 'X') {
934 ++index;
935 return scanHexLiteral(start);
936 }
937 if (ch === 'b' || ch === 'B') {
938 ++index;
939 number = '';
940
941 while (index < length) {
942 ch = source[index];
943 if (ch !== '0' && ch !== '1') {
944 break;
945 }
946 number += source[index++];
947 }
948
949 if (number.length === 0) {
950 // only 0b or 0B
951 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
952 }
953
954 if (index < length) {
955 ch = source.charCodeAt(index);
956 if (isIdentifierStart(ch) || isDecimalDigit(ch)) {
957 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
958 }
959 }
960 return {
961 type: Token.NumericLiteral,
962 value: parseInt(number, 2),
963 lineNumber: lineNumber,
964 lineStart: lineStart,
965 range: [start, index]
966 };
967 }
968 if (ch === 'o' || ch === 'O' || isOctalDigit(ch)) {
969 return scanOctalLiteral(ch, start);
970 }
971 // decimal number starts with '0' such as '09' is illegal.
972 if (ch && isDecimalDigit(ch.charCodeAt(0))) {
973 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
974 }
975 }
976
977 while (isDecimalDigit(source.charCodeAt(index))) {
978 number += source[index++];
979 }
980 ch = source[index];
981 }
982
983 if (ch === '.') {
984 number += source[index++];
985 while (isDecimalDigit(source.charCodeAt(index))) {
986 number += source[index++];
987 }
988 ch = source[index];
989 }
990
991 if (ch === 'e' || ch === 'E') {
992 number += source[index++];
993
994 ch = source[index];
995 if (ch === '+' || ch === '-') {
996 number += source[index++];
997 }
998 if (isDecimalDigit(source.charCodeAt(index))) {
999 while (isDecimalDigit(source.charCodeAt(index))) {
1000 number += source[index++];
1001 }
1002 } else {
1003 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
1004 }
1005 }
1006
1007 if (isIdentifierStart(source.charCodeAt(index))) {
1008 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
1009 }
1010
1011 return {
1012 type: Token.NumericLiteral,
1013 value: parseFloat(number),
1014 lineNumber: lineNumber,
1015 lineStart: lineStart,
1016 range: [start, index]
1017 };
1018 }
1019
1020 // 7.8.4 String Literals
1021
1022 function scanStringLiteral() {
1023 var str = '', quote, start, ch, code, unescaped, restore, octal = false;
1024
1025 quote = source[index];
1026 assert((quote === '\'' || quote === '"'),
1027 'String literal must starts with a quote');
1028
1029 start = index;
1030 ++index;
1031
1032 while (index < length) {
1033 ch = source[index++];
1034
1035 if (ch === quote) {
1036 quote = '';
1037 break;
1038 } else if (ch === '\\') {
1039 ch = source[index++];
1040 if (!ch || !isLineTerminator(ch.charCodeAt(0))) {
1041 switch (ch) {
1042 case 'n':
1043 str += '\n';
1044 break;
1045 case 'r':
1046 str += '\r';
1047 break;
1048 case 't':
1049 str += '\t';
1050 break;
1051 case 'u':
1052 case 'x':
1053 if (source[index] === '{') {
1054 ++index;
1055 str += scanUnicodeCodePointEscape();
1056 } else {
1057 restore = index;
1058 unescaped = scanHexEscape(ch);
1059 if (unescaped) {
1060 str += unescaped;
1061 } else {
1062 index = restore;
1063 str += ch;
1064 }
1065 }
1066 break;
1067 case 'b':
1068 str += '\b';
1069 break;
1070 case 'f':
1071 str += '\f';
1072 break;
1073 case 'v':
1074 str += '\x0B';
1075 break;
1076
1077 default:
1078 if (isOctalDigit(ch)) {
1079 code = '01234567'.indexOf(ch);
1080
1081 // \0 is not octal escape sequence
1082 if (code !== 0) {
1083 octal = true;
1084 }
1085
1086 if (index < length && isOctalDigit(source[index])) {
1087 octal = true;
1088 code = code * 8 + '01234567'.indexOf(source[index++]);
1089
1090 // 3 digits are only allowed when string starts
1091 // with 0, 1, 2, 3
1092 if ('0123'.indexOf(ch) >= 0 &&
1093 index < length &&
1094 isOctalDigit(source[index])) {
1095 code = code * 8 + '01234567'.indexOf(source[index++]);
1096 }
1097 }
1098 str += String.fromCharCode(code);
1099 } else {
1100 str += ch;
1101 }
1102 break;
1103 }
1104 } else {
1105 ++lineNumber;
1106 if (ch === '\r' && source[index] === '\n') {
1107 ++index;
1108 }
1109 }
1110 } else if (isLineTerminator(ch.charCodeAt(0))) {
1111 break;
1112 } else {
1113 str += ch;
1114 }
1115 }
1116
1117 if (quote !== '') {
1118 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
1119 }
1120
1121 return {
1122 type: Token.StringLiteral,
1123 value: str,
1124 octal: octal,
1125 lineNumber: lineNumber,
1126 lineStart: lineStart,
1127 range: [start, index]
1128 };
1129 }
1130
1131 function scanTemplate() {
1132 var cooked = '', ch, start, terminated, tail, restore, unescaped, code, octal;
1133
1134 terminated = false;
1135 tail = false;
1136 start = index;
1137
1138 ++index;
1139
1140 while (index < length) {
1141 ch = source[index++];
1142 if (ch === '`') {
1143 tail = true;
1144 terminated = true;
1145 break;
1146 } else if (ch === '$') {
1147 if (source[index] === '{') {
1148 ++index;
1149 terminated = true;
1150 break;
1151 }
1152 cooked += ch;
1153 } else if (ch === '\\') {
1154 ch = source[index++];
1155 if (!isLineTerminator(ch.charCodeAt(0))) {
1156 switch (ch) {
1157 case 'n':
1158 cooked += '\n';
1159 break;
1160 case 'r':
1161 cooked += '\r';
1162 break;
1163 case 't':
1164 cooked += '\t';
1165 break;
1166 case 'u':
1167 case 'x':
1168 if (source[index] === '{') {
1169 ++index;
1170 cooked += scanUnicodeCodePointEscape();
1171 } else {
1172 restore = index;
1173 unescaped = scanHexEscape(ch);
1174 if (unescaped) {
1175 cooked += unescaped;
1176 } else {
1177 index = restore;
1178 cooked += ch;
1179 }
1180 }
1181 break;
1182 case 'b':
1183 cooked += '\b';
1184 break;
1185 case 'f':
1186 cooked += '\f';
1187 break;
1188 case 'v':
1189 cooked += '\v';
1190 break;
1191
1192 default:
1193 if (isOctalDigit(ch)) {
1194 code = '01234567'.indexOf(ch);
1195
1196 // \0 is not octal escape sequence
1197 if (code !== 0) {
1198 octal = true;
1199 }
1200
1201 if (index < length && isOctalDigit(source[index])) {
1202 octal = true;
1203 code = code * 8 + '01234567'.indexOf(source[index++]);
1204
1205 // 3 digits are only allowed when string starts
1206 // with 0, 1, 2, 3
1207 if ('0123'.indexOf(ch) >= 0 &&
1208 index < length &&
1209 isOctalDigit(source[index])) {
1210 code = code * 8 + '01234567'.indexOf(source[index++]);
1211 }
1212 }
1213 cooked += String.fromCharCode(code);
1214 } else {
1215 cooked += ch;
1216 }
1217 break;
1218 }
1219 } else {
1220 ++lineNumber;
1221 if (ch === '\r' && source[index] === '\n') {
1222 ++index;
1223 }
1224 }
1225 } else if (isLineTerminator(ch.charCodeAt(0))) {
1226 ++lineNumber;
1227 if (ch === '\r' && source[index] === '\n') {
1228 ++index;
1229 }
1230 cooked += '\n';
1231 } else {
1232 cooked += ch;
1233 }
1234 }
1235
1236 if (!terminated) {
1237 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
1238 }
1239
1240 return {
1241 type: Token.Template,
1242 value: {
1243 cooked: cooked,
1244 raw: source.slice(start + 1, index - ((tail) ? 1 : 2))
1245 },
1246 tail: tail,
1247 octal: octal,
1248 lineNumber: lineNumber,
1249 lineStart: lineStart,
1250 range: [start, index]
1251 };
1252 }
1253
1254 function scanTemplateElement(option) {
1255 var startsWith, template;
1256
1257 lookahead = null;
1258 skipComment();
1259
1260 startsWith = (option.head) ? '`' : '}';
1261
1262 if (source[index] !== startsWith) {
1263 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
1264 }
1265
1266 template = scanTemplate();
1267
1268 peek();
1269
1270 return template;
1271 }
1272
1273 function scanRegExp() {
1274 var str, ch, start, pattern, flags, value, classMarker = false, restore, terminated = false;
1275
1276 lookahead = null;
1277 skipComment();
1278
1279 start = index;
1280 ch = source[index];
1281 assert(ch === '/', 'Regular expression literal must start with a slash');
1282 str = source[index++];
1283
1284 while (index < length) {
1285 ch = source[index++];
1286 str += ch;
1287 if (classMarker) {
1288 if (ch === ']') {
1289 classMarker = false;
1290 }
1291 } else {
1292 if (ch === '\\') {
1293 ch = source[index++];
1294 // ECMA-262 7.8.5
1295 if (isLineTerminator(ch.charCodeAt(0))) {
1296 throwError({}, Messages.UnterminatedRegExp);
1297 }
1298 str += ch;
1299 } else if (ch === '/') {
1300 terminated = true;
1301 break;
1302 } else if (ch === '[') {
1303 classMarker = true;
1304 } else if (isLineTerminator(ch.charCodeAt(0))) {
1305 throwError({}, Messages.UnterminatedRegExp);
1306 }
1307 }
1308 }
1309
1310 if (!terminated) {
1311 throwError({}, Messages.UnterminatedRegExp);
1312 }
1313
1314 // Exclude leading and trailing slash.
1315 pattern = str.substr(1, str.length - 2);
1316
1317 flags = '';
1318 while (index < length) {
1319 ch = source[index];
1320 if (!isIdentifierPart(ch.charCodeAt(0))) {
1321 break;
1322 }
1323
1324 ++index;
1325 if (ch === '\\' && index < length) {
1326 ch = source[index];
1327 if (ch === 'u') {
1328 ++index;
1329 restore = index;
1330 ch = scanHexEscape('u');
1331 if (ch) {
1332 flags += ch;
1333 for (str += '\\u'; restore < index; ++restore) {
1334 str += source[restore];
1335 }
1336 } else {
1337 index = restore;
1338 flags += 'u';
1339 str += '\\u';
1340 }
1341 } else {
1342 str += '\\';
1343 }
1344 } else {
1345 flags += ch;
1346 str += ch;
1347 }
1348 }
1349
1350 try {
1351 value = new RegExp(pattern, flags);
1352 } catch (e) {
1353 throwError({}, Messages.InvalidRegExp);
1354 }
1355
1356 peek();
1357
1358
1359 if (extra.tokenize) {
1360 return {
1361 type: Token.RegularExpression,
1362 value: value,
1363 lineNumber: lineNumber,
1364 lineStart: lineStart,
1365 range: [start, index]
1366 };
1367 }
1368 return {
1369 literal: str,
1370 value: value,
1371 range: [start, index]
1372 };
1373 }
1374
1375 function isIdentifierName(token) {
1376 return token.type === Token.Identifier ||
1377 token.type === Token.Keyword ||
1378 token.type === Token.BooleanLiteral ||
1379 token.type === Token.NullLiteral;
1380 }
1381
1382 function advanceSlash() {
1383 var prevToken,
1384 checkToken;
1385 // Using the following algorithm:
1386 // https://github.com/mozilla/sweet.js/wiki/design
1387 prevToken = extra.tokens[extra.tokens.length - 1];
1388 if (!prevToken) {
1389 // Nothing before that: it cannot be a division.
1390 return scanRegExp();
1391 }
1392 if (prevToken.type === 'Punctuator') {
1393 if (prevToken.value === ')') {
1394 checkToken = extra.tokens[extra.openParenToken - 1];
1395 if (checkToken &&
1396 checkToken.type === 'Keyword' &&
1397 (checkToken.value === 'if' ||
1398 checkToken.value === 'while' ||
1399 checkToken.value === 'for' ||
1400 checkToken.value === 'with')) {
1401 return scanRegExp();
1402 }
1403 return scanPunctuator();
1404 }
1405 if (prevToken.value === '}') {
1406 // Dividing a function by anything makes little sense,
1407 // but we have to check for that.
1408 if (extra.tokens[extra.openCurlyToken - 3] &&
1409 extra.tokens[extra.openCurlyToken - 3].type === 'Keyword') {
1410 // Anonymous function.
1411 checkToken = extra.tokens[extra.openCurlyToken - 4];
1412 if (!checkToken) {
1413 return scanPunctuator();
1414 }
1415 } else if (extra.tokens[extra.openCurlyToken - 4] &&
1416 extra.tokens[extra.openCurlyToken - 4].type === 'Keyword') {
1417 // Named function.
1418 checkToken = extra.tokens[extra.openCurlyToken - 5];
1419 if (!checkToken) {
1420 return scanRegExp();
1421 }
1422 } else {
1423 return scanPunctuator();
1424 }
1425 // checkToken determines whether the function is
1426 // a declaration or an expression.
1427 if (FnExprTokens.indexOf(checkToken.value) >= 0) {
1428 // It is an expression.
1429 return scanPunctuator();
1430 }
1431 // It is a declaration.
1432 return scanRegExp();
1433 }
1434 return scanRegExp();
1435 }
1436 if (prevToken.type === 'Keyword') {
1437 return scanRegExp();
1438 }
1439 return scanPunctuator();
1440 }
1441
1442 function advance() {
1443 var ch;
1444
1445 if (!state.inXJSChild) {
1446 skipComment();
1447 }
1448
1449 if (index >= length) {
1450 return {
1451 type: Token.EOF,
1452 lineNumber: lineNumber,
1453 lineStart: lineStart,
1454 range: [index, index]
1455 };
1456 }
1457
1458 if (state.inXJSChild) {
1459 return advanceXJSChild();
1460 }
1461
1462 ch = source.charCodeAt(index);
1463
1464 // Very common: ( and ) and ;
1465 if (ch === 40 || ch === 41 || ch === 58) {
1466 return scanPunctuator();
1467 }
1468
1469 // String literal starts with single quote (#39) or double quote (#34).
1470 if (ch === 39 || ch === 34) {
1471 if (state.inXJSTag) {
1472 return scanXJSStringLiteral();
1473 }
1474 return scanStringLiteral();
1475 }
1476
1477 if (state.inXJSTag && isXJSIdentifierStart(ch)) {
1478 return scanXJSIdentifier();
1479 }
1480
1481 if (ch === 96) {
1482 return scanTemplate();
1483 }
1484 if (isIdentifierStart(ch)) {
1485 return scanIdentifier();
1486 }
1487
1488 // Dot (.) char #46 can also start a floating-point number, hence the need
1489 // to check the next character.
1490 if (ch === 46) {
1491 if (isDecimalDigit(source.charCodeAt(index + 1))) {
1492 return scanNumericLiteral();
1493 }
1494 return scanPunctuator();
1495 }
1496
1497 if (isDecimalDigit(ch)) {
1498 return scanNumericLiteral();
1499 }
1500
1501 // Slash (/) char #47 can also start a regex.
1502 if (extra.tokenize && ch === 47) {
1503 return advanceSlash();
1504 }
1505
1506 return scanPunctuator();
1507 }
1508
1509 function lex() {
1510 var token;
1511
1512 token = lookahead;
1513 index = token.range[1];
1514 lineNumber = token.lineNumber;
1515 lineStart = token.lineStart;
1516
1517 lookahead = advance();
1518
1519 index = token.range[1];
1520 lineNumber = token.lineNumber;
1521 lineStart = token.lineStart;
1522
1523 return token;
1524 }
1525
1526 function peek() {
1527 var pos, line, start;
1528
1529 pos = index;
1530 line = lineNumber;
1531 start = lineStart;
1532 lookahead = advance();
1533 index = pos;
1534 lineNumber = line;
1535 lineStart = start;
1536 }
1537
1538 function lookahead2() {
1539 var adv, pos, line, start, result;
1540
1541 // If we are collecting the tokens, don't grab the next one yet.
1542 adv = (typeof extra.advance === 'function') ? extra.advance : advance;
1543
1544 pos = index;
1545 line = lineNumber;
1546 start = lineStart;
1547
1548 // Scan for the next immediate token.
1549 if (lookahead === null) {
1550 lookahead = adv();
1551 }
1552 index = lookahead.range[1];
1553 lineNumber = lookahead.lineNumber;
1554 lineStart = lookahead.lineStart;
1555
1556 // Grab the token right after.
1557 result = adv();
1558 index = pos;
1559 lineNumber = line;
1560 lineStart = start;
1561
1562 return result;
1563 }
1564
1565 function markerCreate() {
1566 if (!extra.loc && !extra.range) {
1567 return undefined;
1568 }
1569 skipComment();
1570 return {offset: index, line: lineNumber, col: index - lineStart};
1571 }
1572
1573 function markerCreatePreserveWhitespace() {
1574 if (!extra.loc && !extra.range) {
1575 return undefined;
1576 }
1577 return {offset: index, line: lineNumber, col: index - lineStart};
1578 }
1579
1580 function markerApply(marker, node) {
1581 if (extra.range) {
1582 node.range = [marker.offset, index];
1583 }
1584 if (extra.loc) {
1585 node.loc = {
1586 start: {
1587 line: marker.line,
1588 column: marker.col
1589 },
1590 end: {
1591 line: lineNumber,
1592 column: index - lineStart
1593 }
1594 };
1595 node = delegate.postProcess(node);
1596 }
1597 return node;
1598 }
1599
1600 SyntaxTreeDelegate = {
1601
1602 name: 'SyntaxTree',
1603
1604 postProcess: function (node) {
1605 return node;
1606 },
1607
1608 createArrayExpression: function (elements) {
1609 return {
1610 type: Syntax.ArrayExpression,
1611 elements: elements
1612 };
1613 },
1614
1615 createAssignmentExpression: function (operator, left, right) {
1616 return {
1617 type: Syntax.AssignmentExpression,
1618 operator: operator,
1619 left: left,
1620 right: right
1621 };
1622 },
1623
1624 createBinaryExpression: function (operator, left, right) {
1625 var type = (operator === '||' || operator === '&&') ? Syntax.LogicalExpression :
1626 Syntax.BinaryExpression;
1627 return {
1628 type: type,
1629 operator: operator,
1630 left: left,
1631 right: right
1632 };
1633 },
1634
1635 createBlockStatement: function (body) {
1636 return {
1637 type: Syntax.BlockStatement,
1638 body: body
1639 };
1640 },
1641
1642 createBreakStatement: function (label) {
1643 return {
1644 type: Syntax.BreakStatement,
1645 label: label
1646 };
1647 },
1648
1649 createCallExpression: function (callee, args) {
1650 return {
1651 type: Syntax.CallExpression,
1652 callee: callee,
1653 'arguments': args
1654 };
1655 },
1656
1657 createCatchClause: function (param, body) {
1658 return {
1659 type: Syntax.CatchClause,
1660 param: param,
1661 body: body
1662 };
1663 },
1664
1665 createConditionalExpression: function (test, consequent, alternate) {
1666 return {
1667 type: Syntax.ConditionalExpression,
1668 test: test,
1669 consequent: consequent,
1670 alternate: alternate
1671 };
1672 },
1673
1674 createContinueStatement: function (label) {
1675 return {
1676 type: Syntax.ContinueStatement,
1677 label: label
1678 };
1679 },
1680
1681 createDebuggerStatement: function () {
1682 return {
1683 type: Syntax.DebuggerStatement
1684 };
1685 },
1686
1687 createDoWhileStatement: function (body, test) {
1688 return {
1689 type: Syntax.DoWhileStatement,
1690 body: body,
1691 test: test
1692 };
1693 },
1694
1695 createEmptyStatement: function () {
1696 return {
1697 type: Syntax.EmptyStatement
1698 };
1699 },
1700
1701 createExpressionStatement: function (expression) {
1702 return {
1703 type: Syntax.ExpressionStatement,
1704 expression: expression
1705 };
1706 },
1707
1708 createForStatement: function (init, test, update, body) {
1709 return {
1710 type: Syntax.ForStatement,
1711 init: init,
1712 test: test,
1713 update: update,
1714 body: body
1715 };
1716 },
1717
1718 createForInStatement: function (left, right, body) {
1719 return {
1720 type: Syntax.ForInStatement,
1721 left: left,
1722 right: right,
1723 body: body,
1724 each: false
1725 };
1726 },
1727
1728 createForOfStatement: function (left, right, body) {
1729 return {
1730 type: Syntax.ForOfStatement,
1731 left: left,
1732 right: right,
1733 body: body
1734 };
1735 },
1736
1737 createFunctionDeclaration: function (id, params, defaults, body, rest, generator, expression,
1738 returnType, parametricType) {
1739 return {
1740 type: Syntax.FunctionDeclaration,
1741 id: id,
1742 params: params,
1743 defaults: defaults,
1744 body: body,
1745 rest: rest,
1746 generator: generator,
1747 expression: expression,
1748 returnType: returnType,
1749 parametricType: parametricType
1750 };
1751 },
1752
1753 createFunctionExpression: function (id, params, defaults, body, rest, generator, expression,
1754 returnType, parametricType) {
1755 return {
1756 type: Syntax.FunctionExpression,
1757 id: id,
1758 params: params,
1759 defaults: defaults,
1760 body: body,
1761 rest: rest,
1762 generator: generator,
1763 expression: expression,
1764 returnType: returnType,
1765 parametricType: parametricType
1766 };
1767 },
1768
1769 createIdentifier: function (name) {
1770 return {
1771 type: Syntax.Identifier,
1772 name: name,
1773 // Only here to initialize the shape of the object to ensure
1774 // that the 'typeAnnotation' key is ordered before others that
1775 // are added later (like 'loc' and 'range'). This just helps
1776 // keep the shape of Identifier nodes consistent with everything
1777 // else.
1778 typeAnnotation: undefined
1779 };
1780 },
1781
1782 createTypeAnnotation: function (typeIdentifier, parametricType, params, returnType, nullable) {
1783 return {
1784 type: Syntax.TypeAnnotation,
1785 id: typeIdentifier,
1786 parametricType: parametricType,
1787 params: params,
1788 returnType: returnType,
1789 nullable: nullable
1790 };
1791 },
1792
1793 createParametricTypeAnnotation: function (parametricTypes) {
1794 return {
1795 type: Syntax.ParametricTypeAnnotation,
1796 params: parametricTypes
1797 };
1798 },
1799
1800 createVoidTypeAnnotation: function () {
1801 return {
1802 type: Syntax.VoidTypeAnnotation
1803 };
1804 },
1805
1806 createObjectTypeAnnotation: function (properties) {
1807 return {
1808 type: Syntax.ObjectTypeAnnotation,
1809 properties: properties
1810 };
1811 },
1812
1813 createTypeAnnotatedIdentifier: function (identifier, annotation, isOptionalParam) {
1814 return {
1815 type: Syntax.TypeAnnotatedIdentifier,
1816 id: identifier,
1817 annotation: annotation
1818 };
1819 },
1820
1821 createOptionalParameter: function (identifier) {
1822 return {
1823 type: Syntax.OptionalParameter,
1824 id: identifier
1825 };
1826 },
1827
1828 createXJSAttribute: function (name, value) {
1829 return {
1830 type: Syntax.XJSAttribute,
1831 name: name,
1832 value: value
1833 };
1834 },
1835
1836 createXJSSpreadAttribute: function (argument) {
1837 return {
1838 type: Syntax.XJSSpreadAttribute,
1839 argument: argument
1840 };
1841 },
1842
1843 createXJSIdentifier: function (name) {
1844 return {
1845 type: Syntax.XJSIdentifier,
1846 name: name
1847 };
1848 },
1849
1850 createXJSNamespacedName: function (namespace, name) {
1851 return {
1852 type: Syntax.XJSNamespacedName,
1853 namespace: namespace,
1854 name: name
1855 };
1856 },
1857
1858 createXJSMemberExpression: function (object, property) {
1859 return {
1860 type: Syntax.XJSMemberExpression,
1861 object: object,
1862 property: property
1863 };
1864 },
1865
1866 createXJSElement: function (openingElement, closingElement, children) {
1867 return {
1868 type: Syntax.XJSElement,
1869 openingElement: openingElement,
1870 closingElement: closingElement,
1871 children: children
1872 };
1873 },
1874
1875 createXJSEmptyExpression: function () {
1876 return {
1877 type: Syntax.XJSEmptyExpression
1878 };
1879 },
1880
1881 createXJSExpressionContainer: function (expression) {
1882 return {
1883 type: Syntax.XJSExpressionContainer,
1884 expression: expression
1885 };
1886 },
1887
1888 createXJSOpeningElement: function (name, attributes, selfClosing) {
1889 return {
1890 type: Syntax.XJSOpeningElement,
1891 name: name,
1892 selfClosing: selfClosing,
1893 attributes: attributes
1894 };
1895 },
1896
1897 createXJSClosingElement: function (name) {
1898 return {
1899 type: Syntax.XJSClosingElement,
1900 name: name
1901 };
1902 },
1903
1904 createIfStatement: function (test, consequent, alternate) {
1905 return {
1906 type: Syntax.IfStatement,
1907 test: test,
1908 consequent: consequent,
1909 alternate: alternate
1910 };
1911 },
1912
1913 createLabeledStatement: function (label, body) {
1914 return {
1915 type: Syntax.LabeledStatement,
1916 label: label,
1917 body: body
1918 };
1919 },
1920
1921 createLiteral: function (token) {
1922 return {
1923 type: Syntax.Literal,
1924 value: token.value,
1925 raw: source.slice(token.range[0], token.range[1])
1926 };
1927 },
1928
1929 createMemberExpression: function (accessor, object, property) {
1930 return {
1931 type: Syntax.MemberExpression,
1932 computed: accessor === '[',
1933 object: object,
1934 property: property
1935 };
1936 },
1937
1938 createNewExpression: function (callee, args) {
1939 return {
1940 type: Syntax.NewExpression,
1941 callee: callee,
1942 'arguments': args
1943 };
1944 },
1945
1946 createObjectExpression: function (properties) {
1947 return {
1948 type: Syntax.ObjectExpression,
1949 properties: properties
1950 };
1951 },
1952
1953 createPostfixExpression: function (operator, argument) {
1954 return {
1955 type: Syntax.UpdateExpression,
1956 operator: operator,
1957 argument: argument,
1958 prefix: false
1959 };
1960 },
1961
1962 createProgram: function (body) {
1963 return {
1964 type: Syntax.Program,
1965 body: body
1966 };
1967 },
1968
1969 createProperty: function (kind, key, value, method, shorthand, computed) {
1970 return {
1971 type: Syntax.Property,
1972 key: key,
1973 value: value,
1974 kind: kind,
1975 method: method,
1976 shorthand: shorthand,
1977 computed: computed
1978 };
1979 },
1980
1981 createReturnStatement: function (argument) {
1982 return {
1983 type: Syntax.ReturnStatement,
1984 argument: argument
1985 };
1986 },
1987
1988 createSequenceExpression: function (expressions) {
1989 return {
1990 type: Syntax.SequenceExpression,
1991 expressions: expressions
1992 };
1993 },
1994
1995 createSwitchCase: function (test, consequent) {
1996 return {
1997 type: Syntax.SwitchCase,
1998 test: test,
1999 consequent: consequent
2000 };
2001 },
2002
2003 createSwitchStatement: function (discriminant, cases) {
2004 return {
2005 type: Syntax.SwitchStatement,
2006 discriminant: discriminant,
2007 cases: cases
2008 };
2009 },
2010
2011 createThisExpression: function () {
2012 return {
2013 type: Syntax.ThisExpression
2014 };
2015 },
2016
2017 createThrowStatement: function (argument) {
2018 return {
2019 type: Syntax.ThrowStatement,
2020 argument: argument
2021 };
2022 },
2023
2024 createTryStatement: function (block, guardedHandlers, handlers, finalizer) {
2025 return {
2026 type: Syntax.TryStatement,
2027 block: block,
2028 guardedHandlers: guardedHandlers,
2029 handlers: handlers,
2030 finalizer: finalizer
2031 };
2032 },
2033
2034 createUnaryExpression: function (operator, argument) {
2035 if (operator === '++' || operator === '--') {
2036 return {
2037 type: Syntax.UpdateExpression,
2038 operator: operator,
2039 argument: argument,
2040 prefix: true
2041 };
2042 }
2043 return {
2044 type: Syntax.UnaryExpression,
2045 operator: operator,
2046 argument: argument,
2047 prefix: true
2048 };
2049 },
2050
2051 createVariableDeclaration: function (declarations, kind) {
2052 return {
2053 type: Syntax.VariableDeclaration,
2054 declarations: declarations,
2055 kind: kind
2056 };
2057 },
2058
2059 createVariableDeclarator: function (id, init) {
2060 return {
2061 type: Syntax.VariableDeclarator,
2062 id: id,
2063 init: init
2064 };
2065 },
2066
2067 createWhileStatement: function (test, body) {
2068 return {
2069 type: Syntax.WhileStatement,
2070 test: test,
2071 body: body
2072 };
2073 },
2074
2075 createWithStatement: function (object, body) {
2076 return {
2077 type: Syntax.WithStatement,
2078 object: object,
2079 body: body
2080 };
2081 },
2082
2083 createTemplateElement: function (value, tail) {
2084 return {
2085 type: Syntax.TemplateElement,
2086 value: value,
2087 tail: tail
2088 };
2089 },
2090
2091 createTemplateLiteral: function (quasis, expressions) {
2092 return {
2093 type: Syntax.TemplateLiteral,
2094 quasis: quasis,
2095 expressions: expressions
2096 };
2097 },
2098
2099 createSpreadElement: function (argument) {
2100 return {
2101 type: Syntax.SpreadElement,
2102 argument: argument
2103 };
2104 },
2105
2106 createSpreadProperty: function (argument) {
2107 return {
2108 type: Syntax.SpreadProperty,
2109 argument: argument
2110 };
2111 },
2112
2113 createTaggedTemplateExpression: function (tag, quasi) {
2114 return {
2115 type: Syntax.TaggedTemplateExpression,
2116 tag: tag,
2117 quasi: quasi
2118 };
2119 },
2120
2121 createArrowFunctionExpression: function (params, defaults, body, rest, expression) {
2122 return {
2123 type: Syntax.ArrowFunctionExpression,
2124 id: null,
2125 params: params,
2126 defaults: defaults,
2127 body: body,
2128 rest: rest,
2129 generator: false,
2130 expression: expression
2131 };
2132 },
2133
2134 createMethodDefinition: function (propertyType, kind, key, value) {
2135 return {
2136 type: Syntax.MethodDefinition,
2137 key: key,
2138 value: value,
2139 kind: kind,
2140 'static': propertyType === ClassPropertyType.static
2141 };
2142 },
2143
2144 createClassProperty: function (propertyIdentifier) {
2145 return {
2146 type: Syntax.ClassProperty,
2147 id: propertyIdentifier
2148 };
2149 },
2150
2151 createClassBody: function (body) {
2152 return {
2153 type: Syntax.ClassBody,
2154 body: body
2155 };
2156 },
2157
2158 createClassExpression: function (id, superClass, body, parametricType) {
2159 return {
2160 type: Syntax.ClassExpression,
2161 id: id,
2162 superClass: superClass,
2163 body: body,
2164 parametricType: parametricType
2165 };
2166 },
2167
2168 createClassDeclaration: function (id, superClass, body, parametricType, superParametricType) {
2169 return {
2170 type: Syntax.ClassDeclaration,
2171 id: id,
2172 superClass: superClass,
2173 body: body,
2174 parametricType: parametricType,
2175 superParametricType: superParametricType
2176 };
2177 },
2178
2179 createExportSpecifier: function (id, name) {
2180 return {
2181 type: Syntax.ExportSpecifier,
2182 id: id,
2183 name: name
2184 };
2185 },
2186
2187 createExportBatchSpecifier: function () {
2188 return {
2189 type: Syntax.ExportBatchSpecifier
2190 };
2191 },
2192
2193 createExportDeclaration: function (declaration, specifiers, source) {
2194 return {
2195 type: Syntax.ExportDeclaration,
2196 declaration: declaration,
2197 specifiers: specifiers,
2198 source: source
2199 };
2200 },
2201
2202 createImportSpecifier: function (id, name) {
2203 return {
2204 type: Syntax.ImportSpecifier,
2205 id: id,
2206 name: name
2207 };
2208 },
2209
2210 createImportDeclaration: function (specifiers, kind, source) {
2211 return {
2212 type: Syntax.ImportDeclaration,
2213 specifiers: specifiers,
2214 kind: kind,
2215 source: source
2216 };
2217 },
2218
2219 createYieldExpression: function (argument, delegate) {
2220 return {
2221 type: Syntax.YieldExpression,
2222 argument: argument,
2223 delegate: delegate
2224 };
2225 },
2226
2227 createModuleDeclaration: function (id, source, body) {
2228 return {
2229 type: Syntax.ModuleDeclaration,
2230 id: id,
2231 source: source,
2232 body: body
2233 };
2234 },
2235
2236 createComprehensionExpression: function (filter, blocks, body) {
2237 return {
2238 type: Syntax.ComprehensionExpression,
2239 filter: filter,
2240 blocks: blocks,
2241 body: body
2242 };
2243 }
2244
2245 };
2246
2247 // Return true if there is a line terminator before the next token.
2248
2249 function peekLineTerminator() {
2250 var pos, line, start, found;
2251
2252 pos = index;
2253 line = lineNumber;
2254 start = lineStart;
2255 skipComment();
2256 found = lineNumber !== line;
2257 index = pos;
2258 lineNumber = line;
2259 lineStart = start;
2260
2261 return found;
2262 }
2263
2264 // Throw an exception
2265
2266 function throwError(token, messageFormat) {
2267 var error,
2268 args = Array.prototype.slice.call(arguments, 2),
2269 msg = messageFormat.replace(
2270 /%(\d)/g,
2271 function (whole, index) {
2272 assert(index < args.length, 'Message reference must be in range');
2273 return args[index];
2274 }
2275 );
2276
2277 if (typeof token.lineNumber === 'number') {
2278 error = new Error('Line ' + token.lineNumber + ': ' + msg);
2279 error.index = token.range[0];
2280 error.lineNumber = token.lineNumber;
2281 error.column = token.range[0] - lineStart + 1;
2282 } else {
2283 error = new Error('Line ' + lineNumber + ': ' + msg);
2284 error.index = index;
2285 error.lineNumber = lineNumber;
2286 error.column = index - lineStart + 1;
2287 }
2288
2289 error.description = msg;
2290 throw error;
2291 }
2292
2293 function throwErrorTolerant() {
2294 try {
2295 throwError.apply(null, arguments);
2296 } catch (e) {
2297 if (extra.errors) {
2298 extra.errors.push(e);
2299 } else {
2300 throw e;
2301 }
2302 }
2303 }
2304
2305
2306 // Throw an exception because of the token.
2307
2308 function throwUnexpected(token) {
2309 if (token.type === Token.EOF) {
2310 throwError(token, Messages.UnexpectedEOS);
2311 }
2312
2313 if (token.type === Token.NumericLiteral) {
2314 throwError(token, Messages.UnexpectedNumber);
2315 }
2316
2317 if (token.type === Token.StringLiteral || token.type === Token.XJSText) {
2318 throwError(token, Messages.UnexpectedString);
2319 }
2320
2321 if (token.type === Token.Identifier) {
2322 throwError(token, Messages.UnexpectedIdentifier);
2323 }
2324
2325 if (token.type === Token.Keyword) {
2326 if (isFutureReservedWord(token.value)) {
2327 throwError(token, Messages.UnexpectedReserved);
2328 } else if (strict && isStrictModeReservedWord(token.value)) {
2329 throwErrorTolerant(token, Messages.StrictReservedWord);
2330 return;
2331 }
2332 throwError(token, Messages.UnexpectedToken, token.value);
2333 }
2334
2335 if (token.type === Token.Template) {
2336 throwError(token, Messages.UnexpectedTemplate, token.value.raw);
2337 }
2338
2339 // BooleanLiteral, NullLiteral, or Punctuator.
2340 throwError(token, Messages.UnexpectedToken, token.value);
2341 }
2342
2343 // Expect the next token to match the specified punctuator.
2344 // If not, an exception will be thrown.
2345
2346 function expect(value) {
2347 var token = lex();
2348 if (token.type !== Token.Punctuator || token.value !== value) {
2349 throwUnexpected(token);
2350 }
2351 }
2352
2353 // Expect the next token to match the specified keyword.
2354 // If not, an exception will be thrown.
2355
2356 function expectKeyword(keyword) {
2357 var token = lex();
2358 if (token.type !== Token.Keyword || token.value !== keyword) {
2359 throwUnexpected(token);
2360 }
2361 }
2362
2363 // Return true if the next token matches the specified punctuator.
2364
2365 function match(value) {
2366 return lookahead.type === Token.Punctuator && lookahead.value === value;
2367 }
2368
2369 // Return true if the next token matches the specified keyword
2370
2371 function matchKeyword(keyword) {
2372 return lookahead.type === Token.Keyword && lookahead.value === keyword;
2373 }
2374
2375
2376 // Return true if the next token matches the specified contextual keyword
2377
2378 function matchContextualKeyword(keyword) {
2379 return lookahead.type === Token.Identifier && lookahead.value === keyword;
2380 }
2381
2382 // Return true if the next token is an assignment operator
2383
2384 function matchAssign() {
2385 var op;
2386
2387 if (lookahead.type !== Token.Punctuator) {
2388 return false;
2389 }
2390 op = lookahead.value;
2391 return op === '=' ||
2392 op === '*=' ||
2393 op === '/=' ||
2394 op === '%=' ||
2395 op === '+=' ||
2396 op === '-=' ||
2397 op === '<<=' ||
2398 op === '>>=' ||
2399 op === '>>>=' ||
2400 op === '&=' ||
2401 op === '^=' ||
2402 op === '|=';
2403 }
2404
2405 function consumeSemicolon() {
2406 var line;
2407
2408 // Catch the very common case first: immediately a semicolon (char #59).
2409 if (source.charCodeAt(index) === 59) {
2410 lex();
2411 return;
2412 }
2413
2414 line = lineNumber;
2415 skipComment();
2416 if (lineNumber !== line) {
2417 return;
2418 }
2419
2420 if (match(';')) {
2421 lex();
2422 return;
2423 }
2424
2425 if (lookahead.type !== Token.EOF && !match('}')) {
2426 throwUnexpected(lookahead);
2427 }
2428 }
2429
2430 // Return true if provided expression is LeftHandSideExpression
2431
2432 function isLeftHandSide(expr) {
2433 return expr.type === Syntax.Identifier || expr.type === Syntax.MemberExpression;
2434 }
2435
2436 function isAssignableLeftHandSide(expr) {
2437 return isLeftHandSide(expr) || expr.type === Syntax.ObjectPattern || expr.type === Syntax.ArrayPattern;
2438 }
2439
2440 // 11.1.4 Array Initialiser
2441
2442 function parseArrayInitialiser() {
2443 var elements = [], blocks = [], filter = null, tmp, possiblecomprehension = true, body,
2444 marker = markerCreate();
2445
2446 expect('[');
2447 while (!match(']')) {
2448 if (lookahead.value === 'for' &&
2449 lookahead.type === Token.Keyword) {
2450 if (!possiblecomprehension) {
2451 throwError({}, Messages.ComprehensionError);
2452 }
2453 matchKeyword('for');
2454 tmp = parseForStatement({ignoreBody: true});
2455 tmp.of = tmp.type === Syntax.ForOfStatement;
2456 tmp.type = Syntax.ComprehensionBlock;
2457 if (tmp.left.kind) { // can't be let or const
2458 throwError({}, Messages.ComprehensionError);
2459 }
2460 blocks.push(tmp);
2461 } else if (lookahead.value === 'if' &&
2462 lookahead.type === Token.Keyword) {
2463 if (!possiblecomprehension) {
2464 throwError({}, Messages.ComprehensionError);
2465 }
2466 expectKeyword('if');
2467 expect('(');
2468 filter = parseExpression();
2469 expect(')');
2470 } else if (lookahead.value === ',' &&
2471 lookahead.type === Token.Punctuator) {
2472 possiblecomprehension = false; // no longer allowed.
2473 lex();
2474 elements.push(null);
2475 } else {
2476 tmp = parseSpreadOrAssignmentExpression();
2477 elements.push(tmp);
2478 if (tmp && tmp.type === Syntax.SpreadElement) {
2479 if (!match(']')) {
2480 throwError({}, Messages.ElementAfterSpreadElement);
2481 }
2482 } else if (!(match(']') || matchKeyword('for') || matchKeyword('if'))) {
2483 expect(','); // this lexes.
2484 possiblecomprehension = false;
2485 }
2486 }
2487 }
2488
2489 expect(']');
2490
2491 if (filter && !blocks.length) {
2492 throwError({}, Messages.ComprehensionRequiresBlock);
2493 }
2494
2495 if (blocks.length) {
2496 if (elements.length !== 1) {
2497 throwError({}, Messages.ComprehensionError);
2498 }
2499 return markerApply(marker, delegate.createComprehensionExpression(filter, blocks, elements[0]));
2500 }
2501 return markerApply(marker, delegate.createArrayExpression(elements));
2502 }
2503
2504 // 11.1.5 Object Initialiser
2505
2506 function parsePropertyFunction(options) {
2507 var previousStrict, previousYieldAllowed, params, defaults, body,
2508 marker = markerCreate();
2509
2510 previousStrict = strict;
2511 previousYieldAllowed = state.yieldAllowed;
2512 state.yieldAllowed = options.generator;
2513 params = options.params || [];
2514 defaults = options.defaults || [];
2515
2516 body = parseConciseBody();
2517 if (options.name && strict && isRestrictedWord(params[0].name)) {
2518 throwErrorTolerant(options.name, Messages.StrictParamName);
2519 }
2520 strict = previousStrict;
2521 state.yieldAllowed = previousYieldAllowed;
2522
2523 return markerApply(marker, delegate.createFunctionExpression(
2524 null,
2525 params,
2526 defaults,
2527 body,
2528 options.rest || null,
2529 options.generator,
2530 body.type !== Syntax.BlockStatement,
2531 options.returnType,
2532 options.parametricType
2533 ));
2534 }
2535
2536
2537 function parsePropertyMethodFunction(options) {
2538 var previousStrict, tmp, method;
2539
2540 previousStrict = strict;
2541 strict = true;
2542
2543 tmp = parseParams();
2544
2545 if (tmp.stricted) {
2546 throwErrorTolerant(tmp.stricted, tmp.message);
2547 }
2548
2549
2550 method = parsePropertyFunction({
2551 params: tmp.params,
2552 defaults: tmp.defaults,
2553 rest: tmp.rest,
2554 generator: options.generator,
2555 returnType: tmp.returnType,
2556 parametricType: options.parametricType
2557 });
2558
2559 strict = previousStrict;
2560
2561 return method;
2562 }
2563
2564
2565 function parseObjectPropertyKey() {
2566 var marker = markerCreate(),
2567 token = lex(),
2568 propertyKey,
2569 result;
2570
2571 // Note: This function is called only from parseObjectProperty(), where
2572 // EOF and Punctuator tokens are already filtered out.
2573
2574 if (token.type === Token.StringLiteral || token.type === Token.NumericLiteral) {
2575 if (strict && token.octal) {
2576 throwErrorTolerant(token, Messages.StrictOctalLiteral);
2577 }
2578 return markerApply(marker, delegate.createLiteral(token));
2579 }
2580
2581 if (token.type === Token.Punctuator && token.value === '[') {
2582 // For computed properties we should skip the [ and ], and
2583 // capture in marker only the assignment expression itself.
2584 marker = markerCreate();
2585 propertyKey = parseAssignmentExpression();
2586 result = markerApply(marker, propertyKey);
2587 expect(']');
2588 return result;
2589 }
2590
2591 return markerApply(marker, delegate.createIdentifier(token.value));
2592 }
2593
2594 function parseObjectProperty() {
2595 var token, key, id, value, param, expr, computed,
2596 marker = markerCreate();
2597
2598 token = lookahead;
2599 computed = (token.value === '[');
2600
2601 if (token.type === Token.Identifier || computed) {
2602
2603 id = parseObjectPropertyKey();
2604
2605 // Property Assignment: Getter and Setter.
2606
2607 if (token.value === 'get' && !(match(':') || match('('))) {
2608 computed = (lookahead.value === '[');
2609 key = parseObjectPropertyKey();
2610 expect('(');
2611 expect(')');
2612 return markerApply(marker, delegate.createProperty('get', key, parsePropertyFunction({ generator: false }), false, false, computed));
2613 }
2614 if (token.value === 'set' && !(match(':') || match('('))) {
2615 computed = (lookahead.value === '[');
2616 key = parseObjectPropertyKey();
2617 expect('(');
2618 token = lookahead;
2619 param = [ parseTypeAnnotatableIdentifier() ];
2620 expect(')');
2621 return markerApply(marker, delegate.createProperty('set', key, parsePropertyFunction({ params: param, generator: false, name: token }), false, false, computed));
2622 }
2623 if (match(':')) {
2624 lex();
2625 return markerApply(marker, delegate.createProperty('init', id, parseAssignmentExpression(), false, false, computed));
2626 }
2627 if (match('(')) {
2628 return markerApply(marker, delegate.createProperty('init', id, parsePropertyMethodFunction({ generator: false }), true, false, computed));
2629 }
2630 if (computed) {
2631 // Computed properties can only be used with full notation.
2632 throwUnexpected(lookahead);
2633 }
2634 return markerApply(marker, delegate.createProperty('init', id, id, false, true, false));
2635 }
2636 if (token.type === Token.EOF || token.type === Token.Punctuator) {
2637 if (!match('*')) {
2638 throwUnexpected(token);
2639 }
2640 lex();
2641
2642 computed = (lookahead.type === Token.Punctuator && lookahead.value === '[');
2643
2644 id = parseObjectPropertyKey();
2645
2646 if (!match('(')) {
2647 throwUnexpected(lex());
2648 }
2649
2650 return markerApply(marker, delegate.createProperty('init', id, parsePropertyMethodFunction({ generator: true }), true, false, computed));
2651 }
2652 key = parseObjectPropertyKey();
2653 if (match(':')) {
2654 lex();
2655 return markerApply(marker, delegate.createProperty('init', key, parseAssignmentExpression(), false, false, false));
2656 }
2657 if (match('(')) {
2658 return markerApply(marker, delegate.createProperty('init', key, parsePropertyMethodFunction({ generator: false }), true, false, false));
2659 }
2660 throwUnexpected(lex());
2661 }
2662
2663 function parseObjectSpreadProperty() {
2664 var marker = markerCreate();
2665 expect('...');
2666 return markerApply(marker, delegate.createSpreadProperty(parseAssignmentExpression()));
2667 }
2668
2669 function parseObjectInitialiser() {
2670 var properties = [], property, name, key, kind, map = {}, toString = String,
2671 marker = markerCreate();
2672
2673 expect('{');
2674
2675 while (!match('}')) {
2676 if (match('...')) {
2677 property = parseObjectSpreadProperty();
2678 } else {
2679 property = parseObjectProperty();
2680
2681 if (property.key.type === Syntax.Identifier) {
2682 name = property.key.name;
2683 } else {
2684 name = toString(property.key.value);
2685 }
2686 kind = (property.kind === 'init') ? PropertyKind.Data : (property.kind === 'get') ? PropertyKind.Get : PropertyKind.Set;
2687
2688 key = '$' + name;
2689 if (Object.prototype.hasOwnProperty.call(map, key)) {
2690 if (map[key] === PropertyKind.Data) {
2691 if (strict && kind === PropertyKind.Data) {
2692 throwErrorTolerant({}, Messages.StrictDuplicateProperty);
2693 } else if (kind !== PropertyKind.Data) {
2694 throwErrorTolerant({}, Messages.AccessorDataProperty);
2695 }
2696 } else {
2697 if (kind === PropertyKind.Data) {
2698 throwErrorTolerant({}, Messages.AccessorDataProperty);
2699 } else if (map[key] & kind) {
2700 throwErrorTolerant({}, Messages.AccessorGetSet);
2701 }
2702 }
2703 map[key] |= kind;
2704 } else {
2705 map[key] = kind;
2706 }
2707 }
2708
2709 properties.push(property);
2710
2711 if (!match('}')) {
2712 expect(',');
2713 }
2714 }
2715
2716 expect('}');
2717
2718 return markerApply(marker, delegate.createObjectExpression(properties));
2719 }
2720
2721 function parseTemplateElement(option) {
2722 var marker = markerCreate(),
2723 token = scanTemplateElement(option);
2724 if (strict && token.octal) {
2725 throwError(token, Messages.StrictOctalLiteral);
2726 }
2727 return markerApply(marker, delegate.createTemplateElement({ raw: token.value.raw, cooked: token.value.cooked }, token.tail));
2728 }
2729
2730 function parseTemplateLiteral() {
2731 var quasi, quasis, expressions, marker = markerCreate();
2732
2733 quasi = parseTemplateElement({ head: true });
2734 quasis = [ quasi ];
2735 expressions = [];
2736
2737 while (!quasi.tail) {
2738 expressions.push(parseExpression());
2739 quasi = parseTemplateElement({ head: false });
2740 quasis.push(quasi);
2741 }
2742
2743 return markerApply(marker, delegate.createTemplateLiteral(quasis, expressions));
2744 }
2745
2746 // 11.1.6 The Grouping Operator
2747
2748 function parseGroupExpression() {
2749 var expr;
2750
2751 expect('(');
2752
2753 ++state.parenthesizedCount;
2754
2755 expr = parseExpression();
2756
2757 expect(')');
2758
2759 return expr;
2760 }
2761
2762
2763 // 11.1 Primary Expressions
2764
2765 function parsePrimaryExpression() {
2766 var marker, type, token, expr;
2767
2768 type = lookahead.type;
2769
2770 if (type === Token.Identifier) {
2771 marker = markerCreate();
2772 return markerApply(marker, delegate.createIdentifier(lex().value));
2773 }
2774
2775 if (type === Token.StringLiteral || type === Token.NumericLiteral) {
2776 if (strict && lookahead.octal) {
2777 throwErrorTolerant(lookahead, Messages.StrictOctalLiteral);
2778 }
2779 marker = markerCreate();
2780 return markerApply(marker, delegate.createLiteral(lex()));
2781 }
2782
2783 if (type === Token.Keyword) {
2784 if (matchKeyword('this')) {
2785 marker = markerCreate();
2786 lex();
2787 return markerApply(marker, delegate.createThisExpression());
2788 }
2789
2790 if (matchKeyword('function')) {
2791 return parseFunctionExpression();
2792 }
2793
2794 if (matchKeyword('class')) {
2795 return parseClassExpression();
2796 }
2797
2798 if (matchKeyword('super')) {
2799 marker = markerCreate();
2800 lex();
2801 return markerApply(marker, delegate.createIdentifier('super'));
2802 }
2803 }
2804
2805 if (type === Token.BooleanLiteral) {
2806 marker = markerCreate();
2807 token = lex();
2808 token.value = (token.value === 'true');
2809 return markerApply(marker, delegate.createLiteral(token));
2810 }
2811
2812 if (type === Token.NullLiteral) {
2813 marker = markerCreate();
2814 token = lex();
2815 token.value = null;
2816 return markerApply(marker, delegate.createLiteral(token));
2817 }
2818
2819 if (match('[')) {
2820 return parseArrayInitialiser();
2821 }
2822
2823 if (match('{')) {
2824 return parseObjectInitialiser();
2825 }
2826
2827 if (match('(')) {
2828 return parseGroupExpression();
2829 }
2830
2831 if (match('/') || match('/=')) {
2832 marker = markerCreate();
2833 return markerApply(marker, delegate.createLiteral(scanRegExp()));
2834 }
2835
2836 if (type === Token.Template) {
2837 return parseTemplateLiteral();
2838 }
2839
2840 if (match('<')) {
2841 return parseXJSElement();
2842 }
2843
2844 throwUnexpected(lex());
2845 }
2846
2847 // 11.2 Left-Hand-Side Expressions
2848
2849 function parseArguments() {
2850 var args = [], arg;
2851
2852 expect('(');
2853
2854 if (!match(')')) {
2855 while (index < length) {
2856 arg = parseSpreadOrAssignmentExpression();
2857 args.push(arg);
2858
2859 if (match(')')) {
2860 break;
2861 } else if (arg.type === Syntax.SpreadElement) {
2862 throwError({}, Messages.ElementAfterSpreadElement);
2863 }
2864
2865 expect(',');
2866 }
2867 }
2868
2869 expect(')');
2870
2871 return args;
2872 }
2873
2874 function parseSpreadOrAssignmentExpression() {
2875 if (match('...')) {
2876 var marker = markerCreate();
2877 lex();
2878 return markerApply(marker, delegate.createSpreadElement(parseAssignmentExpression()));
2879 }
2880 return parseAssignmentExpression();
2881 }
2882
2883 function parseNonComputedProperty() {
2884 var marker = markerCreate(),
2885 token = lex();
2886
2887 if (!isIdentifierName(token)) {
2888 throwUnexpected(token);
2889 }
2890
2891 return markerApply(marker, delegate.createIdentifier(token.value));
2892 }
2893
2894 function parseNonComputedMember() {
2895 expect('.');
2896
2897 return parseNonComputedProperty();
2898 }
2899
2900 function parseComputedMember() {
2901 var expr;
2902
2903 expect('[');
2904
2905 expr = parseExpression();
2906
2907 expect(']');
2908
2909 return expr;
2910 }
2911
2912 function parseNewExpression() {
2913 var callee, args, marker = markerCreate();
2914
2915 expectKeyword('new');
2916 callee = parseLeftHandSideExpression();
2917 args = match('(') ? parseArguments() : [];
2918
2919 return markerApply(marker, delegate.createNewExpression(callee, args));
2920 }
2921
2922 function parseLeftHandSideExpressionAllowCall() {
2923 var expr, args, marker = markerCreate();
2924
2925 expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression();
2926
2927 while (match('.') || match('[') || match('(') || lookahead.type === Token.Template) {
2928 if (match('(')) {
2929 args = parseArguments();
2930 expr = markerApply(marker, delegate.createCallExpression(expr, args));
2931 } else if (match('[')) {
2932 expr = markerApply(marker, delegate.createMemberExpression('[', expr, parseComputedMember()));
2933 } else if (match('.')) {
2934 expr = markerApply(marker, delegate.createMemberExpression('.', expr, parseNonComputedMember()));
2935 } else {
2936 expr = markerApply(marker, delegate.createTaggedTemplateExpression(expr, parseTemplateLiteral()));
2937 }
2938 }
2939
2940 return expr;
2941 }
2942
2943 function parseLeftHandSideExpression() {
2944 var expr, marker = markerCreate();
2945
2946 expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression();
2947
2948 while (match('.') || match('[') || lookahead.type === Token.Template) {
2949 if (match('[')) {
2950 expr = markerApply(marker, delegate.createMemberExpression('[', expr, parseComputedMember()));
2951 } else if (match('.')) {
2952 expr = markerApply(marker, delegate.createMemberExpression('.', expr, parseNonComputedMember()));
2953 } else {
2954 expr = markerApply(marker, delegate.createTaggedTemplateExpression(expr, parseTemplateLiteral()));
2955 }
2956 }
2957
2958 return expr;
2959 }
2960
2961 // 11.3 Postfix Expressions
2962
2963 function parsePostfixExpression() {
2964 var marker = markerCreate(),
2965 expr = parseLeftHandSideExpressionAllowCall(),
2966 token;
2967
2968 if (lookahead.type !== Token.Punctuator) {
2969 return expr;
2970 }
2971
2972 if ((match('++') || match('--')) && !peekLineTerminator()) {
2973 // 11.3.1, 11.3.2
2974 if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) {
2975 throwErrorTolerant({}, Messages.StrictLHSPostfix);
2976 }
2977
2978 if (!isLeftHandSide(expr)) {
2979 throwError({}, Messages.InvalidLHSInAssignment);
2980 }
2981
2982 token = lex();
2983 expr = markerApply(marker, delegate.createPostfixExpression(token.value, expr));
2984 }
2985
2986 return expr;
2987 }
2988
2989 // 11.4 Unary Operators
2990
2991 function parseUnaryExpression() {
2992 var marker, token, expr;
2993
2994 if (lookahead.type !== Token.Punctuator && lookahead.type !== Token.Keyword) {
2995 return parsePostfixExpression();
2996 }
2997
2998 if (match('++') || match('--')) {
2999 marker = markerCreate();
3000 token = lex();
3001 expr = parseUnaryExpression();
3002 // 11.4.4, 11.4.5
3003 if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) {
3004 throwErrorTolerant({}, Messages.StrictLHSPrefix);
3005 }
3006
3007 if (!isLeftHandSide(expr)) {
3008 throwError({}, Messages.InvalidLHSInAssignment);
3009 }
3010
3011 return markerApply(marker, delegate.createUnaryExpression(token.value, expr));
3012 }
3013
3014 if (match('+') || match('-') || match('~') || match('!')) {
3015 marker = markerCreate();
3016 token = lex();
3017 expr = parseUnaryExpression();
3018 return markerApply(marker, delegate.createUnaryExpression(token.value, expr));
3019 }
3020
3021 if (matchKeyword('delete') || matchKeyword('void') || matchKeyword('typeof')) {
3022 marker = markerCreate();
3023 token = lex();
3024 expr = parseUnaryExpression();
3025 expr = markerApply(marker, delegate.createUnaryExpression(token.value, expr));
3026 if (strict && expr.operator === 'delete' && expr.argument.type === Syntax.Identifier) {
3027 throwErrorTolerant({}, Messages.StrictDelete);
3028 }
3029 return expr;
3030 }
3031
3032 return parsePostfixExpression();
3033 }
3034
3035 function binaryPrecedence(token, allowIn) {
3036 var prec = 0;
3037
3038 if (token.type !== Token.Punctuator && token.type !== Token.Keyword) {
3039 return 0;
3040 }
3041
3042 switch (token.value) {
3043 case '||':
3044 prec = 1;
3045 break;
3046
3047 case '&&':
3048 prec = 2;
3049 break;
3050
3051 case '|':
3052 prec = 3;
3053 break;
3054
3055 case '^':
3056 prec = 4;
3057 break;
3058
3059 case '&':
3060 prec = 5;
3061 break;
3062
3063 case '==':
3064 case '!=':
3065 case '===':
3066 case '!==':
3067 prec = 6;
3068 break;
3069
3070 case '<':
3071 case '>':
3072 case '<=':
3073 case '>=':
3074 case 'instanceof':
3075 prec = 7;
3076 break;
3077
3078 case 'in':
3079 prec = allowIn ? 7 : 0;
3080 break;
3081
3082 case '<<':
3083 case '>>':
3084 case '>>>':
3085 prec = 8;
3086 break;
3087
3088 case '+':
3089 case '-':
3090 prec = 9;
3091 break;
3092
3093 case '*':
3094 case '/':
3095 case '%':
3096 prec = 11;
3097 break;
3098
3099 default:
3100 break;
3101 }
3102
3103 return prec;
3104 }
3105
3106 // 11.5 Multiplicative Operators
3107 // 11.6 Additive Operators
3108 // 11.7 Bitwise Shift Operators
3109 // 11.8 Relational Operators
3110 // 11.9 Equality Operators
3111 // 11.10 Binary Bitwise Operators
3112 // 11.11 Binary Logical Operators
3113
3114 function parseBinaryExpression() {
3115 var expr, token, prec, previousAllowIn, stack, right, operator, left, i,
3116 marker, markers;
3117
3118 previousAllowIn = state.allowIn;
3119 state.allowIn = true;
3120
3121 marker = markerCreate();
3122 left = parseUnaryExpression();
3123
3124 token = lookahead;
3125 prec = binaryPrecedence(token, previousAllowIn);
3126 if (prec === 0) {
3127 return left;
3128 }
3129 token.prec = prec;
3130 lex();
3131
3132 markers = [marker, markerCreate()];
3133 right = parseUnaryExpression();
3134
3135 stack = [left, token, right];
3136
3137 while ((prec = binaryPrecedence(lookahead, previousAllowIn)) > 0) {
3138
3139 // Reduce: make a binary expression from the three topmost entries.
3140 while ((stack.length > 2) && (prec <= stack[stack.length - 2].prec)) {
3141 right = stack.pop();
3142 operator = stack.pop().value;
3143 left = stack.pop();
3144 expr = delegate.createBinaryExpression(operator, left, right);
3145 markers.pop();
3146 marker = markers.pop();
3147 markerApply(marker, expr);
3148 stack.push(expr);
3149 markers.push(marker);
3150 }
3151
3152 // Shift.
3153 token = lex();
3154 token.prec = prec;
3155 stack.push(token);
3156 markers.push(markerCreate());
3157 expr = parseUnaryExpression();
3158 stack.push(expr);
3159 }
3160
3161 state.allowIn = previousAllowIn;
3162
3163 // Final reduce to clean-up the stack.
3164 i = stack.length - 1;
3165 expr = stack[i];
3166 markers.pop();
3167 while (i > 1) {
3168 expr = delegate.createBinaryExpression(stack[i - 1].value, stack[i - 2], expr);
3169 i -= 2;
3170 marker = markers.pop();
3171 markerApply(marker, expr);
3172 }
3173
3174 return expr;
3175 }
3176
3177
3178 // 11.12 Conditional Operator
3179
3180 function parseConditionalExpression() {
3181 var expr, previousAllowIn, consequent, alternate, marker = markerCreate();
3182 expr = parseBinaryExpression();
3183
3184 if (match('?')) {
3185 lex();
3186 previousAllowIn = state.allowIn;
3187 state.allowIn = true;
3188 consequent = parseAssignmentExpression();
3189 state.allowIn = previousAllowIn;
3190 expect(':');
3191 alternate = parseAssignmentExpression();
3192
3193 expr = markerApply(marker, delegate.createConditionalExpression(expr, consequent, alternate));
3194 }
3195
3196 return expr;
3197 }
3198
3199 // 11.13 Assignment Operators
3200
3201 function reinterpretAsAssignmentBindingPattern(expr) {
3202 var i, len, property, element;
3203
3204 if (expr.type === Syntax.ObjectExpression) {
3205 expr.type = Syntax.ObjectPattern;
3206 for (i = 0, len = expr.properties.length; i < len; i += 1) {
3207 property = expr.properties[i];
3208 if (property.type === Syntax.SpreadProperty) {
3209 if (i < len - 1) {
3210 throwError({}, Messages.PropertyAfterSpreadProperty);
3211 }
3212 reinterpretAsAssignmentBindingPattern(property.argument);
3213 } else {
3214 if (property.kind !== 'init') {
3215 throwError({}, Messages.InvalidLHSInAssignment);
3216 }
3217 reinterpretAsAssignmentBindingPattern(property.value);
3218 }
3219 }
3220 } else if (expr.type === Syntax.ArrayExpression) {
3221 expr.type = Syntax.ArrayPattern;
3222 for (i = 0, len = expr.elements.length; i < len; i += 1) {
3223 element = expr.elements[i];
3224 if (element) {
3225 reinterpretAsAssignmentBindingPattern(element);
3226 }
3227 }
3228 } else if (expr.type === Syntax.Identifier) {
3229 if (isRestrictedWord(expr.name)) {
3230 throwError({}, Messages.InvalidLHSInAssignment);
3231 }
3232 } else if (expr.type === Syntax.SpreadElement) {
3233 reinterpretAsAssignmentBindingPattern(expr.argument);
3234 if (expr.argument.type === Syntax.ObjectPattern) {
3235 throwError({}, Messages.ObjectPatternAsSpread);
3236 }
3237 } else {
3238 if (expr.type !== Syntax.MemberExpression && expr.type !== Syntax.CallExpression && expr.type !== Syntax.NewExpression) {
3239 throwError({}, Messages.InvalidLHSInAssignment);
3240 }
3241 }
3242 }
3243
3244
3245 function reinterpretAsDestructuredParameter(options, expr) {
3246 var i, len, property, element;
3247
3248 if (expr.type === Syntax.ObjectExpression) {
3249 expr.type = Syntax.ObjectPattern;
3250 for (i = 0, len = expr.properties.length; i < len; i += 1) {
3251 property = expr.properties[i];
3252 if (property.type === Syntax.SpreadProperty) {
3253 if (i < len - 1) {
3254 throwError({}, Messages.PropertyAfterSpreadProperty);
3255 }
3256 reinterpretAsDestructuredParameter(options, property.argument);
3257 } else {
3258 if (property.kind !== 'init') {
3259 throwError({}, Messages.InvalidLHSInFormalsList);
3260 }
3261 reinterpretAsDestructuredParameter(options, property.value);
3262 }
3263 }
3264 } else if (expr.type === Syntax.ArrayExpression) {
3265 expr.type = Syntax.ArrayPattern;
3266 for (i = 0, len = expr.elements.length; i < len; i += 1) {
3267 element = expr.elements[i];
3268 if (element) {
3269 reinterpretAsDestructuredParameter(options, element);
3270 }
3271 }
3272 } else if (expr.type === Syntax.Identifier) {
3273 validateParam(options, expr, expr.name);
3274 } else {
3275 if (expr.type !== Syntax.MemberExpression) {
3276 throwError({}, Messages.InvalidLHSInFormalsList);
3277 }
3278 }
3279 }
3280
3281 function reinterpretAsCoverFormalsList(expressions) {
3282 var i, len, param, params, defaults, defaultCount, options, rest;
3283
3284 params = [];
3285 defaults = [];
3286 defaultCount = 0;
3287 rest = null;
3288 options = {
3289 paramSet: {}
3290 };
3291
3292 for (i = 0, len = expressions.length; i < len; i += 1) {
3293 param = expressions[i];
3294 if (param.type === Syntax.Identifier) {
3295 params.push(param);
3296 defaults.push(null);
3297 validateParam(options, param, param.name);
3298 } else if (param.type === Syntax.ObjectExpression || param.type === Syntax.ArrayExpression) {
3299 reinterpretAsDestructuredParameter(options, param);
3300 params.push(param);
3301 defaults.push(null);
3302 } else if (param.type === Syntax.SpreadElement) {
3303 assert(i === len - 1, 'It is guaranteed that SpreadElement is last element by parseExpression');
3304 reinterpretAsDestructuredParameter(options, param.argument);
3305 rest = param.argument;
3306 } else if (param.type === Syntax.AssignmentExpression) {
3307 params.push(param.left);
3308 defaults.push(param.right);
3309 ++defaultCount;
3310 validateParam(options, param.left, param.left.name);
3311 } else {
3312 return null;
3313 }
3314 }
3315
3316 if (options.message === Messages.StrictParamDupe) {
3317 throwError(
3318 strict ? options.stricted : options.firstRestricted,
3319 options.message
3320 );
3321 }
3322
3323 if (defaultCount === 0) {
3324 defaults = [];
3325 }
3326
3327 return {
3328 params: params,
3329 defaults: defaults,
3330 rest: rest,
3331 stricted: options.stricted,
3332 firstRestricted: options.firstRestricted,
3333 message: options.message
3334 };
3335 }
3336
3337 function parseArrowFunctionExpression(options, marker) {
3338 var previousStrict, previousYieldAllowed, body;
3339
3340 expect('=>');
3341
3342 previousStrict = strict;
3343 previousYieldAllowed = state.yieldAllowed;
3344 state.yieldAllowed = false;
3345 body = parseConciseBody();
3346
3347 if (strict && options.firstRestricted) {
3348 throwError(options.firstRestricted, options.message);
3349 }
3350 if (strict && options.stricted) {
3351 throwErrorTolerant(options.stricted, options.message);
3352 }
3353
3354 strict = previousStrict;
3355 state.yieldAllowed = previousYieldAllowed;
3356
3357 return markerApply(marker, delegate.createArrowFunctionExpression(
3358 options.params,
3359 options.defaults,
3360 body,
3361 options.rest,
3362 body.type !== Syntax.BlockStatement
3363 ));
3364 }
3365
3366 function parseAssignmentExpression() {
3367 var marker, expr, token, params, oldParenthesizedCount;
3368
3369 // Note that 'yield' is treated as a keyword in strict mode, but a
3370 // contextual keyword (identifier) in non-strict mode, so we need
3371 // to use matchKeyword and matchContextualKeyword appropriately.
3372 if ((state.yieldAllowed && matchContextualKeyword('yield')) || (strict && matchKeyword('yield'))) {
3373 return parseYieldExpression();
3374 }
3375
3376 oldParenthesizedCount = state.parenthesizedCount;
3377
3378 marker = markerCreate();
3379
3380 if (match('(')) {
3381 token = lookahead2();
3382 if ((token.type === Token.Punctuator && token.value === ')') || token.value === '...') {
3383 params = parseParams();
3384 if (!match('=>')) {
3385 throwUnexpected(lex());
3386 }
3387 return parseArrowFunctionExpression(params, marker);
3388 }
3389 }
3390
3391 token = lookahead;
3392 expr = parseConditionalExpression();
3393
3394 if (match('=>') &&
3395 (state.parenthesizedCount === oldParenthesizedCount ||
3396 state.parenthesizedCount === (oldParenthesizedCount + 1))) {
3397 if (expr.type === Syntax.Identifier) {
3398 params = reinterpretAsCoverFormalsList([ expr ]);
3399 } else if (expr.type === Syntax.SequenceExpression) {
3400 params = reinterpretAsCoverFormalsList(expr.expressions);
3401 }
3402 if (params) {
3403 return parseArrowFunctionExpression(params, marker);
3404 }
3405 }
3406
3407 if (matchAssign()) {
3408 // 11.13.1
3409 if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) {
3410 throwErrorTolerant(token, Messages.StrictLHSAssignment);
3411 }
3412
3413 // ES.next draf 11.13 Runtime Semantics step 1
3414 if (match('=') && (expr.type === Syntax.ObjectExpression || expr.type === Syntax.ArrayExpression)) {
3415 reinterpretAsAssignmentBindingPattern(expr);
3416 } else if (!isLeftHandSide(expr)) {
3417 throwError({}, Messages.InvalidLHSInAssignment);
3418 }
3419
3420 expr = markerApply(marker, delegate.createAssignmentExpression(lex().value, expr, parseAssignmentExpression()));
3421 }
3422
3423 return expr;
3424 }
3425
3426 // 11.14 Comma Operator
3427
3428 function parseExpression() {
3429 var marker, expr, expressions, sequence, coverFormalsList, spreadFound, oldParenthesizedCount;
3430
3431 oldParenthesizedCount = state.parenthesizedCount;
3432
3433 marker = markerCreate();
3434 expr = parseAssignmentExpression();
3435 expressions = [ expr ];
3436
3437 if (match(',')) {
3438 while (index < length) {
3439 if (!match(',')) {
3440 break;
3441 }
3442
3443 lex();
3444 expr = parseSpreadOrAssignmentExpression();
3445 expressions.push(expr);
3446
3447 if (expr.type === Syntax.SpreadElement) {
3448 spreadFound = true;
3449 if (!match(')')) {
3450 throwError({}, Messages.ElementAfterSpreadElement);
3451 }
3452 break;
3453 }
3454 }
3455
3456 sequence = markerApply(marker, delegate.createSequenceExpression(expressions));
3457 }
3458
3459 if (match('=>')) {
3460 // Do not allow nested parentheses on the LHS of the =>.
3461 if (state.parenthesizedCount === oldParenthesizedCount || state.parenthesizedCount === (oldParenthesizedCount + 1)) {
3462 expr = expr.type === Syntax.SequenceExpression ? expr.expressions : expressions;
3463 coverFormalsList = reinterpretAsCoverFormalsList(expr);
3464 if (coverFormalsList) {
3465 return parseArrowFunctionExpression(coverFormalsList, marker);
3466 }
3467 }
3468 throwUnexpected(lex());
3469 }
3470
3471 if (spreadFound && lookahead2().value !== '=>') {
3472 throwError({}, Messages.IllegalSpread);
3473 }
3474
3475 return sequence || expr;
3476 }
3477
3478 // 12.1 Block
3479
3480 function parseStatementList() {
3481 var list = [],
3482 statement;
3483
3484 while (index < length) {
3485 if (match('}')) {
3486 break;
3487 }
3488 statement = parseSourceElement();
3489 if (typeof statement === 'undefined') {
3490 break;
3491 }
3492 list.push(statement);
3493 }
3494
3495 return list;
3496 }
3497
3498 function parseBlock() {
3499 var block, marker = markerCreate();
3500
3501 expect('{');
3502
3503 block = parseStatementList();
3504
3505 expect('}');
3506
3507 return markerApply(marker, delegate.createBlockStatement(block));
3508 }
3509
3510 // 12.2 Variable Statement
3511
3512 function parseObjectTypeAnnotation() {
3513 var isMethod, marker, properties = [], property, propertyKey,
3514 propertyTypeAnnotation;
3515
3516 expect('{');
3517
3518 while (!match('}')) {
3519 marker = markerCreate();
3520 propertyKey = parseObjectPropertyKey();
3521 isMethod = match('(');
3522 propertyTypeAnnotation = parseTypeAnnotation();
3523 properties.push(markerApply(marker, delegate.createProperty(
3524 'init',
3525 propertyKey,
3526 propertyTypeAnnotation,
3527 isMethod,
3528 false
3529 )));
3530
3531 if (!match('}')) {
3532 if (match(',') || match(';')) {
3533 lex();
3534 } else {
3535 throwUnexpected(lookahead);
3536 }
3537 }
3538 }
3539
3540 expect('}');
3541
3542 return delegate.createObjectTypeAnnotation(properties);
3543 }
3544
3545 function parseVoidTypeAnnotation() {
3546 var marker = markerCreate();
3547 expectKeyword('void');
3548 return markerApply(marker, delegate.createVoidTypeAnnotation());
3549 }
3550
3551 function parseParametricTypeAnnotation() {
3552 var marker = markerCreate(), typeIdentifier, paramTypes = [];
3553
3554 expect('<');
3555 while (!match('>')) {
3556 paramTypes.push(parseVariableIdentifier());
3557 if (!match('>')) {
3558 expect(',');
3559 }
3560 }
3561 expect('>');
3562
3563 return markerApply(marker, delegate.createParametricTypeAnnotation(
3564 paramTypes
3565 ));
3566 }
3567
3568 function parseTypeAnnotation(dontExpectColon) {
3569 var typeIdentifier = null, params = null, returnType = null,
3570 nullable = false, marker = markerCreate(), returnTypeMarker = null,
3571 parametricType, annotation;
3572
3573 if (!dontExpectColon) {
3574 expect(':');
3575 }
3576
3577 if (match('{')) {
3578 return markerApply(marker, parseObjectTypeAnnotation());
3579 }
3580
3581 if (match('?')) {
3582 lex();
3583 nullable = true;
3584 }
3585
3586 if (lookahead.type === Token.Identifier) {
3587 typeIdentifier = parseVariableIdentifier();
3588 if (match('<')) {
3589 parametricType = parseParametricTypeAnnotation();
3590 }
3591 } else if (match('(')) {
3592 lex();
3593 params = [];
3594 while (lookahead.type === Token.Identifier || match('?')) {
3595 params.push(parseTypeAnnotatableIdentifier(
3596 true, /* requireTypeAnnotation */
3597 true /* canBeOptionalParam */
3598 ));
3599 if (!match(')')) {
3600 expect(',');
3601 }
3602 }
3603 expect(')');
3604
3605 returnTypeMarker = markerCreate();
3606 expect('=>');
3607
3608 returnType = parseTypeAnnotation(true);
3609 } else {
3610 if (!matchKeyword('void')) {
3611 throwUnexpected(lookahead);
3612 } else {
3613 return parseVoidTypeAnnotation();
3614 }
3615 }
3616
3617 return markerApply(marker, delegate.createTypeAnnotation(
3618 typeIdentifier,
3619 parametricType,
3620 params,
3621 returnType,
3622 nullable
3623 ));
3624 }
3625
3626 function parseVariableIdentifier() {
3627 var marker = markerCreate(),
3628 token = lex();
3629
3630 if (token.type !== Token.Identifier) {
3631 throwUnexpected(token);
3632 }
3633
3634 return markerApply(marker, delegate.createIdentifier(token.value));
3635 }
3636
3637 function parseTypeAnnotatableIdentifier(requireTypeAnnotation, canBeOptionalParam) {
3638 var marker = markerCreate(),
3639 ident = parseVariableIdentifier(),
3640 isOptionalParam = false;
3641
3642 if (canBeOptionalParam && match('?')) {
3643 expect('?');
3644 isOptionalParam = true;
3645 }
3646
3647 if (requireTypeAnnotation || match(':')) {
3648 ident = markerApply(marker, delegate.createTypeAnnotatedIdentifier(
3649 ident,
3650 parseTypeAnnotation()
3651 ));
3652 }
3653
3654 if (isOptionalParam) {
3655 ident = markerApply(marker, delegate.createOptionalParameter(ident));
3656 }
3657
3658 return ident;
3659 }
3660
3661 function parseVariableDeclaration(kind) {
3662 var id,
3663 marker = markerCreate(),
3664 init = null;
3665 if (match('{')) {
3666 id = parseObjectInitialiser();
3667 reinterpretAsAssignmentBindingPattern(id);
3668 } else if (match('[')) {
3669 id = parseArrayInitialiser();
3670 reinterpretAsAssignmentBindingPattern(id);
3671 } else {
3672 id = state.allowKeyword ? parseNonComputedProperty() : parseTypeAnnotatableIdentifier();
3673 // 12.2.1
3674 if (strict && isRestrictedWord(id.name)) {
3675 throwErrorTolerant({}, Messages.StrictVarName);
3676 }
3677 }
3678
3679 if (kind === 'const') {
3680 if (!match('=')) {
3681 throwError({}, Messages.NoUnintializedConst);
3682 }
3683 expect('=');
3684 init = parseAssignmentExpression();
3685 } else if (match('=')) {
3686 lex();
3687 init = parseAssignmentExpression();
3688 }
3689
3690 return markerApply(marker, delegate.createVariableDeclarator(id, init));
3691 }
3692
3693 function parseVariableDeclarationList(kind) {
3694 var list = [];
3695
3696 do {
3697 list.push(parseVariableDeclaration(kind));
3698 if (!match(',')) {
3699 break;
3700 }
3701 lex();
3702 } while (index < length);
3703
3704 return list;
3705 }
3706
3707 function parseVariableStatement() {
3708 var declarations, marker = markerCreate();
3709
3710 expectKeyword('var');
3711
3712 declarations = parseVariableDeclarationList();
3713
3714 consumeSemicolon();
3715
3716 return markerApply(marker, delegate.createVariableDeclaration(declarations, 'var'));
3717 }
3718
3719 // kind may be `const` or `let`
3720 // Both are experimental and not in the specification yet.
3721 // see http://wiki.ecmascript.org/doku.php?id=harmony:const
3722 // and http://wiki.ecmascript.org/doku.php?id=harmony:let
3723 function parseConstLetDeclaration(kind) {
3724 var declarations, marker = markerCreate();
3725
3726 expectKeyword(kind);
3727
3728 declarations = parseVariableDeclarationList(kind);
3729
3730 consumeSemicolon();
3731
3732 return markerApply(marker, delegate.createVariableDeclaration(declarations, kind));
3733 }
3734
3735 // http://wiki.ecmascript.org/doku.php?id=harmony:modules
3736
3737 function parseModuleDeclaration() {
3738 var id, src, body, marker = markerCreate();
3739
3740 lex(); // 'module'
3741
3742 if (peekLineTerminator()) {
3743 throwError({}, Messages.NewlineAfterModule);
3744 }
3745
3746 switch (lookahead.type) {
3747
3748 case Token.StringLiteral:
3749 id = parsePrimaryExpression();
3750 body = parseModuleBlock();
3751 src = null;
3752 break;
3753
3754 case Token.Identifier:
3755 id = parseVariableIdentifier();
3756 body = null;
3757 if (!matchContextualKeyword('from')) {
3758 throwUnexpected(lex());
3759 }
3760 lex();
3761 src = parsePrimaryExpression();
3762 if (src.type !== Syntax.Literal) {
3763 throwError({}, Messages.InvalidModuleSpecifier);
3764 }
3765 break;
3766 }
3767
3768 consumeSemicolon();
3769 return markerApply(marker, delegate.createModuleDeclaration(id, src, body));
3770 }
3771
3772 function parseExportBatchSpecifier() {
3773 var marker = markerCreate();
3774 expect('*');
3775 return markerApply(marker, delegate.createExportBatchSpecifier());
3776 }
3777
3778 function parseExportSpecifier() {
3779 var id, name = null, marker = markerCreate();
3780
3781 id = parseVariableIdentifier();
3782 if (matchContextualKeyword('as')) {
3783 lex();
3784 name = parseNonComputedProperty();
3785 }
3786
3787 return markerApply(marker, delegate.createExportSpecifier(id, name));
3788 }
3789
3790 function parseExportDeclaration() {
3791 var previousAllowKeyword, decl, def, src, specifiers,
3792 marker = markerCreate();
3793
3794 expectKeyword('export');
3795
3796 if (lookahead.type === Token.Keyword) {
3797 switch (lookahead.value) {
3798 case 'let':
3799 case 'const':
3800 case 'var':
3801 case 'class':
3802 case 'function':
3803 return markerApply(marker, delegate.createExportDeclaration(parseSourceElement(), null, null));
3804 }
3805 }
3806
3807 if (isIdentifierName(lookahead)) {
3808 previousAllowKeyword = state.allowKeyword;
3809 state.allowKeyword = true;
3810 decl = parseVariableDeclarationList('let');
3811 state.allowKeyword = previousAllowKeyword;
3812 return markerApply(marker, delegate.createExportDeclaration(decl, null, null));
3813 }
3814
3815 specifiers = [];
3816 src = null;
3817
3818 if (match('*')) {
3819 specifiers.push(parseExportBatchSpecifier());
3820 } else {
3821 expect('{');
3822 do {
3823 specifiers.push(parseExportSpecifier());
3824 } while (match(',') && lex());
3825 expect('}');
3826 }
3827
3828 if (matchContextualKeyword('from')) {
3829 lex();
3830 src = parsePrimaryExpression();
3831 if (src.type !== Syntax.Literal) {
3832 throwError({}, Messages.InvalidModuleSpecifier);
3833 }
3834 }
3835
3836 consumeSemicolon();
3837
3838 return markerApply(marker, delegate.createExportDeclaration(null, specifiers, src));
3839 }
3840
3841 function parseImportDeclaration() {
3842 var specifiers, kind, src, marker = markerCreate();
3843
3844 expectKeyword('import');
3845 specifiers = [];
3846
3847 if (isIdentifierName(lookahead)) {
3848 kind = 'default';
3849 specifiers.push(parseImportSpecifier());
3850
3851 if (!matchContextualKeyword('from')) {
3852 throwError({}, Messages.NoFromAfterImport);
3853 }
3854 lex();
3855 } else if (match('{')) {
3856 kind = 'named';
3857 lex();
3858 do {
3859 specifiers.push(parseImportSpecifier());
3860 } while (match(',') && lex());
3861 expect('}');
3862
3863 if (!matchContextualKeyword('from')) {
3864 throwError({}, Messages.NoFromAfterImport);
3865 }
3866 lex();
3867 }
3868
3869 src = parsePrimaryExpression();
3870 if (src.type !== Syntax.Literal) {
3871 throwError({}, Messages.InvalidModuleSpecifier);
3872 }
3873
3874 consumeSemicolon();
3875
3876 return markerApply(marker, delegate.createImportDeclaration(specifiers, kind, src));
3877 }
3878
3879 function parseImportSpecifier() {
3880 var id, name = null, marker = markerCreate();
3881
3882 id = parseNonComputedProperty();
3883 if (matchContextualKeyword('as')) {
3884 lex();
3885 name = parseVariableIdentifier();
3886 }
3887
3888 return markerApply(marker, delegate.createImportSpecifier(id, name));
3889 }
3890
3891 // 12.3 Empty Statement
3892
3893 function parseEmptyStatement() {
3894 var marker = markerCreate();
3895 expect(';');
3896 return markerApply(marker, delegate.createEmptyStatement());
3897 }
3898
3899 // 12.4 Expression Statement
3900
3901 function parseExpressionStatement() {
3902 var marker = markerCreate(), expr = parseExpression();
3903 consumeSemicolon();
3904 return markerApply(marker, delegate.createExpressionStatement(expr));
3905 }
3906
3907 // 12.5 If statement
3908
3909 function parseIfStatement() {
3910 var test, consequent, alternate, marker = markerCreate();
3911
3912 expectKeyword('if');
3913
3914 expect('(');
3915
3916 test = parseExpression();
3917
3918 expect(')');
3919
3920 consequent = parseStatement();
3921
3922 if (matchKeyword('else')) {
3923 lex();
3924 alternate = parseStatement();
3925 } else {
3926 alternate = null;
3927 }
3928
3929 return markerApply(marker, delegate.createIfStatement(test, consequent, alternate));
3930 }
3931
3932 // 12.6 Iteration Statements
3933
3934 function parseDoWhileStatement() {
3935 var body, test, oldInIteration, marker = markerCreate();
3936
3937 expectKeyword('do');
3938
3939 oldInIteration = state.inIteration;
3940 state.inIteration = true;
3941
3942 body = parseStatement();
3943
3944 state.inIteration = oldInIteration;
3945
3946 expectKeyword('while');
3947
3948 expect('(');
3949
3950 test = parseExpression();
3951
3952 expect(')');
3953
3954 if (match(';')) {
3955 lex();
3956 }
3957
3958 return markerApply(marker, delegate.createDoWhileStatement(body, test));
3959 }
3960
3961 function parseWhileStatement() {
3962 var test, body, oldInIteration, marker = markerCreate();
3963
3964 expectKeyword('while');
3965
3966 expect('(');
3967
3968 test = parseExpression();
3969
3970 expect(')');
3971
3972 oldInIteration = state.inIteration;
3973 state.inIteration = true;
3974
3975 body = parseStatement();
3976
3977 state.inIteration = oldInIteration;
3978
3979 return markerApply(marker, delegate.createWhileStatement(test, body));
3980 }
3981
3982 function parseForVariableDeclaration() {
3983 var marker = markerCreate(),
3984 token = lex(),
3985 declarations = parseVariableDeclarationList();
3986
3987 return markerApply(marker, delegate.createVariableDeclaration(declarations, token.value));
3988 }
3989
3990 function parseForStatement(opts) {
3991 var init, test, update, left, right, body, operator, oldInIteration,
3992 marker = markerCreate();
3993 init = test = update = null;
3994 expectKeyword('for');
3995
3996 // http://wiki.ecmascript.org/doku.php?id=proposals:iterators_and_generators&s=each
3997 if (matchContextualKeyword('each')) {
3998 throwError({}, Messages.EachNotAllowed);
3999 }
4000
4001 expect('(');
4002
4003 if (match(';')) {
4004 lex();
4005 } else {
4006 if (matchKeyword('var') || matchKeyword('let') || matchKeyword('const')) {
4007 state.allowIn = false;
4008 init = parseForVariableDeclaration();
4009 state.allowIn = true;
4010
4011 if (init.declarations.length === 1) {
4012 if (matchKeyword('in') || matchContextualKeyword('of')) {
4013 operator = lookahead;
4014 if (!((operator.value === 'in' || init.kind !== 'var') && init.declarations[0].init)) {
4015 lex();
4016 left = init;
4017 right = parseExpression();
4018 init = null;
4019 }
4020 }
4021 }
4022 } else {
4023 state.allowIn = false;
4024 init = parseExpression();
4025 state.allowIn = true;
4026
4027 if (matchContextualKeyword('of')) {
4028 operator = lex();
4029 left = init;
4030 right = parseExpression();
4031 init = null;
4032 } else if (matchKeyword('in')) {
4033 // LeftHandSideExpression
4034 if (!isAssignableLeftHandSide(init)) {
4035 throwError({}, Messages.InvalidLHSInForIn);
4036 }
4037 operator = lex();
4038 left = init;
4039 right = parseExpression();
4040 init = null;
4041 }
4042 }
4043
4044 if (typeof left === 'undefined') {
4045 expect(';');
4046 }
4047 }
4048
4049 if (typeof left === 'undefined') {
4050
4051 if (!match(';')) {
4052 test = parseExpression();
4053 }
4054 expect(';');
4055
4056 if (!match(')')) {
4057 update = parseExpression();
4058 }
4059 }
4060
4061 expect(')');
4062
4063 oldInIteration = state.inIteration;
4064 state.inIteration = true;
4065
4066 if (!(opts !== undefined && opts.ignoreBody)) {
4067 body = parseStatement();
4068 }
4069
4070 state.inIteration = oldInIteration;
4071
4072 if (typeof left === 'undefined') {
4073 return markerApply(marker, delegate.createForStatement(init, test, update, body));
4074 }
4075
4076 if (operator.value === 'in') {
4077 return markerApply(marker, delegate.createForInStatement(left, right, body));
4078 }
4079 return markerApply(marker, delegate.createForOfStatement(left, right, body));
4080 }
4081
4082 // 12.7 The continue statement
4083
4084 function parseContinueStatement() {
4085 var label = null, key, marker = markerCreate();
4086
4087 expectKeyword('continue');
4088
4089 // Optimize the most common form: 'continue;'.
4090 if (source.charCodeAt(index) === 59) {
4091 lex();
4092
4093 if (!state.inIteration) {
4094 throwError({}, Messages.IllegalContinue);
4095 }
4096
4097 return markerApply(marker, delegate.createContinueStatement(null));
4098 }
4099
4100 if (peekLineTerminator()) {
4101 if (!state.inIteration) {
4102 throwError({}, Messages.IllegalContinue);
4103 }
4104
4105 return markerApply(marker, delegate.createContinueStatement(null));
4106 }
4107
4108 if (lookahead.type === Token.Identifier) {
4109 label = parseVariableIdentifier();
4110
4111 key = '$' + label.name;
4112 if (!Object.prototype.hasOwnProperty.call(state.labelSet, key)) {
4113 throwError({}, Messages.UnknownLabel, label.name);
4114 }
4115 }
4116
4117 consumeSemicolon();
4118
4119 if (label === null && !state.inIteration) {
4120 throwError({}, Messages.IllegalContinue);
4121 }
4122
4123 return markerApply(marker, delegate.createContinueStatement(label));
4124 }
4125
4126 // 12.8 The break statement
4127
4128 function parseBreakStatement() {
4129 var label = null, key, marker = markerCreate();
4130
4131 expectKeyword('break');
4132
4133 // Catch the very common case first: immediately a semicolon (char #59).
4134 if (source.charCodeAt(index) === 59) {
4135 lex();
4136
4137 if (!(state.inIteration || state.inSwitch)) {
4138 throwError({}, Messages.IllegalBreak);
4139 }
4140
4141 return markerApply(marker, delegate.createBreakStatement(null));
4142 }
4143
4144 if (peekLineTerminator()) {
4145 if (!(state.inIteration || state.inSwitch)) {
4146 throwError({}, Messages.IllegalBreak);
4147 }
4148
4149 return markerApply(marker, delegate.createBreakStatement(null));
4150 }
4151
4152 if (lookahead.type === Token.Identifier) {
4153 label = parseVariableIdentifier();
4154
4155 key = '$' + label.name;
4156 if (!Object.prototype.hasOwnProperty.call(state.labelSet, key)) {
4157 throwError({}, Messages.UnknownLabel, label.name);
4158 }
4159 }
4160
4161 consumeSemicolon();
4162
4163 if (label === null && !(state.inIteration || state.inSwitch)) {
4164 throwError({}, Messages.IllegalBreak);
4165 }
4166
4167 return markerApply(marker, delegate.createBreakStatement(label));
4168 }
4169
4170 // 12.9 The return statement
4171
4172 function parseReturnStatement() {
4173 var argument = null, marker = markerCreate();
4174
4175 expectKeyword('return');
4176
4177 if (!state.inFunctionBody) {
4178 throwErrorTolerant({}, Messages.IllegalReturn);
4179 }
4180
4181 // 'return' followed by a space and an identifier is very common.
4182 if (source.charCodeAt(index) === 32) {
4183 if (isIdentifierStart(source.charCodeAt(index + 1))) {
4184 argument = parseExpression();
4185 consumeSemicolon();
4186 return markerApply(marker, delegate.createReturnStatement(argument));
4187 }
4188 }
4189
4190 if (peekLineTerminator()) {
4191 return markerApply(marker, delegate.createReturnStatement(null));
4192 }
4193
4194 if (!match(';')) {
4195 if (!match('}') && lookahead.type !== Token.EOF) {
4196 argument = parseExpression();
4197 }
4198 }
4199
4200 consumeSemicolon();
4201
4202 return markerApply(marker, delegate.createReturnStatement(argument));
4203 }
4204
4205 // 12.10 The with statement
4206
4207 function parseWithStatement() {
4208 var object, body, marker = markerCreate();
4209
4210 if (strict) {
4211 throwErrorTolerant({}, Messages.StrictModeWith);
4212 }
4213
4214 expectKeyword('with');
4215
4216 expect('(');
4217
4218 object = parseExpression();
4219
4220 expect(')');
4221
4222 body = parseStatement();
4223
4224 return markerApply(marker, delegate.createWithStatement(object, body));
4225 }
4226
4227 // 12.10 The swith statement
4228
4229 function parseSwitchCase() {
4230 var test,
4231 consequent = [],
4232 sourceElement,
4233 marker = markerCreate();
4234
4235 if (matchKeyword('default')) {
4236 lex();
4237 test = null;
4238 } else {
4239 expectKeyword('case');
4240 test = parseExpression();
4241 }
4242 expect(':');
4243
4244 while (index < length) {
4245 if (match('}') || matchKeyword('default') || matchKeyword('case')) {
4246 break;
4247 }
4248 sourceElement = parseSourceElement();
4249 if (typeof sourceElement === 'undefined') {
4250 break;
4251 }
4252 consequent.push(sourceElement);
4253 }
4254
4255 return markerApply(marker, delegate.createSwitchCase(test, consequent));
4256 }
4257
4258 function parseSwitchStatement() {
4259 var discriminant, cases, clause, oldInSwitch, defaultFound, marker = markerCreate();
4260
4261 expectKeyword('switch');
4262
4263 expect('(');
4264
4265 discriminant = parseExpression();
4266
4267 expect(')');
4268
4269 expect('{');
4270
4271 cases = [];
4272
4273 if (match('}')) {
4274 lex();
4275 return markerApply(marker, delegate.createSwitchStatement(discriminant, cases));
4276 }
4277
4278 oldInSwitch = state.inSwitch;
4279 state.inSwitch = true;
4280 defaultFound = false;
4281
4282 while (index < length) {
4283 if (match('}')) {
4284 break;
4285 }
4286 clause = parseSwitchCase();
4287 if (clause.test === null) {
4288 if (defaultFound) {
4289 throwError({}, Messages.MultipleDefaultsInSwitch);
4290 }
4291 defaultFound = true;
4292 }
4293 cases.push(clause);
4294 }
4295
4296 state.inSwitch = oldInSwitch;
4297
4298 expect('}');
4299
4300 return markerApply(marker, delegate.createSwitchStatement(discriminant, cases));
4301 }
4302
4303 // 12.13 The throw statement
4304
4305 function parseThrowStatement() {
4306 var argument, marker = markerCreate();
4307
4308 expectKeyword('throw');
4309
4310 if (peekLineTerminator()) {
4311 throwError({}, Messages.NewlineAfterThrow);
4312 }
4313
4314 argument = parseExpression();
4315
4316 consumeSemicolon();
4317
4318 return markerApply(marker, delegate.createThrowStatement(argument));
4319 }
4320
4321 // 12.14 The try statement
4322
4323 function parseCatchClause() {
4324 var param, body, marker = markerCreate();
4325
4326 expectKeyword('catch');
4327
4328 expect('(');
4329 if (match(')')) {
4330 throwUnexpected(lookahead);
4331 }
4332
4333 param = parseExpression();
4334 // 12.14.1
4335 if (strict && param.type === Syntax.Identifier && isRestrictedWord(param.name)) {
4336 throwErrorTolerant({}, Messages.StrictCatchVariable);
4337 }
4338
4339 expect(')');
4340 body = parseBlock();
4341 return markerApply(marker, delegate.createCatchClause(param, body));
4342 }
4343
4344 function parseTryStatement() {
4345 var block, handlers = [], finalizer = null, marker = markerCreate();
4346
4347 expectKeyword('try');
4348
4349 block = parseBlock();
4350
4351 if (matchKeyword('catch')) {
4352 handlers.push(parseCatchClause());
4353 }
4354
4355 if (matchKeyword('finally')) {
4356 lex();
4357 finalizer = parseBlock();
4358 }
4359
4360 if (handlers.length === 0 && !finalizer) {
4361 throwError({}, Messages.NoCatchOrFinally);
4362 }
4363
4364 return markerApply(marker, delegate.createTryStatement(block, [], handlers, finalizer));
4365 }
4366
4367 // 12.15 The debugger statement
4368
4369 function parseDebuggerStatement() {
4370 var marker = markerCreate();
4371 expectKeyword('debugger');
4372
4373 consumeSemicolon();
4374
4375 return markerApply(marker, delegate.createDebuggerStatement());
4376 }
4377
4378 // 12 Statements
4379
4380 function parseStatement() {
4381 var type = lookahead.type,
4382 marker,
4383 expr,
4384 labeledBody,
4385 key;
4386
4387 if (type === Token.EOF) {
4388 throwUnexpected(lookahead);
4389 }
4390
4391 if (type === Token.Punctuator) {
4392 switch (lookahead.value) {
4393 case ';':
4394 return parseEmptyStatement();
4395 case '{':
4396 return parseBlock();
4397 case '(':
4398 return parseExpressionStatement();
4399 default:
4400 break;
4401 }
4402 }
4403
4404 if (type === Token.Keyword) {
4405 switch (lookahead.value) {
4406 case 'break':
4407 return parseBreakStatement();
4408 case 'continue':
4409 return parseContinueStatement();
4410 case 'debugger':
4411 return parseDebuggerStatement();
4412 case 'do':
4413 return parseDoWhileStatement();
4414 case 'for':
4415 return parseForStatement();
4416 case 'function':
4417 return parseFunctionDeclaration();
4418 case 'class':
4419 return parseClassDeclaration();
4420 case 'if':
4421 return parseIfStatement();
4422 case 'return':
4423 return parseReturnStatement();
4424 case 'switch':
4425 return parseSwitchStatement();
4426 case 'throw':
4427 return parseThrowStatement();
4428 case 'try':
4429 return parseTryStatement();
4430 case 'var':
4431 return parseVariableStatement();
4432 case 'while':
4433 return parseWhileStatement();
4434 case 'with':
4435 return parseWithStatement();
4436 default:
4437 break;
4438 }
4439 }
4440
4441 marker = markerCreate();
4442 expr = parseExpression();
4443
4444 // 12.12 Labelled Statements
4445 if ((expr.type === Syntax.Identifier) && match(':')) {
4446 lex();
4447
4448 key = '$' + expr.name;
4449 if (Object.prototype.hasOwnProperty.call(state.labelSet, key)) {
4450 throwError({}, Messages.Redeclaration, 'Label', expr.name);
4451 }
4452
4453 state.labelSet[key] = true;
4454 labeledBody = parseStatement();
4455 delete state.labelSet[key];
4456 return markerApply(marker, delegate.createLabeledStatement(expr, labeledBody));
4457 }
4458
4459 consumeSemicolon();
4460
4461 return markerApply(marker, delegate.createExpressionStatement(expr));
4462 }
4463
4464 // 13 Function Definition
4465
4466 function parseConciseBody() {
4467 if (match('{')) {
4468 return parseFunctionSourceElements();
4469 }
4470 return parseAssignmentExpression();
4471 }
4472
4473 function parseFunctionSourceElements() {
4474 var sourceElement, sourceElements = [], token, directive, firstRestricted,
4475 oldLabelSet, oldInIteration, oldInSwitch, oldInFunctionBody, oldParenthesizedCount,
4476 marker = markerCreate();
4477
4478 expect('{');
4479
4480 while (index < length) {
4481 if (lookahead.type !== Token.StringLiteral) {
4482 break;
4483 }
4484 token = lookahead;
4485
4486 sourceElement = parseSourceElement();
4487 sourceElements.push(sourceElement);
4488 if (sourceElement.expression.type !== Syntax.Literal) {
4489 // this is not directive
4490 break;
4491 }
4492 directive = source.slice(token.range[0] + 1, token.range[1] - 1);
4493 if (directive === 'use strict') {
4494 strict = true;
4495 if (firstRestricted) {
4496 throwErrorTolerant(firstRestricted, Messages.StrictOctalLiteral);
4497 }
4498 } else {
4499 if (!firstRestricted && token.octal) {
4500 firstRestricted = token;
4501 }
4502 }
4503 }
4504
4505 oldLabelSet = state.labelSet;
4506 oldInIteration = state.inIteration;
4507 oldInSwitch = state.inSwitch;
4508 oldInFunctionBody = state.inFunctionBody;
4509 oldParenthesizedCount = state.parenthesizedCount;
4510
4511 state.labelSet = {};
4512 state.inIteration = false;
4513 state.inSwitch = false;
4514 state.inFunctionBody = true;
4515 state.parenthesizedCount = 0;
4516
4517 while (index < length) {
4518 if (match('}')) {
4519 break;
4520 }
4521 sourceElement = parseSourceElement();
4522 if (typeof sourceElement === 'undefined') {
4523 break;
4524 }
4525 sourceElements.push(sourceElement);
4526 }
4527
4528 expect('}');
4529
4530 state.labelSet = oldLabelSet;
4531 state.inIteration = oldInIteration;
4532 state.inSwitch = oldInSwitch;
4533 state.inFunctionBody = oldInFunctionBody;
4534 state.parenthesizedCount = oldParenthesizedCount;
4535
4536 return markerApply(marker, delegate.createBlockStatement(sourceElements));
4537 }
4538
4539 function validateParam(options, param, name) {
4540 var key = '$' + name;
4541 if (strict) {
4542 if (isRestrictedWord(name)) {
4543 options.stricted = param;
4544 options.message = Messages.StrictParamName;
4545 }
4546 if (Object.prototype.hasOwnProperty.call(options.paramSet, key)) {
4547 options.stricted = param;
4548 options.message = Messages.StrictParamDupe;
4549 }
4550 } else if (!options.firstRestricted) {
4551 if (isRestrictedWord(name)) {
4552 options.firstRestricted = param;
4553 options.message = Messages.StrictParamName;
4554 } else if (isStrictModeReservedWord(name)) {
4555 options.firstRestricted = param;
4556 options.message = Messages.StrictReservedWord;
4557 } else if (Object.prototype.hasOwnProperty.call(options.paramSet, key)) {
4558 options.firstRestricted = param;
4559 options.message = Messages.StrictParamDupe;
4560 }
4561 }
4562 options.paramSet[key] = true;
4563 }
4564
4565 function parseParam(options) {
4566 var token, rest, param, def;
4567
4568 token = lookahead;
4569 if (token.value === '...') {
4570 token = lex();
4571 rest = true;
4572 }
4573
4574 if (match('[')) {
4575 param = parseArrayInitialiser();
4576 reinterpretAsDestructuredParameter(options, param);
4577 } else if (match('{')) {
4578 if (rest) {
4579 throwError({}, Messages.ObjectPatternAsRestParameter);
4580 }
4581 param = parseObjectInitialiser();
4582 reinterpretAsDestructuredParameter(options, param);
4583 } else {
4584 // Typing rest params is awkward, so punting on that for now
4585 param =
4586 rest
4587 ? parseVariableIdentifier()
4588 : parseTypeAnnotatableIdentifier(
4589 false, /* requireTypeAnnotation */
4590 true /* canBeOptionalParam */
4591 );
4592
4593 validateParam(options, token, token.value);
4594 }
4595
4596 if (match('=')) {
4597 if (rest) {
4598 throwErrorTolerant(lookahead, Messages.DefaultRestParameter);
4599 }
4600 lex();
4601 def = parseAssignmentExpression();
4602 ++options.defaultCount;
4603 }
4604
4605 if (rest) {
4606 if (!match(')')) {
4607 throwError({}, Messages.ParameterAfterRestParameter);
4608 }
4609 options.rest = param;
4610 return false;
4611 }
4612
4613 options.params.push(param);
4614 options.defaults.push(def);
4615 return !match(')');
4616 }
4617
4618 function parseParams(firstRestricted) {
4619 var options, marker = markerCreate();
4620
4621 options = {
4622 params: [],
4623 defaultCount: 0,
4624 defaults: [],
4625 rest: null,
4626 firstRestricted: firstRestricted
4627 };
4628
4629 expect('(');
4630
4631 if (!match(')')) {
4632 options.paramSet = {};
4633 while (index < length) {
4634 if (!parseParam(options)) {
4635 break;
4636 }
4637 expect(',');
4638 }
4639 }
4640
4641 expect(')');
4642
4643 if (options.defaultCount === 0) {
4644 options.defaults = [];
4645 }
4646
4647 if (match(':')) {
4648 options.returnType = parseTypeAnnotation();
4649 }
4650
4651 return markerApply(marker, options);
4652 }
4653
4654 function parseFunctionDeclaration() {
4655 var id, body, token, tmp, firstRestricted, message, previousStrict, previousYieldAllowed, generator,
4656 marker = markerCreate(), parametricType;
4657
4658 expectKeyword('function');
4659
4660 generator = false;
4661 if (match('*')) {
4662 lex();
4663 generator = true;
4664 }
4665
4666 token = lookahead;
4667
4668 id = parseVariableIdentifier();
4669
4670 if (match('<')) {
4671 parametricType = parseParametricTypeAnnotation();
4672 }
4673
4674 if (strict) {
4675 if (isRestrictedWord(token.value)) {
4676 throwErrorTolerant(token, Messages.StrictFunctionName);
4677 }
4678 } else {
4679 if (isRestrictedWord(token.value)) {
4680 firstRestricted = token;
4681 message = Messages.StrictFunctionName;
4682 } else if (isStrictModeReservedWord(token.value)) {
4683 firstRestricted = token;
4684 message = Messages.StrictReservedWord;
4685 }
4686 }
4687
4688 tmp = parseParams(firstRestricted);
4689 firstRestricted = tmp.firstRestricted;
4690 if (tmp.message) {
4691 message = tmp.message;
4692 }
4693
4694 previousStrict = strict;
4695 previousYieldAllowed = state.yieldAllowed;
4696 state.yieldAllowed = generator;
4697
4698 body = parseFunctionSourceElements();
4699
4700 if (strict && firstRestricted) {
4701 throwError(firstRestricted, message);
4702 }
4703 if (strict && tmp.stricted) {
4704 throwErrorTolerant(tmp.stricted, message);
4705 }
4706 strict = previousStrict;
4707 state.yieldAllowed = previousYieldAllowed;
4708
4709 return markerApply(marker, delegate.createFunctionDeclaration(id, tmp.params, tmp.defaults, body, tmp.rest, generator, false,
4710 tmp.returnType, parametricType));
4711 }
4712
4713 function parseFunctionExpression() {
4714 var token, id = null, firstRestricted, message, tmp, body, previousStrict, previousYieldAllowed, generator,
4715 marker = markerCreate(), parametricType;
4716
4717 expectKeyword('function');
4718
4719 generator = false;
4720
4721 if (match('*')) {
4722 lex();
4723 generator = true;
4724 }
4725
4726 if (!match('(')) {
4727 if (!match('<')) {
4728 token = lookahead;
4729 id = parseVariableIdentifier();
4730
4731 if (strict) {
4732 if (isRestrictedWord(token.value)) {
4733 throwErrorTolerant(token, Messages.StrictFunctionName);
4734 }
4735 } else {
4736 if (isRestrictedWord(token.value)) {
4737 firstRestricted = token;
4738 message = Messages.StrictFunctionName;
4739 } else if (isStrictModeReservedWord(token.value)) {
4740 firstRestricted = token;
4741 message = Messages.StrictReservedWord;
4742 }
4743 }
4744 }
4745
4746 if (match('<')) {
4747 parametricType = parseParametricTypeAnnotation();
4748 }
4749 }
4750
4751 tmp = parseParams(firstRestricted);
4752 firstRestricted = tmp.firstRestricted;
4753 if (tmp.message) {
4754 message = tmp.message;
4755 }
4756
4757 previousStrict = strict;
4758 previousYieldAllowed = state.yieldAllowed;
4759 state.yieldAllowed = generator;
4760
4761 body = parseFunctionSourceElements();
4762
4763 if (strict && firstRestricted) {
4764 throwError(firstRestricted, message);
4765 }
4766 if (strict && tmp.stricted) {
4767 throwErrorTolerant(tmp.stricted, message);
4768 }
4769 strict = previousStrict;
4770 state.yieldAllowed = previousYieldAllowed;
4771
4772 return markerApply(marker, delegate.createFunctionExpression(id, tmp.params, tmp.defaults, body, tmp.rest, generator, false,
4773 tmp.returnType, parametricType));
4774 }
4775
4776 function parseYieldExpression() {
4777 var yieldToken, delegateFlag, expr, marker = markerCreate();
4778
4779 yieldToken = lex();
4780 assert(yieldToken.value === 'yield', 'Called parseYieldExpression with non-yield lookahead.');
4781
4782 if (!state.yieldAllowed) {
4783 throwErrorTolerant({}, Messages.IllegalYield);
4784 }
4785
4786 delegateFlag = false;
4787 if (match('*')) {
4788 lex();
4789 delegateFlag = true;
4790 }
4791
4792 expr = parseAssignmentExpression();
4793
4794 return markerApply(marker, delegate.createYieldExpression(expr, delegateFlag));
4795 }
4796
4797 // 14 Classes
4798
4799 function parseMethodDefinition(existingPropNames) {
4800 var token, key, param, propType, isValidDuplicateProp = false,
4801 marker = markerCreate(), token2, parametricType,
4802 parametricTypeMarker, annotationMarker;
4803
4804 if (lookahead.value === 'static') {
4805 propType = ClassPropertyType.static;
4806 lex();
4807 } else {
4808 propType = ClassPropertyType.prototype;
4809 }
4810
4811 if (match('*')) {
4812 lex();
4813 return markerApply(marker, delegate.createMethodDefinition(
4814 propType,
4815 '',
4816 parseObjectPropertyKey(),
4817 parsePropertyMethodFunction({ generator: true })
4818 ));
4819 }
4820
4821 token = lookahead;
4822 //parametricTypeMarker = markerCreate();
4823 key = parseObjectPropertyKey();
4824
4825 if (token.value === 'get' && !match('(')) {
4826 key = parseObjectPropertyKey();
4827
4828 // It is a syntax error if any other properties have a name
4829 // duplicating this one unless they are a setter
4830 if (existingPropNames[propType].hasOwnProperty(key.name)) {
4831 isValidDuplicateProp =
4832 // There isn't already a getter for this prop
4833 existingPropNames[propType][key.name].get === undefined
4834 // There isn't already a data prop by this name
4835 && existingPropNames[propType][key.name].data === undefined
4836 // The only existing prop by this name is a setter
4837 && existingPropNames[propType][key.name].set !== undefined;
4838 if (!isValidDuplicateProp) {
4839 throwError(key, Messages.IllegalDuplicateClassProperty);
4840 }
4841 } else {
4842 existingPropNames[propType][key.name] = {};
4843 }
4844 existingPropNames[propType][key.name].get = true;
4845
4846 expect('(');
4847 expect(')');
4848 return markerApply(marker, delegate.createMethodDefinition(
4849 propType,
4850 'get',
4851 key,
4852 parsePropertyFunction({ generator: false })
4853 ));
4854 }
4855 if (token.value === 'set' && !match('(')) {
4856 key = parseObjectPropertyKey();
4857
4858 // It is a syntax error if any other properties have a name
4859 // duplicating this one unless they are a getter
4860 if (existingPropNames[propType].hasOwnProperty(key.name)) {
4861 isValidDuplicateProp =
4862 // There isn't already a setter for this prop
4863 existingPropNames[propType][key.name].set === undefined
4864 // There isn't already a data prop by this name
4865 && existingPropNames[propType][key.name].data === undefined
4866 // The only existing prop by this name is a getter
4867 && existingPropNames[propType][key.name].get !== undefined;
4868 if (!isValidDuplicateProp) {
4869 throwError(key, Messages.IllegalDuplicateClassProperty);
4870 }
4871 } else {
4872 existingPropNames[propType][key.name] = {};
4873 }
4874 existingPropNames[propType][key.name].set = true;
4875
4876 expect('(');
4877 token = lookahead;
4878 param = [ parseTypeAnnotatableIdentifier() ];
4879 expect(')');
4880 return markerApply(marker, delegate.createMethodDefinition(
4881 propType,
4882 'set',
4883 key,
4884 parsePropertyFunction({ params: param, generator: false, name: token })
4885 ));
4886 }
4887
4888 if (match('<')) {
4889 parametricType = parseParametricTypeAnnotation();
4890 }
4891
4892 // It is a syntax error if any other properties have the same name as a
4893 // non-getter, non-setter method
4894 if (existingPropNames[propType].hasOwnProperty(key.name)) {
4895 throwError(key, Messages.IllegalDuplicateClassProperty);
4896 } else {
4897 existingPropNames[propType][key.name] = {};
4898 }
4899 existingPropNames[propType][key.name].data = true;
4900
4901 return markerApply(marker, delegate.createMethodDefinition(
4902 propType,
4903 '',
4904 key,
4905 parsePropertyMethodFunction({
4906 generator: false,
4907 parametricType: parametricType
4908 })
4909 ));
4910 }
4911
4912 function parseClassProperty(existingPropNames) {
4913 var marker = markerCreate(), propertyIdentifier;
4914
4915 propertyIdentifier = parseTypeAnnotatableIdentifier();
4916 expect(';');
4917
4918 return markerApply(marker, delegate.createClassProperty(
4919 propertyIdentifier
4920 ));
4921 }
4922
4923 function parseClassElement(existingProps) {
4924 if (match(';')) {
4925 lex();
4926 return;
4927 }
4928
4929 var doubleLookahead = lookahead2();
4930 if (doubleLookahead.type === Token.Punctuator) {
4931 if (doubleLookahead.value === ':') {
4932 return parseClassProperty(existingProps);
4933 }
4934 }
4935
4936 return parseMethodDefinition(existingProps);
4937 }
4938
4939 function parseClassBody() {
4940 var classElement, classElements = [], existingProps = {}, marker = markerCreate();
4941
4942 existingProps[ClassPropertyType.static] = {};
4943 existingProps[ClassPropertyType.prototype] = {};
4944
4945 expect('{');
4946
4947 while (index < length) {
4948 if (match('}')) {
4949 break;
4950 }
4951 classElement = parseClassElement(existingProps);
4952
4953 if (typeof classElement !== 'undefined') {
4954 classElements.push(classElement);
4955 }
4956 }
4957
4958 expect('}');
4959
4960 return markerApply(marker, delegate.createClassBody(classElements));
4961 }
4962
4963 function parseClassExpression() {
4964 var id, previousYieldAllowed, superClass = null, marker = markerCreate(),
4965 parametricType;
4966
4967 expectKeyword('class');
4968
4969 if (!matchKeyword('extends') && !match('{')) {
4970 id = parseVariableIdentifier();
4971 }
4972
4973 if (match('<')) {
4974 parametricType = parseParametricTypeAnnotation();
4975 }
4976
4977 if (matchKeyword('extends')) {
4978 expectKeyword('extends');
4979 previousYieldAllowed = state.yieldAllowed;
4980 state.yieldAllowed = false;
4981 superClass = parseAssignmentExpression();
4982 state.yieldAllowed = previousYieldAllowed;
4983 }
4984
4985 return markerApply(marker, delegate.createClassExpression(id, superClass, parseClassBody(), parametricType));
4986 }
4987
4988 function parseClassDeclaration() {
4989 var id, previousYieldAllowed, superClass = null, marker = markerCreate(),
4990 parametricType, superParametricType;
4991
4992 expectKeyword('class');
4993
4994 id = parseVariableIdentifier();
4995
4996 if (match('<')) {
4997 parametricType = parseParametricTypeAnnotation();
4998 }
4999
5000 if (matchKeyword('extends')) {
5001 expectKeyword('extends');
5002 previousYieldAllowed = state.yieldAllowed;
5003 state.yieldAllowed = false;
5004 superClass = parseAssignmentExpression();
5005 state.yieldAllowed = previousYieldAllowed;
5006 }
5007
5008 return markerApply(marker, delegate.createClassDeclaration(id, superClass, parseClassBody(), parametricType, superParametricType));
5009 }
5010
5011 // 15 Program
5012
5013 function matchModuleDeclaration() {
5014 var id;
5015 if (matchContextualKeyword('module')) {
5016 id = lookahead2();
5017 return id.type === Token.StringLiteral || id.type === Token.Identifier;
5018 }
5019 return false;
5020 }
5021
5022 function parseSourceElement() {
5023 if (lookahead.type === Token.Keyword) {
5024 switch (lookahead.value) {
5025 case 'const':
5026 case 'let':
5027 return parseConstLetDeclaration(lookahead.value);
5028 case 'function':
5029 return parseFunctionDeclaration();
5030 case 'export':
5031 return parseExportDeclaration();
5032 case 'import':
5033 return parseImportDeclaration();
5034 default:
5035 return parseStatement();
5036 }
5037 }
5038
5039 if (matchModuleDeclaration()) {
5040 throwError({}, Messages.NestedModule);
5041 }
5042
5043 if (lookahead.type !== Token.EOF) {
5044 return parseStatement();
5045 }
5046 }
5047
5048 function parseProgramElement() {
5049 if (lookahead.type === Token.Keyword) {
5050 switch (lookahead.value) {
5051 case 'export':
5052 return parseExportDeclaration();
5053 case 'import':
5054 return parseImportDeclaration();
5055 }
5056 }
5057
5058 if (matchModuleDeclaration()) {
5059 return parseModuleDeclaration();
5060 }
5061
5062 return parseSourceElement();
5063 }
5064
5065 function parseProgramElements() {
5066 var sourceElement, sourceElements = [], token, directive, firstRestricted;
5067
5068 while (index < length) {
5069 token = lookahead;
5070 if (token.type !== Token.StringLiteral) {
5071 break;
5072 }
5073
5074 sourceElement = parseProgramElement();
5075 sourceElements.push(sourceElement);
5076 if (sourceElement.expression.type !== Syntax.Literal) {
5077 // this is not directive
5078 break;
5079 }
5080 directive = source.slice(token.range[0] + 1, token.range[1] - 1);
5081 if (directive === 'use strict') {
5082 strict = true;
5083 if (firstRestricted) {
5084 throwErrorTolerant(firstRestricted, Messages.StrictOctalLiteral);
5085 }
5086 } else {
5087 if (!firstRestricted && token.octal) {
5088 firstRestricted = token;
5089 }
5090 }
5091 }
5092
5093 while (index < length) {
5094 sourceElement = parseProgramElement();
5095 if (typeof sourceElement === 'undefined') {
5096 break;
5097 }
5098 sourceElements.push(sourceElement);
5099 }
5100 return sourceElements;
5101 }
5102
5103 function parseModuleElement() {
5104 return parseSourceElement();
5105 }
5106
5107 function parseModuleElements() {
5108 var list = [],
5109 statement;
5110
5111 while (index < length) {
5112 if (match('}')) {
5113 break;
5114 }
5115 statement = parseModuleElement();
5116 if (typeof statement === 'undefined') {
5117 break;
5118 }
5119 list.push(statement);
5120 }
5121
5122 return list;
5123 }
5124
5125 function parseModuleBlock() {
5126 var block, marker = markerCreate();
5127
5128 expect('{');
5129
5130 block = parseModuleElements();
5131
5132 expect('}');
5133
5134 return markerApply(marker, delegate.createBlockStatement(block));
5135 }
5136
5137 function parseProgram() {
5138 var body, marker = markerCreate();
5139 strict = false;
5140 peek();
5141 body = parseProgramElements();
5142 return markerApply(marker, delegate.createProgram(body));
5143 }
5144
5145 // The following functions are needed only when the option to preserve
5146 // the comments is active.
5147
5148 function addComment(type, value, start, end, loc) {
5149 var comment;
5150
5151 assert(typeof start === 'number', 'Comment must have valid position');
5152
5153 // Because the way the actual token is scanned, often the comments
5154 // (if any) are skipped twice during the lexical analysis.
5155 // Thus, we need to skip adding a comment if the comment array already
5156 // handled it.
5157 if (state.lastCommentStart >= start) {
5158 return;
5159 }
5160 state.lastCommentStart = start;
5161
5162 comment = {
5163 type: type,
5164 value: value
5165 };
5166 if (extra.range) {
5167 comment.range = [start, end];
5168 }
5169 if (extra.loc) {
5170 comment.loc = loc;
5171 }
5172 extra.comments.push(comment);
5173 }
5174
5175 function scanComment() {
5176 var comment, ch, loc, start, blockComment, lineComment;
5177
5178 comment = '';
5179 blockComment = false;
5180 lineComment = false;
5181
5182 while (index < length) {
5183 ch = source[index];
5184
5185 if (lineComment) {
5186 ch = source[index++];
5187 if (isLineTerminator(ch.charCodeAt(0))) {
5188 loc.end = {
5189 line: lineNumber,
5190 column: index - lineStart - 1
5191 };
5192 lineComment = false;
5193 addComment('Line', comment, start, index - 1, loc);
5194 if (ch === '\r' && source[index] === '\n') {
5195 ++index;
5196 }
5197 ++lineNumber;
5198 lineStart = index;
5199 comment = '';
5200 } else if (index >= length) {
5201 lineComment = false;
5202 comment += ch;
5203 loc.end = {
5204 line: lineNumber,
5205 column: length - lineStart
5206 };
5207 addComment('Line', comment, start, length, loc);
5208 } else {
5209 comment += ch;
5210 }
5211 } else if (blockComment) {
5212 if (isLineTerminator(ch.charCodeAt(0))) {
5213 if (ch === '\r' && source[index + 1] === '\n') {
5214 ++index;
5215 comment += '\r\n';
5216 } else {
5217 comment += ch;
5218 }
5219 ++lineNumber;
5220 ++index;
5221 lineStart = index;
5222 if (index >= length) {
5223 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
5224 }
5225 } else {
5226 ch = source[index++];
5227 if (index >= length) {
5228 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
5229 }
5230 comment += ch;
5231 if (ch === '*') {
5232 ch = source[index];
5233 if (ch === '/') {
5234 comment = comment.substr(0, comment.length - 1);
5235 blockComment = false;
5236 ++index;
5237 loc.end = {
5238 line: lineNumber,
5239 column: index - lineStart
5240 };
5241 addComment('Block', comment, start, index, loc);
5242 comment = '';
5243 }
5244 }
5245 }
5246 } else if (ch === '/') {
5247 ch = source[index + 1];
5248 if (ch === '/') {
5249 loc = {
5250 start: {
5251 line: lineNumber,
5252 column: index - lineStart
5253 }
5254 };
5255 start = index;
5256 index += 2;
5257 lineComment = true;
5258 if (index >= length) {
5259 loc.end = {
5260 line: lineNumber,
5261 column: index - lineStart
5262 };
5263 lineComment = false;
5264 addComment('Line', comment, start, index, loc);
5265 }
5266 } else if (ch === '*') {
5267 start = index;
5268 index += 2;
5269 blockComment = true;
5270 loc = {
5271 start: {
5272 line: lineNumber,
5273 column: index - lineStart - 2
5274 }
5275 };
5276 if (index >= length) {
5277 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
5278 }
5279 } else {
5280 break;
5281 }
5282 } else if (isWhiteSpace(ch.charCodeAt(0))) {
5283 ++index;
5284 } else if (isLineTerminator(ch.charCodeAt(0))) {
5285 ++index;
5286 if (ch === '\r' && source[index] === '\n') {
5287 ++index;
5288 }
5289 ++lineNumber;
5290 lineStart = index;
5291 } else {
5292 break;
5293 }
5294 }
5295 }
5296
5297 // 16 XJS
5298
5299 XHTMLEntities = {
5300 quot: '\u0022',
5301 amp: '&',
5302 apos: '\u0027',
5303 lt: '<',
5304 gt: '>',
5305 nbsp: '\u00A0',
5306 iexcl: '\u00A1',
5307 cent: '\u00A2',
5308 pound: '\u00A3',
5309 curren: '\u00A4',
5310 yen: '\u00A5',
5311 brvbar: '\u00A6',
5312 sect: '\u00A7',
5313 uml: '\u00A8',
5314 copy: '\u00A9',
5315 ordf: '\u00AA',
5316 laquo: '\u00AB',
5317 not: '\u00AC',
5318 shy: '\u00AD',
5319 reg: '\u00AE',
5320 macr: '\u00AF',
5321 deg: '\u00B0',
5322 plusmn: '\u00B1',
5323 sup2: '\u00B2',
5324 sup3: '\u00B3',
5325 acute: '\u00B4',
5326 micro: '\u00B5',
5327 para: '\u00B6',
5328 middot: '\u00B7',
5329 cedil: '\u00B8',
5330 sup1: '\u00B9',
5331 ordm: '\u00BA',
5332 raquo: '\u00BB',
5333 frac14: '\u00BC',
5334 frac12: '\u00BD',
5335 frac34: '\u00BE',
5336 iquest: '\u00BF',
5337 Agrave: '\u00C0',
5338 Aacute: '\u00C1',
5339 Acirc: '\u00C2',
5340 Atilde: '\u00C3',
5341 Auml: '\u00C4',
5342 Aring: '\u00C5',
5343 AElig: '\u00C6',
5344 Ccedil: '\u00C7',
5345 Egrave: '\u00C8',
5346 Eacute: '\u00C9',
5347 Ecirc: '\u00CA',
5348 Euml: '\u00CB',
5349 Igrave: '\u00CC',
5350 Iacute: '\u00CD',
5351 Icirc: '\u00CE',
5352 Iuml: '\u00CF',
5353 ETH: '\u00D0',
5354 Ntilde: '\u00D1',
5355 Ograve: '\u00D2',
5356 Oacute: '\u00D3',
5357 Ocirc: '\u00D4',
5358 Otilde: '\u00D5',
5359 Ouml: '\u00D6',
5360 times: '\u00D7',
5361 Oslash: '\u00D8',
5362 Ugrave: '\u00D9',
5363 Uacute: '\u00DA',
5364 Ucirc: '\u00DB',
5365 Uuml: '\u00DC',
5366 Yacute: '\u00DD',
5367 THORN: '\u00DE',
5368 szlig: '\u00DF',
5369 agrave: '\u00E0',
5370 aacute: '\u00E1',
5371 acirc: '\u00E2',
5372 atilde: '\u00E3',
5373 auml: '\u00E4',
5374 aring: '\u00E5',
5375 aelig: '\u00E6',
5376 ccedil: '\u00E7',
5377 egrave: '\u00E8',
5378 eacute: '\u00E9',
5379 ecirc: '\u00EA',
5380 euml: '\u00EB',
5381 igrave: '\u00EC',
5382 iacute: '\u00ED',
5383 icirc: '\u00EE',
5384 iuml: '\u00EF',
5385 eth: '\u00F0',
5386 ntilde: '\u00F1',
5387 ograve: '\u00F2',
5388 oacute: '\u00F3',
5389 ocirc: '\u00F4',
5390 otilde: '\u00F5',
5391 ouml: '\u00F6',
5392 divide: '\u00F7',
5393 oslash: '\u00F8',
5394 ugrave: '\u00F9',
5395 uacute: '\u00FA',
5396 ucirc: '\u00FB',
5397 uuml: '\u00FC',
5398 yacute: '\u00FD',
5399 thorn: '\u00FE',
5400 yuml: '\u00FF',
5401 OElig: '\u0152',
5402 oelig: '\u0153',
5403 Scaron: '\u0160',
5404 scaron: '\u0161',
5405 Yuml: '\u0178',
5406 fnof: '\u0192',
5407 circ: '\u02C6',
5408 tilde: '\u02DC',
5409 Alpha: '\u0391',
5410 Beta: '\u0392',
5411 Gamma: '\u0393',
5412 Delta: '\u0394',
5413 Epsilon: '\u0395',
5414 Zeta: '\u0396',
5415 Eta: '\u0397',
5416 Theta: '\u0398',
5417 Iota: '\u0399',
5418 Kappa: '\u039A',
5419 Lambda: '\u039B',
5420 Mu: '\u039C',
5421 Nu: '\u039D',
5422 Xi: '\u039E',
5423 Omicron: '\u039F',
5424 Pi: '\u03A0',
5425 Rho: '\u03A1',
5426 Sigma: '\u03A3',
5427 Tau: '\u03A4',
5428 Upsilon: '\u03A5',
5429 Phi: '\u03A6',
5430 Chi: '\u03A7',
5431 Psi: '\u03A8',
5432 Omega: '\u03A9',
5433 alpha: '\u03B1',
5434 beta: '\u03B2',
5435 gamma: '\u03B3',
5436 delta: '\u03B4',
5437 epsilon: '\u03B5',
5438 zeta: '\u03B6',
5439 eta: '\u03B7',
5440 theta: '\u03B8',
5441 iota: '\u03B9',
5442 kappa: '\u03BA',
5443 lambda: '\u03BB',
5444 mu: '\u03BC',
5445 nu: '\u03BD',
5446 xi: '\u03BE',
5447 omicron: '\u03BF',
5448 pi: '\u03C0',
5449 rho: '\u03C1',
5450 sigmaf: '\u03C2',
5451 sigma: '\u03C3',
5452 tau: '\u03C4',
5453 upsilon: '\u03C5',
5454 phi: '\u03C6',
5455 chi: '\u03C7',
5456 psi: '\u03C8',
5457 omega: '\u03C9',
5458 thetasym: '\u03D1',
5459 upsih: '\u03D2',
5460 piv: '\u03D6',
5461 ensp: '\u2002',
5462 emsp: '\u2003',
5463 thinsp: '\u2009',
5464 zwnj: '\u200C',
5465 zwj: '\u200D',
5466 lrm: '\u200E',
5467 rlm: '\u200F',
5468 ndash: '\u2013',
5469 mdash: '\u2014',
5470 lsquo: '\u2018',
5471 rsquo: '\u2019',
5472 sbquo: '\u201A',
5473 ldquo: '\u201C',
5474 rdquo: '\u201D',
5475 bdquo: '\u201E',
5476 dagger: '\u2020',
5477 Dagger: '\u2021',
5478 bull: '\u2022',
5479 hellip: '\u2026',
5480 permil: '\u2030',
5481 prime: '\u2032',
5482 Prime: '\u2033',
5483 lsaquo: '\u2039',
5484 rsaquo: '\u203A',
5485 oline: '\u203E',
5486 frasl: '\u2044',
5487 euro: '\u20AC',
5488 image: '\u2111',
5489 weierp: '\u2118',
5490 real: '\u211C',
5491 trade: '\u2122',
5492 alefsym: '\u2135',
5493 larr: '\u2190',
5494 uarr: '\u2191',
5495 rarr: '\u2192',
5496 darr: '\u2193',
5497 harr: '\u2194',
5498 crarr: '\u21B5',
5499 lArr: '\u21D0',
5500 uArr: '\u21D1',
5501 rArr: '\u21D2',
5502 dArr: '\u21D3',
5503 hArr: '\u21D4',
5504 forall: '\u2200',
5505 part: '\u2202',
5506 exist: '\u2203',
5507 empty: '\u2205',
5508 nabla: '\u2207',
5509 isin: '\u2208',
5510 notin: '\u2209',
5511 ni: '\u220B',
5512 prod: '\u220F',
5513 sum: '\u2211',
5514 minus: '\u2212',
5515 lowast: '\u2217',
5516 radic: '\u221A',
5517 prop: '\u221D',
5518 infin: '\u221E',
5519 ang: '\u2220',
5520 and: '\u2227',
5521 or: '\u2228',
5522 cap: '\u2229',
5523 cup: '\u222A',
5524 'int': '\u222B',
5525 there4: '\u2234',
5526 sim: '\u223C',
5527 cong: '\u2245',
5528 asymp: '\u2248',
5529 ne: '\u2260',
5530 equiv: '\u2261',
5531 le: '\u2264',
5532 ge: '\u2265',
5533 sub: '\u2282',
5534 sup: '\u2283',
5535 nsub: '\u2284',
5536 sube: '\u2286',
5537 supe: '\u2287',
5538 oplus: '\u2295',
5539 otimes: '\u2297',
5540 perp: '\u22A5',
5541 sdot: '\u22C5',
5542 lceil: '\u2308',
5543 rceil: '\u2309',
5544 lfloor: '\u230A',
5545 rfloor: '\u230B',
5546 lang: '\u2329',
5547 rang: '\u232A',
5548 loz: '\u25CA',
5549 spades: '\u2660',
5550 clubs: '\u2663',
5551 hearts: '\u2665',
5552 diams: '\u2666'
5553 };
5554
5555 function getQualifiedXJSName(object) {
5556 if (object.type === Syntax.XJSIdentifier) {
5557 return object.name;
5558 }
5559 if (object.type === Syntax.XJSNamespacedName) {
5560 return object.namespace.name + ':' + object.name.name;
5561 }
5562 if (object.type === Syntax.XJSMemberExpression) {
5563 return (
5564 getQualifiedXJSName(object.object) + '.' +
5565 getQualifiedXJSName(object.property)
5566 );
5567 }
5568 }
5569
5570 function isXJSIdentifierStart(ch) {
5571 // exclude backslash (\)
5572 return (ch !== 92) && isIdentifierStart(ch);
5573 }
5574
5575 function isXJSIdentifierPart(ch) {
5576 // exclude backslash (\) and add hyphen (-)
5577 return (ch !== 92) && (ch === 45 || isIdentifierPart(ch));
5578 }
5579
5580 function scanXJSIdentifier() {
5581 var ch, start, value = '';
5582
5583 start = index;
5584 while (index < length) {
5585 ch = source.charCodeAt(index);
5586 if (!isXJSIdentifierPart(ch)) {
5587 break;
5588 }
5589 value += source[index++];
5590 }
5591
5592 return {
5593 type: Token.XJSIdentifier,
5594 value: value,
5595 lineNumber: lineNumber,
5596 lineStart: lineStart,
5597 range: [start, index]
5598 };
5599 }
5600
5601 function scanXJSEntity() {
5602 var ch, str = '', count = 0, entity;
5603 ch = source[index];
5604 assert(ch === '&', 'Entity must start with an ampersand');
5605 index++;
5606 while (index < length && count++ < 10) {
5607 ch = source[index++];
5608 if (ch === ';') {
5609 break;
5610 }
5611 str += ch;
5612 }
5613
5614 if (str[0] === '#' && str[1] === 'x') {
5615 entity = String.fromCharCode(parseInt(str.substr(2), 16));
5616 } else if (str[0] === '#') {
5617 entity = String.fromCharCode(parseInt(str.substr(1), 10));
5618 } else {
5619 entity = XHTMLEntities[str];
5620 }
5621 return entity;
5622 }
5623
5624 function scanXJSText(stopChars) {
5625 var ch, str = '', start;
5626 start = index;
5627 while (index < length) {
5628 ch = source[index];
5629 if (stopChars.indexOf(ch) !== -1) {
5630 break;
5631 }
5632 if (ch === '&') {
5633 str += scanXJSEntity();
5634 } else {
5635 index++;
5636 if (isLineTerminator(ch.charCodeAt(0))) {
5637 ++lineNumber;
5638 lineStart = index;
5639 }
5640 str += ch;
5641 }
5642 }
5643 return {
5644 type: Token.XJSText,
5645 value: str,
5646 lineNumber: lineNumber,
5647 lineStart: lineStart,
5648 range: [start, index]
5649 };
5650 }
5651
5652 function scanXJSStringLiteral() {
5653 var innerToken, quote, start;
5654
5655 quote = source[index];
5656 assert((quote === '\'' || quote === '"'),
5657 'String literal must starts with a quote');
5658
5659 start = index;
5660 ++index;
5661
5662 innerToken = scanXJSText([quote]);
5663
5664 if (quote !== source[index]) {
5665 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
5666 }
5667
5668 ++index;
5669
5670 innerToken.range = [start, index];
5671
5672 return innerToken;
5673 }
5674
5675 /**
5676 * Between XJS opening and closing tags (e.g. <foo>HERE</foo>), anything that
5677 * is not another XJS tag and is not an expression wrapped by {} is text.
5678 */
5679 function advanceXJSChild() {
5680 var ch = source.charCodeAt(index);
5681
5682 // { (123) and < (60)
5683 if (ch !== 123 && ch !== 60) {
5684 return scanXJSText(['<', '{']);
5685 }
5686
5687 return scanPunctuator();
5688 }
5689
5690 function parseXJSIdentifier() {
5691 var token, marker = markerCreate();
5692
5693 if (lookahead.type !== Token.XJSIdentifier) {
5694 throwUnexpected(lookahead);
5695 }
5696
5697 token = lex();
5698 return markerApply(marker, delegate.createXJSIdentifier(token.value));
5699 }
5700
5701 function parseXJSNamespacedName() {
5702 var namespace, name, marker = markerCreate();
5703
5704 namespace = parseXJSIdentifier();
5705 expect(':');
5706 name = parseXJSIdentifier();
5707
5708 return markerApply(marker, delegate.createXJSNamespacedName(namespace, name));
5709 }
5710
5711 function parseXJSMemberExpression() {
5712 var marker = markerCreate(),
5713 expr = parseXJSIdentifier();
5714
5715 while (match('.')) {
5716 lex();
5717 expr = markerApply(marker, delegate.createXJSMemberExpression(expr, parseXJSIdentifier()));
5718 }
5719
5720 return expr;
5721 }
5722
5723 function parseXJSElementName() {
5724 if (lookahead2().value === ':') {
5725 return parseXJSNamespacedName();
5726 }
5727 if (lookahead2().value === '.') {
5728 return parseXJSMemberExpression();
5729 }
5730
5731 return parseXJSIdentifier();
5732 }
5733
5734 function parseXJSAttributeName() {
5735 if (lookahead2().value === ':') {
5736 return parseXJSNamespacedName();
5737 }
5738
5739 return parseXJSIdentifier();
5740 }
5741
5742 function parseXJSAttributeValue() {
5743 var value, marker;
5744 if (match('{')) {
5745 value = parseXJSExpressionContainer();
5746 if (value.expression.type === Syntax.XJSEmptyExpression) {
5747 throwError(
5748 value,
5749 'XJS attributes must only be assigned a non-empty ' +
5750 'expression'
5751 );
5752 }
5753 } else if (match('<')) {
5754 value = parseXJSElement();
5755 } else if (lookahead.type === Token.XJSText) {
5756 marker = markerCreate();
5757 value = markerApply(marker, delegate.createLiteral(lex()));
5758 } else {
5759 throwError({}, Messages.InvalidXJSAttributeValue);
5760 }
5761 return value;
5762 }
5763
5764 function parseXJSEmptyExpression() {
5765 var marker = markerCreatePreserveWhitespace();
5766 while (source.charAt(index) !== '}') {
5767 index++;
5768 }
5769 return markerApply(marker, delegate.createXJSEmptyExpression());
5770 }
5771
5772 function parseXJSExpressionContainer() {
5773 var expression, origInXJSChild, origInXJSTag, marker = markerCreate();
5774
5775 origInXJSChild = state.inXJSChild;
5776 origInXJSTag = state.inXJSTag;
5777 state.inXJSChild = false;
5778 state.inXJSTag = false;
5779
5780 expect('{');
5781
5782 if (match('}')) {
5783 expression = parseXJSEmptyExpression();
5784 } else {
5785 expression = parseExpression();
5786 }
5787
5788 state.inXJSChild = origInXJSChild;
5789 state.inXJSTag = origInXJSTag;
5790
5791 expect('}');
5792
5793 return markerApply(marker, delegate.createXJSExpressionContainer(expression));
5794 }
5795
5796 function parseXJSSpreadAttribute() {
5797 var expression, origInXJSChild, origInXJSTag, marker = markerCreate();
5798
5799 origInXJSChild = state.inXJSChild;
5800 origInXJSTag = state.inXJSTag;
5801 state.inXJSChild = false;
5802 state.inXJSTag = false;
5803
5804 expect('{');
5805 expect('...');
5806
5807 expression = parseAssignmentExpression();
5808
5809 state.inXJSChild = origInXJSChild;
5810 state.inXJSTag = origInXJSTag;
5811
5812 expect('}');
5813
5814 return markerApply(marker, delegate.createXJSSpreadAttribute(expression));
5815 }
5816
5817 function parseXJSAttribute() {
5818 var name, marker;
5819
5820 if (match('{')) {
5821 return parseXJSSpreadAttribute();
5822 }
5823
5824 marker = markerCreate();
5825
5826 name = parseXJSAttributeName();
5827
5828 // HTML empty attribute
5829 if (match('=')) {
5830 lex();
5831 return markerApply(marker, delegate.createXJSAttribute(name, parseXJSAttributeValue()));
5832 }
5833
5834 return markerApply(marker, delegate.createXJSAttribute(name));
5835 }
5836
5837 function parseXJSChild() {
5838 var token, marker;
5839 if (match('{')) {
5840 token = parseXJSExpressionContainer();
5841 } else if (lookahead.type === Token.XJSText) {
5842 marker = markerCreatePreserveWhitespace();
5843 token = markerApply(marker, delegate.createLiteral(lex()));
5844 } else {
5845 token = parseXJSElement();
5846 }
5847 return token;
5848 }
5849
5850 function parseXJSClosingElement() {
5851 var name, origInXJSChild, origInXJSTag, marker = markerCreate();
5852 origInXJSChild = state.inXJSChild;
5853 origInXJSTag = state.inXJSTag;
5854 state.inXJSChild = false;
5855 state.inXJSTag = true;
5856 expect('<');
5857 expect('/');
5858 name = parseXJSElementName();
5859 // Because advance() (called by lex() called by expect()) expects there
5860 // to be a valid token after >, it needs to know whether to look for a
5861 // standard JS token or an XJS text node
5862 state.inXJSChild = origInXJSChild;
5863 state.inXJSTag = origInXJSTag;
5864 expect('>');
5865 return markerApply(marker, delegate.createXJSClosingElement(name));
5866 }
5867
5868 function parseXJSOpeningElement() {
5869 var name, attribute, attributes = [], selfClosing = false, origInXJSChild, origInXJSTag, marker = markerCreate();
5870
5871 origInXJSChild = state.inXJSChild;
5872 origInXJSTag = state.inXJSTag;
5873 state.inXJSChild = false;
5874 state.inXJSTag = true;
5875
5876 expect('<');
5877
5878 name = parseXJSElementName();
5879
5880 while (index < length &&
5881 lookahead.value !== '/' &&
5882 lookahead.value !== '>') {
5883 attributes.push(parseXJSAttribute());
5884 }
5885
5886 state.inXJSTag = origInXJSTag;
5887
5888 if (lookahead.value === '/') {
5889 expect('/');
5890 // Because advance() (called by lex() called by expect()) expects
5891 // there to be a valid token after >, it needs to know whether to
5892 // look for a standard JS token or an XJS text node
5893 state.inXJSChild = origInXJSChild;
5894 expect('>');
5895 selfClosing = true;
5896 } else {
5897 state.inXJSChild = true;
5898 expect('>');
5899 }
5900 return markerApply(marker, delegate.createXJSOpeningElement(name, attributes, selfClosing));
5901 }
5902
5903 function parseXJSElement() {
5904 var openingElement, closingElement, children = [], origInXJSChild, origInXJSTag, marker = markerCreate();
5905
5906 origInXJSChild = state.inXJSChild;
5907 origInXJSTag = state.inXJSTag;
5908 openingElement = parseXJSOpeningElement();
5909
5910 if (!openingElement.selfClosing) {
5911 while (index < length) {
5912 state.inXJSChild = false; // Call lookahead2() with inXJSChild = false because </ should not be considered in the child
5913 if (lookahead.value === '<' && lookahead2().value === '/') {
5914 break;
5915 }
5916 state.inXJSChild = true;
5917 children.push(parseXJSChild());
5918 }
5919 state.inXJSChild = origInXJSChild;
5920 state.inXJSTag = origInXJSTag;
5921 closingElement = parseXJSClosingElement();
5922 if (getQualifiedXJSName(closingElement.name) !== getQualifiedXJSName(openingElement.name)) {
5923 throwError({}, Messages.ExpectedXJSClosingTag, getQualifiedXJSName(openingElement.name));
5924 }
5925 }
5926
5927 // When (erroneously) writing two adjacent tags like
5928 //
5929 // var x = <div>one</div><div>two</div>;
5930 //
5931 // the default error message is a bit incomprehensible. Since it's
5932 // rarely (never?) useful to write a less-than sign after an XJS
5933 // element, we disallow it here in the parser in order to provide a
5934 // better error message. (In the rare case that the less-than operator
5935 // was intended, the left tag can be wrapped in parentheses.)
5936 if (!origInXJSChild && match('<')) {
5937 throwError(lookahead, Messages.AdjacentXJSElements);
5938 }
5939
5940 return markerApply(marker, delegate.createXJSElement(openingElement, closingElement, children));
5941 }
5942
5943 function collectToken() {
5944 var start, loc, token, range, value;
5945
5946 if (!state.inXJSChild) {
5947 skipComment();
5948 }
5949
5950 start = index;
5951 loc = {
5952 start: {
5953 line: lineNumber,
5954 column: index - lineStart
5955 }
5956 };
5957
5958 token = extra.advance();
5959 loc.end = {
5960 line: lineNumber,
5961 column: index - lineStart
5962 };
5963
5964 if (token.type !== Token.EOF) {
5965 range = [token.range[0], token.range[1]];
5966 value = source.slice(token.range[0], token.range[1]);
5967 extra.tokens.push({
5968 type: TokenName[token.type],
5969 value: value,
5970 range: range,
5971 loc: loc
5972 });
5973 }
5974
5975 return token;
5976 }
5977
5978 function collectRegex() {
5979 var pos, loc, regex, token;
5980
5981 skipComment();
5982
5983 pos = index;
5984 loc = {
5985 start: {
5986 line: lineNumber,
5987 column: index - lineStart
5988 }
5989 };
5990
5991 regex = extra.scanRegExp();
5992 loc.end = {
5993 line: lineNumber,
5994 column: index - lineStart
5995 };
5996
5997 if (!extra.tokenize) {
5998 // Pop the previous token, which is likely '/' or '/='
5999 if (extra.tokens.length > 0) {
6000 token = extra.tokens[extra.tokens.length - 1];
6001 if (token.range[0] === pos && token.type === 'Punctuator') {
6002 if (token.value === '/' || token.value === '/=') {
6003 extra.tokens.pop();
6004 }
6005 }
6006 }
6007
6008 extra.tokens.push({
6009 type: 'RegularExpression',
6010 value: regex.literal,
6011 range: [pos, index],
6012 loc: loc
6013 });
6014 }
6015
6016 return regex;
6017 }
6018
6019 function filterTokenLocation() {
6020 var i, entry, token, tokens = [];
6021
6022 for (i = 0; i < extra.tokens.length; ++i) {
6023 entry = extra.tokens[i];
6024 token = {
6025 type: entry.type,
6026 value: entry.value
6027 };
6028 if (extra.range) {
6029 token.range = entry.range;
6030 }
6031 if (extra.loc) {
6032 token.loc = entry.loc;
6033 }
6034 tokens.push(token);
6035 }
6036
6037 extra.tokens = tokens;
6038 }
6039
6040 function patch() {
6041 if (extra.comments) {
6042 extra.skipComment = skipComment;
6043 skipComment = scanComment;
6044 }
6045
6046 if (typeof extra.tokens !== 'undefined') {
6047 extra.advance = advance;
6048 extra.scanRegExp = scanRegExp;
6049
6050 advance = collectToken;
6051 scanRegExp = collectRegex;
6052 }
6053 }
6054
6055 function unpatch() {
6056 if (typeof extra.skipComment === 'function') {
6057 skipComment = extra.skipComment;
6058 }
6059
6060 if (typeof extra.scanRegExp === 'function') {
6061 advance = extra.advance;
6062 scanRegExp = extra.scanRegExp;
6063 }
6064 }
6065
6066 // This is used to modify the delegate.
6067
6068 function extend(object, properties) {
6069 var entry, result = {};
6070
6071 for (entry in object) {
6072 if (object.hasOwnProperty(entry)) {
6073 result[entry] = object[entry];
6074 }
6075 }
6076
6077 for (entry in properties) {
6078 if (properties.hasOwnProperty(entry)) {
6079 result[entry] = properties[entry];
6080 }
6081 }
6082
6083 return result;
6084 }
6085
6086 function tokenize(code, options) {
6087 var toString,
6088 token,
6089 tokens;
6090
6091 toString = String;
6092 if (typeof code !== 'string' && !(code instanceof String)) {
6093 code = toString(code);
6094 }
6095
6096 delegate = SyntaxTreeDelegate;
6097 source = code;
6098 index = 0;
6099 lineNumber = (source.length > 0) ? 1 : 0;
6100 lineStart = 0;
6101 length = source.length;
6102 lookahead = null;
6103 state = {
6104 allowKeyword: true,
6105 allowIn: true,
6106 labelSet: {},
6107 inFunctionBody: false,
6108 inIteration: false,
6109 inSwitch: false,
6110 lastCommentStart: -1
6111 };
6112
6113 extra = {};
6114
6115 // Options matching.
6116 options = options || {};
6117
6118 // Of course we collect tokens here.
6119 options.tokens = true;
6120 extra.tokens = [];
6121 extra.tokenize = true;
6122 // The following two fields are necessary to compute the Regex tokens.
6123 extra.openParenToken = -1;
6124 extra.openCurlyToken = -1;
6125
6126 extra.range = (typeof options.range === 'boolean') && options.range;
6127 extra.loc = (typeof options.loc === 'boolean') && options.loc;
6128
6129 if (typeof options.comment === 'boolean' && options.comment) {
6130 extra.comments = [];
6131 }
6132 if (typeof options.tolerant === 'boolean' && options.tolerant) {
6133 extra.errors = [];
6134 }
6135
6136 if (length > 0) {
6137 if (typeof source[0] === 'undefined') {
6138 // Try first to convert to a string. This is good as fast path
6139 // for old IE which understands string indexing for string
6140 // literals only and not for string object.
6141 if (code instanceof String) {
6142 source = code.valueOf();
6143 }
6144 }
6145 }
6146
6147 patch();
6148
6149 try {
6150 peek();
6151 if (lookahead.type === Token.EOF) {
6152 return extra.tokens;
6153 }
6154
6155 token = lex();
6156 while (lookahead.type !== Token.EOF) {
6157 try {
6158 token = lex();
6159 } catch (lexError) {
6160 token = lookahead;
6161 if (extra.errors) {
6162 extra.errors.push(lexError);
6163 // We have to break on the first error
6164 // to avoid infinite loops.
6165 break;
6166 } else {
6167 throw lexError;
6168 }
6169 }
6170 }
6171
6172 filterTokenLocation();
6173 tokens = extra.tokens;
6174 if (typeof extra.comments !== 'undefined') {
6175 tokens.comments = extra.comments;
6176 }
6177 if (typeof extra.errors !== 'undefined') {
6178 tokens.errors = extra.errors;
6179 }
6180 } catch (e) {
6181 throw e;
6182 } finally {
6183 unpatch();
6184 extra = {};
6185 }
6186 return tokens;
6187 }
6188
6189 function parse(code, options) {
6190 var program, toString;
6191
6192 toString = String;
6193 if (typeof code !== 'string' && !(code instanceof String)) {
6194 code = toString(code);
6195 }
6196
6197 delegate = SyntaxTreeDelegate;
6198 source = code;
6199 index = 0;
6200 lineNumber = (source.length > 0) ? 1 : 0;
6201 lineStart = 0;
6202 length = source.length;
6203 lookahead = null;
6204 state = {
6205 allowKeyword: false,
6206 allowIn: true,
6207 labelSet: {},
6208 parenthesizedCount: 0,
6209 inFunctionBody: false,
6210 inIteration: false,
6211 inSwitch: false,
6212 inXJSChild: false,
6213 inXJSTag: false,
6214 lastCommentStart: -1,
6215 yieldAllowed: false
6216 };
6217
6218 extra = {};
6219 if (typeof options !== 'undefined') {
6220 extra.range = (typeof options.range === 'boolean') && options.range;
6221 extra.loc = (typeof options.loc === 'boolean') && options.loc;
6222
6223 if (extra.loc && options.source !== null && options.source !== undefined) {
6224 delegate = extend(delegate, {
6225 'postProcess': function (node) {
6226 node.loc.source = toString(options.source);
6227 return node;
6228 }
6229 });
6230 }
6231
6232 if (typeof options.tokens === 'boolean' && options.tokens) {
6233 extra.tokens = [];
6234 }
6235 if (typeof options.comment === 'boolean' && options.comment) {
6236 extra.comments = [];
6237 }
6238 if (typeof options.tolerant === 'boolean' && options.tolerant) {
6239 extra.errors = [];
6240 }
6241 }
6242
6243 if (length > 0) {
6244 if (typeof source[0] === 'undefined') {
6245 // Try first to convert to a string. This is good as fast path
6246 // for old IE which understands string indexing for string
6247 // literals only and not for string object.
6248 if (code instanceof String) {
6249 source = code.valueOf();
6250 }
6251 }
6252 }
6253
6254 patch();
6255 try {
6256 program = parseProgram();
6257 if (typeof extra.comments !== 'undefined') {
6258 program.comments = extra.comments;
6259 }
6260 if (typeof extra.tokens !== 'undefined') {
6261 filterTokenLocation();
6262 program.tokens = extra.tokens;
6263 }
6264 if (typeof extra.errors !== 'undefined') {
6265 program.errors = extra.errors;
6266 }
6267 } catch (e) {
6268 throw e;
6269 } finally {
6270 unpatch();
6271 extra = {};
6272 }
6273
6274 return program;
6275 }
6276
6277 // Sync with *.json manifests.
6278 exports.version = '4001.3001.0000-dev-harmony-fb';
6279
6280 exports.tokenize = tokenize;
6281
6282 exports.parse = parse;
6283
6284 // Deep copy.
6285 exports.Syntax = (function () {
6286 var name, types = {};
6287
6288 if (typeof Object.create === 'function') {
6289 types = Object.create(null);
6290 }
6291
6292 for (name in Syntax) {
6293 if (Syntax.hasOwnProperty(name)) {
6294 types[name] = Syntax[name];
6295 }
6296 }
6297
6298 if (typeof Object.freeze === 'function') {
6299 Object.freeze(types);
6300 }
6301
6302 return types;
6303 }());
6304
6305}));
6306/* vim: set sw=4 ts=4 et tw=80 : */
6307
\No newline at end of file