]>
code.delx.au - gnu-emacs-elpa/blob - lib/esprima.js
2 Copyright (C) 2013 Ariya Hidayat <ariya.hidayat@gmail.com>
3 Copyright (C) 2013 Thaddee Tyl <thaddee.tyl@gmail.com>
4 Copyright (C) 2013 Mathias Bynens <mathias@qiwi.be>
5 Copyright (C) 2012 Ariya Hidayat <ariya.hidayat@gmail.com>
6 Copyright (C) 2012 Mathias Bynens <mathias@qiwi.be>
7 Copyright (C) 2012 Joost-Wim Boekesteijn <joost-wim@boekesteijn.nl>
8 Copyright (C) 2012 Kris Kowal <kris.kowal@cixar.com>
9 Copyright (C) 2012 Yusuke Suzuki <utatane.tea@gmail.com>
10 Copyright (C) 2012 Arpad Borsos <arpad.borsos@googlemail.com>
11 Copyright (C) 2011 Ariya Hidayat <ariya.hidayat@gmail.com>
13 Redistribution and use in source and binary forms, with or without
14 modification, are permitted provided that the following conditions are met:
16 * Redistributions of source code must retain the above copyright
17 notice, this list of conditions and the following disclaimer.
18 * Redistributions in binary form must reproduce the above copyright
19 notice, this list of conditions and the following disclaimer in the
20 documentation and/or other materials provided with the distribution.
22 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
26 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
29 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 /*jslint bitwise:true plusplus:true */
35 /*global esprima:true, define:true, exports:true, window: true,
36 throwErrorTolerant: true,
37 throwError: true, generateStatement: true, peek: true,
38 parseAssignmentExpression: true, parseBlock: true, parseExpression: true,
39 parseFunctionDeclaration: true, parseFunctionExpression: true,
40 parseFunctionSourceElements: true, parseVariableIdentifier: true,
41 parseLeftHandSideExpression: true,
42 parseUnaryExpression: true,
43 parseStatement: true, parseSourceElement: true */
45 (function (root
, factory
) {
48 // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js,
49 // Rhino, and plain browser loading.
51 /* istanbul ignore next */
52 if (typeof define
=== 'function' && define
.amd
) {
53 define(['exports'], factory
);
54 } else if (typeof exports
!== 'undefined') {
57 factory((root
.esprima
= {}));
59 }(this, function (exports
) {
94 TokenName
[Token
.BooleanLiteral
] = 'Boolean';
95 TokenName
[Token
.EOF
] = '<end>';
96 TokenName
[Token
.Identifier
] = 'Identifier';
97 TokenName
[Token
.Keyword
] = 'Keyword';
98 TokenName
[Token
.NullLiteral
] = 'Null';
99 TokenName
[Token
.NumericLiteral
] = 'Numeric';
100 TokenName
[Token
.Punctuator
] = 'Punctuator';
101 TokenName
[Token
.StringLiteral
] = 'String';
102 TokenName
[Token
.RegularExpression
] = 'RegularExpression';
104 // A function following one of those tokens is an expression.
105 FnExprTokens
= ['(', '{', '[', 'in', 'typeof', 'instanceof', 'new',
106 'return', 'case', 'delete', 'throw', 'void',
107 // assignment operators
108 '=', '+=', '-=', '*=', '/=', '%=', '<<=', '>>=', '>>>=',
109 '&=', '|=', '^=', ',',
110 // binary/unary operators
111 '+', '-', '*', '/', '%', '++', '--', '<<', '>>', '>>>', '&',
112 '|', '^', '!', '~', '&&', '||', '?', ':', '===', '==', '>=',
113 '<=', '<', '>', '!=', '!=='];
116 AssignmentExpression
: 'AssignmentExpression',
117 ArrayExpression
: 'ArrayExpression',
118 BlockStatement
: 'BlockStatement',
119 BinaryExpression
: 'BinaryExpression',
120 BreakStatement
: 'BreakStatement',
121 CallExpression
: 'CallExpression',
122 CatchClause
: 'CatchClause',
123 ConditionalExpression
: 'ConditionalExpression',
124 ContinueStatement
: 'ContinueStatement',
125 DoWhileStatement
: 'DoWhileStatement',
126 DebuggerStatement
: 'DebuggerStatement',
127 EmptyStatement
: 'EmptyStatement',
128 ExpressionStatement
: 'ExpressionStatement',
129 ForStatement
: 'ForStatement',
130 ForInStatement
: 'ForInStatement',
131 FunctionDeclaration
: 'FunctionDeclaration',
132 FunctionExpression
: 'FunctionExpression',
133 Identifier
: 'Identifier',
134 IfStatement
: 'IfStatement',
136 LabeledStatement
: 'LabeledStatement',
137 LogicalExpression
: 'LogicalExpression',
138 MemberExpression
: 'MemberExpression',
139 NewExpression
: 'NewExpression',
140 ObjectExpression
: 'ObjectExpression',
142 Property
: 'Property',
143 ReturnStatement
: 'ReturnStatement',
144 SequenceExpression
: 'SequenceExpression',
145 SwitchStatement
: 'SwitchStatement',
146 SwitchCase
: 'SwitchCase',
147 ThisExpression
: 'ThisExpression',
148 ThrowStatement
: 'ThrowStatement',
149 TryStatement
: 'TryStatement',
150 UnaryExpression
: 'UnaryExpression',
151 UpdateExpression
: 'UpdateExpression',
152 VariableDeclaration
: 'VariableDeclaration',
153 VariableDeclarator
: 'VariableDeclarator',
154 WhileStatement
: 'WhileStatement',
155 WithStatement
: 'WithStatement'
164 // Error messages should be identical to V8.
166 UnexpectedToken
: 'Unexpected token %0',
167 UnexpectedNumber
: 'Unexpected number',
168 UnexpectedString
: 'Unexpected string',
169 UnexpectedIdentifier
: 'Unexpected identifier',
170 UnexpectedReserved
: 'Unexpected reserved word',
171 UnexpectedEOS
: 'Unexpected end of input',
172 NewlineAfterThrow
: 'Illegal newline after throw',
173 InvalidRegExp
: 'Invalid regular expression',
174 UnterminatedRegExp
: 'Invalid regular expression: missing /',
175 InvalidLHSInAssignment
: 'Invalid left-hand side in assignment',
176 InvalidLHSInForIn
: 'Invalid left-hand side in for-in',
177 MultipleDefaultsInSwitch
: 'More than one default clause in switch statement',
178 NoCatchOrFinally
: 'Missing catch or finally after try',
179 UnknownLabel
: 'Undefined label \'%0\'',
180 Redeclaration
: '%0 \'%1\' has already been declared',
181 IllegalContinue
: 'Illegal continue statement',
182 IllegalBreak
: 'Illegal break statement',
183 IllegalReturn
: 'Illegal return statement',
184 StrictModeWith
: 'Strict mode code may not include a with statement',
185 StrictCatchVariable
: 'Catch variable may not be eval or arguments in strict mode',
186 StrictVarName
: 'Variable name may not be eval or arguments in strict mode',
187 StrictParamName
: 'Parameter name eval or arguments is not allowed in strict mode',
188 StrictParamDupe
: 'Strict mode function may not have duplicate parameter names',
189 StrictFunctionName
: 'Function name may not be eval or arguments in strict mode',
190 StrictOctalLiteral
: 'Octal literals are not allowed in strict mode.',
191 StrictDelete
: 'Delete of an unqualified identifier in strict mode.',
192 StrictDuplicateProperty
: 'Duplicate data property in object literal not allowed in strict mode',
193 AccessorDataProperty
: 'Object literal may not have data and accessor property with the same name',
194 AccessorGetSet
: 'Object literal may not have multiple get/set accessors with the same name',
195 StrictLHSAssignment
: 'Assignment to eval or arguments is not allowed in strict mode',
196 StrictLHSPostfix
: 'Postfix increment/decrement may not have eval or arguments operand in strict mode',
197 StrictLHSPrefix
: 'Prefix increment/decrement may not have eval or arguments operand in strict mode',
198 StrictReservedWord
: 'Use of future reserved word in strict mode'
201 // See also tools/generate-unicode-regex.py.
203 NonAsciiIdentifierStart
: new RegExp('[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0\u08A2-\u08AC\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097F\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F0\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191C\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA697\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA793\uA7A0-\uA7AA\uA7F8-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA80-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]'),
204 NonAsciiIdentifierPart
: new RegExp('[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0300-\u0374\u0376\u0377\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u0483-\u0487\u048A-\u0527\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u05D0-\u05EA\u05F0-\u05F2\u0610-\u061A\u0620-\u0669\u066E-\u06D3\u06D5-\u06DC\u06DF-\u06E8\u06EA-\u06FC\u06FF\u0710-\u074A\u074D-\u07B1\u07C0-\u07F5\u07FA\u0800-\u082D\u0840-\u085B\u08A0\u08A2-\u08AC\u08E4-\u08FE\u0900-\u0963\u0966-\u096F\u0971-\u0977\u0979-\u097F\u0981-\u0983\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BC-\u09C4\u09C7\u09C8\u09CB-\u09CE\u09D7\u09DC\u09DD\u09DF-\u09E3\u09E6-\u09F1\u0A01-\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A59-\u0A5C\u0A5E\u0A66-\u0A75\u0A81-\u0A83\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABC-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AD0\u0AE0-\u0AE3\u0AE6-\u0AEF\u0B01-\u0B03\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3C-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B5C\u0B5D\u0B5F-\u0B63\u0B66-\u0B6F\u0B71\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD0\u0BD7\u0BE6-\u0BEF\u0C01-\u0C03\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C58\u0C59\u0C60-\u0C63\u0C66-\u0C6F\u0C82\u0C83\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBC-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CDE\u0CE0-\u0CE3\u0CE6-\u0CEF\u0CF1\u0CF2\u0D02\u0D03\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D-\u0D44\u0D46-\u0D48\u0D4A-\u0D4E\u0D57\u0D60-\u0D63\u0D66-\u0D6F\u0D7A-\u0D7F\u0D82\u0D83\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DF2\u0DF3\u0E01-\u0E3A\u0E40-\u0E4E\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB9\u0EBB-\u0EBD\u0EC0-\u0EC4\u0EC6\u0EC8-\u0ECD\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F18\u0F19\u0F20-\u0F29\u0F35\u0F37\u0F39\u0F3E-\u0F47\u0F49-\u0F6C\u0F71-\u0F84\u0F86-\u0F97\u0F99-\u0FBC\u0FC6\u1000-\u1049\u1050-\u109D\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u135D-\u135F\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F0\u1700-\u170C\u170E-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176C\u176E-\u1770\u1772\u1773\u1780-\u17D3\u17D7\u17DC\u17DD\u17E0-\u17E9\u180B-\u180D\u1810-\u1819\u1820-\u1877\u1880-\u18AA\u18B0-\u18F5\u1900-\u191C\u1920-\u192B\u1930-\u193B\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19D9\u1A00-\u1A1B\u1A20-\u1A5E\u1A60-\u1A7C\u1A7F-\u1A89\u1A90-\u1A99\u1AA7\u1B00-\u1B4B\u1B50-\u1B59\u1B6B-\u1B73\u1B80-\u1BF3\u1C00-\u1C37\u1C40-\u1C49\u1C4D-\u1C7D\u1CD0-\u1CD2\u1CD4-\u1CF6\u1D00-\u1DE6\u1DFC-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u200C\u200D\u203F\u2040\u2054\u2071\u207F\u2090-\u209C\u20D0-\u20DC\u20E1\u20E5-\u20F0\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D7F-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2DE0-\u2DFF\u2E2F\u3005-\u3007\u3021-\u302F\u3031-\u3035\u3038-\u303C\u3041-\u3096\u3099\u309A\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66F\uA674-\uA67D\uA67F-\uA697\uA69F-\uA6F1\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA793\uA7A0-\uA7AA\uA7F8-\uA827\uA840-\uA873\uA880-\uA8C4\uA8D0-\uA8D9\uA8E0-\uA8F7\uA8FB\uA900-\uA92D\uA930-\uA953\uA960-\uA97C\uA980-\uA9C0\uA9CF-\uA9D9\uAA00-\uAA36\uAA40-\uAA4D\uAA50-\uAA59\uAA60-\uAA76\uAA7A\uAA7B\uAA80-\uAAC2\uAADB-\uAADD\uAAE0-\uAAEF\uAAF2-\uAAF6\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uABC0-\uABEA\uABEC\uABED\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE00-\uFE0F\uFE20-\uFE26\uFE33\uFE34\uFE4D-\uFE4F\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF3F\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]')
207 // Ensure the condition is true, otherwise throw an error.
208 // This is only to have a better contract semantic, i.e. another safety net
209 // to catch a logic error. The condition shall be fulfilled in normal case.
210 // Do NOT use this to enforce a certain condition on any user input.
212 function assert(condition
, message
) {
213 /* istanbul ignore if */
215 throw new Error('ASSERT: ' + message
);
219 function isDecimalDigit(ch
) {
220 return (ch
>= 48 && ch
<= 57); // 0..9
223 function isHexDigit(ch
) {
224 return '0123456789abcdefABCDEF'.indexOf(ch
) >= 0;
227 function isOctalDigit(ch
) {
228 return '01234567'.indexOf(ch
) >= 0;
234 function isWhiteSpace(ch
) {
235 return (ch
=== 0x20) || (ch
=== 0x09) || (ch
=== 0x0B) || (ch
=== 0x0C) || (ch
=== 0xA0) ||
236 (ch
>= 0x1680 && [0x1680, 0x180E, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008, 0x2009, 0x200A, 0x202F, 0x205F, 0x3000, 0xFEFF].indexOf(ch
) >= 0);
239 // 7.3 Line Terminators
241 function isLineTerminator(ch
) {
242 return (ch
=== 0x0A) || (ch
=== 0x0D) || (ch
=== 0x2028) || (ch
=== 0x2029);
245 // 7.6 Identifier Names and Identifiers
247 function isIdentifierStart(ch
) {
248 return (ch
=== 0x24) || (ch
=== 0x5F) || // $ (dollar) and _ (underscore)
249 (ch
>= 0x41 && ch
<= 0x5A) || // A..Z
250 (ch
>= 0x61 && ch
<= 0x7A) || // a..z
251 (ch
=== 0x5C) || // \ (backslash)
252 ((ch
>= 0x80) && Regex
.NonAsciiIdentifierStart
.test(String
.fromCharCode(ch
)));
255 function isIdentifierPart(ch
) {
256 return (ch
=== 0x24) || (ch
=== 0x5F) || // $ (dollar) and _ (underscore)
257 (ch
>= 0x41 && ch
<= 0x5A) || // A..Z
258 (ch
>= 0x61 && ch
<= 0x7A) || // a..z
259 (ch
>= 0x30 && ch
<= 0x39) || // 0..9
260 (ch
=== 0x5C) || // \ (backslash)
261 ((ch
>= 0x80) && Regex
.NonAsciiIdentifierPart
.test(String
.fromCharCode(ch
)));
264 // 7.6.1.2 Future Reserved Words
266 function isFutureReservedWord(id
) {
280 function isStrictModeReservedWord(id
) {
297 function isRestrictedWord(id
) {
298 return id
=== 'eval' || id
=== 'arguments';
303 function isKeyword(id
) {
304 if (strict
&& isStrictModeReservedWord(id
)) {
308 // 'const' is specialized as Keyword in V8.
309 // 'yield' and 'let' are for compatiblity with SpiderMonkey and ES.next.
310 // Some others are from future reserved words.
314 return (id
=== 'if') || (id
=== 'in') || (id
=== 'do');
316 return (id
=== 'var') || (id
=== 'for') || (id
=== 'new') ||
317 (id
=== 'try') || (id
=== 'let');
319 return (id
=== 'this') || (id
=== 'else') || (id
=== 'case') ||
320 (id
=== 'void') || (id
=== 'with') || (id
=== 'enum');
322 return (id
=== 'while') || (id
=== 'break') || (id
=== 'catch') ||
323 (id
=== 'throw') || (id
=== 'const') || (id
=== 'yield') ||
324 (id
=== 'class') || (id
=== 'super');
326 return (id
=== 'return') || (id
=== 'typeof') || (id
=== 'delete') ||
327 (id
=== 'switch') || (id
=== 'export') || (id
=== 'import');
329 return (id
=== 'default') || (id
=== 'finally') || (id
=== 'extends');
331 return (id
=== 'function') || (id
=== 'continue') || (id
=== 'debugger');
333 return (id
=== 'instanceof');
341 function addComment(type
, value
, start
, end
, loc
) {
342 var comment
, attacher
;
344 assert(typeof start
=== 'number', 'Comment must have valid position');
346 // Because the way the actual token is scanned, often the comments
347 // (if any) are skipped twice during the lexical analysis.
348 // Thus, we need to skip adding a comment if the comment array already
350 if (state
.lastCommentStart
>= start
) {
353 state
.lastCommentStart
= start
;
360 comment
.range
= [start
, end
];
365 extra
.comments
.push(comment
);
366 if (extra
.attachComment
) {
367 extra
.leadingComments
.push(comment
);
368 extra
.trailingComments
.push(comment
);
372 function skipSingleLineComment(offset
) {
373 var start
, loc
, ch
, comment
;
375 start
= index
- offset
;
379 column
: index
- lineStart
- offset
383 while (index
< length
) {
384 ch
= source
.charCodeAt(index
);
386 if (isLineTerminator(ch
)) {
387 if (extra
.comments
) {
388 comment
= source
.slice(start
+ offset
, index
- 1);
391 column
: index
- lineStart
- 1
393 addComment('Line', comment
, start
, index
- 1, loc
);
395 if (ch
=== 13 && source
.charCodeAt(index
) === 10) {
404 if (extra
.comments
) {
405 comment
= source
.slice(start
+ offset
, index
);
408 column
: index
- lineStart
410 addComment('Line', comment
, start
, index
, loc
);
414 function skipMultiLineComment() {
415 var start
, loc
, ch
, comment
;
417 if (extra
.comments
) {
422 column
: index
- lineStart
- 2
427 while (index
< length
) {
428 ch
= source
.charCodeAt(index
);
429 if (isLineTerminator(ch
)) {
430 if (ch
=== 0x0D && source
.charCodeAt(index
+ 1) === 0x0A) {
436 if (index
>= length
) {
437 throwError({}, Messages
.UnexpectedToken
, 'ILLEGAL');
439 } else if (ch
=== 0x2A) {
440 // Block comment ends with '*/'.
441 if (source
.charCodeAt(index
+ 1) === 0x2F) {
444 if (extra
.comments
) {
445 comment
= source
.slice(start
+ 2, index
- 2);
448 column
: index
- lineStart
450 addComment('Block', comment
, start
, index
, loc
);
460 throwError({}, Messages
.UnexpectedToken
, 'ILLEGAL');
463 function skipComment() {
466 start
= (index
=== 0);
467 while (index
< length
) {
468 ch
= source
.charCodeAt(index
);
470 if (isWhiteSpace(ch
)) {
472 } else if (isLineTerminator(ch
)) {
474 if (ch
=== 0x0D && source
.charCodeAt(index
) === 0x0A) {
480 } else if (ch
=== 0x2F) { // U+002F is '/'
481 ch
= source
.charCodeAt(index
+ 1);
485 skipSingleLineComment(2);
487 } else if (ch
=== 0x2A) { // U+002A is '*'
490 skipMultiLineComment();
494 } else if (start
&& ch
=== 0x2D) { // U+002D is '-'
496 if ((source
.charCodeAt(index
+ 1) === 0x2D) && (source
.charCodeAt(index
+ 2) === 0x3E)) {
497 // '-->' is a single-line comment
499 skipSingleLineComment(3);
503 } else if (ch
=== 0x3C) { // U+003C is '<'
504 if (source
.slice(index
+ 1, index
+ 4) === '!--') {
509 skipSingleLineComment(4);
519 function scanHexEscape(prefix
) {
520 var i
, len
, ch
, code
= 0;
522 len
= (prefix
=== 'u') ? 4 : 2;
523 for (i
= 0; i
< len
; ++i
) {
524 if (index
< length
&& isHexDigit(source
[index
])) {
525 ch
= source
[index
++];
526 code
= code
* 16 + '0123456789abcdef'.indexOf(ch
.toLowerCase());
531 return String
.fromCharCode(code
);
534 function getEscapedIdentifier() {
537 ch
= source
.charCodeAt(index
++);
538 id
= String
.fromCharCode(ch
);
540 // '\u' (U+005C, U+0075) denotes an escaped character.
542 if (source
.charCodeAt(index
) !== 0x75) {
543 throwError({}, Messages
.UnexpectedToken
, 'ILLEGAL');
546 ch
= scanHexEscape('u');
547 if (!ch
|| ch
=== '\\' || !isIdentifierStart(ch
.charCodeAt(0))) {
548 throwError({}, Messages
.UnexpectedToken
, 'ILLEGAL');
553 while (index
< length
) {
554 ch
= source
.charCodeAt(index
);
555 if (!isIdentifierPart(ch
)) {
559 id
+= String
.fromCharCode(ch
);
561 // '\u' (U+005C, U+0075) denotes an escaped character.
563 id
= id
.substr(0, id
.length
- 1);
564 if (source
.charCodeAt(index
) !== 0x75) {
565 throwError({}, Messages
.UnexpectedToken
, 'ILLEGAL');
568 ch
= scanHexEscape('u');
569 if (!ch
|| ch
=== '\\' || !isIdentifierPart(ch
.charCodeAt(0))) {
570 throwError({}, Messages
.UnexpectedToken
, 'ILLEGAL');
579 function getIdentifier() {
583 while (index
< length
) {
584 ch
= source
.charCodeAt(index
);
586 // Blackslash (U+005C) marks Unicode escape sequence.
588 return getEscapedIdentifier();
590 if (isIdentifierPart(ch
)) {
597 return source
.slice(start
, index
);
600 function scanIdentifier() {
605 // Backslash (U+005C) starts an escaped character.
606 id
= (source
.charCodeAt(index
) === 0x5C) ? getEscapedIdentifier() : getIdentifier();
608 // There is no keyword or literal with only one character.
609 // Thus, it must be an identifier.
610 if (id
.length
=== 1) {
611 type
= Token
.Identifier
;
612 } else if (isKeyword(id
)) {
613 type
= Token
.Keyword
;
614 } else if (id
=== 'null') {
615 type
= Token
.NullLiteral
;
616 } else if (id
=== 'true' || id
=== 'false') {
617 type
= Token
.BooleanLiteral
;
619 type
= Token
.Identifier
;
625 lineNumber
: lineNumber
,
626 lineStart
: lineStart
,
635 function scanPunctuator() {
637 code
= source
.charCodeAt(index
),
646 // Check for most common single-character punctuators.
648 case 0x28: // ( open bracket
649 case 0x29: // ) close bracket
650 case 0x3B: // ; semicolon
651 case 0x2C: // , comma
652 case 0x7B: // { open curly brace
653 case 0x7D: // } close curly brace
660 if (extra
.tokenize
) {
662 extra
.openParenToken
= extra
.tokens
.length
;
663 } else if (code
=== 0x7B) {
664 extra
.openCurlyToken
= extra
.tokens
.length
;
668 type
: Token
.Punctuator
,
669 value
: String
.fromCharCode(code
),
670 lineNumber
: lineNumber
,
671 lineStart
: lineStart
,
677 code2
= source
.charCodeAt(index
+ 1);
679 // '=' (U+003D) marks an assignment or comparison operator.
680 if (code2
=== 0x3D) {
694 type
: Token
.Punctuator
,
695 value
: String
.fromCharCode(code
) + String
.fromCharCode(code2
),
696 lineNumber
: lineNumber
,
697 lineStart
: lineStart
,
707 if (source
.charCodeAt(index
) === 0x3D) {
711 type
: Token
.Punctuator
,
712 value
: source
.slice(start
, index
),
713 lineNumber
: lineNumber
,
714 lineStart
: lineStart
,
722 // 4-character punctuator: >>>=
724 ch4
= source
.substr(index
, 4);
726 if (ch4
=== '>>>=') {
729 type
: Token
.Punctuator
,
731 lineNumber
: lineNumber
,
732 lineStart
: lineStart
,
738 // 3-character punctuators: === !== >>> <<= >>=
740 ch3
= ch4
.substr(0, 3);
742 if (ch3
=== '>>>' || ch3
=== '<<=' || ch3
=== '>>=') {
745 type
: Token
.Punctuator
,
747 lineNumber
: lineNumber
,
748 lineStart
: lineStart
,
754 // Other 2-character punctuators: ++ -- << >> && ||
755 ch2
= ch3
.substr(0, 2);
757 if ((ch1
=== ch2
[1] && ('+-<>&|'.indexOf(ch1
) >= 0)) || ch2
=== '=>') {
760 type
: Token
.Punctuator
,
762 lineNumber
: lineNumber
,
763 lineStart
: lineStart
,
769 // 1-character punctuators: < > = ! + - * % & | ^ /
770 if ('<>=!+-*%&|^/'.indexOf(ch1
) >= 0) {
773 type
: Token
.Punctuator
,
775 lineNumber
: lineNumber
,
776 lineStart
: lineStart
,
782 throwError({}, Messages
.UnexpectedToken
, 'ILLEGAL');
785 // 7.8.3 Numeric Literals
787 function scanHexLiteral(start
) {
790 while (index
< length
) {
791 if (!isHexDigit(source
[index
])) {
794 number
+= source
[index
++];
797 if (number
.length
=== 0) {
798 throwError({}, Messages
.UnexpectedToken
, 'ILLEGAL');
801 if (isIdentifierStart(source
.charCodeAt(index
))) {
802 throwError({}, Messages
.UnexpectedToken
, 'ILLEGAL');
806 type
: Token
.NumericLiteral
,
807 value
: parseInt('0x' + number
, 16),
808 lineNumber
: lineNumber
,
809 lineStart
: lineStart
,
815 function scanOctalLiteral(start
) {
816 var number
= '0' + source
[index
++];
817 while (index
< length
) {
818 if (!isOctalDigit(source
[index
])) {
821 number
+= source
[index
++];
824 if (isIdentifierStart(source
.charCodeAt(index
)) || isDecimalDigit(source
.charCodeAt(index
))) {
825 throwError({}, Messages
.UnexpectedToken
, 'ILLEGAL');
829 type
: Token
.NumericLiteral
,
830 value
: parseInt(number
, 8),
832 lineNumber
: lineNumber
,
833 lineStart
: lineStart
,
839 function scanNumericLiteral() {
840 var number
, start
, ch
;
843 assert(isDecimalDigit(ch
.charCodeAt(0)) || (ch
=== '.'),
844 'Numeric literal must start with a decimal digit or a decimal point');
849 number
= source
[index
++];
852 // Hex number starts with '0x'.
853 // Octal number starts with '0'.
854 if (number
=== '0') {
855 if (ch
=== 'x' || ch
=== 'X') {
857 return scanHexLiteral(start
);
859 if (isOctalDigit(ch
)) {
860 return scanOctalLiteral(start
);
863 // decimal number starts with '0' such as '09' is illegal.
864 if (ch
&& isDecimalDigit(ch
.charCodeAt(0))) {
865 throwError({}, Messages
.UnexpectedToken
, 'ILLEGAL');
869 while (isDecimalDigit(source
.charCodeAt(index
))) {
870 number
+= source
[index
++];
876 number
+= source
[index
++];
877 while (isDecimalDigit(source
.charCodeAt(index
))) {
878 number
+= source
[index
++];
883 if (ch
=== 'e' || ch
=== 'E') {
884 number
+= source
[index
++];
887 if (ch
=== '+' || ch
=== '-') {
888 number
+= source
[index
++];
890 if (isDecimalDigit(source
.charCodeAt(index
))) {
891 while (isDecimalDigit(source
.charCodeAt(index
))) {
892 number
+= source
[index
++];
895 throwError({}, Messages
.UnexpectedToken
, 'ILLEGAL');
899 if (isIdentifierStart(source
.charCodeAt(index
))) {
900 throwError({}, Messages
.UnexpectedToken
, 'ILLEGAL');
904 type
: Token
.NumericLiteral
,
905 value
: parseFloat(number
),
906 lineNumber
: lineNumber
,
907 lineStart
: lineStart
,
913 // 7.8.4 String Literals
915 function scanStringLiteral() {
916 var str
= '', quote
, start
, ch
, code
, unescaped
, restore
, octal
= false, startLineNumber
, startLineStart
;
917 startLineNumber
= lineNumber
;
918 startLineStart
= lineStart
;
920 quote
= source
[index
];
921 assert((quote
=== '\'' || quote
=== '"'),
922 'String literal must starts with a quote');
927 while (index
< length
) {
928 ch
= source
[index
++];
933 } else if (ch
=== '\\') {
934 ch
= source
[index
++];
935 if (!ch
|| !isLineTerminator(ch
.charCodeAt(0))) {
940 unescaped
= scanHexEscape(ch
);
968 if (isOctalDigit(ch
)) {
969 code
= '01234567'.indexOf(ch
);
971 // \0 is not octal escape sequence
976 if (index
< length
&& isOctalDigit(source
[index
])) {
978 code
= code
* 8 + '01234567'.indexOf(source
[index
++]);
980 // 3 digits are only allowed when string starts
982 if ('0123'.indexOf(ch
) >= 0 &&
984 isOctalDigit(source
[index
])) {
985 code
= code
* 8 + '01234567'.indexOf(source
[index
++]);
988 str
+= String
.fromCharCode(code
);
996 if (ch
=== '\r' && source
[index
] === '\n') {
1001 } else if (isLineTerminator(ch
.charCodeAt(0))) {
1009 throwError({}, Messages
.UnexpectedToken
, 'ILLEGAL');
1013 type
: Token
.StringLiteral
,
1016 startLineNumber
: startLineNumber
,
1017 startLineStart
: startLineStart
,
1018 lineNumber
: lineNumber
,
1019 lineStart
: lineStart
,
1025 function testRegExp(pattern
, flags
) {
1028 value
= new RegExp(pattern
, flags
);
1030 throwError({}, Messages
.InvalidRegExp
);
1035 function scanRegExpBody() {
1036 var ch
, str
, classMarker
, terminated
, body
;
1039 assert(ch
=== '/', 'Regular expression literal must start with a slash');
1040 str
= source
[index
++];
1042 classMarker
= false;
1044 while (index
< length
) {
1045 ch
= source
[index
++];
1048 ch
= source
[index
++];
1050 if (isLineTerminator(ch
.charCodeAt(0))) {
1051 throwError({}, Messages
.UnterminatedRegExp
);
1054 } else if (isLineTerminator(ch
.charCodeAt(0))) {
1055 throwError({}, Messages
.UnterminatedRegExp
);
1056 } else if (classMarker
) {
1058 classMarker
= false;
1064 } else if (ch
=== '[') {
1071 throwError({}, Messages
.UnterminatedRegExp
);
1074 // Exclude leading and trailing slash.
1075 body
= str
.substr(1, str
.length
- 2);
1082 function scanRegExpFlags() {
1083 var ch
, str
, flags
, restore
;
1087 while (index
< length
) {
1089 if (!isIdentifierPart(ch
.charCodeAt(0))) {
1094 if (ch
=== '\\' && index
< length
) {
1099 ch
= scanHexEscape('u');
1102 for (str
+= '\\u'; restore
< index
; ++restore
) {
1103 str
+= source
[restore
];
1110 throwErrorTolerant({}, Messages
.UnexpectedToken
, 'ILLEGAL');
1113 throwErrorTolerant({}, Messages
.UnexpectedToken
, 'ILLEGAL');
1127 function scanRegExp() {
1128 var start
, body
, flags
, pattern
, value
;
1134 body
= scanRegExpBody();
1135 flags
= scanRegExpFlags();
1136 value
= testRegExp(body
.value
, flags
.value
);
1138 if (extra
.tokenize
) {
1140 type
: Token
.RegularExpression
,
1142 lineNumber
: lineNumber
,
1143 lineStart
: lineStart
,
1150 literal
: body
.literal
+ flags
.literal
,
1157 function collectRegex() {
1158 var pos
, loc
, regex
, token
;
1166 column
: index
- lineStart
1170 regex
= scanRegExp();
1173 column
: index
- lineStart
1176 /* istanbul ignore next */
1177 if (!extra
.tokenize
) {
1178 // Pop the previous token, which is likely '/' or '/='
1179 if (extra
.tokens
.length
> 0) {
1180 token
= extra
.tokens
[extra
.tokens
.length
- 1];
1181 if (token
.range
[0] === pos
&& token
.type
=== 'Punctuator') {
1182 if (token
.value
=== '/' || token
.value
=== '/=') {
1189 type
: 'RegularExpression',
1190 value
: regex
.literal
,
1191 range
: [pos
, index
],
1199 function isIdentifierName(token
) {
1200 return token
.type
=== Token
.Identifier
||
1201 token
.type
=== Token
.Keyword
||
1202 token
.type
=== Token
.BooleanLiteral
||
1203 token
.type
=== Token
.NullLiteral
;
1206 function advanceSlash() {
1209 // Using the following algorithm:
1210 // https://github.com/mozilla/sweet.js/wiki/design
1211 prevToken
= extra
.tokens
[extra
.tokens
.length
- 1];
1213 // Nothing before that: it cannot be a division.
1214 return collectRegex();
1216 if (prevToken
.type
=== 'Punctuator') {
1217 if (prevToken
.value
=== ']') {
1218 return scanPunctuator();
1220 if (prevToken
.value
=== ')') {
1221 checkToken
= extra
.tokens
[extra
.openParenToken
- 1];
1223 checkToken
.type
=== 'Keyword' &&
1224 (checkToken
.value
=== 'if' ||
1225 checkToken
.value
=== 'while' ||
1226 checkToken
.value
=== 'for' ||
1227 checkToken
.value
=== 'with')) {
1228 return collectRegex();
1230 return scanPunctuator();
1232 if (prevToken
.value
=== '}') {
1233 // Dividing a function by anything makes little sense,
1234 // but we have to check for that.
1235 if (extra
.tokens
[extra
.openCurlyToken
- 3] &&
1236 extra
.tokens
[extra
.openCurlyToken
- 3].type
=== 'Keyword') {
1237 // Anonymous function.
1238 checkToken
= extra
.tokens
[extra
.openCurlyToken
- 4];
1240 return scanPunctuator();
1242 } else if (extra
.tokens
[extra
.openCurlyToken
- 4] &&
1243 extra
.tokens
[extra
.openCurlyToken
- 4].type
=== 'Keyword') {
1245 checkToken
= extra
.tokens
[extra
.openCurlyToken
- 5];
1247 return collectRegex();
1250 return scanPunctuator();
1252 // checkToken determines whether the function is
1253 // a declaration or an expression.
1254 if (FnExprTokens
.indexOf(checkToken
.value
) >= 0) {
1255 // It is an expression.
1256 return scanPunctuator();
1258 // It is a declaration.
1259 return collectRegex();
1261 return collectRegex();
1263 if (prevToken
.type
=== 'Keyword') {
1264 return collectRegex();
1266 return scanPunctuator();
1269 function advance() {
1274 if (index
>= length
) {
1277 lineNumber
: lineNumber
,
1278 lineStart
: lineStart
,
1284 ch
= source
.charCodeAt(index
);
1286 if (isIdentifierStart(ch
)) {
1287 return scanIdentifier();
1290 // Very common: ( and ) and ;
1291 if (ch
=== 0x28 || ch
=== 0x29 || ch
=== 0x3B) {
1292 return scanPunctuator();
1295 // String literal starts with single quote (U+0027) or double quote (U+0022).
1296 if (ch
=== 0x27 || ch
=== 0x22) {
1297 return scanStringLiteral();
1301 // Dot (.) U+002E can also start a floating-point number, hence the need
1302 // to check the next character.
1304 if (isDecimalDigit(source
.charCodeAt(index
+ 1))) {
1305 return scanNumericLiteral();
1307 return scanPunctuator();
1310 if (isDecimalDigit(ch
)) {
1311 return scanNumericLiteral();
1314 // Slash (/) U+002F can also start a regex.
1315 if (extra
.tokenize
&& ch
=== 0x2F) {
1316 return advanceSlash();
1319 return scanPunctuator();
1322 function collectToken() {
1323 var loc
, token
, range
, value
;
1329 column
: index
- lineStart
1336 column
: index
- lineStart
1339 if (token
.type
!== Token
.EOF
) {
1340 value
= source
.slice(token
.start
, token
.end
);
1342 type
: TokenName
[token
.type
],
1344 range
: [token
.start
, token
.end
],
1357 lineNumber
= token
.lineNumber
;
1358 lineStart
= token
.lineStart
;
1360 lookahead
= (typeof extra
.tokens
!== 'undefined') ? collectToken() : advance();
1363 lineNumber
= token
.lineNumber
;
1364 lineStart
= token
.lineStart
;
1370 var pos
, line
, start
;
1375 lookahead
= (typeof extra
.tokens
!== 'undefined') ? collectToken() : advance();
1381 function Position(line
, column
) {
1383 this.column
= column
;
1386 function SourceLocation(startLine
, startColumn
, line
, column
) {
1387 this.start
= new Position(startLine
, startColumn
);
1388 this.end
= new Position(line
, column
);
1391 SyntaxTreeDelegate
= {
1395 processComment: function (node
) {
1396 var lastChild
, trailingComments
;
1398 if (node
.type
=== Syntax
.Program
) {
1399 if (node
.body
.length
> 0) {
1404 if (extra
.trailingComments
.length
> 0) {
1405 if (extra
.trailingComments
[0].range
[0] >= node
.range
[1]) {
1406 trailingComments
= extra
.trailingComments
;
1407 extra
.trailingComments
= [];
1409 extra
.trailingComments
.length
= 0;
1412 if (extra
.bottomRightStack
.length
> 0 &&
1413 extra
.bottomRightStack
[extra
.bottomRightStack
.length
- 1].trailingComments
&&
1414 extra
.bottomRightStack
[extra
.bottomRightStack
.length
- 1].trailingComments
[0].range
[0] >= node
.range
[1]) {
1415 trailingComments
= extra
.bottomRightStack
[extra
.bottomRightStack
.length
- 1].trailingComments
;
1416 delete extra
.bottomRightStack
[extra
.bottomRightStack
.length
- 1].trailingComments
;
1420 // Eating the stack.
1421 while (extra
.bottomRightStack
.length
> 0 && extra
.bottomRightStack
[extra
.bottomRightStack
.length
- 1].range
[0] >= node
.range
[0]) {
1422 lastChild
= extra
.bottomRightStack
.pop();
1426 if (lastChild
.leadingComments
&& lastChild
.leadingComments
[lastChild
.leadingComments
.length
- 1].range
[1] <= node
.range
[0]) {
1427 node
.leadingComments
= lastChild
.leadingComments
;
1428 delete lastChild
.leadingComments
;
1430 } else if (extra
.leadingComments
.length
> 0 && extra
.leadingComments
[extra
.leadingComments
.length
- 1].range
[1] <= node
.range
[0]) {
1431 node
.leadingComments
= extra
.leadingComments
;
1432 extra
.leadingComments
= [];
1436 if (trailingComments
) {
1437 node
.trailingComments
= trailingComments
;
1440 extra
.bottomRightStack
.push(node
);
1443 markEnd: function (node
, startToken
) {
1445 node
.range
= [startToken
.start
, index
];
1448 node
.loc
= new SourceLocation(
1449 startToken
.startLineNumber
=== undefined ? startToken
.lineNumber
: startToken
.startLineNumber
,
1450 startToken
.start
- (startToken
.startLineStart
=== undefined ? startToken
.lineStart
: startToken
.startLineStart
),
1454 this.postProcess(node
);
1457 if (extra
.attachComment
) {
1458 this.processComment(node
);
1463 postProcess: function (node
) {
1465 node
.loc
.source
= extra
.source
;
1470 createArrayExpression: function (elements
) {
1472 type
: Syntax
.ArrayExpression
,
1477 createAssignmentExpression: function (operator
, left
, right
) {
1479 type
: Syntax
.AssignmentExpression
,
1486 createBinaryExpression: function (operator
, left
, right
) {
1487 var type
= (operator
=== '||' || operator
=== '&&') ? Syntax
.LogicalExpression
:
1488 Syntax
.BinaryExpression
;
1497 createBlockStatement: function (body
) {
1499 type
: Syntax
.BlockStatement
,
1504 createBreakStatement: function (label
) {
1506 type
: Syntax
.BreakStatement
,
1511 createCallExpression: function (callee
, args
) {
1513 type
: Syntax
.CallExpression
,
1519 createCatchClause: function (param
, body
) {
1521 type
: Syntax
.CatchClause
,
1527 createConditionalExpression: function (test
, consequent
, alternate
) {
1529 type
: Syntax
.ConditionalExpression
,
1531 consequent
: consequent
,
1532 alternate
: alternate
1536 createContinueStatement: function (label
) {
1538 type
: Syntax
.ContinueStatement
,
1543 createDebuggerStatement: function () {
1545 type
: Syntax
.DebuggerStatement
1549 createDoWhileStatement: function (body
, test
) {
1551 type
: Syntax
.DoWhileStatement
,
1557 createEmptyStatement: function () {
1559 type
: Syntax
.EmptyStatement
1563 createExpressionStatement: function (expression
) {
1565 type
: Syntax
.ExpressionStatement
,
1566 expression
: expression
1570 createForStatement: function (init
, test
, update
, body
) {
1572 type
: Syntax
.ForStatement
,
1580 createForInStatement: function (left
, right
, body
) {
1582 type
: Syntax
.ForInStatement
,
1590 createFunctionDeclaration: function (id
, params
, defaults
, body
) {
1592 type
: Syntax
.FunctionDeclaration
,
1603 createFunctionExpression: function (id
, params
, defaults
, body
) {
1605 type
: Syntax
.FunctionExpression
,
1616 createIdentifier: function (name
) {
1618 type
: Syntax
.Identifier
,
1623 createIfStatement: function (test
, consequent
, alternate
) {
1625 type
: Syntax
.IfStatement
,
1627 consequent
: consequent
,
1628 alternate
: alternate
1632 createLabeledStatement: function (label
, body
) {
1634 type
: Syntax
.LabeledStatement
,
1640 createLiteral: function (token
) {
1642 type
: Syntax
.Literal
,
1644 raw
: source
.slice(token
.start
, token
.end
)
1648 createMemberExpression: function (accessor
, object
, property
) {
1650 type
: Syntax
.MemberExpression
,
1651 computed
: accessor
=== '[',
1657 createNewExpression: function (callee
, args
) {
1659 type
: Syntax
.NewExpression
,
1665 createObjectExpression: function (properties
) {
1667 type
: Syntax
.ObjectExpression
,
1668 properties
: properties
1672 createPostfixExpression: function (operator
, argument
) {
1674 type
: Syntax
.UpdateExpression
,
1681 createProgram: function (body
) {
1683 type
: Syntax
.Program
,
1688 createProperty: function (kind
, key
, value
) {
1690 type
: Syntax
.Property
,
1697 createReturnStatement: function (argument
) {
1699 type
: Syntax
.ReturnStatement
,
1704 createSequenceExpression: function (expressions
) {
1706 type
: Syntax
.SequenceExpression
,
1707 expressions
: expressions
1711 createSwitchCase: function (test
, consequent
) {
1713 type
: Syntax
.SwitchCase
,
1715 consequent
: consequent
1719 createSwitchStatement: function (discriminant
, cases
) {
1721 type
: Syntax
.SwitchStatement
,
1722 discriminant
: discriminant
,
1727 createThisExpression: function () {
1729 type
: Syntax
.ThisExpression
1733 createThrowStatement: function (argument
) {
1735 type
: Syntax
.ThrowStatement
,
1740 createTryStatement: function (block
, guardedHandlers
, handlers
, finalizer
) {
1742 type
: Syntax
.TryStatement
,
1744 guardedHandlers
: guardedHandlers
,
1746 finalizer
: finalizer
1750 createUnaryExpression: function (operator
, argument
) {
1751 if (operator
=== '++' || operator
=== '--') {
1753 type
: Syntax
.UpdateExpression
,
1760 type
: Syntax
.UnaryExpression
,
1767 createVariableDeclaration: function (declarations
, kind
) {
1769 type
: Syntax
.VariableDeclaration
,
1770 declarations
: declarations
,
1775 createVariableDeclarator: function (id
, init
) {
1777 type
: Syntax
.VariableDeclarator
,
1783 createWhileStatement: function (test
, body
) {
1785 type
: Syntax
.WhileStatement
,
1791 createWithStatement: function (object
, body
) {
1793 type
: Syntax
.WithStatement
,
1800 // Return true if there is a line terminator before the next token.
1802 function peekLineTerminator() {
1803 var pos
, line
, start
, found
;
1809 found
= lineNumber
!== line
;
1817 // Throw an exception
1819 function throwError(token
, messageFormat
) {
1821 args
= Array
.prototype.slice
.call(arguments
, 2),
1822 msg
= messageFormat
.replace(
1824 function (whole
, index
) {
1825 assert(index
< args
.length
, 'Message reference must be in range');
1830 if (typeof token
.lineNumber
=== 'number') {
1831 error
= new Error('Line ' + token
.lineNumber
+ ': ' + msg
);
1832 error
.index
= token
.start
;
1833 error
.lineNumber
= token
.lineNumber
;
1834 error
.column
= token
.start
- lineStart
+ 1;
1836 error
= new Error('Line ' + lineNumber
+ ': ' + msg
);
1837 error
.index
= index
;
1838 error
.lineNumber
= lineNumber
;
1839 error
.column
= index
- lineStart
+ 1;
1842 error
.description
= msg
;
1846 function throwErrorTolerant() {
1848 throwError
.apply(null, arguments
);
1851 extra
.errors
.push(e
);
1859 // Throw an exception because of the token.
1861 function throwUnexpected(token
) {
1862 if (token
.type
=== Token
.EOF
) {
1863 throwError(token
, Messages
.UnexpectedEOS
);
1866 if (token
.type
=== Token
.NumericLiteral
) {
1867 throwError(token
, Messages
.UnexpectedNumber
);
1870 if (token
.type
=== Token
.StringLiteral
) {
1871 throwError(token
, Messages
.UnexpectedString
);
1874 if (token
.type
=== Token
.Identifier
) {
1875 throwError(token
, Messages
.UnexpectedIdentifier
);
1878 if (token
.type
=== Token
.Keyword
) {
1879 if (isFutureReservedWord(token
.value
)) {
1880 throwError(token
, Messages
.UnexpectedReserved
);
1881 } else if (strict
&& isStrictModeReservedWord(token
.value
)) {
1882 throwErrorTolerant(token
, Messages
.StrictReservedWord
);
1885 throwError(token
, Messages
.UnexpectedToken
, token
.value
);
1888 // BooleanLiteral, NullLiteral, or Punctuator.
1889 throwError(token
, Messages
.UnexpectedToken
, token
.value
);
1892 // Expect the next token to match the specified punctuator.
1893 // If not, an exception will be thrown.
1895 function expect(value
) {
1897 if (token
.type
!== Token
.Punctuator
|| token
.value
!== value
) {
1898 throwUnexpected(token
);
1902 // Expect the next token to match the specified keyword.
1903 // If not, an exception will be thrown.
1905 function expectKeyword(keyword
) {
1907 if (token
.type
!== Token
.Keyword
|| token
.value
!== keyword
) {
1908 throwUnexpected(token
);
1912 // Return true if the next token matches the specified punctuator.
1914 function match(value
) {
1915 return lookahead
.type
=== Token
.Punctuator
&& lookahead
.value
=== value
;
1918 // Return true if the next token matches the specified keyword
1920 function matchKeyword(keyword
) {
1921 return lookahead
.type
=== Token
.Keyword
&& lookahead
.value
=== keyword
;
1924 // Return true if the next token is an assignment operator
1926 function matchAssign() {
1929 if (lookahead
.type
!== Token
.Punctuator
) {
1932 op
= lookahead
.value
;
1933 return op
=== '=' ||
1947 function consumeSemicolon() {
1950 // Catch the very common case first: immediately a semicolon (U+003B).
1951 if (source
.charCodeAt(index
) === 0x3B || match(';')) {
1958 if (lineNumber
!== line
) {
1962 if (lookahead
.type
!== Token
.EOF
&& !match('}')) {
1963 throwUnexpected(lookahead
);
1967 // Return true if provided expression is LeftHandSideExpression
1969 function isLeftHandSide(expr
) {
1970 return expr
.type
=== Syntax
.Identifier
|| expr
.type
=== Syntax
.MemberExpression
;
1973 // 11.1.4 Array Initialiser
1975 function parseArrayInitialiser() {
1976 var elements
= [], startToken
;
1978 startToken
= lookahead
;
1981 while (!match(']')) {
1984 elements
.push(null);
1986 elements
.push(parseAssignmentExpression());
1996 return delegate
.markEnd(delegate
.createArrayExpression(elements
), startToken
);
1999 // 11.1.5 Object Initialiser
2001 function parsePropertyFunction(param
, first
) {
2002 var previousStrict
, body
, startToken
;
2004 previousStrict
= strict
;
2005 startToken
= lookahead
;
2006 body
= parseFunctionSourceElements();
2007 if (first
&& strict
&& isRestrictedWord(param
[0].name
)) {
2008 throwErrorTolerant(first
, Messages
.StrictParamName
);
2010 strict
= previousStrict
;
2011 return delegate
.markEnd(delegate
.createFunctionExpression(null, param
, [], body
), startToken
);
2014 function parseObjectPropertyKey() {
2015 var token
, startToken
;
2017 startToken
= lookahead
;
2020 // Note: This function is called only from parseObjectProperty(), where
2021 // EOF and Punctuator tokens are already filtered out.
2023 if (token
.type
=== Token
.StringLiteral
|| token
.type
=== Token
.NumericLiteral
) {
2024 if (strict
&& token
.octal
) {
2025 throwErrorTolerant(token
, Messages
.StrictOctalLiteral
);
2027 return delegate
.markEnd(delegate
.createLiteral(token
), startToken
);
2030 return delegate
.markEnd(delegate
.createIdentifier(token
.value
), startToken
);
2033 function parseObjectProperty() {
2034 var token
, key
, id
, value
, param
, startToken
;
2037 startToken
= lookahead
;
2039 if (token
.type
=== Token
.Identifier
) {
2041 id
= parseObjectPropertyKey();
2043 // Property Assignment: Getter and Setter.
2045 if (token
.value
=== 'get' && !match(':')) {
2046 key
= parseObjectPropertyKey();
2049 value
= parsePropertyFunction([]);
2050 return delegate
.markEnd(delegate
.createProperty('get', key
, value
), startToken
);
2052 if (token
.value
=== 'set' && !match(':')) {
2053 key
= parseObjectPropertyKey();
2056 if (token
.type
!== Token
.Identifier
) {
2058 throwErrorTolerant(token
, Messages
.UnexpectedToken
, token
.value
);
2059 value
= parsePropertyFunction([]);
2061 param
= [ parseVariableIdentifier() ];
2063 value
= parsePropertyFunction(param
, token
);
2065 return delegate
.markEnd(delegate
.createProperty('set', key
, value
), startToken
);
2068 value
= parseAssignmentExpression();
2069 return delegate
.markEnd(delegate
.createProperty('init', id
, value
), startToken
);
2071 if (token
.type
=== Token
.EOF
|| token
.type
=== Token
.Punctuator
) {
2072 throwUnexpected(token
);
2074 key
= parseObjectPropertyKey();
2076 value
= parseAssignmentExpression();
2077 return delegate
.markEnd(delegate
.createProperty('init', key
, value
), startToken
);
2081 function parseObjectInitialiser() {
2082 var properties
= [], property
, name
, key
, kind
, map
= {}, toString
= String
, startToken
;
2084 startToken
= lookahead
;
2088 while (!match('}')) {
2089 property
= parseObjectProperty();
2091 if (property
.key
.type
=== Syntax
.Identifier
) {
2092 name
= property
.key
.name
;
2094 name
= toString(property
.key
.value
);
2096 kind
= (property
.kind
=== 'init') ? PropertyKind
.Data
: (property
.kind
=== 'get') ? PropertyKind
.Get
: PropertyKind
.Set
;
2099 if (Object
.prototype.hasOwnProperty
.call(map
, key
)) {
2100 if (map
[key
] === PropertyKind
.Data
) {
2101 if (strict
&& kind
=== PropertyKind
.Data
) {
2102 throwErrorTolerant({}, Messages
.StrictDuplicateProperty
);
2103 } else if (kind
!== PropertyKind
.Data
) {
2104 throwErrorTolerant({}, Messages
.AccessorDataProperty
);
2107 if (kind
=== PropertyKind
.Data
) {
2108 throwErrorTolerant({}, Messages
.AccessorDataProperty
);
2109 } else if (map
[key
] & kind
) {
2110 throwErrorTolerant({}, Messages
.AccessorGetSet
);
2118 properties
.push(property
);
2127 return delegate
.markEnd(delegate
.createObjectExpression(properties
), startToken
);
2130 // 11.1.6 The Grouping Operator
2132 function parseGroupExpression() {
2137 expr
= parseExpression();
2145 // 11.1 Primary Expressions
2147 function parsePrimaryExpression() {
2148 var type
, token
, expr
, startToken
;
2151 return parseGroupExpression();
2155 return parseArrayInitialiser();
2159 return parseObjectInitialiser();
2162 type
= lookahead
.type
;
2163 startToken
= lookahead
;
2165 if (type
=== Token
.Identifier
) {
2166 expr
= delegate
.createIdentifier(lex().value
);
2167 } else if (type
=== Token
.StringLiteral
|| type
=== Token
.NumericLiteral
) {
2168 if (strict
&& lookahead
.octal
) {
2169 throwErrorTolerant(lookahead
, Messages
.StrictOctalLiteral
);
2171 expr
= delegate
.createLiteral(lex());
2172 } else if (type
=== Token
.Keyword
) {
2173 if (matchKeyword('function')) {
2174 return parseFunctionExpression();
2176 if (matchKeyword('this')) {
2178 expr
= delegate
.createThisExpression();
2180 throwUnexpected(lex());
2182 } else if (type
=== Token
.BooleanLiteral
) {
2184 token
.value
= (token
.value
=== 'true');
2185 expr
= delegate
.createLiteral(token
);
2186 } else if (type
=== Token
.NullLiteral
) {
2189 expr
= delegate
.createLiteral(token
);
2190 } else if (match('/') || match('/=')) {
2191 if (typeof extra
.tokens
!== 'undefined') {
2192 expr
= delegate
.createLiteral(collectRegex());
2194 expr
= delegate
.createLiteral(scanRegExp());
2198 throwUnexpected(lex());
2201 return delegate
.markEnd(expr
, startToken
);
2204 // 11.2 Left-Hand-Side Expressions
2206 function parseArguments() {
2212 while (index
< length
) {
2213 args
.push(parseAssignmentExpression());
2226 function parseNonComputedProperty() {
2227 var token
, startToken
;
2229 startToken
= lookahead
;
2232 if (!isIdentifierName(token
)) {
2233 throwUnexpected(token
);
2236 return delegate
.markEnd(delegate
.createIdentifier(token
.value
), startToken
);
2239 function parseNonComputedMember() {
2242 return parseNonComputedProperty();
2245 function parseComputedMember() {
2250 expr
= parseExpression();
2257 function parseNewExpression() {
2258 var callee
, args
, startToken
;
2260 startToken
= lookahead
;
2261 expectKeyword('new');
2262 callee
= parseLeftHandSideExpression();
2263 args
= match('(') ? parseArguments() : [];
2265 return delegate
.markEnd(delegate
.createNewExpression(callee
, args
), startToken
);
2268 function parseLeftHandSideExpressionAllowCall() {
2269 var previousAllowIn
, expr
, args
, property
, startToken
;
2271 startToken
= lookahead
;
2273 previousAllowIn
= state
.allowIn
;
2274 state
.allowIn
= true;
2275 expr
= matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression();
2276 state
.allowIn
= previousAllowIn
;
2280 property
= parseNonComputedMember();
2281 expr
= delegate
.createMemberExpression('.', expr
, property
);
2282 } else if (match('(')) {
2283 args
= parseArguments();
2284 expr
= delegate
.createCallExpression(expr
, args
);
2285 } else if (match('[')) {
2286 property
= parseComputedMember();
2287 expr
= delegate
.createMemberExpression('[', expr
, property
);
2291 delegate
.markEnd(expr
, startToken
);
2297 function parseLeftHandSideExpression() {
2298 var previousAllowIn
, expr
, property
, startToken
;
2300 startToken
= lookahead
;
2302 previousAllowIn
= state
.allowIn
;
2303 expr
= matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression();
2304 state
.allowIn
= previousAllowIn
;
2306 while (match('.') || match('[')) {
2308 property
= parseComputedMember();
2309 expr
= delegate
.createMemberExpression('[', expr
, property
);
2311 property
= parseNonComputedMember();
2312 expr
= delegate
.createMemberExpression('.', expr
, property
);
2314 delegate
.markEnd(expr
, startToken
);
2320 // 11.3 Postfix Expressions
2322 function parsePostfixExpression() {
2323 var expr
, token
, startToken
= lookahead
;
2325 expr
= parseLeftHandSideExpressionAllowCall();
2327 if (lookahead
.type
=== Token
.Punctuator
) {
2328 if ((match('++') || match('--')) && !peekLineTerminator()) {
2330 if (strict
&& expr
.type
=== Syntax
.Identifier
&& isRestrictedWord(expr
.name
)) {
2331 throwErrorTolerant({}, Messages
.StrictLHSPostfix
);
2334 if (!isLeftHandSide(expr
)) {
2335 throwErrorTolerant({}, Messages
.InvalidLHSInAssignment
);
2339 expr
= delegate
.markEnd(delegate
.createPostfixExpression(token
.value
, expr
), startToken
);
2346 // 11.4 Unary Operators
2348 function parseUnaryExpression() {
2349 var token
, expr
, startToken
;
2351 if (lookahead
.type
!== Token
.Punctuator
&& lookahead
.type
!== Token
.Keyword
) {
2352 expr
= parsePostfixExpression();
2353 } else if (match('++') || match('--')) {
2354 startToken
= lookahead
;
2356 expr
= parseUnaryExpression();
2358 if (strict
&& expr
.type
=== Syntax
.Identifier
&& isRestrictedWord(expr
.name
)) {
2359 throwErrorTolerant({}, Messages
.StrictLHSPrefix
);
2362 if (!isLeftHandSide(expr
)) {
2363 throwErrorTolerant({}, Messages
.InvalidLHSInAssignment
);
2366 expr
= delegate
.createUnaryExpression(token
.value
, expr
);
2367 expr
= delegate
.markEnd(expr
, startToken
);
2368 } else if (match('+') || match('-') || match('~') || match('!')) {
2369 startToken
= lookahead
;
2371 expr
= parseUnaryExpression();
2372 expr
= delegate
.createUnaryExpression(token
.value
, expr
);
2373 expr
= delegate
.markEnd(expr
, startToken
);
2374 } else if (matchKeyword('delete') || matchKeyword('void') || matchKeyword('typeof')) {
2375 startToken
= lookahead
;
2377 expr
= parseUnaryExpression();
2378 expr
= delegate
.createUnaryExpression(token
.value
, expr
);
2379 expr
= delegate
.markEnd(expr
, startToken
);
2380 if (strict
&& expr
.operator
=== 'delete' && expr
.argument
.type
=== Syntax
.Identifier
) {
2381 throwErrorTolerant({}, Messages
.StrictDelete
);
2384 expr
= parsePostfixExpression();
2390 function binaryPrecedence(token
, allowIn
) {
2393 if (token
.type
!== Token
.Punctuator
&& token
.type
!== Token
.Keyword
) {
2397 switch (token
.value
) {
2434 prec
= allowIn
? 7 : 0;
2461 // 11.5 Multiplicative Operators
2462 // 11.6 Additive Operators
2463 // 11.7 Bitwise Shift Operators
2464 // 11.8 Relational Operators
2465 // 11.9 Equality Operators
2466 // 11.10 Binary Bitwise Operators
2467 // 11.11 Binary Logical Operators
2469 function parseBinaryExpression() {
2470 var marker
, markers
, expr
, token
, prec
, stack
, right
, operator
, left
, i
;
2473 left
= parseUnaryExpression();
2476 prec
= binaryPrecedence(token
, state
.allowIn
);
2483 markers
= [marker
, lookahead
];
2484 right
= parseUnaryExpression();
2486 stack
= [left
, token
, right
];
2488 while ((prec
= binaryPrecedence(lookahead
, state
.allowIn
)) > 0) {
2490 // Reduce: make a binary expression from the three topmost entries.
2491 while ((stack
.length
> 2) && (prec
<= stack
[stack
.length
- 2].prec
)) {
2492 right
= stack
.pop();
2493 operator
= stack
.pop().value
;
2495 expr
= delegate
.createBinaryExpression(operator
, left
, right
);
2497 marker
= markers
[markers
.length
- 1];
2498 delegate
.markEnd(expr
, marker
);
2506 markers
.push(lookahead
);
2507 expr
= parseUnaryExpression();
2511 // Final reduce to clean-up the stack.
2512 i
= stack
.length
- 1;
2516 expr
= delegate
.createBinaryExpression(stack
[i
- 1].value
, stack
[i
- 2], expr
);
2518 marker
= markers
.pop();
2519 delegate
.markEnd(expr
, marker
);
2526 // 11.12 Conditional Operator
2528 function parseConditionalExpression() {
2529 var expr
, previousAllowIn
, consequent
, alternate
, startToken
;
2531 startToken
= lookahead
;
2533 expr
= parseBinaryExpression();
2537 previousAllowIn
= state
.allowIn
;
2538 state
.allowIn
= true;
2539 consequent
= parseAssignmentExpression();
2540 state
.allowIn
= previousAllowIn
;
2542 alternate
= parseAssignmentExpression();
2544 expr
= delegate
.createConditionalExpression(expr
, consequent
, alternate
);
2545 delegate
.markEnd(expr
, startToken
);
2551 // 11.13 Assignment Operators
2553 function parseAssignmentExpression() {
2554 var token
, left
, right
, node
, startToken
;
2557 startToken
= lookahead
;
2559 node
= left
= parseConditionalExpression();
2561 if (matchAssign()) {
2562 // LeftHandSideExpression
2563 if (!isLeftHandSide(left
)) {
2564 throwErrorTolerant({}, Messages
.InvalidLHSInAssignment
);
2568 if (strict
&& left
.type
=== Syntax
.Identifier
&& isRestrictedWord(left
.name
)) {
2569 throwErrorTolerant(token
, Messages
.StrictLHSAssignment
);
2573 right
= parseAssignmentExpression();
2574 node
= delegate
.markEnd(delegate
.createAssignmentExpression(token
.value
, left
, right
), startToken
);
2580 // 11.14 Comma Operator
2582 function parseExpression() {
2583 var expr
, startToken
= lookahead
;
2585 expr
= parseAssignmentExpression();
2588 expr
= delegate
.createSequenceExpression([ expr
]);
2590 while (index
< length
) {
2595 expr
.expressions
.push(parseAssignmentExpression());
2598 delegate
.markEnd(expr
, startToken
);
2606 function parseStatementList() {
2610 while (index
< length
) {
2614 statement
= parseSourceElement();
2615 if (typeof statement
=== 'undefined') {
2618 list
.push(statement
);
2624 function parseBlock() {
2625 var block
, startToken
;
2627 startToken
= lookahead
;
2630 block
= parseStatementList();
2634 return delegate
.markEnd(delegate
.createBlockStatement(block
), startToken
);
2637 // 12.2 Variable Statement
2639 function parseVariableIdentifier() {
2640 var token
, startToken
;
2642 startToken
= lookahead
;
2645 if (token
.type
!== Token
.Identifier
) {
2646 throwUnexpected(token
);
2649 return delegate
.markEnd(delegate
.createIdentifier(token
.value
), startToken
);
2652 function parseVariableDeclaration(kind
) {
2653 var init
= null, id
, startToken
;
2655 startToken
= lookahead
;
2656 id
= parseVariableIdentifier();
2659 if (strict
&& isRestrictedWord(id
.name
)) {
2660 throwErrorTolerant({}, Messages
.StrictVarName
);
2663 if (kind
=== 'const') {
2665 init
= parseAssignmentExpression();
2666 } else if (match('=')) {
2668 init
= parseAssignmentExpression();
2671 return delegate
.markEnd(delegate
.createVariableDeclarator(id
, init
), startToken
);
2674 function parseVariableDeclarationList(kind
) {
2678 list
.push(parseVariableDeclaration(kind
));
2683 } while (index
< length
);
2688 function parseVariableStatement() {
2691 expectKeyword('var');
2693 declarations
= parseVariableDeclarationList();
2697 return delegate
.createVariableDeclaration(declarations
, 'var');
2700 // kind may be `const` or `let`
2701 // Both are experimental and not in the specification yet.
2702 // see http://wiki.ecmascript.org/doku.php?id=harmony:const
2703 // and http://wiki.ecmascript.org/doku.php?id=harmony:let
2704 function parseConstLetDeclaration(kind
) {
2705 var declarations
, startToken
;
2707 startToken
= lookahead
;
2709 expectKeyword(kind
);
2711 declarations
= parseVariableDeclarationList(kind
);
2715 return delegate
.markEnd(delegate
.createVariableDeclaration(declarations
, kind
), startToken
);
2718 // 12.3 Empty Statement
2720 function parseEmptyStatement() {
2722 return delegate
.createEmptyStatement();
2725 // 12.4 Expression Statement
2727 function parseExpressionStatement() {
2728 var expr
= parseExpression();
2730 return delegate
.createExpressionStatement(expr
);
2733 // 12.5 If statement
2735 function parseIfStatement() {
2736 var test
, consequent
, alternate
;
2738 expectKeyword('if');
2742 test
= parseExpression();
2746 consequent
= parseStatement();
2748 if (matchKeyword('else')) {
2750 alternate
= parseStatement();
2755 return delegate
.createIfStatement(test
, consequent
, alternate
);
2758 // 12.6 Iteration Statements
2760 function parseDoWhileStatement() {
2761 var body
, test
, oldInIteration
;
2763 expectKeyword('do');
2765 oldInIteration
= state
.inIteration
;
2766 state
.inIteration
= true;
2768 body
= parseStatement();
2770 state
.inIteration
= oldInIteration
;
2772 expectKeyword('while');
2776 test
= parseExpression();
2784 return delegate
.createDoWhileStatement(body
, test
);
2787 function parseWhileStatement() {
2788 var test
, body
, oldInIteration
;
2790 expectKeyword('while');
2794 test
= parseExpression();
2798 oldInIteration
= state
.inIteration
;
2799 state
.inIteration
= true;
2801 body
= parseStatement();
2803 state
.inIteration
= oldInIteration
;
2805 return delegate
.createWhileStatement(test
, body
);
2808 function parseForVariableDeclaration() {
2809 var token
, declarations
, startToken
;
2811 startToken
= lookahead
;
2813 declarations
= parseVariableDeclarationList();
2815 return delegate
.markEnd(delegate
.createVariableDeclaration(declarations
, token
.value
), startToken
);
2818 function parseForStatement() {
2819 var init
, test
, update
, left
, right
, body
, oldInIteration
;
2821 init
= test
= update
= null;
2823 expectKeyword('for');
2830 if (matchKeyword('var') || matchKeyword('let')) {
2831 state
.allowIn
= false;
2832 init
= parseForVariableDeclaration();
2833 state
.allowIn
= true;
2835 if (init
.declarations
.length
=== 1 && matchKeyword('in')) {
2838 right
= parseExpression();
2842 state
.allowIn
= false;
2843 init
= parseExpression();
2844 state
.allowIn
= true;
2846 if (matchKeyword('in')) {
2847 // LeftHandSideExpression
2848 if (!isLeftHandSide(init
)) {
2849 throwErrorTolerant({}, Messages
.InvalidLHSInForIn
);
2854 right
= parseExpression();
2859 if (typeof left
=== 'undefined') {
2864 if (typeof left
=== 'undefined') {
2867 test
= parseExpression();
2872 update
= parseExpression();
2878 oldInIteration
= state
.inIteration
;
2879 state
.inIteration
= true;
2881 body
= parseStatement();
2883 state
.inIteration
= oldInIteration
;
2885 return (typeof left
=== 'undefined') ?
2886 delegate
.createForStatement(init
, test
, update
, body
) :
2887 delegate
.createForInStatement(left
, right
, body
);
2890 // 12.7 The continue statement
2892 function parseContinueStatement() {
2893 var label
= null, key
;
2895 expectKeyword('continue');
2897 // Optimize the most common form: 'continue;'.
2898 if (source
.charCodeAt(index
) === 0x3B) {
2901 if (!state
.inIteration
) {
2902 throwError({}, Messages
.IllegalContinue
);
2905 return delegate
.createContinueStatement(null);
2908 if (peekLineTerminator()) {
2909 if (!state
.inIteration
) {
2910 throwError({}, Messages
.IllegalContinue
);
2913 return delegate
.createContinueStatement(null);
2916 if (lookahead
.type
=== Token
.Identifier
) {
2917 label
= parseVariableIdentifier();
2919 key
= '$' + label
.name
;
2920 if (!Object
.prototype.hasOwnProperty
.call(state
.labelSet
, key
)) {
2921 throwError({}, Messages
.UnknownLabel
, label
.name
);
2927 if (label
=== null && !state
.inIteration
) {
2928 throwError({}, Messages
.IllegalContinue
);
2931 return delegate
.createContinueStatement(label
);
2934 // 12.8 The break statement
2936 function parseBreakStatement() {
2937 var label
= null, key
;
2939 expectKeyword('break');
2941 // Catch the very common case first: immediately a semicolon (U+003B).
2942 if (source
.charCodeAt(index
) === 0x3B) {
2945 if (!(state
.inIteration
|| state
.inSwitch
)) {
2946 throwError({}, Messages
.IllegalBreak
);
2949 return delegate
.createBreakStatement(null);
2952 if (peekLineTerminator()) {
2953 if (!(state
.inIteration
|| state
.inSwitch
)) {
2954 throwError({}, Messages
.IllegalBreak
);
2957 return delegate
.createBreakStatement(null);
2960 if (lookahead
.type
=== Token
.Identifier
) {
2961 label
= parseVariableIdentifier();
2963 key
= '$' + label
.name
;
2964 if (!Object
.prototype.hasOwnProperty
.call(state
.labelSet
, key
)) {
2965 throwError({}, Messages
.UnknownLabel
, label
.name
);
2971 if (label
=== null && !(state
.inIteration
|| state
.inSwitch
)) {
2972 throwError({}, Messages
.IllegalBreak
);
2975 return delegate
.createBreakStatement(label
);
2978 // 12.9 The return statement
2980 function parseReturnStatement() {
2981 var argument
= null;
2983 expectKeyword('return');
2985 if (!state
.inFunctionBody
) {
2986 throwErrorTolerant({}, Messages
.IllegalReturn
);
2989 // 'return' followed by a space and an identifier is very common.
2990 if (source
.charCodeAt(index
) === 0x20) {
2991 if (isIdentifierStart(source
.charCodeAt(index
+ 1))) {
2992 argument
= parseExpression();
2994 return delegate
.createReturnStatement(argument
);
2998 if (peekLineTerminator()) {
2999 return delegate
.createReturnStatement(null);
3003 if (!match('}') && lookahead
.type
!== Token
.EOF
) {
3004 argument
= parseExpression();
3010 return delegate
.createReturnStatement(argument
);
3013 // 12.10 The with statement
3015 function parseWithStatement() {
3019 // TODO(ikarienator): Should we update the test cases instead?
3021 throwErrorTolerant({}, Messages
.StrictModeWith
);
3024 expectKeyword('with');
3028 object
= parseExpression();
3032 body
= parseStatement();
3034 return delegate
.createWithStatement(object
, body
);
3037 // 12.10 The swith statement
3039 function parseSwitchCase() {
3040 var test
, consequent
= [], statement
, startToken
;
3042 startToken
= lookahead
;
3043 if (matchKeyword('default')) {
3047 expectKeyword('case');
3048 test
= parseExpression();
3052 while (index
< length
) {
3053 if (match('}') || matchKeyword('default') || matchKeyword('case')) {
3056 statement
= parseStatement();
3057 consequent
.push(statement
);
3060 return delegate
.markEnd(delegate
.createSwitchCase(test
, consequent
), startToken
);
3063 function parseSwitchStatement() {
3064 var discriminant
, cases
, clause
, oldInSwitch
, defaultFound
;
3066 expectKeyword('switch');
3070 discriminant
= parseExpression();
3080 return delegate
.createSwitchStatement(discriminant
, cases
);
3083 oldInSwitch
= state
.inSwitch
;
3084 state
.inSwitch
= true;
3085 defaultFound
= false;
3087 while (index
< length
) {
3091 clause
= parseSwitchCase();
3092 if (clause
.test
=== null) {
3094 throwError({}, Messages
.MultipleDefaultsInSwitch
);
3096 defaultFound
= true;
3101 state
.inSwitch
= oldInSwitch
;
3105 return delegate
.createSwitchStatement(discriminant
, cases
);
3108 // 12.13 The throw statement
3110 function parseThrowStatement() {
3113 expectKeyword('throw');
3115 if (peekLineTerminator()) {
3116 throwError({}, Messages
.NewlineAfterThrow
);
3119 argument
= parseExpression();
3123 return delegate
.createThrowStatement(argument
);
3126 // 12.14 The try statement
3128 function parseCatchClause() {
3129 var param
, body
, startToken
;
3131 startToken
= lookahead
;
3132 expectKeyword('catch');
3136 throwUnexpected(lookahead
);
3139 param
= parseVariableIdentifier();
3141 if (strict
&& isRestrictedWord(param
.name
)) {
3142 throwErrorTolerant({}, Messages
.StrictCatchVariable
);
3146 body
= parseBlock();
3147 return delegate
.markEnd(delegate
.createCatchClause(param
, body
), startToken
);
3150 function parseTryStatement() {
3151 var block
, handlers
= [], finalizer
= null;
3153 expectKeyword('try');
3155 block
= parseBlock();
3157 if (matchKeyword('catch')) {
3158 handlers
.push(parseCatchClause());
3161 if (matchKeyword('finally')) {
3163 finalizer
= parseBlock();
3166 if (handlers
.length
=== 0 && !finalizer
) {
3167 throwError({}, Messages
.NoCatchOrFinally
);
3170 return delegate
.createTryStatement(block
, [], handlers
, finalizer
);
3173 // 12.15 The debugger statement
3175 function parseDebuggerStatement() {
3176 expectKeyword('debugger');
3180 return delegate
.createDebuggerStatement();
3185 function parseStatement() {
3186 var type
= lookahead
.type
,
3192 if (type
=== Token
.EOF
) {
3193 throwUnexpected(lookahead
);
3196 if (type
=== Token
.Punctuator
&& lookahead
.value
=== '{') {
3197 return parseBlock();
3200 startToken
= lookahead
;
3202 if (type
=== Token
.Punctuator
) {
3203 switch (lookahead
.value
) {
3205 return delegate
.markEnd(parseEmptyStatement(), startToken
);
3207 return delegate
.markEnd(parseExpressionStatement(), startToken
);
3213 if (type
=== Token
.Keyword
) {
3214 switch (lookahead
.value
) {
3216 return delegate
.markEnd(parseBreakStatement(), startToken
);
3218 return delegate
.markEnd(parseContinueStatement(), startToken
);
3220 return delegate
.markEnd(parseDebuggerStatement(), startToken
);
3222 return delegate
.markEnd(parseDoWhileStatement(), startToken
);
3224 return delegate
.markEnd(parseForStatement(), startToken
);
3226 return delegate
.markEnd(parseFunctionDeclaration(), startToken
);
3228 return delegate
.markEnd(parseIfStatement(), startToken
);
3230 return delegate
.markEnd(parseReturnStatement(), startToken
);
3232 return delegate
.markEnd(parseSwitchStatement(), startToken
);
3234 return delegate
.markEnd(parseThrowStatement(), startToken
);
3236 return delegate
.markEnd(parseTryStatement(), startToken
);
3238 return delegate
.markEnd(parseVariableStatement(), startToken
);
3240 return delegate
.markEnd(parseWhileStatement(), startToken
);
3242 return delegate
.markEnd(parseWithStatement(), startToken
);
3248 expr
= parseExpression();
3250 // 12.12 Labelled Statements
3251 if ((expr
.type
=== Syntax
.Identifier
) && match(':')) {
3254 key
= '$' + expr
.name
;
3255 if (Object
.prototype.hasOwnProperty
.call(state
.labelSet
, key
)) {
3256 throwError({}, Messages
.Redeclaration
, 'Label', expr
.name
);
3259 state
.labelSet
[key
] = true;
3260 labeledBody
= parseStatement();
3261 delete state
.labelSet
[key
];
3262 return delegate
.markEnd(delegate
.createLabeledStatement(expr
, labeledBody
), startToken
);
3267 return delegate
.markEnd(delegate
.createExpressionStatement(expr
), startToken
);
3270 // 13 Function Definition
3272 function parseFunctionSourceElements() {
3273 var sourceElement
, sourceElements
= [], token
, directive
, firstRestricted
,
3274 oldLabelSet
, oldInIteration
, oldInSwitch
, oldInFunctionBody
, startToken
;
3276 startToken
= lookahead
;
3279 while (index
< length
) {
3280 if (lookahead
.type
!== Token
.StringLiteral
) {
3285 sourceElement
= parseSourceElement();
3286 sourceElements
.push(sourceElement
);
3287 if (sourceElement
.expression
.type
!== Syntax
.Literal
) {
3288 // this is not directive
3291 directive
= source
.slice(token
.start
+ 1, token
.end
- 1);
3292 if (directive
=== 'use strict') {
3294 if (firstRestricted
) {
3295 throwErrorTolerant(firstRestricted
, Messages
.StrictOctalLiteral
);
3298 if (!firstRestricted
&& token
.octal
) {
3299 firstRestricted
= token
;
3304 oldLabelSet
= state
.labelSet
;
3305 oldInIteration
= state
.inIteration
;
3306 oldInSwitch
= state
.inSwitch
;
3307 oldInFunctionBody
= state
.inFunctionBody
;
3309 state
.labelSet
= {};
3310 state
.inIteration
= false;
3311 state
.inSwitch
= false;
3312 state
.inFunctionBody
= true;
3314 while (index
< length
) {
3318 sourceElement
= parseSourceElement();
3319 if (typeof sourceElement
=== 'undefined') {
3322 sourceElements
.push(sourceElement
);
3327 state
.labelSet
= oldLabelSet
;
3328 state
.inIteration
= oldInIteration
;
3329 state
.inSwitch
= oldInSwitch
;
3330 state
.inFunctionBody
= oldInFunctionBody
;
3332 return delegate
.markEnd(delegate
.createBlockStatement(sourceElements
), startToken
);
3335 function parseParams(firstRestricted
) {
3336 var param
, params
= [], token
, stricted
, paramSet
, key
, message
;
3341 while (index
< length
) {
3343 param
= parseVariableIdentifier();
3344 key
= '$' + token
.value
;
3346 if (isRestrictedWord(token
.value
)) {
3348 message
= Messages
.StrictParamName
;
3350 if (Object
.prototype.hasOwnProperty
.call(paramSet
, key
)) {
3352 message
= Messages
.StrictParamDupe
;
3354 } else if (!firstRestricted
) {
3355 if (isRestrictedWord(token
.value
)) {
3356 firstRestricted
= token
;
3357 message
= Messages
.StrictParamName
;
3358 } else if (isStrictModeReservedWord(token
.value
)) {
3359 firstRestricted
= token
;
3360 message
= Messages
.StrictReservedWord
;
3361 } else if (Object
.prototype.hasOwnProperty
.call(paramSet
, key
)) {
3362 firstRestricted
= token
;
3363 message
= Messages
.StrictParamDupe
;
3367 paramSet
[key
] = true;
3380 firstRestricted
: firstRestricted
,
3385 function parseFunctionDeclaration() {
3386 var id
, params
= [], body
, token
, stricted
, tmp
, firstRestricted
, message
, previousStrict
, startToken
;
3388 startToken
= lookahead
;
3390 expectKeyword('function');
3392 id
= parseVariableIdentifier();
3394 if (isRestrictedWord(token
.value
)) {
3395 throwErrorTolerant(token
, Messages
.StrictFunctionName
);
3398 if (isRestrictedWord(token
.value
)) {
3399 firstRestricted
= token
;
3400 message
= Messages
.StrictFunctionName
;
3401 } else if (isStrictModeReservedWord(token
.value
)) {
3402 firstRestricted
= token
;
3403 message
= Messages
.StrictReservedWord
;
3407 tmp
= parseParams(firstRestricted
);
3408 params
= tmp
.params
;
3409 stricted
= tmp
.stricted
;
3410 firstRestricted
= tmp
.firstRestricted
;
3412 message
= tmp
.message
;
3415 previousStrict
= strict
;
3416 body
= parseFunctionSourceElements();
3417 if (strict
&& firstRestricted
) {
3418 throwError(firstRestricted
, message
);
3420 if (strict
&& stricted
) {
3421 throwErrorTolerant(stricted
, message
);
3423 strict
= previousStrict
;
3425 return delegate
.markEnd(delegate
.createFunctionDeclaration(id
, params
, [], body
), startToken
);
3428 function parseFunctionExpression() {
3429 var token
, id
= null, stricted
, firstRestricted
, message
, tmp
, params
= [], body
, previousStrict
, startToken
;
3431 startToken
= lookahead
;
3432 expectKeyword('function');
3436 id
= parseVariableIdentifier();
3438 if (isRestrictedWord(token
.value
)) {
3439 throwErrorTolerant(token
, Messages
.StrictFunctionName
);
3442 if (isRestrictedWord(token
.value
)) {
3443 firstRestricted
= token
;
3444 message
= Messages
.StrictFunctionName
;
3445 } else if (isStrictModeReservedWord(token
.value
)) {
3446 firstRestricted
= token
;
3447 message
= Messages
.StrictReservedWord
;
3452 tmp
= parseParams(firstRestricted
);
3453 params
= tmp
.params
;
3454 stricted
= tmp
.stricted
;
3455 firstRestricted
= tmp
.firstRestricted
;
3457 message
= tmp
.message
;
3460 previousStrict
= strict
;
3461 body
= parseFunctionSourceElements();
3462 if (strict
&& firstRestricted
) {
3463 throwError(firstRestricted
, message
);
3465 if (strict
&& stricted
) {
3466 throwErrorTolerant(stricted
, message
);
3468 strict
= previousStrict
;
3470 return delegate
.markEnd(delegate
.createFunctionExpression(id
, params
, [], body
), startToken
);
3475 function parseSourceElement() {
3476 if (lookahead
.type
=== Token
.Keyword
) {
3477 switch (lookahead
.value
) {
3480 return parseConstLetDeclaration(lookahead
.value
);
3482 return parseFunctionDeclaration();
3484 return parseStatement();
3488 if (lookahead
.type
!== Token
.EOF
) {
3489 return parseStatement();
3493 function parseSourceElements() {
3494 var sourceElement
, sourceElements
= [], token
, directive
, firstRestricted
;
3496 while (index
< length
) {
3498 if (token
.type
!== Token
.StringLiteral
) {
3502 sourceElement
= parseSourceElement();
3503 sourceElements
.push(sourceElement
);
3504 if (sourceElement
.expression
.type
!== Syntax
.Literal
) {
3505 // this is not directive
3508 directive
= source
.slice(token
.start
+ 1, token
.end
- 1);
3509 if (directive
=== 'use strict') {
3511 if (firstRestricted
) {
3512 throwErrorTolerant(firstRestricted
, Messages
.StrictOctalLiteral
);
3515 if (!firstRestricted
&& token
.octal
) {
3516 firstRestricted
= token
;
3521 while (index
< length
) {
3522 sourceElement
= parseSourceElement();
3523 /* istanbul ignore if */
3524 if (typeof sourceElement
=== 'undefined') {
3527 sourceElements
.push(sourceElement
);
3529 return sourceElements
;
3532 function parseProgram() {
3533 var body
, startToken
;
3537 startToken
= lookahead
;
3540 body
= parseSourceElements();
3541 return delegate
.markEnd(delegate
.createProgram(body
), startToken
);
3544 function filterTokenLocation() {
3545 var i
, entry
, token
, tokens
= [];
3547 for (i
= 0; i
< extra
.tokens
.length
; ++i
) {
3548 entry
= extra
.tokens
[i
];
3554 token
.range
= entry
.range
;
3557 token
.loc
= entry
.loc
;
3562 extra
.tokens
= tokens
;
3565 function tokenize(code
, options
) {
3571 if (typeof code
!== 'string' && !(code
instanceof String
)) {
3572 code
= toString(code
);
3575 delegate
= SyntaxTreeDelegate
;
3578 lineNumber
= (source
.length
> 0) ? 1 : 0;
3580 length
= source
.length
;
3585 inFunctionBody
: false,
3588 lastCommentStart
: -1
3593 // Options matching.
3594 options
= options
|| {};
3596 // Of course we collect tokens here.
3597 options
.tokens
= true;
3599 extra
.tokenize
= true;
3600 // The following two fields are necessary to compute the Regex tokens.
3601 extra
.openParenToken
= -1;
3602 extra
.openCurlyToken
= -1;
3604 extra
.range
= (typeof options
.range
=== 'boolean') && options
.range
;
3605 extra
.loc
= (typeof options
.loc
=== 'boolean') && options
.loc
;
3607 if (typeof options
.comment
=== 'boolean' && options
.comment
) {
3608 extra
.comments
= [];
3610 if (typeof options
.tolerant
=== 'boolean' && options
.tolerant
) {
3616 if (lookahead
.type
=== Token
.EOF
) {
3617 return extra
.tokens
;
3621 while (lookahead
.type
!== Token
.EOF
) {
3624 } catch (lexError
) {
3627 extra
.errors
.push(lexError
);
3628 // We have to break on the first error
3629 // to avoid infinite loops.
3637 filterTokenLocation();
3638 tokens
= extra
.tokens
;
3639 if (typeof extra
.comments
!== 'undefined') {
3640 tokens
.comments
= extra
.comments
;
3642 if (typeof extra
.errors
!== 'undefined') {
3643 tokens
.errors
= extra
.errors
;
3653 function parse(code
, options
) {
3654 var program
, toString
;
3657 if (typeof code
!== 'string' && !(code
instanceof String
)) {
3658 code
= toString(code
);
3661 delegate
= SyntaxTreeDelegate
;
3664 lineNumber
= (source
.length
> 0) ? 1 : 0;
3666 length
= source
.length
;
3671 inFunctionBody
: false,
3674 lastCommentStart
: -1
3678 if (typeof options
!== 'undefined') {
3679 extra
.range
= (typeof options
.range
=== 'boolean') && options
.range
;
3680 extra
.loc
= (typeof options
.loc
=== 'boolean') && options
.loc
;
3681 extra
.attachComment
= (typeof options
.attachComment
=== 'boolean') && options
.attachComment
;
3683 if (extra
.loc
&& options
.source
!== null && options
.source
!== undefined) {
3684 extra
.source
= toString(options
.source
);
3687 if (typeof options
.tokens
=== 'boolean' && options
.tokens
) {
3690 if (typeof options
.comment
=== 'boolean' && options
.comment
) {
3691 extra
.comments
= [];
3693 if (typeof options
.tolerant
=== 'boolean' && options
.tolerant
) {
3696 if (extra
.attachComment
) {
3698 extra
.comments
= [];
3699 extra
.bottomRightStack
= [];
3700 extra
.trailingComments
= [];
3701 extra
.leadingComments
= [];
3706 program
= parseProgram();
3707 if (typeof extra
.comments
!== 'undefined') {
3708 program
.comments
= extra
.comments
;
3710 if (typeof extra
.tokens
!== 'undefined') {
3711 filterTokenLocation();
3712 program
.tokens
= extra
.tokens
;
3714 if (typeof extra
.errors
!== 'undefined') {
3715 program
.errors
= extra
.errors
;
3726 // Sync with *.json manifests.
3727 exports
.version
= '1.2.2';
3729 exports
.tokenize
= tokenize
;
3731 exports
.parse
= parse
;
3734 /* istanbul ignore next */
3735 exports
.Syntax
= (function () {
3736 var name
, types
= {};
3738 if (typeof Object
.create
=== 'function') {
3739 types
= Object
.create(null);
3742 for (name
in Syntax
) {
3743 if (Syntax
.hasOwnProperty(name
)) {
3744 types
[name
] = Syntax
[name
];
3748 if (typeof Object
.freeze
=== 'function') {
3749 Object
.freeze(types
);
3756 /* vim: set sw=4 ts=4 et tw=80 : */