diff --git a/js/jsd/idl/jsdIDebuggerService.idl b/js/jsd/idl/jsdIDebuggerService.idl index cd6b443ffc8c..71b0669c5f80 100644 --- a/js/jsd/idl/jsdIDebuggerService.idl +++ b/js/jsd/idl/jsdIDebuggerService.idl @@ -855,7 +855,7 @@ interface jsdIStackFrame : jsdIEphemeral * Script object. In JavaScript engine terms, there's a single script for each * function, and one for the top level script. */ -[scriptable, uuid(18e09893-f461-4b4b-94d3-776fb0069c6f)] +[scriptable, uuid(53dadd96-69f6-4846-8958-cc8eaa3f9f09)] interface jsdIScript : jsdIEphemeral { /** Internal use only. */ diff --git a/js/narcissus/jsdefs.js b/js/narcissus/jsdefs.js deleted file mode 100644 index e7ca405b1a4e..000000000000 --- a/js/narcissus/jsdefs.js +++ /dev/null @@ -1,309 +0,0 @@ -/* vim: set sw=4 ts=4 et tw=78: */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Narcissus JavaScript engine. - * - * The Initial Developer of the Original Code is - * Brendan Eich . - * Portions created by the Initial Developer are Copyright (C) 2004 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -/* - * Narcissus - JS implemented in JS. - * - * Well-known constants and lookup tables. Many consts are generated from the - * tokens table via eval to minimize redundancy, so consumers must be compiled - * separately to take advantage of the simple switch-case constant propagation - * done by SpiderMonkey. - */ - -(function() { - var builderTypes = Object.create(null, { - "default": { value: function() { - return new narcissus.parser.DefaultBuilder; - } }, - "ssa": { value: function() { - return new narcissus.parser.SSABuilder; - } } - }); - - var builderType; - - var narcissus = { - options: { - version: 185, - get builderType() { return builderType }, - set builderType(type) { - var ctor = builderTypes[type]; - - if (!ctor) - throw new Error("expected builder type ('default' or 'ssa'), got " + type); - - builderType = type; - narcissus.definitions.Builder = ctor; - } - }, - hostGlobal: this - }; - Narcissus = narcissus; -})(); - -Narcissus.definitions = (function() { - - var tokens = [ - // End of source. - "END", - - // Operators and punctuators. Some pair-wise order matters, e.g. (+, -) - // and (UNARY_PLUS, UNARY_MINUS). - "\n", ";", - ",", - "=", - "?", ":", "CONDITIONAL", - "||", - "&&", - "|", - "^", - "&", - "==", "!=", "===", "!==", - "<", "<=", ">=", ">", - "<<", ">>", ">>>", - "+", "-", - "*", "/", "%", - "!", "~", "UNARY_PLUS", "UNARY_MINUS", - "++", "--", - ".", - "[", "]", - "{", "}", - "(", ")", - - // Nonterminal tree node type codes. - "SCRIPT", "BLOCK", "LABEL", "FOR_IN", "CALL", "NEW_WITH_ARGS", "INDEX", - "ARRAY_INIT", "OBJECT_INIT", "PROPERTY_INIT", "GETTER", "SETTER", - "GROUP", "LIST", "LET_BLOCK", "ARRAY_COMP", "GENERATOR", "COMP_TAIL", - - // Terminals. - "IDENTIFIER", "NUMBER", "STRING", "REGEXP", - - // SSA fiction. - "PHI", "INTERVENED", - - // Keywords. - "break", - "case", "catch", "const", "continue", - "debugger", "default", "delete", "do", - "else", - "false", "finally", "for", "function", - "if", "in", "instanceof", - "let", - "new", "null", - "return", - "switch", - "this", "throw", "true", "try", "typeof", - "var", "void", - "yield", - "while", "with", - ]; - - // Operator and punctuator mapping from token to tree node type name. - // NB: because the lexer doesn't backtrack, all token prefixes must themselves - // be valid tokens (e.g. !== is acceptable because its prefixes are the valid - // tokens != and !). - var opTypeNames = { - '\n': "NEWLINE", - ';': "SEMICOLON", - ',': "COMMA", - '?': "HOOK", - ':': "COLON", - '||': "OR", - '&&': "AND", - '|': "BITWISE_OR", - '^': "BITWISE_XOR", - '&': "BITWISE_AND", - '===': "STRICT_EQ", - '==': "EQ", - '=': "ASSIGN", - '!==': "STRICT_NE", - '!=': "NE", - '<<': "LSH", - '<=': "LE", - '<': "LT", - '>>>': "URSH", - '>>': "RSH", - '>=': "GE", - '>': "GT", - '++': "INCREMENT", - '--': "DECREMENT", - '+': "PLUS", - '-': "MINUS", - '*': "MUL", - '/': "DIV", - '%': "MOD", - '!': "NOT", - '~': "BITWISE_NOT", - '.': "DOT", - '[': "LEFT_BRACKET", - ']': "RIGHT_BRACKET", - '{': "LEFT_CURLY", - '}': "RIGHT_CURLY", - '(': "LEFT_PAREN", - ')': "RIGHT_PAREN" - }; - - // Hash of keyword identifier to tokens index. NB: we must null __proto__ to - // avoid toString, etc. namespace pollution. - var keywords = {__proto__: null}; - - // Define const END, etc., based on the token names. Also map name to index. - var tokenIds = {}; - - // Building up a string to be eval'd in different contexts. - var consts = "const "; - for (var i = 0, j = tokens.length; i < j; i++) { - if (i > 0) - consts += ", "; - var t = tokens[i]; - var name; - if (/^[a-z]/.test(t)) { - name = t.toUpperCase(); - keywords[t] = i; - } else { - name = (/^\W/.test(t) ? opTypeNames[t] : t); - } - consts += name + " = " + i; - tokenIds[name] = i; - tokens[t] = i; - } - consts += ";"; - - // Map assignment operators to their indexes in the tokens array. - var assignOps = ['|', '^', '&', '<<', '>>', '>>>', '+', '-', '*', '/', '%']; - - for (i = 0, j = assignOps.length; i < j; i++) { - t = assignOps[i]; - assignOps[t] = tokens[t]; - } - - function defineGetter(obj, prop, fn, dontDelete, dontEnum) { - Object.defineProperty(obj, prop, { get: fn, configurable: !dontDelete, enumerable: !dontEnum }); - } - - function defineProperty(obj, prop, val, dontDelete, readOnly, dontEnum) { - Object.defineProperty(obj, prop, { value: val, writable: !readOnly, configurable: !dontDelete, enumerable: !dontEnum }); - } - - // Returns true if fn is a native function. (Note: SpiderMonkey specific.) - function isNativeCode(fn) { - // Relies on the toString method to identify native code. - return ((typeof fn) === "function") && fn.toString().match(/\[native code\]/); - } - - function getPropertyDescriptor(obj, name) { - while (obj) { - if (({}).hasOwnProperty.call(obj, name)) - return Object.getOwnPropertyDescriptor(obj, name); - obj = Object.getPrototypeOf(obj); - } - } - - function getOwnProperties(obj) { - var map = {}; - for (var name in Object.getOwnPropertyNames(obj)) - map[name] = Object.getOwnPropertyDescriptor(obj, name); - return map; - } - - function makePassthruHandler(obj) { - // Handler copied from - // http://wiki.ecmascript.org/doku.php?id=harmony:proxies&s=proxy%20object#examplea_no-op_forwarding_proxy - return { - getOwnPropertyDescriptor: function(name) { - var desc = Object.getOwnPropertyDescriptor(obj, name); - - // a trapping proxy's properties must always be configurable - desc.configurable = true; - return desc; - }, - getPropertyDescriptor: function(name) { - var desc = getPropertyDescriptor(obj, name); - - // a trapping proxy's properties must always be configurable - desc.configurable = true; - return desc; - }, - getOwnPropertyNames: function() { - return Object.getOwnPropertyNames(obj); - }, - defineProperty: function(name, desc) { - Object.defineProperty(obj, name, desc); - }, - delete: function(name) { return delete obj[name]; }, - fix: function() { - if (Object.isFrozen(obj)) { - return getOwnProperties(obj); - } - - // As long as obj is not frozen, the proxy won't allow itself to be fixed. - return undefined; // will cause a TypeError to be thrown - }, - - has: function(name) { return name in obj; }, - hasOwn: function(name) { return ({}).hasOwnProperty.call(obj, name); }, - get: function(receiver, name) { return obj[name]; }, - - // bad behavior when set fails in non-strict mode - set: function(receiver, name, val) { obj[name] = val; return true; }, - enumerate: function() { - var result = []; - for (name in obj) { result.push(name); }; - return result; - }, - keys: function() { return Object.keys(obj); } - }; - } - - return { - tokens: tokens, - opTypeNames: opTypeNames, - keywords: keywords, - tokenIds: tokenIds, - consts: consts, - assignOps: assignOps, - defineGetter: defineGetter, - defineProperty: defineProperty, - isNativeCode: isNativeCode, - makePassthruHandler: makePassthruHandler, - Builder: function() { - throw new Error("no Builder type selected"); - } - }; -}()); - -Narcissus.options.builderType = "default"; diff --git a/js/narcissus/jsexec.js b/js/narcissus/jsexec.js deleted file mode 100644 index 26f7d89b9391..000000000000 --- a/js/narcissus/jsexec.js +++ /dev/null @@ -1,1200 +0,0 @@ -/* -*- Mode: JS; tab-width: 4; indent-tabs-mode: nil; -*- - * vim: set sw=4 ts=4 et tw=78: -/* ***** BEGIN LICENSE BLOCK ***** - * - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Narcissus JavaScript engine. - * - * The Initial Developer of the Original Code is - * Brendan Eich . - * Portions created by the Initial Developer are Copyright (C) 2004 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -/* - * Narcissus - JS implemented in JS. - * - * Execution of parse trees. - * - * Standard classes except for eval, Function, Array, and String are borrowed - * from the host JS environment. Function is metacircular. Array and String - * are reflected via wrapping the corresponding native constructor and adding - * an extra level of prototype-based delegation. - */ - -Narcissus.interpreter = (function() { - - var parser = Narcissus.parser; - var definitions = Narcissus.definitions; - var hostGlobal = Narcissus.hostGlobal; - - // Set constants in the local scope. - eval(definitions.consts); - - const GLOBAL_CODE = 0, EVAL_CODE = 1, FUNCTION_CODE = 2; - - function ExecutionContext(type) { - this.type = type; - } - - function isStackOverflow(e) { - var re = /InternalError: (script stack space quota is exhausted|too much recursion)/; - return re.test(e.toString()); - } - - // The underlying global object for narcissus. - var narcissusGlobal = { - // Value properties. - NaN: NaN, Infinity: Infinity, undefined: undefined, - - // Function properties. - eval: function eval(s) { - if (typeof s !== "string") - return s; - - var x = ExecutionContext.current; - var x2 = new ExecutionContext(EVAL_CODE); - x2.thisObject = x.thisObject; - x2.caller = x.caller; - x2.callee = x.callee; - x2.scope = x.scope; - try { - x2.execute(parser.parse(new definitions.Builder, s)); - return x2.result; - } catch (e if e instanceof SyntaxError || isStackOverflow(e)) { - /* - * If we get an internal error during parsing we need to reify - * the exception as a Narcissus THROW. - * - * See bug 152646. - */ - x.result = e; - throw THROW; - } - }, - - // Class constructors. Where ECMA-262 requires C.length === 1, we declare - // a dummy formal parameter. - Function: function Function(dummy) { - var p = "", b = "", n = arguments.length; - if (n) { - var m = n - 1; - if (m) { - p += arguments[0]; - for (var k = 1; k < m; k++) - p += "," + arguments[k]; - } - b += arguments[m]; - } - - // XXX We want to pass a good file and line to the tokenizer. - // Note the anonymous name to maintain parity with Spidermonkey. - var t = new parser.Tokenizer("anonymous(" + p + ") {" + b + "}"); - - // NB: Use the STATEMENT_FORM constant since we don't want to push this - // function onto the fake compilation context. - var x = { builder: new definitions.Builder }; - var f = parser.FunctionDefinition(t, x, false, parser.STATEMENT_FORM); - var s = {object: global, parent: null}; - return newFunction(f,{scope:s}); - }, - Array: function (dummy) { - // Array when called as a function acts as a constructor. - return Array.apply(this, arguments); - }, - String: function String(s) { - // Called as function or constructor: convert argument to string type. - s = arguments.length ? "" + s : ""; - if (this instanceof String) { - // Called as constructor: save the argument as the string value - // of this String object and return this object. - this.value = s; - return this; - } - return s; - }, - - // Don't want to proxy RegExp or some features won't work - RegExp: RegExp, - - // Extensions to ECMA. - load: function load(s) { - if (typeof s !== "string") - return s; - - evaluate(snarf(s), s, 1) - }, - version: function() { return Narcissus.options.version; }, - quit: function() { throw END; } - }; - - // Create global handler with needed modifications. - var globalHandler = definitions.makePassthruHandler(narcissusGlobal); - globalHandler.has = function(name) { - if (name in narcissusGlobal) { return true; } - // Hide Narcissus implementation code. - else if (name === "Narcissus") { return false; } - else { return (name in hostGlobal); } - }; - globalHandler.get = function(receiver, name) { - if (narcissusGlobal.hasOwnProperty(name)) - return narcissusGlobal[name]; - - var globalFun = hostGlobal[name]; - if (definitions.isNativeCode(globalFun)) { - // Enables native browser functions like 'alert' to work correctly. - return Proxy.createFunction( - definitions.makePassthruHandler(globalFun), - function() { return globalFun.apply(hostGlobal, arguments); }, - function() { - var a = arguments; - switch (a.length) { - case 0: - return new globalFun(); - case 1: - return new globalFun(a[0]); - case 2: - return new globalFun(a[0], a[1]); - case 3: - return new globalFun(a[0], a[1], a[2]); - default: - var argStr = ""; - for (var i=0; i= 0) { - i = n.defaultIndex - 1; // no case matched, do default - matchDefault = true; - continue; - } - break; // no default, exit switch_loop - } - t = a[i]; // next case (might be default!) - if (t.type === CASE) { - u = getValue(execute(t.caseLabel, x)); - } else { - if (!matchDefault) // not defaulting, skip for now - continue; - u = s; // force match to do default - } - if (u === s) { - for (;;) { // this loop exits switch_loop - if (t.statements.children.length) { - try { - execute(t.statements, x); - } catch (e if e === BREAK && x.target === n) { - break switch_loop; - } - } - if (++i === j) - break switch_loop; - t = a[i]; - } - // NOT REACHED - } - } - break; - - case FOR: - n.setup && getValue(execute(n.setup, x)); - // FALL THROUGH - case WHILE: - while (!n.condition || getValue(execute(n.condition, x))) { - try { - execute(n.body, x); - } catch (e if e === BREAK && x.target === n) { - break; - } catch (e if e === CONTINUE && x.target === n) { - // Must run the update expression. - } - n.update && getValue(execute(n.update, x)); - } - break; - - case FOR_IN: - u = n.varDecl; - if (u) - execute(u, x); - r = n.iterator; - s = execute(n.object, x); - v = getValue(s); - - // ECMA deviation to track extant browser JS implementation behavior. - t = ((v === null || v === undefined) && !x.ecma3OnlyMode) - ? v - : toObject(v, s, n.object); - a = []; - for (i in t) - a.push(i); - for (i = 0, j = a.length; i < j; i++) { - putValue(execute(r, x), a[i], r); - try { - execute(n.body, x); - } catch (e if e === BREAK && x.target === n) { - break; - } catch (e if e === CONTINUE && x.target === n) { - continue; - } - } - break; - - case DO: - do { - try { - execute(n.body, x); - } catch (e if e === BREAK && x.target === n) { - break; - } catch (e if e === CONTINUE && x.target === n) { - continue; - } - } while (getValue(execute(n.condition, x))); - break; - - case BREAK: - case CONTINUE: - x.target = n.target; - throw n.type; - - case TRY: - try { - execute(n.tryBlock, x); - } catch (e if e === THROW && (j = n.catchClauses.length)) { - e = x.result; - x.result = undefined; - for (i = 0; ; i++) { - if (i === j) { - x.result = e; - throw THROW; - } - t = n.catchClauses[i]; - x.scope = {object: {}, parent: x.scope}; - definitions.defineProperty(x.scope.object, t.varName, e, true); - try { - if (t.guard && !getValue(execute(t.guard, x))) - continue; - execute(t.block, x); - break; - } finally { - x.scope = x.scope.parent; - } - } - } finally { - if (n.finallyBlock) - execute(n.finallyBlock, x); - } - break; - - case THROW: - x.result = getValue(execute(n.exception, x)); - throw THROW; - - case RETURN: - // Check for returns with no return value - x.result = n.value ? getValue(execute(n.value, x)) : undefined; - throw RETURN; - - case WITH: - r = execute(n.object, x); - t = toObject(getValue(r), r, n.object); - x.scope = {object: t, parent: x.scope}; - try { - execute(n.body, x); - } finally { - x.scope = x.scope.parent; - } - break; - - case VAR: - case CONST: - c = n.children; - for (i = 0, j = c.length; i < j; i++) { - u = c[i].initializer; - if (!u) - continue; - t = c[i].name; - for (s = x.scope; s; s = s.parent) { - if (hasDirectProperty(s.object, t)) - break; - } - u = getValue(execute(u, x)); - if (n.type === CONST) - definitions.defineProperty(s.object, t, u, x.type !== EVAL_CODE, true); - else - s.object[t] = u; - } - break; - - case DEBUGGER: - throw "NYI: " + definitions.tokens[n.type]; - - case SEMICOLON: - if (n.expression) - x.result = getValue(execute(n.expression, x)); - break; - - case LABEL: - try { - execute(n.statement, x); - } catch (e if e === BREAK && x.target === n) { - } - break; - - case COMMA: - c = n.children; - for (i = 0, j = c.length; i < j; i++) - v = getValue(execute(c[i], x)); - break; - - case ASSIGN: - c = n.children; - r = execute(c[0], x); - t = n.assignOp; - if (t) - u = getValue(r); - v = getValue(execute(c[1], x)); - if (t) { - switch (t) { - case BITWISE_OR: v = u | v; break; - case BITWISE_XOR: v = u ^ v; break; - case BITWISE_AND: v = u & v; break; - case LSH: v = u << v; break; - case RSH: v = u >> v; break; - case URSH: v = u >>> v; break; - case PLUS: v = u + v; break; - case MINUS: v = u - v; break; - case MUL: v = u * v; break; - case DIV: v = u / v; break; - case MOD: v = u % v; break; - } - } - putValue(r, v, c[0]); - break; - - case HOOK: - c = n.children; - v = getValue(execute(c[0], x)) ? getValue(execute(c[1], x)) - : getValue(execute(c[2], x)); - break; - - case OR: - c = n.children; - v = getValue(execute(c[0], x)) || getValue(execute(c[1], x)); - break; - - case AND: - c = n.children; - v = getValue(execute(c[0], x)) && getValue(execute(c[1], x)); - break; - - case BITWISE_OR: - c = n.children; - v = getValue(execute(c[0], x)) | getValue(execute(c[1], x)); - break; - - case BITWISE_XOR: - c = n.children; - v = getValue(execute(c[0], x)) ^ getValue(execute(c[1], x)); - break; - - case BITWISE_AND: - c = n.children; - v = getValue(execute(c[0], x)) & getValue(execute(c[1], x)); - break; - - case EQ: - c = n.children; - v = getValue(execute(c[0], x)) == getValue(execute(c[1], x)); - break; - - case NE: - c = n.children; - v = getValue(execute(c[0], x)) != getValue(execute(c[1], x)); - break; - - case STRICT_EQ: - c = n.children; - v = getValue(execute(c[0], x)) === getValue(execute(c[1], x)); - break; - - case STRICT_NE: - c = n.children; - v = getValue(execute(c[0], x)) !== getValue(execute(c[1], x)); - break; - - case LT: - c = n.children; - v = getValue(execute(c[0], x)) < getValue(execute(c[1], x)); - break; - - case LE: - c = n.children; - v = getValue(execute(c[0], x)) <= getValue(execute(c[1], x)); - break; - - case GE: - c = n.children; - v = getValue(execute(c[0], x)) >= getValue(execute(c[1], x)); - break; - - case GT: - c = n.children; - v = getValue(execute(c[0], x)) > getValue(execute(c[1], x)); - break; - - case IN: - c = n.children; - v = getValue(execute(c[0], x)) in getValue(execute(c[1], x)); - break; - - case INSTANCEOF: - c = n.children; - t = getValue(execute(c[0], x)); - u = getValue(execute(c[1], x)); - if (isObject(u) && typeof u.__hasInstance__ === "function") - v = u.__hasInstance__(t); - else - v = t instanceof u; - break; - - case LSH: - c = n.children; - v = getValue(execute(c[0], x)) << getValue(execute(c[1], x)); - break; - - case RSH: - c = n.children; - v = getValue(execute(c[0], x)) >> getValue(execute(c[1], x)); - break; - - case URSH: - c = n.children; - v = getValue(execute(c[0], x)) >>> getValue(execute(c[1], x)); - break; - - case PLUS: - c = n.children; - v = getValue(execute(c[0], x)) + getValue(execute(c[1], x)); - break; - - case MINUS: - c = n.children; - v = getValue(execute(c[0], x)) - getValue(execute(c[1], x)); - break; - - case MUL: - c = n.children; - v = getValue(execute(c[0], x)) * getValue(execute(c[1], x)); - break; - - case DIV: - c = n.children; - v = getValue(execute(c[0], x)) / getValue(execute(c[1], x)); - break; - - case MOD: - c = n.children; - v = getValue(execute(c[0], x)) % getValue(execute(c[1], x)); - break; - - case DELETE: - t = execute(n.children[0], x); - v = !(t instanceof Reference) || delete t.base[t.propertyName]; - break; - - case VOID: - getValue(execute(n.children[0], x)); - break; - - case TYPEOF: - t = execute(n.children[0], x); - if (t instanceof Reference) - t = t.base ? t.base[t.propertyName] : undefined; - v = typeof t; - break; - - case NOT: - v = !getValue(execute(n.children[0], x)); - break; - - case BITWISE_NOT: - v = ~getValue(execute(n.children[0], x)); - break; - - case UNARY_PLUS: - v = +getValue(execute(n.children[0], x)); - break; - - case UNARY_MINUS: - v = -getValue(execute(n.children[0], x)); - break; - - case INCREMENT: - case DECREMENT: - t = execute(n.children[0], x); - u = Number(getValue(t)); - if (n.postfix) - v = u; - putValue(t, (n.type === INCREMENT) ? ++u : --u, n.children[0]); - if (!n.postfix) - v = u; - break; - - case DOT: - c = n.children; - r = execute(c[0], x); - t = getValue(r); - u = c[1].value; - v = new Reference(toObject(t, r, c[0]), u, n); - break; - - case INDEX: - c = n.children; - r = execute(c[0], x); - t = getValue(r); - u = getValue(execute(c[1], x)); - v = new Reference(toObject(t, r, c[0]), String(u), n); - break; - - case LIST: - // Curse ECMA for specifying that arguments is not an Array object! - v = {}; - c = n.children; - for (i = 0, j = c.length; i < j; i++) { - u = getValue(execute(c[i], x)); - definitions.defineProperty(v, i, u, false, false, true); - } - definitions.defineProperty(v, "length", i, false, false, true); - break; - - case CALL: - c = n.children; - r = execute(c[0], x); - a = execute(c[1], x); - f = getValue(r); - if (isPrimitive(f) || typeof f.__call__ !== "function") { - throw new TypeError(r + " is not callable", c[0].filename, c[0].lineno); - } - t = (r instanceof Reference) ? r.base : null; - if (t instanceof Activation) - t = null; - v = f.__call__(t, a, x); - break; - - case NEW: - case NEW_WITH_ARGS: - c = n.children; - r = execute(c[0], x); - f = getValue(r); - if (n.type === NEW) { - a = {}; - definitions.defineProperty(a, "length", 0, false, false, true); - } else { - a = execute(c[1], x); - } - if (isPrimitive(f) || typeof f.__construct__ !== "function") { - throw new TypeError(r + " is not a constructor", c[0].filename, c[0].lineno); - } - v = f.__construct__(a, x); - break; - - case ARRAY_INIT: - v = []; - c = n.children; - for (i = 0, j = c.length; i < j; i++) { - if (c[i]) - v[i] = getValue(execute(c[i], x)); - } - v.length = j; - break; - - case OBJECT_INIT: - v = {}; - c = n.children; - for (i = 0, j = c.length; i < j; i++) { - t = c[i]; - if (t.type === PROPERTY_INIT) { - let c2 = t.children; - v[c2[0].value] = getValue(execute(c2[1], x)); - } else { - f = newFunction(t, x); - u = (t.type === GETTER) ? '__defineGetter__' - : '__defineSetter__'; - v[u](t.name, thunk(f, x)); - } - } - break; - - case NULL: - v = null; - break; - - case THIS: - v = x.thisObject; - break; - - case TRUE: - v = true; - break; - - case FALSE: - v = false; - break; - - case IDENTIFIER: - if (typeof n.resolve !== "function") - throw n; - - // Identifiers with forward pointers that weren't intervened can't be - // lvalues, so we safely get the cached value directly. - var resolved = n.resolve(); - - if (n.forward && !resolved.intervened && - !(resolved.type == FUNCTION && - resolved.functionForm == parser.DECLARED_FORM)) { - v = resolved.v; - break; - } - - for (s = x.scope; s; s = s.parent) { - if (n.value in s.object) - break; - } - v = new Reference(s && s.object, n.value, n); - break; - - case NUMBER: - case STRING: - case REGEXP: - v = n.value; - break; - - case GROUP: - v = execute(n.children[0], x); - break; - - default: - throw "PANIC: unknown operation " + n.type + ": " + uneval(n); - } - - if (n.backwards) { - n.v = v; - } - evaluatePhis(n, v); - - return v; - } - - function Activation(f, a) { - for (var i = 0, j = f.params.length; i < j; i++) - definitions.defineProperty(this, f.params[i], a[i], true); - definitions.defineProperty(this, "arguments", a, true); - } - - // Null Activation.prototype's proto slot so that Object.prototype.* does not - // pollute the scope of heavyweight functions. Also delete its 'constructor' - // property so that it doesn't pollute function scopes. - - Activation.prototype.__proto__ = null; - delete Activation.prototype.constructor; - - function FunctionObject(node, scope) { - this.node = node; - this.scope = scope; - definitions.defineProperty(this, "length", node.params.length, true, true, true); - var proto = {}; - definitions.defineProperty(this, "prototype", proto, true); - definitions.defineProperty(proto, "constructor", this, false, false, true); - } - - function getPropertyDescriptor(obj, name) { - while (obj) { - if (({}).hasOwnProperty.call(obj, name)) - return Object.getOwnPropertyDescriptor(obj, name); - obj = Object.getPrototypeOf(obj); - } - } - - function getOwnProperties(obj) { - var map = {}; - for (var name in Object.getOwnPropertyNames(obj)) - map[name] = Object.getOwnPropertyDescriptor(obj, name); - return map; - } - - // Returns a new function wrapped with a Proxy. - function newFunction(n, x) { - var fobj = new FunctionObject(n, x.scope); - var handler = definitions.makePassthruHandler(fobj); - var p = Proxy.createFunction(handler, - function() { return fobj.__call__(this, arguments, x); }, - function() { return fobj.__construct__(arguments, x); }); - return p; - } - - var FOp = FunctionObject.prototype = { - - // Internal methods. - __call__: function (t, a, x) { - var x2 = new ExecutionContext(FUNCTION_CODE); - x2.thisObject = t || global; - x2.caller = x; - x2.callee = this; - definitions.defineProperty(a, "callee", this, false, false, true); - var f = this.node; - x2.scope = {object: new Activation(f, a), parent: this.scope}; - - try { - x2.execute(f.body); - } catch (e if e === RETURN) { - return x2.result; - } - return undefined; - }, - - __construct__: function (a, x) { - var o = new Object; - var p = this.prototype; - if (isObject(p)) - o.__proto__ = p; - // else o.__proto__ defaulted to Object.prototype - - var v = this.__call__(o, a, x); - if (isObject(v)) - return v; - return o; - }, - - __hasInstance__: function (v) { - if (isPrimitive(v)) - return false; - var p = this.prototype; - if (isPrimitive(p)) { - throw new TypeError("'prototype' property is not an object", - this.node.filename, this.node.lineno); - } - var o; - while ((o = v.__proto__)) { - if (o === p) - return true; - v = o; - } - return false; - }, - - // Standard methods. - toString: function () { - return this.node.getSource(); - }, - - apply: function (t, a) { - // Curse ECMA again! - if (typeof this.__call__ !== "function") { - throw new TypeError("Function.prototype.apply called on" + - " uncallable object"); - } - - if (t === undefined || t === null) - t = global; - else if (typeof t !== "object") - t = toObject(t, t); - - if (a === undefined || a === null) { - a = {}; - definitions.defineProperty(a, "length", 0, false, false, true); - } else if (a instanceof Array) { - var v = {}; - for (var i = 0, j = a.length; i < j; i++) - definitions.defineProperty(v, i, a[i], false, false, true); - definitions.defineProperty(v, "length", i, false, false, true); - a = v; - } else if (!(a instanceof Object)) { - // XXX check for a non-arguments object - throw new TypeError("Second argument to Function.prototype.apply" + - " must be an array or arguments object", - this.node.filename, this.node.lineno); - } - - return this.__call__(t, a, ExecutionContext.current); - }, - - call: function (t) { - // Curse ECMA a third time! - var a = Array.prototype.splice.call(arguments, 1); - return this.apply(t, a); - } - }; - - // Connect Function.prototype and Function.prototype.constructor in global. - reflectClass('Function', FOp); - - // Help native and host-scripted functions be like FunctionObjects. - var Fp = Function.prototype; - var REp = RegExp.prototype; - - if (!('__call__' in Fp)) { - definitions.defineProperty(Fp, "__call__", - function (t, a, x) { - // Curse ECMA yet again! - a = Array.prototype.splice.call(a, 0, a.length); - return this.apply(t, a); - }, true, true, true); - definitions.defineProperty(REp, "__call__", - function (t, a, x) { - a = Array.prototype.splice.call(a, 0, a.length); - return this.exec.apply(this, a); - }, true, true, true); - definitions.defineProperty(Fp, "__construct__", - function (a, x) { - a = Array.prototype.splice.call(a, 0, a.length); - switch (a.length) { - case 0: - return new this(); - case 1: - return new this(a[0]); - case 2: - return new this(a[0], a[1]); - case 3: - return new this(a[0], a[1], a[2]); - default: - var argStr = ""; - for (var i=0; i "); - var line = readline(); - // If readline receives EOF it returns null. - if (line === null) { - print(""); - break; - } - try { - execute(parser.parse(b, line, "stdin", 1), x); - display(x.result); - } catch (e if e === THROW) { - print("uncaught exception: " + string(x.result)); - } catch (e if e === END) { - break; - } catch (e if e instanceof SyntaxError) { - print(e.toString()); - } catch (e) { - print("internal Narcissus error"); - if (typeof e === "object" && e.stack) { - let st = String(e.stack).split(/\n/); - // beautify stack trace: - // - eliminate blank lines - // - sanitize confusing trace lines for getters and js -e expressions - // - simplify source location reporting - // - indent - for (let i = 0; i < st.length; i++) { - let line = st[i].trim(); - if (line) { - line = line.replace(/^(\(\))?@/, "@"); - line = line.replace(/@(.*\/|\\)?([^\/\\]+:[0-9]+)/, " at $2"); - print(" in " + line); - } - } - } - throw e; - } - } - ExecutionContext.current = null; - } - - return { - global: global, - evaluate: evaluate, - repl: repl - }; - -}()); diff --git a/js/narcissus/jslex.js b/js/narcissus/jslex.js deleted file mode 100644 index 10d6a8e5df06..000000000000 --- a/js/narcissus/jslex.js +++ /dev/null @@ -1,470 +0,0 @@ -/* vim: set sw=4 ts=4 et tw=78: */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Narcissus JavaScript engine. - * - * The Initial Developer of the Original Code is - * Brendan Eich . - * Portions created by the Initial Developer are Copyright (C) 2004 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -/* - * Narcissus - JS implemented in JS. - * - * Lexical scanner. - */ - -Narcissus.lexer = (function() { - - var definitions = Narcissus.definitions; - - // Set constants in the local scope. - eval(definitions.consts); - - // Build up a trie of operator tokens. - var opTokens = {}; - for (var op in definitions.opTypeNames) { - if (op === '\n' || op === '.') - continue; - - var node = opTokens; - for (var i = 0; i < op.length; i++) { - var ch = op[i]; - if (!(ch in node)) - node[ch] = {}; - node = node[ch]; - node.op = op; - } - } - - /* - * Tokenizer :: (file ptr, path, line number) -> Tokenizer - */ - function Tokenizer(s, f, l) { - this.cursor = 0; - this.source = String(s); - this.tokens = []; - this.tokenIndex = 0; - this.lookahead = 0; - this.scanNewlines = false; - this.filename = f || ""; - this.lineno = l || 1; - } - - Tokenizer.prototype = { - get done() { - // We need to set scanOperand to true here because the first thing - // might be a regexp. - return this.peek(true) === END; - }, - - get token() { - return this.tokens[this.tokenIndex]; - }, - - match: function (tt, scanOperand) { - return this.get(scanOperand) === tt || this.unget(); - }, - - mustMatch: function (tt) { - if (!this.match(tt)) { - throw this.newSyntaxError("Missing " + - definitions.tokens[tt].toLowerCase()); - } - return this.token; - }, - - peek: function (scanOperand) { - var tt, next; - if (this.lookahead) { - next = this.tokens[(this.tokenIndex + this.lookahead) & 3]; - tt = (this.scanNewlines && next.lineno !== this.lineno) - ? NEWLINE - : next.type; - } else { - tt = this.get(scanOperand); - this.unget(); - } - return tt; - }, - - peekOnSameLine: function (scanOperand) { - this.scanNewlines = true; - var tt = this.peek(scanOperand); - this.scanNewlines = false; - return tt; - }, - - // Eats comments and whitespace. - skip: function () { - var input = this.source; - for (;;) { - var ch = input[this.cursor++]; - var next = input[this.cursor]; - if (ch === '\n' && !this.scanNewlines) { - this.lineno++; - } else if (ch === '/' && next === '*') { - this.cursor++; - for (;;) { - ch = input[this.cursor++]; - if (ch === undefined) - throw this.newSyntaxError("Unterminated comment"); - - if (ch === '*') { - next = input[this.cursor]; - if (next === '/') { - this.cursor++; - break; - } - } else if (ch === '\n') { - this.lineno++; - } - } - } else if (ch === '/' && next === '/') { - this.cursor++; - for (;;) { - ch = input[this.cursor++]; - if (ch === undefined) - return; - - if (ch === '\n') { - this.lineno++; - break; - } - } - } else if (ch !== ' ' && ch !== '\t') { - this.cursor--; - return; - } - } - }, - - // Lexes the exponential part of a number, if present. Returns true iff an - // exponential part was found. - lexExponent: function() { - var input = this.source; - var next = input[this.cursor]; - if (next === 'e' || next === 'E') { - this.cursor++; - ch = input[this.cursor++]; - if (ch === '+' || ch === '-') - ch = input[this.cursor++]; - - if (ch < '0' || ch > '9') - throw this.newSyntaxError("Missing exponent"); - - do { - ch = input[this.cursor++]; - } while (ch >= '0' && ch <= '9'); - this.cursor--; - - return true; - } - - return false; - }, - - lexZeroNumber: function (ch) { - var token = this.token, input = this.source; - token.type = NUMBER; - - ch = input[this.cursor++]; - if (ch === '.') { - do { - ch = input[this.cursor++]; - } while (ch >= '0' && ch <= '9'); - this.cursor--; - - this.lexExponent(); - token.value = parseFloat(token.start, this.cursor); - } else if (ch === 'x' || ch === 'X') { - do { - ch = input[this.cursor++]; - } while ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || - (ch >= 'A' && ch <= 'F')); - this.cursor--; - - token.value = parseInt(input.substring(token.start, this.cursor)); - } else if (ch >= '0' && ch <= '7') { - do { - ch = input[this.cursor++]; - } while (ch >= '0' && ch <= '7'); - this.cursor--; - - token.value = parseInt(input.substring(token.start, this.cursor)); - } else { - this.cursor--; - this.lexExponent(); // 0E1, &c. - token.value = 0; - } - }, - - lexNumber: function (ch) { - var token = this.token, input = this.source; - token.type = NUMBER; - - var floating = false; - do { - ch = input[this.cursor++]; - if (ch === '.' && !floating) { - floating = true; - ch = input[this.cursor++]; - } - } while (ch >= '0' && ch <= '9'); - - this.cursor--; - - var exponent = this.lexExponent(); - floating = floating || exponent; - - var str = input.substring(token.start, this.cursor); - token.value = floating ? parseFloat(str) : parseInt(str); - }, - - lexDot: function (ch) { - var token = this.token, input = this.source; - var next = input[this.cursor]; - if (next >= '0' && next <= '9') { - do { - ch = input[this.cursor++]; - } while (ch >= '0' && ch <= '9'); - this.cursor--; - - this.lexExponent(); - - token.type = NUMBER; - token.value = parseFloat(token.start, this.cursor); - } else { - token.type = DOT; - token.assignOp = null; - token.value = '.'; - } - }, - - lexString: function (ch) { - var token = this.token, input = this.source; - token.type = STRING; - - var hasEscapes = false; - var delim = ch; - ch = input[this.cursor++]; - while (ch !== delim) { - if (ch === '\\') { - hasEscapes = true; - this.cursor++; - } - ch = input[this.cursor++]; - } - - token.value = (hasEscapes) - ? eval(input.substring(token.start, this.cursor)) - : input.substring(token.start + 1, this.cursor - 1); - }, - - lexRegExp: function (ch) { - var token = this.token, input = this.source; - token.type = REGEXP; - - do { - ch = input[this.cursor++]; - if (ch === '\\') { - this.cursor++; - } else if (ch === '[') { - do { - if (ch === undefined) - throw this.newSyntaxError("Unterminated character class"); - - if (ch === '\\') - this.cursor++; - - ch = input[this.cursor++]; - } while (ch !== ']'); - } else if (ch === undefined) { - throw this.newSyntaxError("Unterminated regex"); - } - } while (ch !== '/'); - - do { - ch = input[this.cursor++]; - } while (ch >= 'a' && ch <= 'z'); - - this.cursor--; - - token.value = eval(input.substring(token.start, this.cursor)); - }, - - lexOp: function (ch) { - var token = this.token, input = this.source; - - // A bit ugly, but it seems wasteful to write a trie lookup routine for - // only 3 characters... - var node = opTokens[ch]; - var next = input[this.cursor]; - if (next in node) { - node = node[next]; - this.cursor++; - next = input[this.cursor]; - if (next in node) { - node = node[next]; - this.cursor++; - next = input[this.cursor]; - } - } - - var op = node.op; - if (definitions.assignOps[op] && input[this.cursor] === '=') { - this.cursor++; - token.type = ASSIGN; - token.assignOp = definitions.tokenIds[definitions.opTypeNames[op]]; - op += '='; - } else { - token.type = definitions.tokenIds[definitions.opTypeNames[op]]; - token.assignOp = null; - } - - token.value = op; - }, - - // FIXME: Unicode escape sequences - // FIXME: Unicode identifiers - lexIdent: function (ch) { - var token = this.token, input = this.source; - - do { - ch = input[this.cursor++]; - } while ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || - (ch >= '0' && ch <= '9') || ch === '$' || ch === '_'); - - this.cursor--; // Put the non-word character back. - - var id = input.substring(token.start, this.cursor); - token.type = definitions.keywords[id] || IDENTIFIER; - token.value = id; - }, - - /* - * Tokenizer.get :: void -> token type - * - * Consumes input *only* if there is no lookahead. - * Dispatch to the appropriate lexing function depending on the input. - */ - get: function (scanOperand) { - var token; - while (this.lookahead) { - --this.lookahead; - this.tokenIndex = (this.tokenIndex + 1) & 3; - token = this.tokens[this.tokenIndex]; - if (token.type !== NEWLINE || this.scanNewlines) - return token.type; - } - - this.skip(); - - this.tokenIndex = (this.tokenIndex + 1) & 3; - token = this.tokens[this.tokenIndex]; - if (!token) - this.tokens[this.tokenIndex] = token = {}; - - var input = this.source; - if (this.cursor === input.length) - return token.type = END; - - token.start = this.cursor; - token.lineno = this.lineno; - - var ch = input[this.cursor++]; - if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || - ch === '$' || ch === '_') { - this.lexIdent(ch); - } else if (scanOperand && ch === '/') { - this.lexRegExp(ch); - } else if (ch in opTokens) { - this.lexOp(ch); - } else if (ch === '.') { - this.lexDot(ch); - } else if (ch >= '1' && ch <= '9') { - this.lexNumber(ch); - } else if (ch === '0') { - this.lexZeroNumber(ch); - } else if (ch === '"' || ch === "'") { - this.lexString(ch); - } else if (this.scanNewlines && ch === '\n') { - token.type = NEWLINE; - token.value = '\n'; - this.lineno++; - } else { - throw this.newSyntaxError("Illegal token"); - } - - token.end = this.cursor; - return token.type; - }, - - /* - * Tokenizer.unget :: void -> undefined - * - * Match depends on unget returning undefined. - */ - unget: function () { - if (++this.lookahead === 4) throw "PANIC: too much lookahead!"; - this.tokenIndex = (this.tokenIndex - 1) & 3; - }, - - newSyntaxError: function (m) { - var e = new SyntaxError(m, this.filename, this.lineno); - e.source = this.source; - e.cursor = this.cursor; - return e; - }, - - save: function () { - return { - cursor: this.cursor, - tokenIndex: this.tokenIndex, - tokens: this.tokens.slice(), - lookahead: this.lookahead, - scanNewlines: this.scanNewlines, - lineno: this.lineno - }; - }, - - rewind: function(point) { - this.cursor = point.cursor; - this.tokenIndex = point.tokenIndex; - this.tokens = point.tokens.slice(); - this.lookahead = point.lookahead; - this.scanNewline = point.scanNewline; - this.lineno = point.lineno; - } - }; - - return { Tokenizer: Tokenizer }; - -}()); diff --git a/js/narcissus/jsparse.js b/js/narcissus/jsparse.js deleted file mode 100644 index c3182f3f740b..000000000000 --- a/js/narcissus/jsparse.js +++ /dev/null @@ -1,2400 +0,0 @@ -/* -*- Mode: JS; tab-width: 4; indent-tabs-mode: nil; -*- - * vim: set sw=4 ts=4 et tw=78: - * ***** BEGIN LICENSE BLOCK ***** - * - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Narcissus JavaScript engine. - * - * The Initial Developer of the Original Code is - * Brendan Eich . - * Portions created by the Initial Developer are Copyright (C) 2004 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -/* - * Narcissus - JS implemented in JS. - * - * Parser. - */ - -Narcissus.parser = (function() { - - var lexer = Narcissus.lexer; - var definitions = Narcissus.definitions; - - // Set constants in the local scope. - eval(definitions.consts); - - /* - * Function.prototype.bind is not yet implemented in many browsers. - * The following definition will be removed when it is. - * - * Similar to Prototype's implementation. - */ - - function bindMethod(method, context) { - if (arguments.length < 3 && arguments[0] === undefined) - return method; - var slice = Array.prototype.slice; - var args = slice.call(arguments, 2); - // Optimization for when there's no currying. - if (args.length === 0) { - return function() { - return method.apply(context, arguments); - } - } - - return function() { - var a = slice.call(args, 0); - for (var i = 0, j = arguments.length; i < j; i++) { - a.push(arguments[i]); - } - return method.apply(context, a); - } - } - - function bindSubBuilders(builder, proto) { - for (var ns in proto) { - var unbound = proto[ns]; - // We do not want to bind functions like setHoists. - if (typeof unbound !== "object") - continue; - - // We store the bound sub-builder as builder's own property - // so that we can have multiple builders at the same time. - var bound = builder[ns] = {}; - for (var m in unbound) { - bound[m] = bindMethod(unbound[m], builder); - } - } - } - - /* - * The vanilla AST builder. - */ - - function DefaultBuilder() { - bindSubBuilders(this, DefaultBuilder.prototype); - } - - function pushDestructuringVarDecls(n, x) { - for (var i in n) { - var sub = n[i]; - if (sub.type === IDENTIFIER) { - x.varDecls.push(sub); - } else { - pushDestructuringVarDecls(sub, x); - } - } - } - - function mkBinopBuilder(type) { - return { - build: !type ? function(t) { return new Node(t); } - : function(t) { return new Node(t, type); }, - addOperand: function(n, n2) { n.push(n2); }, - finish: function(n) { } - }; - } - - DefaultBuilder.prototype = { - IF: { - build: function(t) { - return new Node(t, IF); - }, - - setCondition: function(n, e) { - n.condition = e; - }, - - setThenPart: function(n, s) { - n.thenPart = s; - }, - - setElsePart: function(n, s) { - n.elsePart = s; - }, - - finish: function(n) { - } - }, - - SWITCH: { - build: function(t) { - var n = new Node(t, SWITCH); - n.cases = []; - n.defaultIndex = -1; - return n; - }, - - setDiscriminant: function(n, e) { - n.discriminant = e; - }, - - setDefaultIndex: function(n, i) { - n.defaultIndex = i; - }, - - addCase: function(n, n2) { - n.cases.push(n2); - }, - - finish: function(n) { - } - }, - - CASE: { - build: function(t) { - return new Node(t, CASE); - }, - - setLabel: function(n, e) { - n.caseLabel = e; - }, - - initializeStatements: function(n, t) { - n.statements = new Node(t, BLOCK); - }, - - addStatement: function(n, s) { - n.statements.push(s); - }, - - finish: function(n) { - } - }, - - DEFAULT: { - build: function(t, p) { - return new Node(t, DEFAULT); - }, - - initializeStatements: function(n, t) { - n.statements = new Node(t, BLOCK); - }, - - addStatement: function(n, s) { - n.statements.push(s); - }, - - finish: function(n) { - } - }, - - FOR: { - build: function(t) { - var n = new Node(t, FOR); - n.isLoop = true; - n.isEach = false; - return n; - }, - - rebuildForEach: function(n) { - n.isEach = true; - }, - - // NB. This function is called after rebuildForEach, if that's called - // at all. - rebuildForIn: function(n) { - n.type = FOR_IN; - }, - - setCondition: function(n, e) { - n.condition = e; - }, - - setSetup: function(n, e) { - n.setup = e || null; - }, - - setUpdate: function(n, e) { - n.update = e; - }, - - setObject: function(n, e) { - n.object = e; - }, - - setIterator: function(n, e, e2) { - n.iterator = e; - n.varDecl = e2; - }, - - setBody: function(n, s) { - n.body = s; - }, - - finish: function(n) { - } - }, - - WHILE: { - build: function(t) { - var n = new Node(t, WHILE); - n.isLoop = true; - return n; - }, - - setCondition: function(n, e) { - n.condition = e; - }, - - setBody: function(n, s) { - n.body = s; - }, - - finish: function(n) { - } - }, - - DO: { - build: function(t) { - var n = new Node(t, DO); - n.isLoop = true; - return n; - }, - - setCondition: function(n, e) { - n.condition = e; - }, - - setBody: function(n, s) { - n.body = s; - }, - - finish: function(n) { - } - }, - - BREAK: { - build: function(t) { - return new Node(t, BREAK); - }, - - setLabel: function(n, v) { - n.label = v; - }, - - setTarget: function(n, n2) { - n.target = n2; - }, - - finish: function(n) { - } - }, - - CONTINUE: { - build: function(t) { - return new Node(t, CONTINUE); - }, - - setLabel: function(n, v) { - n.label = v; - }, - - setTarget: function(n, n2) { - n.target = n2; - }, - - finish: function(n) { - } - }, - - TRY: { - build: function(t) { - var n = new Node(t, TRY); - n.catchClauses = []; - return n; - }, - - setTryBlock: function(n, s) { - n.tryBlock = s; - }, - - addCatch: function(n, n2) { - n.catchClauses.push(n2); - }, - - finishCatches: function(n) { - }, - - setFinallyBlock: function(n, s) { - n.finallyBlock = s; - }, - - finish: function(n) { - } - }, - - CATCH: { - build: function(t) { - var n = new Node(t, CATCH); - n.guard = null; - return n; - }, - - setVarName: function(n, v) { - n.varName = v; - }, - - setGuard: function(n, e) { - n.guard = e; - }, - - setBlock: function(n, s) { - n.block = s; - }, - - finish: function(n) { - } - }, - - THROW: { - build: function(t) { - return new Node(t, THROW); - }, - - setException: function(n, e) { - n.exception = e; - }, - - finish: function(n) { - } - }, - - RETURN: { - build: function(t) { - var n = new Node(t, RETURN); - n.value = undefined; - return n; - }, - - setValue: function(n, e) { - n.value = e; - }, - - finish: function(n) { - } - }, - - YIELD: { - build: function(t) { - return new Node(t, YIELD); - }, - - setValue: function(n, e) { - n.value = e; - }, - - finish: function(n) { - } - }, - - GENERATOR: { - build: function(t) { - return new Node(t, GENERATOR); - }, - - setExpression: function(n, e) { - n.expression = e; - }, - - setTail: function(n, n2) { - n.tail = n2; - }, - - finish: function(n) { - } - }, - - WITH: { - build: function(t) { - return new Node(t, WITH); - }, - - setObject: function(n, e) { - n.object = e; - }, - - setBody: function(n, s) { - n.body = s; - }, - - finish: function(n) { - } - }, - - DEBUGGER: { - build: function(t) { - return new Node(t, DEBUGGER); - } - }, - - SEMICOLON: { - build: function(t) { - return new Node(t, SEMICOLON); - }, - - setExpression: function(n, e) { - n.expression = e; - }, - - finish: function(n) { - } - }, - - LABEL: { - build: function(t) { - return new Node(t, LABEL); - }, - - setLabel: function(n, e) { - n.label = e; - }, - - setStatement: function(n, s) { - n.statement = s; - }, - - finish: function(n) { - } - }, - - FUNCTION: { - build: function(t) { - var n = new Node(t); - if (n.type !== FUNCTION) - n.type = (n.value === "get") ? GETTER : SETTER; - n.params = []; - return n; - }, - - setName: function(n, v) { - n.name = v; - }, - - addParam: function(n, v) { - n.params.push(v); - }, - - setBody: function(n, s) { - n.body = s; - }, - - hoistVars: function(x) { - }, - - finish: function(n, x) { - } - }, - - VAR: { - build: function(t) { - return new Node(t, VAR); - }, - - addDestructuringDecl: function(n, n2, x) { - n.push(n2); - pushDestructuringVarDecls(n2.name.destructuredNames, x); - }, - - addDecl: function(n, n2, x) { - n.push(n2); - x.varDecls.push(n2); - }, - - finish: function(n) { - } - }, - - CONST: { - build: function(t) { - return new Node(t, CONST); - }, - - addDestructuringDecl: function(n, n2, x) { - n.push(n2); - pushDestructuringVarDecls(n2.name.destructuredNames, x); - }, - - addDecl: function(n, n2, x) { - n.push(n2); - x.varDecls.push(n2); - }, - - finish: function(n) { - } - }, - - LET: { - build: function(t) { - return new Node(t, LET); - }, - - addDestructuringDecl: function(n, n2, x) { - n.push(n2); - pushDestructuringVarDecls(n2.name.destructuredNames, x); - }, - - addDecl: function(n, n2, x) { - n.push(n2); - x.varDecls.push(n2); - }, - - finish: function(n) { - } - }, - - DECL: { - build: function(t) { - return new Node(t, IDENTIFIER); - }, - - setName: function(n, v) { - n.name = v; - }, - - setInitializer: function(n, e) { - n.initializer = e; - }, - - setReadOnly: function(n, b) { - n.readOnly = b; - }, - - finish: function(n) { - } - }, - - LET_BLOCK: { - build: function(t) { - var n = new Node(t, LET_BLOCK); - n.varDecls = []; - return n; - }, - - setVariables: function(n, n2) { - n.variables = n2; - }, - - setExpression: function(n, e) { - n.expression = e; - }, - - setBlock: function(n, s) { - n.block = s; - }, - - finish: function(n) { - } - }, - - BLOCK: { - build: function(t, id) { - var n = new Node(t, BLOCK); - n.varDecls = []; - n.id = id; - return n; - }, - - hoistLets: function(n) { - }, - - addStatement: function(n, n2) { - n.push(n2); - }, - - finish: function(n) { - } - }, - - ASSIGN: { - build: function(t) { - return new Node(t, ASSIGN); - }, - - addOperand: function(n, n2) { - n.push(n2); - }, - - setAssignOp: function(n, o) { - n.assignOp = o; - }, - - finish: function(n) { - } - }, - - HOOK: { - build: function(t) { - return new Node(t, HOOK); - }, - - setCondition: function(n, e) { - n.children[0] = e; - }, - - setThenPart: function(n, n2) { - n.children[1] = n2; - }, - - setElsePart: function(n, n2) { - n.children[2] = n2; - }, - - finish: function(n) { - } - }, - - OR: mkBinopBuilder(OR), - AND: mkBinopBuilder(AND), - BITWISE_OR: mkBinopBuilder(BITWISE_OR), - BITWISE_XOR: mkBinopBuilder(BITWISE_XOR), - BITWISE_AND: mkBinopBuilder(BITWISE_AND), - EQUALITY: mkBinopBuilder(), // EQ | NE | STRICT_EQ | STRICT_NE - RELATIONAL: mkBinopBuilder(), // LT | LE | GE | GT - SHIFT: mkBinopBuilder(), // LSH | RSH | URSH - ADD: mkBinopBuilder(), // PLUS | MINUS - MULTIPLY: mkBinopBuilder(), // MUL | DIV | MOD - - UNARY: { - // DELETE | VOID | TYPEOF | NOT | BITWISE_NOT - // UNARY_PLUS | UNARY_MINUS | INCREMENT | DECREMENT - build: function(t) { - if (t.token.type === PLUS) - t.token.type = UNARY_PLUS; - else if (t.token.type === MINUS) - t.token.type = UNARY_MINUS; - return new Node(t); - }, - - addOperand: function(n, n2) { - n.push(n2); - }, - - setPostfix: function(n) { - n.postfix = true; - }, - - finish: function(n) { - } - }, - - MEMBER: { - // NEW | DOT | INDEX - build: function(t, tt) { - return new Node(t, tt); - }, - - rebuildNewWithArgs: function(n) { - n.type = NEW_WITH_ARGS; - }, - - addOperand: function(n, n2) { - n.push(n2); - }, - - finish: function(n) { - } - }, - - PRIMARY: { - build: function(t, tt) { - // NULL | THIS | TRUE | FALSE | IDENTIFIER | NUMBER - // STRING | REGEXP. - return new Node(t, tt); - }, - - finish: function(n) { - } - }, - - ARRAY_INIT: { - build: function(t) { - return new Node(t, ARRAY_INIT); - }, - - addElement: function(n, n2) { - n.push(n2); - }, - - finish: function(n) { - } - }, - - ARRAY_COMP: { - build: function(t) { - return new Node(t, ARRAY_COMP); - }, - - setExpression: function(n, e) { - n.expression = e - }, - - setTail: function(n, n2) { - n.tail = n2; - }, - - finish: function(n) { - } - }, - - COMP_TAIL: { - build: function(t) { - return new Node(t, COMP_TAIL); - }, - - setGuard: function(n, e) { - n.guard = e; - }, - - addFor: function(n, n2) { - n.push(n2); - }, - - finish: function(n) { - } - }, - - OBJECT_INIT: { - build: function(t) { - return new Node(t, OBJECT_INIT); - }, - - addProperty: function(n, n2) { - n.push(n2); - }, - - finish: function(n) { - } - }, - - PROPERTY_NAME: { - build: function(t) { - return new Node(t, IDENTIFIER); - }, - - finish: function(n) { - } - }, - - PROPERTY_INIT: { - build: function(t) { - return new Node(t, PROPERTY_INIT); - }, - - addOperand: function(n, n2) { - n.push(n2); - }, - - finish: function(n) { - } - }, - - COMMA: { - build: function(t) { - return new Node(t, COMMA); - }, - - addOperand: function(n, n2) { - n.push(n2); - }, - - finish: function(n) { - } - }, - - LIST: { - build: function(t) { - return new Node(t, LIST); - }, - - addOperand: function(n, n2) { - n.push(n2); - }, - - finish: function(n) { - } - }, - - setHoists: function(id, vds) { - } - }; - - function StaticContext(inFunction, builder) { - this.inFunction = inFunction; - this.hasEmptyReturn = false; - this.hasReturnWithValue = false; - this.isGenerator = false; - this.blockId = 0; - this.builder = builder; - this.stmtStack = []; - this.funDecls = []; - this.varDecls = []; - } - - StaticContext.prototype = { - bracketLevel: 0, - curlyLevel: 0, - parenLevel: 0, - hookLevel: 0, - ecma3OnlyMode: false, - inForLoopInit: false, - }; - - /* - * Script :: (tokenizer, compiler context) -> node - * - * Parses the toplevel and function bodies. - */ - function Script(t, x) { - var n = Statements(t, x); - n.type = SCRIPT; - n.funDecls = x.funDecls; - n.varDecls = x.varDecls; - return n; - } - - // Node extends Array, which we extend slightly with a top-of-stack method. - definitions.defineProperty(Array.prototype, "top", - function() { - return this.length && this[this.length-1]; - }, false, false, true); - - /* - * Node :: (tokenizer, optional type) -> node - */ - function Node(t, type) { - var token = t.token; - if (token) { - this.type = type || token.type; - this.value = token.value; - this.lineno = token.lineno; - // Start & end are file positions for error handling. - this.start = token.start; - this.end = token.end; - } else { - this.type = type; - this.lineno = t.lineno; - } - // Nodes use a tokenizer for debugging (getSource, filename getter). - this.tokenizer = t; - - this.children = []; - for (var i = 2; i < arguments.length; i++) - this.push(arguments[i]); - } - - var Np = Node.prototype = {}; - Np.constructor = Node; - Np.toSource = Object.prototype.toSource; - - // Always use push to add operands to an expression, to update start and end. - Np.push = function (kid) { - // kid can be null e.g. [1, , 2]. - if (kid !== null) { - if (kid.start < this.start) - this.start = kid.start; - if (this.end < kid.end) - this.end = kid.end; - } - return this.children.push(kid); - } - - Node.indentLevel = 0; - - function tokenstr(tt) { - var t = definitions.tokens[tt]; - return /^\W/.test(t) ? definitions.opTypeNames[t] : t.toUpperCase(); - } - - Np.toString = function () { - var a = []; - for (var i in this) { - if (this.hasOwnProperty(i) && i !== 'type' && i !== 'target') - a.push({id: i, value: this[i]}); - } - a.sort(function (a,b) { return (a.id < b.id) ? -1 : 1; }); - const INDENTATION = " "; - var n = ++Node.indentLevel; - var s = "{\n" + INDENTATION.repeat(n) + "type: " + tokenstr(this.type); - for (i = 0; i < a.length; i++) - s += ",\n" + INDENTATION.repeat(n) + a[i].id + ": " + a[i].value; - n = --Node.indentLevel; - s += "\n" + INDENTATION.repeat(n) + "}"; - return s; - } - - Np.getSource = function () { - return this.tokenizer.source.slice(this.start, this.end); - }; - - definitions.defineGetter(Np, "filename", - function() { - return this.tokenizer.filename; - }); - - definitions.defineGetter(Np, "length", - function() { - throw new Error("Node.prototype.length is gone; use n.children.length instead"); - }); - - definitions.defineProperty(String.prototype, "repeat", - function(n) { - var s = "", t = this + s; - while (--n >= 0) - s += t; - return s; - }, false, false, true); - - // Statement stack and nested statement handler. - function nest(t, x, node, func, end) { - x.stmtStack.push(node); - var n = func(t, x); - x.stmtStack.pop(); - end && t.mustMatch(end); - return n; - } - - /* - * Statements :: (tokenizer, compiler context) -> node - * - * Parses a list of Statements. - */ - function Statements(t, x) { - /* - * Blocks are uniquely numbered by a blockId within a function that is - * at the top level of the program. blockId starts from 0. - * - * This is done to aid hoisting for parse-time analyses done in custom - * builders. - * - * For more details in its interaction with hoisting, see comments in - * FunctionDefinition. - */ - var builder = x.builder; - var b = builder.BLOCK; - var n = b.build(t, x.blockId++); - b.hoistLets(n); - x.stmtStack.push(n); - while (!t.done && t.peek(true) !== RIGHT_CURLY) - b.addStatement(n, Statement(t, x)); - x.stmtStack.pop(); - b.finish(n); - if (n.needsHoisting) { - builder.setHoists(n.id, n.varDecls); - /* - * If a block needs hoisting, we need to propagate this flag up to - * the CompilerContext. - */ - x.needsHoisting = true; - } - return n; - } - - function Block(t, x) { - t.mustMatch(LEFT_CURLY); - var n = Statements(t, x); - t.mustMatch(RIGHT_CURLY); - return n; - } - - const DECLARED_FORM = 0, EXPRESSED_FORM = 1, STATEMENT_FORM = 2; - - /* - * Statement :: (tokenizer, compiler context) -> node - * - * Parses a Statement. - */ - function Statement(t, x) { - var i, label, n, n2, c, ss, tt = t.get(true); - var builder = x.builder, b, b2, b3; - - // Cases for statements ending in a right curly return early, avoiding the - // common semicolon insertion magic after this switch. - switch (tt) { - case FUNCTION: - // DECLARED_FORM extends funDecls of x, STATEMENT_FORM doesn't. - return FunctionDefinition(t, x, true, - (x.stmtStack.length > 1) - ? STATEMENT_FORM - : DECLARED_FORM); - - case LEFT_CURLY: - n = Statements(t, x); - t.mustMatch(RIGHT_CURLY); - return n; - - case IF: - b = builder.IF; - n = b.build(t); - b.setCondition(n, ParenExpression(t, x)); - x.stmtStack.push(n); - b.setThenPart(n, Statement(t, x)); - if (t.match(ELSE)) - b.setElsePart(n, Statement(t, x)); - x.stmtStack.pop(); - b.finish(n); - return n; - - case SWITCH: - // This allows CASEs after a DEFAULT, which is in the standard. - b = builder.SWITCH; - b2 = builder.DEFAULT; - b3 = builder.CASE; - n = b.build(t); - b.setDiscriminant(n, ParenExpression(t, x)); - x.stmtStack.push(n); - t.mustMatch(LEFT_CURLY); - while ((tt = t.get()) !== RIGHT_CURLY) { - switch (tt) { - case DEFAULT: - if (n.defaultIndex >= 0) - throw t.newSyntaxError("More than one switch default"); - n2 = b2.build(t); - b.setDefaultIndex(n, n.cases.length); - t.mustMatch(COLON); - b2.initializeStatements(n2, t); - while ((tt=t.peek(true)) !== CASE && tt !== DEFAULT && - tt !== RIGHT_CURLY) - b2.addStatement(n2, Statement(t, x)); - b2.finish(n2); - break; - - case CASE: - n2 = b3.build(t); - b3.setLabel(n2, Expression(t, x, COLON)); - t.mustMatch(COLON); - b3.initializeStatements(n2, t); - while ((tt=t.peek(true)) !== CASE && tt !== DEFAULT && - tt !== RIGHT_CURLY) - b3.addStatement(n2, Statement(t, x)); - b3.finish(n2); - break; - - default: - throw t.newSyntaxError("Invalid switch case"); - } - b.addCase(n, n2); - } - x.stmtStack.pop(); - b.finish(n); - return n; - - case FOR: - b = builder.FOR; - n = b.build(t); - if (t.match(IDENTIFIER) && t.token.value === "each") - b.rebuildForEach(n); - t.mustMatch(LEFT_PAREN); - if ((tt = t.peek()) !== SEMICOLON) { - x.inForLoopInit = true; - if (tt === VAR || tt === CONST) { - t.get(); - n2 = Variables(t, x); - } else if (tt === LET) { - t.get(); - if (t.peek() === LEFT_PAREN) { - n2 = LetBlock(t, x, false); - } else { - /* - * Let in for head, we need to add an implicit block - * around the rest of the for. - */ - var forBlock = builder.BLOCK.build(t, x.blockId++); - x.stmtStack.push(forBlock); - n2 = Variables(t, x, forBlock); - } - } else { - n2 = Expression(t, x); - } - x.inForLoopInit = false; - } - if (n2 && t.match(IN)) { - // for-ins always get a for block to help desugaring. - if (!forBlock) { - var forBlock = builder.BLOCK.build(t, x.blockId++); - forBlock.isInternalForInBlock = true; - x.stmtStack.push(forBlock); - } - - b.rebuildForIn(n); - b.setObject(n, Expression(t, x)); - if (n2.type === VAR || n2.type === LET) { - c = n2.children; - - // Destructuring turns one decl into multiples, so either - // there must be only one destructuring or only one - // decl. - if (c.length !== 1 && n2.destructurings.length !== 1) { - throw new SyntaxError("Invalid for..in left-hand side", - t.filename, n2.lineno); - } - if (n2.destructurings.length > 0) { - b.setIterator(n, n2.destructurings[0], n2, forBlock); - } else { - b.setIterator(n, c[0], n2, forBlock); - } - } else { - if (n2.type === ARRAY_INIT || n2.type === OBJECT_INIT) { - n2.destructuredNames = checkDestructuring(t, x, n2); - } - b.setIterator(n, n2, null, forBlock); - } - } else { - b.setSetup(n, n2); - t.mustMatch(SEMICOLON); - if (n.isEach) - throw t.newSyntaxError("Invalid for each..in loop"); - b.setCondition(n, (t.peek() === SEMICOLON) - ? null - : Expression(t, x)); - t.mustMatch(SEMICOLON); - b.setUpdate(n, (t.peek() === RIGHT_PAREN) - ? null - : Expression(t, x)); - } - t.mustMatch(RIGHT_PAREN); - b.setBody(n, nest(t, x, n, Statement)); - b.finish(n); - - // In case desugaring statements were added to the imaginary - // block. - if (forBlock) { - builder.BLOCK.finish(forBlock); - x.stmtStack.pop(); - c = forBlock.children; - for (var i = 0, j = c.length; i < j; i++) { - n.body.unshift(c[i]); - } - } - return n; - - case WHILE: - b = builder.WHILE; - n = b.build(t); - b.setCondition(n, ParenExpression(t, x)); - b.setBody(n, nest(t, x, n, Statement)); - b.finish(n); - return n; - - case DO: - b = builder.DO; - n = b.build(t); - b.setBody(n, nest(t, x, n, Statement, WHILE)); - b.setCondition(n, ParenExpression(t, x)); - b.finish(n); - if (!x.ecmaStrictMode) { - //