UNPKG

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