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