using Esprima.Ast;
using Jint.Native.Function;
using Jint.Runtime.Environments;
namespace Jint.Runtime.Interpreter.Expressions
{
internal sealed class JintFunctionExpression : JintExpression
{
private readonly JintFunctionDefinition _function;
public JintFunctionExpression(Engine engine, FunctionExpression function) : base(function)
{
_function = new JintFunctionDefinition(engine, function);
}
protected override ExpressionResult EvaluateInternal(EvaluationContext context)
{
return GetValue(context);
}
public override Completion GetValue(EvaluationContext context)
{
var closure = !_function.Function.Generator
? InstantiateOrdinaryFunctionExpression(context, _function.Name!)
: InstantiateGeneratorFunctionExpression(context, _function.Name!);
return new(CompletionType.Normal, closure, _expression);
}
///
/// 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 || engine._isStrict
? 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-instantiategeneratorfunctionexpression
///
private ScriptFunctionInstance InstantiateGeneratorFunctionExpression(EvaluationContext context, string name = "")
{
// TODO generators
return InstantiateOrdinaryFunctionExpression(context, name);
}
}
}