Skip to content

Commit 23a2a25

Browse files
authored
Add partial support for yield via experimental flag (#1815)
1 parent 8078b4a commit 23a2a25

File tree

6 files changed

+1825
-390
lines changed

6 files changed

+1825
-390
lines changed

Jint.Tests.Test262/Test262Harness.settings.json

Lines changed: 944 additions & 29 deletions
Large diffs are not rendered by default.

Jint.Tests.Test262/Test262Test.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ private Engine BuildTestExecutor(Test262File file)
1515
{
1616
var relativePath = Path.GetDirectoryName(file.FileName);
1717
cfg.EnableModules(new Test262ModuleLoader(State.Test262Stream.Options.FileSystem, relativePath));
18+
cfg.ExperimentalFeatures = ExperimentalFeature.All;
1819
});
1920

2021
if (file.Flags.Contains("raw"))

Jint.Tests/Runtime/GeneratorTests.cs

Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
1+
namespace Jint.Tests.Runtime;
2+
3+
public class GeneratorTests
4+
{
5+
private readonly Engine _engine;
6+
7+
public GeneratorTests()
8+
{
9+
_engine = new Engine(options => options.ExperimentalFeatures = ExperimentalFeature.Generators);
10+
}
11+
12+
[Fact]
13+
public void LoopYield()
14+
{
15+
const string Script = """
16+
const foo = function*() {
17+
yield 'a';
18+
yield 'b';
19+
yield 'c';
20+
};
21+
22+
let str = '';
23+
for (const val of foo()) {
24+
str += val;
25+
}
26+
return str;
27+
""";
28+
29+
Assert.Equal("abc", _engine.Evaluate(Script));
30+
}
31+
32+
[Fact]
33+
public void ReturnDuringYield()
34+
{
35+
const string Script = """
36+
const foo = function*() {
37+
yield 'a';
38+
return;
39+
yield 'c';
40+
};
41+
42+
let str = '';
43+
for (const val of foo()) {
44+
str += val;
45+
}
46+
return str;
47+
""";
48+
49+
Assert.Equal("a", _engine.Evaluate(Script));
50+
}
51+
52+
[Fact]
53+
public void LoneReturnInYield()
54+
{
55+
const string Script = """
56+
const foo = function*() {
57+
return;
58+
};
59+
60+
let str = '';
61+
for (const val of foo()) {
62+
str += val;
63+
}
64+
return str;
65+
""";
66+
67+
Assert.Equal("", _engine.Evaluate(Script));
68+
}
69+
70+
[Fact]
71+
public void LoneReturnValueInYield()
72+
{
73+
const string Script = """
74+
const foo = function*() {
75+
return 'a';
76+
};
77+
78+
let str = '';
79+
for (const val of foo()) {
80+
str += val;
81+
}
82+
return str;
83+
""";
84+
85+
Assert.Equal("", _engine.Evaluate(Script));
86+
}
87+
88+
[Fact]
89+
public void YieldUndefined()
90+
{
91+
const string Script = """
92+
const foo = function*() {
93+
yield undefined;
94+
};
95+
96+
let str = '';
97+
for (const val of foo()) {
98+
str += val;
99+
}
100+
return str;
101+
""";
102+
103+
Assert.Equal("undefined", _engine.Evaluate(Script));
104+
}
105+
106+
[Fact]
107+
public void ReturnUndefined()
108+
{
109+
const string Script = """
110+
const foo = function*() {
111+
return undefined;
112+
};
113+
114+
let str = '';
115+
for (const val of foo()) {
116+
str += val;
117+
}
118+
return str;
119+
""";
120+
121+
Assert.Equal("", _engine.Evaluate(Script));
122+
}
123+
124+
[Fact]
125+
public void Basic()
126+
{
127+
_engine.Execute("function * generator() { yield 5; yield 6; };");
128+
_engine.Execute("var iterator = generator(); var item = iterator.next();");
129+
Assert.Equal(5, _engine.Evaluate("item.value"));
130+
Assert.False(_engine.Evaluate("item.done").AsBoolean());
131+
_engine.Execute("item = iterator.next();");
132+
Assert.Equal(6, _engine.Evaluate("item.value"));
133+
Assert.False(_engine.Evaluate("item.done").AsBoolean());
134+
_engine.Execute("item = iterator.next();");
135+
Assert.True(_engine.Evaluate("item.value === void undefined").AsBoolean());
136+
Assert.True(_engine.Evaluate("item.done").AsBoolean());
137+
}
138+
139+
[Fact]
140+
public void FunctionExpressions()
141+
{
142+
_engine.Execute("var generator = function * () { yield 5; yield 6; };");
143+
_engine.Execute("var iterator = generator(); var item = iterator.next();");
144+
Assert.Equal(5, _engine.Evaluate("item.value"));
145+
Assert.False(_engine.Evaluate("item.done").AsBoolean());
146+
_engine.Execute("item = iterator.next();");
147+
Assert.Equal(6, _engine.Evaluate("item.value"));
148+
Assert.False(_engine.Evaluate("item.done").AsBoolean());
149+
_engine.Execute("item = iterator.next();");
150+
Assert.True(_engine.Evaluate("item.value === void undefined").AsBoolean());
151+
Assert.True(_engine.Evaluate("item.done").AsBoolean());
152+
}
153+
154+
[Fact]
155+
public void CorrectThisBinding()
156+
{
157+
_engine.Execute("var generator = function * () { yield 5; yield 6; };");
158+
_engine.Execute("var iterator = { g: generator, x: 5, y: 6 }.g(); var item = iterator.next();");
159+
Assert.Equal(5, _engine.Evaluate("item.value"));
160+
Assert.False(_engine.Evaluate("item.done").AsBoolean());
161+
_engine.Execute("item = iterator.next();");
162+
Assert.Equal(6, _engine.Evaluate("item.value"));
163+
Assert.False(_engine.Evaluate("item.done").AsBoolean());
164+
_engine.Execute("item = iterator.next();");
165+
Assert.True(_engine.Evaluate("item.value === void undefined").AsBoolean());
166+
Assert.True(_engine.Evaluate("item.done").AsBoolean());
167+
}
168+
169+
[Fact(Skip = "TODO es6-generators")]
170+
public void Sending()
171+
{
172+
const string Script = """
173+
var sent;
174+
function * generator() {
175+
sent = [yield 5, yield 6];
176+
};
177+
var iterator = generator();
178+
iterator.next();
179+
iterator.next("foo");
180+
iterator.next("bar");
181+
""";
182+
183+
_engine.Execute(Script);
184+
185+
Assert.Equal("foo", _engine.Evaluate("sent[0]"));
186+
Assert.Equal("bar", _engine.Evaluate("sent[1]"));
187+
}
188+
189+
[Fact(Skip = "TODO es6-generators")]
190+
public void Sending2()
191+
{
192+
const string Script = """
193+
function* counter(value) {
194+
while (true) {
195+
const step = yield value++;
196+
197+
if (step) {
198+
value += step;
199+
}
200+
}
201+
}
202+
203+
const generatorFunc = counter(0);
204+
""";
205+
206+
_engine.Execute(Script);
207+
208+
Assert.Equal(0, _engine.Evaluate("generatorFunc.next().value")); // 0
209+
Assert.Equal(1, _engine.Evaluate("generatorFunc.next().value")); // 1
210+
Assert.Equal(2, _engine.Evaluate("generatorFunc.next().value")); // 2
211+
Assert.Equal(3, _engine.Evaluate("generatorFunc.next().value")); // 3
212+
Assert.Equal(14, _engine.Evaluate("generatorFunc.next(10).value")); // 14
213+
Assert.Equal(15, _engine.Evaluate("generatorFunc.next().value")); // 15
214+
Assert.Equal(26, _engine.Evaluate("generatorFunc.next(10).value")); // 26
215+
}
216+
217+
[Fact(Skip = "TODO es6-generators")]
218+
public void Fibonacci()
219+
{
220+
const string Script = """
221+
function* fibonacci() {
222+
let current = 0;
223+
let next = 1;
224+
while (true) {
225+
const reset = yield current;
226+
[current, next] = [next, next + current];
227+
if (reset) {
228+
current = 0;
229+
next = 1;
230+
}
231+
}
232+
}
233+
234+
const sequence = fibonacci();
235+
""";
236+
237+
_engine.Execute(Script);
238+
239+
Assert.Equal(0, _engine.Evaluate("sequence.next().value"));
240+
Assert.Equal(1, _engine.Evaluate("sequence.next().value"));
241+
Assert.Equal(1, _engine.Evaluate("sequence.next().value"));
242+
Assert.Equal(2, _engine.Evaluate("sequence.next().value"));
243+
Assert.Equal(3, _engine.Evaluate("sequence.next().value"));
244+
Assert.Equal(5, _engine.Evaluate("sequence.next().value"));
245+
Assert.Equal(9, _engine.Evaluate("sequence.next().value"));
246+
Assert.Equal(0, _engine.Evaluate("sequence.next(true).value"));
247+
Assert.Equal(1, _engine.Evaluate("sequence.next().value)"));
248+
Assert.Equal(1, _engine.Evaluate("sequence.next().value)"));
249+
Assert.Equal(2, _engine.Evaluate("sequence.next().value)"));
250+
}
251+
}

0 commit comments

Comments
 (0)