|
@@ -1,4 +1,5 @@
|
|
|
-using Esprima;
|
|
|
+using System;
|
|
|
+using Esprima;
|
|
|
using Esprima.Ast;
|
|
|
using Jint.Native.Object;
|
|
|
using Jint.Runtime;
|
|
@@ -38,43 +39,119 @@ namespace Jint.Native.Function
|
|
|
|
|
|
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>
|
|
|
- private ObjectInstance Construct(JsValue[] arguments, JsValue newTarget)
|
|
|
+ internal FunctionInstance CreateDynamicFunction(
|
|
|
+ ObjectInstance constructor,
|
|
|
+ JsValue newTarget,
|
|
|
+ FunctionKind kind,
|
|
|
+ JsValue[] args)
|
|
|
{
|
|
|
- var argCount = arguments.Length;
|
|
|
- string p = "";
|
|
|
- string body = "";
|
|
|
+ // 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(arguments[0]);
|
|
|
+ body = TypeConverter.ToString(args[0]);
|
|
|
}
|
|
|
else if (argCount > 1)
|
|
|
{
|
|
|
- var firstArg = arguments[0];
|
|
|
+ var firstArg = args[0];
|
|
|
p = TypeConverter.ToString(firstArg);
|
|
|
for (var k = 1; k < argCount - 1; k++)
|
|
|
{
|
|
|
- var nextArg = arguments[k];
|
|
|
+ var nextArg = args[k];
|
|
|
p += "," + TypeConverter.ToString(nextArg);
|
|
|
}
|
|
|
|
|
|
- body = TypeConverter.ToString(arguments[argCount-1]);
|
|
|
+ body = TypeConverter.ToString(args[argCount - 1]);
|
|
|
}
|
|
|
|
|
|
IFunction function = null;
|
|
|
try
|
|
|
{
|
|
|
- string functionExpression;
|
|
|
+ string functionExpression = null;
|
|
|
if (argCount == 0)
|
|
|
{
|
|
|
- functionExpression = "function f(){}";
|
|
|
+ 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
|
|
|
{
|
|
|
- functionExpression = "function f(";
|
|
|
+ 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
|
|
@@ -101,49 +178,105 @@ namespace Jint.Native.Function
|
|
|
var parser = new JavaScriptParser(functionExpression, ParserOptions);
|
|
|
function = (IFunction) parser.ParseScript().Body[0];
|
|
|
}
|
|
|
- catch (ParserException)
|
|
|
+ catch (ParserException ex)
|
|
|
{
|
|
|
- ExceptionHelper.ThrowSyntaxError(_realm);
|
|
|
+ ExceptionHelper.ThrowSyntaxError(_engine.ExecutionContext.Realm, ex.Message);
|
|
|
}
|
|
|
|
|
|
- // TODO generators etc, rewrite logic
|
|
|
- var proto = GetPrototypeFromConstructor(newTarget, static intrinsics => intrinsics.Function.PrototypeObject);
|
|
|
+ var proto = GetPrototypeFromConstructor(newTarget, fallbackProto);
|
|
|
+ var realmF = _realm;
|
|
|
+ var scope = realmF.GlobalEnv;
|
|
|
+ PrivateEnvironmentRecord privateScope = null;
|
|
|
+
|
|
|
+ var definition = new JintFunctionDefinition(_engine, function);
|
|
|
+ FunctionInstance F = OrdinaryFunctionCreate(proto, definition, function.Strict ? FunctionThisMode.Strict : FunctionThisMode.Global, scope, privateScope);
|
|
|
+ F.SetFunctionName(_functionNameAnonymous, force: true);
|
|
|
|
|
|
- var functionObject = new ScriptFunctionInstance(
|
|
|
- Engine,
|
|
|
+ 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,
|
|
|
- _realm.GlobalEnv,
|
|
|
- function.Strict,
|
|
|
- proto)
|
|
|
+ scope,
|
|
|
+ thisMode,
|
|
|
+ functionPrototype)
|
|
|
{
|
|
|
+ _privateEnvironment = privateScope,
|
|
|
_realm = _realm
|
|
|
};
|
|
|
-
|
|
|
- functionObject.MakeConstructor();
|
|
|
-
|
|
|
- // the function is not actually a named function
|
|
|
- functionObject.SetFunctionName(_functionNameAnonymous, force: true);
|
|
|
-
|
|
|
- return functionObject;
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// https://tc39.es/ecma262/#sec-runtime-semantics-instantiatefunctionobject
|
|
|
/// </summary>
|
|
|
- internal FunctionInstance InstantiateFunctionObject(JintFunctionDefinition functionDeclaration, EnvironmentRecord env)
|
|
|
+ internal FunctionInstance InstantiateFunctionObject(
|
|
|
+ JintFunctionDefinition functionDeclaration,
|
|
|
+ EnvironmentRecord scope,
|
|
|
+ PrivateEnvironmentRecord privateScope)
|
|
|
{
|
|
|
- var functionObject = new ScriptFunctionInstance(
|
|
|
- Engine,
|
|
|
+ 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,
|
|
|
- env,
|
|
|
- functionDeclaration.ThisMode)
|
|
|
- {
|
|
|
- _realm = _realm
|
|
|
- };
|
|
|
+ functionDeclaration.ThisMode,
|
|
|
+ scope,
|
|
|
+ privateScope);
|
|
|
|
|
|
- functionObject.MakeConstructor();
|
|
|
+ var name = functionDeclaration.Name ?? "default";
|
|
|
+ F.SetFunctionName(name);
|
|
|
+ F.MakeConstructor();
|
|
|
+ return F;
|
|
|
+ }
|
|
|
|
|
|
- return functionObject;
|
|
|
+ /// <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);
|
|
|
}
|
|
|
}
|
|
|
}
|