/**
* 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.objects.iteration;
import static com.github.anba.es6draft.runtime.internal.Properties.createProperties;
import static com.github.anba.es6draft.runtime.objects.FunctionConstructor.functionSource;
import static com.github.anba.es6draft.runtime.objects.FunctionConstructor.functionSourceText;
import static com.github.anba.es6draft.runtime.objects.FunctionConstructor.newFunctionExecutable;
import static com.github.anba.es6draft.runtime.types.builtins.OrdinaryFunction.FunctionInitialize;
import static com.github.anba.es6draft.runtime.types.builtins.OrdinaryFunction.MakeConstructor;
import static com.github.anba.es6draft.runtime.types.builtins.OrdinaryFunction.SetFunctionName;
import com.github.anba.es6draft.compiler.CompilationException;
import com.github.anba.es6draft.parser.ParserException;
import com.github.anba.es6draft.runtime.ExecutionContext;
import com.github.anba.es6draft.runtime.GlobalEnvironmentRecord;
import com.github.anba.es6draft.runtime.LexicalEnvironment;
import com.github.anba.es6draft.runtime.Realm;
import com.github.anba.es6draft.runtime.internal.CompatibilityOption;
import com.github.anba.es6draft.runtime.internal.Initializable;
import com.github.anba.es6draft.runtime.internal.Properties.Attributes;
import com.github.anba.es6draft.runtime.internal.Properties.Prototype;
import com.github.anba.es6draft.runtime.internal.Properties.Value;
import com.github.anba.es6draft.runtime.internal.RuntimeInfo;
import com.github.anba.es6draft.runtime.internal.ScriptLoader;
import com.github.anba.es6draft.runtime.internal.Source;
import com.github.anba.es6draft.runtime.objects.FunctionConstructor.SourceKind;
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.builtins.BuiltinConstructor;
import com.github.anba.es6draft.runtime.types.builtins.FunctionObject;
import com.github.anba.es6draft.runtime.types.builtins.FunctionObject.FunctionKind;
import com.github.anba.es6draft.runtime.types.builtins.OrdinaryConstructorGenerator;
import com.github.anba.es6draft.runtime.types.builtins.OrdinaryGenerator;
import com.github.anba.es6draft.runtime.types.builtins.OrdinaryObject;
/**
* <h1>25 Control Abstraction Objects</h1><br>
* <h2>25.2 GeneratorFunction Objects</h2>
* <ul>
* <li>25.2.1 The GeneratorFunction Constructor
* <li>25.2.2 Properties of the GeneratorFunction Constructor
* </ul>
*/
public final class GeneratorFunctionConstructor extends BuiltinConstructor implements Initializable {
/**
* Constructs a new Generator Function constructor function.
*
* @param realm
* the realm object
*/
public GeneratorFunctionConstructor(Realm realm) {
super(realm, "GeneratorFunction", 1);
}
@Override
public void initialize(Realm realm) {
createProperties(realm, this, Properties.class);
}
@Override
public GeneratorFunctionConstructor clone() {
return new GeneratorFunctionConstructor(getRealm());
}
/**
* 25.2.1.1 GeneratorFunction (p1, p2, ... , pn, body)
*/
@Override
public FunctionObject call(ExecutionContext callerContext, Object thisValue, Object... args) {
/* steps 1-3 */
return CreateDynamicFunction(callerContext, calleeContext(), this, args);
}
/**
* 25.2.1.1 GeneratorFunction (p1, p2, ... , pn, body)
*/
@Override
public FunctionObject construct(ExecutionContext callerContext, Constructor newTarget, Object... args) {
/* steps 1-3 */
return CreateDynamicFunction(callerContext, calleeContext(), newTarget, args);
}
/**
* 19.2.1.1.1 RuntimeSemantics: CreateDynamicFunction(constructor, newTarget, kind, args)
*
* @param callerContext
* the caller execution context
* @param cx
* the execution context
* @param newTarget
* the newTarget constructor function
* @param args
* the function arguments
* @return the new generator function object
*/
private static FunctionObject CreateDynamicFunction(ExecutionContext callerContext, ExecutionContext cx,
Constructor newTarget, Object... args) {
if (cx.getRealm().isEnabled(CompatibilityOption.GeneratorNonConstructor)) {
return CreateDynamicGenerator(callerContext, cx, newTarget, args);
}
return CreateDynamicConstructorGenerator(callerContext, cx, newTarget, args);
}
private static OrdinaryConstructorGenerator CreateDynamicConstructorGenerator(ExecutionContext callerContext,
ExecutionContext cx, Constructor newTarget, Object... args) {
/* step 1 (not applicable) */
/* step 2 (not applicable) */
/* step 3 */
Intrinsics fallbackProto = Intrinsics.Generator;
/* steps 4-10 */
String[] sourceText = functionSourceText(cx, args);
String parameters = sourceText[0], bodyText = sourceText[1];
/* steps 11, 13-20 */
Source source = functionSource(SourceKind.Generator, cx.getRealm(), callerContext);
RuntimeInfo.Function function;
try {
ScriptLoader scriptLoader = cx.getRealm().getScriptLoader();
function = scriptLoader.generator(source, parameters, bodyText).getFunction();
} catch (ParserException | CompilationException e) {
throw e.toScriptException(cx);
}
/* step 12 */
boolean strict = function.isStrict();
/* steps 21-22 */
ScriptObject proto = GetPrototypeFromConstructor(cx, newTarget, fallbackProto);
/* step 23 */
OrdinaryConstructorGenerator f = OrdinaryConstructorGenerator.FunctionAllocate(cx, proto, strict,
FunctionKind.Normal);
/* steps 24-25 */
LexicalEnvironment<GlobalEnvironmentRecord> scope = f.getRealm().getGlobalEnv();
/* step 26 */
FunctionInitialize(f, FunctionKind.Normal, function, scope, newFunctionExecutable(source));
/* step 27 */
OrdinaryObject prototype = ObjectCreate(cx, Intrinsics.GeneratorPrototype);
MakeConstructor(f, true, prototype);
/* step 28 (not applicable) */
/* step 29 */
SetFunctionName(f, "anonymous");
/* step 30 */
return f;
}
private static OrdinaryGenerator CreateDynamicGenerator(ExecutionContext callerContext, ExecutionContext cx,
Constructor newTarget, Object... args) {
/* step 1 (not applicable) */
/* step 2 (not applicable) */
/* step 3 */
Intrinsics fallbackProto = Intrinsics.Generator;
/* steps 4-10 */
String[] sourceText = functionSourceText(cx, args);
String parameters = sourceText[0], bodyText = sourceText[1];
/* steps 11, 13-20 */
Source source = functionSource(SourceKind.Generator, cx.getRealm(), callerContext);
RuntimeInfo.Function function;
try {
ScriptLoader scriptLoader = cx.getRealm().getScriptLoader();
function = scriptLoader.generator(source, parameters, bodyText).getFunction();
} catch (ParserException | CompilationException e) {
throw e.toScriptException(cx);
}
/* step 12 */
boolean strict = function.isStrict();
/* steps 21-22 */
ScriptObject proto = GetPrototypeFromConstructor(cx, newTarget, fallbackProto);
/* step 23 */
OrdinaryGenerator f = OrdinaryGenerator.FunctionAllocate(cx, proto, strict, FunctionKind.Normal);
/* steps 24-25 */
LexicalEnvironment<GlobalEnvironmentRecord> scope = f.getRealm().getGlobalEnv();
/* step 26 */
FunctionInitialize(f, FunctionKind.Normal, function, scope, newFunctionExecutable(source));
/* step 27 */
OrdinaryObject prototype = ObjectCreate(cx, Intrinsics.GeneratorPrototype);
f.infallibleDefineOwnProperty("prototype", new Property(prototype, true, false, false));
/* step 28 (not applicable) */
/* step 29 */
SetFunctionName(f, "anonymous");
/* step 30 */
return f;
}
/**
* 25.2.2 Properties of the GeneratorFunction Constructor
*/
public enum Properties {
;
@Prototype
public static final Intrinsics __proto__ = Intrinsics.Function;
/**
* 25.2.2.2 GeneratorFunction.prototype
*/
@Value(name = "prototype", attributes = @Attributes(writable = false, enumerable = false,
configurable = false))
public static final Intrinsics prototype = Intrinsics.Generator;
/**
* 25.2.2.1 GeneratorFunction.length
*/
@Value(name = "length", attributes = @Attributes(writable = false, enumerable = false,
configurable = true))
public static final int length = 1;
@Value(name = "name", attributes = @Attributes(writable = false, enumerable = false,
configurable = true))
public static final String name = "GeneratorFunction";
}
}