using Esprima.Ast; using Jint.Native; using Jint.Native.Function; using Jint.Runtime.Environments; namespace Jint.Runtime.Interpreter.Expressions { internal sealed class JintFunctionExpression : JintExpression { private readonly JintFunctionDefinition _function; public JintFunctionExpression(FunctionExpression function) : base(function) { _function = new JintFunctionDefinition(function); } protected override object EvaluateInternal(EvaluationContext context) { return GetValue(context); } public override JsValue GetValue(EvaluationContext context) { ScriptFunctionInstance closure; if (!_function.Function.Generator) { closure = _function.Function.Async ? InstantiateAsyncFunctionExpression(context, _function.Name) : InstantiateOrdinaryFunctionExpression(context, _function.Name); } else { closure = InstantiateGeneratorFunctionExpression(context, _function.Name); } return closure; } /// /// https://tc39.es/ecma262/#sec-runtime-semantics-instantiateordinaryfunctionexpression /// private ScriptFunctionInstance InstantiateOrdinaryFunctionExpression(EvaluationContext context, string? name = "") { var engine = context.Engine; var runningExecutionContext = engine.ExecutionContext; var scope = runningExecutionContext.LexicalEnvironment; DeclarativeEnvironmentRecord? funcEnv = null; if (!string.IsNullOrWhiteSpace(name)) { funcEnv = JintEnvironment.NewDeclarativeEnvironment(engine, engine.ExecutionContext.LexicalEnvironment); funcEnv.CreateImmutableBinding(name!, strict: false); } var privateScope = runningExecutionContext.PrivateEnvironment; var thisMode = _function.Strict ? FunctionThisMode.Strict : FunctionThisMode.Global; var intrinsics = engine.Realm.Intrinsics; var closure = intrinsics.Function.OrdinaryFunctionCreate( intrinsics.Function.PrototypeObject, _function, thisMode, funcEnv ?? scope, privateScope ); if (name is not null) { closure.SetFunctionName(name); } closure.MakeConstructor(); funcEnv?.InitializeBinding(name!, closure); return closure; } /// /// https://tc39.es/ecma262/#sec-runtime-semantics-instantiateasyncfunctionexpression /// private ScriptFunctionInstance InstantiateAsyncFunctionExpression(EvaluationContext context, string? name = "") { var engine = context.Engine; var runningExecutionContext = engine.ExecutionContext; var scope = runningExecutionContext.LexicalEnvironment; DeclarativeEnvironmentRecord? funcEnv = null; if (!string.IsNullOrWhiteSpace(name)) { funcEnv = JintEnvironment.NewDeclarativeEnvironment(engine, engine.ExecutionContext.LexicalEnvironment); funcEnv.CreateImmutableBinding(name!, strict: false); } var privateScope = runningExecutionContext.PrivateEnvironment; var thisMode = _function.Strict ? FunctionThisMode.Strict : FunctionThisMode.Global; var intrinsics = engine.Realm.Intrinsics; var closure = intrinsics.Function.OrdinaryFunctionCreate( intrinsics.AsyncFunction.PrototypeObject, _function, thisMode, funcEnv ?? scope, privateScope ); closure.SetFunctionName(name ?? ""); funcEnv?.InitializeBinding(name!, closure); return closure; } /// /// https://tc39.es/ecma262/#sec-runtime-semantics-instantiategeneratorfunctionexpression /// private ScriptFunctionInstance InstantiateGeneratorFunctionExpression(EvaluationContext context, string? name) { // TODO generators return InstantiateOrdinaryFunctionExpression(context, name); } } }