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 isImplicitOctalLiteral() {
842 // Implicit octal, unless there is a non-octal digit.
843 // (Annex B.1.1 on Numeric Literals)
844 for (i = index + 1; i < length; ++i) {
846 if (ch === '8' || ch === '9') {
849 if (!isOctalDigit(ch)) {
857 function scanNumericLiteral() {
858 var number, start, ch;
861 assert(isDecimalDigit(ch.charCodeAt(0)) || (ch === '.'),
862 'Numeric literal must start with a decimal digit or a decimal point');
867 number = source[index++];
870 // Hex number starts with '0x'.
871 // Octal number starts with '0'.
872 if (number === '0') {
873 if (ch === 'x' || ch === 'X') {
875 return scanHexLiteral(start);
877 if (isOctalDigit(ch)) {
878 if (isImplicitOctalLiteral()) {
879 return scanOctalLiteral(start);
884 while (isDecimalDigit(source.charCodeAt(index))) {
885 number += source[index++];
891 number += source[index++];
892 while (isDecimalDigit(source.charCodeAt(index))) {
893 number += source[index++];
898 if (ch === 'e' || ch === 'E') {
899 number += source[index++];
902 if (ch === '+' || ch === '-') {
903 number += source[index++];
905 if (isDecimalDigit(source.charCodeAt(index))) {
906 while (isDecimalDigit(source.charCodeAt(index))) {
907 number += source[index++];
910 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
914 if (isIdentifierStart(source.charCodeAt(index))) {
915 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
919 type: Token.NumericLiteral,
920 value: parseFloat(number),
921 lineNumber: lineNumber,
922 lineStart: lineStart,
928 // 7.8.4 String Literals
930 function scanStringLiteral() {
931 var str = '', quote, start, ch, code, unescaped, restore, octal = false, startLineNumber, startLineStart;
932 startLineNumber = lineNumber;
933 startLineStart = lineStart;
935 quote = source[index];
936 assert((quote === '\'' || quote === '"'),
937 'String literal must starts with a quote');
942 while (index < length) {
943 ch = source[index++];
948 } else if (ch === '\\') {
949 ch = source[index++];
950 if (!ch || !isLineTerminator(ch.charCodeAt(0))) {
955 unescaped = scanHexEscape(ch);
983 if (isOctalDigit(ch)) {
984 code = '01234567'.indexOf(ch);
986 // \0 is not octal escape sequence
991 if (index < length && isOctalDigit(source[index])) {
993 code = code * 8 + '01234567'.indexOf(source[index++]);
995 // 3 digits are only allowed when string starts
997 if ('0123'.indexOf(ch) >= 0 &&
999 isOctalDigit(source[index])) {
1000 code = code * 8 + '01234567'.indexOf(source[index++]);
1003 str += String.fromCharCode(code);
1011 if (ch === '\r' && source[index] === '\n') {
1016 } else if (isLineTerminator(ch.charCodeAt(0))) {
1024 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
1028 type: Token.StringLiteral,
1031 startLineNumber: startLineNumber,
1032 startLineStart: startLineStart,
1033 lineNumber: lineNumber,
1034 lineStart: lineStart,
1040 function testRegExp(pattern, flags) {
1043 value = new RegExp(pattern, flags);
1045 throwError({}, Messages.InvalidRegExp);
1050 function scanRegExpBody() {
1051 var ch, str, classMarker, terminated, body;
1054 assert(ch === '/', 'Regular expression literal must start with a slash');
1055 str = source[index++];
1057 classMarker = false;
1059 while (index < length) {
1060 ch = source[index++];
1063 ch = source[index++];
1065 if (isLineTerminator(ch.charCodeAt(0))) {
1066 throwError({}, Messages.UnterminatedRegExp);
1069 } else if (isLineTerminator(ch.charCodeAt(0))) {
1070 throwError({}, Messages.UnterminatedRegExp);
1071 } else if (classMarker) {
1073 classMarker = false;
1079 } else if (ch === '[') {
1086 throwError({}, Messages.UnterminatedRegExp);
1089 // Exclude leading and trailing slash.
1090 body = str.substr(1, str.length - 2);
1097 function scanRegExpFlags() {
1098 var ch, str, flags, restore;
1102 while (index < length) {
1104 if (!isIdentifierPart(ch.charCodeAt(0))) {
1109 if (ch === '\\' && index < length) {
1114 ch = scanHexEscape('u');
1117 for (str += '\\u'; restore < index; ++restore) {
1118 str += source[restore];
1125 throwErrorTolerant({}, Messages.UnexpectedToken, 'ILLEGAL');
1128 throwErrorTolerant({}, Messages.UnexpectedToken, 'ILLEGAL');
1142 function scanRegExp() {
1143 var start, body, flags, pattern, value;
1149 body = scanRegExpBody();
1150 flags = scanRegExpFlags();
1151 value = testRegExp(body.value, flags.value);
1153 if (extra.tokenize) {
1155 type: Token.RegularExpression,
1157 lineNumber: lineNumber,
1158 lineStart: lineStart,
1165 literal: body.literal + flags.literal,
1172 function collectRegex() {
1173 var pos, loc, regex, token;
1181 column: index - lineStart
1185 regex = scanRegExp();
1188 column: index - lineStart
1191 /* istanbul ignore next */
1192 if (!extra.tokenize) {
1193 // Pop the previous token, which is likely '/' or '/='
1194 if (extra.tokens.length > 0) {
1195 token = extra.tokens[extra.tokens.length - 1];
1196 if (token.range[0] === pos && token.type === 'Punctuator') {
1197 if (token.value === '/' || token.value === '/=') {
1204 type: 'RegularExpression',
1205 value: regex.literal,
1206 range: [pos, index],
1214 function isIdentifierName(token) {
1215 return token.type === Token.Identifier ||
1216 token.type === Token.Keyword ||
1217 token.type === Token.BooleanLiteral ||
1218 token.type === Token.NullLiteral;
1221 function advanceSlash() {
1224 // Using the following algorithm:
1225 // https://github.com/mozilla/sweet.js/wiki/design
1226 prevToken = extra.tokens[extra.tokens.length - 1];
1228 // Nothing before that: it cannot be a division.
1229 return collectRegex();
1231 if (prevToken.type === 'Punctuator') {
1232 if (prevToken.value === ']') {
1233 return scanPunctuator();
1235 if (prevToken.value === ')') {
1236 checkToken = extra.tokens[extra.openParenToken - 1];
1238 checkToken.type === 'Keyword' &&
1239 (checkToken.value === 'if' ||
1240 checkToken.value === 'while' ||
1241 checkToken.value === 'for' ||
1242 checkToken.value === 'with')) {
1243 return collectRegex();
1245 return scanPunctuator();
1247 if (prevToken.value === '}') {
1248 // Dividing a function by anything makes little sense,
1249 // but we have to check for that.
1250 if (extra.tokens[extra.openCurlyToken - 3] &&
1251 extra.tokens[extra.openCurlyToken - 3].type === 'Keyword') {
1252 // Anonymous function.
1253 checkToken = extra.tokens[extra.openCurlyToken - 4];
1255 return scanPunctuator();
1257 } else if (extra.tokens[extra.openCurlyToken - 4] &&
1258 extra.tokens[extra.openCurlyToken - 4].type === 'Keyword') {
1260 checkToken = extra.tokens[extra.openCurlyToken - 5];
1262 return collectRegex();
1265 return scanPunctuator();
1267 // checkToken determines whether the function is
1268 // a declaration or an expression.
1269 if (FnExprTokens.indexOf(checkToken.value) >= 0) {
1270 // It is an expression.
1271 return scanPunctuator();
1273 // It is a declaration.
1274 return collectRegex();
1276 return collectRegex();
1278 if (prevToken.type === 'Keyword' && prevToken.value !== 'this') {
1279 return collectRegex();
1281 return scanPunctuator();
1284 function advance() {
1289 if (index >= length) {
1292 lineNumber: lineNumber,
1293 lineStart: lineStart,
1299 ch = source.charCodeAt(index);
1301 if (isIdentifierStart(ch)) {
1302 return scanIdentifier();
1305 // Very common: ( and ) and ;
1306 if (ch === 0x28 || ch === 0x29 || ch === 0x3B) {
1307 return scanPunctuator();
1310 // String literal starts with single quote (U+0027) or double quote (U+0022).
1311 if (ch === 0x27 || ch === 0x22) {
1312 return scanStringLiteral();
1316 // Dot (.) U+002E can also start a floating-point number, hence the need
1317 // to check the next character.
1319 if (isDecimalDigit(source.charCodeAt(index + 1))) {
1320 return scanNumericLiteral();
1322 return scanPunctuator();
1325 if (isDecimalDigit(ch)) {
1326 return scanNumericLiteral();
1329 // Slash (/) U+002F can also start a regex.
1330 if (extra.tokenize && ch === 0x2F) {
1331 return advanceSlash();
1334 return scanPunctuator();
1337 function collectToken() {
1338 var loc, token, range, value;
1344 column: index - lineStart
1351 column: index - lineStart
1354 if (token.type !== Token.EOF) {
1355 value = source.slice(token.start, token.end);
1357 type: TokenName[token.type],
1359 range: [token.start, token.end],
1372 lineNumber = token.lineNumber;
1373 lineStart = token.lineStart;
1375 lookahead = (typeof extra.tokens !== 'undefined') ? collectToken() : advance();
1378 lineNumber = token.lineNumber;
1379 lineStart = token.lineStart;
1385 var pos, line, start;
1390 lookahead = (typeof extra.tokens !== 'undefined') ? collectToken() : advance();
1396 function Position(line, column) {
1398 this.column = column;
1401 function SourceLocation(startLine, startColumn, line, column) {
1402 this.start = new Position(startLine, startColumn);
1403 this.end = new Position(line, column);
1406 SyntaxTreeDelegate = {
1410 processComment: function (node) {
1411 var lastChild, trailingComments;
1413 if (node.type === Syntax.Program) {
1414 if (node.body.length > 0) {
1419 if (extra.trailingComments.length > 0) {
1420 if (extra.trailingComments[0].range[0] >= node.range[1]) {
1421 trailingComments = extra.trailingComments;
1422 extra.trailingComments = [];
1424 extra.trailingComments.length = 0;
1427 if (extra.bottomRightStack.length > 0 &&
1428 extra.bottomRightStack[extra.bottomRightStack.length - 1].trailingComments &&
1429 extra.bottomRightStack[extra.bottomRightStack.length - 1].trailingComments[0].range[0] >= node.range[1]) {
1430 trailingComments = extra.bottomRightStack[extra.bottomRightStack.length - 1].trailingComments;
1431 delete extra.bottomRightStack[extra.bottomRightStack.length - 1].trailingComments;
1435 // Eating the stack.
1436 while (extra.bottomRightStack.length > 0 && extra.bottomRightStack[extra.bottomRightStack.length - 1].range[0] >= node.range[0]) {
1437 lastChild = extra.bottomRightStack.pop();
1441 if (lastChild.leadingComments && lastChild.leadingComments[lastChild.leadingComments.length - 1].range[1] <= node.range[0]) {
1442 node.leadingComments = lastChild.leadingComments;
1443 delete lastChild.leadingComments;
1445 } else if (extra.leadingComments.length > 0 && extra.leadingComments[extra.leadingComments.length - 1].range[1] <= node.range[0]) {
1446 node.leadingComments = extra.leadingComments;
1447 extra.leadingComments = [];
1451 if (trailingComments) {
1452 node.trailingComments = trailingComments;
1455 extra.bottomRightStack.push(node);
1458 markEnd: function (node, startToken) {
1460 node.range = [startToken.start, index];
1463 node.loc = new SourceLocation(
1464 startToken.startLineNumber === undefined ? startToken.lineNumber : startToken.startLineNumber,
1465 startToken.start - (startToken.startLineStart === undefined ? startToken.lineStart : startToken.startLineStart),
1469 this.postProcess(node);
1472 if (extra.attachComment) {
1473 this.processComment(node);
1478 postProcess: function (node) {
1480 node.loc.source = extra.source;
1485 createArrayExpression: function (elements) {
1487 type: Syntax.ArrayExpression,
1492 createAssignmentExpression: function (operator, left, right) {
1494 type: Syntax.AssignmentExpression,
1501 createBinaryExpression: function (operator, left, right) {
1502 var type = (operator === '||' || operator === '&&') ? Syntax.LogicalExpression :
1503 Syntax.BinaryExpression;
1512 createBlockStatement: function (body) {
1514 type: Syntax.BlockStatement,
1519 createBreakStatement: function (label) {
1521 type: Syntax.BreakStatement,
1526 createCallExpression: function (callee, args) {
1528 type: Syntax.CallExpression,
1534 createCatchClause: function (param, body) {
1536 type: Syntax.CatchClause,
1542 createConditionalExpression: function (test, consequent, alternate) {
1544 type: Syntax.ConditionalExpression,
1546 consequent: consequent,
1547 alternate: alternate
1551 createContinueStatement: function (label) {
1553 type: Syntax.ContinueStatement,
1558 createDebuggerStatement: function () {
1560 type: Syntax.DebuggerStatement
1564 createDoWhileStatement: function (body, test) {
1566 type: Syntax.DoWhileStatement,
1572 createEmptyStatement: function () {
1574 type: Syntax.EmptyStatement
1578 createExpressionStatement: function (expression) {
1580 type: Syntax.ExpressionStatement,
1581 expression: expression
1585 createForStatement: function (init, test, update, body) {
1587 type: Syntax.ForStatement,
1595 createForInStatement: function (left, right, body) {
1597 type: Syntax.ForInStatement,
1605 createFunctionDeclaration: function (id, params, defaults, body) {
1607 type: Syntax.FunctionDeclaration,
1618 createFunctionExpression: function (id, params, defaults, body) {
1620 type: Syntax.FunctionExpression,
1631 createIdentifier: function (name) {
1633 type: Syntax.Identifier,
1638 createIfStatement: function (test, consequent, alternate) {
1640 type: Syntax.IfStatement,
1642 consequent: consequent,
1643 alternate: alternate
1647 createLabeledStatement: function (label, body) {
1649 type: Syntax.LabeledStatement,
1655 createLiteral: function (token) {
1657 type: Syntax.Literal,
1659 raw: source.slice(token.start, token.end)
1663 createMemberExpression: function (accessor, object, property) {
1665 type: Syntax.MemberExpression,
1666 computed: accessor === '[',
1672 createNewExpression: function (callee, args) {
1674 type: Syntax.NewExpression,
1680 createObjectExpression: function (properties) {
1682 type: Syntax.ObjectExpression,
1683 properties: properties
1687 createPostfixExpression: function (operator, argument) {
1689 type: Syntax.UpdateExpression,
1696 createProgram: function (body) {
1698 type: Syntax.Program,
1703 createProperty: function (kind, key, value) {
1705 type: Syntax.Property,
1712 createReturnStatement: function (argument) {
1714 type: Syntax.ReturnStatement,
1719 createSequenceExpression: function (expressions) {
1721 type: Syntax.SequenceExpression,
1722 expressions: expressions
1726 createSwitchCase: function (test, consequent) {
1728 type: Syntax.SwitchCase,
1730 consequent: consequent
1734 createSwitchStatement: function (discriminant, cases) {
1736 type: Syntax.SwitchStatement,
1737 discriminant: discriminant,
1742 createThisExpression: function () {
1744 type: Syntax.ThisExpression
1748 createThrowStatement: function (argument) {
1750 type: Syntax.ThrowStatement,
1755 createTryStatement: function (block, guardedHandlers, handlers, finalizer) {
1757 type: Syntax.TryStatement,
1759 guardedHandlers: guardedHandlers,
1761 finalizer: finalizer
1765 createUnaryExpression: function (operator, argument) {
1766 if (operator === '++' || operator === '--') {
1768 type: Syntax.UpdateExpression,
1775 type: Syntax.UnaryExpression,
1782 createVariableDeclaration: function (declarations, kind) {
1784 type: Syntax.VariableDeclaration,
1785 declarations: declarations,
1790 createVariableDeclarator: function (id, init) {
1792 type: Syntax.VariableDeclarator,
1798 createWhileStatement: function (test, body) {
1800 type: Syntax.WhileStatement,
1806 createWithStatement: function (object, body) {
1808 type: Syntax.WithStatement,
1815 // Return true if there is a line terminator before the next token.
1817 function peekLineTerminator() {
1818 var pos, line, start, found;
1824 found = lineNumber !== line;
1832 // Throw an exception
1834 function throwError(token, messageFormat) {
1836 args = Array.prototype.slice.call(arguments, 2),
1837 msg = messageFormat.replace(
1839 function (whole, index) {
1840 assert(index < args.length, 'Message reference must be in range');
1845 if (typeof token.lineNumber === 'number') {
1846 error = new Error('Line ' + token.lineNumber + ': ' + msg);
1847 error.index = token.start;
1848 error.lineNumber = token.lineNumber;
1849 error.column = token.start - lineStart + 1;
1851 error = new Error('Line ' + lineNumber + ': ' + msg);
1852 error.index = index;
1853 error.lineNumber = lineNumber;
1854 error.column = index - lineStart + 1;
1857 error.description = msg;
1861 function throwErrorTolerant() {
1863 throwError.apply(null, arguments);
1866 extra.errors.push(e);
1874 // Throw an exception because of the token.
1876 function throwUnexpected(token) {
1877 if (token.type === Token.EOF) {
1878 throwError(token, Messages.UnexpectedEOS);
1881 if (token.type === Token.NumericLiteral) {
1882 throwError(token, Messages.UnexpectedNumber);
1885 if (token.type === Token.StringLiteral) {
1886 throwError(token, Messages.UnexpectedString);
1889 if (token.type === Token.Identifier) {
1890 throwError(token, Messages.UnexpectedIdentifier);
1893 if (token.type === Token.Keyword) {
1894 if (isFutureReservedWord(token.value)) {
1895 throwError(token, Messages.UnexpectedReserved);
1896 } else if (strict && isStrictModeReservedWord(token.value)) {
1897 throwErrorTolerant(token, Messages.StrictReservedWord);
1900 throwError(token, Messages.UnexpectedToken, token.value);
1903 // BooleanLiteral, NullLiteral, or Punctuator.
1904 throwError(token, Messages.UnexpectedToken, token.value);
1907 // Expect the next token to match the specified punctuator.
1908 // If not, an exception will be thrown.
1910 function expect(value) {
1912 if (token.type !== Token.Punctuator || token.value !== value) {
1913 throwUnexpected(token);
1917 // Expect the next token to match the specified keyword.
1918 // If not, an exception will be thrown.
1920 function expectKeyword(keyword) {
1922 if (token.type !== Token.Keyword || token.value !== keyword) {
1923 throwUnexpected(token);
1927 // Return true if the next token matches the specified punctuator.
1929 function match(value) {
1930 return lookahead.type === Token.Punctuator && lookahead.value === value;
1933 // Return true if the next token matches the specified keyword
1935 function matchKeyword(keyword) {
1936 return lookahead.type === Token.Keyword && lookahead.value === keyword;
1939 // Return true if the next token is an assignment operator
1941 function matchAssign() {
1944 if (lookahead.type !== Token.Punctuator) {
1947 op = lookahead.value;
1948 return op === '=' ||
1962 function consumeSemicolon() {
1963 var line, oldIndex = index, oldLineNumber = lineNumber,
1964 oldLineStart = lineStart, oldLookahead = lookahead;
1966 // Catch the very common case first: immediately a semicolon (U+003B).
1967 if (source.charCodeAt(index) === 0x3B || match(';')) {
1974 if (lineNumber !== line) {
1976 lineNumber = oldLineNumber;
1977 lineStart = oldLineStart;
1978 lookahead = oldLookahead;
1982 if (lookahead.type !== Token.EOF && !match('}')) {
1983 throwUnexpected(lookahead);
1987 // Return true if provided expression is LeftHandSideExpression
1989 function isLeftHandSide(expr) {
1990 return expr.type === Syntax.Identifier || expr.type === Syntax.MemberExpression;
1993 // 11.1.4 Array Initialiser
1995 function parseArrayInitialiser() {
1996 var elements = [], startToken;
1998 startToken = lookahead;
2001 while (!match(']')) {
2004 elements.push(null);
2006 elements.push(parseAssignmentExpression());
2016 return delegate.markEnd(delegate.createArrayExpression(elements), startToken);
2019 // 11.1.5 Object Initialiser
2021 function parsePropertyFunction(param, first) {
2022 var previousStrict, body, startToken;
2024 previousStrict = strict;
2025 startToken = lookahead;
2026 body = parseFunctionSourceElements();
2027 if (first && strict && isRestrictedWord(param[0].name)) {
2028 throwErrorTolerant(first, Messages.StrictParamName);
2030 strict = previousStrict;
2031 return delegate.markEnd(delegate.createFunctionExpression(null, param, [], body), startToken);
2034 function parseObjectPropertyKey() {
2035 var token, startToken;
2037 startToken = lookahead;
2040 // Note: This function is called only from parseObjectProperty(), where
2041 // EOF and Punctuator tokens are already filtered out.
2043 if (token.type === Token.StringLiteral || token.type === Token.NumericLiteral) {
2044 if (strict && token.octal) {
2045 throwErrorTolerant(token, Messages.StrictOctalLiteral);
2047 return delegate.markEnd(delegate.createLiteral(token), startToken);
2050 return delegate.markEnd(delegate.createIdentifier(token.value), startToken);
2053 function parseObjectProperty() {
2054 var token, key, id, value, param, startToken;
2057 startToken = lookahead;
2059 if (token.type === Token.Identifier) {
2061 id = parseObjectPropertyKey();
2063 // Property Assignment: Getter and Setter.
2065 if (token.value === 'get' && !match(':')) {
2066 key = parseObjectPropertyKey();
2069 value = parsePropertyFunction([]);
2070 return delegate.markEnd(delegate.createProperty('get', key, value), startToken);
2072 if (token.value === 'set' && !match(':')) {
2073 key = parseObjectPropertyKey();
2076 if (token.type !== Token.Identifier) {
2078 throwErrorTolerant(token, Messages.UnexpectedToken, token.value);
2079 value = parsePropertyFunction([]);
2081 param = [ parseVariableIdentifier() ];
2083 value = parsePropertyFunction(param, token);
2085 return delegate.markEnd(delegate.createProperty('set', key, value), startToken);
2088 value = parseAssignmentExpression();
2089 return delegate.markEnd(delegate.createProperty('init', id, value), startToken);
2091 if (token.type === Token.EOF || token.type === Token.Punctuator) {
2092 throwUnexpected(token);
2094 key = parseObjectPropertyKey();
2096 value = parseAssignmentExpression();
2097 return delegate.markEnd(delegate.createProperty('init', key, value), startToken);
2101 function parseObjectInitialiser() {
2102 var properties = [], property, name, key, kind, map = {}, toString = String, startToken;
2104 startToken = lookahead;
2108 while (!match('}')) {
2109 property = parseObjectProperty();
2111 if (property.key.type === Syntax.Identifier) {
2112 name = property.key.name;
2114 name = toString(property.key.value);
2116 kind = (property.kind === 'init') ? PropertyKind.Data : (property.kind === 'get') ? PropertyKind.Get : PropertyKind.Set;
2119 if (Object.prototype.hasOwnProperty.call(map, key)) {
2120 if (map[key] === PropertyKind.Data) {
2121 if (strict && kind === PropertyKind.Data) {
2122 throwErrorTolerant({}, Messages.StrictDuplicateProperty);
2123 } else if (kind !== PropertyKind.Data) {
2124 throwErrorTolerant({}, Messages.AccessorDataProperty);
2127 if (kind === PropertyKind.Data) {
2128 throwErrorTolerant({}, Messages.AccessorDataProperty);
2129 } else if (map[key] & kind) {
2130 throwErrorTolerant({}, Messages.AccessorGetSet);
2138 properties.push(property);
2147 return delegate.markEnd(delegate.createObjectExpression(properties), startToken);
2150 // 11.1.6 The Grouping Operator
2152 function parseGroupExpression() {
2157 expr = parseExpression();
2165 // 11.1 Primary Expressions
2167 function parsePrimaryExpression() {
2168 var type, token, expr, startToken;
2171 return parseGroupExpression();
2175 return parseArrayInitialiser();
2179 return parseObjectInitialiser();
2182 type = lookahead.type;
2183 startToken = lookahead;
2185 if (type === Token.Identifier) {
2186 expr = delegate.createIdentifier(lex().value);
2187 } else if (type === Token.StringLiteral || type === Token.NumericLiteral) {
2188 if (strict && lookahead.octal) {
2189 throwErrorTolerant(lookahead, Messages.StrictOctalLiteral);
2191 expr = delegate.createLiteral(lex());
2192 } else if (type === Token.Keyword) {
2193 if (matchKeyword('function')) {
2194 return parseFunctionExpression();
2196 if (matchKeyword('this')) {
2198 expr = delegate.createThisExpression();
2200 throwUnexpected(lex());
2202 } else if (type === Token.BooleanLiteral) {
2204 token.value = (token.value === 'true');
2205 expr = delegate.createLiteral(token);
2206 } else if (type === Token.NullLiteral) {
2209 expr = delegate.createLiteral(token);
2210 } else if (match('/') || match('/=')) {
2211 if (typeof extra.tokens !== 'undefined') {
2212 expr = delegate.createLiteral(collectRegex());
2214 expr = delegate.createLiteral(scanRegExp());
2218 throwUnexpected(lex());
2221 return delegate.markEnd(expr, startToken);
2224 // 11.2 Left-Hand-Side Expressions
2226 function parseArguments() {
2232 while (index < length) {
2233 args.push(parseAssignmentExpression());
2246 function parseNonComputedProperty() {
2247 var token, startToken;
2249 startToken = lookahead;
2252 if (!isIdentifierName(token)) {
2253 throwUnexpected(token);
2256 return delegate.markEnd(delegate.createIdentifier(token.value), startToken);
2259 function parseNonComputedMember() {
2262 return parseNonComputedProperty();
2265 function parseComputedMember() {
2270 expr = parseExpression();
2277 function parseNewExpression() {
2278 var callee, args, startToken;
2280 startToken = lookahead;
2281 expectKeyword('new');
2282 callee = parseLeftHandSideExpression();
2283 args = match('(') ? parseArguments() : [];
2285 return delegate.markEnd(delegate.createNewExpression(callee, args), startToken);
2288 function parseLeftHandSideExpressionAllowCall() {
2289 var expr, args, property, startToken, previousAllowIn = state.allowIn;
2291 startToken = lookahead;
2292 state.allowIn = true;
2293 expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression();
2297 property = parseNonComputedMember();
2298 expr = delegate.createMemberExpression('.', expr, property);
2299 } else if (match('(')) {
2300 args = parseArguments();
2301 expr = delegate.createCallExpression(expr, args);
2302 } else if (match('[')) {
2303 property = parseComputedMember();
2304 expr = delegate.createMemberExpression('[', expr, property);
2308 delegate.markEnd(expr, startToken);
2310 state.allowIn = previousAllowIn;
2315 function parseLeftHandSideExpression() {
2316 var expr, property, startToken;
2317 assert(state.allowIn, 'callee of new expression always allow in keyword.');
2319 startToken = lookahead;
2321 expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression();
2323 while (match('.') || match('[')) {
2325 property = parseComputedMember();
2326 expr = delegate.createMemberExpression('[', expr, property);
2328 property = parseNonComputedMember();
2329 expr = delegate.createMemberExpression('.', expr, property);
2331 delegate.markEnd(expr, startToken);
2336 // 11.3 Postfix Expressions
2338 function parsePostfixExpression() {
2339 var expr, token, startToken = lookahead;
2341 expr = parseLeftHandSideExpressionAllowCall();
2343 if (lookahead.type === Token.Punctuator) {
2344 if ((match('++') || match('--')) && !peekLineTerminator()) {
2346 if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) {
2347 throwErrorTolerant({}, Messages.StrictLHSPostfix);
2350 if (!isLeftHandSide(expr)) {
2351 throwErrorTolerant({}, Messages.InvalidLHSInAssignment);
2355 expr = delegate.markEnd(delegate.createPostfixExpression(token.value, expr), startToken);
2362 // 11.4 Unary Operators
2364 function parseUnaryExpression() {
2365 var token, expr, startToken;
2367 if (lookahead.type !== Token.Punctuator && lookahead.type !== Token.Keyword) {
2368 expr = parsePostfixExpression();
2369 } else if (match('++') || match('--')) {
2370 startToken = lookahead;
2372 expr = parseUnaryExpression();
2374 if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) {
2375 throwErrorTolerant({}, Messages.StrictLHSPrefix);
2378 if (!isLeftHandSide(expr)) {
2379 throwErrorTolerant({}, Messages.InvalidLHSInAssignment);
2382 expr = delegate.createUnaryExpression(token.value, expr);
2383 expr = delegate.markEnd(expr, startToken);
2384 } else if (match('+') || match('-') || match('~') || match('!')) {
2385 startToken = lookahead;
2387 expr = parseUnaryExpression();
2388 expr = delegate.createUnaryExpression(token.value, expr);
2389 expr = delegate.markEnd(expr, startToken);
2390 } else if (matchKeyword('delete') || matchKeyword('void') || matchKeyword('typeof')) {
2391 startToken = lookahead;
2393 expr = parseUnaryExpression();
2394 expr = delegate.createUnaryExpression(token.value, expr);
2395 expr = delegate.markEnd(expr, startToken);
2396 if (strict && expr.operator === 'delete' && expr.argument.type === Syntax.Identifier) {
2397 throwErrorTolerant({}, Messages.StrictDelete);
2400 expr = parsePostfixExpression();
2406 function binaryPrecedence(token, allowIn) {
2409 if (token.type !== Token.Punctuator && token.type !== Token.Keyword) {
2413 switch (token.value) {
2450 prec = allowIn ? 7 : 0;
2477 // 11.5 Multiplicative Operators
2478 // 11.6 Additive Operators
2479 // 11.7 Bitwise Shift Operators
2480 // 11.8 Relational Operators
2481 // 11.9 Equality Operators
2482 // 11.10 Binary Bitwise Operators
2483 // 11.11 Binary Logical Operators
2485 function parseBinaryExpression() {
2486 var marker, markers, expr, token, prec, stack, right, operator, left, i;
2489 left = parseUnaryExpression();
2492 prec = binaryPrecedence(token, state.allowIn);
2499 markers = [marker, lookahead];
2500 right = parseUnaryExpression();
2502 stack = [left, token, right];
2504 while ((prec = binaryPrecedence(lookahead, state.allowIn)) > 0) {
2506 // Reduce: make a binary expression from the three topmost entries.
2507 while ((stack.length > 2) && (prec <= stack[stack.length - 2].prec)) {
2508 right = stack.pop();
2509 operator = stack.pop().value;
2511 expr = delegate.createBinaryExpression(operator, left, right);
2513 marker = markers[markers.length - 1];
2514 delegate.markEnd(expr, marker);
2522 markers.push(lookahead);
2523 expr = parseUnaryExpression();
2527 // Final reduce to clean-up the stack.
2528 i = stack.length - 1;
2532 expr = delegate.createBinaryExpression(stack[i - 1].value, stack[i - 2], expr);
2534 marker = markers.pop();
2535 delegate.markEnd(expr, marker);
2542 // 11.12 Conditional Operator
2544 function parseConditionalExpression() {
2545 var expr, previousAllowIn, consequent, alternate, startToken;
2547 startToken = lookahead;
2549 expr = parseBinaryExpression();
2553 previousAllowIn = state.allowIn;
2554 state.allowIn = true;
2555 consequent = parseAssignmentExpression();
2556 state.allowIn = previousAllowIn;
2558 alternate = parseAssignmentExpression();
2560 expr = delegate.createConditionalExpression(expr, consequent, alternate);
2561 delegate.markEnd(expr, startToken);
2567 // 11.13 Assignment Operators
2569 function parseAssignmentExpression() {
2570 var token, left, right, node, startToken;
2573 startToken = lookahead;
2575 node = left = parseConditionalExpression();
2577 if (matchAssign()) {
2578 // LeftHandSideExpression
2579 if (!isLeftHandSide(left)) {
2580 throwErrorTolerant({}, Messages.InvalidLHSInAssignment);
2584 if (strict && left.type === Syntax.Identifier && isRestrictedWord(left.name)) {
2585 throwErrorTolerant(token, Messages.StrictLHSAssignment);
2589 right = parseAssignmentExpression();
2590 node = delegate.markEnd(delegate.createAssignmentExpression(token.value, left, right), startToken);
2596 // 11.14 Comma Operator
2598 function parseExpression() {
2599 var expr, startToken = lookahead;
2601 expr = parseAssignmentExpression();
2604 expr = delegate.createSequenceExpression([ expr ]);
2606 while (index < length) {
2611 expr.expressions.push(parseAssignmentExpression());
2614 delegate.markEnd(expr, startToken);
2622 function parseStatementList() {
2626 while (index < length) {
2630 statement = parseSourceElement();
2631 if (typeof statement === 'undefined') {
2634 list.push(statement);
2640 function parseBlock() {
2641 var block, startToken;
2643 startToken = lookahead;
2646 block = parseStatementList();
2650 return delegate.markEnd(delegate.createBlockStatement(block), startToken);
2653 // 12.2 Variable Statement
2655 function parseVariableIdentifier() {
2656 var token, startToken;
2658 startToken = lookahead;
2661 if (token.type !== Token.Identifier) {
2662 throwUnexpected(token);
2665 return delegate.markEnd(delegate.createIdentifier(token.value), startToken);
2668 function parseVariableDeclaration(kind) {
2669 var init = null, id, startToken;
2671 startToken = lookahead;
2672 id = parseVariableIdentifier();
2675 if (strict && isRestrictedWord(id.name)) {
2676 throwErrorTolerant({}, Messages.StrictVarName);
2679 if (kind === 'const') {
2681 init = parseAssignmentExpression();
2682 } else if (match('=')) {
2684 init = parseAssignmentExpression();
2687 return delegate.markEnd(delegate.createVariableDeclarator(id, init), startToken);
2690 function parseVariableDeclarationList(kind) {
2694 list.push(parseVariableDeclaration(kind));
2699 } while (index < length);
2704 function parseVariableStatement() {
2707 expectKeyword('var');
2709 declarations = parseVariableDeclarationList();
2713 return delegate.createVariableDeclaration(declarations, 'var');
2716 // kind may be `const` or `let`
2717 // Both are experimental and not in the specification yet.
2718 // see http://wiki.ecmascript.org/doku.php?id=harmony:const
2719 // and http://wiki.ecmascript.org/doku.php?id=harmony:let
2720 function parseConstLetDeclaration(kind) {
2721 var declarations, startToken;
2723 startToken = lookahead;
2725 expectKeyword(kind);
2727 declarations = parseVariableDeclarationList(kind);
2731 return delegate.markEnd(delegate.createVariableDeclaration(declarations, kind), startToken);
2734 // 12.3 Empty Statement
2736 function parseEmptyStatement() {
2738 return delegate.createEmptyStatement();
2741 // 12.4 Expression Statement
2743 function parseExpressionStatement() {
2744 var expr = parseExpression();
2746 return delegate.createExpressionStatement(expr);
2749 // 12.5 If statement
2751 function parseIfStatement() {
2752 var test, consequent, alternate;
2754 expectKeyword('if');
2758 test = parseExpression();
2762 consequent = parseStatement();
2764 if (matchKeyword('else')) {
2766 alternate = parseStatement();
2771 return delegate.createIfStatement(test, consequent, alternate);
2774 // 12.6 Iteration Statements
2776 function parseDoWhileStatement() {
2777 var body, test, oldInIteration;
2779 expectKeyword('do');
2781 oldInIteration = state.inIteration;
2782 state.inIteration = true;
2784 body = parseStatement();
2786 state.inIteration = oldInIteration;
2788 expectKeyword('while');
2792 test = parseExpression();
2800 return delegate.createDoWhileStatement(body, test);
2803 function parseWhileStatement() {
2804 var test, body, oldInIteration;
2806 expectKeyword('while');
2810 test = parseExpression();
2814 oldInIteration = state.inIteration;
2815 state.inIteration = true;
2817 body = parseStatement();
2819 state.inIteration = oldInIteration;
2821 return delegate.createWhileStatement(test, body);
2824 function parseForVariableDeclaration() {
2825 var token, declarations, startToken;
2827 startToken = lookahead;
2829 declarations = parseVariableDeclarationList();
2831 return delegate.markEnd(delegate.createVariableDeclaration(declarations, token.value), startToken);
2834 function parseForStatement() {
2835 var init, test, update, left, right, body, oldInIteration, previousAllowIn = state.allowIn;
2837 init = test = update = null;
2839 expectKeyword('for');
2846 if (matchKeyword('var') || matchKeyword('let')) {
2847 state.allowIn = false;
2848 init = parseForVariableDeclaration();
2849 state.allowIn = previousAllowIn;
2851 if (init.declarations.length === 1 && matchKeyword('in')) {
2854 right = parseExpression();
2858 state.allowIn = false;
2859 init = parseExpression();
2860 state.allowIn = previousAllowIn;
2862 if (matchKeyword('in')) {
2863 // LeftHandSideExpression
2864 if (!isLeftHandSide(init)) {
2865 throwErrorTolerant({}, Messages.InvalidLHSInForIn);
2870 right = parseExpression();
2875 if (typeof left === 'undefined') {
2880 if (typeof left === 'undefined') {
2883 test = parseExpression();
2888 update = parseExpression();
2894 oldInIteration = state.inIteration;
2895 state.inIteration = true;
2897 body = parseStatement();
2899 state.inIteration = oldInIteration;
2901 return (typeof left === 'undefined') ?
2902 delegate.createForStatement(init, test, update, body) :
2903 delegate.createForInStatement(left, right, body);
2906 // 12.7 The continue statement
2908 function parseContinueStatement() {
2909 var label = null, key;
2911 expectKeyword('continue');
2913 // Optimize the most common form: 'continue;'.
2914 if (source.charCodeAt(index) === 0x3B) {
2917 if (!state.inIteration) {
2918 throwError({}, Messages.IllegalContinue);
2921 return delegate.createContinueStatement(null);
2924 if (peekLineTerminator()) {
2925 if (!state.inIteration) {
2926 throwError({}, Messages.IllegalContinue);
2929 return delegate.createContinueStatement(null);
2932 if (lookahead.type === Token.Identifier) {
2933 label = parseVariableIdentifier();
2935 key = '$' + label.name;
2936 if (!Object.prototype.hasOwnProperty.call(state.labelSet, key)) {
2937 throwError({}, Messages.UnknownLabel, label.name);
2943 if (label === null && !state.inIteration) {
2944 throwError({}, Messages.IllegalContinue);
2947 return delegate.createContinueStatement(label);
2950 // 12.8 The break statement
2952 function parseBreakStatement() {
2953 var label = null, key;
2955 expectKeyword('break');
2957 // Catch the very common case first: immediately a semicolon (U+003B).
2958 if (source.charCodeAt(index) === 0x3B) {
2961 if (!(state.inIteration || state.inSwitch)) {
2962 throwError({}, Messages.IllegalBreak);
2965 return delegate.createBreakStatement(null);
2968 if (peekLineTerminator()) {
2969 if (!(state.inIteration || state.inSwitch)) {
2970 throwError({}, Messages.IllegalBreak);
2973 return delegate.createBreakStatement(null);
2976 if (lookahead.type === Token.Identifier) {
2977 label = parseVariableIdentifier();
2979 key = '$' + label.name;
2980 if (!Object.prototype.hasOwnProperty.call(state.labelSet, key)) {
2981 throwError({}, Messages.UnknownLabel, label.name);
2987 if (label === null && !(state.inIteration || state.inSwitch)) {
2988 throwError({}, Messages.IllegalBreak);
2991 return delegate.createBreakStatement(label);
2994 // 12.9 The return statement
2996 function parseReturnStatement() {
2997 var argument = null;
2999 expectKeyword('return');
3001 if (!state.inFunctionBody) {
3002 throwErrorTolerant({}, Messages.IllegalReturn);
3005 // 'return' followed by a space and an identifier is very common.
3006 if (source.charCodeAt(index) === 0x20) {
3007 if (isIdentifierStart(source.charCodeAt(index + 1))) {
3008 argument = parseExpression();
3010 return delegate.createReturnStatement(argument);
3014 if (peekLineTerminator()) {
3015 return delegate.createReturnStatement(null);
3019 if (!match('}') && lookahead.type !== Token.EOF) {
3020 argument = parseExpression();
3026 return delegate.createReturnStatement(argument);
3029 // 12.10 The with statement
3031 function parseWithStatement() {
3035 // TODO(ikarienator): Should we update the test cases instead?
3037 throwErrorTolerant({}, Messages.StrictModeWith);
3040 expectKeyword('with');
3044 object = parseExpression();
3048 body = parseStatement();
3050 return delegate.createWithStatement(object, body);
3053 // 12.10 The swith statement
3055 function parseSwitchCase() {
3056 var test, consequent = [], statement, startToken;
3058 startToken = lookahead;
3059 if (matchKeyword('default')) {
3063 expectKeyword('case');
3064 test = parseExpression();
3068 while (index < length) {
3069 if (match('}') || matchKeyword('default') || matchKeyword('case')) {
3072 statement = parseStatement();
3073 consequent.push(statement);
3076 return delegate.markEnd(delegate.createSwitchCase(test, consequent), startToken);
3079 function parseSwitchStatement() {
3080 var discriminant, cases, clause, oldInSwitch, defaultFound;
3082 expectKeyword('switch');
3086 discriminant = parseExpression();
3096 return delegate.createSwitchStatement(discriminant, cases);
3099 oldInSwitch = state.inSwitch;
3100 state.inSwitch = true;
3101 defaultFound = false;
3103 while (index < length) {
3107 clause = parseSwitchCase();
3108 if (clause.test === null) {
3110 throwError({}, Messages.MultipleDefaultsInSwitch);
3112 defaultFound = true;
3117 state.inSwitch = oldInSwitch;
3121 return delegate.createSwitchStatement(discriminant, cases);
3124 // 12.13 The throw statement
3126 function parseThrowStatement() {
3129 expectKeyword('throw');
3131 if (peekLineTerminator()) {
3132 throwError({}, Messages.NewlineAfterThrow);
3135 argument = parseExpression();
3139 return delegate.createThrowStatement(argument);
3142 // 12.14 The try statement
3144 function parseCatchClause() {
3145 var param, body, startToken;
3147 startToken = lookahead;
3148 expectKeyword('catch');
3152 throwUnexpected(lookahead);
3155 param = parseVariableIdentifier();
3157 if (strict && isRestrictedWord(param.name)) {
3158 throwErrorTolerant({}, Messages.StrictCatchVariable);
3162 body = parseBlock();
3163 return delegate.markEnd(delegate.createCatchClause(param, body), startToken);
3166 function parseTryStatement() {
3167 var block, handlers = [], finalizer = null;
3169 expectKeyword('try');
3171 block = parseBlock();
3173 if (matchKeyword('catch')) {
3174 handlers.push(parseCatchClause());
3177 if (matchKeyword('finally')) {
3179 finalizer = parseBlock();
3182 if (handlers.length === 0 && !finalizer) {
3183 throwError({}, Messages.NoCatchOrFinally);
3186 return delegate.createTryStatement(block, [], handlers, finalizer);
3189 // 12.15 The debugger statement
3191 function parseDebuggerStatement() {
3192 expectKeyword('debugger');
3196 return delegate.createDebuggerStatement();
3201 function parseStatement() {
3202 var type = lookahead.type,
3208 if (type === Token.EOF) {
3209 throwUnexpected(lookahead);
3212 if (type === Token.Punctuator && lookahead.value === '{') {
3213 return parseBlock();
3216 startToken = lookahead;
3218 if (type === Token.Punctuator) {
3219 switch (lookahead.value) {
3221 return delegate.markEnd(parseEmptyStatement(), startToken);
3223 return delegate.markEnd(parseExpressionStatement(), startToken);
3229 if (type === Token.Keyword) {
3230 switch (lookahead.value) {
3232 return delegate.markEnd(parseBreakStatement(), startToken);
3234 return delegate.markEnd(parseContinueStatement(), startToken);
3236 return delegate.markEnd(parseDebuggerStatement(), startToken);
3238 return delegate.markEnd(parseDoWhileStatement(), startToken);
3240 return delegate.markEnd(parseForStatement(), startToken);
3242 return delegate.markEnd(parseFunctionDeclaration(), startToken);
3244 return delegate.markEnd(parseIfStatement(), startToken);
3246 return delegate.markEnd(parseReturnStatement(), startToken);
3248 return delegate.markEnd(parseSwitchStatement(), startToken);
3250 return delegate.markEnd(parseThrowStatement(), startToken);
3252 return delegate.markEnd(parseTryStatement(), startToken);
3254 return delegate.markEnd(parseVariableStatement(), startToken);
3256 return delegate.markEnd(parseWhileStatement(), startToken);
3258 return delegate.markEnd(parseWithStatement(), startToken);
3264 expr = parseExpression();
3266 // 12.12 Labelled Statements
3267 if ((expr.type === Syntax.Identifier) && match(':')) {
3270 key = '$' + expr.name;
3271 if (Object.prototype.hasOwnProperty.call(state.labelSet, key)) {
3272 throwError({}, Messages.Redeclaration, 'Label', expr.name);
3275 state.labelSet[key] = true;
3276 labeledBody = parseStatement();
3277 delete state.labelSet[key];
3278 return delegate.markEnd(delegate.createLabeledStatement(expr, labeledBody), startToken);
3283 return delegate.markEnd(delegate.createExpressionStatement(expr), startToken);
3286 // 13 Function Definition
3288 function parseFunctionSourceElements() {
3289 var sourceElement, sourceElements = [], token, directive, firstRestricted,
3290 oldLabelSet, oldInIteration, oldInSwitch, oldInFunctionBody, startToken;
3292 startToken = lookahead;
3295 while (index < length) {
3296 if (lookahead.type !== Token.StringLiteral) {
3301 sourceElement = parseSourceElement();
3302 sourceElements.push(sourceElement);
3303 if (sourceElement.expression.type !== Syntax.Literal) {
3304 // this is not directive
3307 directive = source.slice(token.start + 1, token.end - 1);
3308 if (directive === 'use strict') {
3310 if (firstRestricted) {
3311 throwErrorTolerant(firstRestricted, Messages.StrictOctalLiteral);
3314 if (!firstRestricted && token.octal) {
3315 firstRestricted = token;
3320 oldLabelSet = state.labelSet;
3321 oldInIteration = state.inIteration;
3322 oldInSwitch = state.inSwitch;
3323 oldInFunctionBody = state.inFunctionBody;
3325 state.labelSet = {};
3326 state.inIteration = false;
3327 state.inSwitch = false;
3328 state.inFunctionBody = true;
3330 while (index < length) {
3334 sourceElement = parseSourceElement();
3335 if (typeof sourceElement === 'undefined') {
3338 sourceElements.push(sourceElement);
3343 state.labelSet = oldLabelSet;
3344 state.inIteration = oldInIteration;
3345 state.inSwitch = oldInSwitch;
3346 state.inFunctionBody = oldInFunctionBody;
3348 return delegate.markEnd(delegate.createBlockStatement(sourceElements), startToken);
3351 function parseParams(firstRestricted) {
3352 var param, params = [], token, stricted, paramSet, key, message;
3357 while (index < length) {
3359 param = parseVariableIdentifier();
3360 key = '$' + token.value;
3362 if (isRestrictedWord(token.value)) {
3364 message = Messages.StrictParamName;
3366 if (Object.prototype.hasOwnProperty.call(paramSet, key)) {
3368 message = Messages.StrictParamDupe;
3370 } else if (!firstRestricted) {
3371 if (isRestrictedWord(token.value)) {
3372 firstRestricted = token;
3373 message = Messages.StrictParamName;
3374 } else if (isStrictModeReservedWord(token.value)) {
3375 firstRestricted = token;
3376 message = Messages.StrictReservedWord;
3377 } else if (Object.prototype.hasOwnProperty.call(paramSet, key)) {
3378 firstRestricted = token;
3379 message = Messages.StrictParamDupe;
3383 paramSet[key] = true;
3396 firstRestricted: firstRestricted,
3401 function parseFunctionDeclaration() {
3402 var id, params = [], body, token, stricted, tmp, firstRestricted, message, previousStrict, startToken;
3404 startToken = lookahead;
3406 expectKeyword('function');
3408 id = parseVariableIdentifier();
3410 if (isRestrictedWord(token.value)) {
3411 throwErrorTolerant(token, Messages.StrictFunctionName);
3414 if (isRestrictedWord(token.value)) {
3415 firstRestricted = token;
3416 message = Messages.StrictFunctionName;
3417 } else if (isStrictModeReservedWord(token.value)) {
3418 firstRestricted = token;
3419 message = Messages.StrictReservedWord;
3423 tmp = parseParams(firstRestricted);
3424 params = tmp.params;
3425 stricted = tmp.stricted;
3426 firstRestricted = tmp.firstRestricted;
3428 message = tmp.message;
3431 previousStrict = strict;
3432 body = parseFunctionSourceElements();
3433 if (strict && firstRestricted) {
3434 throwError(firstRestricted, message);
3436 if (strict && stricted) {
3437 throwErrorTolerant(stricted, message);
3439 strict = previousStrict;
3441 return delegate.markEnd(delegate.createFunctionDeclaration(id, params, [], body), startToken);
3444 function parseFunctionExpression() {
3445 var token, id = null, stricted, firstRestricted, message, tmp, params = [], body, previousStrict, startToken;
3447 startToken = lookahead;
3448 expectKeyword('function');
3452 id = parseVariableIdentifier();
3454 if (isRestrictedWord(token.value)) {
3455 throwErrorTolerant(token, Messages.StrictFunctionName);
3458 if (isRestrictedWord(token.value)) {
3459 firstRestricted = token;
3460 message = Messages.StrictFunctionName;
3461 } else if (isStrictModeReservedWord(token.value)) {
3462 firstRestricted = token;
3463 message = Messages.StrictReservedWord;
3468 tmp = parseParams(firstRestricted);
3469 params = tmp.params;
3470 stricted = tmp.stricted;
3471 firstRestricted = tmp.firstRestricted;
3473 message = tmp.message;
3476 previousStrict = strict;
3477 body = parseFunctionSourceElements();
3478 if (strict && firstRestricted) {
3479 throwError(firstRestricted, message);
3481 if (strict && stricted) {
3482 throwErrorTolerant(stricted, message);
3484 strict = previousStrict;
3486 return delegate.markEnd(delegate.createFunctionExpression(id, params, [], body), startToken);
3491 function parseSourceElement() {
3492 if (lookahead.type === Token.Keyword) {
3493 switch (lookahead.value) {
3496 return parseConstLetDeclaration(lookahead.value);
3498 return parseFunctionDeclaration();
3500 return parseStatement();
3504 if (lookahead.type !== Token.EOF) {
3505 return parseStatement();
3509 function parseSourceElements() {
3510 var sourceElement, sourceElements = [], token, directive, firstRestricted;
3512 while (index < length) {
3514 if (token.type !== Token.StringLiteral) {
3518 sourceElement = parseSourceElement();
3519 sourceElements.push(sourceElement);
3520 if (sourceElement.expression.type !== Syntax.Literal) {
3521 // this is not directive
3524 directive = source.slice(token.start + 1, token.end - 1);
3525 if (directive === 'use strict') {
3527 if (firstRestricted) {
3528 throwErrorTolerant(firstRestricted, Messages.StrictOctalLiteral);
3531 if (!firstRestricted && token.octal) {
3532 firstRestricted = token;
3537 while (index < length) {
3538 sourceElement = parseSourceElement();
3539 /* istanbul ignore if */
3540 if (typeof sourceElement === 'undefined') {
3543 sourceElements.push(sourceElement);
3545 return sourceElements;
3548 function parseProgram() {
3549 var body, startToken;
3553 startToken = lookahead;
3556 body = parseSourceElements();
3557 return delegate.markEnd(delegate.createProgram(body), startToken);
3560 function filterTokenLocation() {
3561 var i, entry, token, tokens = [];
3563 for (i = 0; i < extra.tokens.length; ++i) {
3564 entry = extra.tokens[i];
3570 token.range = entry.range;
3573 token.loc = entry.loc;
3578 extra.tokens = tokens;
3581 function tokenize(code, options) {
3587 if (typeof code !== 'string' && !(code instanceof String)) {
3588 code = toString(code);
3591 delegate = SyntaxTreeDelegate;
3594 lineNumber = (source.length > 0) ? 1 : 0;
3596 length = source.length;
3601 inFunctionBody: false,
3604 lastCommentStart: -1
3609 // Options matching.
3610 options = options || {};
3612 // Of course we collect tokens here.
3613 options.tokens = true;
3615 extra.tokenize = true;
3616 // The following two fields are necessary to compute the Regex tokens.
3617 extra.openParenToken = -1;
3618 extra.openCurlyToken = -1;
3620 extra.range = (typeof options.range === 'boolean') && options.range;
3621 extra.loc = (typeof options.loc === 'boolean') && options.loc;
3623 if (typeof options.comment === 'boolean' && options.comment) {
3624 extra.comments = [];
3626 if (typeof options.tolerant === 'boolean' && options.tolerant) {
3632 if (lookahead.type === Token.EOF) {
3633 return extra.tokens;
3637 while (lookahead.type !== Token.EOF) {
3640 } catch (lexError) {
3643 extra.errors.push(lexError);
3644 // We have to break on the first error
3645 // to avoid infinite loops.
3653 filterTokenLocation();
3654 tokens = extra.tokens;
3655 if (typeof extra.comments !== 'undefined') {
3656 tokens.comments = extra.comments;
3658 if (typeof extra.errors !== 'undefined') {
3659 tokens.errors = extra.errors;
3669 function parse(code, options) {
3670 var program, toString;
3673 if (typeof code !== 'string' && !(code instanceof String)) {
3674 code = toString(code);
3677 delegate = SyntaxTreeDelegate;
3680 lineNumber = (source.length > 0) ? 1 : 0;
3682 length = source.length;
3687 inFunctionBody: false,
3690 lastCommentStart: -1
3694 if (typeof options !== 'undefined') {
3695 extra.range = (typeof options.range === 'boolean') && options.range;
3696 extra.loc = (typeof options.loc === 'boolean') && options.loc;
3697 extra.attachComment = (typeof options.attachComment === 'boolean') && options.attachComment;
3699 if (extra.loc && options.source !== null && options.source !== undefined) {
3700 extra.source = toString(options.source);
3703 if (typeof options.tokens === 'boolean' && options.tokens) {
3706 if (typeof options.comment === 'boolean' && options.comment) {
3707 extra.comments = [];
3709 if (typeof options.tolerant === 'boolean' && options.tolerant) {
3712 if (extra.attachComment) {
3714 extra.comments = [];
3715 extra.bottomRightStack = [];
3716 extra.trailingComments = [];
3717 extra.leadingComments = [];
3722 program = parseProgram();
3723 if (typeof extra.comments !== 'undefined') {
3724 program.comments = extra.comments;
3726 if (typeof extra.tokens !== 'undefined') {
3727 filterTokenLocation();
3728 program.tokens = extra.tokens;
3730 if (typeof extra.errors !== 'undefined') {
3731 program.errors = extra.errors;
3742 // Sync with *.json manifests.
3743 exports.version = '1.2.5';
3745 exports.tokenize = tokenize;
3747 exports.parse = parse;
3750 /* istanbul ignore next */
3751 exports.Syntax = (function () {
3752 var name, types = {};
3754 if (typeof Object.create === 'function') {
3755 types = Object.create(null);
3758 for (name in Syntax) {
3759 if (Syntax.hasOwnProperty(name)) {
3760 types[name] = Syntax[name];
3764 if (typeof Object.freeze === 'function') {
3765 Object.freeze(types);
3772 /* vim: set sw=4 ts=4 et tw=80 : */