Skip to content

Commit

Permalink
wip-check
Browse files Browse the repository at this point in the history
  • Loading branch information
lahma committed Oct 25, 2023
1 parent b88a30e commit 8cc1487
Show file tree
Hide file tree
Showing 10 changed files with 221 additions and 40 deletions.
180 changes: 178 additions & 2 deletions Jint.Tests/Runtime/GeneratorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ namespace Jint.Tests.Runtime;
public class GeneratorTests
{
[Fact]
public void BasicYield()
public void LoopYield()
{
const string Script = @"
const foo = function*() {
Expand All @@ -15,9 +15,185 @@ public void BasicYield()
let str = '';
for (const val of foo()) {
str += val;
}";
}
return str;";

var engine = new Engine();
Assert.Equal("abc", engine.Evaluate(Script));
}

[Fact]
public void ReturnDuringYield()
{
const string Script = @"
const foo = function*() {
yield 'a';
return;
yield 'c';
};
let str = '';
for (const val of foo()) {
str += val;
}
return str;";

var engine = new Engine();
Assert.Equal("a", engine.Evaluate(Script));
}

[Fact]
public void LoneReturnInYield()
{
const string Script = @"
const foo = function*() {
return;
};
let str = '';
for (const val of foo()) {
str += val;
}
return str;";

var engine = new Engine();
Assert.Equal("", engine.Evaluate(Script));
}

[Fact]
public void LoneReturnValueInYield()
{
const string Script = @"
const foo = function*() {
return 'a';
};
let str = '';
for (const val of foo()) {
str += val;
}
return str;";

var engine = new Engine();
Assert.Equal("", engine.Evaluate(Script));
}

[Fact]
public void YieldUndefined()
{
const string Script = @"
const foo = function*() {
yield undefined;
};
let str = '';
for (const val of foo()) {
str += val;
}
return str;";

var engine = new Engine();
Assert.Equal("undefined", engine.Evaluate(Script));
}

[Fact]
public void ReturnUndefined()
{
const string Script = @"
const foo = function*() {
return undefined;
};
let str = '';
for (const val of foo()) {
str += val;
}
return str;";

var engine = new Engine();
Assert.Equal("", engine.Evaluate(Script));
}

[Fact]
public void Basic()
{
const string Script = @"
function * generator(){
yield 5; yield 6;
};
var iterator = generator();
var item = iterator.next();
var passed = item.value === 5 && item.done === false;
item = iterator.next();
passed &= item.value === 6 && item.done === false;
item = iterator.next();
passed &= item.value === void undefined && item.done === true;
return passed;";

var engine = new Engine();
Assert.True(engine.Evaluate(Script).AsBoolean());

Check failure on line 134 in Jint.Tests/Runtime/GeneratorTests.cs

View workflow job for this annotation

GitHub Actions / linux

Jint.Tests.Runtime.GeneratorTests.Basic

System.ArgumentException : Expected boolean but got Integer

Check failure on line 134 in Jint.Tests/Runtime/GeneratorTests.cs

View workflow job for this annotation

GitHub Actions / macos

Jint.Tests.Runtime.GeneratorTests.Basic

System.ArgumentException : Expected boolean but got Integer
}

[Fact]
public void FunctionExpressions()
{
const string Script = @"
var generator = function * (){
yield 5; yield 6;
};
var iterator = generator();
var item = iterator.next();
var passed = item.value === 5 && item.done === false;
item = iterator.next();
passed &= item.value === 6 && item.done === false;
item = iterator.next();
passed &= item.value === void undefined && item.done === true;
return passed;";

var engine = new Engine();
Assert.True(engine.Evaluate(Script).AsBoolean());

Check failure on line 154 in Jint.Tests/Runtime/GeneratorTests.cs

View workflow job for this annotation

GitHub Actions / linux

Jint.Tests.Runtime.GeneratorTests.FunctionExpressions

System.ArgumentException : Expected boolean but got Integer

Check failure on line 154 in Jint.Tests/Runtime/GeneratorTests.cs

View workflow job for this annotation

GitHub Actions / macos

Jint.Tests.Runtime.GeneratorTests.FunctionExpressions

System.ArgumentException : Expected boolean but got Integer
}

[Fact]
public void CorrectThisBinding()
{
const string Script = @"
function * generator(){
yield this.x; yield this.y;
};
var iterator = { g: generator, x: 5, y: 6 }.g();
var item = iterator.next();
var passed = item.value === 5 && item.done === false;
item = iterator.next();
passed &= item.value === 6 && item.done === false;
item = iterator.next();
passed &= item.value === void undefined && item.done === true;
return passed;";

var engine = new Engine();
Assert.True(engine.Evaluate(Script).AsBoolean());

Check failure on line 174 in Jint.Tests/Runtime/GeneratorTests.cs

View workflow job for this annotation

GitHub Actions / linux

Jint.Tests.Runtime.GeneratorTests.CorrectThisBinding

System.ArgumentException : Expected boolean but got Integer

Check failure on line 174 in Jint.Tests/Runtime/GeneratorTests.cs

View workflow job for this annotation

GitHub Actions / macos

Jint.Tests.Runtime.GeneratorTests.CorrectThisBinding

System.ArgumentException : Expected boolean but got Integer
}

[Fact]
public void Sending()
{
const string Script = @"
var sent;
function * generator(){
sent = [yield 5, yield 6];
};
var iterator = generator();
iterator.next();
iterator.next(""foo"");
iterator.next(""bar"");";

var engine = new Engine();
engine.Execute(Script);

var sent0 = engine.Evaluate("sent[0]");
var sent1 = engine.Evaluate("sent[1]");

Assert.Equal("foo", sent0);

Check failure on line 196 in Jint.Tests/Runtime/GeneratorTests.cs

View workflow job for this annotation

GitHub Actions / linux

Jint.Tests.Runtime.GeneratorTests.Sending

Assert.Equal() Failure: Values differ Expected: foo Actual: 5

Check failure on line 196 in Jint.Tests/Runtime/GeneratorTests.cs

View workflow job for this annotation

GitHub Actions / macos

Jint.Tests.Runtime.GeneratorTests.Sending

Assert.Equal() Failure: Values differ Expected: foo Actual: 5
Assert.Equal("bar", sent1);
}
}
21 changes: 15 additions & 6 deletions Jint/Native/Generator/GeneratorInstance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ internal sealed class GeneratorInstance : ObjectInstance
private ExecutionContext _generatorContext;
private readonly JsValue? _generatorBrand = null;
private JintStatementList _generatorBody = null!;
public JsValue? _nextValue;

public GeneratorInstance(Engine engine) : base(engine)
{
Expand Down Expand Up @@ -50,6 +51,8 @@ public JsValue GeneratorResume(JsValue value, JsValue? generatorBrand)

// 6. Suspend methodContext.

_nextValue = value;

var context = _engine._activeEvaluationContext;
return ResumeExecution(genContext, context!);
}
Expand Down Expand Up @@ -79,9 +82,10 @@ public JsValue GeneratorResumeAbrupt(in Completion abruptCompletion, JsValue? ge
var genContext = _generatorContext;
var methodContext = _engine.ExecutionContext;

// Suspend methodContext.
// Suspend methodContext
_nextValue = abruptCompletion.Value;

return ResumeExecution(genContext, new EvaluationContext(_engine, abruptCompletion));
return ResumeExecution(genContext, new EvaluationContext(_engine));
}

private JsValue ResumeExecution(ExecutionContext genContext, EvaluationContext context)
Expand All @@ -92,19 +96,24 @@ private JsValue ResumeExecution(ExecutionContext genContext, EvaluationContext c
var result = _generatorBody.Execute(context);
_engine.LeaveExecutionContext();

_nextValue = null;

ObjectInstance? resultValue = null;
if (result.Type == CompletionType.Normal)
{
_generatorState = GeneratorState.Completed;
var value = context.ResumedCompletion.GetValueOrDefault();
resultValue = IteratorInstance.ValueIteratorPosition.Done(_engine, value);
resultValue = IteratorResult.CreateValueIteratorPosition(_engine, result.Value, done: JsBoolean.True);
}
else if (result.Type == CompletionType.Return)
{
resultValue = new IteratorInstance.ValueIteratorPosition(_engine, result.Value, false);
if (_generatorBody.Completed)
if (_generatorState == GeneratorState.SuspendedYield)
{
resultValue = IteratorResult.CreateValueIteratorPosition(_engine, result.Value, done: JsBoolean.False);
}
else
{
_generatorState = GeneratorState.Completed;
resultValue = IteratorResult.CreateValueIteratorPosition(_engine, null!, done: JsBoolean.True);
}
}

Expand Down
12 changes: 6 additions & 6 deletions Jint/Native/Generator/GeneratorPrototype.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,14 @@ internal GeneratorPrototype(

protected override void Initialize()
{
const PropertyFlag propertyFlags = PropertyFlag.Configurable | PropertyFlag.Writable;
const PropertyFlag lengthFlags = PropertyFlag.Configurable;
const PropertyFlag PropertyFlags = PropertyFlag.Configurable | PropertyFlag.Writable;
const PropertyFlag LengthFlags = PropertyFlag.Configurable;
var properties = new PropertyDictionary(4, false)
{
["constructor"] = new(_constructor, PropertyFlag.Configurable),
["next"] = new(new ClrFunctionInstance(Engine, "next", Next, 1, lengthFlags), propertyFlags),
["return"] = new(new ClrFunctionInstance(Engine, "return", Return, 1, lengthFlags), propertyFlags),
["throw"] = new(new ClrFunctionInstance(Engine, "throw", Throw, 1, lengthFlags), propertyFlags)
["next"] = new(new ClrFunctionInstance(Engine, "next", Next, 1, LengthFlags), PropertyFlags),
["return"] = new(new ClrFunctionInstance(Engine, "return", Return, 1, LengthFlags), PropertyFlags),
["throw"] = new(new ClrFunctionInstance(Engine, "throw", Throw, 1, LengthFlags), PropertyFlags)
};
SetProperties(properties);

Expand All @@ -50,7 +50,7 @@ protected override void Initialize()
private JsValue Next(JsValue thisObject, JsValue[] arguments)
{
var g = AssertGeneratorInstance(thisObject);
var value = arguments.At(0);
var value = arguments.At(0, null!);
return g.GeneratorResume(value, null);
}

Expand Down
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
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
13 changes: 10 additions & 3 deletions Jint/Runtime/Interpreter/Expressions/JintYieldExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,20 @@ public JintYieldExpression(YieldExpression expression) : base(expression)
protected override object EvaluateInternal(EvaluationContext context)
{
var expression = (YieldExpression) _expression;
var engine = context.Engine;

var value = JsValue.Undefined;
if (expression.Argument is not null)
JsValue value;
if (context.Engine.ExecutionContext.Generator?._nextValue is not null)
{
value = context.Engine.ExecutionContext.Generator._nextValue;
}
else if (expression.Argument is not null)
{
value = Build(expression.Argument).GetValue(context);
}
else
{
value = JsValue.Undefined;
}

if (expression.Delegate)
{
Expand Down
11 changes: 7 additions & 4 deletions Jint/Runtime/Interpreter/JintStatementList.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ private sealed class Pair

private Pair[]? _jintStatements;
private bool _initialized;
private readonly uint _index;
private uint _index;
private readonly bool _generator;

public JintStatementList(IFunction function)
Expand Down Expand Up @@ -102,10 +102,13 @@ public Completion Execute(EvaluationContext context)
}
}

if (_generator && context.Engine.ExecutionContext.Generator?._generatorState == GeneratorState.SuspendedYield)
if (_generator)
{
_index = i + 1;
return new Completion(CompletionType.Return, c.Value, s._statement);
if (context.Engine.ExecutionContext.Generator?._generatorState == GeneratorState.SuspendedYield)
{
_index = i + 1;
return new Completion(CompletionType.Return, c.Value, s._statement);
}
}

if (c.Type != CompletionType.Normal)
Expand Down
2 changes: 1 addition & 1 deletion Jint/Runtime/Interpreter/Statements/JintBlockStatement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ protected override void Initialize(EvaluationContext context)
_lexicalDeclarations = HoistingScope.GetLexicalDeclarations(_statement);
}

internal override bool SupportsResume => true;
internal bool SupportsResume => true;

/// <summary>
/// Optimized for direct access without virtual dispatch.
Expand Down
Loading

0 comments on commit 8cc1487

Please sign in to comment.