private void performFunctionDeclarationBindings( final JSCode code, final boolean configurableBindings) { // 10.5 Function Declaration Binding List<FunctionDeclaration> decls = code.getFunctionDeclarations(); EnvironmentRecord env = this.variableEnvironment.getRecord(); for (FunctionDeclaration each : decls) { String identifier = each.getIdentifier(); if (!env.hasBinding(this, identifier)) { env.createMutableBinding(this, identifier, configurableBindings); } else if (env.isGlobal()) { JSObject globalObject = ((ObjectEnvironmentRecord) env).getBindingObject(); PropertyDescriptor existingProp = (PropertyDescriptor) globalObject.getProperty(this, identifier); if (existingProp.isConfigurable()) { PropertyDescriptor newProp = new PropertyDescriptor() { { set("Value", Types.UNDEFINED); set("Writable", true); set("Enumerable", true); set("Configurable", configurableBindings); } }; globalObject.defineOwnProperty(this, identifier, newProp, true); } else if (existingProp.isAccessorDescriptor() || (!existingProp.isWritable() && !existingProp.isEnumerable())) { throw new ThrowException( this, createTypeError("unable to bind function '" + identifier + "'")); } } JSFunction function = getCompiler() .compileFunction( this, identifier, each.getFormalParameters(), each.getBlock(), each.isStrict()); function.setDebugContext(identifier); env.setMutableBinding(this, identifier, function, code.isStrict()); } }
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; }