Migrate away from the PrefMetricsService-based device ID in PrefHashCalculator.
[chromium-blink-merge.git] / third_party / blanketjs / src / blanket.js
blob9377d4faf14c93ed1b9161bf02b79b9a70e54812
1 /*! blanket - v1.1.5 */
2 (function(define){
4 /*
5   Copyright (C) 2012 Ariya Hidayat <ariya.hidayat@gmail.com>
6   Copyright (C) 2012 Mathias Bynens <mathias@qiwi.be>
7   Copyright (C) 2012 Joost-Wim Boekesteijn <joost-wim@boekesteijn.nl>
8   Copyright (C) 2012 Kris Kowal <kris.kowal@cixar.com>
9   Copyright (C) 2012 Yusuke Suzuki <utatane.tea@gmail.com>
10   Copyright (C) 2012 Arpad Borsos <arpad.borsos@googlemail.com>
11   Copyright (C) 2011 Ariya Hidayat <ariya.hidayat@gmail.com>
13   Redistribution and use in source and binary forms, with or without
14   modification, are permitted provided that the following conditions are met:
16     * Redistributions of source code must retain the above copyright
17       notice, this list of conditions and the following disclaimer.
18     * Redistributions in binary form must reproduce the above copyright
19       notice, this list of conditions and the following disclaimer in the
20       documentation and/or other materials provided with the distribution.
22   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25   ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
26   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
29   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 /*jslint bitwise:true plusplus:true */
35 /*global esprima:true, define:true, exports:true, window: true,
36 throwError: true, createLiteral: true, generateStatement: true,
37 parseAssignmentExpression: true, parseBlock: true, parseExpression: true,
38 parseFunctionDeclaration: true, parseFunctionExpression: true,
39 parseFunctionSourceElements: true, parseVariableIdentifier: true,
40 parseLeftHandSideExpression: true,
41 parseStatement: true, parseSourceElement: true */
43 (function (root, factory) {
44     'use strict';
46     // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js,
47     // Rhino, and plain browser loading.
48     if (typeof define === 'function' && define.amd) {
49         define(['exports'], factory);
50     } else if (typeof exports !== 'undefined') {
51         factory(exports);
52     } else {
53         factory((root.esprima = {}));
54     }
55 }(this, function (exports) {
56     'use strict';
58     var Token,
59         TokenName,
60         Syntax,
61         PropertyKind,
62         Messages,
63         Regex,
64         source,
65         strict,
66         index,
67         lineNumber,
68         lineStart,
69         length,
70         buffer,
71         state,
72         extra;
74     Token = {
75         BooleanLiteral: 1,
76         EOF: 2,
77         Identifier: 3,
78         Keyword: 4,
79         NullLiteral: 5,
80         NumericLiteral: 6,
81         Punctuator: 7,
82         StringLiteral: 8
83     };
85     TokenName = {};
86     TokenName[Token.BooleanLiteral] = 'Boolean';
87     TokenName[Token.EOF] = '<end>';
88     TokenName[Token.Identifier] = 'Identifier';
89     TokenName[Token.Keyword] = 'Keyword';
90     TokenName[Token.NullLiteral] = 'Null';
91     TokenName[Token.NumericLiteral] = 'Numeric';
92     TokenName[Token.Punctuator] = 'Punctuator';
93     TokenName[Token.StringLiteral] = 'String';
95     Syntax = {
96         AssignmentExpression: 'AssignmentExpression',
97         ArrayExpression: 'ArrayExpression',
98         BlockStatement: 'BlockStatement',
99         BinaryExpression: 'BinaryExpression',
100         BreakStatement: 'BreakStatement',
101         CallExpression: 'CallExpression',
102         CatchClause: 'CatchClause',
103         ConditionalExpression: 'ConditionalExpression',
104         ContinueStatement: 'ContinueStatement',
105         DoWhileStatement: 'DoWhileStatement',
106         DebuggerStatement: 'DebuggerStatement',
107         EmptyStatement: 'EmptyStatement',
108         ExpressionStatement: 'ExpressionStatement',
109         ForStatement: 'ForStatement',
110         ForInStatement: 'ForInStatement',
111         FunctionDeclaration: 'FunctionDeclaration',
112         FunctionExpression: 'FunctionExpression',
113         Identifier: 'Identifier',
114         IfStatement: 'IfStatement',
115         Literal: 'Literal',
116         LabeledStatement: 'LabeledStatement',
117         LogicalExpression: 'LogicalExpression',
118         MemberExpression: 'MemberExpression',
119         NewExpression: 'NewExpression',
120         ObjectExpression: 'ObjectExpression',
121         Program: 'Program',
122         Property: 'Property',
123         ReturnStatement: 'ReturnStatement',
124         SequenceExpression: 'SequenceExpression',
125         SwitchStatement: 'SwitchStatement',
126         SwitchCase: 'SwitchCase',
127         ThisExpression: 'ThisExpression',
128         ThrowStatement: 'ThrowStatement',
129         TryStatement: 'TryStatement',
130         UnaryExpression: 'UnaryExpression',
131         UpdateExpression: 'UpdateExpression',
132         VariableDeclaration: 'VariableDeclaration',
133         VariableDeclarator: 'VariableDeclarator',
134         WhileStatement: 'WhileStatement',
135         WithStatement: 'WithStatement'
136     };
138     PropertyKind = {
139         Data: 1,
140         Get: 2,
141         Set: 4
142     };
144     // Error messages should be identical to V8.
145     Messages = {
146         UnexpectedToken:  'Unexpected token %0',
147         UnexpectedNumber:  'Unexpected number',
148         UnexpectedString:  'Unexpected string',
149         UnexpectedIdentifier:  'Unexpected identifier',
150         UnexpectedReserved:  'Unexpected reserved word',
151         UnexpectedEOS:  'Unexpected end of input',
152         NewlineAfterThrow:  'Illegal newline after throw',
153         InvalidRegExp: 'Invalid regular expression',
154         UnterminatedRegExp:  'Invalid regular expression: missing /',
155         InvalidLHSInAssignment:  'Invalid left-hand side in assignment',
156         InvalidLHSInForIn:  'Invalid left-hand side in for-in',
157         MultipleDefaultsInSwitch: 'More than one default clause in switch statement',
158         NoCatchOrFinally:  'Missing catch or finally after try',
159         UnknownLabel: 'Undefined label \'%0\'',
160         Redeclaration: '%0 \'%1\' has already been declared',
161         IllegalContinue: 'Illegal continue statement',
162         IllegalBreak: 'Illegal break statement',
163         IllegalReturn: 'Illegal return statement',
164         StrictModeWith:  'Strict mode code may not include a with statement',
165         StrictCatchVariable:  'Catch variable may not be eval or arguments in strict mode',
166         StrictVarName:  'Variable name may not be eval or arguments in strict mode',
167         StrictParamName:  'Parameter name eval or arguments is not allowed in strict mode',
168         StrictParamDupe: 'Strict mode function may not have duplicate parameter names',
169         StrictFunctionName:  'Function name may not be eval or arguments in strict mode',
170         StrictOctalLiteral:  'Octal literals are not allowed in strict mode.',
171         StrictDelete:  'Delete of an unqualified identifier in strict mode.',
172         StrictDuplicateProperty:  'Duplicate data property in object literal not allowed in strict mode',
173         AccessorDataProperty:  'Object literal may not have data and accessor property with the same name',
174         AccessorGetSet:  'Object literal may not have multiple get/set accessors with the same name',
175         StrictLHSAssignment:  'Assignment to eval or arguments is not allowed in strict mode',
176         StrictLHSPostfix:  'Postfix increment/decrement may not have eval or arguments operand in strict mode',
177         StrictLHSPrefix:  'Prefix increment/decrement may not have eval or arguments operand in strict mode',
178         StrictReservedWord:  'Use of future reserved word in strict mode'
179     };
181     // See also tools/generate-unicode-regex.py.
182     Regex = {
183         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]'),
184         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]')
185     };
187     // Ensure the condition is true, otherwise throw an error.
188     // This is only to have a better contract semantic, i.e. another safety net
189     // to catch a logic error. The condition shall be fulfilled in normal case.
190     // Do NOT use this to enforce a certain condition on any user input.
192     function assert(condition, message) {
193         if (!condition) {
194             throw new Error('ASSERT: ' + message);
195         }
196     }
198     function sliceSource(from, to) {
199         return source.slice(from, to);
200     }
202     if (typeof 'esprima'[0] === 'undefined') {
203         sliceSource = function sliceArraySource(from, to) {
204             return source.slice(from, to).join('');
205         };
206     }
208     function isDecimalDigit(ch) {
209         return '0123456789'.indexOf(ch) >= 0;
210     }
212     function isHexDigit(ch) {
213         return '0123456789abcdefABCDEF'.indexOf(ch) >= 0;
214     }
216     function isOctalDigit(ch) {
217         return '01234567'.indexOf(ch) >= 0;
218     }
221     // 7.2 White Space
223     function isWhiteSpace(ch) {
224         return (ch === ' ') || (ch === '\u0009') || (ch === '\u000B') ||
225             (ch === '\u000C') || (ch === '\u00A0') ||
226             (ch.charCodeAt(0) >= 0x1680 &&
227              '\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\uFEFF'.indexOf(ch) >= 0);
228     }
230     // 7.3 Line Terminators
232     function isLineTerminator(ch) {
233         return (ch === '\n' || ch === '\r' || ch === '\u2028' || ch === '\u2029');
234     }
236     // 7.6 Identifier Names and Identifiers
238     function isIdentifierStart(ch) {
239         return (ch === '$') || (ch === '_') || (ch === '\\') ||
240             (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') ||
241             ((ch.charCodeAt(0) >= 0x80) && Regex.NonAsciiIdentifierStart.test(ch));
242     }
244     function isIdentifierPart(ch) {
245         return (ch === '$') || (ch === '_') || (ch === '\\') ||
246             (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') ||
247             ((ch >= '0') && (ch <= '9')) ||
248             ((ch.charCodeAt(0) >= 0x80) && Regex.NonAsciiIdentifierPart.test(ch));
249     }
251     // 7.6.1.2 Future Reserved Words
253     function isFutureReservedWord(id) {
254         switch (id) {
256         // Future reserved words.
257         case 'class':
258         case 'enum':
259         case 'export':
260         case 'extends':
261         case 'import':
262         case 'super':
263             return true;
264         }
266         return false;
267     }
269     function isStrictModeReservedWord(id) {
270         switch (id) {
272         // Strict Mode reserved words.
273         case 'implements':
274         case 'interface':
275         case 'package':
276         case 'private':
277         case 'protected':
278         case 'public':
279         case 'static':
280         case 'yield':
281         case 'let':
282             return true;
283         }
285         return false;
286     }
288     function isRestrictedWord(id) {
289         return id === 'eval' || id === 'arguments';
290     }
292     // 7.6.1.1 Keywords
294     function isKeyword(id) {
295         var keyword = false;
296         switch (id.length) {
297         case 2:
298             keyword = (id === 'if') || (id === 'in') || (id === 'do');
299             break;
300         case 3:
301             keyword = (id === 'var') || (id === 'for') || (id === 'new') || (id === 'try');
302             break;
303         case 4:
304             keyword = (id === 'this') || (id === 'else') || (id === 'case') || (id === 'void') || (id === 'with');
305             break;
306         case 5:
307             keyword = (id === 'while') || (id === 'break') || (id === 'catch') || (id === 'throw');
308             break;
309         case 6:
310             keyword = (id === 'return') || (id === 'typeof') || (id === 'delete') || (id === 'switch');
311             break;
312         case 7:
313             keyword = (id === 'default') || (id === 'finally');
314             break;
315         case 8:
316             keyword = (id === 'function') || (id === 'continue') || (id === 'debugger');
317             break;
318         case 10:
319             keyword = (id === 'instanceof');
320             break;
321         }
323         if (keyword) {
324             return true;
325         }
327         switch (id) {
328         // Future reserved words.
329         // 'const' is specialized as Keyword in V8.
330         case 'const':
331             return true;
333         // For compatiblity to SpiderMonkey and ES.next
334         case 'yield':
335         case 'let':
336             return true;
337         }
339         if (strict && isStrictModeReservedWord(id)) {
340             return true;
341         }
343         return isFutureReservedWord(id);
344     }
346     // 7.4 Comments
348     function skipComment() {
349         var ch, blockComment, lineComment;
351         blockComment = false;
352         lineComment = false;
354         while (index < length) {
355             ch = source[index];
357             if (lineComment) {
358                 ch = source[index++];
359                 if (isLineTerminator(ch)) {
360                     lineComment = false;
361                     if (ch === '\r' && source[index] === '\n') {
362                         ++index;
363                     }
364                     ++lineNumber;
365                     lineStart = index;
366                 }
367             } else if (blockComment) {
368                 if (isLineTerminator(ch)) {
369                     if (ch === '\r' && source[index + 1] === '\n') {
370                         ++index;
371                     }
372                     ++lineNumber;
373                     ++index;
374                     lineStart = index;
375                     if (index >= length) {
376                         throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
377                     }
378                 } else {
379                     ch = source[index++];
380                     if (index >= length) {
381                         throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
382                     }
383                     if (ch === '*') {
384                         ch = source[index];
385                         if (ch === '/') {
386                             ++index;
387                             blockComment = false;
388                         }
389                     }
390                 }
391             } else if (ch === '/') {
392                 ch = source[index + 1];
393                 if (ch === '/') {
394                     index += 2;
395                     lineComment = true;
396                 } else if (ch === '*') {
397                     index += 2;
398                     blockComment = true;
399                     if (index >= length) {
400                         throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
401                     }
402                 } else {
403                     break;
404                 }
405             } else if (isWhiteSpace(ch)) {
406                 ++index;
407             } else if (isLineTerminator(ch)) {
408                 ++index;
409                 if (ch ===  '\r' && source[index] === '\n') {
410                     ++index;
411                 }
412                 ++lineNumber;
413                 lineStart = index;
414             } else {
415                 break;
416             }
417         }
418     }
420     function scanHexEscape(prefix) {
421         var i, len, ch, code = 0;
423         len = (prefix === 'u') ? 4 : 2;
424         for (i = 0; i < len; ++i) {
425             if (index < length && isHexDigit(source[index])) {
426                 ch = source[index++];
427                 code = code * 16 + '0123456789abcdef'.indexOf(ch.toLowerCase());
428             } else {
429                 return '';
430             }
431         }
432         return String.fromCharCode(code);
433     }
435     function scanIdentifier() {
436         var ch, start, id, restore;
438         ch = source[index];
439         if (!isIdentifierStart(ch)) {
440             return;
441         }
443         start = index;
444         if (ch === '\\') {
445             ++index;
446             if (source[index] !== 'u') {
447                 return;
448             }
449             ++index;
450             restore = index;
451             ch = scanHexEscape('u');
452             if (ch) {
453                 if (ch === '\\' || !isIdentifierStart(ch)) {
454                     return;
455                 }
456                 id = ch;
457             } else {
458                 index = restore;
459                 id = 'u';
460             }
461         } else {
462             id = source[index++];
463         }
465         while (index < length) {
466             ch = source[index];
467             if (!isIdentifierPart(ch)) {
468                 break;
469             }
470             if (ch === '\\') {
471                 ++index;
472                 if (source[index] !== 'u') {
473                     return;
474                 }
475                 ++index;
476                 restore = index;
477                 ch = scanHexEscape('u');
478                 if (ch) {
479                     if (ch === '\\' || !isIdentifierPart(ch)) {
480                         return;
481                     }
482                     id += ch;
483                 } else {
484                     index = restore;
485                     id += 'u';
486                 }
487             } else {
488                 id += source[index++];
489             }
490         }
492         // There is no keyword or literal with only one character.
493         // Thus, it must be an identifier.
494         if (id.length === 1) {
495             return {
496                 type: Token.Identifier,
497                 value: id,
498                 lineNumber: lineNumber,
499                 lineStart: lineStart,
500                 range: [start, index]
501             };
502         }
504         if (isKeyword(id)) {
505             return {
506                 type: Token.Keyword,
507                 value: id,
508                 lineNumber: lineNumber,
509                 lineStart: lineStart,
510                 range: [start, index]
511             };
512         }
514         // 7.8.1 Null Literals
516         if (id === 'null') {
517             return {
518                 type: Token.NullLiteral,
519                 value: id,
520                 lineNumber: lineNumber,
521                 lineStart: lineStart,
522                 range: [start, index]
523             };
524         }
526         // 7.8.2 Boolean Literals
528         if (id === 'true' || id === 'false') {
529             return {
530                 type: Token.BooleanLiteral,
531                 value: id,
532                 lineNumber: lineNumber,
533                 lineStart: lineStart,
534                 range: [start, index]
535             };
536         }
538         return {
539             type: Token.Identifier,
540             value: id,
541             lineNumber: lineNumber,
542             lineStart: lineStart,
543             range: [start, index]
544         };
545     }
547     // 7.7 Punctuators
549     function scanPunctuator() {
550         var start = index,
551             ch1 = source[index],
552             ch2,
553             ch3,
554             ch4;
556         // Check for most common single-character punctuators.
558         if (ch1 === ';' || ch1 === '{' || ch1 === '}') {
559             ++index;
560             return {
561                 type: Token.Punctuator,
562                 value: ch1,
563                 lineNumber: lineNumber,
564                 lineStart: lineStart,
565                 range: [start, index]
566             };
567         }
569         if (ch1 === ',' || ch1 === '(' || ch1 === ')') {
570             ++index;
571             return {
572                 type: Token.Punctuator,
573                 value: ch1,
574                 lineNumber: lineNumber,
575                 lineStart: lineStart,
576                 range: [start, index]
577             };
578         }
580         // Dot (.) can also start a floating-point number, hence the need
581         // to check the next character.
583         ch2 = source[index + 1];
584         if (ch1 === '.' && !isDecimalDigit(ch2)) {
585             return {
586                 type: Token.Punctuator,
587                 value: source[index++],
588                 lineNumber: lineNumber,
589                 lineStart: lineStart,
590                 range: [start, index]
591             };
592         }
594         // Peek more characters.
596         ch3 = source[index + 2];
597         ch4 = source[index + 3];
599         // 4-character punctuator: >>>=
601         if (ch1 === '>' && ch2 === '>' && ch3 === '>') {
602             if (ch4 === '=') {
603                 index += 4;
604                 return {
605                     type: Token.Punctuator,
606                     value: '>>>=',
607                     lineNumber: lineNumber,
608                     lineStart: lineStart,
609                     range: [start, index]
610                 };
611             }
612         }
614         // 3-character punctuators: === !== >>> <<= >>=
616         if (ch1 === '=' && ch2 === '=' && ch3 === '=') {
617             index += 3;
618             return {
619                 type: Token.Punctuator,
620                 value: '===',
621                 lineNumber: lineNumber,
622                 lineStart: lineStart,
623                 range: [start, index]
624             };
625         }
627         if (ch1 === '!' && ch2 === '=' && ch3 === '=') {
628             index += 3;
629             return {
630                 type: Token.Punctuator,
631                 value: '!==',
632                 lineNumber: lineNumber,
633                 lineStart: lineStart,
634                 range: [start, index]
635             };
636         }
638         if (ch1 === '>' && ch2 === '>' && ch3 === '>') {
639             index += 3;
640             return {
641                 type: Token.Punctuator,
642                 value: '>>>',
643                 lineNumber: lineNumber,
644                 lineStart: lineStart,
645                 range: [start, index]
646             };
647         }
649         if (ch1 === '<' && ch2 === '<' && ch3 === '=') {
650             index += 3;
651             return {
652                 type: Token.Punctuator,
653                 value: '<<=',
654                 lineNumber: lineNumber,
655                 lineStart: lineStart,
656                 range: [start, index]
657             };
658         }
660         if (ch1 === '>' && ch2 === '>' && ch3 === '=') {
661             index += 3;
662             return {
663                 type: Token.Punctuator,
664                 value: '>>=',
665                 lineNumber: lineNumber,
666                 lineStart: lineStart,
667                 range: [start, index]
668             };
669         }
671         // 2-character punctuators: <= >= == != ++ -- << >> && ||
672         // += -= *= %= &= |= ^= /=
674         if (ch2 === '=') {
675             if ('<>=!+-*%&|^/'.indexOf(ch1) >= 0) {
676                 index += 2;
677                 return {
678                     type: Token.Punctuator,
679                     value: ch1 + ch2,
680                     lineNumber: lineNumber,
681                     lineStart: lineStart,
682                     range: [start, index]
683                 };
684             }
685         }
687         if (ch1 === ch2 && ('+-<>&|'.indexOf(ch1) >= 0)) {
688             if ('+-<>&|'.indexOf(ch2) >= 0) {
689                 index += 2;
690                 return {
691                     type: Token.Punctuator,
692                     value: ch1 + ch2,
693                     lineNumber: lineNumber,
694                     lineStart: lineStart,
695                     range: [start, index]
696                 };
697             }
698         }
700         // The remaining 1-character punctuators.
702         if ('[]<>+-*%&|^!~?:=/'.indexOf(ch1) >= 0) {
703             return {
704                 type: Token.Punctuator,
705                 value: source[index++],
706                 lineNumber: lineNumber,
707                 lineStart: lineStart,
708                 range: [start, index]
709             };
710         }
711     }
713     // 7.8.3 Numeric Literals
715     function scanNumericLiteral() {
716         var number, start, ch;
718         ch = source[index];
719         assert(isDecimalDigit(ch) || (ch === '.'),
720             'Numeric literal must start with a decimal digit or a decimal point');
722         start = index;
723         number = '';
724         if (ch !== '.') {
725             number = source[index++];
726             ch = source[index];
728             // Hex number starts with '0x'.
729             // Octal number starts with '0'.
730             if (number === '0') {
731                 if (ch === 'x' || ch === 'X') {
732                     number += source[index++];
733                     while (index < length) {
734                         ch = source[index];
735                         if (!isHexDigit(ch)) {
736                             break;
737                         }
738                         number += source[index++];
739                     }
741                     if (number.length <= 2) {
742                         // only 0x
743                         throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
744                     }
746                     if (index < length) {
747                         ch = source[index];
748                         if (isIdentifierStart(ch)) {
749                             throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
750                         }
751                     }
752                     return {
753                         type: Token.NumericLiteral,
754                         value: parseInt(number, 16),
755                         lineNumber: lineNumber,
756                         lineStart: lineStart,
757                         range: [start, index]
758                     };
759                 } else if (isOctalDigit(ch)) {
760                     number += source[index++];
761                     while (index < length) {
762                         ch = source[index];
763                         if (!isOctalDigit(ch)) {
764                             break;
765                         }
766                         number += source[index++];
767                     }
769                     if (index < length) {
770                         ch = source[index];
771                         if (isIdentifierStart(ch) || isDecimalDigit(ch)) {
772                             throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
773                         }
774                     }
775                     return {
776                         type: Token.NumericLiteral,
777                         value: parseInt(number, 8),
778                         octal: true,
779                         lineNumber: lineNumber,
780                         lineStart: lineStart,
781                         range: [start, index]
782                     };
783                 }
785                 // decimal number starts with '0' such as '09' is illegal.
786                 if (isDecimalDigit(ch)) {
787                     throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
788                 }
789             }
791             while (index < length) {
792                 ch = source[index];
793                 if (!isDecimalDigit(ch)) {
794                     break;
795                 }
796                 number += source[index++];
797             }
798         }
800         if (ch === '.') {
801             number += source[index++];
802             while (index < length) {
803                 ch = source[index];
804                 if (!isDecimalDigit(ch)) {
805                     break;
806                 }
807                 number += source[index++];
808             }
809         }
811         if (ch === 'e' || ch === 'E') {
812             number += source[index++];
814             ch = source[index];
815             if (ch === '+' || ch === '-') {
816                 number += source[index++];
817             }
819             ch = source[index];
820             if (isDecimalDigit(ch)) {
821                 number += source[index++];
822                 while (index < length) {
823                     ch = source[index];
824                     if (!isDecimalDigit(ch)) {
825                         break;
826                     }
827                     number += source[index++];
828                 }
829             } else {
830                 ch = 'character ' + ch;
831                 if (index >= length) {
832                     ch = '<end>';
833                 }
834                 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
835             }
836         }
838         if (index < length) {
839             ch = source[index];
840             if (isIdentifierStart(ch)) {
841                 throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
842             }
843         }
845         return {
846             type: Token.NumericLiteral,
847             value: parseFloat(number),
848             lineNumber: lineNumber,
849             lineStart: lineStart,
850             range: [start, index]
851         };
852     }
854     // 7.8.4 String Literals
856     function scanStringLiteral() {
857         var str = '', quote, start, ch, code, unescaped, restore, octal = false;
859         quote = source[index];
860         assert((quote === '\'' || quote === '"'),
861             'String literal must starts with a quote');
863         start = index;
864         ++index;
866         while (index < length) {
867             ch = source[index++];
869             if (ch === quote) {
870                 quote = '';
871                 break;
872             } else if (ch === '\\') {
873                 ch = source[index++];
874                 if (!isLineTerminator(ch)) {
875                     switch (ch) {
876                     case 'n':
877                         str += '\n';
878                         break;
879                     case 'r':
880                         str += '\r';
881                         break;
882                     case 't':
883                         str += '\t';
884                         break;
885                     case 'u':
886                     case 'x':
887                         restore = index;
888                         unescaped = scanHexEscape(ch);
889                         if (unescaped) {
890                             str += unescaped;
891                         } else {
892                             index = restore;
893                             str += ch;
894                         }
895                         break;
896                     case 'b':
897                         str += '\b';
898                         break;
899                     case 'f':
900                         str += '\f';
901                         break;
902                     case 'v':
903                         str += '\v';
904                         break;
906                     default:
907                         if (isOctalDigit(ch)) {
908                             code = '01234567'.indexOf(ch);
910                             // \0 is not octal escape sequence
911                             if (code !== 0) {
912                                 octal = true;
913                             }
915                             if (index < length && isOctalDigit(source[index])) {
916                                 octal = true;
917                                 code = code * 8 + '01234567'.indexOf(source[index++]);
919                                 // 3 digits are only allowed when string starts
920                                 // with 0, 1, 2, 3
921                                 if ('0123'.indexOf(ch) >= 0 &&
922                                         index < length &&
923                                         isOctalDigit(source[index])) {
924                                     code = code * 8 + '01234567'.indexOf(source[index++]);
925                                 }
926                             }
927                             str += String.fromCharCode(code);
928                         } else {
929                             str += ch;
930                         }
931                         break;
932                     }
933                 } else {
934                     ++lineNumber;
935                     if (ch ===  '\r' && source[index] === '\n') {
936                         ++index;
937                     }
938                 }
939             } else if (isLineTerminator(ch)) {
940                 break;
941             } else {
942                 str += ch;
943             }
944         }
946         if (quote !== '') {
947             throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
948         }
950         return {
951             type: Token.StringLiteral,
952             value: str,
953             octal: octal,
954             lineNumber: lineNumber,
955             lineStart: lineStart,
956             range: [start, index]
957         };
958     }
960     function scanRegExp() {
961         var str, ch, start, pattern, flags, value, classMarker = false, restore, terminated = false;
963         buffer = null;
964         skipComment();
966         start = index;
967         ch = source[index];
968         assert(ch === '/', 'Regular expression literal must start with a slash');
969         str = source[index++];
971         while (index < length) {
972             ch = source[index++];
973             str += ch;
974             if (classMarker) {
975                 if (ch === ']') {
976                     classMarker = false;
977                 }
978             } else {
979                 if (ch === '\\') {
980                     ch = source[index++];
981                     // ECMA-262 7.8.5
982                     if (isLineTerminator(ch)) {
983                         throwError({}, Messages.UnterminatedRegExp);
984                     }
985                     str += ch;
986                 } else if (ch === '/') {
987                     terminated = true;
988                     break;
989                 } else if (ch === '[') {
990                     classMarker = true;
991                 } else if (isLineTerminator(ch)) {
992                     throwError({}, Messages.UnterminatedRegExp);
993                 }
994             }
995         }
997         if (!terminated) {
998             throwError({}, Messages.UnterminatedRegExp);
999         }
1001         // Exclude leading and trailing slash.
1002         pattern = str.substr(1, str.length - 2);
1004         flags = '';
1005         while (index < length) {
1006             ch = source[index];
1007             if (!isIdentifierPart(ch)) {
1008                 break;
1009             }
1011             ++index;
1012             if (ch === '\\' && index < length) {
1013                 ch = source[index];
1014                 if (ch === 'u') {
1015                     ++index;
1016                     restore = index;
1017                     ch = scanHexEscape('u');
1018                     if (ch) {
1019                         flags += ch;
1020                         str += '\\u';
1021                         for (; restore < index; ++restore) {
1022                             str += source[restore];
1023                         }
1024                     } else {
1025                         index = restore;
1026                         flags += 'u';
1027                         str += '\\u';
1028                     }
1029                 } else {
1030                     str += '\\';
1031                 }
1032             } else {
1033                 flags += ch;
1034                 str += ch;
1035             }
1036         }
1038         try {
1039             value = new RegExp(pattern, flags);
1040         } catch (e) {
1041             throwError({}, Messages.InvalidRegExp);
1042         }
1044         return {
1045             literal: str,
1046             value: value,
1047             range: [start, index]
1048         };
1049     }
1051     function isIdentifierName(token) {
1052         return token.type === Token.Identifier ||
1053             token.type === Token.Keyword ||
1054             token.type === Token.BooleanLiteral ||
1055             token.type === Token.NullLiteral;
1056     }
1058     function advance() {
1059         var ch, token;
1061         skipComment();
1063         if (index >= length) {
1064             return {
1065                 type: Token.EOF,
1066                 lineNumber: lineNumber,
1067                 lineStart: lineStart,
1068                 range: [index, index]
1069             };
1070         }
1072         token = scanPunctuator();
1073         if (typeof token !== 'undefined') {
1074             return token;
1075         }
1077         ch = source[index];
1079         if (ch === '\'' || ch === '"') {
1080             return scanStringLiteral();
1081         }
1083         if (ch === '.' || isDecimalDigit(ch)) {
1084             return scanNumericLiteral();
1085         }
1087         token = scanIdentifier();
1088         if (typeof token !== 'undefined') {
1089             return token;
1090         }
1092         throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
1093     }
1095     function lex() {
1096         var token;
1098         if (buffer) {
1099             index = buffer.range[1];
1100             lineNumber = buffer.lineNumber;
1101             lineStart = buffer.lineStart;
1102             token = buffer;
1103             buffer = null;
1104             return token;
1105         }
1107         buffer = null;
1108         return advance();
1109     }
1111     function lookahead() {
1112         var pos, line, start;
1114         if (buffer !== null) {
1115             return buffer;
1116         }
1118         pos = index;
1119         line = lineNumber;
1120         start = lineStart;
1121         buffer = advance();
1122         index = pos;
1123         lineNumber = line;
1124         lineStart = start;
1126         return buffer;
1127     }
1129     // Return true if there is a line terminator before the next token.
1131     function peekLineTerminator() {
1132         var pos, line, start, found;
1134         pos = index;
1135         line = lineNumber;
1136         start = lineStart;
1137         skipComment();
1138         found = lineNumber !== line;
1139         index = pos;
1140         lineNumber = line;
1141         lineStart = start;
1143         return found;
1144     }
1146     // Throw an exception
1148     function throwError(token, messageFormat) {
1149         var error,
1150             args = Array.prototype.slice.call(arguments, 2),
1151             msg = messageFormat.replace(
1152                 /%(\d)/g,
1153                 function (whole, index) {
1154                     return args[index] || '';
1155                 }
1156             );
1158         if (typeof token.lineNumber === 'number') {
1159             error = new Error('Line ' + token.lineNumber + ': ' + msg);
1160             error.index = token.range[0];
1161             error.lineNumber = token.lineNumber;
1162             error.column = token.range[0] - lineStart + 1;
1163         } else {
1164             error = new Error('Line ' + lineNumber + ': ' + msg);
1165             error.index = index;
1166             error.lineNumber = lineNumber;
1167             error.column = index - lineStart + 1;
1168         }
1170         throw error;
1171     }
1173     function throwErrorTolerant() {
1174         try {
1175             throwError.apply(null, arguments);
1176         } catch (e) {
1177             if (extra.errors) {
1178                 extra.errors.push(e);
1179             } else {
1180                 throw e;
1181             }
1182         }
1183     }
1186     // Throw an exception because of the token.
1188     function throwUnexpected(token) {
1189         if (token.type === Token.EOF) {
1190             throwError(token, Messages.UnexpectedEOS);
1191         }
1193         if (token.type === Token.NumericLiteral) {
1194             throwError(token, Messages.UnexpectedNumber);
1195         }
1197         if (token.type === Token.StringLiteral) {
1198             throwError(token, Messages.UnexpectedString);
1199         }
1201         if (token.type === Token.Identifier) {
1202             throwError(token, Messages.UnexpectedIdentifier);
1203         }
1205         if (token.type === Token.Keyword) {
1206             if (isFutureReservedWord(token.value)) {
1207                 throwError(token, Messages.UnexpectedReserved);
1208             } else if (strict && isStrictModeReservedWord(token.value)) {
1209                 throwErrorTolerant(token, Messages.StrictReservedWord);
1210                 return;
1211             }
1212             throwError(token, Messages.UnexpectedToken, token.value);
1213         }
1215         // BooleanLiteral, NullLiteral, or Punctuator.
1216         throwError(token, Messages.UnexpectedToken, token.value);
1217     }
1219     // Expect the next token to match the specified punctuator.
1220     // If not, an exception will be thrown.
1222     function expect(value) {
1223         var token = lex();
1224         if (token.type !== Token.Punctuator || token.value !== value) {
1225             throwUnexpected(token);
1226         }
1227     }
1229     // Expect the next token to match the specified keyword.
1230     // If not, an exception will be thrown.
1232     function expectKeyword(keyword) {
1233         var token = lex();
1234         if (token.type !== Token.Keyword || token.value !== keyword) {
1235             throwUnexpected(token);
1236         }
1237     }
1239     // Return true if the next token matches the specified punctuator.
1241     function match(value) {
1242         var token = lookahead();
1243         return token.type === Token.Punctuator && token.value === value;
1244     }
1246     // Return true if the next token matches the specified keyword
1248     function matchKeyword(keyword) {
1249         var token = lookahead();
1250         return token.type === Token.Keyword && token.value === keyword;
1251     }
1253     // Return true if the next token is an assignment operator
1255     function matchAssign() {
1256         var token = lookahead(),
1257             op = token.value;
1259         if (token.type !== Token.Punctuator) {
1260             return false;
1261         }
1262         return op === '=' ||
1263             op === '*=' ||
1264             op === '/=' ||
1265             op === '%=' ||
1266             op === '+=' ||
1267             op === '-=' ||
1268             op === '<<=' ||
1269             op === '>>=' ||
1270             op === '>>>=' ||
1271             op === '&=' ||
1272             op === '^=' ||
1273             op === '|=';
1274     }
1276     function consumeSemicolon() {
1277         var token, line;
1279         // Catch the very common case first.
1280         if (source[index] === ';') {
1281             lex();
1282             return;
1283         }
1285         line = lineNumber;
1286         skipComment();
1287         if (lineNumber !== line) {
1288             return;
1289         }
1291         if (match(';')) {
1292             lex();
1293             return;
1294         }
1296         token = lookahead();
1297         if (token.type !== Token.EOF && !match('}')) {
1298             throwUnexpected(token);
1299         }
1300     }
1302     // Return true if provided expression is LeftHandSideExpression
1304     function isLeftHandSide(expr) {
1305         return expr.type === Syntax.Identifier || expr.type === Syntax.MemberExpression;
1306     }
1308     // 11.1.4 Array Initialiser
1310     function parseArrayInitialiser() {
1311         var elements = [];
1313         expect('[');
1315         while (!match(']')) {
1316             if (match(',')) {
1317                 lex();
1318                 elements.push(null);
1319             } else {
1320                 elements.push(parseAssignmentExpression());
1322                 if (!match(']')) {
1323                     expect(',');
1324                 }
1325             }
1326         }
1328         expect(']');
1330         return {
1331             type: Syntax.ArrayExpression,
1332             elements: elements
1333         };
1334     }
1336     // 11.1.5 Object Initialiser
1338     function parsePropertyFunction(param, first) {
1339         var previousStrict, body;
1341         previousStrict = strict;
1342         body = parseFunctionSourceElements();
1343         if (first && strict && isRestrictedWord(param[0].name)) {
1344             throwErrorTolerant(first, Messages.StrictParamName);
1345         }
1346         strict = previousStrict;
1348         return {
1349             type: Syntax.FunctionExpression,
1350             id: null,
1351             params: param,
1352             defaults: [],
1353             body: body,
1354             rest: null,
1355             generator: false,
1356             expression: false
1357         };
1358     }
1360     function parseObjectPropertyKey() {
1361         var token = lex();
1363         // Note: This function is called only from parseObjectProperty(), where
1364         // EOF and Punctuator tokens are already filtered out.
1366         if (token.type === Token.StringLiteral || token.type === Token.NumericLiteral) {
1367             if (strict && token.octal) {
1368                 throwErrorTolerant(token, Messages.StrictOctalLiteral);
1369             }
1370             return createLiteral(token);
1371         }
1373         return {
1374             type: Syntax.Identifier,
1375             name: token.value
1376         };
1377     }
1379     function parseObjectProperty() {
1380         var token, key, id, param;
1382         token = lookahead();
1384         if (token.type === Token.Identifier) {
1386             id = parseObjectPropertyKey();
1388             // Property Assignment: Getter and Setter.
1390             if (token.value === 'get' && !match(':')) {
1391                 key = parseObjectPropertyKey();
1392                 expect('(');
1393                 expect(')');
1394                 return {
1395                     type: Syntax.Property,
1396                     key: key,
1397                     value: parsePropertyFunction([]),
1398                     kind: 'get'
1399                 };
1400             } else if (token.value === 'set' && !match(':')) {
1401                 key = parseObjectPropertyKey();
1402                 expect('(');
1403                 token = lookahead();
1404                 if (token.type !== Token.Identifier) {
1405                     throwUnexpected(lex());
1406                 }
1407                 param = [ parseVariableIdentifier() ];
1408                 expect(')');
1409                 return {
1410                     type: Syntax.Property,
1411                     key: key,
1412                     value: parsePropertyFunction(param, token),
1413                     kind: 'set'
1414                 };
1415             } else {
1416                 expect(':');
1417                 return {
1418                     type: Syntax.Property,
1419                     key: id,
1420                     value: parseAssignmentExpression(),
1421                     kind: 'init'
1422                 };
1423             }
1424         } else if (token.type === Token.EOF || token.type === Token.Punctuator) {
1425             throwUnexpected(token);
1426         } else {
1427             key = parseObjectPropertyKey();
1428             expect(':');
1429             return {
1430                 type: Syntax.Property,
1431                 key: key,
1432                 value: parseAssignmentExpression(),
1433                 kind: 'init'
1434             };
1435         }
1436     }
1438     function parseObjectInitialiser() {
1439         var properties = [], property, name, kind, map = {}, toString = String;
1441         expect('{');
1443         while (!match('}')) {
1444             property = parseObjectProperty();
1446             if (property.key.type === Syntax.Identifier) {
1447                 name = property.key.name;
1448             } else {
1449                 name = toString(property.key.value);
1450             }
1451             kind = (property.kind === 'init') ? PropertyKind.Data : (property.kind === 'get') ? PropertyKind.Get : PropertyKind.Set;
1452             if (Object.prototype.hasOwnProperty.call(map, name)) {
1453                 if (map[name] === PropertyKind.Data) {
1454                     if (strict && kind === PropertyKind.Data) {
1455                         throwErrorTolerant({}, Messages.StrictDuplicateProperty);
1456                     } else if (kind !== PropertyKind.Data) {
1457                         throwErrorTolerant({}, Messages.AccessorDataProperty);
1458                     }
1459                 } else {
1460                     if (kind === PropertyKind.Data) {
1461                         throwErrorTolerant({}, Messages.AccessorDataProperty);
1462                     } else if (map[name] & kind) {
1463                         throwErrorTolerant({}, Messages.AccessorGetSet);
1464                     }
1465                 }
1466                 map[name] |= kind;
1467             } else {
1468                 map[name] = kind;
1469             }
1471             properties.push(property);
1473             if (!match('}')) {
1474                 expect(',');
1475             }
1476         }
1478         expect('}');
1480         return {
1481             type: Syntax.ObjectExpression,
1482             properties: properties
1483         };
1484     }
1486     // 11.1.6 The Grouping Operator
1488     function parseGroupExpression() {
1489         var expr;
1491         expect('(');
1493         expr = parseExpression();
1495         expect(')');
1497         return expr;
1498     }
1501     // 11.1 Primary Expressions
1503     function parsePrimaryExpression() {
1504         var token = lookahead(),
1505             type = token.type;
1507         if (type === Token.Identifier) {
1508             return {
1509                 type: Syntax.Identifier,
1510                 name: lex().value
1511             };
1512         }
1514         if (type === Token.StringLiteral || type === Token.NumericLiteral) {
1515             if (strict && token.octal) {
1516                 throwErrorTolerant(token, Messages.StrictOctalLiteral);
1517             }
1518             return createLiteral(lex());
1519         }
1521         if (type === Token.Keyword) {
1522             if (matchKeyword('this')) {
1523                 lex();
1524                 return {
1525                     type: Syntax.ThisExpression
1526                 };
1527             }
1529             if (matchKeyword('function')) {
1530                 return parseFunctionExpression();
1531             }
1532         }
1534         if (type === Token.BooleanLiteral) {
1535             lex();
1536             token.value = (token.value === 'true');
1537             return createLiteral(token);
1538         }
1540         if (type === Token.NullLiteral) {
1541             lex();
1542             token.value = null;
1543             return createLiteral(token);
1544         }
1546         if (match('[')) {
1547             return parseArrayInitialiser();
1548         }
1550         if (match('{')) {
1551             return parseObjectInitialiser();
1552         }
1554         if (match('(')) {
1555             return parseGroupExpression();
1556         }
1558         if (match('/') || match('/=')) {
1559             return createLiteral(scanRegExp());
1560         }
1562         return throwUnexpected(lex());
1563     }
1565     // 11.2 Left-Hand-Side Expressions
1567     function parseArguments() {
1568         var args = [];
1570         expect('(');
1572         if (!match(')')) {
1573             while (index < length) {
1574                 args.push(parseAssignmentExpression());
1575                 if (match(')')) {
1576                     break;
1577                 }
1578                 expect(',');
1579             }
1580         }
1582         expect(')');
1584         return args;
1585     }
1587     function parseNonComputedProperty() {
1588         var token = lex();
1590         if (!isIdentifierName(token)) {
1591             throwUnexpected(token);
1592         }
1594         return {
1595             type: Syntax.Identifier,
1596             name: token.value
1597         };
1598     }
1600     function parseNonComputedMember() {
1601         expect('.');
1603         return parseNonComputedProperty();
1604     }
1606     function parseComputedMember() {
1607         var expr;
1609         expect('[');
1611         expr = parseExpression();
1613         expect(']');
1615         return expr;
1616     }
1618     function parseNewExpression() {
1619         var expr;
1621         expectKeyword('new');
1623         expr = {
1624             type: Syntax.NewExpression,
1625             callee: parseLeftHandSideExpression(),
1626             'arguments': []
1627         };
1629         if (match('(')) {
1630             expr['arguments'] = parseArguments();
1631         }
1633         return expr;
1634     }
1636     function parseLeftHandSideExpressionAllowCall() {
1637         var expr;
1639         expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression();
1641         while (match('.') || match('[') || match('(')) {
1642             if (match('(')) {
1643                 expr = {
1644                     type: Syntax.CallExpression,
1645                     callee: expr,
1646                     'arguments': parseArguments()
1647                 };
1648             } else if (match('[')) {
1649                 expr = {
1650                     type: Syntax.MemberExpression,
1651                     computed: true,
1652                     object: expr,
1653                     property: parseComputedMember()
1654                 };
1655             } else {
1656                 expr = {
1657                     type: Syntax.MemberExpression,
1658                     computed: false,
1659                     object: expr,
1660                     property: parseNonComputedMember()
1661                 };
1662             }
1663         }
1665         return expr;
1666     }
1669     function parseLeftHandSideExpression() {
1670         var expr;
1672         expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression();
1674         while (match('.') || match('[')) {
1675             if (match('[')) {
1676                 expr = {
1677                     type: Syntax.MemberExpression,
1678                     computed: true,
1679                     object: expr,
1680                     property: parseComputedMember()
1681                 };
1682             } else {
1683                 expr = {
1684                     type: Syntax.MemberExpression,
1685                     computed: false,
1686                     object: expr,
1687                     property: parseNonComputedMember()
1688                 };
1689             }
1690         }
1692         return expr;
1693     }
1695     // 11.3 Postfix Expressions
1697     function parsePostfixExpression() {
1698         var expr = parseLeftHandSideExpressionAllowCall(), token;
1700         token = lookahead();
1701         if (token.type !== Token.Punctuator) {
1702             return expr;
1703         }
1705         if ((match('++') || match('--')) && !peekLineTerminator()) {
1706             // 11.3.1, 11.3.2
1707             if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) {
1708                 throwErrorTolerant({}, Messages.StrictLHSPostfix);
1709             }
1711             if (!isLeftHandSide(expr)) {
1712                 throwError({}, Messages.InvalidLHSInAssignment);
1713             }
1715             expr = {
1716                 type: Syntax.UpdateExpression,
1717                 operator: lex().value,
1718                 argument: expr,
1719                 prefix: false
1720             };
1721         }
1723         return expr;
1724     }
1726     // 11.4 Unary Operators
1728     function parseUnaryExpression() {
1729         var token, expr;
1731         token = lookahead();
1732         if (token.type !== Token.Punctuator && token.type !== Token.Keyword) {
1733             return parsePostfixExpression();
1734         }
1736         if (match('++') || match('--')) {
1737             token = lex();
1738             expr = parseUnaryExpression();
1739             // 11.4.4, 11.4.5
1740             if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) {
1741                 throwErrorTolerant({}, Messages.StrictLHSPrefix);
1742             }
1744             if (!isLeftHandSide(expr)) {
1745                 throwError({}, Messages.InvalidLHSInAssignment);
1746             }
1748             expr = {
1749                 type: Syntax.UpdateExpression,
1750                 operator: token.value,
1751                 argument: expr,
1752                 prefix: true
1753             };
1754             return expr;
1755         }
1757         if (match('+') || match('-') || match('~') || match('!')) {
1758             expr = {
1759                 type: Syntax.UnaryExpression,
1760                 operator: lex().value,
1761                 argument: parseUnaryExpression()
1762             };
1763             return expr;
1764         }
1766         if (matchKeyword('delete') || matchKeyword('void') || matchKeyword('typeof')) {
1767             expr = {
1768                 type: Syntax.UnaryExpression,
1769                 operator: lex().value,
1770                 argument: parseUnaryExpression()
1771             };
1772             if (strict && expr.operator === 'delete' && expr.argument.type === Syntax.Identifier) {
1773                 throwErrorTolerant({}, Messages.StrictDelete);
1774             }
1775             return expr;
1776         }
1778         return parsePostfixExpression();
1779     }
1781     // 11.5 Multiplicative Operators
1783     function parseMultiplicativeExpression() {
1784         var expr = parseUnaryExpression();
1786         while (match('*') || match('/') || match('%')) {
1787             expr = {
1788                 type: Syntax.BinaryExpression,
1789                 operator: lex().value,
1790                 left: expr,
1791                 right: parseUnaryExpression()
1792             };
1793         }
1795         return expr;
1796     }
1798     // 11.6 Additive Operators
1800     function parseAdditiveExpression() {
1801         var expr = parseMultiplicativeExpression();
1803         while (match('+') || match('-')) {
1804             expr = {
1805                 type: Syntax.BinaryExpression,
1806                 operator: lex().value,
1807                 left: expr,
1808                 right: parseMultiplicativeExpression()
1809             };
1810         }
1812         return expr;
1813     }
1815     // 11.7 Bitwise Shift Operators
1817     function parseShiftExpression() {
1818         var expr = parseAdditiveExpression();
1820         while (match('<<') || match('>>') || match('>>>')) {
1821             expr = {
1822                 type: Syntax.BinaryExpression,
1823                 operator: lex().value,
1824                 left: expr,
1825                 right: parseAdditiveExpression()
1826             };
1827         }
1829         return expr;
1830     }
1831     // 11.8 Relational Operators
1833     function parseRelationalExpression() {
1834         var expr, previousAllowIn;
1836         previousAllowIn = state.allowIn;
1837         state.allowIn = true;
1839         expr = parseShiftExpression();
1841         while (match('<') || match('>') || match('<=') || match('>=') || (previousAllowIn && matchKeyword('in')) || matchKeyword('instanceof')) {
1842             expr = {
1843                 type: Syntax.BinaryExpression,
1844                 operator: lex().value,
1845                 left: expr,
1846                 right: parseShiftExpression()
1847             };
1848         }
1850         state.allowIn = previousAllowIn;
1851         return expr;
1852     }
1854     // 11.9 Equality Operators
1856     function parseEqualityExpression() {
1857         var expr = parseRelationalExpression();
1859         while (match('==') || match('!=') || match('===') || match('!==')) {
1860             expr = {
1861                 type: Syntax.BinaryExpression,
1862                 operator: lex().value,
1863                 left: expr,
1864                 right: parseRelationalExpression()
1865             };
1866         }
1868         return expr;
1869     }
1871     // 11.10 Binary Bitwise Operators
1873     function parseBitwiseANDExpression() {
1874         var expr = parseEqualityExpression();
1876         while (match('&')) {
1877             lex();
1878             expr = {
1879                 type: Syntax.BinaryExpression,
1880                 operator: '&',
1881                 left: expr,
1882                 right: parseEqualityExpression()
1883             };
1884         }
1886         return expr;
1887     }
1889     function parseBitwiseXORExpression() {
1890         var expr = parseBitwiseANDExpression();
1892         while (match('^')) {
1893             lex();
1894             expr = {
1895                 type: Syntax.BinaryExpression,
1896                 operator: '^',
1897                 left: expr,
1898                 right: parseBitwiseANDExpression()
1899             };
1900         }
1902         return expr;
1903     }
1905     function parseBitwiseORExpression() {
1906         var expr = parseBitwiseXORExpression();
1908         while (match('|')) {
1909             lex();
1910             expr = {
1911                 type: Syntax.BinaryExpression,
1912                 operator: '|',
1913                 left: expr,
1914                 right: parseBitwiseXORExpression()
1915             };
1916         }
1918         return expr;
1919     }
1921     // 11.11 Binary Logical Operators
1923     function parseLogicalANDExpression() {
1924         var expr = parseBitwiseORExpression();
1926         while (match('&&')) {
1927             lex();
1928             expr = {
1929                 type: Syntax.LogicalExpression,
1930                 operator: '&&',
1931                 left: expr,
1932                 right: parseBitwiseORExpression()
1933             };
1934         }
1936         return expr;
1937     }
1939     function parseLogicalORExpression() {
1940         var expr = parseLogicalANDExpression();
1942         while (match('||')) {
1943             lex();
1944             expr = {
1945                 type: Syntax.LogicalExpression,
1946                 operator: '||',
1947                 left: expr,
1948                 right: parseLogicalANDExpression()
1949             };
1950         }
1952         return expr;
1953     }
1955     // 11.12 Conditional Operator
1957     function parseConditionalExpression() {
1958         var expr, previousAllowIn, consequent;
1960         expr = parseLogicalORExpression();
1962         if (match('?')) {
1963             lex();
1964             previousAllowIn = state.allowIn;
1965             state.allowIn = true;
1966             consequent = parseAssignmentExpression();
1967             state.allowIn = previousAllowIn;
1968             expect(':');
1970             expr = {
1971                 type: Syntax.ConditionalExpression,
1972                 test: expr,
1973                 consequent: consequent,
1974                 alternate: parseAssignmentExpression()
1975             };
1976         }
1978         return expr;
1979     }
1981     // 11.13 Assignment Operators
1983     function parseAssignmentExpression() {
1984         var token, expr;
1986         token = lookahead();
1987         expr = parseConditionalExpression();
1989         if (matchAssign()) {
1990             // LeftHandSideExpression
1991             if (!isLeftHandSide(expr)) {
1992                 throwError({}, Messages.InvalidLHSInAssignment);
1993             }
1995             // 11.13.1
1996             if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) {
1997                 throwErrorTolerant(token, Messages.StrictLHSAssignment);
1998             }
2000             expr = {
2001                 type: Syntax.AssignmentExpression,
2002                 operator: lex().value,
2003                 left: expr,
2004                 right: parseAssignmentExpression()
2005             };
2006         }
2008         return expr;
2009     }
2011     // 11.14 Comma Operator
2013     function parseExpression() {
2014         var expr = parseAssignmentExpression();
2016         if (match(',')) {
2017             expr = {
2018                 type: Syntax.SequenceExpression,
2019                 expressions: [ expr ]
2020             };
2022             while (index < length) {
2023                 if (!match(',')) {
2024                     break;
2025                 }
2026                 lex();
2027                 expr.expressions.push(parseAssignmentExpression());
2028             }
2030         }
2031         return expr;
2032     }
2034     // 12.1 Block
2036     function parseStatementList() {
2037         var list = [],
2038             statement;
2040         while (index < length) {
2041             if (match('}')) {
2042                 break;
2043             }
2044             statement = parseSourceElement();
2045             if (typeof statement === 'undefined') {
2046                 break;
2047             }
2048             list.push(statement);
2049         }
2051         return list;
2052     }
2054     function parseBlock() {
2055         var block;
2057         expect('{');
2059         block = parseStatementList();
2061         expect('}');
2063         return {
2064             type: Syntax.BlockStatement,
2065             body: block
2066         };
2067     }
2069     // 12.2 Variable Statement
2071     function parseVariableIdentifier() {
2072         var token = lex();
2074         if (token.type !== Token.Identifier) {
2075             throwUnexpected(token);
2076         }
2078         return {
2079             type: Syntax.Identifier,
2080             name: token.value
2081         };
2082     }
2084     function parseVariableDeclaration(kind) {
2085         var id = parseVariableIdentifier(),
2086             init = null;
2088         // 12.2.1
2089         if (strict && isRestrictedWord(id.name)) {
2090             throwErrorTolerant({}, Messages.StrictVarName);
2091         }
2093         if (kind === 'const') {
2094             expect('=');
2095             init = parseAssignmentExpression();
2096         } else if (match('=')) {
2097             lex();
2098             init = parseAssignmentExpression();
2099         }
2101         return {
2102             type: Syntax.VariableDeclarator,
2103             id: id,
2104             init: init
2105         };
2106     }
2108     function parseVariableDeclarationList(kind) {
2109         var list = [];
2111         while (index < length) {
2112             list.push(parseVariableDeclaration(kind));
2113             if (!match(',')) {
2114                 break;
2115             }
2116             lex();
2117         }
2119         return list;
2120     }
2122     function parseVariableStatement() {
2123         var declarations;
2125         expectKeyword('var');
2127         declarations = parseVariableDeclarationList();
2129         consumeSemicolon();
2131         return {
2132             type: Syntax.VariableDeclaration,
2133             declarations: declarations,
2134             kind: 'var'
2135         };
2136     }
2138     // kind may be `const` or `let`
2139     // Both are experimental and not in the specification yet.
2140     // see http://wiki.ecmascript.org/doku.php?id=harmony:const
2141     // and http://wiki.ecmascript.org/doku.php?id=harmony:let
2142     function parseConstLetDeclaration(kind) {
2143         var declarations;
2145         expectKeyword(kind);
2147         declarations = parseVariableDeclarationList(kind);
2149         consumeSemicolon();
2151         return {
2152             type: Syntax.VariableDeclaration,
2153             declarations: declarations,
2154             kind: kind
2155         };
2156     }
2158     // 12.3 Empty Statement
2160     function parseEmptyStatement() {
2161         expect(';');
2163         return {
2164             type: Syntax.EmptyStatement
2165         };
2166     }
2168     // 12.4 Expression Statement
2170     function parseExpressionStatement() {
2171         var expr = parseExpression();
2173         consumeSemicolon();
2175         return {
2176             type: Syntax.ExpressionStatement,
2177             expression: expr
2178         };
2179     }
2181     // 12.5 If statement
2183     function parseIfStatement() {
2184         var test, consequent, alternate;
2186         expectKeyword('if');
2188         expect('(');
2190         test = parseExpression();
2192         expect(')');
2194         consequent = parseStatement();
2196         if (matchKeyword('else')) {
2197             lex();
2198             alternate = parseStatement();
2199         } else {
2200             alternate = null;
2201         }
2203         return {
2204             type: Syntax.IfStatement,
2205             test: test,
2206             consequent: consequent,
2207             alternate: alternate
2208         };
2209     }
2211     // 12.6 Iteration Statements
2213     function parseDoWhileStatement() {
2214         var body, test, oldInIteration;
2216         expectKeyword('do');
2218         oldInIteration = state.inIteration;
2219         state.inIteration = true;
2221         body = parseStatement();
2223         state.inIteration = oldInIteration;
2225         expectKeyword('while');
2227         expect('(');
2229         test = parseExpression();
2231         expect(')');
2233         if (match(';')) {
2234             lex();
2235         }
2237         return {
2238             type: Syntax.DoWhileStatement,
2239             body: body,
2240             test: test
2241         };
2242     }
2244     function parseWhileStatement() {
2245         var test, body, oldInIteration;
2247         expectKeyword('while');
2249         expect('(');
2251         test = parseExpression();
2253         expect(')');
2255         oldInIteration = state.inIteration;
2256         state.inIteration = true;
2258         body = parseStatement();
2260         state.inIteration = oldInIteration;
2262         return {
2263             type: Syntax.WhileStatement,
2264             test: test,
2265             body: body
2266         };
2267     }
2269     function parseForVariableDeclaration() {
2270         var token = lex();
2272         return {
2273             type: Syntax.VariableDeclaration,
2274             declarations: parseVariableDeclarationList(),
2275             kind: token.value
2276         };
2277     }
2279     function parseForStatement() {
2280         var init, test, update, left, right, body, oldInIteration;
2282         init = test = update = null;
2284         expectKeyword('for');
2286         expect('(');
2288         if (match(';')) {
2289             lex();
2290         } else {
2291             if (matchKeyword('var') || matchKeyword('let')) {
2292                 state.allowIn = false;
2293                 init = parseForVariableDeclaration();
2294                 state.allowIn = true;
2296                 if (init.declarations.length === 1 && matchKeyword('in')) {
2297                     lex();
2298                     left = init;
2299                     right = parseExpression();
2300                     init = null;
2301                 }
2302             } else {
2303                 state.allowIn = false;
2304                 init = parseExpression();
2305                 state.allowIn = true;
2307                 if (matchKeyword('in')) {
2308                     // LeftHandSideExpression
2309                     if (!isLeftHandSide(init)) {
2310                         throwError({}, Messages.InvalidLHSInForIn);
2311                     }
2313                     lex();
2314                     left = init;
2315                     right = parseExpression();
2316                     init = null;
2317                 }
2318             }
2320             if (typeof left === 'undefined') {
2321                 expect(';');
2322             }
2323         }
2325         if (typeof left === 'undefined') {
2327             if (!match(';')) {
2328                 test = parseExpression();
2329             }
2330             expect(';');
2332             if (!match(')')) {
2333                 update = parseExpression();
2334             }
2335         }
2337         expect(')');
2339         oldInIteration = state.inIteration;
2340         state.inIteration = true;
2342         body = parseStatement();
2344         state.inIteration = oldInIteration;
2346         if (typeof left === 'undefined') {
2347             return {
2348                 type: Syntax.ForStatement,
2349                 init: init,
2350                 test: test,
2351                 update: update,
2352                 body: body
2353             };
2354         }
2356         return {
2357             type: Syntax.ForInStatement,
2358             left: left,
2359             right: right,
2360             body: body,
2361             each: false
2362         };
2363     }
2365     // 12.7 The continue statement
2367     function parseContinueStatement() {
2368         var token, label = null;
2370         expectKeyword('continue');
2372         // Optimize the most common form: 'continue;'.
2373         if (source[index] === ';') {
2374             lex();
2376             if (!state.inIteration) {
2377                 throwError({}, Messages.IllegalContinue);
2378             }
2380             return {
2381                 type: Syntax.ContinueStatement,
2382                 label: null
2383             };
2384         }
2386         if (peekLineTerminator()) {
2387             if (!state.inIteration) {
2388                 throwError({}, Messages.IllegalContinue);
2389             }
2391             return {
2392                 type: Syntax.ContinueStatement,
2393                 label: null
2394             };
2395         }
2397         token = lookahead();
2398         if (token.type === Token.Identifier) {
2399             label = parseVariableIdentifier();
2401             if (!Object.prototype.hasOwnProperty.call(state.labelSet, label.name)) {
2402                 throwError({}, Messages.UnknownLabel, label.name);
2403             }
2404         }
2406         consumeSemicolon();
2408         if (label === null && !state.inIteration) {
2409             throwError({}, Messages.IllegalContinue);
2410         }
2412         return {
2413             type: Syntax.ContinueStatement,
2414             label: label
2415         };
2416     }
2418     // 12.8 The break statement
2420     function parseBreakStatement() {
2421         var token, label = null;
2423         expectKeyword('break');
2425         // Optimize the most common form: 'break;'.
2426         if (source[index] === ';') {
2427             lex();
2429             if (!(state.inIteration || state.inSwitch)) {
2430                 throwError({}, Messages.IllegalBreak);
2431             }
2433             return {
2434                 type: Syntax.BreakStatement,
2435                 label: null
2436             };
2437         }
2439         if (peekLineTerminator()) {
2440             if (!(state.inIteration || state.inSwitch)) {
2441                 throwError({}, Messages.IllegalBreak);
2442             }
2444             return {
2445                 type: Syntax.BreakStatement,
2446                 label: null
2447             };
2448         }
2450         token = lookahead();
2451         if (token.type === Token.Identifier) {
2452             label = parseVariableIdentifier();
2454             if (!Object.prototype.hasOwnProperty.call(state.labelSet, label.name)) {
2455                 throwError({}, Messages.UnknownLabel, label.name);
2456             }
2457         }
2459         consumeSemicolon();
2461         if (label === null && !(state.inIteration || state.inSwitch)) {
2462             throwError({}, Messages.IllegalBreak);
2463         }
2465         return {
2466             type: Syntax.BreakStatement,
2467             label: label
2468         };
2469     }
2471     // 12.9 The return statement
2473     function parseReturnStatement() {
2474         var token, argument = null;
2476         expectKeyword('return');
2478         if (!state.inFunctionBody) {
2479             throwErrorTolerant({}, Messages.IllegalReturn);
2480         }
2482         // 'return' followed by a space and an identifier is very common.
2483         if (source[index] === ' ') {
2484             if (isIdentifierStart(source[index + 1])) {
2485                 argument = parseExpression();
2486                 consumeSemicolon();
2487                 return {
2488                     type: Syntax.ReturnStatement,
2489                     argument: argument
2490                 };
2491             }
2492         }
2494         if (peekLineTerminator()) {
2495             return {
2496                 type: Syntax.ReturnStatement,
2497                 argument: null
2498             };
2499         }
2501         if (!match(';')) {
2502             token = lookahead();
2503             if (!match('}') && token.type !== Token.EOF) {
2504                 argument = parseExpression();
2505             }
2506         }
2508         consumeSemicolon();
2510         return {
2511             type: Syntax.ReturnStatement,
2512             argument: argument
2513         };
2514     }
2516     // 12.10 The with statement
2518     function parseWithStatement() {
2519         var object, body;
2521         if (strict) {
2522             throwErrorTolerant({}, Messages.StrictModeWith);
2523         }
2525         expectKeyword('with');
2527         expect('(');
2529         object = parseExpression();
2531         expect(')');
2533         body = parseStatement();
2535         return {
2536             type: Syntax.WithStatement,
2537             object: object,
2538             body: body
2539         };
2540     }
2542     // 12.10 The swith statement
2544     function parseSwitchCase() {
2545         var test,
2546             consequent = [],
2547             statement;
2549         if (matchKeyword('default')) {
2550             lex();
2551             test = null;
2552         } else {
2553             expectKeyword('case');
2554             test = parseExpression();
2555         }
2556         expect(':');
2558         while (index < length) {
2559             if (match('}') || matchKeyword('default') || matchKeyword('case')) {
2560                 break;
2561             }
2562             statement = parseStatement();
2563             if (typeof statement === 'undefined') {
2564                 break;
2565             }
2566             consequent.push(statement);
2567         }
2569         return {
2570             type: Syntax.SwitchCase,
2571             test: test,
2572             consequent: consequent
2573         };
2574     }
2576     function parseSwitchStatement() {
2577         var discriminant, cases, clause, oldInSwitch, defaultFound;
2579         expectKeyword('switch');
2581         expect('(');
2583         discriminant = parseExpression();
2585         expect(')');
2587         expect('{');
2589         if (match('}')) {
2590             lex();
2591             return {
2592                 type: Syntax.SwitchStatement,
2593                 discriminant: discriminant
2594             };
2595         }
2597         cases = [];
2599         oldInSwitch = state.inSwitch;
2600         state.inSwitch = true;
2601         defaultFound = false;
2603         while (index < length) {
2604             if (match('}')) {
2605                 break;
2606             }
2607             clause = parseSwitchCase();
2608             if (clause.test === null) {
2609                 if (defaultFound) {
2610                     throwError({}, Messages.MultipleDefaultsInSwitch);
2611                 }
2612                 defaultFound = true;
2613             }
2614             cases.push(clause);
2615         }
2617         state.inSwitch = oldInSwitch;
2619         expect('}');
2621         return {
2622             type: Syntax.SwitchStatement,
2623             discriminant: discriminant,
2624             cases: cases
2625         };
2626     }
2628     // 12.13 The throw statement
2630     function parseThrowStatement() {
2631         var argument;
2633         expectKeyword('throw');
2635         if (peekLineTerminator()) {
2636             throwError({}, Messages.NewlineAfterThrow);
2637         }
2639         argument = parseExpression();
2641         consumeSemicolon();
2643         return {
2644             type: Syntax.ThrowStatement,
2645             argument: argument
2646         };
2647     }
2649     // 12.14 The try statement
2651     function parseCatchClause() {
2652         var param;
2654         expectKeyword('catch');
2656         expect('(');
2657         if (!match(')')) {
2658             param = parseExpression();
2659             // 12.14.1
2660             if (strict && param.type === Syntax.Identifier && isRestrictedWord(param.name)) {
2661                 throwErrorTolerant({}, Messages.StrictCatchVariable);
2662             }
2663         }
2664         expect(')');
2666         return {
2667             type: Syntax.CatchClause,
2668             param: param,
2669             body: parseBlock()
2670         };
2671     }
2673     function parseTryStatement() {
2674         var block, handlers = [], finalizer = null;
2676         expectKeyword('try');
2678         block = parseBlock();
2680         if (matchKeyword('catch')) {
2681             handlers.push(parseCatchClause());
2682         }
2684         if (matchKeyword('finally')) {
2685             lex();
2686             finalizer = parseBlock();
2687         }
2689         if (handlers.length === 0 && !finalizer) {
2690             throwError({}, Messages.NoCatchOrFinally);
2691         }
2693         return {
2694             type: Syntax.TryStatement,
2695             block: block,
2696             guardedHandlers: [],
2697             handlers: handlers,
2698             finalizer: finalizer
2699         };
2700     }
2702     // 12.15 The debugger statement
2704     function parseDebuggerStatement() {
2705         expectKeyword('debugger');
2707         consumeSemicolon();
2709         return {
2710             type: Syntax.DebuggerStatement
2711         };
2712     }
2714     // 12 Statements
2716     function parseStatement() {
2717         var token = lookahead(),
2718             expr,
2719             labeledBody;
2721         if (token.type === Token.EOF) {
2722             throwUnexpected(token);
2723         }
2725         if (token.type === Token.Punctuator) {
2726             switch (token.value) {
2727             case ';':
2728                 return parseEmptyStatement();
2729             case '{':
2730                 return parseBlock();
2731             case '(':
2732                 return parseExpressionStatement();
2733             default:
2734                 break;
2735             }
2736         }
2738         if (token.type === Token.Keyword) {
2739             switch (token.value) {
2740             case 'break':
2741                 return parseBreakStatement();
2742             case 'continue':
2743                 return parseContinueStatement();
2744             case 'debugger':
2745                 return parseDebuggerStatement();
2746             case 'do':
2747                 return parseDoWhileStatement();
2748             case 'for':
2749                 return parseForStatement();
2750             case 'function':
2751                 return parseFunctionDeclaration();
2752             case 'if':
2753                 return parseIfStatement();
2754             case 'return':
2755                 return parseReturnStatement();
2756             case 'switch':
2757                 return parseSwitchStatement();
2758             case 'throw':
2759                 return parseThrowStatement();
2760             case 'try':
2761                 return parseTryStatement();
2762             case 'var':
2763                 return parseVariableStatement();
2764             case 'while':
2765                 return parseWhileStatement();
2766             case 'with':
2767                 return parseWithStatement();
2768             default:
2769                 break;
2770             }
2771         }
2773         expr = parseExpression();
2775         // 12.12 Labelled Statements
2776         if ((expr.type === Syntax.Identifier) && match(':')) {
2777             lex();
2779             if (Object.prototype.hasOwnProperty.call(state.labelSet, expr.name)) {
2780                 throwError({}, Messages.Redeclaration, 'Label', expr.name);
2781             }
2783             state.labelSet[expr.name] = true;
2784             labeledBody = parseStatement();
2785             delete state.labelSet[expr.name];
2787             return {
2788                 type: Syntax.LabeledStatement,
2789                 label: expr,
2790                 body: labeledBody
2791             };
2792         }
2794         consumeSemicolon();
2796         return {
2797             type: Syntax.ExpressionStatement,
2798             expression: expr
2799         };
2800     }
2802     // 13 Function Definition
2804     function parseFunctionSourceElements() {
2805         var sourceElement, sourceElements = [], token, directive, firstRestricted,
2806             oldLabelSet, oldInIteration, oldInSwitch, oldInFunctionBody;
2808         expect('{');
2810         while (index < length) {
2811             token = lookahead();
2812             if (token.type !== Token.StringLiteral) {
2813                 break;
2814             }
2816             sourceElement = parseSourceElement();
2817             sourceElements.push(sourceElement);
2818             if (sourceElement.expression.type !== Syntax.Literal) {
2819                 // this is not directive
2820                 break;
2821             }
2822             directive = sliceSource(token.range[0] + 1, token.range[1] - 1);
2823             if (directive === 'use strict') {
2824                 strict = true;
2825                 if (firstRestricted) {
2826                     throwErrorTolerant(firstRestricted, Messages.StrictOctalLiteral);
2827                 }
2828             } else {
2829                 if (!firstRestricted && token.octal) {
2830                     firstRestricted = token;
2831                 }
2832             }
2833         }
2835         oldLabelSet = state.labelSet;
2836         oldInIteration = state.inIteration;
2837         oldInSwitch = state.inSwitch;
2838         oldInFunctionBody = state.inFunctionBody;
2840         state.labelSet = {};
2841         state.inIteration = false;
2842         state.inSwitch = false;
2843         state.inFunctionBody = true;
2845         while (index < length) {
2846             if (match('}')) {
2847                 break;
2848             }
2849             sourceElement = parseSourceElement();
2850             if (typeof sourceElement === 'undefined') {
2851                 break;
2852             }
2853             sourceElements.push(sourceElement);
2854         }
2856         expect('}');
2858         state.labelSet = oldLabelSet;
2859         state.inIteration = oldInIteration;
2860         state.inSwitch = oldInSwitch;
2861         state.inFunctionBody = oldInFunctionBody;
2863         return {
2864             type: Syntax.BlockStatement,
2865             body: sourceElements
2866         };
2867     }
2869     function parseFunctionDeclaration() {
2870         var id, param, params = [], body, token, stricted, firstRestricted, message, previousStrict, paramSet;
2872         expectKeyword('function');
2873         token = lookahead();
2874         id = parseVariableIdentifier();
2875         if (strict) {
2876             if (isRestrictedWord(token.value)) {
2877                 throwErrorTolerant(token, Messages.StrictFunctionName);
2878             }
2879         } else {
2880             if (isRestrictedWord(token.value)) {
2881                 firstRestricted = token;
2882                 message = Messages.StrictFunctionName;
2883             } else if (isStrictModeReservedWord(token.value)) {
2884                 firstRestricted = token;
2885                 message = Messages.StrictReservedWord;
2886             }
2887         }
2889         expect('(');
2891         if (!match(')')) {
2892             paramSet = {};
2893             while (index < length) {
2894                 token = lookahead();
2895                 param = parseVariableIdentifier();
2896                 if (strict) {
2897                     if (isRestrictedWord(token.value)) {
2898                         stricted = token;
2899                         message = Messages.StrictParamName;
2900                     }
2901                     if (Object.prototype.hasOwnProperty.call(paramSet, token.value)) {
2902                         stricted = token;
2903                         message = Messages.StrictParamDupe;
2904                     }
2905                 } else if (!firstRestricted) {
2906                     if (isRestrictedWord(token.value)) {
2907                         firstRestricted = token;
2908                         message = Messages.StrictParamName;
2909                     } else if (isStrictModeReservedWord(token.value)) {
2910                         firstRestricted = token;
2911                         message = Messages.StrictReservedWord;
2912                     } else if (Object.prototype.hasOwnProperty.call(paramSet, token.value)) {
2913                         firstRestricted = token;
2914                         message = Messages.StrictParamDupe;
2915                     }
2916                 }
2917                 params.push(param);
2918                 paramSet[param.name] = true;
2919                 if (match(')')) {
2920                     break;
2921                 }
2922                 expect(',');
2923             }
2924         }
2926         expect(')');
2928         previousStrict = strict;
2929         body = parseFunctionSourceElements();
2930         if (strict && firstRestricted) {
2931             throwError(firstRestricted, message);
2932         }
2933         if (strict && stricted) {
2934             throwErrorTolerant(stricted, message);
2935         }
2936         strict = previousStrict;
2938         return {
2939             type: Syntax.FunctionDeclaration,
2940             id: id,
2941             params: params,
2942             defaults: [],
2943             body: body,
2944             rest: null,
2945             generator: false,
2946             expression: false
2947         };
2948     }
2950     function parseFunctionExpression() {
2951         var token, id = null, stricted, firstRestricted, message, param, params = [], body, previousStrict, paramSet;
2953         expectKeyword('function');
2955         if (!match('(')) {
2956             token = lookahead();
2957             id = parseVariableIdentifier();
2958             if (strict) {
2959                 if (isRestrictedWord(token.value)) {
2960                     throwErrorTolerant(token, Messages.StrictFunctionName);
2961                 }
2962             } else {
2963                 if (isRestrictedWord(token.value)) {
2964                     firstRestricted = token;
2965                     message = Messages.StrictFunctionName;
2966                 } else if (isStrictModeReservedWord(token.value)) {
2967                     firstRestricted = token;
2968                     message = Messages.StrictReservedWord;
2969                 }
2970             }
2971         }
2973         expect('(');
2975         if (!match(')')) {
2976             paramSet = {};
2977             while (index < length) {
2978                 token = lookahead();
2979                 param = parseVariableIdentifier();
2980                 if (strict) {
2981                     if (isRestrictedWord(token.value)) {
2982                         stricted = token;
2983                         message = Messages.StrictParamName;
2984                     }
2985                     if (Object.prototype.hasOwnProperty.call(paramSet, token.value)) {
2986                         stricted = token;
2987                         message = Messages.StrictParamDupe;
2988                     }
2989                 } else if (!firstRestricted) {
2990                     if (isRestrictedWord(token.value)) {
2991                         firstRestricted = token;
2992                         message = Messages.StrictParamName;
2993                     } else if (isStrictModeReservedWord(token.value)) {
2994                         firstRestricted = token;
2995                         message = Messages.StrictReservedWord;
2996                     } else if (Object.prototype.hasOwnProperty.call(paramSet, token.value)) {
2997                         firstRestricted = token;
2998                         message = Messages.StrictParamDupe;
2999                     }
3000                 }
3001                 params.push(param);
3002                 paramSet[param.name] = true;
3003                 if (match(')')) {
3004                     break;
3005                 }
3006                 expect(',');
3007             }
3008         }
3010         expect(')');
3012         previousStrict = strict;
3013         body = parseFunctionSourceElements();
3014         if (strict && firstRestricted) {
3015             throwError(firstRestricted, message);
3016         }
3017         if (strict && stricted) {
3018             throwErrorTolerant(stricted, message);
3019         }
3020         strict = previousStrict;
3022         return {
3023             type: Syntax.FunctionExpression,
3024             id: id,
3025             params: params,
3026             defaults: [],
3027             body: body,
3028             rest: null,
3029             generator: false,
3030             expression: false
3031         };
3032     }
3034     // 14 Program
3036     function parseSourceElement() {
3037         var token = lookahead();
3039         if (token.type === Token.Keyword) {
3040             switch (token.value) {
3041             case 'const':
3042             case 'let':
3043                 return parseConstLetDeclaration(token.value);
3044             case 'function':
3045                 return parseFunctionDeclaration();
3046             default:
3047                 return parseStatement();
3048             }
3049         }
3051         if (token.type !== Token.EOF) {
3052             return parseStatement();
3053         }
3054     }
3056     function parseSourceElements() {
3057         var sourceElement, sourceElements = [], token, directive, firstRestricted;
3059         while (index < length) {
3060             token = lookahead();
3061             if (token.type !== Token.StringLiteral) {
3062                 break;
3063             }
3065             sourceElement = parseSourceElement();
3066             sourceElements.push(sourceElement);
3067             if (sourceElement.expression.type !== Syntax.Literal) {
3068                 // this is not directive
3069                 break;
3070             }
3071             directive = sliceSource(token.range[0] + 1, token.range[1] - 1);
3072             if (directive === 'use strict') {
3073                 strict = true;
3074                 if (firstRestricted) {
3075                     throwErrorTolerant(firstRestricted, Messages.StrictOctalLiteral);
3076                 }
3077             } else {
3078                 if (!firstRestricted && token.octal) {
3079                     firstRestricted = token;
3080                 }
3081             }
3082         }
3084         while (index < length) {
3085             sourceElement = parseSourceElement();
3086             if (typeof sourceElement === 'undefined') {
3087                 break;
3088             }
3089             sourceElements.push(sourceElement);
3090         }
3091         return sourceElements;
3092     }
3094     function parseProgram() {
3095         var program;
3096         strict = false;
3097         program = {
3098             type: Syntax.Program,
3099             body: parseSourceElements()
3100         };
3101         return program;
3102     }
3104     // The following functions are needed only when the option to preserve
3105     // the comments is active.
3107     function addComment(type, value, start, end, loc) {
3108         assert(typeof start === 'number', 'Comment must have valid position');
3110         // Because the way the actual token is scanned, often the comments
3111         // (if any) are skipped twice during the lexical analysis.
3112         // Thus, we need to skip adding a comment if the comment array already
3113         // handled it.
3114         if (extra.comments.length > 0) {
3115             if (extra.comments[extra.comments.length - 1].range[1] > start) {
3116                 return;
3117             }
3118         }
3120         extra.comments.push({
3121             type: type,
3122             value: value,
3123             range: [start, end],
3124             loc: loc
3125         });
3126     }
3128     function scanComment() {
3129         var comment, ch, loc, start, blockComment, lineComment;
3131         comment = '';
3132         blockComment = false;
3133         lineComment = false;
3135         while (index < length) {
3136             ch = source[index];
3138             if (lineComment) {
3139                 ch = source[index++];
3140                 if (isLineTerminator(ch)) {
3141                     loc.end = {
3142                         line: lineNumber,
3143                         column: index - lineStart - 1
3144                     };
3145                     lineComment = false;
3146                     addComment('Line', comment, start, index - 1, loc);
3147                     if (ch === '\r' && source[index] === '\n') {
3148                         ++index;
3149                     }
3150                     ++lineNumber;
3151                     lineStart = index;
3152                     comment = '';
3153                 } else if (index >= length) {
3154                     lineComment = false;
3155                     comment += ch;
3156                     loc.end = {
3157                         line: lineNumber,
3158                         column: length - lineStart
3159                     };
3160                     addComment('Line', comment, start, length, loc);
3161                 } else {
3162                     comment += ch;
3163                 }
3164             } else if (blockComment) {
3165                 if (isLineTerminator(ch)) {
3166                     if (ch === '\r' && source[index + 1] === '\n') {
3167                         ++index;
3168                         comment += '\r\n';
3169                     } else {
3170                         comment += ch;
3171                     }
3172                     ++lineNumber;
3173                     ++index;
3174                     lineStart = index;
3175                     if (index >= length) {
3176                         throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
3177                     }
3178                 } else {
3179                     ch = source[index++];
3180                     if (index >= length) {
3181                         throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
3182                     }
3183                     comment += ch;
3184                     if (ch === '*') {
3185                         ch = source[index];
3186                         if (ch === '/') {
3187                             comment = comment.substr(0, comment.length - 1);
3188                             blockComment = false;
3189                             ++index;
3190                             loc.end = {
3191                                 line: lineNumber,
3192                                 column: index - lineStart
3193                             };
3194                             addComment('Block', comment, start, index, loc);
3195                             comment = '';
3196                         }
3197                     }
3198                 }
3199             } else if (ch === '/') {
3200                 ch = source[index + 1];
3201                 if (ch === '/') {
3202                     loc = {
3203                         start: {
3204                             line: lineNumber,
3205                             column: index - lineStart
3206                         }
3207                     };
3208                     start = index;
3209                     index += 2;
3210                     lineComment = true;
3211                     if (index >= length) {
3212                         loc.end = {
3213                             line: lineNumber,
3214                             column: index - lineStart
3215                         };
3216                         lineComment = false;
3217                         addComment('Line', comment, start, index, loc);
3218                     }
3219                 } else if (ch === '*') {
3220                     start = index;
3221                     index += 2;
3222                     blockComment = true;
3223                     loc = {
3224                         start: {
3225                             line: lineNumber,
3226                             column: index - lineStart - 2
3227                         }
3228                     };
3229                     if (index >= length) {
3230                         throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
3231                     }
3232                 } else {
3233                     break;
3234                 }
3235             } else if (isWhiteSpace(ch)) {
3236                 ++index;
3237             } else if (isLineTerminator(ch)) {
3238                 ++index;
3239                 if (ch ===  '\r' && source[index] === '\n') {
3240                     ++index;
3241                 }
3242                 ++lineNumber;
3243                 lineStart = index;
3244             } else {
3245                 break;
3246             }
3247         }
3248     }
3250     function filterCommentLocation() {
3251         var i, entry, comment, comments = [];
3253         for (i = 0; i < extra.comments.length; ++i) {
3254             entry = extra.comments[i];
3255             comment = {
3256                 type: entry.type,
3257                 value: entry.value
3258             };
3259             if (extra.range) {
3260                 comment.range = entry.range;
3261             }
3262             if (extra.loc) {
3263                 comment.loc = entry.loc;
3264             }
3265             comments.push(comment);
3266         }
3268         extra.comments = comments;
3269     }
3271     function collectToken() {
3272         var start, loc, token, range, value;
3274         skipComment();
3275         start = index;
3276         loc = {
3277             start: {
3278                 line: lineNumber,
3279                 column: index - lineStart
3280             }
3281         };
3283         token = extra.advance();
3284         loc.end = {
3285             line: lineNumber,
3286             column: index - lineStart
3287         };
3289         if (token.type !== Token.EOF) {
3290             range = [token.range[0], token.range[1]];
3291             value = sliceSource(token.range[0], token.range[1]);
3292             extra.tokens.push({
3293                 type: TokenName[token.type],
3294                 value: value,
3295                 range: range,
3296                 loc: loc
3297             });
3298         }
3300         return token;
3301     }
3303     function collectRegex() {
3304         var pos, loc, regex, token;
3306         skipComment();
3308         pos = index;
3309         loc = {
3310             start: {
3311                 line: lineNumber,
3312                 column: index - lineStart
3313             }
3314         };
3316         regex = extra.scanRegExp();
3317         loc.end = {
3318             line: lineNumber,
3319             column: index - lineStart
3320         };
3322         // Pop the previous token, which is likely '/' or '/='
3323         if (extra.tokens.length > 0) {
3324             token = extra.tokens[extra.tokens.length - 1];
3325             if (token.range[0] === pos && token.type === 'Punctuator') {
3326                 if (token.value === '/' || token.value === '/=') {
3327                     extra.tokens.pop();
3328                 }
3329             }
3330         }
3332         extra.tokens.push({
3333             type: 'RegularExpression',
3334             value: regex.literal,
3335             range: [pos, index],
3336             loc: loc
3337         });
3339         return regex;
3340     }
3342     function filterTokenLocation() {
3343         var i, entry, token, tokens = [];
3345         for (i = 0; i < extra.tokens.length; ++i) {
3346             entry = extra.tokens[i];
3347             token = {
3348                 type: entry.type,
3349                 value: entry.value
3350             };
3351             if (extra.range) {
3352                 token.range = entry.range;
3353             }
3354             if (extra.loc) {
3355                 token.loc = entry.loc;
3356             }
3357             tokens.push(token);
3358         }
3360         extra.tokens = tokens;
3361     }
3363     function createLiteral(token) {
3364         return {
3365             type: Syntax.Literal,
3366             value: token.value
3367         };
3368     }
3370     function createRawLiteral(token) {
3371         return {
3372             type: Syntax.Literal,
3373             value: token.value,
3374             raw: sliceSource(token.range[0], token.range[1])
3375         };
3376     }
3378     function createLocationMarker() {
3379         var marker = {};
3381         marker.range = [index, index];
3382         marker.loc = {
3383             start: {
3384                 line: lineNumber,
3385                 column: index - lineStart
3386             },
3387             end: {
3388                 line: lineNumber,
3389                 column: index - lineStart
3390             }
3391         };
3393         marker.end = function () {
3394             this.range[1] = index;
3395             this.loc.end.line = lineNumber;
3396             this.loc.end.column = index - lineStart;
3397         };
3399         marker.applyGroup = function (node) {
3400             if (extra.range) {
3401                 node.groupRange = [this.range[0], this.range[1]];
3402             }
3403             if (extra.loc) {
3404                 node.groupLoc = {
3405                     start: {
3406                         line: this.loc.start.line,
3407                         column: this.loc.start.column
3408                     },
3409                     end: {
3410                         line: this.loc.end.line,
3411                         column: this.loc.end.column
3412                     }
3413                 };
3414             }
3415         };
3417         marker.apply = function (node) {
3418             if (extra.range) {
3419                 node.range = [this.range[0], this.range[1]];
3420             }
3421             if (extra.loc) {
3422                 node.loc = {
3423                     start: {
3424                         line: this.loc.start.line,
3425                         column: this.loc.start.column
3426                     },
3427                     end: {
3428                         line: this.loc.end.line,
3429                         column: this.loc.end.column
3430                     }
3431                 };
3432             }
3433         };
3435         return marker;
3436     }
3438     function trackGroupExpression() {
3439         var marker, expr;
3441         skipComment();
3442         marker = createLocationMarker();
3443         expect('(');
3445         expr = parseExpression();
3447         expect(')');
3449         marker.end();
3450         marker.applyGroup(expr);
3452         return expr;
3453     }
3455     function trackLeftHandSideExpression() {
3456         var marker, expr;
3458         skipComment();
3459         marker = createLocationMarker();
3461         expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression();
3463         while (match('.') || match('[')) {
3464             if (match('[')) {
3465                 expr = {
3466                     type: Syntax.MemberExpression,
3467                     computed: true,
3468                     object: expr,
3469                     property: parseComputedMember()
3470                 };
3471                 marker.end();
3472                 marker.apply(expr);
3473             } else {
3474                 expr = {
3475                     type: Syntax.MemberExpression,
3476                     computed: false,
3477                     object: expr,
3478                     property: parseNonComputedMember()
3479                 };
3480                 marker.end();
3481                 marker.apply(expr);
3482             }
3483         }
3485         return expr;
3486     }
3488     function trackLeftHandSideExpressionAllowCall() {
3489         var marker, expr;
3491         skipComment();
3492         marker = createLocationMarker();
3494         expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression();
3496         while (match('.') || match('[') || match('(')) {
3497             if (match('(')) {
3498                 expr = {
3499                     type: Syntax.CallExpression,
3500                     callee: expr,
3501                     'arguments': parseArguments()
3502                 };
3503                 marker.end();
3504                 marker.apply(expr);
3505             } else if (match('[')) {
3506                 expr = {
3507                     type: Syntax.MemberExpression,
3508                     computed: true,
3509                     object: expr,
3510                     property: parseComputedMember()
3511                 };
3512                 marker.end();
3513                 marker.apply(expr);
3514             } else {
3515                 expr = {
3516                     type: Syntax.MemberExpression,
3517                     computed: false,
3518                     object: expr,
3519                     property: parseNonComputedMember()
3520                 };
3521                 marker.end();
3522                 marker.apply(expr);
3523             }
3524         }
3526         return expr;
3527     }
3529     function filterGroup(node) {
3530         var n, i, entry;
3532         n = (Object.prototype.toString.apply(node) === '[object Array]') ? [] : {};
3533         for (i in node) {
3534             if (node.hasOwnProperty(i) && i !== 'groupRange' && i !== 'groupLoc') {
3535                 entry = node[i];
3536                 if (entry === null || typeof entry !== 'object' || entry instanceof RegExp) {
3537                     n[i] = entry;
3538                 } else {
3539                     n[i] = filterGroup(entry);
3540                 }
3541             }
3542         }
3543         return n;
3544     }
3546     function wrapTrackingFunction(range, loc) {
3548         return function (parseFunction) {
3550             function isBinary(node) {
3551                 return node.type === Syntax.LogicalExpression ||
3552                     node.type === Syntax.BinaryExpression;
3553             }
3555             function visit(node) {
3556                 var start, end;
3558                 if (isBinary(node.left)) {
3559                     visit(node.left);
3560                 }
3561                 if (isBinary(node.right)) {
3562                     visit(node.right);
3563                 }
3565                 if (range) {
3566                     if (node.left.groupRange || node.right.groupRange) {
3567                         start = node.left.groupRange ? node.left.groupRange[0] : node.left.range[0];
3568                         end = node.right.groupRange ? node.right.groupRange[1] : node.right.range[1];
3569                         node.range = [start, end];
3570                     } else if (typeof node.range === 'undefined') {
3571                         start = node.left.range[0];
3572                         end = node.right.range[1];
3573                         node.range = [start, end];
3574                     }
3575                 }
3576                 if (loc) {
3577                     if (node.left.groupLoc || node.right.groupLoc) {
3578                         start = node.left.groupLoc ? node.left.groupLoc.start : node.left.loc.start;
3579                         end = node.right.groupLoc ? node.right.groupLoc.end : node.right.loc.end;
3580                         node.loc = {
3581                             start: start,
3582                             end: end
3583                         };
3584                     } else if (typeof node.loc === 'undefined') {
3585                         node.loc = {
3586                             start: node.left.loc.start,
3587                             end: node.right.loc.end
3588                         };
3589                     }
3590                 }
3591             }
3593             return function () {
3594                 var marker, node;
3596                 skipComment();
3598                 marker = createLocationMarker();
3599                 node = parseFunction.apply(null, arguments);
3600                 marker.end();
3602                 if (range && typeof node.range === 'undefined') {
3603                     marker.apply(node);
3604                 }
3606                 if (loc && typeof node.loc === 'undefined') {
3607                     marker.apply(node);
3608                 }
3610                 if (isBinary(node)) {
3611                     visit(node);
3612                 }
3614                 return node;
3615             };
3616         };
3617     }
3619     function patch() {
3621         var wrapTracking;
3623         if (extra.comments) {
3624             extra.skipComment = skipComment;
3625             skipComment = scanComment;
3626         }
3628         if (extra.raw) {
3629             extra.createLiteral = createLiteral;
3630             createLiteral = createRawLiteral;
3631         }
3633         if (extra.range || extra.loc) {
3635             extra.parseGroupExpression = parseGroupExpression;
3636             extra.parseLeftHandSideExpression = parseLeftHandSideExpression;
3637             extra.parseLeftHandSideExpressionAllowCall = parseLeftHandSideExpressionAllowCall;
3638             parseGroupExpression = trackGroupExpression;
3639             parseLeftHandSideExpression = trackLeftHandSideExpression;
3640             parseLeftHandSideExpressionAllowCall = trackLeftHandSideExpressionAllowCall;
3642             wrapTracking = wrapTrackingFunction(extra.range, extra.loc);
3644             extra.parseAdditiveExpression = parseAdditiveExpression;
3645             extra.parseAssignmentExpression = parseAssignmentExpression;
3646             extra.parseBitwiseANDExpression = parseBitwiseANDExpression;
3647             extra.parseBitwiseORExpression = parseBitwiseORExpression;
3648             extra.parseBitwiseXORExpression = parseBitwiseXORExpression;
3649             extra.parseBlock = parseBlock;
3650             extra.parseFunctionSourceElements = parseFunctionSourceElements;
3651             extra.parseCatchClause = parseCatchClause;
3652             extra.parseComputedMember = parseComputedMember;
3653             extra.parseConditionalExpression = parseConditionalExpression;
3654             extra.parseConstLetDeclaration = parseConstLetDeclaration;
3655             extra.parseEqualityExpression = parseEqualityExpression;
3656             extra.parseExpression = parseExpression;
3657             extra.parseForVariableDeclaration = parseForVariableDeclaration;
3658             extra.parseFunctionDeclaration = parseFunctionDeclaration;
3659             extra.parseFunctionExpression = parseFunctionExpression;
3660             extra.parseLogicalANDExpression = parseLogicalANDExpression;
3661             extra.parseLogicalORExpression = parseLogicalORExpression;
3662             extra.parseMultiplicativeExpression = parseMultiplicativeExpression;
3663             extra.parseNewExpression = parseNewExpression;
3664             extra.parseNonComputedProperty = parseNonComputedProperty;
3665             extra.parseObjectProperty = parseObjectProperty;
3666             extra.parseObjectPropertyKey = parseObjectPropertyKey;
3667             extra.parsePostfixExpression = parsePostfixExpression;
3668             extra.parsePrimaryExpression = parsePrimaryExpression;
3669             extra.parseProgram = parseProgram;
3670             extra.parsePropertyFunction = parsePropertyFunction;
3671             extra.parseRelationalExpression = parseRelationalExpression;
3672             extra.parseStatement = parseStatement;
3673             extra.parseShiftExpression = parseShiftExpression;
3674             extra.parseSwitchCase = parseSwitchCase;
3675             extra.parseUnaryExpression = parseUnaryExpression;
3676             extra.parseVariableDeclaration = parseVariableDeclaration;
3677             extra.parseVariableIdentifier = parseVariableIdentifier;
3679             parseAdditiveExpression = wrapTracking(extra.parseAdditiveExpression);
3680             parseAssignmentExpression = wrapTracking(extra.parseAssignmentExpression);
3681             parseBitwiseANDExpression = wrapTracking(extra.parseBitwiseANDExpression);
3682             parseBitwiseORExpression = wrapTracking(extra.parseBitwiseORExpression);
3683             parseBitwiseXORExpression = wrapTracking(extra.parseBitwiseXORExpression);
3684             parseBlock = wrapTracking(extra.parseBlock);
3685             parseFunctionSourceElements = wrapTracking(extra.parseFunctionSourceElements);
3686             parseCatchClause = wrapTracking(extra.parseCatchClause);
3687             parseComputedMember = wrapTracking(extra.parseComputedMember);
3688             parseConditionalExpression = wrapTracking(extra.parseConditionalExpression);
3689             parseConstLetDeclaration = wrapTracking(extra.parseConstLetDeclaration);
3690             parseEqualityExpression = wrapTracking(extra.parseEqualityExpression);
3691             parseExpression = wrapTracking(extra.parseExpression);
3692             parseForVariableDeclaration = wrapTracking(extra.parseForVariableDeclaration);
3693             parseFunctionDeclaration = wrapTracking(extra.parseFunctionDeclaration);
3694             parseFunctionExpression = wrapTracking(extra.parseFunctionExpression);
3695             parseLeftHandSideExpression = wrapTracking(parseLeftHandSideExpression);
3696             parseLogicalANDExpression = wrapTracking(extra.parseLogicalANDExpression);
3697             parseLogicalORExpression = wrapTracking(extra.parseLogicalORExpression);
3698             parseMultiplicativeExpression = wrapTracking(extra.parseMultiplicativeExpression);
3699             parseNewExpression = wrapTracking(extra.parseNewExpression);
3700             parseNonComputedProperty = wrapTracking(extra.parseNonComputedProperty);
3701             parseObjectProperty = wrapTracking(extra.parseObjectProperty);
3702             parseObjectPropertyKey = wrapTracking(extra.parseObjectPropertyKey);
3703             parsePostfixExpression = wrapTracking(extra.parsePostfixExpression);
3704             parsePrimaryExpression = wrapTracking(extra.parsePrimaryExpression);
3705             parseProgram = wrapTracking(extra.parseProgram);
3706             parsePropertyFunction = wrapTracking(extra.parsePropertyFunction);
3707             parseRelationalExpression = wrapTracking(extra.parseRelationalExpression);
3708             parseStatement = wrapTracking(extra.parseStatement);
3709             parseShiftExpression = wrapTracking(extra.parseShiftExpression);
3710             parseSwitchCase = wrapTracking(extra.parseSwitchCase);
3711             parseUnaryExpression = wrapTracking(extra.parseUnaryExpression);
3712             parseVariableDeclaration = wrapTracking(extra.parseVariableDeclaration);
3713             parseVariableIdentifier = wrapTracking(extra.parseVariableIdentifier);
3714         }
3716         if (typeof extra.tokens !== 'undefined') {
3717             extra.advance = advance;
3718             extra.scanRegExp = scanRegExp;
3720             advance = collectToken;
3721             scanRegExp = collectRegex;
3722         }
3723     }
3725     function unpatch() {
3726         if (typeof extra.skipComment === 'function') {
3727             skipComment = extra.skipComment;
3728         }
3730         if (extra.raw) {
3731             createLiteral = extra.createLiteral;
3732         }
3734         if (extra.range || extra.loc) {
3735             parseAdditiveExpression = extra.parseAdditiveExpression;
3736             parseAssignmentExpression = extra.parseAssignmentExpression;
3737             parseBitwiseANDExpression = extra.parseBitwiseANDExpression;
3738             parseBitwiseORExpression = extra.parseBitwiseORExpression;
3739             parseBitwiseXORExpression = extra.parseBitwiseXORExpression;
3740             parseBlock = extra.parseBlock;
3741             parseFunctionSourceElements = extra.parseFunctionSourceElements;
3742             parseCatchClause = extra.parseCatchClause;
3743             parseComputedMember = extra.parseComputedMember;
3744             parseConditionalExpression = extra.parseConditionalExpression;
3745             parseConstLetDeclaration = extra.parseConstLetDeclaration;
3746             parseEqualityExpression = extra.parseEqualityExpression;
3747             parseExpression = extra.parseExpression;
3748             parseForVariableDeclaration = extra.parseForVariableDeclaration;
3749             parseFunctionDeclaration = extra.parseFunctionDeclaration;
3750             parseFunctionExpression = extra.parseFunctionExpression;
3751             parseGroupExpression = extra.parseGroupExpression;
3752             parseLeftHandSideExpression = extra.parseLeftHandSideExpression;
3753             parseLeftHandSideExpressionAllowCall = extra.parseLeftHandSideExpressionAllowCall;
3754             parseLogicalANDExpression = extra.parseLogicalANDExpression;
3755             parseLogicalORExpression = extra.parseLogicalORExpression;
3756             parseMultiplicativeExpression = extra.parseMultiplicativeExpression;
3757             parseNewExpression = extra.parseNewExpression;
3758             parseNonComputedProperty = extra.parseNonComputedProperty;
3759             parseObjectProperty = extra.parseObjectProperty;
3760             parseObjectPropertyKey = extra.parseObjectPropertyKey;
3761             parsePrimaryExpression = extra.parsePrimaryExpression;
3762             parsePostfixExpression = extra.parsePostfixExpression;
3763             parseProgram = extra.parseProgram;
3764             parsePropertyFunction = extra.parsePropertyFunction;
3765             parseRelationalExpression = extra.parseRelationalExpression;
3766             parseStatement = extra.parseStatement;
3767             parseShiftExpression = extra.parseShiftExpression;
3768             parseSwitchCase = extra.parseSwitchCase;
3769             parseUnaryExpression = extra.parseUnaryExpression;
3770             parseVariableDeclaration = extra.parseVariableDeclaration;
3771             parseVariableIdentifier = extra.parseVariableIdentifier;
3772         }
3774         if (typeof extra.scanRegExp === 'function') {
3775             advance = extra.advance;
3776             scanRegExp = extra.scanRegExp;
3777         }
3778     }
3780     function stringToArray(str) {
3781         var length = str.length,
3782             result = [],
3783             i;
3784         for (i = 0; i < length; ++i) {
3785             result[i] = str.charAt(i);
3786         }
3787         return result;
3788     }
3790     function parse(code, options) {
3791         var program, toString;
3793         toString = String;
3794         if (typeof code !== 'string' && !(code instanceof String)) {
3795             code = toString(code);
3796         }
3798         source = code;
3799         index = 0;
3800         lineNumber = (source.length > 0) ? 1 : 0;
3801         lineStart = 0;
3802         length = source.length;
3803         buffer = null;
3804         state = {
3805             allowIn: true,
3806             labelSet: {},
3807             inFunctionBody: false,
3808             inIteration: false,
3809             inSwitch: false
3810         };
3812         extra = {};
3813         if (typeof options !== 'undefined') {
3814             extra.range = (typeof options.range === 'boolean') && options.range;
3815             extra.loc = (typeof options.loc === 'boolean') && options.loc;
3816             extra.raw = (typeof options.raw === 'boolean') && options.raw;
3817             if (typeof options.tokens === 'boolean' && options.tokens) {
3818                 extra.tokens = [];
3819             }
3820             if (typeof options.comment === 'boolean' && options.comment) {
3821                 extra.comments = [];
3822             }
3823             if (typeof options.tolerant === 'boolean' && options.tolerant) {
3824                 extra.errors = [];
3825             }
3826         }
3828         if (length > 0) {
3829             if (typeof source[0] === 'undefined') {
3830                 // Try first to convert to a string. This is good as fast path
3831                 // for old IE which understands string indexing for string
3832                 // literals only and not for string object.
3833                 if (code instanceof String) {
3834                     source = code.valueOf();
3835                 }
3837                 // Force accessing the characters via an array.
3838                 if (typeof source[0] === 'undefined') {
3839                     source = stringToArray(code);
3840                 }
3841             }
3842         }
3844         patch();
3845         try {
3846             program = parseProgram();
3847             if (typeof extra.comments !== 'undefined') {
3848                 filterCommentLocation();
3849                 program.comments = extra.comments;
3850             }
3851             if (typeof extra.tokens !== 'undefined') {
3852                 filterTokenLocation();
3853                 program.tokens = extra.tokens;
3854             }
3855             if (typeof extra.errors !== 'undefined') {
3856                 program.errors = extra.errors;
3857             }
3858             if (extra.range || extra.loc) {
3859                 program.body = filterGroup(program.body);
3860             }
3861         } catch (e) {
3862             throw e;
3863         } finally {
3864             unpatch();
3865             extra = {};
3866         }
3868         return program;
3869     }
3871     // Sync with package.json.
3872     exports.version = '1.0.2';
3874     exports.parse = parse;
3876     // Deep copy.
3877     exports.Syntax = (function () {
3878         var name, types = {};
3880         if (typeof Object.create === 'function') {
3881             types = Object.create(null);
3882         }
3884         for (name in Syntax) {
3885             if (Syntax.hasOwnProperty(name)) {
3886                 types[name] = Syntax[name];
3887             }
3888         }
3890         if (typeof Object.freeze === 'function') {
3891             Object.freeze(types);
3892         }
3894         return types;
3895     }());
3897 }));
3898 /* vim: set sw=4 ts=4 et tw=80 : */
3900 })(null);
3902 (function(require,module){
3904 var parse = require('esprima').parse;
3905 var objectKeys = Object.keys || function (obj) {
3906     var keys = [];
3907     for (var key in obj) keys.push(key);
3908     return keys;
3910 var forEach = function (xs, fn) {
3911     if (xs.forEach) return xs.forEach(fn);
3912     for (var i = 0; i < xs.length; i++) {
3913         fn.call(xs, xs[i], i, xs);
3914     }
3917 var isArray = Array.isArray || function (xs) {
3918     return Object.prototype.toString.call(xs) === '[object Array]';
3921 module.exports = function (src, opts, fn) {
3922     if (typeof opts === 'function') {
3923         fn = opts;
3924         opts = {};
3925     }
3926     if (typeof src === 'object') {
3927         opts = src;
3928         src = opts.source;
3929         delete opts.source;
3930     }
3931     src = src === undefined ? opts.source : src;
3932     opts.range = true;
3933     if (typeof src !== 'string') src = String(src);
3935     var ast = parse(src, opts);
3937     var result = {
3938         chunks : src.split(''),
3939         toString : function () { return result.chunks.join('') },
3940         inspect : function () { return result.toString() }
3941     };
3942     var index = 0;
3944     (function walk (node, parent) {
3945         insertHelpers(node, parent, result.chunks);
3947         forEach(objectKeys(node), function (key) {
3948             if (key === 'parent') return;
3950             var child = node[key];
3951             if (isArray(child)) {
3952                 forEach(child, function (c) {
3953                     if (c && typeof c.type === 'string') {
3954                         walk(c, node);
3955                     }
3956                 });
3957             }
3958             else if (child && typeof child.type === 'string') {
3959                 insertHelpers(child, node, result.chunks);
3960                 walk(child, node);
3961             }
3962         });
3963         fn(node);
3964     })(ast, undefined);
3966     return result;
3969 function insertHelpers (node, parent, chunks) {
3970     if (!node.range) return;
3972     node.parent = parent;
3974     node.source = function () {
3975         return chunks.slice(
3976             node.range[0], node.range[1]
3977         ).join('');
3978     };
3980     if (node.update && typeof node.update === 'object') {
3981         var prev = node.update;
3982         forEach(objectKeys(prev), function (key) {
3983             update[key] = prev[key];
3984         });
3985         node.update = update;
3986     }
3987     else {
3988         node.update = update;
3989     }
3991     function update (s) {
3992         chunks[node.range[0]] = s;
3993         for (var i = node.range[0] + 1; i < node.range[1]; i++) {
3994             chunks[i] = '';
3995         }
3996     };
3999 window.falafel = module.exports;})(function(){return {parse: esprima.parse};},{exports: {}});
4001 var inBrowser = typeof window !== 'undefined' && this === window;
4002 var parseAndModify = (inBrowser ? window.falafel : require("falafel"));
4004 (inBrowser ? window : exports).blanket = (function(){
4005     var linesToAddTracking = [
4006         "ExpressionStatement",
4007         "BreakStatement"   ,
4008         "ContinueStatement" ,
4009         "VariableDeclaration",
4010         "ReturnStatement"   ,
4011         "ThrowStatement"   ,
4012         "TryStatement"     ,
4013         "FunctionDeclaration"    ,
4014         "IfStatement"       ,
4015         "WhileStatement"    ,
4016         "DoWhileStatement"   ,
4017         "ForStatement"   ,
4018         "ForInStatement"  ,
4019         "SwitchStatement"  ,
4020         "WithStatement"
4021     ],
4022     linesToAddBrackets = [
4023         "IfStatement"       ,
4024         "WhileStatement"    ,
4025         "DoWhileStatement"     ,
4026         "ForStatement"   ,
4027         "ForInStatement"  ,
4028         "WithStatement"
4029     ],
4030     __blanket,
4031     copynumber = Math.floor(Math.random()*1000),
4032     coverageInfo = {},options = {
4033         reporter: null,
4034         adapter:null,
4035         filter: null,
4036         customVariable: null,
4037         loader: null,
4038         ignoreScriptError: false,
4039         existingRequireJS:false,
4040         autoStart: false,
4041         timeout: 180,
4042         ignoreCors: false,
4043         branchTracking: false,
4044         sourceURL: false,
4045         debug:false,
4046         engineOnly:false,
4047         testReadyCallback:null,
4048         commonJS:false,
4049         instrumentCache:false,
4050         modulePattern: null
4051     };
4053     if (inBrowser && typeof window.blanket !== 'undefined'){
4054         __blanket = window.blanket.noConflict();
4055     }
4057     _blanket = {
4058         noConflict: function(){
4059             if (__blanket){
4060                 return __blanket;
4061             }
4062             return _blanket;
4063         },
4064         _getCopyNumber: function(){
4065             //internal method
4066             //for differentiating between instances
4067             return copynumber;
4068         },
4069         extend: function(obj) {
4070             //borrowed from underscore
4071             _blanket._extend(_blanket,obj);
4072         },
4073         _extend: function(dest,source){
4074           if (source) {
4075             for (var prop in source) {
4076               if ( dest[prop] instanceof Object && typeof dest[prop] !== "function"){
4077                 _blanket._extend(dest[prop],source[prop]);
4078               }else{
4079                   dest[prop] = source[prop];
4080               }
4081             }
4082           }
4083         },
4084         getCovVar: function(){
4085             var opt = _blanket.options("customVariable");
4086             if (opt){
4087                 if (_blanket.options("debug")) {console.log("BLANKET-Using custom tracking variable:",opt);}
4088                 return inBrowser ? "window."+opt : opt;
4089             }
4090             return inBrowser ?   "window._$blanket" : "_$jscoverage";
4091         },
4092         options: function(key,value){
4093             if (typeof key !== "string"){
4094                 _blanket._extend(options,key);
4095             }else if (typeof value === 'undefined'){
4096                 return options[key];
4097             }else{
4098                 options[key]=value;
4099             }
4100         },
4101         instrument: function(config, next){
4102             //check instrumented hash table,
4103             //return instrumented code if available.
4104             var inFile = config.inputFile,
4105                 inFileName = config.inputFileName;
4106             //check instrument cache
4107            if (_blanket.options("instrumentCache") && sessionStorage && sessionStorage.getItem("blanket_instrument_store-"+inFileName)){
4108                 if (_blanket.options("debug")) {console.log("BLANKET-Reading instrumentation from cache: ",inFileName);}
4109                 next(sessionStorage.getItem("blanket_instrument_store-"+inFileName));
4110             }else{
4111                 var sourceArray = _blanket._prepareSource(inFile);
4112                 _blanket._trackingArraySetup=[];
4113                 var instrumented =  parseAndModify(inFile,{loc:true,comment:true}, _blanket._addTracking(inFileName));
4114                 instrumented = _blanket._trackingSetup(inFileName,sourceArray)+instrumented;
4115                 if (_blanket.options("sourceURL")){
4116                     instrumented += "\n//@ sourceURL="+inFileName.replace("http://","");
4117                 }
4118                 if (_blanket.options("debug")) {console.log("BLANKET-Instrumented file: ",inFileName);}
4119                 if (_blanket.options("instrumentCache") && sessionStorage){
4120                     if (_blanket.options("debug")) {console.log("BLANKET-Saving instrumentation to cache: ",inFileName);}
4121                     sessionStorage.setItem("blanket_instrument_store-"+inFileName,instrumented);
4122                 }
4123                 next(instrumented);
4124             }
4125         },
4126         _trackingArraySetup: [],
4127         _branchingArraySetup: [],
4128         _prepareSource: function(source){
4129             return source.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(/(\r\n|\n|\r)/gm,"\n").split('\n');
4130         },
4131         _trackingSetup: function(filename,sourceArray){
4132             var branches = _blanket.options("branchTracking");
4133             var sourceString = sourceArray.join("',\n'");
4134             var intro = "";
4135             var covVar = _blanket.getCovVar();
4137             intro += "if (typeof "+covVar+" === 'undefined') "+covVar+" = {};\n";
4138             if (branches){
4139                 intro += "var _$branchFcn=function(f,l,c,r){ ";
4140                 intro += "if (!!r) { ";
4141                 intro += covVar+"[f].branchData[l][c][0] = "+covVar+"[f].branchData[l][c][0] || [];";
4142                 intro += covVar+"[f].branchData[l][c][0].push(r); }";
4143                 intro += "else { ";
4144                 intro += covVar+"[f].branchData[l][c][1] = "+covVar+"[f].branchData[l][c][1] || [];";
4145                 intro += covVar+"[f].branchData[l][c][1].push(r); }";
4146                 intro += "return r;};\n";
4147             }
4148             intro += "if (typeof "+covVar+"['"+filename+"'] === 'undefined'){";
4150             intro += covVar+"['"+filename+"']=[];\n";
4151             if (branches){
4152                 intro += covVar+"['"+filename+"'].branchData=[];\n";
4153             }
4154             intro += covVar+"['"+filename+"'].source=['"+sourceString+"'];\n";
4155             //initialize array values
4156             _blanket._trackingArraySetup.sort(function(a,b){
4157                 return parseInt(a,10) > parseInt(b,10);
4158             }).forEach(function(item){
4159                 intro += covVar+"['"+filename+"']["+item+"]=0;\n";
4160             });
4161             if (branches){
4162                 _blanket._branchingArraySetup.sort(function(a,b){
4163                     return a.line > b.line;
4164                 }).sort(function(a,b){
4165                     return a.column > b.column;
4166                 }).forEach(function(item){
4167                     if (item.file === filename){
4168                         intro += "if (typeof "+ covVar+"['"+filename+"'].branchData["+item.line+"] === 'undefined'){\n";
4169                         intro += covVar+"['"+filename+"'].branchData["+item.line+"]=[];\n";
4170                         intro += "}";
4171                         intro += covVar+"['"+filename+"'].branchData["+item.line+"]["+item.column+"] = [];\n";
4172                         intro += covVar+"['"+filename+"'].branchData["+item.line+"]["+item.column+"].consequent = "+JSON.stringify(item.consequent)+";\n";
4173                         intro += covVar+"['"+filename+"'].branchData["+item.line+"]["+item.column+"].alternate = "+JSON.stringify(item.alternate)+";\n";
4174                     }
4175                 });
4176             }
4177             intro += "}";
4179             return intro;
4180         },
4181         _blockifyIf: function(node){
4182             if (linesToAddBrackets.indexOf(node.type) > -1){
4183                 var bracketsExistObject = node.consequent || node.body;
4184                 var bracketsExistAlt = node.alternate;
4185                 if( bracketsExistAlt && bracketsExistAlt.type !== "BlockStatement") {
4186                     bracketsExistAlt.update("{\n"+bracketsExistAlt.source()+"}\n");
4187                 }
4188                 if( bracketsExistObject && bracketsExistObject.type !== "BlockStatement") {
4189                     bracketsExistObject.update("{\n"+bracketsExistObject.source()+"}\n");
4190                 }
4191             }
4192         },
4193         _trackBranch: function(node,filename){
4194             //recursive on consequent and alternative
4195             var line = node.loc.start.line;
4196             var col = node.loc.start.column;
4198             _blanket._branchingArraySetup.push({
4199                 line: line,
4200                 column: col,
4201                 file:filename,
4202                 consequent: node.consequent.loc,
4203                 alternate: node.alternate.loc
4204             });
4206             var source = node.source();
4207             var updated = "_$branchFcn"+
4208                           "('"+filename+"',"+line+","+col+","+source.slice(0,source.indexOf("?"))+
4209                           ")"+source.slice(source.indexOf("?"));
4210             node.update(updated);
4211         },
4212         _addTracking: function (filename) {
4213             //falafel doesn't take a file name
4214             //so we include the filename in a closure
4215             //and return the function to falafel
4216             var covVar = _blanket.getCovVar();
4218             return function(node){
4219                 _blanket._blockifyIf(node);
4221                 if (linesToAddTracking.indexOf(node.type) > -1 && node.parent.type !== "LabeledStatement") {
4222                     _blanket._checkDefs(node,filename);
4223                     if (node.type === "VariableDeclaration" &&
4224                         (node.parent.type === "ForStatement" || node.parent.type === "ForInStatement")){
4225                         return;
4226                     }
4227                     if (node.loc && node.loc.start){
4228                         node.update(covVar+"['"+filename+"']["+node.loc.start.line+"]++;\n"+node.source());
4229                         _blanket._trackingArraySetup.push(node.loc.start.line);
4230                     }else{
4231                         //I don't think we can handle a node with no location
4232                         throw new Error("The instrumenter encountered a node with no location: "+Object.keys(node));
4233                     }
4234                 }else if (_blanket.options("branchTracking") && node.type === "ConditionalExpression"){
4235                     _blanket._trackBranch(node,filename);
4236                 }
4237             };
4238         },
4239         _checkDefs: function(node,filename){
4240             // Make sure developers don't redefine window. if they do, inform them it is wrong.
4241             if (inBrowser){
4242                 if (node.type === "VariableDeclaration" && node.declarations) {
4243                     node.declarations.forEach(function(declaration) {
4244                         if (declaration.id.name === "window") {
4245                             throw new Error("Instrumentation error, you cannot redefine the 'window' variable in  " + filename + ":" + node.loc.start.line);
4246                         }
4247                     });
4248                 }
4249                 if (node.type === "FunctionDeclaration" && node.params) {
4250                     node.params.forEach(function(param) {
4251                         if (param.name === "window") {
4252                             throw new Error("Instrumentation error, you cannot redefine the 'window' variable in  " + filename + ":" + node.loc.start.line);
4253                         }
4254                     });
4255                 }
4256                 //Make sure developers don't redefine the coverage variable
4257                 if (node.type === "ExpressionStatement" &&
4258                     node.expression && node.expression.left &&
4259                     node.expression.left.object && node.expression.left.property &&
4260                     node.expression.left.object.name +
4261                         "." + node.expression.left.property.name === _blanket.getCovVar()) {
4262                     throw new Error("Instrumentation error, you cannot redefine the coverage variable in  " + filename + ":" + node.loc.start.line);
4263                 }
4264             }else{
4265                 //Make sure developers don't redefine the coverage variable in node
4266                 if (node.type === "ExpressionStatement" &&
4267                     node.expression && node.expression.left &&
4268                     !node.expression.left.object && !node.expression.left.property &&
4269                     node.expression.left.name === _blanket.getCovVar()) {
4270                     throw new Error("Instrumentation error, you cannot redefine the coverage variable in  " + filename + ":" + node.loc.start.line);
4271                 }
4272             }
4273         },
4274         setupCoverage: function(){
4275             coverageInfo.instrumentation = "blanket";
4276             coverageInfo.stats = {
4277                 "suites": 0,
4278                 "tests": 0,
4279                 "passes": 0,
4280                 "pending": 0,
4281                 "failures": 0,
4282                 "start": new Date()
4283             };
4284         },
4285         _checkIfSetup: function(){
4286             if (!coverageInfo.stats){
4287                 throw new Error("You must call blanket.setupCoverage() first.");
4288             }
4289         },
4290         onTestStart: function(){
4291             if (_blanket.options("debug")) {console.log("BLANKET-Test event started");}
4292             this._checkIfSetup();
4293             coverageInfo.stats.tests++;
4294             coverageInfo.stats.pending++;
4295         },
4296         onTestDone: function(total,passed){
4297             this._checkIfSetup();
4298             if(passed === total){
4299                 coverageInfo.stats.passes++;
4300             }else{
4301                 coverageInfo.stats.failures++;
4302             }
4303             coverageInfo.stats.pending--;
4304         },
4305         onModuleStart: function(){
4306             this._checkIfSetup();
4307             coverageInfo.stats.suites++;
4308         },
4309         onTestsDone: function(){
4310             if (_blanket.options("debug")) {console.log("BLANKET-Test event done");}
4311             this._checkIfSetup();
4312             coverageInfo.stats.end = new Date();
4314             if (inBrowser){
4315                 this.report(coverageInfo);
4316             }else{
4317                 if (!_blanket.options("branchTracking")){
4318                     delete (inBrowser ? window : global)[_blanket.getCovVar()].branchFcn;
4319                 }
4320                 this.options("reporter").call(this,coverageInfo);
4321             }
4322         }
4323     };
4324     return _blanket;
4325 })();
4327 (function(_blanket){
4328     var oldOptions = _blanket.options;
4329 _blanket.extend({
4330     outstandingRequireFiles:[],
4331     options: function(key,value){
4332         var newVal={};
4334         if (typeof key !== "string"){
4335             //key is key/value map
4336             oldOptions(key);
4337             newVal = key;
4338         }else if (typeof value === 'undefined'){
4339             //accessor
4340             return oldOptions(key);
4341         }else{
4342             //setter
4343             oldOptions(key,value);
4344             newVal[key] = value;
4345         }
4347         if (newVal.adapter){
4348             _blanket._loadFile(newVal.adapter);
4349         }
4350         if (newVal.loader){
4351             _blanket._loadFile(newVal.loader);
4352         }
4353     },
4354     requiringFile: function(filename,done){
4355         if (typeof filename === "undefined"){
4356             _blanket.outstandingRequireFiles=[];
4357         }else if (typeof done === "undefined"){
4358             _blanket.outstandingRequireFiles.push(filename);
4359         }else{
4360             _blanket.outstandingRequireFiles.splice(_blanket.outstandingRequireFiles.indexOf(filename),1);
4361         }
4362     },
4363     requireFilesLoaded: function(){
4364         return _blanket.outstandingRequireFiles.length === 0;
4365     },
4366     showManualLoader: function(){
4367         if (document.getElementById("blanketLoaderDialog")){
4368             return;
4369         }
4370         //copied from http://blog.avtex.com/2012/01/26/cross-browser-css-only-modal-box/
4371         var loader = "<div class='blanketDialogOverlay'>";
4372             loader += "&nbsp;</div>";
4373             loader += "<div class='blanketDialogVerticalOffset'>";
4374             loader += "<div class='blanketDialogBox'>";
4375             loader += "<b>Error:</b> Blanket.js encountered a cross origin request error while instrumenting the source files.  ";
4376             loader += "<br><br>This is likely caused by the source files being referenced locally (using the file:// protocol). ";
4377             loader += "<br><br>Some solutions include <a href='http://askubuntu.com/questions/160245/making-google-chrome-option-allow-file-access-from-files-permanent' target='_blank'>starting Chrome with special flags</a>, <a target='_blank' href='https://github.com/remy/servedir'>running a server locally</a>, or using a browser without these CORS restrictions (Safari).";
4378             loader += "<br>";
4379             if (typeof FileReader !== "undefined"){
4380                 loader += "<br>Or, try the experimental loader.  When prompted, simply click on the directory containing all the source files you want covered.";
4381                 loader += "<a href='javascript:document.getElementById(\"fileInput\").click();'>Start Loader</a>";
4382                 loader += "<input type='file' type='application/x-javascript' accept='application/x-javascript' webkitdirectory id='fileInput' multiple onchange='window.blanket.manualFileLoader(this.files)' style='visibility:hidden;position:absolute;top:-50;left:-50'/>";
4383             }
4384             loader += "<br><span style='float:right;cursor:pointer;'  onclick=document.getElementById('blanketLoaderDialog').style.display='none';>Close</span>";
4385             loader += "<div style='clear:both'></div>";
4386             loader += "</div></div>";
4388         var css = ".blanketDialogWrapper {";
4389             css += "display:block;";
4390             css += "position:fixed;";
4391             css += "z-index:40001; }";
4393             css += ".blanketDialogOverlay {";
4394             css += "position:fixed;";
4395             css += "width:100%;";
4396             css += "height:100%;";
4397             css += "background-color:black;";
4398             css += "opacity:.5; ";
4399             css += "-ms-filter:'progid:DXImageTransform.Microsoft.Alpha(Opacity=50)'; ";
4400             css += "filter:alpha(opacity=50); ";
4401             css += "z-index:40001; }";
4403             css += ".blanketDialogVerticalOffset { ";
4404             css += "position:fixed;";
4405             css += "top:30%;";
4406             css += "width:100%;";
4407             css += "z-index:40002; }";
4409             css += ".blanketDialogBox { ";
4410             css += "width:405px; ";
4411             css += "position:relative;";
4412             css += "margin:0 auto;";
4413             css += "background-color:white;";
4414             css += "padding:10px;";
4415             css += "border:1px solid black; }";
4417         var dom = document.createElement("style");
4418         dom.innerHTML = css;
4419         document.head.appendChild(dom);
4421         var div = document.createElement("div");
4422         div.id = "blanketLoaderDialog";
4423         div.className = "blanketDialogWrapper";
4424         div.innerHTML = loader;
4425         document.body.insertBefore(div,document.body.firstChild);
4427     },
4428     manualFileLoader: function(files){
4429         var toArray =Array.prototype.slice;
4430         files = toArray.call(files).filter(function(item){
4431             return item.type !== "";
4432         });
4433         var sessionLength = files.length-1;
4434         var sessionIndx=0;
4435         var sessionArray = {};
4436         if (sessionStorage["blanketSessionLoader"]){
4437             sessionArray = JSON.parse(sessionStorage["blanketSessionLoader"]);
4438         }
4441         var fileLoader = function(event){
4442             var fileContent = event.currentTarget.result;
4443             var file = files[sessionIndx];
4444             var filename = file.webkitRelativePath && file.webkitRelativePath !== '' ? file.webkitRelativePath : file.name;
4445             sessionArray[filename] = fileContent;
4446             sessionIndx++;
4447             if (sessionIndx === sessionLength){
4448                 sessionStorage.setItem("blanketSessionLoader", JSON.stringify(sessionArray));
4449                 document.location.reload();
4450             }else{
4451                 readFile(files[sessionIndx]);
4452             }
4453         };
4454         function readFile(file){
4455             var reader = new FileReader();
4456             reader.onload = fileLoader;
4457             reader.readAsText(file);
4458         }
4459         readFile(files[sessionIndx]);
4460     },
4461     _loadFile: function(path){
4462         if (typeof path !== "undefined"){
4463             var request = new XMLHttpRequest();
4464             request.open('GET', path, false);
4465             request.send();
4466             _blanket._addScript(request.responseText);
4467         }
4468     },
4469     _addScript: function(data){
4470         var script = document.createElement("script");
4471         script.type = "text/javascript";
4472         script.text = data;
4473         (document.body || document.getElementsByTagName('head')[0]).appendChild(script);
4474     },
4475     hasAdapter: function(callback){
4476         return _blanket.options("adapter") !== null;
4477     },
4478     report: function(coverage_data){
4479         if (!document.getElementById("blanketLoaderDialog")){
4480             //all found, clear it
4481             _blanket.blanketSession = null;
4482         }
4483         coverage_data.files = window._$blanket;
4484         var require = blanket.options("commonJS") ? blanket._commonjs.require : window.require;
4486         // Check if we have any covered files that requires reporting
4487         // otherwise just exit gracefully.
4488         if (!coverage_data.files || !Object.keys(coverage_data.files).length) {
4489             if (_blanket.options("debug")) {console.log("BLANKET-Reporting No files were instrumented.");}
4490             return;
4491         }
4493         if (typeof coverage_data.files.branchFcn !== "undefined"){
4494             delete coverage_data.files.branchFcn;
4495         }
4496         if (typeof _blanket.options("reporter") === "string"){
4497             _blanket._loadFile(_blanket.options("reporter"));
4498             _blanket.customReporter(coverage_data,_blanket.options("reporter_options"));
4499         }else if (typeof _blanket.options("reporter") === "function"){
4500             _blanket.options("reporter")(coverage_data);
4501         }else if (typeof _blanket.defaultReporter === 'function'){
4502             _blanket.defaultReporter(coverage_data);
4503         }else{
4504             throw new Error("no reporter defined.");
4505         }
4506     },
4507     _bindStartTestRunner: function(bindEvent,startEvent){
4508         if (bindEvent){
4509             bindEvent(startEvent);
4510         }else{
4511             window.addEventListener("load",startEvent,false);
4512         }
4513     },
4514     _loadSourceFiles: function(callback){
4515         var require = blanket.options("commonJS") ? blanket._commonjs.require : window.require;
4516         function copy(o){
4517           var _copy = Object.create( Object.getPrototypeOf(o) );
4518           var propNames = Object.getOwnPropertyNames(o);
4520           propNames.forEach(function(name){
4521             var desc = Object.getOwnPropertyDescriptor(o, name);
4522             Object.defineProperty(_copy, name, desc);
4523           });
4525           return _copy;
4526         }
4527         if (_blanket.options("debug")) {console.log("BLANKET-Collecting page scripts");}
4528         var scripts = _blanket.utils.collectPageScripts();
4529         //_blanket.options("filter",scripts);
4530         if (scripts.length === 0){
4531             callback();
4532         }else{
4534             //check session state
4535             if (sessionStorage["blanketSessionLoader"]){
4536                 _blanket.blanketSession = JSON.parse(sessionStorage["blanketSessionLoader"]);
4537             }
4539             scripts.forEach(function(file,indx){
4540                 _blanket.utils.cache[file+".js"]={
4541                     loaded:false
4542                 };
4543             });
4545             var currScript=-1;
4546             _blanket.utils.loadAll(function(test){
4547                 if (test){
4548                   return typeof scripts[currScript+1] !== 'undefined';
4549                 }
4550                 currScript++;
4551                 if (currScript >= scripts.length){
4552                   return null;
4553                 }
4554                 return scripts[currScript]+".js";
4555             },callback);
4556         }
4557     },
4558     beforeStartTestRunner: function(opts){
4559         opts = opts || {};
4560         opts.checkRequirejs = typeof opts.checkRequirejs === "undefined" ? true : opts.checkRequirejs;
4561         opts.callback = opts.callback || function() {  };
4562         opts.coverage = typeof opts.coverage === "undefined" ? true : opts.coverage;
4563         if (opts.coverage) {
4564             _blanket._bindStartTestRunner(opts.bindEvent,
4565             function(){
4566                 _blanket._loadSourceFiles(function() {
4568                     var allLoaded = function(){
4569                         return opts.condition ? opts.condition() : _blanket.requireFilesLoaded();
4570                     };
4571                     var check = function() {
4572                         if (allLoaded()) {
4573                             if (_blanket.options("debug")) {console.log("BLANKET-All files loaded, init start test runner callback.");}
4574                             var cb = _blanket.options("testReadyCallback");
4576                             if (cb){
4577                                 if (typeof cb === "function"){
4578                                     cb(opts.callback);
4579                                 }else if (typeof cb === "string"){
4580                                     _blanket._addScript(cb);
4581                                     opts.callback();
4582                                 }
4583                             }else{
4584                                 opts.callback();
4585                             }
4586                         } else {
4587                             setTimeout(check, 13);
4588                         }
4589                     };
4590                     check();
4591                 });
4592             });
4593         }else{
4594             opts.callback();
4595         }
4596     },
4597     utils: {
4598         qualifyURL: function (url) {
4599             //http://stackoverflow.com/questions/470832/getting-an-absolute-url-from-a-relative-one-ie6-issue
4600             var a = document.createElement('a');
4601             a.href = url;
4602             return a.href;
4603         }
4604     }
4607 })(blanket);
4609 blanket.defaultReporter = function(coverage){
4610     var cssSytle = "#blanket-main {margin:2px;background:#EEE;color:#333;clear:both;font-family:'Helvetica Neue Light', 'HelveticaNeue-Light', 'Helvetica Neue', Calibri, Helvetica, Arial, sans-serif; font-size:17px;} #blanket-main a {color:#333;text-decoration:none;}  #blanket-main a:hover {text-decoration:underline;} .blanket {margin:0;padding:5px;clear:both;border-bottom: 1px solid #FFFFFF;} .bl-error {color:red;}.bl-success {color:#5E7D00;} .bl-file{width:auto;} .bl-cl{float:left;} .blanket div.rs {margin-left:50px; width:150px; float:right} .bl-nb {padding-right:10px;} #blanket-main a.bl-logo {color: #EB1764;cursor: pointer;font-weight: bold;text-decoration: none} .bl-source{ overflow-x:scroll; background-color: #FFFFFF; border: 1px solid #CBCBCB; color: #363636; margin: 25px 20px; width: 80%;} .bl-source div{white-space: pre;font-family: monospace;} .bl-source > div > span:first-child{background-color: #EAEAEA;color: #949494;display: inline-block;padding: 0 10px;text-align: center;width: 30px;} .bl-source .miss{background-color:#e6c3c7} .bl-source span.branchWarning{color:#000;background-color:yellow;} .bl-source span.branchOkay{color:#000;background-color:transparent;}",
4611         successRate = 60,
4612         head = document.head,
4613         fileNumber = 0,
4614         body = document.body,
4615         headerContent,
4616         hasBranchTracking = Object.keys(coverage.files).some(function(elem){
4617           return typeof coverage.files[elem].branchData !== 'undefined';
4618         }),
4619         bodyContent = "<div id='blanket-main'><div class='blanket bl-title'><div class='bl-cl bl-file'><a href='http://alex-seville.github.com/blanket/' target='_blank' class='bl-logo'>Blanket.js</a> results</div><div class='bl-cl rs'>Coverage (%)</div><div class='bl-cl rs'>Covered/Total Smts.</div>"+(hasBranchTracking ? "<div class='bl-cl rs'>Covered/Total Branches</div>":"")+"<div style='clear:both;'></div></div>",
4620         fileTemplate = "<div class='blanket {{statusclass}}'><div class='bl-cl bl-file'><span class='bl-nb'>{{fileNumber}}.</span><a href='javascript:blanket_toggleSource(\"file-{{fileNumber}}\")'>{{file}}</a></div><div class='bl-cl rs'>{{percentage}} %</div><div class='bl-cl rs'>{{numberCovered}}/{{totalSmts}}</div>"+( hasBranchTracking ? "<div class='bl-cl rs'>{{passedBranches}}/{{totalBranches}}</div>" : "" )+"<div id='file-{{fileNumber}}' class='bl-source' style='display:none;'>{{source}}</div><div style='clear:both;'></div></div>";
4621         grandTotalTemplate = "<div class='blanket grand-total {{statusclass}}'><div class='bl-cl'>{{rowTitle}}</div><div class='bl-cl rs'>{{percentage}} %</div><div class='bl-cl rs'>{{numberCovered}}/{{totalSmts}}</div>"+( hasBranchTracking ? "<div class='bl-cl rs'>{{passedBranches}}/{{totalBranches}}</div>" : "" ) + "<div style='clear:both;'></div></div>";
4623     function blanket_toggleSource(id) {
4624         var element = document.getElementById(id);
4625         if(element.style.display === 'block') {
4626             element.style.display = 'none';
4627         } else {
4628             element.style.display = 'block';
4629         }
4630     }
4633     var script = document.createElement("script");
4634     script.type = "text/javascript";
4635     script.text = blanket_toggleSource.toString().replace('function ' + blanket_toggleSource.name, 'function blanket_toggleSource');
4636     body.appendChild(script);
4638     var percentage = function(number, total) {
4639         return (Math.round(((number/total) * 100)*100)/100);
4640     };
4642     var appendTag = function (type, el, str) {
4643         var dom = document.createElement(type);
4644         dom.innerHTML = str;
4645         el.appendChild(dom);
4646     };
4648     function escapeInvalidXmlChars(str) {
4649         return str.replace(/\&/g, "&amp;")
4650             .replace(/</g, "&lt;")
4651             .replace(/\>/g, "&gt;")
4652             .replace(/\"/g, "&quot;")
4653             .replace(/\'/g, "&apos;");
4654     }
4656     function isBranchFollowed(data,bool){
4657         var mode = bool ? 0 : 1;
4658         if (typeof data === 'undefined' ||
4659             typeof data === null ||
4660             typeof data[mode] === 'undefined'){
4661             return false;
4662         }
4663         return data[mode].length > 0;
4664     }
4666     var branchStack = [];
4668     function branchReport(colsIndex,src,cols,offset,lineNum){
4669       var newsrc="";
4670        var postfix="";
4671       if (branchStack.length > 0){
4672         newsrc += "<span class='" + (isBranchFollowed(branchStack[0][1],branchStack[0][1].consequent === branchStack[0][0]) ? 'branchOkay' : 'branchWarning') + "'>";
4673         if (branchStack[0][0].end.line === lineNum){
4674           newsrc += escapeInvalidXmlChars(src.slice(0,branchStack[0][0].end.column)) + "</span>";
4675           src = src.slice(branchStack[0][0].end.column);
4676           branchStack.shift();
4677           if (branchStack.length > 0){
4678             newsrc += "<span class='" + (isBranchFollowed(branchStack[0][1],false) ? 'branchOkay' : 'branchWarning') + "'>";
4679             if (branchStack[0][0].end.line === lineNum){
4680               newsrc += escapeInvalidXmlChars(src.slice(0,branchStack[0][0].end.column)) + "</span>";
4681               src = src.slice(branchStack[0][0].end.column);
4682               branchStack.shift();
4683               if (!cols){
4684                 return {src: newsrc + escapeInvalidXmlChars(src) ,cols:cols};
4685               }
4686             }
4687             else if (!cols){
4688               return {src: newsrc + escapeInvalidXmlChars(src) + "</span>",cols:cols};
4689             }
4690             else{
4691               postfix = "</span>";
4692             }
4693           }else if (!cols){
4694             return {src: newsrc + escapeInvalidXmlChars(src) ,cols:cols};
4695           }
4696         }else if(!cols){
4697           return {src: newsrc + escapeInvalidXmlChars(src) + "</span>",cols:cols};
4698         }else{
4699           postfix = "</span>";
4700         }
4701       }
4702       var thisline = cols[colsIndex];
4703       //consequent
4705       var cons = thisline.consequent;
4706       if (cons.start.line > lineNum){
4707         branchStack.unshift([thisline.alternate,thisline]);
4708         branchStack.unshift([cons,thisline]);
4709         src = escapeInvalidXmlChars(src);
4710       }else{
4711         var style = "<span class='" + (isBranchFollowed(thisline,true) ? 'branchOkay' : 'branchWarning') + "'>";
4712         newsrc += escapeInvalidXmlChars(src.slice(0,cons.start.column-offset)) + style;
4714         if (cols.length > colsIndex+1 &&
4715           cols[colsIndex+1].consequent.start.line === lineNum &&
4716           cols[colsIndex+1].consequent.start.column-offset < cols[colsIndex].consequent.end.column-offset)
4717         {
4718           var res = branchReport(colsIndex+1,src.slice(cons.start.column-offset,cons.end.column-offset),cols,cons.start.column-offset,lineNum);
4719           newsrc += res.src;
4720           cols = res.cols;
4721           cols[colsIndex+1] = cols[colsIndex+2];
4722           cols.length--;
4723         }else{
4724           newsrc += escapeInvalidXmlChars(src.slice(cons.start.column-offset,cons.end.column-offset));
4725         }
4726         newsrc += "</span>";
4728         var alt = thisline.alternate;
4729         if (alt.start.line > lineNum){
4730           newsrc += escapeInvalidXmlChars(src.slice(cons.end.column-offset));
4731           branchStack.unshift([alt,thisline]);
4732         }else{
4733           newsrc += escapeInvalidXmlChars(src.slice(cons.end.column-offset,alt.start.column-offset));
4734           style = "<span class='" + (isBranchFollowed(thisline,false) ? 'branchOkay' : 'branchWarning') + "'>";
4735           newsrc +=  style;
4736           if (cols.length > colsIndex+1 &&
4737             cols[colsIndex+1].consequent.start.line === lineNum &&
4738             cols[colsIndex+1].consequent.start.column-offset < cols[colsIndex].alternate.end.column-offset)
4739           {
4740             var res2 = branchReport(colsIndex+1,src.slice(alt.start.column-offset,alt.end.column-offset),cols,alt.start.column-offset,lineNum);
4741             newsrc += res2.src;
4742             cols = res2.cols;
4743             cols[colsIndex+1] = cols[colsIndex+2];
4744             cols.length--;
4745           }else{
4746             newsrc += escapeInvalidXmlChars(src.slice(alt.start.column-offset,alt.end.column-offset));
4747           }
4748           newsrc += "</span>";
4749           newsrc += escapeInvalidXmlChars(src.slice(alt.end.column-offset));
4750           src = newsrc;
4751         }
4752       }
4753       return {src:src+postfix, cols:cols};
4754     }
4756     var isUndefined =  function(item){
4757             return typeof item !== 'undefined';
4758       };
4760     var files = coverage.files;
4761     var totals = {
4762       totalSmts: 0,
4763       numberOfFilesCovered: 0,
4764       passedBranches: 0,
4765       totalBranches: 0,
4766       moduleTotalStatements : {},
4767       moduleTotalCoveredStatements : {},
4768       moduleTotalBranches : {},
4769       moduleTotalCoveredBranches : {}
4770     };
4772     // check if a data-cover-modulepattern was provided for per-module coverage reporting
4773     var modulePattern = _blanket.options("modulePattern");
4774     var modulePatternRegex = ( modulePattern ? new RegExp(modulePattern) : null );
4776     for(var file in files)
4777     {
4778         fileNumber++;
4780         var statsForFile = files[file],
4781             totalSmts = 0,
4782             numberOfFilesCovered = 0,
4783             code = [],
4784             i;
4787         var end = [];
4788         for(i = 0; i < statsForFile.source.length; i +=1){
4789             var src = statsForFile.source[i];
4791             if (branchStack.length > 0 ||
4792                 typeof statsForFile.branchData !== 'undefined')
4793             {
4794                 if (typeof statsForFile.branchData[i+1] !== 'undefined')
4795                 {
4796                   var cols = statsForFile.branchData[i+1].filter(isUndefined);
4797                   var colsIndex=0;
4800                   src = branchReport(colsIndex,src,cols,0,i+1).src;
4802                 }else if (branchStack.length){
4803                   src = branchReport(0,src,null,0,i+1).src;
4804                 }else{
4805                   src = escapeInvalidXmlChars(src);
4806                 }
4807               }else{
4808                 src = escapeInvalidXmlChars(src);
4809               }
4810               var lineClass="";
4811               if(statsForFile[i+1]) {
4812                 numberOfFilesCovered += 1;
4813                 totalSmts += 1;
4814                 lineClass = 'hit';
4815               }else{
4816                 if(statsForFile[i+1] === 0){
4817                     totalSmts++;
4818                     lineClass = 'miss';
4819                 }
4820               }
4821               code[i + 1] = "<div class='"+lineClass+"'><span class=''>"+(i + 1)+"</span>"+src+"</div>";
4822         }
4823         totals.totalSmts += totalSmts;
4824         totals.numberOfFilesCovered += numberOfFilesCovered;
4825         var totalBranches=0;
4826         var passedBranches=0;
4827         if (typeof statsForFile.branchData !== 'undefined'){
4828           for(var j=0;j<statsForFile.branchData.length;j++){
4829             if (typeof statsForFile.branchData[j] !== 'undefined'){
4830               for(var k=0;k<statsForFile.branchData[j].length;k++){
4831                 if (typeof statsForFile.branchData[j][k] !== 'undefined'){
4832                   totalBranches++;
4833                   if (typeof statsForFile.branchData[j][k][0] !== 'undefined' &&
4834                     statsForFile.branchData[j][k][0].length > 0 &&
4835                     typeof statsForFile.branchData[j][k][1] !== 'undefined' &&
4836                     statsForFile.branchData[j][k][1].length > 0){
4837                     passedBranches++;
4838                   }
4839                 }
4840               }
4841             }
4842           }
4843         }
4844         totals.passedBranches += passedBranches;
4845         totals.totalBranches += totalBranches;
4847         // if "data-cover-modulepattern" was provided,
4848         // track totals per module name as well as globally
4849         if (modulePatternRegex) {
4850             var moduleName = file.match(modulePatternRegex)[1];
4852             if(!totals.moduleTotalStatements.hasOwnProperty(moduleName)) {
4853                 totals.moduleTotalStatements[moduleName] = 0;
4854                 totals.moduleTotalCoveredStatements[moduleName] = 0;
4855             }
4857             totals.moduleTotalStatements[moduleName] += totalSmts;
4858             totals.moduleTotalCoveredStatements[moduleName] += numberOfFilesCovered;
4860             if(!totals.moduleTotalBranches.hasOwnProperty(moduleName)) {
4861                 totals.moduleTotalBranches[moduleName] = 0;
4862                 totals.moduleTotalCoveredBranches[moduleName] = 0;
4863             }
4865             totals.moduleTotalBranches[moduleName] += totalBranches;
4866             totals.moduleTotalCoveredBranches[moduleName] += passedBranches;
4867         }
4869         var result = percentage(numberOfFilesCovered, totalSmts);
4871         var output = fileTemplate.replace("{{file}}", file)
4872                                  .replace("{{percentage}}",result)
4873                                  .replace("{{numberCovered}}", numberOfFilesCovered)
4874                                  .replace(/\{\{fileNumber\}\}/g, fileNumber)
4875                                  .replace("{{totalSmts}}", totalSmts)
4876                                  .replace("{{totalBranches}}", totalBranches)
4877                                  .replace("{{passedBranches}}", passedBranches)
4878                                  .replace("{{source}}", code.join(" "));
4879         if(result < successRate)
4880         {
4881             output = output.replace("{{statusclass}}", "bl-error");
4882         } else {
4883             output = output.replace("{{statusclass}}", "bl-success");
4884         }
4885         bodyContent += output;
4886     }
4888     // create temporary function for use by the global totals reporter,
4889     // as well as the per-module totals reporter
4890     var createAggregateTotal = function(numSt, numCov, numBranch, numCovBr, moduleName) {
4892         var totalPercent = percentage(numCov, numSt);
4893         var statusClass = totalPercent < successRate ? "bl-error" : "bl-success";
4894         var rowTitle = ( moduleName ? "Total for module: " + moduleName : "Global total" );
4895         var totalsOutput = grandTotalTemplate.replace("{{rowTitle}}", rowTitle)
4896             .replace("{{percentage}}", totalPercent)
4897             .replace("{{numberCovered}}", numCov)
4898             .replace("{{totalSmts}}", numSt)
4899             .replace("{{passedBranches}}", numCovBr)
4900             .replace("{{totalBranches}}", numBranch)
4901             .replace("{{statusclass}}", statusClass);
4903         bodyContent += totalsOutput;
4904     };
4906     // if "data-cover-modulepattern" was provided,
4907     // output the per-module totals alongside the global totals
4908     if (modulePatternRegex) {
4909         for (var thisModuleName in totals.moduleTotalStatements) {
4910             if (totals.moduleTotalStatements.hasOwnProperty(thisModuleName)) {
4912                 var moduleTotalSt = totals.moduleTotalStatements[thisModuleName];
4913                 var moduleTotalCovSt = totals.moduleTotalCoveredStatements[thisModuleName];
4915                 var moduleTotalBr = totals.moduleTotalBranches[thisModuleName];
4916                 var moduleTotalCovBr = totals.moduleTotalCoveredBranches[thisModuleName];
4918                 createAggregateTotal(moduleTotalSt, moduleTotalCovSt, moduleTotalBr, moduleTotalCovBr, thisModuleName);
4919             }
4920         }
4921     }
4923     createAggregateTotal(totals.totalSmts, totals.numberOfFilesCovered, totals.totalBranches, totals.passedBranches, null);
4924     bodyContent += "</div>"; //closing main
4927     appendTag('style', head, cssSytle);
4928     //appendStyle(body, headerContent);
4929     if (document.getElementById("blanket-main")){
4930         document.getElementById("blanket-main").innerHTML=
4931             bodyContent.slice(23,-6);
4932     }else{
4933         appendTag('div', body, bodyContent);
4934     }
4935     //appendHtml(body, '</div>');
4938 (function(){
4939     var newOptions={};
4940     //http://stackoverflow.com/a/2954896
4941     var toArray =Array.prototype.slice;
4942     var scripts = toArray.call(document.scripts);
4943     toArray.call(scripts[scripts.length - 1].attributes)
4944                     .forEach(function(es){
4945                         if(es.nodeName === "data-cover-only"){
4946                             newOptions.filter = es.nodeValue;
4947                         }
4948                         if(es.nodeName === "data-cover-never"){
4949                             newOptions.antifilter = es.nodeValue;
4950                         }
4951                         if(es.nodeName === "data-cover-reporter"){
4952                             newOptions.reporter = es.nodeValue;
4953                         }
4954                         if (es.nodeName === "data-cover-adapter"){
4955                             newOptions.adapter = es.nodeValue;
4956                         }
4957                         if (es.nodeName === "data-cover-loader"){
4958                             newOptions.loader = es.nodeValue;
4959                         }
4960                         if (es.nodeName === "data-cover-timeout"){
4961                             newOptions.timeout = es.nodeValue;
4962                         }
4963                         if (es.nodeName === "data-cover-modulepattern") {
4964                             newOptions.modulePattern = es.nodeValue;
4965                         }
4966                         if (es.nodeName === "data-cover-reporter-options"){
4967                             try{
4968                                 newOptions.reporter_options = JSON.parse(es.nodeValue);
4969                             }catch(e){
4970                                 if (blanket.options("debug")){
4971                                     throw new Error("Invalid reporter options.  Must be a valid stringified JSON object.");
4972                                 }
4973                             }
4974                         }
4975                         if (es.nodeName === "data-cover-testReadyCallback"){
4976                             newOptions.testReadyCallback = es.nodeValue;
4977                         }
4978                         if (es.nodeName === "data-cover-customVariable"){
4979                             newOptions.customVariable = es.nodeValue;
4980                         }
4981                         if (es.nodeName === "data-cover-flags"){
4982                             var flags = " "+es.nodeValue+" ";
4983                             if (flags.indexOf(" ignoreError ") > -1){
4984                                 newOptions.ignoreScriptError = true;
4985                             }
4986                             if (flags.indexOf(" autoStart ") > -1){
4987                                 newOptions.autoStart = true;
4988                             }
4989                             if (flags.indexOf(" ignoreCors ") > -1){
4990                                 newOptions.ignoreCors = true;
4991                             }
4992                             if (flags.indexOf(" branchTracking ") > -1){
4993                                 newOptions.branchTracking = true;
4994                             }
4995                             if (flags.indexOf(" sourceURL ") > -1){
4996                                 newOptions.sourceURL = true;
4997                             }
4998                             if (flags.indexOf(" debug ") > -1){
4999                                 newOptions.debug = true;
5000                             }
5001                             if (flags.indexOf(" engineOnly ") > -1){
5002                                 newOptions.engineOnly = true;
5003                             }
5004                             if (flags.indexOf(" commonJS ") > -1){
5005                                 newOptions.commonJS = true;
5006                             }
5007                              if (flags.indexOf(" instrumentCache ") > -1){
5008                                 newOptions.instrumentCache = true;
5009                             }
5010                         }
5011                     });
5012     blanket.options(newOptions);
5014     if (typeof requirejs !== 'undefined'){
5015         blanket.options("existingRequireJS",true);
5016     }
5017     /* setup requirejs loader, if needed */
5019     if (blanket.options("commonJS")){
5020         blanket._commonjs = {};
5021     }
5022 })();
5023 (function(_blanket){
5024 _blanket.extend({
5025     utils: {
5026         normalizeBackslashes: function(str) {
5027             return str.replace(/\\/g, '/');
5028         },
5029         matchPatternAttribute: function(filename,pattern){
5030             if (typeof pattern === 'string'){
5031                 if (pattern.indexOf("[") === 0){
5032                     //treat as array
5033                     var pattenArr = pattern.slice(1,pattern.length-1).split(",");
5034                     return pattenArr.some(function(elem){
5035                         return _blanket.utils.matchPatternAttribute(filename,_blanket.utils.normalizeBackslashes(elem.slice(1,-1)));
5036                         //return filename.indexOf(_blanket.utils.normalizeBackslashes(elem.slice(1,-1))) > -1;
5037                     });
5038                 }else if ( pattern.indexOf("//") === 0){
5039                     var ex = pattern.slice(2,pattern.lastIndexOf('/'));
5040                     var mods = pattern.slice(pattern.lastIndexOf('/')+1);
5041                     var regex = new RegExp(ex,mods);
5042                     return regex.test(filename);
5043                 }else if (pattern.indexOf("#") === 0){
5044                     return window[pattern.slice(1)].call(window,filename);
5045                 }else{
5046                     return filename.indexOf(_blanket.utils.normalizeBackslashes(pattern)) > -1;
5047                 }
5048             }else if ( pattern instanceof Array ){
5049                 return pattern.some(function(elem){
5050                     return _blanket.utils.matchPatternAttribute(filename,elem);
5051                 });
5052             }else if (pattern instanceof RegExp){
5053                 return pattern.test(filename);
5054             }else if (typeof pattern === "function"){
5055                 return pattern.call(window,filename);
5056             }
5057         },
5058         blanketEval: function(data){
5059             _blanket._addScript(data);
5060         },
5061         collectPageScripts: function(){
5062             var toArray = Array.prototype.slice;
5063             var scripts = toArray.call(document.scripts);
5064             var selectedScripts=[],scriptNames=[];
5065             var filter = _blanket.options("filter");
5066             if(filter != null){
5067                 //global filter in place, data-cover-only
5068                 var antimatch = _blanket.options("antifilter");
5069                 selectedScripts = toArray.call(document.scripts)
5070                                 .filter(function(s){
5071                                     return toArray.call(s.attributes).filter(function(sn){
5072                                         return sn.nodeName === "src" && _blanket.utils.matchPatternAttribute(sn.nodeValue,filter) &&
5073                                             (typeof antimatch === "undefined" || !_blanket.utils.matchPatternAttribute(sn.nodeValue,antimatch));
5074                                     }).length === 1;
5075                                 });
5076             }else{
5077                 selectedScripts = toArray.call(document.querySelectorAll("script[data-cover]"));
5078             }
5079             scriptNames = selectedScripts.map(function(s){
5080                                     return _blanket.utils.qualifyURL(
5081                                         toArray.call(s.attributes).filter(
5082                                             function(sn){
5083                                                 return sn.nodeName === "src";
5084                                             })[0].nodeValue).replace(".js","");
5085                                     });
5086             if (!filter){
5087                 _blanket.options("filter","['"+scriptNames.join("','")+"']");
5088             }
5089             return scriptNames;
5090         },
5091         loadAll: function(nextScript,cb,preprocessor){
5092             /**
5093              * load dependencies
5094              * @param {nextScript} factory for priority level
5095              * @param {cb} the done callback
5096              */
5097             var currScript=nextScript();
5098             var isLoaded = _blanket.utils.scriptIsLoaded(
5099                                 currScript,
5100                                 _blanket.utils.ifOrdered,
5101                                 nextScript,
5102                                 cb
5103                             );
5105             if (!(_blanket.utils.cache[currScript] && _blanket.utils.cache[currScript].loaded)){
5106                 var attach = function(){
5107                     if (_blanket.options("debug")) {console.log("BLANKET-Mark script:"+currScript+", as loaded and move to next script.");}
5108                     isLoaded();
5109                 };
5110                 var whenDone = function(result){
5111                     if (_blanket.options("debug")) {console.log("BLANKET-File loading finished");}
5112                     if (typeof result !== 'undefined'){
5113                         if (_blanket.options("debug")) {console.log("BLANKET-Add file to DOM.");}
5114                         _blanket._addScript(result);
5115                     }
5116                     attach();
5117                 };
5119                 _blanket.utils.attachScript(
5120                     {
5121                         url: currScript
5122                     },
5123                     function (content){
5124                         _blanket.utils.processFile(
5125                             content,
5126                             currScript,
5127                             whenDone,
5128                             whenDone
5129                         );
5130                     }
5131                 );
5132             }else{
5133                 isLoaded();
5134             }
5135         },
5136         attachScript: function(options,cb){
5137            var timeout = _blanket.options("timeout") || 3000;
5138            setTimeout(function(){
5139                 if (!_blanket.utils.cache[options.url].loaded){
5140                     throw new Error("error loading source script");
5141                 }
5142            },timeout);
5143            _blanket.utils.getFile(
5144                 options.url,
5145                 cb,
5146                 function(){ throw new Error("error loading source script");}
5147             );
5148         },
5149         ifOrdered: function(nextScript,cb){
5150             /**
5151              * ordered loading callback
5152              * @param {nextScript} factory for priority level
5153              * @param {cb} the done callback
5154              */
5155             var currScript = nextScript(true);
5156             if (currScript){
5157               _blanket.utils.loadAll(nextScript,cb);
5158             }else{
5159               cb(new Error("Error in loading chain."));
5160             }
5161         },
5162         scriptIsLoaded: function(url,orderedCb,nextScript,cb){
5163             /**
5164            * returns a callback that checks a loading list to see if a script is loaded.
5165            * @param {orderedCb} callback if ordered loading is being done
5166            * @param {nextScript} factory for next priority level
5167            * @param {cb} the done callback
5168            */
5169            if (_blanket.options("debug")) {console.log("BLANKET-Returning function");}
5170             return function(){
5171                 if (_blanket.options("debug")) {console.log("BLANKET-Marking file as loaded: "+url);}
5173                 _blanket.utils.cache[url].loaded=true;
5175                 if (_blanket.utils.allLoaded()){
5176                     if (_blanket.options("debug")) {console.log("BLANKET-All files loaded");}
5177                     cb();
5178                 }else if (orderedCb){
5179                     //if it's ordered we need to
5180                     //traverse down to the next
5181                     //priority level
5182                     if (_blanket.options("debug")) {console.log("BLANKET-Load next file.");}
5183                     orderedCb(nextScript,cb);
5184                 }
5185             };
5186         },
5187         cache: {},
5188         allLoaded: function (){
5189             /**
5190              * check if depdencies are loaded in cache
5191              */
5192             var cached = Object.keys(_blanket.utils.cache);
5193             for (var i=0;i<cached.length;i++){
5194                 if (!_blanket.utils.cache[cached[i]].loaded){
5195                     return false;
5196                 }
5197             }
5198             return true;
5199         },
5200         processFile: function (content,url,cb,oldCb) {
5201             var match = _blanket.options("filter");
5202             //we check the never matches first
5203             var antimatch = _blanket.options("antifilter");
5204             if (typeof antimatch !== "undefined" &&
5205                     _blanket.utils.matchPatternAttribute(url.replace(/\.js$/,""),antimatch)
5206                 ){
5207                 oldCb(content);
5208                 if (_blanket.options("debug")) {console.log("BLANKET-File will never be instrumented:"+url);}
5209                 _blanket.requiringFile(url,true);
5210             }else if (_blanket.utils.matchPatternAttribute(url.replace(/\.js$/,""),match)){
5211                 if (_blanket.options("debug")) {console.log("BLANKET-Attempting instrument of:"+url);}
5212                 _blanket.instrument({
5213                     inputFile: content,
5214                     inputFileName: url
5215                 },function(instrumented){
5216                     try{
5217                         if (_blanket.options("debug")) {console.log("BLANKET-instrument of:"+url+" was successfull.");}
5218                         _blanket.utils.blanketEval(instrumented);
5219                         cb();
5220                         _blanket.requiringFile(url,true);
5221                     }
5222                     catch(err){
5223                         if (_blanket.options("ignoreScriptError")){
5224                             //we can continue like normal if
5225                             //we're ignoring script errors,
5226                             //but otherwise we don't want
5227                             //to completeLoad or the error might be
5228                             //missed.
5229                             if (_blanket.options("debug")) { console.log("BLANKET-There was an error loading the file:"+url); }
5230                             cb(content);
5231                             _blanket.requiringFile(url,true);
5232                         }else{
5233                             throw new Error("Error parsing instrumented code: "+err);
5234                         }
5235                     }
5236                 });
5237             }else{
5238                 if (_blanket.options("debug")) { console.log("BLANKET-Loading (without instrumenting) the file:"+url);}
5239                 oldCb(content);
5240                 _blanket.requiringFile(url,true);
5241             }
5243         },
5244         createXhr: function(){
5245             var xhr, i, progId;
5246             if (typeof XMLHttpRequest !== "undefined") {
5247                 return new XMLHttpRequest();
5248             } else if (typeof ActiveXObject !== "undefined") {
5249                 for (i = 0; i < 3; i += 1) {
5250                     progId = progIds[i];
5251                     try {
5252                         xhr = new ActiveXObject(progId);
5253                     } catch (e) {}
5255                     if (xhr) {
5256                         progIds = [progId];  // so faster next time
5257                         break;
5258                     }
5259                 }
5260             }
5262             return xhr;
5263         },
5264         getFile: function(url, callback, errback, onXhr){
5265             var foundInSession = false;
5266             if (_blanket.blanketSession){
5267                 var files = Object.keys(_blanket.blanketSession);
5268                 for (var i=0; i<files.length;i++ ){
5269                     var key = files[i];
5270                     if (url.indexOf(key) > -1){
5271                         callback(_blanket.blanketSession[key]);
5272                         foundInSession=true;
5273                         return;
5274                     }
5275                 }
5276             }
5277             if (!foundInSession){
5278                 var xhr = _blanket.utils.createXhr();
5279                 xhr.open('GET', url, true);
5281                 //Allow overrides specified in config
5282                 if (onXhr) {
5283                     onXhr(xhr, url);
5284                 }
5286                 xhr.onreadystatechange = function (evt) {
5287                     var status, err;
5289                     //Do not explicitly handle errors, those should be
5290                     //visible via console output in the browser.
5291                     if (xhr.readyState === 4) {
5292                         status = xhr.status;
5293                         if ((status > 399 && status < 600) /*||
5294                             (status === 0 &&
5295                                 navigator.userAgent.toLowerCase().indexOf('firefox') > -1)
5296                            */ ) {
5297                             //An http 4xx or 5xx error. Signal an error.
5298                             err = new Error(url + ' HTTP status: ' + status);
5299                             err.xhr = xhr;
5300                             errback(err);
5301                         } else {
5302                             callback(xhr.responseText);
5303                         }
5304                     }
5305                 };
5306                 try{
5307                     xhr.send(null);
5308                 }catch(e){
5309                     if (e.code && (e.code === 101 || e.code === 1012) && _blanket.options("ignoreCors") === false){
5310                         //running locally and getting error from browser
5311                         _blanket.showManualLoader();
5312                     } else {
5313                         throw e;
5314                     }
5315                 }
5316             }
5317         }
5318     }
5321 (function(){
5322     var require = blanket.options("commonJS") ? blanket._commonjs.require : window.require;
5323     var requirejs = blanket.options("commonJS") ? blanket._commonjs.requirejs : window.requirejs;
5324     if (!_blanket.options("engineOnly") && _blanket.options("existingRequireJS")){
5326         _blanket.utils.oldloader = requirejs.load;
5328         requirejs.load = function (context, moduleName, url) {
5329             _blanket.requiringFile(url);
5330             _blanket.utils.getFile(url,
5331                 function(content){
5332                     _blanket.utils.processFile(
5333                         content,
5334                         url,
5335                         function newLoader(){
5336                             context.completeLoad(moduleName);
5337                         },
5338                         function oldLoader(){
5339                             _blanket.utils.oldloader(context, moduleName, url);
5340                         }
5341                     );
5342                 }, function (err) {
5343                 _blanket.requiringFile();
5344                 throw err;
5345             });
5346         };
5347     }
5348 })();
5350 })(blanket);