Skip to content

Commit 62ab481

Browse files
authored
Sync WIP generator structures to main (#1762)
1 parent 1ddfad3 commit 62ab481

File tree

12 files changed

+180
-47
lines changed

12 files changed

+180
-47
lines changed

Jint.Tests/Runtime/AwaitTests.cs renamed to Jint.Tests/Runtime/AsyncTests.cs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,4 +148,36 @@ public void ShouldValueTaskAwaitCurrentStack()
148148
Assert.Equal("12", log);
149149
}
150150
#endif
151+
152+
[Fact(Skip = "TODO es6-await https://github.com/sebastienros/jint/issues/1385")]
153+
public void ShouldHaveCorrectOrder()
154+
{
155+
var engine = new Engine();
156+
engine.Evaluate("var log = [];");
157+
158+
const string Script = """
159+
async function foo(name) {
160+
log.push(name + " start");
161+
await log.push(name + " middle");
162+
log.push(name + " end");
163+
}
164+
165+
foo("First");
166+
foo("Second");
167+
""";
168+
169+
engine.Execute(Script);
170+
171+
var log = engine.GetValue("log").AsArray();
172+
string[] expected = [
173+
"First start",
174+
"First middle",
175+
"Second start",
176+
"Second middle",
177+
"First end",
178+
"Second end",
179+
];
180+
181+
Assert.Equal(expected, log.Select(x => x.AsString()).ToArray());
182+
}
151183
}

Jint/Native/Function/Function.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,7 @@ internal ExecutionContext PrepareForOrdinaryCall(JsValue newTarget)
332332
variableEnvironment: localEnv,
333333
_privateEnvironment,
334334
calleeRealm,
335+
generator: null,
335336
function: this);
336337

337338
// If callerContext is not already suspended, suspend callerContext.

Jint/Native/Function/FunctionConstructor.cs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,24 @@ private ScriptFunction InstantiateGeneratorFunctionObject(
114114
Environment scope,
115115
PrivateEnvironment? privateScope)
116116
{
117-
// TODO generators
118-
return InstantiateOrdinaryFunctionObject(functionDeclaration, scope, privateScope);
117+
var thisMode = functionDeclaration.Strict || _engine._isStrict
118+
? FunctionThisMode.Strict
119+
: FunctionThisMode.Global;
120+
121+
var name = functionDeclaration.Function.Id?.Name ?? "default";
122+
var F = OrdinaryFunctionCreate(
123+
_realm.Intrinsics.GeneratorFunction.PrototypeObject,
124+
functionDeclaration,
125+
thisMode,
126+
scope,
127+
privateScope);
128+
129+
F.SetFunctionName(name);
130+
131+
var prototype = OrdinaryObjectCreate(_engine, _realm.Intrinsics.GeneratorFunction.PrototypeObject.PrototypeObject);
132+
F.DefinePropertyOrThrow(CommonProperties.Prototype, new PropertyDescriptor(prototype, PropertyFlag.Writable));
133+
134+
return F;
119135
}
120136
}
121137
}

Jint/Native/Function/FunctionInstance.Dynamic.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using Esprima.Ast;
33
using Jint.Native.Object;
44
using Jint.Runtime;
5+
using Jint.Runtime.Descriptors;
56
using Jint.Runtime.Environments;
67
using Jint.Runtime.Interpreter;
78
using Environment = Jint.Runtime.Environments.Environment;
@@ -45,6 +46,8 @@ internal Function CreateDynamicFunction(
4546
fallbackProto = static intrinsics => intrinsics.AsyncFunction.PrototypeObject;
4647
break;
4748
case FunctionKind.Generator:
49+
fallbackProto = static intrinsics => intrinsics.GeneratorFunction.PrototypeObject;
50+
break;
4851
case FunctionKind.AsyncGenerator:
4952
default:
5053
ExceptionHelper.ThrowArgumentOutOfRangeException(nameof(kind), kind.ToString());
@@ -164,7 +167,8 @@ internal Function CreateDynamicFunction(
164167

165168
if (kind == FunctionKind.Generator)
166169
{
167-
ExceptionHelper.ThrowNotImplementedException("generators not implemented");
170+
var prototype = OrdinaryObjectCreate(_engine, _realm.Intrinsics.GeneratorFunction.PrototypeObject.PrototypeObject);
171+
F.DefinePropertyOrThrow(CommonProperties.Prototype, new PropertyDescriptor(prototype, PropertyFlag.Writable));
168172
}
169173
else if (kind == FunctionKind.AsyncGenerator)
170174
{
Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
namespace Jint.Native.Generator
1+
namespace Jint.Native.Generator;
2+
3+
internal enum GeneratorKind
24
{
3-
internal enum GeneratorKind
4-
{
5-
NonGenerator,
6-
Sync,
7-
Async
8-
}
9-
}
5+
NonGenerator,
6+
Sync,
7+
Async
8+
}

Jint/Native/Global/GlobalObject.Properties.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ public partial class GlobalObject
2323
private static readonly Key propertyFloat32Array = "Float32Array";
2424
private static readonly Key propertyFloat64Array = "Float64Array";
2525
private static readonly Key propertyFunction = "Function";
26+
private static readonly Key propertyGeneratorFunction = "Generator";
2627
private static readonly Key propertyInt16Array = "Int16Array";
2728
private static readonly Key propertyInt32Array = "Int32Array";
2829
private static readonly Key propertyInt8Array = "Int8Array";
@@ -97,6 +98,7 @@ protected override void Initialize()
9798
properties.AddDangerous(propertyFloat32Array, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Float32Array, PropertyFlags));
9899
properties.AddDangerous(propertyFloat64Array, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Float64Array, PropertyFlags));
99100
properties.AddDangerous(propertyFunction, new PropertyDescriptor(_realm.Intrinsics.Function, PropertyFlags));
101+
properties.AddDangerous(propertyGeneratorFunction, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.GeneratorFunction, PropertyFlags));
100102
properties.AddDangerous(propertyInt16Array, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Int16Array, PropertyFlags));
101103
properties.AddDangerous(propertyInt32Array, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Int32Array, PropertyFlags));
102104
properties.AddDangerous(propertyInt8Array, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Int8Array, PropertyFlags));

Jint/Native/Iterator/IteratorInstance.cs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Globalization;
2+
using Jint.Native.Generator;
23
using Jint.Native.Object;
34
using Jint.Native.RegExp;
45
using Jint.Runtime;
@@ -68,7 +69,7 @@ private ObjectInstance IteratorNext()
6869
var instance = jsValue as ObjectInstance;
6970
if (instance is null)
7071
{
71-
ExceptionHelper.ThrowTypeError(_target.Engine.Realm, "Iterator result " + jsValue + " is not an object");
72+
ExceptionHelper.ThrowTypeError(_target.Engine.Realm, $"Iterator result {jsValue} is not an object");
7273
}
7374

7475
return instance;
@@ -210,5 +211,22 @@ public override bool TryIteratorStep(out ObjectInstance nextItem)
210211
return false;
211212
}
212213
}
214+
215+
internal sealed class GeneratorIterator : IteratorInstance
216+
{
217+
private readonly GeneratorInstance _generator;
218+
219+
public GeneratorIterator(Engine engine, GeneratorInstance generator) : base(engine)
220+
{
221+
_generator = generator;
222+
}
223+
224+
public override bool TryIteratorStep(out ObjectInstance nextItem)
225+
{
226+
nextItem = IteratorResult.CreateValueIteratorPosition(_engine, done: JsBoolean.True);
227+
return false;
228+
}
229+
}
230+
213231
}
214232
}

Jint/Runtime/Interpreter/EvaluationContext.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,9 @@ internal sealed class EvaluationContext
1010
{
1111
private readonly bool _shouldRunBeforeExecuteStatementChecks;
1212

13-
public EvaluationContext(Engine engine, in Completion? resumedCompletion = null)
13+
public EvaluationContext(Engine engine)
1414
{
1515
Engine = engine;
16-
ResumedCompletion = resumedCompletion ?? default; // TODO later
1716
OperatorOverloadingAllowed = engine.Options.Interop.AllowOperatorOverloading;
1817
_shouldRunBeforeExecuteStatementChecks = engine._constraints.Length > 0 || engine._isDebugMode;
1918
}
@@ -22,13 +21,11 @@ public EvaluationContext(Engine engine, in Completion? resumedCompletion = null)
2221
public EvaluationContext()
2322
{
2423
Engine = null!;
25-
ResumedCompletion = default; // TODO later
2624
OperatorOverloadingAllowed = false;
2725
_shouldRunBeforeExecuteStatementChecks = false;
2826
}
2927

3028
public readonly Engine Engine;
31-
public readonly Completion ResumedCompletion;
3229
public bool DebugMode => Engine._isDebugMode;
3330

3431
public SyntaxElement LastSyntaxElement

Jint/Runtime/Interpreter/Expressions/JintFunctionExpression.cs

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
using Esprima.Ast;
22
using Jint.Native;
33
using Jint.Native.Function;
4+
using Jint.Native.Object;
5+
using Jint.Runtime.Descriptors;
46
using Jint.Runtime.Environments;
57

68
namespace Jint.Runtime.Interpreter.Expressions
@@ -123,8 +125,43 @@ private ScriptFunction InstantiateAsyncFunctionExpression(EvaluationContext cont
123125
/// </summary>
124126
private ScriptFunction InstantiateGeneratorFunctionExpression(EvaluationContext context, string? name)
125127
{
126-
// TODO generators
127-
return InstantiateOrdinaryFunctionExpression(context, name);
128+
var engine = context.Engine;
129+
var runningExecutionContext = engine.ExecutionContext;
130+
var scope = runningExecutionContext.LexicalEnvironment;
131+
132+
DeclarativeEnvironment? funcEnv = null;
133+
if (!string.IsNullOrWhiteSpace(name))
134+
{
135+
funcEnv = JintEnvironment.NewDeclarativeEnvironment(engine, engine.ExecutionContext.LexicalEnvironment);
136+
funcEnv.CreateImmutableBinding(name!, strict: false);
137+
}
138+
139+
var privateScope = runningExecutionContext.PrivateEnvironment;
140+
141+
var thisMode = _function.Strict || engine._isStrict
142+
? FunctionThisMode.Strict
143+
: FunctionThisMode.Global;
144+
145+
var intrinsics = engine.Realm.Intrinsics;
146+
var closure = intrinsics.Function.OrdinaryFunctionCreate(
147+
intrinsics.GeneratorFunction.PrototypeObject,
148+
_function,
149+
thisMode,
150+
funcEnv ?? scope,
151+
privateScope
152+
);
153+
154+
if (name is not null)
155+
{
156+
closure.SetFunctionName(name);
157+
}
158+
159+
var prototype = ObjectInstance.OrdinaryObjectCreate(engine, intrinsics.GeneratorFunction.PrototypeObject.PrototypeObject);
160+
closure.DefinePropertyOrThrow(CommonProperties.Prototype, new PropertyDescriptor(prototype, PropertyFlag.Writable));
161+
162+
funcEnv?.InitializeBinding(name!, closure);
163+
164+
return closure;
128165
}
129166
}
130167
}

Jint/Runtime/Interpreter/JintFunctionDefinition.cs

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using Esprima.Ast;
33
using Jint.Native;
44
using Jint.Native.Function;
5+
using Jint.Native.Generator;
56
using Jint.Native.Promise;
67
using Jint.Runtime.Environments;
78
using Jint.Runtime.Interpreter.Expressions;
@@ -63,11 +64,7 @@ internal Completion EvaluateBody(EvaluationContext context, Function functionObj
6364
}
6465
else if (Function.Generator)
6566
{
66-
// TODO generators
67-
// result = EvaluateGeneratorBody(functionObject, argumentsList);
68-
argumentsInstance = context.Engine.FunctionDeclarationInstantiation(functionObject, argumentsList);
69-
_bodyStatementList ??= new JintStatementList(Function);
70-
result = _bodyStatementList.Execute(context);
67+
result = EvaluateGeneratorBody(context, functionObject, argumentsList);
7168
}
7269
else
7370
{
@@ -108,7 +105,11 @@ private static void AsyncFunctionStart(EvaluationContext context, PromiseCapabil
108105
/// <summary>
109106
/// https://tc39.es/ecma262/#sec-asyncblockstart
110107
/// </summary>
111-
private static void AsyncBlockStart(EvaluationContext context, PromiseCapability promiseCapability, Func<EvaluationContext, Completion> asyncBody, in ExecutionContext asyncContext)
108+
private static void AsyncBlockStart(
109+
EvaluationContext context,
110+
PromiseCapability promiseCapability,
111+
Func<EvaluationContext, Completion> asyncBody,
112+
in ExecutionContext asyncContext)
112113
{
113114
var runningContext = context.Engine.ExecutionContext;
114115
// Set the code evaluation state of asyncContext such that when evaluation is resumed for that execution contxt the following steps will be performed:
@@ -149,10 +150,23 @@ 8. Return unused.
149150
/// <summary>
150151
/// https://tc39.es/ecma262/#sec-runtime-semantics-evaluategeneratorbody
151152
/// </summary>
152-
private static Completion EvaluateGeneratorBody(Function functionObject, JsValue[] argumentsList)
153+
private Completion EvaluateGeneratorBody(
154+
EvaluationContext context,
155+
Function functionObject,
156+
JsValue[] argumentsList)
153157
{
154-
ExceptionHelper.ThrowNotImplementedException("generators not implemented");
155-
return default;
158+
var engine = context.Engine;
159+
engine.FunctionDeclarationInstantiation(functionObject, argumentsList);
160+
var G = engine.Realm.Intrinsics.Function.OrdinaryCreateFromConstructor(
161+
functionObject,
162+
static intrinsics => intrinsics.GeneratorFunction.PrototypeObject.PrototypeObject,
163+
static (Engine engine , Realm _, object? _) => new GeneratorInstance(engine));
164+
165+
_bodyStatementList ??= new JintStatementList(Function);
166+
_bodyStatementList.Reset();
167+
G.GeneratorStart(_bodyStatementList);
168+
169+
return new Completion(CompletionType.Return, G, Function.Body);
156170
}
157171

158172
internal State Initialize()

0 commit comments

Comments
 (0)