using Esprima; using Esprima.Ast; using Jint.Native.Object; using Jint.Runtime; using Jint.Runtime.Environments; using Jint.Runtime.Interpreter; namespace Jint.Native.Function; public partial class FunctionInstance { private static readonly JsString _functionNameAnonymous = new JsString("anonymous"); /// /// https://tc39.es/ecma262/#sec-createdynamicfunction /// internal FunctionInstance CreateDynamicFunction( ObjectInstance constructor, JsValue newTarget, FunctionKind kind, JsValue[] args) { // TODO var callerContext = _engine.GetExecutionContext(1); var callerContext = _engine.ExecutionContext; var callerRealm = callerContext.Realm; var calleeRealm = _engine.ExecutionContext.Realm; _engine._host.EnsureCanCompileStrings(callerRealm, calleeRealm); if (newTarget.IsUndefined()) { newTarget = constructor; } Func? fallbackProto = null; switch (kind) { case FunctionKind.Normal: fallbackProto = static intrinsics => intrinsics.Function.PrototypeObject; break; case FunctionKind.Async: fallbackProto = static intrinsics => intrinsics.AsyncFunction.PrototypeObject; break; case FunctionKind.Generator: case FunctionKind.AsyncGenerator: default: ExceptionHelper.ThrowArgumentOutOfRangeException(nameof(kind), kind.ToString()); break; } var argCount = args.Length; var p = ""; var body = ""; if (argCount == 1) { body = TypeConverter.ToString(args[0]); } else if (argCount > 1) { var firstArg = args[0]; p = TypeConverter.ToString(firstArg); for (var k = 1; k < argCount - 1; k++) { var nextArg = args[k]; p += "," + TypeConverter.ToString(nextArg); } body = TypeConverter.ToString(args[argCount - 1]); } IFunction? function = null; try { string? functionExpression = null; if (argCount == 0) { switch (kind) { case FunctionKind.Normal: functionExpression = "function f(){}"; break; case FunctionKind.Generator: functionExpression = "function* f(){}"; break; case FunctionKind.Async: functionExpression = "async function f(){}"; break; case FunctionKind.AsyncGenerator: ExceptionHelper.ThrowNotImplementedException("Async generators not implemented"); break; default: ExceptionHelper.ThrowArgumentOutOfRangeException(nameof(kind), kind.ToString()); break; } } else { switch (kind) { case FunctionKind.Normal: functionExpression = "function f("; break; case FunctionKind.Async: functionExpression = "async function f("; break; case FunctionKind.Generator: functionExpression = "function* f("; break; case FunctionKind.AsyncGenerator: ExceptionHelper.ThrowNotImplementedException("Async generators not implemented"); break; default: ExceptionHelper.ThrowArgumentOutOfRangeException(nameof(kind), kind.ToString()); break; } if (p.IndexOf('/') != -1) { // ensure comments don't screw up things functionExpression += "\n" + p + "\n"; } else { functionExpression += p; } functionExpression += ")"; if (body.IndexOf('/') != -1) { // ensure comments don't screw up things functionExpression += "{\n" + body + "\n}"; } else { functionExpression += "{" + body + "}"; } } JavaScriptParser parser = new(new ParserOptions { Tolerant = false, RegexTimeout = _engine.Options.Constraints.RegexTimeout }); function = (IFunction) parser.ParseScript(functionExpression, source: null, _engine._isStrict).Body[0]; } catch (ParserException ex) { ExceptionHelper.ThrowSyntaxError(_engine.ExecutionContext.Realm, ex.Message); } var proto = GetPrototypeFromConstructor(newTarget, fallbackProto); var realmF = _realm; var scope = realmF.GlobalEnv; PrivateEnvironmentRecord? privateEnv = null; var definition = new JintFunctionDefinition(function); FunctionInstance F = OrdinaryFunctionCreate(proto, definition, function.Strict ? FunctionThisMode.Strict : FunctionThisMode.Global, scope, privateEnv); F.SetFunctionName(_functionNameAnonymous, force: true); if (kind == FunctionKind.Generator) { ExceptionHelper.ThrowNotImplementedException("generators not implemented"); } else if (kind == FunctionKind.AsyncGenerator) { // TODO // Let prototype be ! OrdinaryObjectCreate(%AsyncGeneratorFunction.prototype.prototype%). // Perform DefinePropertyOrThrow(F, "prototype", PropertyDescriptor { [[Value]]: prototype, [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false }). ExceptionHelper.ThrowNotImplementedException("async generators not implemented"); } else if (kind == FunctionKind.Normal) { F.MakeConstructor(); } return F; } /// /// https://tc39.es/ecma262/#sec-ordinaryfunctioncreate /// internal ScriptFunctionInstance OrdinaryFunctionCreate( ObjectInstance functionPrototype, JintFunctionDefinition function, FunctionThisMode thisMode, EnvironmentRecord scope, PrivateEnvironmentRecord? privateScope) { return new ScriptFunctionInstance( _engine, function, scope, thisMode, functionPrototype) { _privateEnvironment = privateScope, _realm = _realm }; } }