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