Download
Getting Started
Members
Projects
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
More
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
Toggle navigation
Bugzilla – Attachment 241229 Details for
Bug 423091
Update to Esprima 1.1.0-dev
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
Log In
[x]
|
Terms of Use
|
Copyright Agent
Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read
this important communication.
[patch]
towards tolerant Esprima
tolerant_esprima.patch (text/plain), 132.93 KB, created by
Michael Rennie
on 2014-03-25 11:29:37 EDT
(
hide
)
Description:
towards tolerant Esprima
Filename:
MIME Type:
Creator:
Michael Rennie
Created:
2014-03-25 11:29:37 EDT
Size:
132.93 KB
patch
obsolete
>diff --git a/bundles/org.eclipse.orion.client.ui/web/esprima/esprima_tolerant.js b/bundles/org.eclipse.orion.client.ui/web/esprima/esprima_tolerant.js >new file mode 100644 >index 0000000..27b84e3 >--- /dev/null >+++ b/bundles/org.eclipse.orion.client.ui/web/esprima/esprima_tolerant.js >@@ -0,0 +1,4082 @@ >+/* >+ Copyright (C) 2013 Ariya Hidayat <ariya.hidayat@gmail.com> >+ Copyright (C) 2013 Thaddee Tyl <thaddee.tyl@gmail.com> >+ Copyright (C) 2013 Mathias Bynens <mathias@qiwi.be> >+ Copyright (C) 2012 Ariya Hidayat <ariya.hidayat@gmail.com> >+ Copyright (C) 2012 Mathias Bynens <mathias@qiwi.be> >+ Copyright (C) 2012 Joost-Wim Boekesteijn <joost-wim@boekesteijn.nl> >+ Copyright (C) 2012 Kris Kowal <kris.kowal@cixar.com> >+ Copyright (C) 2012 Yusuke Suzuki <utatane.tea@gmail.com> >+ Copyright (C) 2012 Arpad Borsos <arpad.borsos@googlemail.com> >+ Copyright (C) 2011 Ariya Hidayat <ariya.hidayat@gmail.com> >+ >+ Redistribution and use in source and binary forms, with or without >+ modification, are permitted provided that the following conditions are met: >+ >+ * Redistributions of source code must retain the above copyright >+ notice, this list of conditions and the following disclaimer. >+ * Redistributions in binary form must reproduce the above copyright >+ notice, this list of conditions and the following disclaimer in the >+ documentation and/or other materials provided with the distribution. >+ >+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" >+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE >+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE >+ ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY >+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES >+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; >+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND >+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT >+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF >+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >+*/ >+ >+/*jslint bitwise:true plusplus:true */ >+/*global esprima:true, define:true, exports:true, window: true, >+createLocationMarker: true, >+throwError: true, generateStatement: true, peek: true, >+parseAssignmentExpression: true, parseBlock: true, >+expectConditionCloseBracketWrapThrow: true, parseExpression: true, >+parseFunctionDeclaration: true, parseFunctionExpression: true, >+parseFunctionSourceElements: true, parseVariableIdentifier: true, >+parseLeftHandSideExpression: true, >+parseUnaryExpression: true, >+parseStatement: true, parseSourceElement: true */ >+ >+(function (root, factory) { >+ 'use strict'; >+ >+ // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js, >+ // Rhino, and plain browser loading. >+ if (typeof define === 'function' && define.amd) { >+ define(['exports'], factory); >+ } else if (typeof exports !== 'undefined') { >+ factory(exports); >+ } else { >+ factory((root.esprima = {})); >+ } >+}(this, function (exports) { >+ 'use strict'; >+ >+ var Token, >+ TokenName, >+ FnExprTokens, >+ Syntax, >+ PropertyKind, >+ Messages, >+ Regex, >+ SyntaxTreeDelegate, >+ source, >+ strict, >+ index, >+ lineNumber, >+ lineStart, >+ length, >+ delegate, >+ lookahead, >+ state, >+ extra; >+ >+ Token = { >+ BooleanLiteral: 1, >+ EOF: 2, >+ Identifier: 3, >+ Keyword: 4, >+ NullLiteral: 5, >+ NumericLiteral: 6, >+ Punctuator: 7, >+ StringLiteral: 8, >+ RegularExpression: 9 >+ }; >+ >+ TokenName = {}; >+ TokenName[Token.BooleanLiteral] = 'Boolean'; >+ TokenName[Token.EOF] = '<end>'; >+ TokenName[Token.Identifier] = 'Identifier'; >+ TokenName[Token.Keyword] = 'Keyword'; >+ TokenName[Token.NullLiteral] = 'Null'; >+ TokenName[Token.NumericLiteral] = 'Numeric'; >+ TokenName[Token.Punctuator] = 'Punctuator'; >+ TokenName[Token.StringLiteral] = 'String'; >+ TokenName[Token.RegularExpression] = 'RegularExpression'; >+ >+ // A function following one of those tokens is an expression. >+ FnExprTokens = ['(', '{', '[', 'in', 'typeof', 'instanceof', 'new', >+ 'return', 'case', 'delete', 'throw', 'void', >+ // assignment operators >+ '=', '+=', '-=', '*=', '/=', '%=', '<<=', '>>=', '>>>=', >+ '&=', '|=', '^=', ',', >+ // binary/unary operators >+ '+', '-', '*', '/', '%', '++', '--', '<<', '>>', '>>>', '&', >+ '|', '^', '!', '~', '&&', '||', '?', ':', '===', '==', '>=', >+ '<=', '<', '>', '!=', '!==']; >+ >+ Syntax = { >+ AssignmentExpression: 'AssignmentExpression', >+ ArrayExpression: 'ArrayExpression', >+ BlockStatement: 'BlockStatement', >+ BinaryExpression: 'BinaryExpression', >+ BreakStatement: 'BreakStatement', >+ CallExpression: 'CallExpression', >+ CatchClause: 'CatchClause', >+ ConditionalExpression: 'ConditionalExpression', >+ ContinueStatement: 'ContinueStatement', >+ DoWhileStatement: 'DoWhileStatement', >+ DebuggerStatement: 'DebuggerStatement', >+ EmptyStatement: 'EmptyStatement', >+ ExpressionStatement: 'ExpressionStatement', >+ ForStatement: 'ForStatement', >+ ForInStatement: 'ForInStatement', >+ FunctionDeclaration: 'FunctionDeclaration', >+ FunctionExpression: 'FunctionExpression', >+ Identifier: 'Identifier', >+ IfStatement: 'IfStatement', >+ Literal: 'Literal', >+ LabeledStatement: 'LabeledStatement', >+ LogicalExpression: 'LogicalExpression', >+ MemberExpression: 'MemberExpression', >+ NewExpression: 'NewExpression', >+ ObjectExpression: 'ObjectExpression', >+ Program: 'Program', >+ Property: 'Property', >+ ReturnStatement: 'ReturnStatement', >+ SequenceExpression: 'SequenceExpression', >+ SwitchStatement: 'SwitchStatement', >+ SwitchCase: 'SwitchCase', >+ ThisExpression: 'ThisExpression', >+ ThrowStatement: 'ThrowStatement', >+ TryStatement: 'TryStatement', >+ UnaryExpression: 'UnaryExpression', >+ UpdateExpression: 'UpdateExpression', >+ VariableDeclaration: 'VariableDeclaration', >+ VariableDeclarator: 'VariableDeclarator', >+ WhileStatement: 'WhileStatement', >+ WithStatement: 'WithStatement' >+ }; >+ >+ PropertyKind = { >+ Data: 1, >+ Get: 2, >+ Set: 4 >+ }; >+ >+ // Error messages should be identical to V8. >+ Messages = { >+ UnexpectedToken: 'Unexpected token %0', >+ UnexpectedNumber: 'Unexpected number', >+ UnexpectedString: 'Unexpected string', >+ UnexpectedIdentifier: 'Unexpected identifier', >+ UnexpectedReserved: 'Unexpected reserved word', >+ UnexpectedEOS: 'Unexpected end of input', >+ NewlineAfterThrow: 'Illegal newline after throw', >+ InvalidRegExp: 'Invalid regular expression', >+ UnterminatedRegExp: 'Invalid regular expression: missing /', >+ InvalidLHSInAssignment: 'Invalid left-hand side in assignment', >+ InvalidLHSInForIn: 'Invalid left-hand side in for-in', >+ MultipleDefaultsInSwitch: 'More than one default clause in switch statement', >+ NoCatchOrFinally: 'Missing catch or finally after try', >+ UnknownLabel: 'Undefined label \'%0\'', >+ Redeclaration: '%0 \'%1\' has already been declared', >+ IllegalContinue: 'Illegal continue statement', >+ IllegalBreak: 'Illegal break statement', >+ IllegalReturn: 'Illegal return statement', >+ StrictModeWith: 'Strict mode code may not include a with statement', >+ StrictCatchVariable: 'Catch variable may not be eval or arguments in strict mode', >+ StrictVarName: 'Variable name may not be eval or arguments in strict mode', >+ StrictParamName: 'Parameter name eval or arguments is not allowed in strict mode', >+ StrictParamDupe: 'Strict mode function may not have duplicate parameter names', >+ StrictFunctionName: 'Function name may not be eval or arguments in strict mode', >+ StrictOctalLiteral: 'Octal literals are not allowed in strict mode.', >+ StrictDelete: 'Delete of an unqualified identifier in strict mode.', >+ StrictDuplicateProperty: 'Duplicate data property in object literal not allowed in strict mode', >+ AccessorDataProperty: 'Object literal may not have data and accessor property with the same name', >+ AccessorGetSet: 'Object literal may not have multiple get/set accessors with the same name', >+ StrictLHSAssignment: 'Assignment to eval or arguments is not allowed in strict mode', >+ StrictLHSPostfix: 'Postfix increment/decrement may not have eval or arguments operand in strict mode', >+ StrictLHSPrefix: 'Prefix increment/decrement may not have eval or arguments operand in strict mode', >+ StrictReservedWord: 'Use of future reserved word in strict mode' >+ }; >+ >+ // See also tools/generate-unicode-regex.py. >+ Regex = { >+ 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]'), >+ 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]') >+ }; >+ >+ // Ensure the condition is true, otherwise throw an error. >+ // This is only to have a better contract semantic, i.e. another safety net >+ // to catch a logic error. The condition shall be fulfilled in normal case. >+ // Do NOT use this to enforce a certain condition on any user input. >+ >+ function assert(condition, message) { >+ if (!condition) { >+ throw new Error('ASSERT: ' + message); >+ } >+ } >+ >+ function isDecimalDigit(ch) { >+ return (ch >= 48 && ch <= 57); // 0..9 >+ } >+ >+ function isHexDigit(ch) { >+ return '0123456789abcdefABCDEF'.indexOf(ch) >= 0; >+ } >+ >+ function isOctalDigit(ch) { >+ return '01234567'.indexOf(ch) >= 0; >+ } >+ >+ >+ // 7.2 White Space >+ >+ function isWhiteSpace(ch) { >+ return (ch === 0x20) || (ch === 0x09) || (ch === 0x0B) || (ch === 0x0C) || (ch === 0xA0) || >+ (ch >= 0x1680 && [0x1680, 0x180E, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008, 0x2009, 0x200A, 0x202F, 0x205F, 0x3000, 0xFEFF].indexOf(ch) >= 0); >+ } >+ >+ // 7.3 Line Terminators >+ >+ function isLineTerminator(ch) { >+ return (ch === 0x0A) || (ch === 0x0D) || (ch === 0x2028) || (ch === 0x2029); >+ } >+ >+ // 7.6 Identifier Names and Identifiers >+ >+ function isIdentifierStart(ch) { >+ return (ch === 36) || (ch === 95) || // $ (dollar) and _ (underscore) >+ (ch >= 65 && ch <= 90) || // A..Z >+ (ch >= 97 && ch <= 122) || // a..z >+ (ch === 92) || // \ (backslash) >+ ((ch >= 0x80) && Regex.NonAsciiIdentifierStart.test(String.fromCharCode(ch))); >+ } >+ >+ function isIdentifierPart(ch) { >+ return (ch === 36) || (ch === 95) || // $ (dollar) and _ (underscore) >+ (ch >= 65 && ch <= 90) || // A..Z >+ (ch >= 97 && ch <= 122) || // a..z >+ (ch >= 48 && ch <= 57) || // 0..9 >+ (ch === 92) || // \ (backslash) >+ ((ch >= 0x80) && Regex.NonAsciiIdentifierPart.test(String.fromCharCode(ch))); >+ } >+ >+ // 7.6.1.2 Future Reserved Words >+ >+ function isFutureReservedWord(id) { >+ switch (id) { >+ case 'class': >+ case 'enum': >+ case 'export': >+ case 'extends': >+ case 'import': >+ case 'super': >+ return true; >+ default: >+ return false; >+ } >+ } >+ >+ function isStrictModeReservedWord(id) { >+ switch (id) { >+ case 'implements': >+ case 'interface': >+ case 'package': >+ case 'private': >+ case 'protected': >+ case 'public': >+ case 'static': >+ case 'yield': >+ case 'let': >+ return true; >+ default: >+ return false; >+ } >+ } >+ >+ function isRestrictedWord(id) { >+ return id === 'eval' || id === 'arguments'; >+ } >+ >+ // 7.6.1.1 Keywords >+ >+ function isKeyword(id) { >+ if (strict && isStrictModeReservedWord(id)) { >+ return true; >+ } >+ >+ // 'const' is specialized as Keyword in V8. >+ // 'yield' and 'let' are for compatiblity with SpiderMonkey and ES.next. >+ // Some others are from future reserved words. >+ >+ switch (id.length) { >+ case 2: >+ return (id === 'if') || (id === 'in') || (id === 'do'); >+ case 3: >+ return (id === 'var') || (id === 'for') || (id === 'new') || >+ (id === 'try') || (id === 'let'); >+ case 4: >+ return (id === 'this') || (id === 'else') || (id === 'case') || >+ (id === 'void') || (id === 'with') || (id === 'enum'); >+ case 5: >+ return (id === 'while') || (id === 'break') || (id === 'catch') || >+ (id === 'throw') || (id === 'const') || (id === 'yield') || >+ (id === 'class') || (id === 'super'); >+ case 6: >+ return (id === 'return') || (id === 'typeof') || (id === 'delete') || >+ (id === 'switch') || (id === 'export') || (id === 'import'); >+ case 7: >+ return (id === 'default') || (id === 'finally') || (id === 'extends'); >+ case 8: >+ return (id === 'function') || (id === 'continue') || (id === 'debugger'); >+ case 10: >+ return (id === 'instanceof'); >+ default: >+ return false; >+ } >+ } >+ >+ // 7.4 Comments >+ >+ function addComment(type, value, start, end, loc) { >+ var comment, attacher; >+ >+ assert(typeof start === 'number', 'Comment must have valid position'); >+ >+ // Because the way the actual token is scanned, often the comments >+ // (if any) are skipped twice during the lexical analysis. >+ // Thus, we need to skip adding a comment if the comment array already >+ // handled it. >+ if (state.lastCommentStart >= start) { >+ return; >+ } >+ state.lastCommentStart = start; >+ >+ comment = { >+ type: type, >+ value: value >+ }; >+ if (extra.range) { >+ comment.range = [start, end]; >+ } >+ if (extra.loc) { >+ comment.loc = loc; >+ } >+ extra.comments.push(comment); >+ >+ if (extra.attachComment) { >+ attacher = { >+ comment: comment, >+ leading: null, >+ trailing: null, >+ range: [start, end] >+ }; >+ extra.pendingComments.push(attacher); >+ } >+ } >+ >+ function skipSingleLineComment() { >+ var start, loc, ch, comment; >+ >+ start = index - 2; >+ loc = { >+ start: { >+ line: lineNumber, >+ column: index - lineStart - 2 >+ } >+ }; >+ >+ while (index < length) { >+ ch = source.charCodeAt(index); >+ ++index; >+ if (isLineTerminator(ch)) { >+ if (extra.comments) { >+ comment = source.slice(start + 2, index - 1); >+ loc.end = { >+ line: lineNumber, >+ column: index - lineStart - 1 >+ }; >+ addComment('Line', comment, start, index - 1, loc); >+ } >+ if (ch === 13 && source.charCodeAt(index) === 10) { >+ ++index; >+ } >+ ++lineNumber; >+ lineStart = index; >+ return; >+ } >+ } >+ >+ if (extra.comments) { >+ comment = source.slice(start + 2, index); >+ loc.end = { >+ line: lineNumber, >+ column: index - lineStart >+ }; >+ addComment('Line', comment, start, index, loc); >+ } >+ } >+ >+ function skipMultiLineComment() { >+ var start, loc, ch, comment; >+ >+ if (extra.comments) { >+ start = index - 2; >+ loc = { >+ start: { >+ line: lineNumber, >+ column: index - lineStart - 2 >+ } >+ }; >+ } >+ >+ while (index < length) { >+ ch = source.charCodeAt(index); >+ if (isLineTerminator(ch)) { >+ if (ch === 13 && source.charCodeAt(index + 1) === 10) { >+ ++index; >+ } >+ ++lineNumber; >+ ++index; >+ lineStart = index; >+ if (index >= length) { >+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); >+ } >+ } else if (ch === 42) { >+ // Block comment ends with '*/' (char #42, char #47). >+ if (source.charCodeAt(index + 1) === 47) { >+ ++index; >+ ++index; >+ if (extra.comments) { >+ comment = source.slice(start + 2, index - 2); >+ loc.end = { >+ line: lineNumber, >+ column: index - lineStart >+ }; >+ addComment('Block', comment, start, index, loc); >+ } >+ return; >+ } >+ ++index; >+ } else { >+ ++index; >+ } >+ } >+ >+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); >+ } >+ >+ function skipComment() { >+ var ch, start; >+ >+ start = (index === 0); >+ while (index < length) { >+ ch = source.charCodeAt(index); >+ >+ if (isWhiteSpace(ch)) { >+ ++index; >+ } else if (isLineTerminator(ch)) { >+ ++index; >+ if (ch === 13 && source.charCodeAt(index) === 10) { >+ ++index; >+ } >+ ++lineNumber; >+ lineStart = index; >+ start = true; >+ } else if (ch === 47) { // 47 is '/' >+ ch = source.charCodeAt(index + 1); >+ if (ch === 47) { >+ ++index; >+ ++index; >+ skipSingleLineComment(); >+ start = true; >+ } else if (ch === 42) { // 42 is '*' >+ ++index; >+ ++index; >+ skipMultiLineComment(); >+ } else { >+ break; >+ } >+ } else if (start && ch === 45) { // 45 is '-' >+ // 62 is '>' >+ if ((source.charCodeAt(index + 1) === 45) && (source.charCodeAt(index + 2) === 62)) { >+ // '-->' is a single-line comment >+ index += 3; >+ skipSingleLineComment(); >+ } else { >+ break; >+ } >+ } else if (ch === 60) { // 60 is '<' >+ if (source.slice(index + 1, index + 4) === '!--') { >+ ++index; // `<` >+ ++index; // `!` >+ ++index; // `-` >+ ++index; // `-` >+ skipSingleLineComment(); >+ } else { >+ break; >+ } >+ } else { >+ break; >+ } >+ } >+ } >+ >+ function scanHexEscape(prefix) { >+ var i, len, ch, code = 0; >+ >+ len = (prefix === 'u') ? 4 : 2; >+ for (i = 0; i < len; ++i) { >+ if (index < length && isHexDigit(source[index])) { >+ ch = source[index++]; >+ code = code * 16 + '0123456789abcdef'.indexOf(ch.toLowerCase()); >+ } else { >+ return ''; >+ } >+ } >+ return String.fromCharCode(code); >+ } >+ >+ function getEscapedIdentifier() { >+ var ch, id; >+ >+ ch = source.charCodeAt(index++); >+ id = String.fromCharCode(ch); >+ >+ // '\u' (char #92, char #117) denotes an escaped character. >+ if (ch === 92) { >+ if (source.charCodeAt(index) !== 117) { >+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); >+ } >+ ++index; >+ ch = scanHexEscape('u'); >+ if (!ch || ch === '\\' || !isIdentifierStart(ch.charCodeAt(0))) { >+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); >+ } >+ id = ch; >+ } >+ >+ while (index < length) { >+ ch = source.charCodeAt(index); >+ if (!isIdentifierPart(ch)) { >+ break; >+ } >+ ++index; >+ id += String.fromCharCode(ch); >+ >+ // '\u' (char #92, char #117) denotes an escaped character. >+ if (ch === 92) { >+ id = id.substr(0, id.length - 1); >+ if (source.charCodeAt(index) !== 117) { >+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); >+ } >+ ++index; >+ ch = scanHexEscape('u'); >+ if (!ch || ch === '\\' || !isIdentifierPart(ch.charCodeAt(0))) { >+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); >+ } >+ id += ch; >+ } >+ } >+ >+ return id; >+ } >+ >+ function getIdentifier() { >+ var start, ch; >+ >+ start = index++; >+ while (index < length) { >+ ch = source.charCodeAt(index); >+ if (ch === 92) { >+ // Blackslash (char #92) marks Unicode escape sequence. >+ index = start; >+ return getEscapedIdentifier(); >+ } >+ if (isIdentifierPart(ch)) { >+ ++index; >+ } else { >+ break; >+ } >+ } >+ >+ return source.slice(start, index); >+ } >+ >+ function scanIdentifier() { >+ var start, id, type; >+ >+ start = index; >+ >+ // Backslash (char #92) starts an escaped character. >+ id = (source.charCodeAt(index) === 92) ? getEscapedIdentifier() : getIdentifier(); >+ >+ // There is no keyword or literal with only one character. >+ // Thus, it must be an identifier. >+ if (id.length === 1) { >+ type = Token.Identifier; >+ } else if (isKeyword(id)) { >+ type = Token.Keyword; >+ } else if (id === 'null') { >+ type = Token.NullLiteral; >+ } else if (id === 'true' || id === 'false') { >+ type = Token.BooleanLiteral; >+ } else { >+ type = Token.Identifier; >+ } >+ >+ return { >+ type: type, >+ value: id, >+ lineNumber: lineNumber, >+ lineStart: lineStart, >+ range: [start, index] >+ }; >+ } >+ >+ >+ // 7.7 Punctuators >+ >+ function scanPunctuator() { >+ var start = index, >+ code = source.charCodeAt(index), >+ code2, >+ ch1 = source[index], >+ ch2, >+ ch3, >+ ch4; >+ >+ switch (code) { >+ >+ // Check for most common single-character punctuators. >+ case 46: // . dot >+ case 40: // ( open bracket >+ case 41: // ) close bracket >+ case 59: // ; semicolon >+ case 44: // , comma >+ case 123: // { open curly brace >+ case 125: // } close curly brace >+ case 91: // [ >+ case 93: // ] >+ case 58: // : >+ case 63: // ? >+ case 126: // ~ >+ ++index; >+ if (extra.tokenize) { >+ if (code === 40) { >+ extra.openParenToken = extra.tokens.length; >+ } else if (code === 123) { >+ extra.openCurlyToken = extra.tokens.length; >+ } >+ } >+ return { >+ type: Token.Punctuator, >+ value: String.fromCharCode(code), >+ lineNumber: lineNumber, >+ lineStart: lineStart, >+ range: [start, index] >+ }; >+ >+ default: >+ code2 = source.charCodeAt(index + 1); >+ >+ // '=' (char #61) marks an assignment or comparison operator. >+ if (code2 === 61) { >+ switch (code) { >+ case 37: // % >+ case 38: // & >+ case 42: // *: >+ case 43: // + >+ case 45: // - >+ case 47: // / >+ case 60: // < >+ case 62: // > >+ case 94: // ^ >+ case 124: // | >+ index += 2; >+ return { >+ type: Token.Punctuator, >+ value: String.fromCharCode(code) + String.fromCharCode(code2), >+ lineNumber: lineNumber, >+ lineStart: lineStart, >+ range: [start, index] >+ }; >+ >+ case 33: // ! >+ case 61: // = >+ index += 2; >+ >+ // !== and === >+ if (source.charCodeAt(index) === 61) { >+ ++index; >+ } >+ return { >+ type: Token.Punctuator, >+ value: source.slice(start, index), >+ lineNumber: lineNumber, >+ lineStart: lineStart, >+ range: [start, index] >+ }; >+ default: >+ break; >+ } >+ } >+ break; >+ } >+ >+ // Peek more characters. >+ >+ ch2 = source[index + 1]; >+ ch3 = source[index + 2]; >+ ch4 = source[index + 3]; >+ >+ // 4-character punctuator: >>>= >+ >+ if (ch1 === '>' && ch2 === '>' && ch3 === '>') { >+ if (ch4 === '=') { >+ index += 4; >+ return { >+ type: Token.Punctuator, >+ value: '>>>=', >+ lineNumber: lineNumber, >+ lineStart: lineStart, >+ range: [start, index] >+ }; >+ } >+ } >+ >+ // 3-character punctuators: === !== >>> <<= >>= >+ >+ if (ch1 === '>' && ch2 === '>' && ch3 === '>') { >+ index += 3; >+ return { >+ type: Token.Punctuator, >+ value: '>>>', >+ lineNumber: lineNumber, >+ lineStart: lineStart, >+ range: [start, index] >+ }; >+ } >+ >+ if (ch1 === '<' && ch2 === '<' && ch3 === '=') { >+ index += 3; >+ return { >+ type: Token.Punctuator, >+ value: '<<=', >+ lineNumber: lineNumber, >+ lineStart: lineStart, >+ range: [start, index] >+ }; >+ } >+ >+ if (ch1 === '>' && ch2 === '>' && ch3 === '=') { >+ index += 3; >+ return { >+ type: Token.Punctuator, >+ value: '>>=', >+ lineNumber: lineNumber, >+ lineStart: lineStart, >+ range: [start, index] >+ }; >+ } >+ >+ // Other 2-character punctuators: ++ -- << >> && || >+ >+ if (ch1 === ch2 && ('+-<>&|'.indexOf(ch1) >= 0)) { >+ index += 2; >+ return { >+ type: Token.Punctuator, >+ value: ch1 + ch2, >+ lineNumber: lineNumber, >+ lineStart: lineStart, >+ range: [start, index] >+ }; >+ } >+ >+ if ('<>=!+-*%&|^/'.indexOf(ch1) >= 0) { >+ ++index; >+ return { >+ type: Token.Punctuator, >+ value: ch1, >+ lineNumber: lineNumber, >+ lineStart: lineStart, >+ range: [start, index] >+ }; >+ } >+ >+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); >+ } >+ >+ // 7.8.3 Numeric Literals >+ >+ function scanHexLiteral(start) { >+ var number = ''; >+ >+ while (index < length) { >+ if (!isHexDigit(source[index])) { >+ break; >+ } >+ number += source[index++]; >+ } >+ >+ if (number.length === 0) { >+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); >+ } >+ >+ if (isIdentifierStart(source.charCodeAt(index))) { >+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); >+ } >+ >+ return { >+ type: Token.NumericLiteral, >+ value: parseInt('0x' + number, 16), >+ lineNumber: lineNumber, >+ lineStart: lineStart, >+ range: [start, index] >+ }; >+ } >+ >+ function scanOctalLiteral(start) { >+ var number = '0' + source[index++]; >+ while (index < length) { >+ if (!isOctalDigit(source[index])) { >+ break; >+ } >+ number += source[index++]; >+ } >+ >+ if (isIdentifierStart(source.charCodeAt(index)) || isDecimalDigit(source.charCodeAt(index))) { >+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); >+ } >+ >+ return { >+ type: Token.NumericLiteral, >+ value: parseInt(number, 8), >+ octal: true, >+ lineNumber: lineNumber, >+ lineStart: lineStart, >+ range: [start, index] >+ }; >+ } >+ >+ function scanNumericLiteral() { >+ var number, start, ch; >+ >+ ch = source[index]; >+ assert(isDecimalDigit(ch.charCodeAt(0)) || (ch === '.'), >+ 'Numeric literal must start with a decimal digit or a decimal point'); >+ >+ start = index; >+ number = ''; >+ if (ch !== '.') { >+ number = source[index++]; >+ ch = source[index]; >+ >+ // Hex number starts with '0x'. >+ // Octal number starts with '0'. >+ if (number === '0') { >+ if (ch === 'x' || ch === 'X') { >+ ++index; >+ return scanHexLiteral(start); >+ } >+ if (isOctalDigit(ch)) { >+ return scanOctalLiteral(start); >+ } >+ >+ // decimal number starts with '0' such as '09' is illegal. >+ if (ch && isDecimalDigit(ch.charCodeAt(0))) { >+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); >+ } >+ } >+ >+ while (isDecimalDigit(source.charCodeAt(index))) { >+ number += source[index++]; >+ } >+ ch = source[index]; >+ } >+ >+ if (ch === '.') { >+ number += source[index++]; >+ while (isDecimalDigit(source.charCodeAt(index))) { >+ number += source[index++]; >+ } >+ ch = source[index]; >+ } >+ >+ if (ch === 'e' || ch === 'E') { >+ number += source[index++]; >+ >+ ch = source[index]; >+ if (ch === '+' || ch === '-') { >+ number += source[index++]; >+ } >+ if (isDecimalDigit(source.charCodeAt(index))) { >+ while (isDecimalDigit(source.charCodeAt(index))) { >+ number += source[index++]; >+ } >+ } else { >+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); >+ } >+ } >+ >+ if (isIdentifierStart(source.charCodeAt(index))) { >+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); >+ } >+ >+ return { >+ type: Token.NumericLiteral, >+ value: parseFloat(number), >+ lineNumber: lineNumber, >+ lineStart: lineStart, >+ range: [start, index] >+ }; >+ } >+ >+ // 7.8.4 String Literals >+ >+ function scanStringLiteral() { >+ var str = '', quote, start, ch, code, unescaped, restore, octal = false; >+ >+ quote = source[index]; >+ assert((quote === '\'' || quote === '"'), >+ 'String literal must starts with a quote'); >+ >+ start = index; >+ ++index; >+ >+ while (index < length) { >+ ch = source[index++]; >+ >+ if (ch === quote) { >+ quote = ''; >+ break; >+ } else if (ch === '\\') { >+ ch = source[index++]; >+ if (!ch || !isLineTerminator(ch.charCodeAt(0))) { >+ switch (ch) { >+ case 'n': >+ str += '\n'; >+ break; >+ case 'r': >+ str += '\r'; >+ break; >+ case 't': >+ str += '\t'; >+ break; >+ case 'u': >+ case 'x': >+ restore = index; >+ unescaped = scanHexEscape(ch); >+ if (unescaped) { >+ str += unescaped; >+ } else { >+ index = restore; >+ str += ch; >+ } >+ break; >+ case 'b': >+ str += '\b'; >+ break; >+ case 'f': >+ str += '\f'; >+ break; >+ case 'v': >+ str += '\x0B'; >+ break; >+ >+ default: >+ if (isOctalDigit(ch)) { >+ code = '01234567'.indexOf(ch); >+ >+ // \0 is not octal escape sequence >+ if (code !== 0) { >+ octal = true; >+ } >+ >+ if (index < length && isOctalDigit(source[index])) { >+ octal = true; >+ code = code * 8 + '01234567'.indexOf(source[index++]); >+ >+ // 3 digits are only allowed when string starts >+ // with 0, 1, 2, 3 >+ if ('0123'.indexOf(ch) >= 0 && >+ index < length && >+ isOctalDigit(source[index])) { >+ code = code * 8 + '01234567'.indexOf(source[index++]); >+ } >+ } >+ str += String.fromCharCode(code); >+ } else { >+ str += ch; >+ } >+ break; >+ } >+ } else { >+ ++lineNumber; >+ if (ch === '\r' && source[index] === '\n') { >+ ++index; >+ } >+ } >+ } else if (isLineTerminator(ch.charCodeAt(0))) { >+ break; >+ } else { >+ str += ch; >+ } >+ } >+ >+ if (quote !== '') { >+ throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); >+ } >+ >+ return { >+ type: Token.StringLiteral, >+ value: str, >+ octal: octal, >+ lineNumber: lineNumber, >+ lineStart: lineStart, >+ range: [start, index] >+ }; >+ } >+ >+ function scanRegExp() { >+ var str, ch, start, pattern, flags, value, classMarker = false, restore, terminated = false; >+ >+ lookahead = null; >+ skipComment(); >+ >+ start = index; >+ ch = source[index]; >+ assert(ch === '/', 'Regular expression literal must start with a slash'); >+ str = source[index++]; >+ >+ while (index < length) { >+ ch = source[index++]; >+ str += ch; >+ if (ch === '\\') { >+ ch = source[index++]; >+ // ECMA-262 7.8.5 >+ if (isLineTerminator(ch.charCodeAt(0))) { >+ throwError({}, Messages.UnterminatedRegExp); >+ } >+ str += ch; >+ } else if (isLineTerminator(ch.charCodeAt(0))) { >+ throwError({}, Messages.UnterminatedRegExp); >+ } else if (classMarker) { >+ if (ch === ']') { >+ classMarker = false; >+ } >+ } else { >+ if (ch === '/') { >+ terminated = true; >+ break; >+ } else if (ch === '[') { >+ classMarker = true; >+ } >+ } >+ } >+ >+ if (!terminated) { >+ throwError({}, Messages.UnterminatedRegExp); >+ } >+ >+ // Exclude leading and trailing slash. >+ pattern = str.substr(1, str.length - 2); >+ >+ flags = ''; >+ while (index < length) { >+ ch = source[index]; >+ if (!isIdentifierPart(ch.charCodeAt(0))) { >+ break; >+ } >+ >+ ++index; >+ if (ch === '\\' && index < length) { >+ ch = source[index]; >+ if (ch === 'u') { >+ ++index; >+ restore = index; >+ ch = scanHexEscape('u'); >+ if (ch) { >+ flags += ch; >+ for (str += '\\u'; restore < index; ++restore) { >+ str += source[restore]; >+ } >+ } else { >+ index = restore; >+ flags += 'u'; >+ str += '\\u'; >+ } >+ } else { >+ str += '\\'; >+ } >+ } else { >+ flags += ch; >+ str += ch; >+ } >+ } >+ >+ try { >+ value = new RegExp(pattern, flags); >+ } catch (e) { >+ throwError({}, Messages.InvalidRegExp); >+ } >+ >+ >+ >+ if (extra.tokenize) { >+ return { >+ type: Token.RegularExpression, >+ value: value, >+ lineNumber: lineNumber, >+ lineStart: lineStart, >+ range: [start, index] >+ }; >+ } >+ return { >+ literal: str, >+ value: value, >+ range: [start, index] >+ }; >+ } >+ >+ function collectRegex() { >+ var pos, loc, regex, token; >+ >+ skipComment(); >+ >+ pos = index; >+ loc = { >+ start: { >+ line: lineNumber, >+ column: index - lineStart >+ } >+ }; >+ >+ regex = scanRegExp(); >+ loc.end = { >+ line: lineNumber, >+ column: index - lineStart >+ }; >+ >+ if (!extra.tokenize) { >+ // Pop the previous token, which is likely '/' or '/=' >+ if (extra.tokens.length > 0) { >+ token = extra.tokens[extra.tokens.length - 1]; >+ if (token.range[0] === pos && token.type === 'Punctuator') { >+ if (token.value === '/' || token.value === '/=') { >+ extra.tokens.pop(); >+ } >+ } >+ } >+ >+ extra.tokens.push({ >+ type: 'RegularExpression', >+ value: regex.literal, >+ range: [pos, index], >+ loc: loc >+ }); >+ } >+ >+ return regex; >+ } >+ >+ function isIdentifierName(token) { >+ return token.type === Token.Identifier || >+ token.type === Token.Keyword || >+ token.type === Token.BooleanLiteral || >+ token.type === Token.NullLiteral; >+ } >+ >+ function advanceSlash() { >+ var prevToken, >+ checkToken; >+ // Using the following algorithm: >+ // https://github.com/mozilla/sweet.js/wiki/design >+ prevToken = extra.tokens[extra.tokens.length - 1]; >+ if (!prevToken) { >+ // Nothing before that: it cannot be a division. >+ return collectRegex(); >+ } >+ if (prevToken.type === 'Punctuator') { >+ if (prevToken.value === ')') { >+ checkToken = extra.tokens[extra.openParenToken - 1]; >+ if (checkToken && >+ checkToken.type === 'Keyword' && >+ (checkToken.value === 'if' || >+ checkToken.value === 'while' || >+ checkToken.value === 'for' || >+ checkToken.value === 'with')) { >+ return collectRegex(); >+ } >+ return scanPunctuator(); >+ } >+ if (prevToken.value === '}') { >+ // Dividing a function by anything makes little sense, >+ // but we have to check for that. >+ if (extra.tokens[extra.openCurlyToken - 3] && >+ extra.tokens[extra.openCurlyToken - 3].type === 'Keyword') { >+ // Anonymous function. >+ checkToken = extra.tokens[extra.openCurlyToken - 4]; >+ if (!checkToken) { >+ return scanPunctuator(); >+ } >+ } else if (extra.tokens[extra.openCurlyToken - 4] && >+ extra.tokens[extra.openCurlyToken - 4].type === 'Keyword') { >+ // Named function. >+ checkToken = extra.tokens[extra.openCurlyToken - 5]; >+ if (!checkToken) { >+ return collectRegex(); >+ } >+ } else { >+ return scanPunctuator(); >+ } >+ // checkToken determines whether the function is >+ // a declaration or an expression. >+ if (FnExprTokens.indexOf(checkToken.value) >= 0) { >+ // It is an expression. >+ return scanPunctuator(); >+ } >+ // It is a declaration. >+ return collectRegex(); >+ } >+ return collectRegex(); >+ } >+ if (prevToken.type === 'Keyword') { >+ return collectRegex(); >+ } >+ return scanPunctuator(); >+ } >+ >+ function advance() { >+ var ch; >+ >+ skipComment(); >+ >+ if (index >= length) { >+ return { >+ type: Token.EOF, >+ lineNumber: lineNumber, >+ lineStart: lineStart, >+ range: [index, index] >+ }; >+ } >+ >+ ch = source.charCodeAt(index); >+ >+ // Very common: ( and ) and ; >+ if (ch === 40 || ch === 41 || ch === 58) { >+ return scanPunctuator(); >+ } >+ >+ // String literal starts with single quote (#39) or double quote (#34). >+ if (ch === 39 || ch === 34) { >+ return scanStringLiteral(); >+ } >+ >+ if (isIdentifierStart(ch)) { >+ return scanIdentifier(); >+ } >+ >+ // Dot (.) char #46 can also start a floating-point number, hence the need >+ // to check the next character. >+ if (ch === 46) { >+ if (isDecimalDigit(source.charCodeAt(index + 1))) { >+ return scanNumericLiteral(); >+ } >+ return scanPunctuator(); >+ } >+ >+ if (isDecimalDigit(ch)) { >+ return scanNumericLiteral(); >+ } >+ >+ // Slash (/) char #47 can also start a regex. >+ if (extra.tokenize && ch === 47) { >+ return advanceSlash(); >+ } >+ >+ return scanPunctuator(); >+ } >+ >+ function collectToken() { >+ var start, loc, token, range, value; >+ >+ skipComment(); >+ start = index; >+ loc = { >+ start: { >+ line: lineNumber, >+ column: index - lineStart >+ } >+ }; >+ >+ token = advance(); >+ loc.end = { >+ line: lineNumber, >+ column: index - lineStart >+ }; >+ >+ if (token.type !== Token.EOF) { >+ range = [token.range[0], token.range[1]]; >+ value = source.slice(token.range[0], token.range[1]); >+ extra.tokens.push({ >+ type: TokenName[token.type], >+ value: value, >+ range: range, >+ loc: loc >+ }); >+ } >+ >+ return token; >+ } >+ >+ function lex() { >+ var token; >+ >+ token = lookahead; >+ index = token.range[1]; >+ lineNumber = token.lineNumber; >+ lineStart = token.lineStart; >+ >+ lookahead = (typeof extra.tokens !== 'undefined') ? collectToken() : advance(); >+ >+ index = token.range[1]; >+ lineNumber = token.lineNumber; >+ lineStart = token.lineStart; >+ >+ return token; >+ } >+ >+ function peek() { >+ var pos, line, start; >+ >+ pos = index; >+ line = lineNumber; >+ start = lineStart; >+ lookahead = (typeof extra.tokens !== 'undefined') ? collectToken() : advance(); >+ index = pos; >+ lineNumber = line; >+ lineStart = start; >+ } >+ >+ SyntaxTreeDelegate = { >+ >+ name: 'SyntaxTree', >+ >+ markStart: function () { >+ if (extra.loc) { >+ state.markerStack.push(index - lineStart); >+ state.markerStack.push(lineNumber); >+ } >+ if (extra.range) { >+ state.markerStack.push(index); >+ } >+ }, >+ >+ processComment: function (node) { >+ var i, attacher, pos, len, candidate; >+ >+ if (typeof node.type === 'undefined' || node.type === Syntax.Program) { >+ return; >+ } >+ >+ // Check for possible additional trailing comments. >+ peek(); >+ >+ for (i = 0; i < extra.pendingComments.length; ++i) { >+ attacher = extra.pendingComments[i]; >+ if (node.range[0] >= attacher.comment.range[1]) { >+ candidate = attacher.leading; >+ if (candidate) { >+ pos = candidate.range[0]; >+ len = candidate.range[1] - pos; >+ if (node.range[0] <= pos && (node.range[1] - node.range[0] >= len)) { >+ attacher.leading = node; >+ } >+ } else { >+ attacher.leading = node; >+ } >+ } >+ if (node.range[1] <= attacher.comment.range[0]) { >+ candidate = attacher.trailing; >+ if (candidate) { >+ pos = candidate.range[0]; >+ len = candidate.range[1] - pos; >+ if (node.range[0] <= pos && (node.range[1] - node.range[0] >= len)) { >+ attacher.trailing = node; >+ } >+ } else { >+ attacher.trailing = node; >+ } >+ } >+ } >+ }, >+ >+ markEnd: function (node) { >+ if (extra.range) { >+ node.range = [state.markerStack.pop(), index]; >+ } >+ if (extra.loc) { >+ node.loc = { >+ start: { >+ line: state.markerStack.pop(), >+ column: state.markerStack.pop() >+ }, >+ end: { >+ line: lineNumber, >+ column: index - lineStart >+ } >+ }; >+ this.postProcess(node); >+ } >+ if (extra.attachComment) { >+ this.processComment(node); >+ } >+ return node; >+ }, >+ >+ markEndIf: function (node) { >+ if (node.range || node.loc) { >+ if (extra.loc) { >+ state.markerStack.pop(); >+ state.markerStack.pop(); >+ } >+ if (extra.range) { >+ state.markerStack.pop(); >+ } >+ } else { >+ this.markEnd(node); >+ } >+ return node; >+ }, >+ >+ postProcess: function (node) { >+ if (extra.source) { >+ node.loc.source = extra.source; >+ } >+ return node; >+ }, >+ >+ createArrayExpression: function (elements) { >+ return { >+ type: Syntax.ArrayExpression, >+ elements: elements >+ }; >+ }, >+ >+ createAssignmentExpression: function (operator, left, right) { >+ return { >+ type: Syntax.AssignmentExpression, >+ operator: operator, >+ left: left, >+ right: right >+ }; >+ }, >+ >+ createBinaryExpression: function (operator, left, right) { >+ var type = (operator === '||' || operator === '&&') ? Syntax.LogicalExpression : >+ Syntax.BinaryExpression; >+ return { >+ type: type, >+ operator: operator, >+ left: left, >+ right: right >+ }; >+ }, >+ >+ createBlockStatement: function (body) { >+ return { >+ type: Syntax.BlockStatement, >+ body: body >+ }; >+ }, >+ >+ createBreakStatement: function (label) { >+ return { >+ type: Syntax.BreakStatement, >+ label: label >+ }; >+ }, >+ >+ createCallExpression: function (callee, args) { >+ return { >+ type: Syntax.CallExpression, >+ callee: callee, >+ 'arguments': args >+ }; >+ }, >+ >+ createCatchClause: function (param, body) { >+ return { >+ type: Syntax.CatchClause, >+ param: param, >+ body: body >+ }; >+ }, >+ >+ createConditionalExpression: function (test, consequent, alternate) { >+ return { >+ type: Syntax.ConditionalExpression, >+ test: test, >+ consequent: consequent, >+ alternate: alternate >+ }; >+ }, >+ >+ createContinueStatement: function (label) { >+ return { >+ type: Syntax.ContinueStatement, >+ label: label >+ }; >+ }, >+ >+ createDebuggerStatement: function () { >+ return { >+ type: Syntax.DebuggerStatement >+ }; >+ }, >+ >+ createDoWhileStatement: function (body, test) { >+ return { >+ type: Syntax.DoWhileStatement, >+ body: body, >+ test: test >+ }; >+ }, >+ >+ createEmptyStatement: function () { >+ return { >+ type: Syntax.EmptyStatement >+ }; >+ }, >+ >+ createExpressionStatement: function (expression) { >+ return { >+ type: Syntax.ExpressionStatement, >+ expression: expression >+ }; >+ }, >+ >+ createForStatement: function (init, test, update, body) { >+ return { >+ type: Syntax.ForStatement, >+ init: init, >+ test: test, >+ update: update, >+ body: body >+ }; >+ }, >+ >+ createForInStatement: function (left, right, body) { >+ return { >+ type: Syntax.ForInStatement, >+ left: left, >+ right: right, >+ body: body, >+ each: false >+ }; >+ }, >+ >+ createFunctionDeclaration: function (id, params, defaults, body) { >+ return { >+ type: Syntax.FunctionDeclaration, >+ id: id, >+ params: params, >+ defaults: defaults, >+ body: body, >+ rest: null, >+ generator: false, >+ expression: false >+ }; >+ }, >+ >+ createFunctionExpression: function (id, params, defaults, body) { >+ return { >+ type: Syntax.FunctionExpression, >+ id: id, >+ params: params, >+ defaults: defaults, >+ body: body, >+ rest: null, >+ generator: false, >+ expression: false >+ }; >+ }, >+ >+ createIdentifier: function (name) { >+ return { >+ type: Syntax.Identifier, >+ name: name >+ }; >+ }, >+ >+ createIfStatement: function (test, consequent, alternate) { >+ return { >+ type: Syntax.IfStatement, >+ test: test, >+ consequent: consequent, >+ alternate: alternate >+ }; >+ }, >+ >+ createLabeledStatement: function (label, body) { >+ return { >+ type: Syntax.LabeledStatement, >+ label: label, >+ body: body >+ }; >+ }, >+ >+ createLiteral: function (token) { >+ return { >+ type: Syntax.Literal, >+ value: token.value, >+ raw: source.slice(token.range[0], token.range[1]) >+ }; >+ }, >+ >+ createMemberExpression: function (accessor, object, property) { >+ return { >+ type: Syntax.MemberExpression, >+ computed: accessor === '[', >+ object: object, >+ property: property >+ }; >+ }, >+ >+ createNewExpression: function (callee, args) { >+ return { >+ type: Syntax.NewExpression, >+ callee: callee, >+ 'arguments': args >+ }; >+ }, >+ >+ createObjectExpression: function (properties) { >+ return { >+ type: Syntax.ObjectExpression, >+ properties: properties >+ }; >+ }, >+ >+ createPostfixExpression: function (operator, argument) { >+ return { >+ type: Syntax.UpdateExpression, >+ operator: operator, >+ argument: argument, >+ prefix: false >+ }; >+ }, >+ >+ createProgram: function (body) { >+ return { >+ type: Syntax.Program, >+ body: body >+ }; >+ }, >+ >+ createProperty: function (kind, key, value) { >+ return { >+ type: Syntax.Property, >+ key: key, >+ value: value, >+ kind: kind >+ }; >+ }, >+ >+ createReturnStatement: function (argument) { >+ return { >+ type: Syntax.ReturnStatement, >+ argument: argument >+ }; >+ }, >+ >+ createSequenceExpression: function (expressions) { >+ return { >+ type: Syntax.SequenceExpression, >+ expressions: expressions >+ }; >+ }, >+ >+ createSwitchCase: function (test, consequent) { >+ return { >+ type: Syntax.SwitchCase, >+ test: test, >+ consequent: consequent >+ }; >+ }, >+ >+ createSwitchStatement: function (discriminant, cases) { >+ return { >+ type: Syntax.SwitchStatement, >+ discriminant: discriminant, >+ cases: cases >+ }; >+ }, >+ >+ createThisExpression: function () { >+ return { >+ type: Syntax.ThisExpression >+ }; >+ }, >+ >+ createThrowStatement: function (argument) { >+ return { >+ type: Syntax.ThrowStatement, >+ argument: argument >+ }; >+ }, >+ >+ createTryStatement: function (block, guardedHandlers, handlers, finalizer) { >+ return { >+ type: Syntax.TryStatement, >+ block: block, >+ guardedHandlers: guardedHandlers, >+ handlers: handlers, >+ finalizer: finalizer >+ }; >+ }, >+ >+ createUnaryExpression: function (operator, argument) { >+ if (operator === '++' || operator === '--') { >+ return { >+ type: Syntax.UpdateExpression, >+ operator: operator, >+ argument: argument, >+ prefix: true >+ }; >+ } >+ return { >+ type: Syntax.UnaryExpression, >+ operator: operator, >+ argument: argument, >+ prefix: true >+ }; >+ }, >+ >+ createVariableDeclaration: function (declarations, kind) { >+ return { >+ type: Syntax.VariableDeclaration, >+ declarations: declarations, >+ kind: kind >+ }; >+ }, >+ >+ createVariableDeclarator: function (id, init) { >+ return { >+ type: Syntax.VariableDeclarator, >+ id: id, >+ init: init >+ }; >+ }, >+ >+ createWhileStatement: function (test, body) { >+ return { >+ type: Syntax.WhileStatement, >+ test: test, >+ body: body >+ }; >+ }, >+ >+ createWithStatement: function (object, body) { >+ return { >+ type: Syntax.WithStatement, >+ object: object, >+ body: body >+ }; >+ } >+ }; >+ >+ // Return true if there is a line terminator before the next token. >+ >+ function peekLineTerminator() { >+ var pos, line, start, found; >+ >+ pos = index; >+ line = lineNumber; >+ start = lineStart; >+ skipComment(); >+ found = lineNumber !== line; >+ index = pos; >+ lineNumber = line; >+ lineStart = start; >+ >+ return found; >+ } >+ >+ // Throw an exception >+ >+ function throwError(token, messageFormat) { >+ var error, >+ args = Array.prototype.slice.call(arguments, 2), >+ msg = messageFormat.replace( >+ /%(\d)/g, >+ function (whole, index) { >+ assert(index < args.length, 'Message reference must be in range'); >+ return args[index]; >+ } >+ ); >+ >+ if (typeof token.lineNumber === 'number') { >+ error = new Error('Line ' + token.lineNumber + ': ' + msg); >+ error.index = token.range[0]; >+ error.lineNumber = token.lineNumber; >+ error.column = token.range[0] - lineStart + 1; >+ } else { >+ error = new Error('Line ' + lineNumber + ': ' + msg); >+ error.index = index; >+ error.lineNumber = lineNumber; >+ error.column = index - lineStart + 1; >+ } >+ >+ error.description = msg; >+ throw error; >+ } >+ >+ function throwErrorTolerant() { >+ try { >+ throwError.apply(null, arguments); >+ } catch (e) { >+ if (extra.errors) { >+ extra.errors.push(e); >+ } else { >+ throw e; >+ } >+ } >+ } >+ >+ >+ // Throw an exception because of the token. >+ >+ function throwUnexpected(token) { >+ if (token.type === Token.EOF) { >+ throwError(token, Messages.UnexpectedEOS); >+ } >+ >+ if (token.type === Token.NumericLiteral) { >+ throwError(token, Messages.UnexpectedNumber); >+ } >+ >+ if (token.type === Token.StringLiteral) { >+ throwError(token, Messages.UnexpectedString); >+ } >+ >+ if (token.type === Token.Identifier) { >+ throwError(token, Messages.UnexpectedIdentifier); >+ } >+ >+ if (token.type === Token.Keyword) { >+ if (isFutureReservedWord(token.value)) { >+ throwError(token, Messages.UnexpectedReserved); >+ } else if (strict && isStrictModeReservedWord(token.value)) { >+ throwErrorTolerant(token, Messages.StrictReservedWord); >+ return; >+ } >+ throwError(token, Messages.UnexpectedToken, token.value); >+ } >+ >+ // BooleanLiteral, NullLiteral, or Punctuator. >+ throwError(token, Messages.UnexpectedToken, token.value); >+ } >+ >+ // Expect the next token to match the specified punctuator. >+ // If not, an exception will be thrown. >+ >+ function expect(value) { >+ var token = lex(); >+ if (token.type !== Token.Punctuator || token.value !== value) { >+ throwUnexpected(token); >+ } >+ } >+ >+ // Expect the next token to match the specified keyword. >+ // If not, an exception will be thrown. >+ >+ function expectKeyword(keyword) { >+ var token = lex(); >+ if (token.type !== Token.Keyword || token.value !== keyword) { >+ throwUnexpected(token); >+ } >+ } >+ >+ // Return true if the next token matches the specified punctuator. >+ >+ function match(value) { >+ return lookahead.type === Token.Punctuator && lookahead.value === value; >+ } >+ >+ // Return true if the next token matches the specified keyword >+ >+ function matchKeyword(keyword) { >+ return lookahead.type === Token.Keyword && lookahead.value === keyword; >+ } >+ >+ // Return true if the next token is an assignment operator >+ >+ function matchAssign() { >+ var op; >+ >+ if (lookahead.type !== Token.Punctuator) { >+ return false; >+ } >+ op = lookahead.value; >+ return op === '=' || >+ op === '*=' || >+ op === '/=' || >+ op === '%=' || >+ op === '+=' || >+ op === '-=' || >+ op === '<<=' || >+ op === '>>=' || >+ op === '>>>=' || >+ op === '&=' || >+ op === '^=' || >+ op === '|='; >+ } >+ >+ function consumeSemicolon() { >+ var line; >+ >+ // Catch the very common case first: immediately a semicolon (char #59). >+ if (source.charCodeAt(index) === 59) { >+ lex(); >+ return; >+ } >+ >+ line = lineNumber; >+ skipComment(); >+ if (lineNumber !== line) { >+ return; >+ } >+ >+ if (match(';')) { >+ lex(); >+ return; >+ } >+ >+ if (lookahead.type !== Token.EOF && !match('}')) { >+ if (extra.errors) { >+ rewind(); >+ } >+ throwUnexpected(lookahead); >+ } >+ } >+ >+ // Return true if provided expression is LeftHandSideExpression >+ >+ function isLeftHandSide(expr) { >+ return expr.type === Syntax.Identifier || expr.type === Syntax.MemberExpression; >+ } >+ >+ // 11.1.4 Array Initialiser >+ >+ function parseArrayInitialiser() { >+ var elements = []; >+ >+ expect('['); >+ >+ while (!match(']')) { >+ if (match(',')) { >+ lex(); >+ elements.push(null); >+ } else { >+ elements.push(parseAssignmentExpression()); >+ >+ if (!match(']')) { >+ expect(','); >+ } >+ } >+ } >+ >+ expect(']'); >+ >+ return delegate.createArrayExpression(elements); >+ } >+ >+ // 11.1.5 Object Initialiser >+ >+ function parsePropertyFunction(param, first) { >+ var previousStrict, body; >+ >+ previousStrict = strict; >+ skipComment(); >+ delegate.markStart(); >+ body = parseFunctionSourceElements(); >+ if (first && strict && isRestrictedWord(param[0].name)) { >+ throwErrorTolerant(first, Messages.StrictParamName); >+ } >+ strict = previousStrict; >+ return delegate.markEnd(delegate.createFunctionExpression(null, param, [], body)); >+ } >+ >+ function parseObjectPropertyKey() { >+ var token; >+ >+ skipComment(); >+ delegate.markStart(); >+ token = lex(); >+ >+ // Note: This function is called only from parseObjectProperty(), where >+ // EOF and Punctuator tokens are already filtered out. >+ >+ if (token.type === Token.StringLiteral || token.type === Token.NumericLiteral) { >+ if (strict && token.octal) { >+ throwErrorTolerant(token, Messages.StrictOctalLiteral); >+ } >+ return delegate.markEnd(delegate.createLiteral(token)); >+ } >+ >+ return delegate.markEnd(delegate.createIdentifier(token.value)); >+ } >+ >+ function parseObjectProperty() { >+ var token, key, id, value, param; >+ >+ token = lookahead; >+ skipComment(); >+ delegate.markStart(); >+ >+ if (token.type === Token.Identifier) { >+ >+ id = parseObjectPropertyKey(); >+ >+ // Property Assignment: Getter and Setter. >+ >+ if (token.value === 'get' && !match(':')) { >+ key = parseObjectPropertyKey(); >+ expect('('); >+ expect(')'); >+ value = parsePropertyFunction([]); >+ return delegate.markEnd(delegate.createProperty('get', key, value)); >+ } >+ if (token.value === 'set' && !match(':')) { >+ key = parseObjectPropertyKey(); >+ expect('('); >+ token = lookahead; >+ if (token.type !== Token.Identifier) { >+ expect(')'); >+ throwErrorTolerant(token, Messages.UnexpectedToken, token.value); >+ value = parsePropertyFunction([]); >+ } else { >+ param = [ parseVariableIdentifier() ]; >+ expect(')'); >+ value = parsePropertyFunction(param, token); >+ } >+ return delegate.markEnd(delegate.createProperty('set', key, value)); >+ } >+ expect(':'); >+ value = parseAssignmentExpression(); >+ return delegate.markEnd(delegate.createProperty('init', id, value)); >+ } >+ if (token.type === Token.EOF || token.type === Token.Punctuator) { >+ throwUnexpected(token); >+ } else { >+ key = parseObjectPropertyKey(); >+ expect(':'); >+ value = parseAssignmentExpression(); >+ return delegate.markEnd(delegate.createProperty('init', key, value)); >+ } >+ } >+ >+ function parseObjectInitialiser() { >+ var properties = [], property, name, key, kind, map = {}, toString = String; >+ >+ expect('{'); >+ >+ while (!match('}')) { >+ property = parseObjectProperty(); >+ >+ if (property.key.type === Syntax.Identifier) { >+ name = property.key.name; >+ } else { >+ name = toString(property.key.value); >+ } >+ kind = (property.kind === 'init') ? PropertyKind.Data : (property.kind === 'get') ? PropertyKind.Get : PropertyKind.Set; >+ >+ key = '$' + name; >+ if (Object.prototype.hasOwnProperty.call(map, key)) { >+ if (map[key] === PropertyKind.Data) { >+ if (strict && kind === PropertyKind.Data) { >+ throwErrorTolerant({}, Messages.StrictDuplicateProperty); >+ } else if (kind !== PropertyKind.Data) { >+ throwErrorTolerant({}, Messages.AccessorDataProperty); >+ } >+ } else { >+ if (kind === PropertyKind.Data) { >+ throwErrorTolerant({}, Messages.AccessorDataProperty); >+ } else if (map[key] & kind) { >+ throwErrorTolerant({}, Messages.AccessorGetSet); >+ } >+ } >+ map[key] |= kind; >+ } else { >+ map[key] = kind; >+ } >+ >+ properties.push(property); >+ >+ if (!match('}')) { >+ expect(','); >+ } >+ } >+ >+ expect('}'); >+ >+ return delegate.createObjectExpression(properties); >+ } >+ >+ // 11.1.6 The Grouping Operator >+ >+ function parseGroupExpression() { >+ var expr; >+ >+ expect('('); >+ >+ expr = parseExpression(); >+ >+ expect(')'); >+ >+ return expr; >+ } >+ >+ >+ // 11.1 Primary Expressions >+ >+ function parsePrimaryExpression() { >+ var type, token, expr; >+ >+ if (match('(')) { >+ return parseGroupExpression(); >+ } >+ >+ type = lookahead.type; >+ delegate.markStart(); >+ >+ if (type === Token.Identifier) { >+ expr = delegate.createIdentifier(lex().value); >+ } else if (type === Token.StringLiteral || type === Token.NumericLiteral) { >+ if (strict && lookahead.octal) { >+ throwErrorTolerant(lookahead, Messages.StrictOctalLiteral); >+ } >+ expr = delegate.createLiteral(lex()); >+ } else if (type === Token.Keyword) { >+ if (matchKeyword('this')) { >+ lex(); >+ expr = delegate.createThisExpression(); >+ } else if (matchKeyword('function')) { >+ expr = parseFunctionExpression(); >+ } >+ } else if (type === Token.BooleanLiteral) { >+ token = lex(); >+ token.value = (token.value === 'true'); >+ expr = delegate.createLiteral(token); >+ } else if (type === Token.NullLiteral) { >+ token = lex(); >+ token.value = null; >+ expr = delegate.createLiteral(token); >+ } else if (match('[')) { >+ expr = parseArrayInitialiser(); >+ } else if (match('{')) { >+ expr = parseObjectInitialiser(); >+ } else if (match('/') || match('/=')) { >+ if (typeof extra.tokens !== 'undefined') { >+ expr = delegate.createLiteral(collectRegex()); >+ } else { >+ expr = delegate.createLiteral(scanRegExp()); >+ } >+ peek(); >+ } >+ >+ if (expr) { >+ return delegate.markEnd(expr); >+ } >+ >+ throwUnexpected(lex()); >+ } >+ >+ // 11.2 Left-Hand-Side Expressions >+ >+ function parseArguments() { >+ var args = []; >+ >+ expect('('); >+ >+ if (!match(')')) { >+ while (index < length) { >+ args.push(parseAssignmentExpression()); >+ if (match(')')) { >+ break; >+ } >+ try { >+ expect(','); >+ } catch (e) { >+ if (extra.errors) { >+ // pretend the argument list is done >+ pushError(e); >+ break; >+ } else { >+ throw e; >+ } >+ } >+ } >+ } >+ >+ //expect(')'); >+ expectConditionCloseParenWrapThrow(); >+ >+ return args; >+ } >+ >+ function parseNonComputedProperty() { >+ var token; >+ >+ delegate.markStart(); >+ token = lex(); >+ >+ if (!isIdentifierName(token)) { >+ if (extra.errors) { >+ attemptRecoveryNonComputedProperty(token); >+ } >+ throwUnexpected(token); >+ } >+ >+ return delegate.markEnd(delegate.createIdentifier(token.value)); >+ } >+ >+ function parseNonComputedMember() { >+ expect('.'); >+ >+ return parseNonComputedProperty(); >+ } >+ >+ function parseComputedMember() { >+ var expr; >+ >+ expect('['); >+ >+ expr = parseExpression(); >+ >+ expect(']'); >+ >+ return expr; >+ } >+ >+ function parseNewExpression() { >+ var callee, args; >+ >+ delegate.markStart(); >+ expectKeyword('new'); >+ callee = parseLeftHandSideExpression(); >+ args = match('(') ? parseArguments() : []; >+ >+ return delegate.markEnd(delegate.createNewExpression(callee, args)); >+ } >+ >+ function parseLeftHandSideExpressionAllowCall() { >+ var marker, previousAllowIn, expr, args, property; >+ >+ marker = createLocationMarker(); >+ >+ previousAllowIn = state.allowIn; >+ state.allowIn = true; >+ expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression(); >+ state.allowIn = previousAllowIn; >+ >+ while (match('.') || match('[') || match('(')) { >+ if (match('(')) { >+ args = parseArguments(); >+ expr = delegate.createCallExpression(expr, args); >+ } else if (match('[')) { >+ property = parseComputedMember(); >+ expr = delegate.createMemberExpression('[', expr, property); >+ } else { >+ property = parseNonComputedMember(); >+ expr = delegate.createMemberExpression('.', expr, property); >+ } >+ if (marker) { >+ marker.end(); >+ marker.apply(expr); >+ } >+ } >+ >+ return expr; >+ } >+ >+ function parseLeftHandSideExpression() { >+ var marker, previousAllowIn, expr, property; >+ >+ marker = createLocationMarker(); >+ >+ previousAllowIn = state.allowIn; >+ expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression(); >+ state.allowIn = previousAllowIn; >+ >+ while (match('.') || match('[')) { >+ if (match('[')) { >+ property = parseComputedMember(); >+ expr = delegate.createMemberExpression('[', expr, property); >+ } else { >+ property = parseNonComputedMember(); >+ expr = delegate.createMemberExpression('.', expr, property); >+ } >+ if (marker) { >+ marker.end(); >+ marker.apply(expr); >+ } >+ } >+ >+ return expr; >+ } >+ >+ // 11.3 Postfix Expressions >+ >+ function parsePostfixExpression() { >+ var expr, token; >+ >+ delegate.markStart(); >+ expr = parseLeftHandSideExpressionAllowCall(); >+ >+ if (lookahead.type === Token.Punctuator) { >+ if ((match('++') || match('--')) && !peekLineTerminator()) { >+ // 11.3.1, 11.3.2 >+ if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) { >+ throwErrorTolerant({}, Messages.StrictLHSPostfix); >+ } >+ >+ if (!isLeftHandSide(expr)) { >+ throwErrorTolerant({}, Messages.InvalidLHSInAssignment); >+ } >+ >+ token = lex(); >+ expr = delegate.createPostfixExpression(token.value, expr); >+ } >+ } >+ >+ return delegate.markEndIf(expr); >+ } >+ >+ // 11.4 Unary Operators >+ >+ function parseUnaryExpression() { >+ var token, expr; >+ >+ delegate.markStart(); >+ >+ if (lookahead.type !== Token.Punctuator && lookahead.type !== Token.Keyword) { >+ expr = parsePostfixExpression(); >+ } else if (match('++') || match('--')) { >+ token = lex(); >+ expr = parseUnaryExpression(); >+ // 11.4.4, 11.4.5 >+ if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) { >+ throwErrorTolerant({}, Messages.StrictLHSPrefix); >+ } >+ >+ if (!isLeftHandSide(expr)) { >+ throwErrorTolerant({}, Messages.InvalidLHSInAssignment); >+ } >+ >+ expr = delegate.createUnaryExpression(token.value, expr); >+ } else if (match('+') || match('-') || match('~') || match('!')) { >+ token = lex(); >+ expr = parseUnaryExpression(); >+ expr = delegate.createUnaryExpression(token.value, expr); >+ } else if (matchKeyword('delete') || matchKeyword('void') || matchKeyword('typeof')) { >+ token = lex(); >+ expr = parseUnaryExpression(); >+ expr = delegate.createUnaryExpression(token.value, expr); >+ if (strict && expr.operator === 'delete' && expr.argument.type === Syntax.Identifier) { >+ throwErrorTolerant({}, Messages.StrictDelete); >+ } >+ } else { >+ expr = parsePostfixExpression(); >+ } >+ >+ return delegate.markEndIf(expr); >+ } >+ >+ function binaryPrecedence(token, allowIn) { >+ var prec = 0; >+ >+ if (token.type !== Token.Punctuator && token.type !== Token.Keyword) { >+ return 0; >+ } >+ >+ switch (token.value) { >+ case '||': >+ prec = 1; >+ break; >+ >+ case '&&': >+ prec = 2; >+ break; >+ >+ case '|': >+ prec = 3; >+ break; >+ >+ case '^': >+ prec = 4; >+ break; >+ >+ case '&': >+ prec = 5; >+ break; >+ >+ case '==': >+ case '!=': >+ case '===': >+ case '!==': >+ prec = 6; >+ break; >+ >+ case '<': >+ case '>': >+ case '<=': >+ case '>=': >+ case 'instanceof': >+ prec = 7; >+ break; >+ >+ case 'in': >+ prec = allowIn ? 7 : 0; >+ break; >+ >+ case '<<': >+ case '>>': >+ case '>>>': >+ prec = 8; >+ break; >+ >+ case '+': >+ case '-': >+ prec = 9; >+ break; >+ >+ case '*': >+ case '/': >+ case '%': >+ prec = 11; >+ break; >+ >+ default: >+ break; >+ } >+ >+ return prec; >+ } >+ >+ // 11.5 Multiplicative Operators >+ // 11.6 Additive Operators >+ // 11.7 Bitwise Shift Operators >+ // 11.8 Relational Operators >+ // 11.9 Equality Operators >+ // 11.10 Binary Bitwise Operators >+ // 11.11 Binary Logical Operators >+ >+ function parseBinaryExpression() { >+ var marker, markers, expr, token, prec, stack, right, operator, left, i; >+ >+ marker = createLocationMarker(); >+ left = parseUnaryExpression(); >+ >+ token = lookahead; >+ prec = binaryPrecedence(token, state.allowIn); >+ if (prec === 0) { >+ return left; >+ } >+ token.prec = prec; >+ lex(); >+ >+ markers = [marker, createLocationMarker()]; >+ right = parseUnaryExpression(); >+ >+ stack = [left, token, right]; >+ >+ while ((prec = binaryPrecedence(lookahead, state.allowIn)) > 0) { >+ >+ // Reduce: make a binary expression from the three topmost entries. >+ while ((stack.length > 2) && (prec <= stack[stack.length - 2].prec)) { >+ right = stack.pop(); >+ operator = stack.pop().value; >+ left = stack.pop(); >+ expr = delegate.createBinaryExpression(operator, left, right); >+ markers.pop(); >+ marker = markers.pop(); >+ if (marker) { >+ marker.end(); >+ marker.apply(expr); >+ } >+ stack.push(expr); >+ markers.push(marker); >+ } >+ >+ // Shift. >+ token = lex(); >+ token.prec = prec; >+ stack.push(token); >+ markers.push(createLocationMarker()); >+ expr = parseUnaryExpression(); >+ stack.push(expr); >+ } >+ >+ // Final reduce to clean-up the stack. >+ i = stack.length - 1; >+ expr = stack[i]; >+ markers.pop(); >+ while (i > 1) { >+ expr = delegate.createBinaryExpression(stack[i - 1].value, stack[i - 2], expr); >+ i -= 2; >+ marker = markers.pop(); >+ if (marker) { >+ marker.end(); >+ marker.apply(expr); >+ } >+ } >+ >+ return expr; >+ } >+ >+ >+ // 11.12 Conditional Operator >+ >+ function parseConditionalExpression() { >+ var expr, previousAllowIn, consequent, alternate; >+ >+ delegate.markStart(); >+ expr = parseBinaryExpression(); >+ >+ if (match('?')) { >+ lex(); >+ previousAllowIn = state.allowIn; >+ state.allowIn = true; >+ consequent = parseAssignmentExpression(); >+ state.allowIn = previousAllowIn; >+ expect(':'); >+ alternate = parseAssignmentExpression(); >+ >+ expr = delegate.markEnd(delegate.createConditionalExpression(expr, consequent, alternate)); >+ } else { >+ delegate.markEnd({}); >+ } >+ >+ return expr; >+ } >+ >+ // 11.13 Assignment Operators >+ >+ function parseAssignmentExpression() { >+ var token, left, right, node; >+ >+ token = lookahead; >+ delegate.markStart(); >+ node = left = parseConditionalExpression(); >+ >+ if (matchAssign()) { >+ // LeftHandSideExpression >+ if (!isLeftHandSide(left)) { >+ throwErrorTolerant({}, Messages.InvalidLHSInAssignment); >+ } >+ >+ // 11.13.1 >+ if (strict && left.type === Syntax.Identifier && isRestrictedWord(left.name)) { >+ throwErrorTolerant(token, Messages.StrictLHSAssignment); >+ } >+ >+ token = lex(); >+ right = parseAssignmentExpression(); >+ node = delegate.createAssignmentExpression(token.value, left, right); >+ } >+ >+ return delegate.markEndIf(node); >+ } >+ >+ // 11.14 Comma Operator >+ >+ function parseExpression() { >+ var expr; >+ >+ delegate.markStart(); >+ expr = parseAssignmentExpression(); >+ >+ if (match(',')) { >+ expr = delegate.createSequenceExpression([ expr ]); >+ >+ while (index < length) { >+ if (!match(',')) { >+ break; >+ } >+ lex(); >+ expr.expressions.push(parseAssignmentExpression()); >+ } >+ } >+ >+ return delegate.markEndIf(expr); >+ } >+ >+ // 12.1 Block >+ >+ function parseStatementList() { >+ var list = [], >+ statement; >+ >+ while (index < length) { >+ if (match('}')) { >+ break; >+ } >+ statement = parseSourceElement(); >+ if (typeof statement === 'undefined') { >+ break; >+ } >+ list.push(statement); >+ } >+ >+ return list; >+ } >+ >+ function parseBlock() { >+ var block; >+ >+ skipComment(); >+ delegate.markStart(); >+ expect('{'); >+ >+ block = parseStatementList(); >+ >+ //expect('}'); >+ expectConditionCloseBracketWrapThrow(); >+ >+ return delegate.markEnd(delegate.createBlockStatement(block)); >+ } >+ >+ // 12.2 Variable Statement >+ >+ function parseVariableIdentifier() { >+ var token; >+ >+ skipComment(); >+ delegate.markStart(); >+ token = lex(); >+ >+ if (token.type !== Token.Identifier) { >+ throwUnexpected(token); >+ } >+ >+ return delegate.markEnd(delegate.createIdentifier(token.value)); >+ } >+ >+ function parseVariableDeclaration(kind) { >+ var init = null, id; >+ >+ skipComment(); >+ delegate.markStart(); >+ id = parseVariableIdentifier(); >+ >+ // 12.2.1 >+ if (strict && isRestrictedWord(id.name)) { >+ throwErrorTolerant({}, Messages.StrictVarName); >+ } >+ >+ if (kind === 'const') { >+ expect('='); >+ init = parseAssignmentExpression(); >+ } else if (match('=')) { >+ lex(); >+ init = parseAssignmentExpression(); >+ } >+ >+ return delegate.markEnd(delegate.createVariableDeclarator(id, init)); >+ } >+ >+ function parseVariableDeclarationList(kind) { >+ var list = []; >+ >+ do { >+ list.push(parseVariableDeclaration(kind)); >+ if (!match(',')) { >+ break; >+ } >+ lex(); >+ } while (index < length); >+ >+ return list; >+ } >+ >+ function parseVariableStatement() { >+ var declarations; >+ >+ expectKeyword('var'); >+ >+ declarations = parseVariableDeclarationList(); >+ >+ consumeSemicolon(); >+ >+ return delegate.createVariableDeclaration(declarations, 'var'); >+ } >+ >+ // kind may be `const` or `let` >+ // Both are experimental and not in the specification yet. >+ // see http://wiki.ecmascript.org/doku.php?id=harmony:const >+ // and http://wiki.ecmascript.org/doku.php?id=harmony:let >+ function parseConstLetDeclaration(kind) { >+ var declarations; >+ >+ skipComment(); >+ delegate.markStart(); >+ >+ expectKeyword(kind); >+ >+ declarations = parseVariableDeclarationList(kind); >+ >+ consumeSemicolon(); >+ >+ return delegate.markEnd(delegate.createVariableDeclaration(declarations, kind)); >+ } >+ >+ // 12.3 Empty Statement >+ >+ function parseEmptyStatement() { >+ expect(';'); >+ return delegate.createEmptyStatement(); >+ } >+ >+ // 12.4 Expression Statement >+ >+ function parseExpressionStatement() { >+ var expr = parseExpression(); >+ consumeSemicolon(); >+ return delegate.createExpressionStatement(expr); >+ } >+ >+ // 12.5 If statement >+ >+ function parseIfStatement() { >+ >+ var test, consequent, alternate; >+ >+ expectKeyword('if'); >+ >+ expect('('); >+ >+ test = parseExpression(); >+ >+ //expect(')'); >+ expectConditionCloseParenWrapThrow(); >+ >+ consequent = parseStatement(); >+ // required because of the check in wrapTracking that returns nothing if node is undefined >+ if (!consequent) { >+ consequent = null; >+ } >+ if (matchKeyword('else')) { >+ lex(); >+ alternate = parseStatement(); >+ } else { >+ alternate = null; >+ } >+ >+ return delegate.createIfStatement(test, consequent, alternate); >+ } >+ >+ // 12.6 Iteration Statements >+ >+ function parseDoWhileStatement() { >+ var body, test, oldInIteration; >+ >+ expectKeyword('do'); >+ >+ oldInIteration = state.inIteration; >+ state.inIteration = true; >+ >+ body = parseStatement(); >+ >+ state.inIteration = oldInIteration; >+ >+ expectKeyword('while'); >+ >+ expect('('); >+ >+ test = parseExpression(); >+ >+ expect(')'); >+ >+ if (match(';')) { >+ lex(); >+ } >+ >+ return delegate.createDoWhileStatement(body, test); >+ } >+ >+ function parseWhileStatement() { >+ var test, body, oldInIteration; >+ >+ expectKeyword('while'); >+ >+ expect('('); >+ >+ test = parseExpression(); >+ >+ //expect(')'); >+ expectConditionCloseParenWrapThrow(); >+ >+ oldInIteration = state.inIteration; >+ state.inIteration = true; >+ >+ body = parseStatement(); >+ >+ state.inIteration = oldInIteration; >+ >+ return delegate.createWhileStatement(test, body); >+ } >+ >+ function parseForVariableDeclaration() { >+ var token, declarations; >+ >+ delegate.markStart(); >+ token = lex(); >+ declarations = parseVariableDeclarationList(); >+ >+ return delegate.markEnd(delegate.createVariableDeclaration(declarations, token.value)); >+ } >+ >+ function parseForStatement() { >+ var init, test, update, left, right, body, oldInIteration; >+ >+ init = test = update = null; >+ >+ expectKeyword('for'); >+ >+ expect('('); >+ >+ if (match(';')) { >+ lex(); >+ } else { >+ if (matchKeyword('var') || matchKeyword('let')) { >+ state.allowIn = false; >+ init = parseForVariableDeclaration(); >+ state.allowIn = true; >+ >+ if (init.declarations.length === 1 && matchKeyword('in')) { >+ lex(); >+ left = init; >+ right = parseExpression(); >+ init = null; >+ } >+ } else { >+ state.allowIn = false; >+ init = parseExpression(); >+ state.allowIn = true; >+ >+ if (matchKeyword('in')) { >+ // LeftHandSideExpression >+ if (!isLeftHandSide(init)) { >+ throwErrorTolerant({}, Messages.InvalidLHSInForIn); >+ } >+ >+ lex(); >+ left = init; >+ right = parseExpression(); >+ init = null; >+ } >+ } >+ >+ if (typeof left === 'undefined') { >+ expect(';'); >+ } >+ } >+ >+ if (typeof left === 'undefined') { >+ >+ if (!match(';')) { >+ test = parseExpression(); >+ } >+ expect(';'); >+ >+ if (!match(')')) { >+ update = parseExpression(); >+ } >+ } >+ >+ //expect(')'); >+ expectConditionCloseParenWrapThrow(); >+ >+ oldInIteration = state.inIteration; >+ state.inIteration = true; >+ >+ body = parseStatement(); >+ >+ state.inIteration = oldInIteration; >+ >+ return (typeof left === 'undefined') ? >+ delegate.createForStatement(init, test, update, body) : >+ delegate.createForInStatement(left, right, body); >+ } >+ >+ // 12.7 The continue statement >+ >+ function parseContinueStatement() { >+ var label = null, key; >+ >+ expectKeyword('continue'); >+ >+ // Optimize the most common form: 'continue;'. >+ if (source.charCodeAt(index) === 59) { >+ lex(); >+ >+ if (!state.inIteration) { >+ throwError({}, Messages.IllegalContinue); >+ } >+ >+ return delegate.createContinueStatement(null); >+ } >+ >+ if (peekLineTerminator()) { >+ if (!state.inIteration) { >+ throwError({}, Messages.IllegalContinue); >+ } >+ >+ return delegate.createContinueStatement(null); >+ } >+ >+ if (lookahead.type === Token.Identifier) { >+ label = parseVariableIdentifier(); >+ >+ key = '$' + label.name; >+ if (!Object.prototype.hasOwnProperty.call(state.labelSet, key)) { >+ throwError({}, Messages.UnknownLabel, label.name); >+ } >+ } >+ >+ consumeSemicolon(); >+ >+ if (label === null && !state.inIteration) { >+ throwError({}, Messages.IllegalContinue); >+ } >+ >+ return delegate.createContinueStatement(label); >+ } >+ >+ // 12.8 The break statement >+ >+ function parseBreakStatement() { >+ var label = null, key; >+ >+ expectKeyword('break'); >+ >+ // Catch the very common case first: immediately a semicolon (char #59). >+ if (source.charCodeAt(index) === 59) { >+ lex(); >+ >+ if (!(state.inIteration || state.inSwitch)) { >+ throwError({}, Messages.IllegalBreak); >+ } >+ >+ return delegate.createBreakStatement(null); >+ } >+ >+ if (peekLineTerminator()) { >+ if (!(state.inIteration || state.inSwitch)) { >+ throwError({}, Messages.IllegalBreak); >+ } >+ >+ return delegate.createBreakStatement(null); >+ } >+ >+ if (lookahead.type === Token.Identifier) { >+ label = parseVariableIdentifier(); >+ >+ key = '$' + label.name; >+ if (!Object.prototype.hasOwnProperty.call(state.labelSet, key)) { >+ throwError({}, Messages.UnknownLabel, label.name); >+ } >+ } >+ >+ consumeSemicolon(); >+ >+ if (label === null && !(state.inIteration || state.inSwitch)) { >+ throwError({}, Messages.IllegalBreak); >+ } >+ >+ return delegate.createBreakStatement(label); >+ } >+ >+ // 12.9 The return statement >+ >+ function parseReturnStatement() { >+ var argument = null; >+ >+ expectKeyword('return'); >+ >+ if (!state.inFunctionBody) { >+ throwErrorTolerant({}, Messages.IllegalReturn); >+ } >+ >+ // 'return' followed by a space and an identifier is very common. >+ if (source.charCodeAt(index) === 32) { >+ if (isIdentifierStart(source.charCodeAt(index + 1))) { >+ argument = parseExpression(); >+ consumeSemicolon(); >+ return delegate.createReturnStatement(argument); >+ } >+ } >+ >+ if (peekLineTerminator()) { >+ return delegate.createReturnStatement(null); >+ } >+ >+ if (!match(';')) { >+ if (!match('}') && lookahead.type !== Token.EOF) { >+ argument = parseExpression(); >+ } >+ } >+ >+ consumeSemicolon(); >+ >+ return delegate.createReturnStatement(argument); >+ } >+ >+ // 12.10 The with statement >+ >+ function parseWithStatement() { >+ var object, body; >+ >+ if (strict) { >+ throwErrorTolerant({}, Messages.StrictModeWith); >+ } >+ >+ expectKeyword('with'); >+ >+ expect('('); >+ >+ object = parseExpression(); >+ >+ expect(')'); >+ >+ body = parseStatement(); >+ >+ return delegate.createWithStatement(object, body); >+ } >+ >+ // 12.10 The swith statement >+ >+ function parseSwitchCase() { >+ var test, >+ consequent = [], >+ statement; >+ >+ skipComment(); >+ delegate.markStart(); >+ if (matchKeyword('default')) { >+ lex(); >+ test = null; >+ } else { >+ expectKeyword('case'); >+ test = parseExpression(); >+ } >+ expect(':'); >+ >+ while (index < length) { >+ if (match('}') || matchKeyword('default') || matchKeyword('case')) { >+ break; >+ } >+ statement = parseStatement(); >+ consequent.push(statement); >+ } >+ >+ return delegate.markEnd(delegate.createSwitchCase(test, consequent)); >+ } >+ >+ function parseSwitchStatement() { >+ var discriminant, cases, clause, oldInSwitch, defaultFound; >+ >+ expectKeyword('switch'); >+ >+ expect('('); >+ >+ discriminant = parseExpression(); >+ >+ expect(')'); >+ >+ expect('{'); >+ >+ cases = []; >+ >+ if (match('}')) { >+ lex(); >+ return delegate.createSwitchStatement(discriminant, cases); >+ } >+ >+ oldInSwitch = state.inSwitch; >+ state.inSwitch = true; >+ defaultFound = false; >+ >+ while (index < length) { >+ if (match('}')) { >+ break; >+ } >+ clause = parseSwitchCase(); >+ if (clause.test === null) { >+ if (defaultFound) { >+ throwError({}, Messages.MultipleDefaultsInSwitch); >+ } >+ defaultFound = true; >+ } >+ cases.push(clause); >+ } >+ >+ state.inSwitch = oldInSwitch; >+ >+ expect('}'); >+ >+ return delegate.createSwitchStatement(discriminant, cases); >+ } >+ >+ // 12.13 The throw statement >+ >+ function parseThrowStatement() { >+ var argument; >+ >+ expectKeyword('throw'); >+ >+ if (peekLineTerminator()) { >+ throwError({}, Messages.NewlineAfterThrow); >+ } >+ >+ argument = parseExpression(); >+ >+ consumeSemicolon(); >+ >+ return delegate.createThrowStatement(argument); >+ } >+ >+ // 12.14 The try statement >+ >+ function parseCatchClause() { >+ var param, body; >+ >+ skipComment(); >+ delegate.markStart(); >+ expectKeyword('catch'); >+ >+ expect('('); >+ if (match(')')) { >+ throwUnexpected(lookahead); >+ } >+ >+ param = parseVariableIdentifier(); >+ // 12.14.1 >+ if (strict && isRestrictedWord(param.name)) { >+ throwErrorTolerant({}, Messages.StrictCatchVariable); >+ } >+ >+ expect(')'); >+ body = parseBlock(); >+ return delegate.markEnd(delegate.createCatchClause(param, body)); >+ } >+ >+ function parseTryStatement() { >+ var block, handlers = [], finalizer = null; >+ >+ expectKeyword('try'); >+ >+ block = parseBlock(); >+ >+ if (matchKeyword('catch')) { >+ handlers.push(parseCatchClause()); >+ } >+ >+ if (matchKeyword('finally')) { >+ lex(); >+ finalizer = parseBlock(); >+ } >+ >+ if (handlers.length === 0 && !finalizer) { >+ throwError({}, Messages.NoCatchOrFinally); >+ } >+ >+ return delegate.createTryStatement(block, [], handlers, finalizer); >+ } >+ >+ // 12.15 The debugger statement >+ >+ function parseDebuggerStatement() { >+ expectKeyword('debugger'); >+ >+ consumeSemicolon(); >+ >+ return delegate.createDebuggerStatement(); >+ } >+ >+ // 12 Statements >+ >+ function parseStatement() { >+ var type = lookahead.type, >+ expr, >+ labeledBody, >+ key; >+ >+ if (type === Token.EOF) { >+ throwUnexpected(lookahead); >+ } >+ >+ skipComment(); >+ delegate.markStart(); >+ >+ if (type === Token.Punctuator) { >+ switch (lookahead.value) { >+ case ';': >+ return delegate.markEnd(parseEmptyStatement()); >+ case '{': >+ return delegate.markEnd(parseBlock()); >+ case '(': >+ return delegate.markEnd(parseExpressionStatement()); >+ default: >+ break; >+ } >+ } >+ >+ if (type === Token.Keyword) { >+ switch (lookahead.value) { >+ case 'break': >+ return delegate.markEnd(parseBreakStatement()); >+ case 'continue': >+ return delegate.markEnd(parseContinueStatement()); >+ case 'debugger': >+ return delegate.markEnd(parseDebuggerStatement()); >+ case 'do': >+ return delegate.markEnd(parseDoWhileStatement()); >+ case 'for': >+ return delegate.markEnd(parseForStatement()); >+ case 'function': >+ return delegate.markEnd(parseFunctionDeclaration()); >+ case 'if': >+ return delegate.markEnd(parseIfStatement()); >+ case 'return': >+ return delegate.markEnd(parseReturnStatement()); >+ case 'switch': >+ return delegate.markEnd(parseSwitchStatement()); >+ case 'throw': >+ return delegate.markEnd(parseThrowStatement()); >+ case 'try': >+ return delegate.markEnd(parseTryStatement()); >+ case 'var': >+ return delegate.markEnd(parseVariableStatement()); >+ case 'while': >+ return delegate.markEnd(parseWhileStatement()); >+ case 'with': >+ return delegate.markEnd(parseWithStatement()); >+ default: >+ break; >+ } >+ } >+ >+ expr = parseExpression(); >+ >+ // 12.12 Labelled Statements >+ if (expr && (expr.type === Syntax.Identifier) && match(':')) { >+ lex(); >+ >+ key = '$' + expr.name; >+ if (Object.prototype.hasOwnProperty.call(state.labelSet, key)) { >+ throwError({}, Messages.Redeclaration, 'Label', expr.name); >+ } >+ >+ state.labelSet[key] = true; >+ labeledBody = parseStatement(); >+ delete state.labelSet[key]; >+ return delegate.markEnd(delegate.createLabeledStatement(expr, labeledBody)); >+ } >+ >+ consumeSemicolon(); >+ >+ return delegate.markEnd(delegate.createExpressionStatement(expr)); >+ } >+ >+ // 13 Function Definition >+ >+ function parseFunctionSourceElements() { >+ var sourceElement, sourceElements = [], token, directive, firstRestricted, >+ oldLabelSet, oldInIteration, oldInSwitch, oldInFunctionBody; >+ >+ skipComment(); >+ delegate.markStart(); >+ expect('{'); >+ >+ while (index < length) { >+ if (lookahead.type !== Token.StringLiteral) { >+ break; >+ } >+ token = lookahead; >+ >+ sourceElement = parseSourceElement(); >+ sourceElements.push(sourceElement); >+ if (sourceElement.expression.type !== Syntax.Literal) { >+ // this is not directive >+ break; >+ } >+ directive = source.slice(token.range[0] + 1, token.range[1] - 1); >+ if (directive === 'use strict') { >+ strict = true; >+ if (firstRestricted) { >+ throwErrorTolerant(firstRestricted, Messages.StrictOctalLiteral); >+ } >+ } else { >+ if (!firstRestricted && token.octal) { >+ firstRestricted = token; >+ } >+ } >+ } >+ >+ oldLabelSet = state.labelSet; >+ oldInIteration = state.inIteration; >+ oldInSwitch = state.inSwitch; >+ oldInFunctionBody = state.inFunctionBody; >+ >+ state.labelSet = {}; >+ state.inIteration = false; >+ state.inSwitch = false; >+ state.inFunctionBody = true; >+ >+ while (index < length) { >+ if (match('}')) { >+ break; >+ } >+ sourceElement = parseSourceElement(); >+ if (typeof sourceElement === 'undefined') { >+ break; >+ } >+ sourceElements.push(sourceElement); >+ } >+ >+ //expect('}'); >+ expectConditionCloseBracketWrapThrow(); >+ >+ state.labelSet = oldLabelSet; >+ state.inIteration = oldInIteration; >+ state.inSwitch = oldInSwitch; >+ state.inFunctionBody = oldInFunctionBody; >+ >+ return delegate.markEnd(delegate.createBlockStatement(sourceElements)); >+ } >+ >+ function parseParams(firstRestricted) { >+ var param, params = [], token, stricted, paramSet, key, message; >+ expect('('); >+ >+ if (!match(')')) { >+ paramSet = {}; >+ while (index < length) { >+ token = lookahead; >+ param = parseVariableIdentifier(); >+ key = '$' + token.value; >+ if (strict) { >+ if (isRestrictedWord(token.value)) { >+ stricted = token; >+ message = Messages.StrictParamName; >+ } >+ if (Object.prototype.hasOwnProperty.call(paramSet, key)) { >+ stricted = token; >+ message = Messages.StrictParamDupe; >+ } >+ } else if (!firstRestricted) { >+ if (isRestrictedWord(token.value)) { >+ firstRestricted = token; >+ message = Messages.StrictParamName; >+ } else if (isStrictModeReservedWord(token.value)) { >+ firstRestricted = token; >+ message = Messages.StrictReservedWord; >+ } else if (Object.prototype.hasOwnProperty.call(paramSet, key)) { >+ firstRestricted = token; >+ message = Messages.StrictParamDupe; >+ } >+ } >+ params.push(param); >+ paramSet[key] = true; >+ if (match(')')) { >+ break; >+ } >+ expect(','); >+ } >+ } >+ >+ expect(')'); >+ >+ return { >+ params: params, >+ stricted: stricted, >+ firstRestricted: firstRestricted, >+ message: message >+ }; >+ } >+ >+ function parseFunctionDeclaration() { >+ var id, params = [], body, token, stricted, tmp, firstRestricted, message, previousStrict; >+ >+ skipComment(); >+ delegate.markStart(); >+ >+ expectKeyword('function'); >+ token = lookahead; >+ id = parseVariableIdentifier(); >+ if (strict) { >+ if (isRestrictedWord(token.value)) { >+ throwErrorTolerant(token, Messages.StrictFunctionName); >+ } >+ } else { >+ if (isRestrictedWord(token.value)) { >+ firstRestricted = token; >+ message = Messages.StrictFunctionName; >+ } else if (isStrictModeReservedWord(token.value)) { >+ firstRestricted = token; >+ message = Messages.StrictReservedWord; >+ } >+ } >+ >+ tmp = parseParams(firstRestricted); >+ params = tmp.params; >+ stricted = tmp.stricted; >+ firstRestricted = tmp.firstRestricted; >+ if (tmp.message) { >+ message = tmp.message; >+ } >+ >+ previousStrict = strict; >+ body = parseFunctionSourceElements(); >+ if (strict && firstRestricted) { >+ throwError(firstRestricted, message); >+ } >+ if (strict && stricted) { >+ throwErrorTolerant(stricted, message); >+ } >+ strict = previousStrict; >+ >+ return delegate.markEnd(delegate.createFunctionDeclaration(id, params, [], body)); >+ } >+ >+ function parseFunctionExpression() { >+ var token, id = null, stricted, firstRestricted, message, tmp, params = [], body, previousStrict; >+ >+ delegate.markStart(); >+ expectKeyword('function'); >+ >+ if (!match('(')) { >+ token = lookahead; >+ id = parseVariableIdentifier(); >+ if (strict) { >+ if (isRestrictedWord(token.value)) { >+ throwErrorTolerant(token, Messages.StrictFunctionName); >+ } >+ } else { >+ if (isRestrictedWord(token.value)) { >+ firstRestricted = token; >+ message = Messages.StrictFunctionName; >+ } else if (isStrictModeReservedWord(token.value)) { >+ firstRestricted = token; >+ message = Messages.StrictReservedWord; >+ } >+ } >+ } >+ >+ tmp = parseParams(firstRestricted); >+ params = tmp.params; >+ stricted = tmp.stricted; >+ firstRestricted = tmp.firstRestricted; >+ if (tmp.message) { >+ message = tmp.message; >+ } >+ >+ previousStrict = strict; >+ body = parseFunctionSourceElements(); >+ if (strict && firstRestricted) { >+ throwError(firstRestricted, message); >+ } >+ if (strict && stricted) { >+ throwErrorTolerant(stricted, message); >+ } >+ strict = previousStrict; >+ >+ return delegate.markEnd(delegate.createFunctionExpression(id, params, [], body)); >+ } >+ >+ // 14 Program >+ >+ function parseSourceElement() { >+ if (lookahead.type === Token.Keyword) { >+ switch (lookahead.value) { >+ case 'const': >+ case 'let': >+ return parseConstLetDeclaration(lookahead.value); >+ case 'function': >+ return parseFunctionDeclaration(); >+ default: >+ return parseStatement(); >+ } >+ } >+ >+ if (lookahead.type !== Token.EOF) { >+ return parseStatement(); >+ } >+ } >+ >+ function parseSourceElements() { >+ var sourceElement, sourceElements = [], token, directive, firstRestricted; >+ >+ while (index < length) { >+ token = lookahead; >+ if (token.type !== Token.StringLiteral) { >+ break; >+ } >+ >+ sourceElement = parseSourceElement(); >+ sourceElements.push(sourceElement); >+ if (sourceElement.expression.type !== Syntax.Literal) { >+ // this is not directive >+ break; >+ } >+ directive = source.slice(token.range[0] + 1, token.range[1] - 1); >+ if (directive === 'use strict') { >+ strict = true; >+ if (firstRestricted) { >+ throwErrorTolerant(firstRestricted, Messages.StrictOctalLiteral); >+ } >+ } else { >+ if (!firstRestricted && token.octal) { >+ firstRestricted = token; >+ } >+ } >+ } >+ >+ while (index < length) { >+ sourceElement = parseSourceElement(); >+ if (typeof sourceElement === 'undefined') { >+ break; >+ } >+ sourceElements.push(sourceElement); >+ } >+ return sourceElements; >+ } >+ >+ function parseProgram() { >+ var body; >+ >+ skipComment(); >+ delegate.markStart(); >+ strict = false; >+ peek(); >+ body = parseSourceElements(); >+ return delegate.markEnd(delegate.createProgram(body)); >+ } >+ >+ function attachComments() { >+ var i, attacher, comment, leading, trailing; >+ >+ for (i = 0; i < extra.pendingComments.length; ++i) { >+ attacher = extra.pendingComments[i]; >+ comment = attacher.comment; >+ leading = attacher.leading; >+ if (leading) { >+ if (typeof leading.leadingComments === 'undefined') { >+ leading.leadingComments = []; >+ } >+ leading.leadingComments.push(attacher.comment); >+ } >+ trailing = attacher.trailing; >+ if (trailing) { >+ if (typeof trailing.trailingComments === 'undefined') { >+ trailing.trailingComments = []; >+ } >+ trailing.trailingComments.push(attacher.comment); >+ } >+ } >+ extra.pendingComments = []; >+ } >+ >+ function filterTokenLocation() { >+ var i, entry, token, tokens = []; >+ >+ for (i = 0; i < extra.tokens.length; ++i) { >+ entry = extra.tokens[i]; >+ token = { >+ type: entry.type, >+ value: entry.value >+ }; >+ if (extra.range) { >+ token.range = entry.range; >+ } >+ if (extra.loc) { >+ token.loc = entry.loc; >+ } >+ tokens.push(token); >+ } >+ >+ extra.tokens = tokens; >+ } >+ >+ function LocationMarker() { >+ this.marker = [index, lineNumber, index - lineStart, 0, 0, 0]; >+ } >+ >+ LocationMarker.prototype = { >+ constructor: LocationMarker, >+ >+ end: function () { >+ this.marker[3] = index; >+ this.marker[4] = lineNumber; >+ this.marker[5] = index - lineStart; >+ }, >+ >+ apply: function (node) { >+ if (extra.range) { >+ node.range = [this.marker[0], this.marker[3]]; >+ } >+ if (extra.loc) { >+ node.loc = { >+ start: { >+ line: this.marker[1], >+ column: this.marker[2] >+ }, >+ end: { >+ line: this.marker[4], >+ column: this.marker[5] >+ } >+ }; >+ node = delegate.postProcess(node); >+ } >+ if (extra.attachComment) { >+ delegate.processComment(node); >+ } >+ } >+ }; >+ >+ function createLocationMarker() { >+ if (!extra.loc && !extra.range) { >+ return null; >+ } >+ >+ skipComment(); >+ >+ return new LocationMarker(); >+ } >+ >+ function tokenize(code, options) { >+ var toString, >+ token, >+ tokens; >+ >+ toString = String; >+ if (typeof code !== 'string' && !(code instanceof String)) { >+ code = toString(code); >+ } >+ >+ delegate = SyntaxTreeDelegate; >+ source = code; >+ index = 0; >+ lineNumber = (source.length > 0) ? 1 : 0; >+ lineStart = 0; >+ length = source.length; >+ lookahead = null; >+ state = { >+ allowIn: true, >+ labelSet: {}, >+ inFunctionBody: false, >+ inIteration: false, >+ inSwitch: false, >+ lastCommentStart: -1 >+ }; >+ >+ extra = {}; >+ >+ // Options matching. >+ options = options || {}; >+ >+ // Of course we collect tokens here. >+ options.tokens = true; >+ extra.tokens = []; >+ extra.tokenize = true; >+ // The following two fields are necessary to compute the Regex tokens. >+ extra.openParenToken = -1; >+ extra.openCurlyToken = -1; >+ >+ extra.range = (typeof options.range === 'boolean') && options.range; >+ extra.loc = (typeof options.loc === 'boolean') && options.loc; >+ >+ if (typeof options.comment === 'boolean' && options.comment) { >+ extra.comments = []; >+ } >+ if (typeof options.tolerant === 'boolean' && options.tolerant) { >+ extra.errors = []; >+ } >+ >+ if (length > 0) { >+ if (typeof source[0] === 'undefined') { >+ // Try first to convert to a string. This is good as fast path >+ // for old IE which understands string indexing for string >+ // literals only and not for string object. >+ if (code instanceof String) { >+ source = code.valueOf(); >+ } >+ } >+ } >+ >+ try { >+ peek(); >+ if (lookahead.type === Token.EOF) { >+ return extra.tokens; >+ } >+ >+ token = lex(); >+ while (lookahead.type !== Token.EOF) { >+ try { >+ token = lex(); >+ } catch (lexError) { >+ token = lookahead; >+ if (extra.errors) { >+ extra.errors.push(lexError); >+ // We have to break on the first error >+ // to avoid infinite loops. >+ break; >+ } else { >+ throw lexError; >+ } >+ } >+ } >+ >+ filterTokenLocation(); >+ tokens = extra.tokens; >+ if (typeof extra.comments !== 'undefined') { >+ tokens.comments = extra.comments; >+ } >+ if (typeof extra.errors !== 'undefined') { >+ tokens.errors = extra.errors; >+ } >+ } catch (e) { >+ throw e; >+ } finally { >+ extra = {}; >+ } >+ return tokens; >+ } >+ >+ function parse(code, options) { >+ var program, toString; >+ >+ toString = String; >+ if (typeof code !== 'string' && !(code instanceof String)) { >+ code = toString(code); >+ } >+ >+ delegate = SyntaxTreeDelegate; >+ source = code; >+ index = 0; >+ lineNumber = (source.length > 0) ? 1 : 0; >+ lineStart = 0; >+ length = source.length; >+ lookahead = null; >+ state = { >+ allowIn: true, >+ labelSet: {}, >+ inFunctionBody: false, >+ inIteration: false, >+ inSwitch: false, >+ lastCommentStart: -1, >+ markerStack: [] >+ }; >+ >+ extra = {}; >+ if (typeof options !== 'undefined') { >+ extra.range = (typeof options.range === 'boolean') && options.range; >+ extra.loc = (typeof options.loc === 'boolean') && options.loc; >+ extra.attachComment = (typeof options.attachComment === 'boolean') && options.attachComment; >+ >+ if (extra.loc && options.source !== null && options.source !== undefined) { >+ extra.source = toString(options.source); >+ } >+ >+ if (typeof options.tokens === 'boolean' && options.tokens) { >+ extra.tokens = []; >+ } >+ if (typeof options.comment === 'boolean' && options.comment) { >+ extra.comments = []; >+ } >+ if (typeof options.tolerant === 'boolean' && options.tolerant) { >+ extra.errors = []; >+ } >+ if (extra.attachComment) { >+ extra.range = true; >+ extra.pendingComments = []; >+ extra.comments = []; >+ } >+ } >+ >+ if (length > 0) { >+ if (typeof source[0] === 'undefined') { >+ // Try first to convert to a string. This is good as fast path >+ // for old IE which understands string indexing for string >+ // literals only and not for string object. >+ if (code instanceof String) { >+ source = code.valueOf(); >+ } >+ } >+ } >+ >+ try { >+ program = parseProgram(); >+ if (typeof extra.comments !== 'undefined') { >+ program.comments = extra.comments; >+ } >+ if (typeof extra.tokens !== 'undefined') { >+ filterTokenLocation(); >+ program.tokens = extra.tokens; >+ } >+ if (typeof extra.errors !== 'undefined') { >+ program.errors = extra.errors; >+ } >+ if (extra.attachComment) { >+ attachComments(); >+ } >+ } catch (e) { >+ throw e; >+ } finally { >+ extra = {}; >+ } >+ >+ return program; >+ } >+ >+ /** >+ * @name expectConditionCloseBracketWrapThrow >+ * @description Gracefully handles a missing '}' if the mode is set to tolerant >+ * @function >+ * @private >+ * @since 5.0 >+ */ >+ function expectConditionCloseBracketWrapThrow() { >+ if (extra.errors) { >+ // continue parsing even with missing close >+ // brace. This gives a better AST for the >+ // block, as information about >+ // the parsed statements remain >+ try { >+ expect('}'); >+ } catch (e) { >+ pushError(e); >+ } >+ } else { >+ expect('}'); >+ } >+ } >+ >+ /** >+ * @name expectConditionCloseParenWrapThrow >+ * @description For statements like if, while, for, etc. check for the ')' on the condition. If >+ * it is not present, catch the error, and backtrack if we see a '{' instead (to continue parsing the block) >+ * @function >+ * @private >+ * @throws The original error from trying to consume the ')' char if not in tolerant mode >+ * @since 5.0 >+ */ >+ function expectConditionCloseParenWrapThrow() { >+ // needs generalizing to a 'expect A but don't consume if you hit B or C' >+ try { >+ expect(')'); >+ } catch (e) { >+ if (extra.errors) { >+ pushError(e); >+ // If a { was hit instead of a ) then don't consume it, let us assume a ')' was >+ // missed and the consequent block is OK >+ if (source[e.index] === '{') { >+ index=e.index; >+ lookahead = null; >+ // activating this block will mean the following statement is parsed as a consequent / body. >+ // without it the statement is considered not at all part of the enclosing statement at all >+ //} else { >+ // rewind(); >+ } >+ } else { >+ throw e; >+ } >+ } >+ >+ } >+ >+ /** >+ * @name pushError >+ * @description Add the error if not already reported. >+ * @function >+ * @private >+ * @param {Object} error The error object to push >+ * @since 5.0 >+ */ >+ function pushError(error) { >+ var len = extra.errors.length; >+ for (var e=0; e < len; e++) { >+ var existingError = extra.errors[e]; >+ if (existingError.index === error.index && existingError.message === error.message) { >+ return; // do not add duplicate >+ } >+ } >+ extra.errors.push(error); >+ } >+ >+ //Recovery >+ >+ /** >+ * @name isNewlineOrSemicolon >+ * @description If the given char is the new line char or a semicolon char >+ * @function >+ * @private >+ * @param {String} ch The character to check >+ * @returns {Boolean} <code>true</code> if the char is a new line or semicolon <code>false</code> otherwise >+ * @since 5.0 >+ */ >+ function isNewlineOrSemicolon(ch) { >+ return ch===';' || ch==='\n'; >+ } >+ >+ /** >+ * @name rewind >+ * @descripton Rewind the lex position to the most recent newline or semicolon. If that turns out >+ * to be the same position as the most recent parsing of a statement was attempted at, >+ * don't rewind (because it will fail in the same way). If it turns out to be the same >+ * position as where we last rewound to, don't do it. Clears the buffer and sets the >+ * index in order to continue lexing from the new position. >+ * @function >+ * @private >+ * @since 5.0 >+ */ >+ function rewind() { >+ var idx = index; >+ while (idx>0 && !isNewlineOrSemicolon(source[idx])) { >+ idx--; >+ } >+ if (idx<=extra.statementStart) { >+ return; >+ } >+ var doRewind = false; >+ if (extra.lastRewindLocation) { >+ doRewind = true; >+ } else { >+ var v = extra.lastRewindLocation; >+ if (v!==idx) { >+ doRewind=true; >+ } >+ } >+ if (doRewind) { >+ index = idx; >+ lookahead = null; >+ extra.lastRewindLocation = index; >+ } >+ } >+ >+ /** >+ * @name rewindToInterestingChar >+ * @description From a position 'idx' in the source this function moves back through the source until >+ * it finds a non-whitespace (including newlines) character. It will jump over block comments. >+ * Returns an object with properties: index - the index it rewound to. lineChange - boolean indicating >+ * if a line was crossed during rewind. >+ * @function >+ * @private >+ * @param {Number} idx The index to rewind to >+ * @returns {Object} Returns the object with the index and line change to rewind to >+ * @since 5.0 >+ */ >+ function rewindToInterestingChar(idx) { >+ var done = false; >+ var lineChange=false; >+ var ch; >+ while (!done) { >+ ch = source[idx]; >+ if (ch==='/') { >+ // possibly rewind over a block comment >+ if (idx>2 && source[idx-1]==='*') { >+ // it is, let's reverse over it >+ idx = idx - 2; >+ var skippedComment = false; >+ while (!skippedComment) { >+ ch = source[idx]; >+ if (ch === '*') { >+ if (idx>0 && source[idx-1]==='/') { >+ skippedComment=true; >+ } >+ } else if (ch==='\n') { >+ lineChange=true; >+ } >+ if (idx === 0) { >+ skippedComment = true; // error scenario, hit front of array before finding /* >+ } >+ idx--; >+ } >+ } else { >+ done=true; >+ } >+ } else >+ if (ch==='\n') { >+ lineChange=true; >+ } else if (!isWhiteSpace(ch)) { >+ done=true; >+ } >+ if (!done) { >+ idx--; >+ } >+ } >+ return {"index":idx,"lineChange":lineChange}; >+ } >+ >+ /** >+ * @name attemptRecoveryNonComputedProperty >+ * @description When a problem occurs in parseNonComputedProperty, attempt to reposition >+ * the lexer to continue processing. >+ * Example: '(foo.)' we will hit the ')' instead of discovering a property and consuming the ')' >+ * will cause the parse of the paretheses to fail, so 'unconsume' it. >+ * Basically rewind by one token if punctuation (type 7) is hit and the char before it was >+ * a dot. This will enable the enclosing parse rule to consume the punctuation. >+ * @function >+ * @private >+ * @param {String} token The token to try and recover from >+ * @since 5.0 >+ */ >+ function attemptRecoveryNonComputedProperty(token) { >+ if (token.value && token.type===Token.Punctuator) { >+ var rewindInfo = rewindToInterestingChar(index-token.value.length-1); >+ var idx = rewindInfo.index; >+ var ch= source[idx]; >+ // Check if worth rewinding >+ // Special case: >+ // "foo.\n(foo())\n" - don't really want that to parse as "foo(foo())" >+ if (ch==='.' && rewindInfo.lineChange && token.value==='(') { >+ // do not recover in this case >+ } else if (ch==='.') { >+ index = idx+1; >+ lookahead=null; >+ } >+ } >+ } >+ >+ // Sync with *.json manifests. >+ exports.version = '1.1.0-dev'; >+ >+ exports.tokenize = tokenize; >+ >+ exports.parse = parse; >+ >+ // Deep copy. >+ exports.Syntax = (function () { >+ var name, types = {}; >+ >+ if (typeof Object.create === 'function') { >+ types = Object.create(null); >+ } >+ >+ for (name in Syntax) { >+ if (Syntax.hasOwnProperty(name)) { >+ types[name] = Syntax[name]; >+ } >+ } >+ >+ if (typeof Object.freeze === 'function') { >+ Object.freeze(types); >+ } >+ >+ return types; >+ }()); >+ >+})); >+/* vim: set sw=4 ts=4 et tw=80 : */
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 423091
: 241229