diff --git a/harmony-tests/run.sh b/harmony-tests/run.sh index ec27881..ff604bd 100755 --- a/harmony-tests/run.sh +++ b/harmony-tests/run.sh @@ -15,7 +15,7 @@ SUCCEED_PASS=0 SUCCEED_FAIL=0 for f in harmony-tests/succeed/*.js ; do - ./njs -H -f $f >/dev/null 2>&1 + ./njs -f $f >/dev/null 2>&1 if [ $? -eq 0 ]; then SUCCEED_PASS=$(($SUCCEED_PASS + 1)) else @@ -35,7 +35,7 @@ FAIL_RESOLVE_PASS=0 FAIL_RESOLVE_FAIL=0 for f in harmony-tests/fail-resolve/*.js ; do - ./njs -H -E "Narcissus.resolver.resolve(Narcissus.parser.parse(snarf('$f')),Narcissus.interpreter.globalStaticEnv)" >/dev/null 2>&1 + ./njs -E "Narcissus.resolver.resolve(Narcissus.parser.parse(snarf('$f')),Narcissus.interpreter.globalStaticEnv)" >/dev/null 2>&1 if [ $? -eq 0 ]; then FAIL_RESOLVE_FAIL=$((FAIL_RESOLVE_FAIL + 1)) FAILURES="$FAILURES $f" @@ -55,7 +55,7 @@ FAIL_EXECUTE_PASS=0 FAIL_EXECUTE_FAIL=0 for f in harmony-tests/fail-execute ; do - ./njs -H -f $f >/dev/null 2>&1 + ./njs -f $f >/dev/null 2>&1 if [ $? -eq 0 ]; then FAIL_EXECUTE_FAIL=$(($FAIL_EXECUTE_FAIL + 1)) FAILURES="$FAILURES $f" diff --git a/lib/jsdefs.js b/lib/jsdefs.js index 680bb4f..70cd5a1 100644 --- a/lib/jsdefs.js +++ b/lib/jsdefs.js @@ -54,13 +54,16 @@ var narcissus = { options: { - version: 185, // Global variables to hide from the interpreter hiddenHostGlobals: { Narcissus: true }, // Desugar SpiderMonkey language extensions? desugarExtensions: false, // Allow HTML comments? - allowHTMLComments: false + allowHTMLComments: false, + // Allow non-standard Mozilla extensions? + mozillaMode: true, + // Allow experimental paren-free mode? + parenFreeMode: false }, hostSupportsEvalConst: (function() { try { @@ -374,29 +377,6 @@ Narcissus.definitions = (function(hostGlobal) { return mixinHandler(redirect, catchall); } - function mirrorHandler(target, writable) { - var handler = makePassthruHandler(target); - - var defineProperty = handler.defineProperty; - handler.defineProperty = function(name, desc) { - if (!desc.enumerable) - throw new Error("mirror property must be enumerable"); - if (!desc.configurable) - throw new Error("mirror property must be configurable"); - if (desc.writable !== writable) - throw new Error("mirror property must " + (writable ? "" : "not ") + "be writable"); - defineProperty(name, desc); - }; - - handler.fix = function() { }; - handler.getOwnPropertyDescriptor = handler.getPropertyDescriptor; - handler.getOwnPropertyNames = getPropertyNames.bind(handler, target); - handler.keys = handler.enumerate; - handler["delete"] = function() { return false; }; - handler.hasOwn = handler.has; - return handler; - } - /* * Mixin proxies break the single-inheritance model of prototypes, so * the handler treats all properties as own-properties: @@ -721,7 +701,6 @@ Narcissus.definitions = (function(hostGlobal) { isNativeCode: isNativeCode, apply: apply, applyNew: applyNew, - mirrorHandler: mirrorHandler, mixinHandler: mixinHandler, whitelistHandler: whitelistHandler, blacklistHandler: blacklistHandler, diff --git a/lib/jsexec.js b/lib/jsexec.js index d75c343..04c0111 100644 --- a/lib/jsexec.js +++ b/lib/jsexec.js @@ -86,14 +86,9 @@ Narcissus.interpreter = (function() { CONTINUE_SIGNAL = new InternalSignal, EXIT_SIGNAL = new InternalSignal; - function ExecutionContext(type, version) { + function ExecutionContext(type, strict) { this.type = type; - this.version = version; - // In Harmony, the global scope record is not exposed to the program. - if (type === GLOBAL_CODE && version === "harmony") { - this.scope = {object: globalScope, parent: null}; - this.thisObject = globalMirror; - } + this.strict = !!strict; } function isStackOverflow(e) { @@ -112,13 +107,13 @@ Narcissus.interpreter = (function() { return s; var x = ExecutionContext.current; - var x2 = new ExecutionContext(EVAL_CODE, x.version); + var x2 = new ExecutionContext(EVAL_CODE); x2.thisObject = x.thisObject; x2.thisModule = x.thisModule; x2.functionInstance = x.functionInstance; - x2.scope = x.version === "harmony" ? { object: new Object, parent: x.scope } : x.scope; + x2.scope = x.strict ? { object: new Object, parent: x.scope } : x.scope; var ast = parser.parse(s); - if (x.version === "harmony") { + if (ast.hasModules) { resolver.resolve(ast, new StaticEnv(x.staticEnv)); instantiateModules(ast, x2.scope); } @@ -184,7 +179,6 @@ Narcissus.interpreter = (function() { throw new TypeError("only works on scripts"); return fint.getBytecode().toString(); }, - version: function() { return ExecutionContext.current.version; }, quit: function() { throw EXIT_SIGNAL; }, assertEq: function() { return assertEq.apply(null, arguments); @@ -197,24 +191,7 @@ Narcissus.interpreter = (function() { return Proxy.createFunction( definitions.makePassthruHandler(val), function() { return val.apply(hostGlobal, arguments); }, - function() { - var a = arguments; - switch (a.length) { - case 0: - return new val(); - case 1: - return new val(a[0]); - case 2: - return new val(a[0], a[1]); - case 3: - return new val(a[0], a[1], a[2]); - default: - var argStr = ""; - for (var i = 0; i < a.length; i++) - argStr += 'a[' + i + '],'; - return eval('new ' + name + '(' + argStr.slice(0,-1) + ');'); - } - }); + function() { return applyNew(val, arguments); }); } var hostHandler = definitions.blacklistHandler(hostGlobal, @@ -227,23 +204,14 @@ Narcissus.interpreter = (function() { var globalStaticEnv; // global static scope var moduleInstances = new WeakMap(); // maps module instance objects -> module instances - var global = Object.create(hostProxy, {}); // exposed global object (legacy) - - // unexposed global scope record (Harmony) - var globalScope = Object.create(hostProxy, {}); - - // exposed global scope mirror (Harmony) - var globalMirror = Proxy.create(definitions.mirrorHandler(globalScope, true)); + var global = Object.create(hostProxy, {}); // user global object function resetEnvironment() { - ExecutionContext.current = new ExecutionContext(GLOBAL_CODE, Narcissus.options.version); + ExecutionContext.current = new ExecutionContext(GLOBAL_CODE); let names = Object.getOwnPropertyNames(global); for (let i = 0, n = names.length; i < n; i++) { delete global[names[i]]; } - for (let key in globalScope) { - delete globalScope[key]; - } moduleInstances = new WeakMap(); globalStaticEnv = new StaticEnv(); @@ -254,7 +222,6 @@ Narcissus.interpreter = (function() { for (let key in globalBase) { let val = globalBase[key]; global[key] = val; - globalScope[key] = val; // NB: this assumes globalBase never contains module or import bindings globalStaticEnv.bind(key, new Def()); } @@ -293,7 +260,6 @@ Narcissus.interpreter = (function() { functionInstance: null, result: undefined, target: null, - ecma3OnlyMode: false, // Execute a node in this execution context. execute: function(n) { @@ -419,7 +385,7 @@ Narcissus.interpreter = (function() { function executeModule(n, x) { var m = x.scope.object[n.name]; var inst = moduleInstances.get(m); - var x2 = new ExecutionContext(MODULE_CODE, x.version); + var x2 = new ExecutionContext(MODULE_CODE, true); x2.scope = inst.scope; x2.thisObject = m; x2.thisModule = m; @@ -594,10 +560,7 @@ Narcissus.interpreter = (function() { 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); + t = (v === null || v === undefined) ? v : toObject(v, s, n.object); a = []; for (i in t) a.push(i); @@ -1218,7 +1181,7 @@ Narcissus.interpreter = (function() { var FIp = FunctionInternals.prototype = { call: function(f, t, a, x) { - var x2 = new ExecutionContext(FUNCTION_CODE, x.version); + var x2 = new ExecutionContext(FUNCTION_CODE, this.node.body.strict); x2.thisObject = t || global; x2.thisModule = null; x2.functionInstance = this; @@ -1275,11 +1238,11 @@ Narcissus.interpreter = (function() { if (typeof s !== "string") return s; - var x = new ExecutionContext(GLOBAL_CODE, Narcissus.options.version); + var x = new ExecutionContext(GLOBAL_CODE); var ast = parser.parse(s, f, l); if (Narcissus.options.desugarExtensions) ast = desugaring.desugar(ast); - if (x.version === "harmony") { + if (ast.hasModules) { resolveGlobal(ast); instantiateModules(ast, x.scope); } @@ -1364,7 +1327,7 @@ Narcissus.interpreter = (function() { return false; } - var x = new ExecutionContext(GLOBAL_CODE, Narcissus.options.version); + var x = new ExecutionContext(GLOBAL_CODE); // Line number in/out parameter to parser.parseStdin. var ln = {value: 0}; diff --git a/lib/jsparse.js b/lib/jsparse.js index ff6a629..a45c788 100644 --- a/lib/jsparse.js +++ b/lib/jsparse.js @@ -82,8 +82,7 @@ Narcissus.parser = (function() { this.t = tokenizer; this.x = null; this.unexpectedEOF = false; - Narcissus.options.ecma3OnlyMode && (this.ecma3OnlyMode = true); - Narcissus.options.version === 185 && (this.mozillaMode = true); + Narcissus.options.mozillaMode && (this.mozillaMode = true); Narcissus.options.parenFreeMode && (this.parenFreeMode = true); } @@ -162,8 +161,6 @@ Narcissus.parser = (function() { var Pp = Parser.prototype; - Pp.ecma3OnlyMode = false; - Pp.mozillaMode = false; Pp.parenFreeMode = false; @@ -214,9 +211,8 @@ Narcissus.parser = (function() { var node = this.newNode(scriptInit()); var x2 = new StaticContext(node, node, inModule, inFunction); this.withContext(x2, function() { - this.Statements(node, false); + this.Statements(node, true); }); - for (var i = 0, n = node.children.length; i < n && Pragma(node.children[i]); i++); if (expectEnd && !this.done()) this.fail("expected end of input"); return node; @@ -431,14 +427,23 @@ Narcissus.parser = (function() { } /* - * Statements :: (node) -> void + * Statements :: (node[, boolean]) -> void * * Parses a sequence of Statements. */ - Pp.Statements = function Statements(n) { + Pp.Statements = function Statements(n, topLevel) { + var prologue = !!topLevel; try { - while (!this.done() && this.peek(true) !== RIGHT_CURLY) - n.push(this.Statement()); + while (!this.done() && this.peek(true) !== RIGHT_CURLY) { + var n2 = this.Statement(); + n.push(n2); + if (prologue && Pragma(n2)) { + this.x.strictMode = true; + n.strict = true; + } else { + prologue = false; + } + } } catch (e) { if (this.done()) this.unexpectedEOF = true; @@ -453,7 +458,7 @@ Narcissus.parser = (function() { this.withContext(x2, function() { this.Statements(n); }); - t.mustMatch(RIGHT_CURLY); + this.mustMatch(RIGHT_CURLY); return n; } @@ -647,7 +652,7 @@ Narcissus.parser = (function() { } this.mustMatch(COLON); n2.statements = this.newNode(blockInit()); - while ((tt=t.peek(true)) !== CASE && tt !== DEFAULT && + while ((tt=this.peek(true)) !== CASE && tt !== DEFAULT && tt !== RIGHT_CURLY) n2.statements.push(this.Statement()); n.cases.push(n2); @@ -761,16 +766,13 @@ Narcissus.parser = (function() { this.withContext(x2, function() { n.body = this.Statement(); }); - t.mustMatch(WHILE); + this.mustMatch(WHILE); n.condition = this.HeadExpression(); - if (!this.ecma3OnlyMode) { - //