Skip to content

Commit

Permalink
Sync WIP generator structures to main (#1762)
Browse files Browse the repository at this point in the history
  • Loading branch information
lahma authored Jan 27, 2024
1 parent 1ddfad3 commit 62ab481
Show file tree
Hide file tree
Showing 12 changed files with 180 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -148,4 +148,36 @@ public void ShouldValueTaskAwaitCurrentStack()
Assert.Equal("12", log);
}
#endif

[Fact(Skip = "TODO es6-await https://github.com/sebastienros/jint/issues/1385")]
public void ShouldHaveCorrectOrder()
{
var engine = new Engine();
engine.Evaluate("var log = [];");

const string Script = """
async function foo(name) {
log.push(name + " start");
await log.push(name + " middle");
log.push(name + " end");
}

foo("First");
foo("Second");
""";

engine.Execute(Script);

var log = engine.GetValue("log").AsArray();
string[] expected = [
"First start",
"First middle",
"Second start",
"Second middle",
"First end",
"Second end",
];

Assert.Equal(expected, log.Select(x => x.AsString()).ToArray());
}
}
1 change: 1 addition & 0 deletions Jint/Native/Function/Function.cs
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,7 @@ internal ExecutionContext PrepareForOrdinaryCall(JsValue newTarget)
variableEnvironment: localEnv,
_privateEnvironment,
calleeRealm,
generator: null,
function: this);

// If callerContext is not already suspended, suspend callerContext.
Expand Down
20 changes: 18 additions & 2 deletions Jint/Native/Function/FunctionConstructor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,24 @@ private ScriptFunction InstantiateGeneratorFunctionObject(
Environment scope,
PrivateEnvironment? privateScope)
{
// TODO generators
return InstantiateOrdinaryFunctionObject(functionDeclaration, scope, privateScope);
var thisMode = functionDeclaration.Strict || _engine._isStrict
? FunctionThisMode.Strict
: FunctionThisMode.Global;

var name = functionDeclaration.Function.Id?.Name ?? "default";
var F = OrdinaryFunctionCreate(
_realm.Intrinsics.GeneratorFunction.PrototypeObject,
functionDeclaration,
thisMode,
scope,
privateScope);

F.SetFunctionName(name);

var prototype = OrdinaryObjectCreate(_engine, _realm.Intrinsics.GeneratorFunction.PrototypeObject.PrototypeObject);
F.DefinePropertyOrThrow(CommonProperties.Prototype, new PropertyDescriptor(prototype, PropertyFlag.Writable));

return F;
}
}
}
6 changes: 5 additions & 1 deletion Jint/Native/Function/FunctionInstance.Dynamic.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using Esprima.Ast;
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;
Expand Down Expand Up @@ -45,6 +46,8 @@ internal Function CreateDynamicFunction(
fallbackProto = static intrinsics => intrinsics.AsyncFunction.PrototypeObject;
break;
case FunctionKind.Generator:
fallbackProto = static intrinsics => intrinsics.GeneratorFunction.PrototypeObject;
break;
case FunctionKind.AsyncGenerator:
default:
ExceptionHelper.ThrowArgumentOutOfRangeException(nameof(kind), kind.ToString());
Expand Down Expand Up @@ -164,7 +167,8 @@ internal Function CreateDynamicFunction(

if (kind == FunctionKind.Generator)
{
ExceptionHelper.ThrowNotImplementedException("generators not implemented");
var prototype = OrdinaryObjectCreate(_engine, _realm.Intrinsics.GeneratorFunction.PrototypeObject.PrototypeObject);
F.DefinePropertyOrThrow(CommonProperties.Prototype, new PropertyDescriptor(prototype, PropertyFlag.Writable));
}
else if (kind == FunctionKind.AsyncGenerator)
{
Expand Down
15 changes: 7 additions & 8 deletions Jint/Native/Generator/GeneratorKind.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
namespace Jint.Native.Generator
namespace Jint.Native.Generator;

internal enum GeneratorKind
{
internal enum GeneratorKind
{
NonGenerator,
Sync,
Async
}
}
NonGenerator,
Sync,
Async
}
2 changes: 2 additions & 0 deletions Jint/Native/Global/GlobalObject.Properties.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public partial class GlobalObject
private static readonly Key propertyFloat32Array = "Float32Array";
private static readonly Key propertyFloat64Array = "Float64Array";
private static readonly Key propertyFunction = "Function";
private static readonly Key propertyGeneratorFunction = "Generator";
private static readonly Key propertyInt16Array = "Int16Array";
private static readonly Key propertyInt32Array = "Int32Array";
private static readonly Key propertyInt8Array = "Int8Array";
Expand Down Expand Up @@ -97,6 +98,7 @@ protected override void Initialize()
properties.AddDangerous(propertyFloat32Array, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Float32Array, PropertyFlags));
properties.AddDangerous(propertyFloat64Array, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Float64Array, PropertyFlags));
properties.AddDangerous(propertyFunction, new PropertyDescriptor(_realm.Intrinsics.Function, PropertyFlags));
properties.AddDangerous(propertyGeneratorFunction, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.GeneratorFunction, PropertyFlags));
properties.AddDangerous(propertyInt16Array, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Int16Array, PropertyFlags));
properties.AddDangerous(propertyInt32Array, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Int32Array, PropertyFlags));
properties.AddDangerous(propertyInt8Array, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Int8Array, PropertyFlags));
Expand Down
20 changes: 19 additions & 1 deletion Jint/Native/Iterator/IteratorInstance.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Globalization;
using Jint.Native.Generator;
using Jint.Native.Object;
using Jint.Native.RegExp;
using Jint.Runtime;
Expand Down Expand Up @@ -68,7 +69,7 @@ private ObjectInstance IteratorNext()
var instance = jsValue as ObjectInstance;
if (instance is null)
{
ExceptionHelper.ThrowTypeError(_target.Engine.Realm, "Iterator result " + jsValue + " is not an object");
ExceptionHelper.ThrowTypeError(_target.Engine.Realm, $"Iterator result {jsValue} is not an object");
}

return instance;
Expand Down Expand Up @@ -210,5 +211,22 @@ public override bool TryIteratorStep(out ObjectInstance nextItem)
return false;
}
}

internal sealed class GeneratorIterator : IteratorInstance
{
private readonly GeneratorInstance _generator;

public GeneratorIterator(Engine engine, GeneratorInstance generator) : base(engine)
{
_generator = generator;
}

public override bool TryIteratorStep(out ObjectInstance nextItem)
{
nextItem = IteratorResult.CreateValueIteratorPosition(_engine, done: JsBoolean.True);
return false;
}
}

}
}
5 changes: 1 addition & 4 deletions Jint/Runtime/Interpreter/EvaluationContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,9 @@ internal sealed class EvaluationContext
{
private readonly bool _shouldRunBeforeExecuteStatementChecks;

public EvaluationContext(Engine engine, in Completion? resumedCompletion = null)
public EvaluationContext(Engine engine)
{
Engine = engine;
ResumedCompletion = resumedCompletion ?? default; // TODO later
OperatorOverloadingAllowed = engine.Options.Interop.AllowOperatorOverloading;
_shouldRunBeforeExecuteStatementChecks = engine._constraints.Length > 0 || engine._isDebugMode;
}
Expand All @@ -22,13 +21,11 @@ public EvaluationContext(Engine engine, in Completion? resumedCompletion = null)
public EvaluationContext()
{
Engine = null!;
ResumedCompletion = default; // TODO later
OperatorOverloadingAllowed = false;
_shouldRunBeforeExecuteStatementChecks = false;
}

public readonly Engine Engine;
public readonly Completion ResumedCompletion;
public bool DebugMode => Engine._isDebugMode;

public SyntaxElement LastSyntaxElement
Expand Down
41 changes: 39 additions & 2 deletions Jint/Runtime/Interpreter/Expressions/JintFunctionExpression.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using Esprima.Ast;
using Jint.Native;
using Jint.Native.Function;
using Jint.Native.Object;
using Jint.Runtime.Descriptors;
using Jint.Runtime.Environments;

namespace Jint.Runtime.Interpreter.Expressions
Expand Down Expand Up @@ -123,8 +125,43 @@ private ScriptFunction InstantiateAsyncFunctionExpression(EvaluationContext cont
/// </summary>
private ScriptFunction InstantiateGeneratorFunctionExpression(EvaluationContext context, string? name)
{
// TODO generators
return InstantiateOrdinaryFunctionExpression(context, name);
var engine = context.Engine;
var runningExecutionContext = engine.ExecutionContext;
var scope = runningExecutionContext.LexicalEnvironment;

DeclarativeEnvironment? 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.GeneratorFunction.PrototypeObject,
_function,
thisMode,
funcEnv ?? scope,
privateScope
);

if (name is not null)
{
closure.SetFunctionName(name);
}

var prototype = ObjectInstance.OrdinaryObjectCreate(engine, intrinsics.GeneratorFunction.PrototypeObject.PrototypeObject);
closure.DefinePropertyOrThrow(CommonProperties.Prototype, new PropertyDescriptor(prototype, PropertyFlag.Writable));

funcEnv?.InitializeBinding(name!, closure);

return closure;
}
}
}
32 changes: 23 additions & 9 deletions Jint/Runtime/Interpreter/JintFunctionDefinition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using Esprima.Ast;
using Jint.Native;
using Jint.Native.Function;
using Jint.Native.Generator;
using Jint.Native.Promise;
using Jint.Runtime.Environments;
using Jint.Runtime.Interpreter.Expressions;
Expand Down Expand Up @@ -63,11 +64,7 @@ internal Completion EvaluateBody(EvaluationContext context, Function functionObj
}
else if (Function.Generator)
{
// TODO generators
// result = EvaluateGeneratorBody(functionObject, argumentsList);
argumentsInstance = context.Engine.FunctionDeclarationInstantiation(functionObject, argumentsList);
_bodyStatementList ??= new JintStatementList(Function);
result = _bodyStatementList.Execute(context);
result = EvaluateGeneratorBody(context, functionObject, argumentsList);
}
else
{
Expand Down Expand Up @@ -108,7 +105,11 @@ private static void AsyncFunctionStart(EvaluationContext context, PromiseCapabil
/// <summary>
/// https://tc39.es/ecma262/#sec-asyncblockstart
/// </summary>
private static void AsyncBlockStart(EvaluationContext context, PromiseCapability promiseCapability, Func<EvaluationContext, Completion> asyncBody, in ExecutionContext asyncContext)
private static void AsyncBlockStart(
EvaluationContext context,
PromiseCapability promiseCapability,
Func<EvaluationContext, Completion> asyncBody,
in ExecutionContext asyncContext)
{
var runningContext = context.Engine.ExecutionContext;
// Set the code evaluation state of asyncContext such that when evaluation is resumed for that execution contxt the following steps will be performed:
Expand Down Expand Up @@ -149,10 +150,23 @@ 8. Return unused.
/// <summary>
/// https://tc39.es/ecma262/#sec-runtime-semantics-evaluategeneratorbody
/// </summary>
private static Completion EvaluateGeneratorBody(Function functionObject, JsValue[] argumentsList)
private Completion EvaluateGeneratorBody(
EvaluationContext context,
Function functionObject,
JsValue[] argumentsList)
{
ExceptionHelper.ThrowNotImplementedException("generators not implemented");
return default;
var engine = context.Engine;
engine.FunctionDeclarationInstantiation(functionObject, argumentsList);
var G = engine.Realm.Intrinsics.Function.OrdinaryCreateFromConstructor(
functionObject,
static intrinsics => intrinsics.GeneratorFunction.PrototypeObject.PrototypeObject,
static (Engine engine , Realm _, object? _) => new GeneratorInstance(engine));

_bodyStatementList ??= new JintStatementList(Function);
_bodyStatementList.Reset();
G.GeneratorStart(_bodyStatementList);

return new Completion(CompletionType.Return, G, Function.Body);
}

internal State Initialize()
Expand Down
Loading

0 comments on commit 62ab481

Please sign in to comment.