public ExecutionContext createFunctionExecutionContext( Object functionReference, JSFunction function, Object thisArg, Object... arguments) { // 10.4.3 Object thisBinding = null; if (function.isStrict()) { thisBinding = thisArg; } else { if (thisArg == null || thisArg == Types.NULL || thisArg == Types.UNDEFINED) { thisBinding = this.getLexicalEnvironment().getGlobalObject(); } else if (!(thisArg instanceof JSObject)) { // thisBinding = Types.toObject(this, thisArg); thisBinding = Types.toThisObject(this, thisArg); } else { thisBinding = thisArg; } } LexicalEnvironment scope = function.getScope(); LexicalEnvironment localEnv = LexicalEnvironment.newDeclarativeEnvironment(scope); ExecutionContext context = new ExecutionContext(this, localEnv, localEnv, thisBinding, function.isStrict()); context.performDeclarationBindingInstantiation(function, arguments); context.fileName = function.getFileName(); // System.err.println( "debug null: " + ( function.getDebugContext() == null ? function : "not // null") ); context.debugContext = function.getDebugContext(); context.functionReference = functionReference; return context; }
private void performDeclarationBindingInstantiation(JSFunction function, Object[] arguments) { // 10.5 (Functions) String[] names = function.getFormalParameters(); Object v = null; DeclarativeEnvironmentRecord env = (DeclarativeEnvironmentRecord) this.variableEnvironment.getRecord(); // * 4 for (int i = 0; i < names.length; ++i) { if ((i + 1) > arguments.length) { v = Types.UNDEFINED; } else { v = arguments[i]; } if (!env.hasBinding(this, names[i])) { env.createMutableBinding(this, names[i], false); } env.setMutableBinding(this, names[i], v, function.isStrict()); } // * 5 performFunctionDeclarationBindings(function, false); // * 6 if (!env.hasBinding(this, "arguments")) { // * 7 Arguments argsObj = createArgumentsObject(function, arguments); if (function.isStrict()) { env.createImmutableBinding("arguments"); env.initializeImmutableBinding("arguments", argsObj); } else { env.createMutableBinding(this, "arguments", false); env.setMutableBinding(this, "arguments", argsObj, false); } } // * 8 performVariableDeclarationBindings(function, false); }
private Arguments createArgumentsObject(final JSFunction function, final Object[] arguments) { // 10.6 Arguments obj = new Arguments(getGlobalObject()); PropertyDescriptor desc = new PropertyDescriptor() { { set("Value", arguments.length); set("Writable", true); set("Enumerable", false); set("Configurable", true); } }; obj.defineOwnProperty(this, "length", desc, false); String[] names = function.getFormalParameters(); JSObject map = new DynObject(getGlobalObject()); List<String> mappedNames = new ArrayList<>(); final LexicalEnvironment env = getVariableEnvironment(); for (int i = 0; i < arguments.length; ++i) { final Object val = arguments[i]; desc = new PropertyDescriptor() { { set("Value", val); set("Writable", true); set("Enumerable", true); set("Configurable", true); } }; obj.defineOwnProperty(this, "" + i, desc, false); if (i < names.length) { if (!function.isStrict()) { final String name = names[i]; if (i < names.length) { if (!mappedNames.contains(name)) { mappedNames.add(name); desc = new PropertyDescriptor() { { set("Set", new ArgSetter(env, name)); set("Get", new ArgGetter(env, name)); set("Configurable", true); } }; map.defineOwnProperty(this, "" + i, desc, false); } } } } } if (!mappedNames.isEmpty()) { obj.setParameterMap(map); } if (function.isStrict()) { final JSFunction thrower = (JSFunction) getGlobalObject().get(this, "__throwTypeError"); obj.defineOwnProperty( this, "caller", new PropertyDescriptor() { { set("Get", thrower); set("Set", thrower); set("Enumerable", false); set("Configurable", false); } }, false); obj.defineOwnProperty( this, "callee", new PropertyDescriptor() { { set("Get", thrower); set("Set", thrower); set("Enumerable", false); set("Configurable", false); } }, false); } else { obj.defineOwnProperty( this, "callee", new PropertyDescriptor() { { set("Value", function); set("Writable", true); set("Enumerable", false); set("Configurable", true); } }, false); } return obj; }