-
-
Notifications
You must be signed in to change notification settings - Fork 560
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add partial support for yield via experimental flag (#1815)
- Loading branch information
Showing
6 changed files
with
1,825 additions
and
390 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,251 @@ | ||
namespace Jint.Tests.Runtime; | ||
|
||
public class GeneratorTests | ||
{ | ||
private readonly Engine _engine; | ||
|
||
public GeneratorTests() | ||
{ | ||
_engine = new Engine(options => options.ExperimentalFeatures = ExperimentalFeature.Generators); | ||
} | ||
|
||
[Fact] | ||
public void LoopYield() | ||
{ | ||
const string Script = """ | ||
const foo = function*() { | ||
yield 'a'; | ||
yield 'b'; | ||
yield 'c'; | ||
}; | ||
|
||
let str = ''; | ||
for (const val of foo()) { | ||
str += val; | ||
} | ||
return str; | ||
"""; | ||
|
||
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; | ||
"""; | ||
|
||
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; | ||
"""; | ||
|
||
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; | ||
"""; | ||
|
||
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; | ||
"""; | ||
|
||
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; | ||
"""; | ||
|
||
Assert.Equal("", _engine.Evaluate(Script)); | ||
} | ||
|
||
[Fact] | ||
public void Basic() | ||
{ | ||
_engine.Execute("function * generator() { yield 5; yield 6; };"); | ||
_engine.Execute("var iterator = generator(); var item = iterator.next();"); | ||
Assert.Equal(5, _engine.Evaluate("item.value")); | ||
Assert.False(_engine.Evaluate("item.done").AsBoolean()); | ||
_engine.Execute("item = iterator.next();"); | ||
Assert.Equal(6, _engine.Evaluate("item.value")); | ||
Assert.False(_engine.Evaluate("item.done").AsBoolean()); | ||
_engine.Execute("item = iterator.next();"); | ||
Assert.True(_engine.Evaluate("item.value === void undefined").AsBoolean()); | ||
Assert.True(_engine.Evaluate("item.done").AsBoolean()); | ||
} | ||
|
||
[Fact] | ||
public void FunctionExpressions() | ||
{ | ||
_engine.Execute("var generator = function * () { yield 5; yield 6; };"); | ||
_engine.Execute("var iterator = generator(); var item = iterator.next();"); | ||
Assert.Equal(5, _engine.Evaluate("item.value")); | ||
Assert.False(_engine.Evaluate("item.done").AsBoolean()); | ||
_engine.Execute("item = iterator.next();"); | ||
Assert.Equal(6, _engine.Evaluate("item.value")); | ||
Assert.False(_engine.Evaluate("item.done").AsBoolean()); | ||
_engine.Execute("item = iterator.next();"); | ||
Assert.True(_engine.Evaluate("item.value === void undefined").AsBoolean()); | ||
Assert.True(_engine.Evaluate("item.done").AsBoolean()); | ||
} | ||
|
||
[Fact] | ||
public void CorrectThisBinding() | ||
{ | ||
_engine.Execute("var generator = function * () { yield 5; yield 6; };"); | ||
_engine.Execute("var iterator = { g: generator, x: 5, y: 6 }.g(); var item = iterator.next();"); | ||
Assert.Equal(5, _engine.Evaluate("item.value")); | ||
Assert.False(_engine.Evaluate("item.done").AsBoolean()); | ||
_engine.Execute("item = iterator.next();"); | ||
Assert.Equal(6, _engine.Evaluate("item.value")); | ||
Assert.False(_engine.Evaluate("item.done").AsBoolean()); | ||
_engine.Execute("item = iterator.next();"); | ||
Assert.True(_engine.Evaluate("item.value === void undefined").AsBoolean()); | ||
Assert.True(_engine.Evaluate("item.done").AsBoolean()); | ||
} | ||
|
||
[Fact(Skip = "TODO es6-generators")] | ||
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"); | ||
"""; | ||
|
||
_engine.Execute(Script); | ||
|
||
Assert.Equal("foo", _engine.Evaluate("sent[0]")); | ||
Assert.Equal("bar", _engine.Evaluate("sent[1]")); | ||
} | ||
|
||
[Fact(Skip = "TODO es6-generators")] | ||
public void Sending2() | ||
{ | ||
const string Script = """ | ||
function* counter(value) { | ||
while (true) { | ||
const step = yield value++; | ||
|
||
if (step) { | ||
value += step; | ||
} | ||
} | ||
} | ||
|
||
const generatorFunc = counter(0); | ||
"""; | ||
|
||
_engine.Execute(Script); | ||
|
||
Assert.Equal(0, _engine.Evaluate("generatorFunc.next().value")); // 0 | ||
Assert.Equal(1, _engine.Evaluate("generatorFunc.next().value")); // 1 | ||
Assert.Equal(2, _engine.Evaluate("generatorFunc.next().value")); // 2 | ||
Assert.Equal(3, _engine.Evaluate("generatorFunc.next().value")); // 3 | ||
Assert.Equal(14, _engine.Evaluate("generatorFunc.next(10).value")); // 14 | ||
Assert.Equal(15, _engine.Evaluate("generatorFunc.next().value")); // 15 | ||
Assert.Equal(26, _engine.Evaluate("generatorFunc.next(10).value")); // 26 | ||
} | ||
|
||
[Fact(Skip = "TODO es6-generators")] | ||
public void Fibonacci() | ||
{ | ||
const string Script = """ | ||
function* fibonacci() { | ||
let current = 0; | ||
let next = 1; | ||
while (true) { | ||
const reset = yield current; | ||
[current, next] = [next, next + current]; | ||
if (reset) { | ||
current = 0; | ||
next = 1; | ||
} | ||
} | ||
} | ||
|
||
const sequence = fibonacci(); | ||
"""; | ||
|
||
_engine.Execute(Script); | ||
|
||
Assert.Equal(0, _engine.Evaluate("sequence.next().value")); | ||
Assert.Equal(1, _engine.Evaluate("sequence.next().value")); | ||
Assert.Equal(1, _engine.Evaluate("sequence.next().value")); | ||
Assert.Equal(2, _engine.Evaluate("sequence.next().value")); | ||
Assert.Equal(3, _engine.Evaluate("sequence.next().value")); | ||
Assert.Equal(5, _engine.Evaluate("sequence.next().value")); | ||
Assert.Equal(9, _engine.Evaluate("sequence.next().value")); | ||
Assert.Equal(0, _engine.Evaluate("sequence.next(true).value")); | ||
Assert.Equal(1, _engine.Evaluate("sequence.next().value)")); | ||
Assert.Equal(1, _engine.Evaluate("sequence.next().value)")); | ||
Assert.Equal(2, _engine.Evaluate("sequence.next().value)")); | ||
} | ||
} |
Oops, something went wrong.