({type:42, lineno:1, tokenizer:#1={cursor:33428, source:"/* vim: set sw=4 ts=8 et tw=78: */\r\n/* ***** BEGIN LICENSE BLOCK *****\r\n * Version: MPL 1.1/GPL 2.0/LGPL 2.1\r\n *\r\n * The contents of this file are subject to the Mozilla Public License Version\r\n * 1.1 (the \"License\"); you may not use this file except in compliance with\r\n * the License. You may obtain a copy of the License at\r\n * http://www.mozilla.org/MPL/\r\n *\r\n * Software distributed under the License is distributed on an \"AS IS\" basis,\r\n * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\r\n * for the specific language governing rights and limitations under the\r\n * License.\r\n *\r\n * The Original Code is the Narcissus JavaScript engine.\r\n *\r\n * The Initial Developer of the Original Code is\r\n * Brendan Eich .\r\n * Portions created by the Initial Developer are Copyright (C) 2004\r\n * the Initial Developer. All Rights Reserved.\r\n *\r\n * Contributor(s):\r\n *\r\n * Alternatively, the contents of this file may be used under the terms of\r\n * either the GNU General Public License Version 2 or later (the \"GPL\"), or\r\n * the GNU Lesser General Public License Version 2.1 or later (the \"LGPL\"),\r\n * in which case the provisions of the GPL or the LGPL are applicable instead\r\n * of those above. If you wish to allow use of your version of this file only\r\n * under the terms of either the GPL or the LGPL, and not to allow others to\r\n * use your version of this file under the terms of the MPL, indicate your\r\n * decision by deleting the provisions above and replace them with the notice\r\n * and other provisions required by the GPL or the LGPL. If you do not delete\r\n * the provisions above, a recipient may use your version of this file under\r\n * the terms of any one of the MPL, the GPL or the LGPL.\r\n *\r\n * ***** END LICENSE BLOCK ***** */\r\n\r\n/*\r\n * Narcissus - JS implemented in JS.\r\n *\r\n * Lexical scanner and parser.\r\n */\r\n\r\n// Build a regexp that recognizes operators and punctuators (except newline).\r\nvar opRegExpSrc = \"^\";\r\nfor (i in opTypeNames) {\r\n if (i == '\\n')\r\n continue;\r\n if (opRegExpSrc != \"^\")\r\n opRegExpSrc += \"|^\";\r\n opRegExpSrc += i.replace(/[?|^&(){}\\[\\]+\\-*\\/\\.]/g, \"\\\\$&\");\r\n}\r\nvar opRegExp = new RegExp(opRegExpSrc);\r\n\r\n// A regexp to match floating point literals (but not integer literals).\r\nvar fpRegExp = /^\\d+\\.\\d*(?:[eE][-+]?\\d+)?|^\\d+(?:\\.\\d*)?[eE][-+]?\\d+|^\\.\\d+(?:[eE][-+]?\\d+)?/;\r\n\r\n// A regexp to match regexp literals.\r\nvar reRegExp = /^\\/((?:\\\\.|\\[(?:\\\\.|[^\\]])*\\]|[^\\/])+)\\/([gimy]*)/;\r\n\r\nfunction Tokenizer(s, f, l) {\r\n this.cursor = 0;\r\n this.source = String(s);\r\n this.tokens = [];\r\n this.tokenIndex = 0;\r\n this.lookahead = 0;\r\n this.scanNewlines = false;\r\n this.scanOperand = true;\r\n this.filename = f || \"\";\r\n this.lineno = l || 1;\r\n}\r\n\r\nTokenizer.prototype = {\r\n get input() {\r\n return this.source.substring(this.cursor);\r\n },\r\n\r\n get done() {\r\n return this.peek() == END;\r\n },\r\n\r\n get token() {\r\n return this.tokens[this.tokenIndex];\r\n },\r\n\r\n match: function (tt) {\r\n return this.get() == tt || this.unget();\r\n },\r\n\r\n mustMatch: function (tt) {\r\n if (!this.match(tt))\r\n throw this.newSyntaxError(\"Missing \" + tokens[tt].toLowerCase());\r\n return this.token;\r\n },\r\n\r\n peek: function () {\r\n var tt, next;\r\n if (this.lookahead) {\r\n next = this.tokens[(this.tokenIndex + this.lookahead) & 3];\r\n if (this.scanNewlines && next.lineno != this.lineno)\r\n tt = NEWLINE;\r\n else\r\n tt = next.type;\r\n } else {\r\n tt = this.get();\r\n this.unget();\r\n }\r\n return tt;\r\n },\r\n\r\n peekOnSameLine: function () {\r\n this.scanNewlines = true;\r\n var tt = this.peek();\r\n this.scanNewlines = false;\r\n return tt;\r\n },\r\n\r\n get: function () {\r\n var token;\r\n while (this.lookahead) {\r\n --this.lookahead;\r\n this.tokenIndex = (this.tokenIndex + 1) & 3;\r\n token = this.tokens[this.tokenIndex];\r\n if (token.type != NEWLINE || this.scanNewlines)\r\n return token.type;\r\n }\r\n\r\n for (;;) {\r\n var input = this.input;\r\n var match = (this.scanNewlines ? /^[ \\t]+/ : /^\\s+/)(input);\r\n if (match) {\r\n var spaces = match[0];\r\n this.cursor += spaces.length;\r\n var newlines = spaces.match(/\\n/g);\r\n if (newlines)\r\n this.lineno += newlines.length;\r\n input = this.input;\r\n }\r\n\r\n if (!(match = /^\\/(?:\\*(?:.|\\n)*?\\*\\/|\\/.*)/(input)))\r\n break;\r\n var comment = match[0];\r\n this.cursor += comment.length;\r\n newlines = comment.match(/\\n/g);\r\n if (newlines)\r\n this.lineno += newlines.length\r\n }\r\n\r\n this.tokenIndex = (this.tokenIndex + 1) & 3;\r\n token = this.tokens[this.tokenIndex];\r\n if (!token)\r\n this.tokens[this.tokenIndex] = token = {};\r\n\r\n if (!input)\r\n return token.type = END;\r\n\r\n if ((match = fpRegExp(input))) {\r\n token.type = NUMBER;\r\n token.value = parseFloat(match[0]);\r\n } else if ((match = /^0[xX][\\da-fA-F]+|^0[0-7]*|^\\d+/(input))) {\r\n token.type = NUMBER;\r\n token.value = parseInt(match[0]);\r\n } else if ((match = /^[$_\\w]+/(input))) { // FIXME no ES3 unicode\r\n var id = match[0];\r\n token.type = keywords[id] || IDENTIFIER;\r\n token.value = id;\r\n } else if ((match = /^\"(?:\\\\.|[^\"])*\"|^'(?:\\\\.|[^'])*'/(input))) { //\"){\r\n token.type = STRING;\r\n token.value = eval(match[0]);\r\n } else if (this.scanOperand && (match = reRegExp(input))) {\r\n token.type = REGEXP;\r\n token.value = new RegExp(match[1], match[2]);\r\n } else if ((match = opRegExp(input))) {\r\n var op = match[0];\r\n if (assignOps[op] && input[op.length] == '=') {\r\n token.type = ASSIGN;\r\n token.assignOp = GLOBAL[opTypeNames[op]];\r\n match[0] += '=';\r\n } else {\r\n token.type = GLOBAL[opTypeNames[op]];\r\n if (this.scanOperand &&\r\n (token.type == PLUS || token.type == MINUS)) {\r\n token.type += UNARY_PLUS - PLUS;\r\n }\r\n token.assignOp = null;\r\n }\r\n token.value = op;\r\n } else if (this.scanNewlines && (match = /^\\n/(input))) {\r\n token.type = NEWLINE;\r\n } else {\r\n throw this.newSyntaxError(\"Illegal token\");\r\n }\r\n\r\n token.start = this.cursor;\r\n this.cursor += match[0].length;\r\n token.end = this.cursor;\r\n token.lineno = this.lineno;\r\n return token.type;\r\n },\r\n\r\n unget: function () {\r\n if (++this.lookahead == 4) throw \"PANIC: too much lookahead!\";\r\n this.tokenIndex = (this.tokenIndex - 1) & 3;\r\n },\r\n\r\n newSyntaxError: function (m) {\r\n var e = new SyntaxError(m, this.filename, this.lineno);\r\n e.source = this.source;\r\n e.cursor = this.cursor;\r\n return e;\r\n }\r\n};\r\n\r\nfunction CompilerContext(inFunction) {\r\n this.inFunction = inFunction;\r\n this.stmtStack = [];\r\n this.funDecls = [];\r\n this.varDecls = [];\r\n}\r\n\r\nvar CCp = CompilerContext.prototype;\r\nCCp.bracketLevel = CCp.curlyLevel = CCp.parenLevel = CCp.hookLevel = 0;\r\nCCp.ecmaStrictMode = CCp.inForLoopInit = false;\r\n\r\nfunction Script(t, x) {\r\n var n = Statements(t, x);\r\n n.type = SCRIPT;\r\n n.funDecls = x.funDecls;\r\n n.varDecls = x.varDecls;\r\n return n;\r\n}\r\n\r\n// Node extends Array, which we extend slightly with a top-of-stack method.\r\nArray.prototype.__defineProperty__(\r\n 'top',\r\n function () {\r\n return this.length && this[this.length-1];\r\n },\r\n false, false, true\r\n);\r\n\r\nfunction Node(t, type) {\r\n var token = t.token;\r\n if (token) {\r\n this.type = type || token.type;\r\n this.value = token.value;\r\n this.lineno = token.lineno;\r\n this.start = token.start;\r\n this.end = token.end;\r\n } else {\r\n this.type = type;\r\n this.lineno = t.lineno;\r\n }\r\n this.tokenizer = t;\r\n\r\n for (var i = 2; i < arguments.length; i++)\r\n this.push(arguments[i]);\r\n}\r\n\r\nvar Np = Node.prototype = new Array;\r\nNp.constructor = Node;\r\nNp.toSource = Object.prototype.toSource;\r\n\r\n// Always use push to add operands to an expression, to update start and end.\r\nNp.push = function (kid) {\r\n if (kid.start < this.start)\r\n this.start = kid.start;\r\n if (this.end < kid.end)\r\n this.end = kid.end;\r\n return Array.prototype.push.call(this, kid);\r\n}\r\n\r\nNode.indentLevel = 0;\r\n\r\nfunction tokenstr(tt) {\r\n var t = tokens[tt];\r\n return /^\\W/.test(t) ? opTypeNames[t] : t.toUpperCase();\r\n}\r\n\r\nNp.toString = function () {\r\n var a = [];\r\n for (var i in this) {\r\n if (this.hasOwnProperty(i) && i != 'type' && i != 'target')\r\n a.push({id: i, value: this[i]});\r\n }\r\n a.sort(function (a,b) { return (a.id < b.id) ? -1 : 1; });\r\n const INDENTATION = \" \";\r\n var n = ++Node.indentLevel;\r\n var s = \"{\\n\" + INDENTATION.repeat(n) + \"type: \" + tokenstr(this.type);\r\n for (i = 0; i < a.length; i++)\r\n s += \",\\n\" + INDENTATION.repeat(n) + a[i].id + \": \" + a[i].value;\r\n n = --Node.indentLevel;\r\n s += \"\\n\" + INDENTATION.repeat(n) + \"}\";\r\n return s;\r\n}\r\n\r\nNp.getSource = function () {\r\n return this.tokenizer.source.slice(this.start, this.end);\r\n};\r\n\r\nNp.__defineGetter__('filename',\r\n function () { return this.tokenizer.filename; });\r\n\r\nString.prototype.__defineProperty__(\r\n 'repeat',\r\n function (n) {\r\n var s = \"\", t = this + s;\r\n while (--n >= 0)\r\n s += t;\r\n return s;\r\n },\r\n false, false, true\r\n);\r\n\r\n// Statement stack and nested statement handler.\r\nfunction nest(t, x, node, func, end) {\r\n x.stmtStack.push(node);\r\n var n = func(t, x);\r\n x.stmtStack.pop();\r\n end && t.mustMatch(end);\r\n return n;\r\n}\r\n\r\nfunction Statements(t, x) {\r\n var n = new Node(t, BLOCK);\r\n x.stmtStack.push(n);\r\n while (!t.done && t.peek() != RIGHT_CURLY)\r\n n.push(Statement(t, x));\r\n x.stmtStack.pop();\r\n return n;\r\n}\r\n\r\nfunction Block(t, x) {\r\n t.mustMatch(LEFT_CURLY);\r\n var n = Statements(t, x);\r\n t.mustMatch(RIGHT_CURLY);\r\n return n;\r\n}\r\n\r\nconst DECLARED_FORM = 0, EXPRESSED_FORM = 1, STATEMENT_FORM = 2;\r\n\r\nfunction Statement(t, x) {\r\n var i, label, n, n2, ss, tt = t.get();\r\n\r\n // Cases for statements ending in a right curly return early, avoiding the\r\n // common semicolon insertion magic after this switch.\r\n switch (tt) {\r\n case FUNCTION:\r\n return FunctionDefinition(t, x, true,\r\n (x.stmtStack.length > 1)\r\n ? STATEMENT_FORM\r\n : DECLARED_FORM);\r\n\r\n case LEFT_CURLY:\r\n n = Statements(t, x);\r\n t.mustMatch(RIGHT_CURLY);\r\n return n;\r\n\r\n case IF:\r\n n = new Node(t);\r\n n.condition = ParenExpression(t, x);\r\n x.stmtStack.push(n);\r\n n.thenPart = Statement(t, x);\r\n n.elsePart = t.match(ELSE) ? Statement(t, x) : null;\r\n x.stmtStack.pop();\r\n return n;\r\n\r\n case SWITCH:\r\n n = new Node(t);\r\n t.mustMatch(LEFT_PAREN);\r\n n.discriminant = Expression(t, x);\r\n t.mustMatch(RIGHT_PAREN);\r\n n.cases = [];\r\n n.defaultIndex = -1;\r\n x.stmtStack.push(n);\r\n t.mustMatch(LEFT_CURLY);\r\n while ((tt = t.get()) != RIGHT_CURLY) {\r\n switch (tt) {\r\n case DEFAULT:\r\n if (n.defaultIndex >= 0)\r\n throw t.newSyntaxError(\"More than one switch default\");\r\n // FALL THROUGH\r\n case CASE:\r\n n2 = new Node(t);\r\n if (tt == DEFAULT)\r\n n.defaultIndex = n.cases.length;\r\n else\r\n n2.caseLabel = Expression(t, x, COLON);\r\n break;\r\n default:\r\n throw t.newSyntaxError(\"Invalid switch case\");\r\n }\r\n t.mustMatch(COLON);\r\n n2.statements = new Node(t, BLOCK);\r\n while ((tt=t.peek()) != CASE && tt != DEFAULT && tt != RIGHT_CURLY)\r\n n2.statements.push(Statement(t, x));\r\n n.cases.push(n2);\r\n }\r\n x.stmtStack.pop();\r\n return n;\r\n\r\n case FOR:\r\n n = new Node(t);\r\n n.isLoop = true;\r\n t.mustMatch(LEFT_PAREN);\r\n if ((tt = t.peek()) != SEMICOLON) {\r\n x.inForLoopInit = true;\r\n if (tt == VAR || tt == CONST) {\r\n t.get();\r\n n2 = Variables(t, x);\r\n } else {\r\n n2 = Expression(t, x);\r\n }\r\n x.inForLoopInit = false;\r\n }\r\n if (n2 && t.match(IN)) {\r\n n.type = FOR_IN;\r\n if (n2.type == VAR) {\r\n if (n2.length != 1) {\r\n throw new SyntaxError(\"Invalid for..in left-hand side\",\r\n t.filename, n2.lineno);\r\n }\r\n\r\n // NB: n2[0].type == IDENTIFIER and n2[0].value == n2[0].name.\r\n n.iterator = n2[0];\r\n n.varDecl = n2;\r\n } else {\r\n n.iterator = n2;\r\n n.varDecl = null;\r\n }\r\n n.object = Expression(t, x);\r\n } else {\r\n n.setup = n2 || null;\r\n t.mustMatch(SEMICOLON);\r\n n.condition = (t.peek() == SEMICOLON) ? null : Expression(t, x);\r\n t.mustMatch(SEMICOLON);\r\n n.update = (t.peek() == RIGHT_PAREN) ? null : Expression(t, x);\r\n }\r\n t.mustMatch(RIGHT_PAREN);\r\n n.body = nest(t, x, n, Statement);\r\n return n;\r\n\r\n case WHILE:\r\n n = new Node(t);\r\n n.isLoop = true;\r\n n.condition = ParenExpression(t, x);\r\n n.body = nest(t, x, n, Statement);\r\n return n;\r\n\r\n case DO:\r\n n = new Node(t);\r\n n.isLoop = true;\r\n n.body = nest(t, x, n, Statement, WHILE);\r\n n.condition = ParenExpression(t, x);\r\n if (!x.ecmaStrictMode) {\r\n //