/** * Copyright (c) 2012-2016 André Bargull * Alle Rechte vorbehalten / All Rights Reserved. Use is subject to license terms. * * <https://github.com/anba/es6draft> */ package com.github.anba.es6draft.runtime.types.builtins; import com.github.anba.es6draft.Executable; import com.github.anba.es6draft.runtime.ExecutionContext; import com.github.anba.es6draft.runtime.LexicalEnvironment; import com.github.anba.es6draft.runtime.Realm; import com.github.anba.es6draft.runtime.internal.RuntimeInfo; import com.github.anba.es6draft.runtime.types.Callable; import com.github.anba.es6draft.runtime.types.Constructor; import com.github.anba.es6draft.runtime.types.Intrinsics; import com.github.anba.es6draft.runtime.types.Property; import com.github.anba.es6draft.runtime.types.ScriptObject; import com.github.anba.es6draft.runtime.types.Symbol; /** * <h1>9 Ordinary and Exotic Objects Behaviours</h1> * <ul> * <li>9.2 ECMAScript Function Objects * </ul> */ public final class OrdinaryFunction extends FunctionObject { /** * Constructs a new Function object. * * @param realm * the realm object */ protected OrdinaryFunction(Realm realm) { super(realm); } @Override protected OrdinaryFunction allocateNew() { return FunctionAllocate(getRealm().defaultContext(), getPrototype(), isStrict(), getFunctionKind()); } /** * 9.2.1 [[Call]] (thisArgument, argumentsList) */ @Override public Object call(ExecutionContext callerContext, Object thisValue, Object... argumentsList) { try { return getCallMethod().invokeExact(this, callerContext, thisValue, argumentsList); } catch (Throwable e) { throw FunctionObject.<RuntimeException> rethrow(e); } } /** * 9.2.1 [[Call]] (thisArgument, argumentsList) */ @Override public Object tailCall(ExecutionContext callerContext, Object thisValue, Object... argumentsList) throws Throwable { return getTailCallMethod().invokeExact(this, callerContext, thisValue, argumentsList); } /* ***************************************************************************************** */ /** * 9.2.3 FunctionAllocate (functionPrototype, strict) * * @param cx * the execution context * @param functionPrototype * the function prototype * @param strict * the strict mode flag * @param functionKind * the function kind * @return the new function object */ public static OrdinaryFunction FunctionAllocate(ExecutionContext cx, ScriptObject functionPrototype, boolean strict, FunctionKind functionKind) { assert !(functionKind == FunctionKind.Normal || functionKind == FunctionKind.ClassConstructor); Realm realm = cx.getRealm(); /* steps 1-5 (implicit) */ /* steps 6-9 */ OrdinaryFunction f = new OrdinaryFunction(realm); /* steps 10-14 */ f.allocate(realm, functionPrototype, strict, functionKind, ConstructorKind.Base); /* step 15 */ return f; } /** * 9.2.4 FunctionInitialize (F, kind, ParameterList, Body, Scope) * * @param f * the function object * @param kind * the function kind * @param function * the function code * @param scope * the lexical environment * @param executable * the executable object */ public static void FunctionInitialize(FunctionObject f, FunctionKind kind, RuntimeInfo.Function function, LexicalEnvironment<?> scope, Executable executable) { /* step 1 */ assert f.isExtensible() && !f.ordinaryHasOwnProperty("length"); /* step 2 */ int len = function.expectedArgumentCount(); /* steps 3-4 */ f.infallibleDefineOwnProperty("length", new Property(len, false, false, true)); /* steps 5-11 */ f.initialize(kind, function, scope, executable); /* step 12 (return) */ } /** * 9.2.5 FunctionCreate (kind, ParameterList, Body, Scope, Strict, prototype) * * @param cx * the execution context * @param kind * the function kind * @param function * the function code * @param scope * the lexical environment * @return the new function object */ public static OrdinaryFunction FunctionCreate(ExecutionContext cx, FunctionKind kind, RuntimeInfo.Function function, LexicalEnvironment<?> scope) { assert !function.isGenerator() && !function.isAsync(); /* step 1 */ ScriptObject functionPrototype = cx.getIntrinsic(Intrinsics.FunctionPrototype); /* steps 2-3 (not applicable) */ /* step 4 */ OrdinaryFunction f = FunctionAllocate(cx, functionPrototype, function.isStrict(), kind); /* step 5 */ FunctionInitialize(f, kind, function, scope, cx.getCurrentExecutable()); return f; } /** * 9.2.7 AddRestrictedFunctionProperties ( F, realm ) * * @param <FUNCTION> * the function type * @param f * the function object * @param realm * the realm object */ public static <FUNCTION extends OrdinaryObject & Callable> void AddRestrictedFunctionProperties(FUNCTION f, Realm realm) { /* steps 1-2 */ Callable thrower = realm.getThrowTypeError(); /* steps 3-4 */ f.infallibleDefineOwnProperty("caller", new Property(thrower, thrower, false, true)); /* steps 5-6 */ f.infallibleDefineOwnProperty("arguments", new Property(thrower, thrower, false, true)); } /** * 9.2.8 MakeConstructor (F, writablePrototype, prototype) * * @param <CONSTRUCTOR> * the constructor function type * @param cx * the execution context * @param f * the function object */ public static <CONSTRUCTOR extends FunctionObject & Constructor> void MakeConstructor(ExecutionContext cx, CONSTRUCTOR f) { /* steps 1-2 (not applicable) */ /* step 3 */ assert f.isExtensible() && !f.ordinaryHasOwnProperty("prototype"); /* step 4 */ boolean writablePrototype = true; /* step 5.a */ OrdinaryObject prototype = ObjectCreate(cx, Intrinsics.ObjectPrototype); /* step 5.b-c */ prototype.infallibleDefineOwnProperty("constructor", new Property(f, writablePrototype, false, true)); /* steps 6-7 */ f.infallibleDefineOwnProperty("prototype", new Property(prototype, writablePrototype, false, false)); /* step 8 (return) */ } /** * 9.2.8 MakeConstructor (F, writablePrototype, prototype) * * @param <CONSTRUCTOR> * the constructor function type * @param f * the function object * @param writablePrototype * the writable flag for the .prototype property * @param prototype * the prototype object */ public static <CONSTRUCTOR extends FunctionObject & Constructor> void MakeConstructor(CONSTRUCTOR f, boolean writablePrototype, ScriptObject prototype) { /* steps 1-2 (not applicable) */ /* step 3 */ assert f.isExtensible() && !f.ordinaryHasOwnProperty("prototype"); /* steps 4-5 (not applicable) */ /* steps 6-7 */ f.infallibleDefineOwnProperty("prototype", new Property(prototype, writablePrototype, false, false)); /* step 8 (return) */ } /** * 9.2.9 MakeClassConstructor (F) * * @param f * the function object */ public static void MakeClassConstructor(OrdinaryConstructorFunction f) { /* step 1 (not applicable) */ /* steps 2-3 */ assert f.getFunctionKind() == FunctionKind.ClassConstructor; /* step 4 (return) */ } /** * 9.2.10 MakeMethod (F, homeObject) * * @param f * the function object * @param homeObject * the home object */ public static void MakeMethod(FunctionObject f, ScriptObject homeObject) { /* steps 1-2 (not applicable) */ /* step 3 */ f.toMethod(homeObject); /* step 4 (return) */ } /** * 9.2.11 SetFunctionName (F, name, prefix) * * @param <FUNCTION> * the function type * @param f * the function object * @param name * the function name */ public static <FUNCTION extends OrdinaryObject & Callable> void SetFunctionName(FUNCTION f, String name) { SetFunctionName(f, name, null); } /** * 9.2.11 SetFunctionName (F, name, prefix) * * @param <FUNCTION> * the function type * @param f * the function object * @param name * the function name * @param prefix * the function name prefix */ public static <FUNCTION extends OrdinaryObject & Callable> void SetFunctionName(FUNCTION f, String name, String prefix) { /* step 1 */ assert f.isExtensible() && !f.ordinaryHasOwnProperty("name"); /* steps 2-4 (not applicable) */ /* step 5 */ if (prefix != null) { name = prefix + " " + name; } /* steps 6-7 */ f.infallibleDefineOwnProperty("name", new Property(name, false, false, true)); } /** * 9.2.11 SetFunctionName (F, name, prefix) * * @param <FUNCTION> * the function type * @param f * the function object * @param name * the function name */ public static <FUNCTION extends OrdinaryObject & Callable> void SetFunctionName(FUNCTION f, Symbol name) { SetFunctionName(f, name, null); } /** * 9.2.11 SetFunctionName (F, name, prefix) * * @param <FUNCTION> * the function type * @param f * the function object * @param name * the function name * @param prefix * the function name prefix */ public static <FUNCTION extends OrdinaryObject & Callable> void SetFunctionName(FUNCTION f, Symbol name, String prefix) { /* step 1 */ assert f.isExtensible() && !f.ordinaryHasOwnProperty("name"); /* steps 2-3 (not applicable) */ /* step 4 */ String description = name.getDescription(); String sname = description == null ? "" : "[" + description + "]"; /* step 5 */ if (prefix != null) { sname = prefix + " " + sname; } /* steps 6-7 */ f.infallibleDefineOwnProperty("name", new Property(sname, false, false, true)); } }