123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281 |
- using Esprima;
- using Esprima.Ast;
- using Jint.Native.Object;
- using Jint.Runtime;
- using Jint.Runtime.Descriptors;
- using Jint.Runtime.Environments;
- using Jint.Runtime.Interpreter;
- namespace Jint.Native.Function
- {
- /// <summary>
- /// https://tc39.es/ecma262/#sec-function-constructor
- /// </summary>
- public sealed class FunctionConstructor : FunctionInstance, IConstructor
- {
- private static readonly JsString _functionName = new JsString("Function");
- private static readonly JsString _functionNameAnonymous = new JsString("anonymous");
- private readonly JavaScriptParser _parser = new(new ParserOptions { Tolerant = false });
- internal FunctionConstructor(
- Engine engine,
- Realm realm,
- ObjectPrototype objectPrototype)
- : base(engine, realm, _functionName)
- {
- PrototypeObject = new FunctionPrototype(engine, realm, objectPrototype);
- _prototype = PrototypeObject;
- _prototypeDescriptor = new PropertyDescriptor(PrototypeObject, PropertyFlag.AllForbidden);
- _length = new PropertyDescriptor(JsNumber.PositiveOne, PropertyFlag.Configurable);
- }
- public FunctionPrototype PrototypeObject { get; }
- protected internal override JsValue Call(JsValue thisObject, JsValue[] arguments)
- {
- return Construct(arguments, thisObject);
- }
- ObjectInstance IConstructor.Construct(JsValue[] arguments, JsValue newTarget) => Construct(arguments, newTarget);
- private ObjectInstance Construct(JsValue[] arguments, JsValue newTarget)
- {
- var function = CreateDynamicFunction(
- this,
- newTarget,
- FunctionKind.Normal,
- arguments);
- return function;
- }
- /// <summary>
- /// https://tc39.es/ecma262/#sec-createdynamicfunction
- /// </summary>
- 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<Intrinsics, ObjectInstance>? fallbackProto = null;
- switch (kind)
- {
- case FunctionKind.Normal:
- fallbackProto = static intrinsics => intrinsics.Function.PrototypeObject;
- break;
- case FunctionKind.Generator:
- case FunctionKind.AsyncGenerator:
- case FunctionKind.Async:
- 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:
- ExceptionHelper.ThrowNotImplementedException("Async functions not implemented");
- 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.Generator:
- functionExpression = "function* f(";
- break;
- case FunctionKind.Async:
- ExceptionHelper.ThrowNotImplementedException("Async functions not implemented");
- 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 + "}";
- }
- }
- function = (IFunction) _parser.ParseScript(functionExpression).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? privateScope = null;
- var definition = new JintFunctionDefinition(function);
- FunctionInstance F = OrdinaryFunctionCreate(proto, definition, function.Strict ? FunctionThisMode.Strict : FunctionThisMode.Global, scope, privateScope);
- 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;
- }
- /// <summary>
- /// https://tc39.es/ecma262/#sec-ordinaryfunctioncreate
- /// </summary>
- 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
- };
- }
- /// <summary>
- /// https://tc39.es/ecma262/#sec-runtime-semantics-instantiatefunctionobject
- /// </summary>
- internal FunctionInstance InstantiateFunctionObject(
- JintFunctionDefinition functionDeclaration,
- EnvironmentRecord scope,
- PrivateEnvironmentRecord? privateScope)
- {
- return !functionDeclaration.Function.Generator
- ? InstantiateOrdinaryFunctionObject(functionDeclaration, scope, privateScope)
- : InstantiateGeneratorFunctionObject(functionDeclaration, scope, privateScope);
- }
- /// <summary>
- /// https://tc39.es/ecma262/#sec-runtime-semantics-instantiateordinaryfunctionobject
- /// </summary>
- private FunctionInstance InstantiateOrdinaryFunctionObject(
- JintFunctionDefinition functionDeclaration,
- EnvironmentRecord scope,
- PrivateEnvironmentRecord? privateScope)
- {
- var F = OrdinaryFunctionCreate(
- _realm.Intrinsics.Function.PrototypeObject,
- functionDeclaration,
- functionDeclaration.ThisMode,
- scope,
- privateScope);
- var name = functionDeclaration.Name ?? "default";
- F.SetFunctionName(name);
- F.MakeConstructor();
- return F;
- }
- /// <summary>
- /// https://tc39.es/ecma262/#sec-runtime-semantics-instantiategeneratorfunctionobject
- /// </summary>
- private FunctionInstance InstantiateGeneratorFunctionObject(
- JintFunctionDefinition functionDeclaration,
- EnvironmentRecord scope,
- PrivateEnvironmentRecord? privateScope)
- {
- // TODO generators
- return InstantiateOrdinaryFunctionObject(functionDeclaration, scope, privateScope);
- }
- }
- }
|