using Jint.Native.Object; using Jint.Runtime; using Jint.Runtime.Descriptors; using Jint.Runtime.Environments; using Jint.Runtime.Interpreter; using Environment = Jint.Runtime.Environments.Environment; namespace Jint.Native.Function; #pragma warning disable MA0049 public partial class Function #pragma warning restore MA0049 { private static readonly JsString _functionNameAnonymous = new JsString("anonymous"); /// /// https://tc39.es/ecma262/#sec-createdynamicfunction /// internal Function CreateDynamicFunction( ObjectInstance constructor, JsValue newTarget, FunctionKind kind, JsCallArguments arguments) { // 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: fallbackProto = static intrinsics => intrinsics.GeneratorFunction.PrototypeObject; break; case FunctionKind.AsyncGenerator: fallbackProto = static intrinsics => intrinsics.AsyncGeneratorFunction.PrototypeObject; break; default: Throw.ArgumentOutOfRangeException(nameof(kind), kind.ToString()); break; } var argCount = arguments.Length; var p = ""; var body = ""; if (argCount == 1) { body = TypeConverter.ToString(arguments[0]); } else if (argCount > 1) { var firstArg = arguments[0]; p = TypeConverter.ToString(firstArg); for (var k = 1; k < argCount - 1; k++) { var nextArg = arguments[k]; p += "," + TypeConverter.ToString(nextArg); } body = TypeConverter.ToString(arguments[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: functionExpression = "async function* f(){}"; break; default: Throw.ArgumentOutOfRangeException(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: functionExpression = "async function* f("; break; default: Throw.ArgumentOutOfRangeException(nameof(kind), kind.ToString()); break; } if (p.Contains('/')) { // ensure comments don't screw up things functionExpression += "\n" + p + "\n"; } else { functionExpression += p; } functionExpression += ")"; if (body.Contains('/')) { // ensure comments don't screw up things functionExpression += "{\n" + body + "\n}"; } else { functionExpression += "{" + body + "}"; } } var parserOptions = _engine.GetActiveParserOptions(); if (!parserOptions.AllowReturnOutsideFunction) { parserOptions = parserOptions with { AllowReturnOutsideFunction = true }; } Parser parser = new(parserOptions); function = (IFunction) parser.ParseScriptGuarded(callerRealm, functionExpression, strict: _engine._isStrict).Body[0]; } catch (ParseErrorException ex) { Throw.SyntaxError(_engine.ExecutionContext.Realm, ex.Message); } var proto = GetPrototypeFromConstructor(newTarget, fallbackProto); var realmF = _realm; var scope = realmF.GlobalEnv; PrivateEnvironment? privateEnv = null; var definition = new JintFunctionDefinition(function); Function F = OrdinaryFunctionCreate(proto, definition, function.IsStrict() ? FunctionThisMode.Strict : FunctionThisMode.Global, scope, privateEnv); F.SetFunctionName(_functionNameAnonymous, force: true); if (kind == FunctionKind.Generator) { var prototype = OrdinaryObjectCreate(_engine, _realm.Intrinsics.GeneratorFunction.PrototypeObject.PrototypeObject); F.DefinePropertyOrThrow(CommonProperties.Prototype, new PropertyDescriptor(prototype, PropertyFlag.Writable)); } else if (kind == FunctionKind.AsyncGenerator) { var prototype = OrdinaryObjectCreate(_engine, _realm.Intrinsics.AsyncGeneratorFunction.PrototypeObject.PrototypeObject); F.DefinePropertyOrThrow(CommonProperties.Prototype, new PropertyDescriptor(prototype, PropertyFlag.Writable)); } else if (kind == FunctionKind.Normal) { F.MakeConstructor(); } return F; } /// /// https://tc39.es/ecma262/#sec-ordinaryfunctioncreate /// internal ScriptFunction OrdinaryFunctionCreate( ObjectInstance functionPrototype, JintFunctionDefinition function, FunctionThisMode thisMode, Environment scope, PrivateEnvironment? privateScope) { return new ScriptFunction( _engine, function, scope, thisMode, functionPrototype) { _privateEnvironment = privateScope, _realm = _realm, }; } }