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