public static FunctionObject FunctionCreate(FunctionCreateKind kind, FormalParameters parameters, FunctionStatementList body, LexicalEnvironment scope, bool strict, IValue?prototype = null) { if (prototype == null) { prototype = Interpreter.Instance().CurrentRealm().Intrinsics.FunctionPrototype; } var functionKind = kind == FunctionCreateKind.Normal ? FunctionKind.Normal : FunctionKind.NonConstructor; FunctionObject F = FunctionAllocate(prototype, strict, functionKind); return(FunctionInitialize(F, kind, parameters, body, scope)); }
public static LexicalEnvironment NewFunctionalEnvironment(FunctionObject F, IValue newTarget) { if (!(newTarget is UndefinedValue) && !(newTarget is Object)) { throw new InvalidOperationException("Spec 8.1.2.4 step 2"); } var env = new LexicalEnvironment(); var envRec = new FunctionEnvironmentRecord(F, newTarget); env.EnvironmentRecord = envRec; env.Outer = F.Environment; return(env); }
public FunctionEnvironmentRecord(FunctionObject F, IValue newTarget) { FunctionObject = F; if (F.ThisMode == ThisMode.Lexical) { ThisBindingStatus = ThisBindingStatus.Lexical; } else { ThisBindingStatus = ThisBindingStatus.Uninitialized; } HomeObject = F.HomeObject ?? UndefinedValue.Instance; NewTarget = newTarget; }
public static FunctionObject FunctionInitialize(FunctionObject f, FunctionCreateKind kind, FormalParameters parameters, FunctionStatementList body, LexicalEnvironment scope) { var len = parameters.ExpectedArgumentCount(); f.DefinePropertyOrThrow("length", new PropertyDescriptor(new NumberValue(len), false, false, true)); f.Environment = scope; f.FormalParameters = parameters; f.Code = body; if (kind == FunctionCreateKind.Arrow) { f.ThisMode = ThisMode.Lexical; } else if (f.Strict) { f.ThisMode = ThisMode.Strict; } else { f.ThisMode = ThisMode.Global; } return(f); }
public static FunctionObject FunctionAllocate(IValue prototype, bool strict, FunctionKind functionKind) { if (!(prototype is Object)) { throw new InvalidOperationException("FunctionObject.FunctionAllocate: non-object prototype is not allowed."); } bool needsConstruct = functionKind == FunctionKind.Normal; if (functionKind == FunctionKind.NonConstructor) { functionKind = FunctionKind.Normal; } var F = new FunctionObject(); if (needsConstruct) { F.ConstructorKind = ConstructorKind.Base; } F.Strict = strict; F.FunctionKind = functionKind; F.SetPrototypeOf(prototype); F.Realm = Interpreter.Instance().RunningExecutionContext().Realm; return(F); }
public Completion FunctionDeclarationInstantiation(IReadOnlyList <IValue> arguments) { var calleeContext = Interpreter.Instance().RunningExecutionContext(); var env = calleeContext.LexicalEnvironment; var envRec = env.EnvironmentRecord; var parameterNames = FormalParameters.BoundNames(); var hasDuplicates = parameterNames.Distinct().Count() < parameterNames.Count; var simpleParameterList = FormalParameters.IsSimpleParameterList(); var hasParameterExpressions = FormalParameters.formalParameters.Any(p => p.hasInitializer); var varNames = Code.VarDeclaredNames(); var varDeclarations = Code.VarScopedDeclarations(); var functionNames = new LinkedList <string>(); var functionsToInitialize = new LinkedList <FunctionDeclaration>(); foreach (var d in varDeclarations.Reverse()) { if (d is FunctionDeclaration functionDeclaration) { var fn = functionDeclaration.BoundNames()[0]; if (!functionNames.Contains(fn)) { functionNames.AddFirst(fn); functionsToInitialize.AddFirst(functionDeclaration); } } } var argumentsObjectNeeded = true; if (ThisMode == ThisMode.Lexical) { argumentsObjectNeeded = false; } else if (parameterNames.Contains("arguments")) { argumentsObjectNeeded = false; } else if (!hasParameterExpressions) { if (functionNames.Contains("arguments")) { argumentsObjectNeeded = false; } } foreach (var paramName in parameterNames) { var alreadyDeclared = envRec.HasBinding(paramName).Other == true; if (!alreadyDeclared) { envRec.CreateMutableBinding(paramName, false); if (hasDuplicates) { envRec.InitializeBinding(paramName, UndefinedValue.Instance); } } } IReadOnlyList <string> parameterBindings; if (argumentsObjectNeeded) { Object ao; if (Strict || !simpleParameterList) { ao = CreateUnmappedArgumentsObject(arguments); } else { ao = CreateMappedArgumentsObject(FormalParameters, arguments, envRec); } if (Strict) { envRec.CreateImmutableBinding("arguments", false); } else { envRec.CreateMutableBinding("arguments", false); } envRec.InitializeBinding("arguments", ao); parameterBindings = parameterNames.Concat(new[] { "arguments" }).ToList(); } else { parameterBindings = parameterNames; } var iterator = new ArgumentIterator(arguments); Completion comp; if (hasDuplicates) { comp = FormalParameters.IteratorBindingInitialization(null, iterator); } else { comp = FormalParameters.IteratorBindingInitialization(env, iterator); } if (comp.IsAbrupt()) { return(comp); } LexicalEnvironment varEnv; EnvironmentRecord varEnvRec; if (!hasParameterExpressions) { var instantiatedVarNames = new List <string>(parameterNames); foreach (var n in varNames) { if (!instantiatedVarNames.Contains(n)) { instantiatedVarNames.Add(n); envRec.CreateMutableBinding(n, false); envRec.InitializeBinding(n, UndefinedValue.Instance); } } varEnv = env; varEnvRec = envRec; } else { varEnv = env.NewDeclarativeEnvironment(); varEnvRec = varEnv.EnvironmentRecord; calleeContext.VariableEnvironment = varEnv; var instantiatedVarNames = new List <string>(); foreach (var n in varNames) { if (!instantiatedVarNames.Contains(n)) { instantiatedVarNames.Add(n); varEnvRec.CreateMutableBinding(n, false); IValue initialValue; if (!parameterBindings.Contains(n) || functionNames.Contains(n)) { initialValue = UndefinedValue.Instance; } else { initialValue = envRec.GetBindingValue(n, false).value !; } varEnvRec.InitializeBinding(n, initialValue); } } } var lexEnv = !Strict?varEnv.NewDeclarativeEnvironment() : varEnv; var lexEnvRec = lexEnv.EnvironmentRecord; calleeContext.LexicalEnvironment = lexEnv; var lexDeclarations = Code.LexicallyScopedDeclarations(); foreach (var d in lexDeclarations) { foreach (var dn in d.BoundNames()) { if (d.IsConstantDeclaration()) { lexEnvRec.CreateImmutableBinding(dn, true); } else { lexEnvRec.CreateMutableBinding(dn, false); } } } foreach (var f in functionsToInitialize) { var fn = f.BoundNames()[0]; FunctionObject fo = f.InstantiateFunctionObject(lexEnv); varEnvRec.SetMutableBinding(fn, fo, false); } return(Completion.NormalCompletion()); }
private Completion CreateDynamicFunction(Object?newTarget, FunctionKind kind, IReadOnlyList <IValue> arguments) { if (Interpreter.Instance().ExecutionContextStackSize() < 2) { throw new InvalidOperationException("Spec 19.2.1.1.1 step 1"); } var callerContext = Interpreter.Instance().SecondExecutionContext(); var callerRealm = callerContext.Realm; var calleeRealm = Interpreter.Instance().CurrentRealm(); //TODO HostEnsureCanCompileStrings if (newTarget == null) { newTarget = this; } Func <Parser.Parser, AST.FunctionStatementList> goal; Func <Intrinsics, Object> fallbackProto; switch (kind) { case FunctionKind.Normal: goal = (p) => p.ParseFunctionBody(); fallbackProto = i => i.FunctionPrototype; break; default: throw new NotImplementedException("Async and/or generators"); } var argCount = arguments.Count; var P = ""; string bodyText; if (argCount == 0) { bodyText = ""; } else if (argCount == 1) { var bodyComp = arguments[0].ToJsString(); if (bodyComp.IsAbrupt()) { return(bodyComp); } bodyText = (bodyComp.value as StringValue) !.@string; } else { var firstArg = arguments[0]; var pComp = firstArg.ToJsString(); if (pComp.IsAbrupt()) { return(pComp); } P = (pComp.value as StringValue) !.@string; int k = 1; for (; k < argCount - 1; k++) { var nextArg = arguments[k]; var nextArgStringComp = nextArg.ToJsString(); if (nextArgStringComp.IsAbrupt()) { return(nextArgStringComp); } var nextArgString = (nextArgStringComp.value as StringValue) !.@string; P += "," + nextArgString; } var bodyComp = arguments[k].ToJsString(); if (bodyComp.IsAbrupt()) { return(bodyComp); } bodyText = (bodyComp.value as StringValue) !.@string; } AST.FormalParameters?parameters = new AST.FormalParameters(); try { if (!string.IsNullOrEmpty(P)) { parameters = new Parser.Parser(P).ParseFormalParameters(); } if (parameters == null) { throw new Parser.ParseFailureException($"parameters {P} could not be parsed."); } } catch (Parser.ParseFailureException e) { return(Completion.ThrowSyntaxError($"Failed to parse parameters \"{P}\".\n{e.Message}")); } AST.FunctionStatementList body; try { body = goal(new Parser.Parser(bodyText)); } catch (Parser.ParseFailureException e) { return(Completion.ThrowSyntaxError($"Failed to parse body \"{bodyText}\".\n{e.Message}")); } //TODO detect strict mode: ContainsUseStrict bool strict = body.IsStrictMode; if (!parameters.IsSimpleParameterList() && strict) { return(Completion.ThrowSyntaxError($"parameters must be simple in strict mode. \"{P}\"")); } //TODO implement tree walking for checking if parameters or body contains a SuperCall or SuperProperty //TODO generator yield, async await errors var protoComp = Utils.GetPrototypeFromConstructor(newTarget, fallbackProto); if (protoComp.IsAbrupt()) { return(protoComp); } var proto = protoComp.value; var F = FunctionObject.FunctionAllocate(proto !, strict, kind); var realmF = F.Realm; var scope = realmF.GlobalEnv; FunctionObject.FunctionInitialize(F, FunctionCreateKind.Normal, parameters, body, scope); //TODO generator, async generator if (kind == FunctionKind.Normal) { F.MakeConstructor(); } F.SetFunctionName("anonymous"); return(Completion.NormalCompletion(F)); }