swc/ecmascript/transforms/compat/tests/es2015_regenerator.rs

1292 lines
24 KiB
Rust

use swc_common::{chain, Mark};
use swc_ecma_parser::Syntax;
use swc_ecma_transforms_base::resolver::resolver;
use swc_ecma_transforms_compat::{
es2015, es2015::regenerator, es2016, es2017, es2017::async_to_generator,
};
use swc_ecma_transforms_testing::test;
use swc_ecma_transforms_testing::test_exec;
use swc_ecma_visit::Fold;
fn syntax() -> Syntax {
Syntax::default()
}
fn tr(_: ()) -> impl Fold {
chain!(resolver(), regenerator(Mark::fresh(Mark::root())))
}
// computed_properties_example
test!(
syntax(),
|_| tr(Default::default()),
computed_properties_example,
r#"
var o = {
*foo() {
return "foo";
}
};
"#,
r#"
var regeneratorRuntime = require('regenerator-runtime');
var o = {
foo() {
return regeneratorRuntime.mark(function _callee() {
return regeneratorRuntime.wrap(function _callee$(_ctx) {
while (1) switch (_ctx.prev = _ctx.next) {
case 0:
return _ctx.abrupt("return", "foo");
case 1:
case "end":
return _ctx.stop();
}
}, _callee);
})()
;
}
};
"#
);
// class_argument_scope_example
test_exec!(
syntax(),
|_| tr(Default::default()),
class_argument_scope_example_exec,
r#"
class Test {
*iter(arg = this) {
yield arg;
}
}
let test = new Test;
expect(test.iter().next().value).toBe(test);
"#
);
//// regression_T7041
//test!(
// syntax(),
// |_| tr(Default::default()),
// regression_t7041,
// r#"
//var _regeneratorRuntime = require("regenerator-runtime");
//
//Object.keys({});
//
//function * fn(){}
//
//"#,
// r#"
//var _regeneratorRuntime = require("regenerator-runtime");
//
//var _marked = _regeneratorRuntime.mark(fn);
//
//Object.keys({});
//
//function fn() {
// return _regeneratorRuntime.wrap(function fn$(_ctx) {
// while (1) {
// switch (_ctx.prev = _ctx.next) {
// case 0:
// case "end":
// return _ctx.stop();
// }
// }
// }, _marked);
//}
//
//"#
//);
test!(
syntax(),
|_| tr(Default::default()),
empty_fn_decl_1,
"function* foo(a,b,c){}
",
r#"
var regeneratorRuntime = require('regenerator-runtime');
var _marked = regeneratorRuntime.mark(foo);
function foo(a, b, c) {
return regeneratorRuntime.wrap(function foo$(_ctx) {
while (1)
switch (_ctx.prev = _ctx.next) {
case 0:
case "end":
return _ctx.stop();
}
}, _marked);
}
"#
);
test_exec!(
syntax(),
|_| tr(Default::default()),
conditional_return_1,
"
let v = (function* (){
yield 3;
if (true)
return 1
})();
expect(v.next()).toEqual({ value: 3, done: false });
expect(v.next()).toEqual({ value: 1, done: true });
"
);
test_exec!(
syntax(),
|_| tr(Default::default()),
conditional_return_2,
"
let v = (function* (){
if (false)
return a
yield 1
})();
expect(v.next()).toEqual({ value: 1, done: false });
expect(v.next()).toEqual({ done: true });
"
);
test_exec!(
syntax(),
|_| tr(Default::default()),
conditional_return_exec_1,
"
let v = (function* (){
yield 3;
if (true)
return 2;
yield 1
})();
expect(v.next()).toEqual({ done: false, value: 3 });
expect(v.next()).toEqual({ done: true, value: 2 });
"
);
test_exec!(
syntax(),
|_| tr(Default::default()),
conditional_return_exec_2,
"
let v = (function* (){
yield 3;
if (false)
return 2;
yield 1
})();
expect(v.next()).toEqual({ done: false, value: 3 });
expect(v.next()).toEqual({ done: false, value: 1 });
expect(v.next()).toEqual({ done: true, value: undefined });
"
);
test_exec!(
syntax(),
|_| tr(Default::default()),
conditional_yield_1,
"
let v = (function* () {
if (true)
yield 1
})();
expect(v.next()).toEqual({ done: false, value: 1 });
expect(v.next()).toEqual({ done: true });
"
);
test_exec!(
syntax(),
|_| tr(Default::default()),
conditional_yield_2,
"
let v = (function* () {
if (true)
yield 1
if (false)
yield 2
yield 3
})();
expect(v.next()).toEqual({ done: false, value: 1 });
expect(v.next()).toEqual({ done: false, value: 3 });
expect(v.next()).toEqual({ done: true, value: undefined });
"
);
test_exec!(
syntax(),
|_| tr(Default::default()),
yield_in_seq,
"
let v = (function* () {
return (1, yield 2, yield 3, 4, yield 5);
})();
expect(v.next()).toEqual({ done: false, value: 2 });
expect(v.next()).toEqual({ done: false, value: 3 });
expect(v.next()).toEqual({ done: false, value: 5 });
expect(v.next()).toEqual({ done: true });
"
);
test_exec!(
syntax(),
|_| tr(Default::default()),
yield_in_cond_seq,
"
let v = (function* () {
if (true)
return (1, yield 2, yield 3, 4, yield 5);
})();
expect(v.next()).toEqual({ done: false, value: 2 });
expect(v.next()).toEqual({ done: false, value: 3 });
expect(v.next()).toEqual({ done: false, value: 5 });
expect(v.next()).toEqual({ done: true });
"
);
test_exec!(
syntax(),
|_| tr(Default::default()),
yield_in_return_and_call,
"
function id(v) { return v; }
let v = (function* () {
if (true)
return (1, id(yield id(2)));
})();
expect(v.next()).toEqual({ done: false, value: 2 });
expect(v.next()).toEqual({ done: true });
"
);
test_exec!(
syntax(),
|_| tr(Default::default()),
yield_in_call,
"
function id(v) { return v; }
let v = (function* () {
return (1, id(yield id(2)));
return (3, id(yield id(4)));
})();
expect(v.next()).toEqual({ done: false, value: 2 });
expect(v.next()).toEqual({ done: true });
"
);
test_exec!(
ignore,
syntax(),
|_| tr(Default::default()),
yield_temp,
"
function id(v) { return v; }
let v = (function* () {
yield (1, id(yield id(2), 2));
return (3, id(yield id(4)));
})();
expect(v.next()).toEqual({ done: false, value: 2 });
expect(v.next()).toEqual({ done: false, value: 2 });
expect(v.next()).toEqual({ done: true });
"
);
test_exec!(
ignore,
syntax(),
|_| tr(Default::default()),
yield_next_value,
"
let v = (function* () {
let bar = yield 'foo';
yield bar
})();
expect(v.next('bar')).toEqual({value: 'foo', done: false})
expect(v.next()).toEqual({value: 'bar', done: false})
expect(v.next()).toEqual({done: true})
"
);
test_exec!(
syntax(),
|_| tr(Default::default()),
only_yield,
"
let v = (function* () {
yield 1
})();
expect(v.next()).toEqual({ done: false, value: 1 });
expect(v.next()).toEqual({ done: true });
"
);
test_exec!(
syntax(),
|_| tr(Default::default()),
expr_cond,
"
let v = (function* (){
true ? yield 1 : yield 2;
})();
expect(v.next()).toEqual({ value: 1, done: false });
expect(v.next()).toEqual({ done: true });
"
);
test_exec!(
syntax(),
|_| tr(Default::default()),
expr_array,
"
let v = (function* (){
yield [yield 1, 2];
})();
expect(v.next()).toEqual({ value: 1, done: false });
expect(v.next()).toEqual({ value: [undefined, 2], done: false });
expect(v.next()).toEqual({ done: true });
"
);
test_exec!(
syntax(),
|_| tr(Default::default()),
expr_object,
"
let v = (function* (){
yield { a: 1 };
})();
expect(v.next()).toEqual({ value: { a: 1 }, done: false });
expect(v.next()).toEqual({ done: true });
"
);
test_exec!(
syntax(),
|_| tr(Default::default()),
expr_logical_and,
"
let v = (function* (){
(yield 1) && (yield 2);
})();
expect(v.next()).toEqual({ value: 1, done: false });
expect(v.next()).toEqual({ done: true });
"
);
test_exec!(
syntax(),
|_| tr(Default::default()),
expr_logical_or,
"
let v = (function* (){
(yield 1) || (yield 2);
})();
expect(v.next()).toEqual({ value: 1, done: false });
expect(v.next()).toEqual({ value: 2, done: false });
expect(v.next()).toEqual({ done: true });
"
);
test_exec!(
syntax(),
|_| tr(Default::default()),
expr_update_prefix,
"
let v = (function* (){
let i = 0;
yield ++i;
yield i;
})();
expect(v.next()).toEqual({ value: 1, done: false });
expect(v.next()).toEqual({ value: 1, done: false });
expect(v.next()).toEqual({ done: true });
"
);
test_exec!(
syntax(),
|_| tr(Default::default()),
expr_update_postfix,
"
let v = (function* (){
let i = 0;
yield i++;
yield i;
})();
expect(v.next()).toEqual({ value: 0, done: false });
expect(v.next()).toEqual({ value: 1, done: false });
expect(v.next()).toEqual({ done: true });
"
);
test_exec!(
syntax(),
|_| tr(Default::default()),
bin_expr_1,
"
let v = (function* (){
yield ((yield 1) + (yield 2));
})();
expect(v.next()).toEqual({ value: 1, done: false });
expect(v.next()).toEqual({ value: 2, done: false });
expect(v.next()).toEqual({ value: NaN, done: false });
expect(v.next()).toEqual({ done: true });
"
);
test_exec!(
syntax(),
|_| tr(Default::default()),
try_stmt_1,
"
let v = (function* (){
try {
yield 1;
} catch(e){
}
})();
expect(v.next()).toEqual({ value: 1, done: false });
expect(v.next()).toEqual({ done: true });
"
);
test_exec!(
syntax(),
|_| tr(Default::default()),
try_stmt_2,
"
let v = (function* (){
try {
yield 1;
throw new Error('');
} catch(e){
yield 2;
}
})();
expect(v.next()).toEqual({ value: 1, done: false });
expect(v.next()).toEqual({ value: 2, done: false });
"
);
test_exec!(
syntax(),
|_| tr(Default::default()),
try_stmt_3,
"
let v = (function* (){
try {
yield 1;
throw new Error('');
} finally {
yield 2;
}
})();
expect(v.next()).toEqual({ value: 1, done: false });
expect(v.next()).toEqual({ value: 2, done: false });
expect(() => v.next()).toThrow();
"
);
test_exec!(
syntax(),
|_| tr(Default::default()),
try_stmt_4,
"
let v = (function* (){
try {
yield 1;
throw new Error('');
} catch (e) {
yield 2;
} finally {
yield 3;
}
})();
expect(v.next()).toEqual({ value: 1, done: false });
expect(v.next()).toEqual({ value: 2, done: false });
expect(v.next()).toEqual({ value: 3, done: false });
"
);
test_exec!(
syntax(),
|_| tr(Default::default()),
try_stmt_5,
"
let v = (function* (){
try {
yield 1;
} catch (e) {
}
try {
yield 2;
} catch (e) {
}
})();
expect(v.next()).toEqual({ value: 1, done: false });
expect(v.next()).toEqual({ value: 2, done: false });
"
);
// TODO
test_exec!(
syntax(),
|_| tr(Default::default()),
labeled_stmt_1,
"
let v = (function* (){
})();
expect(v.next()).toEqual({ done: true });
"
);
// TODO
test_exec!(
syntax(),
|_| tr(Default::default()),
break_stmt_1,
"
let v = (function* (){
})();
expect(v.next()).toEqual({ done: true });
"
);
// TODO
test_exec!(
syntax(),
|_| tr(Default::default()),
continue_stmt_1,
"
let v = (function* (){
})();
expect(v.next()).toEqual({ done: true });
"
);
test_exec!(
syntax(),
|_| tr(Default::default()),
switch_stmt_1,
"
let v = (function* (){
switch(1) {
case 1:
yield 1
yield 2
}
})();
expect(v.next()).toEqual({ value: 1, done: false });
expect(v.next()).toEqual({ value: 2, done: false });
expect(v.next()).toEqual({ done: true });
"
);
test_exec!(
syntax(),
|_| tr(Default::default()),
switch_stmt_2,
"
let v = (function* (){
switch(2) {
case 1:
yield 1
yield 2
}
})();
expect(v.next()).toEqual({ done: true });
"
);
test_exec!(
syntax(),
|_| tr(Default::default()),
switch_stmt_3,
"
let v = (function* (){
switch(2) {
default:
yield 1
yield 2
}
})();
expect(v.next()).toEqual({ value: 1, done: false });
expect(v.next()).toEqual({ value: 2, done: false });
expect(v.next()).toEqual({ done: true });
"
);
test_exec!(
syntax(),
|_| tr(Default::default()),
switch_stmt_4,
"
let v = (function* (){
switch(1) {
case 1:
yield 1
case 2:
yield 2
}
})();
expect(v.next()).toEqual({ value: 1, done: false });
expect(v.next()).toEqual({ value: 2, done: false });
expect(v.next()).toEqual({ done: true });
"
);
test_exec!(
syntax(),
|_| tr(Default::default()),
switch_stmt_5,
"
let v = (function* (){
switch(1) {
case 1:
yield 1;
break;
case 2:
yield 2;
break;
case 3:
yield 3;
break;
case 4:
yield 4;
break;
}
})();
expect(v.next()).toEqual({ value: 1, done: false });
expect(v.next()).toEqual({ done: true });
"
);
// TODO
test_exec!(
syntax(),
|_| tr(Default::default()),
throw_stmt_1,
"
let v = (function* (){
})();
expect(v.next()).toEqual({ done: true });
"
);
test_exec!(
syntax(),
|_| tr(Default::default()),
while_stmt_1,
"
let v = (function* (){
let i = 0;
while (true) {
yield i++;
}
})();
expect(v.next()).toEqual({ value: 0, done: false });
expect(v.next()).toEqual({ value: 1, done: false });
expect(v.next()).toEqual({ value: 2, done: false });
expect(v.next()).toEqual({ value: 3, done: false });
expect(v.next()).toEqual({ value: 4, done: false });
"
);
test_exec!(
syntax(),
|_| tr(Default::default()),
do_while_stmt_1,
"
let v = (function* (){
let i = 0;
do {
yield i++;
} while(true);
})();
expect(v.next()).toEqual({ value: 0, done: false });
expect(v.next()).toEqual({ value: 1, done: false });
expect(v.next()).toEqual({ value: 2, done: false });
expect(v.next()).toEqual({ value: 3, done: false });
expect(v.next()).toEqual({ value: 4, done: false });
"
);
test_exec!(
syntax(),
|_| tr(Default::default()),
do_while_stmt_2,
"
let v = (function* (){
do {
yield 1;
} while(false);
})();
expect(v.next()).toEqual({ value: 1, done: false });
expect(v.next()).toEqual({ done: true });
"
);
// TODO
test_exec!(
syntax(),
|_| tr(Default::default()),
for_stmt_1,
"
let v = (function* (){
})();
expect(v.next()).toEqual({ done: true });
"
);
// TODO
test_exec!(
syntax(),
|_| tr(Default::default()),
for_of_stmt_1,
"
let v = (function* (){
})();
expect(v.next()).toEqual({ done: true });
"
);
// TODO
test_exec!(
syntax(),
|_| tr(Default::default()),
for_in_stmt_1,
"
let v = (function* (){
})();
expect(v.next()).toEqual({ done: true });
"
);
test_exec!(
syntax(),
|_| tr(Default::default()),
bin_expr_2,
"
let v = (function* (){
let a = 1;
let b = 2;
yield a + b;
yield (yield a) + (yield b)
})();
expect(v.next()).toEqual({ value: 3, done: false });
expect(v.next()).toEqual({ value: 1, done: false });
expect(v.next()).toEqual({ value: 2, done: false });
expect(v.next()).toEqual({ value: NaN, done: false });
expect(v.next()).toEqual({ done: true });
"
);
test_exec!(
syntax(),
|_| tr(Default::default()),
arguments_1,
"
function* gen(){
yield Array.prototype.slice.call(arguments);
}
var v = gen(1, 2);
expect(v.next()).toEqual({ value: [1, 2], done: false });
expect(v.next()).toEqual({ done: true });
"
);
test_exec!(
syntax(),
|_| tr(Default::default()),
arguments_2,
"
function* gen(){
yield arguments[0];
yield arguments[1];
}
var v = gen(1, 2);
expect(v.next()).toEqual({ value: 1, done: false });
expect(v.next()).toEqual({ value: 2, done: false });
expect(v.next()).toEqual({ done: true });
var v = gen(3, 4);
expect(v.next()).toEqual({ value: 3, done: false });
expect(v.next()).toEqual({ value: 4, done: false });
expect(v.next()).toEqual({ done: true });
"
);
test_exec!(
syntax(),
|_| chain!(
es2017(),
es2016(),
es2015(Mark::fresh(Mark::root()), Default::default()),
),
issue_600_full,
"async function foo(b) {
for (let a of b) {
await a
}
}"
);
test_exec!(
syntax(),
|_| chain!(
async_to_generator(),
es2015::for_of(Default::default()),
es2015::regenerator(Mark::fresh(Mark::root())),
),
issue_600_exact_passes,
"async function foo(b) {
for (let a of b) {
await a
}
}"
);
test_exec!(
syntax(),
|_| es2015::regenerator(Mark::fresh(Mark::root())),
issue_600_min,
"function* foo() {
try {
yield 1;
throw new Error('1')
} finally{
try {
yield 2;
} finally{
throw new Error('2');
}
}
}
var v = foo();
expect(v.next()).toEqual({ value: 1, done: false });
expect(v.next()).toEqual({ value: 2, done: false });
expect(() => v.next()).toThrow('2')
"
);
test_exec!(
syntax(),
|_| es2015::regenerator(Mark::fresh(Mark::root())),
issue_831_1,
"function* myGenerator() {
yield* [1,2,3];
}
const v = myGenerator();
expect(v.next()).toEqual({ value: 1, done: false });
expect(v.next()).toEqual({ value: 2, done: false });
expect(v.next()).toEqual({ value: 3, done: false });
expect(v.next()).toEqual({ done: true });
"
);
// test interop between export and regenerator
test!(
syntax(),
|_| {
let mark = Mark::fresh(Mark::root());
es2015::regenerator(mark)
},
issue_831_3,
"export function* myGenerator() {
yield* [1,2,3];
}",
"var regeneratorRuntime = require('regenerator-runtime');
var _marked = regeneratorRuntime.mark(myGenerator);
export function myGenerator() {
return regeneratorRuntime.wrap(function myGenerator$(_ctx) {
while(1)switch(_ctx.prev = _ctx.next){
case 0:
return _ctx.delegateYield([
1,
2,
3
], _ctx.t0, 1);
case 1:
case 'end':
return _ctx.stop();
}
}, _marked);
}
"
);
test_exec!(
syntax(),
|_| es2015::regenerator(Mark::fresh(Mark::root())),
issue_849_1,
"function* gen() { yield 1 };
function genFactory() { return function*() { yield 1 }; }
const v = genFactory()();
expect(v.next()).toEqual({ value: 1, done: false })
expect(v.next()).toEqual({ done: true })"
);
test_exec!(
syntax(),
|_| es2015::regenerator(Mark::fresh(Mark::root())),
issue_853_1,
"function throwingFn() { throw 'Error' }
function* gen() {
try { yield throwingFn() } catch (e) { yield e }
};
const v = gen();
expect(v.next()).toEqual({ done: false, value: 'Error'});
"
);
test_exec!(
Syntax::default(),
|_| chain!(async_to_generator(), tr(())),
issue_1036_1,
"
const x = async function() {
return await Promise.all([[1], [2], [3]].map(
async ([a]) => Promise.resolve().then(() => a * 2))
)
};
return x().then(x => {
expect(x).toEqual([2, 4, 6])
})
"
);
test!(
Syntax::default(),
|_| tr(()),
issue_1036_2,
"
const x = function*() {
return Promise.all([[1], [2], [3]].map(
function*([a]) {
Promise.resolve().then(() => a * 2)
})
)
}
",
r#"
var regeneratorRuntime = require("regenerator-runtime");
const x = regeneratorRuntime.mark(function _callee() {
return regeneratorRuntime.wrap(function _callee$(_ctx) {
while(1)switch(_ctx.prev = _ctx.next){
case 0:
return _ctx.abrupt("return", Promise.all([
[
1
],
[
2
],
[
3
]
].map(regeneratorRuntime.mark(function _callee1([a]) {
return regeneratorRuntime.wrap(function _callee$1(_ctx1) {
while(1)switch(_ctx1.prev = _ctx1.next){
case 0:
Promise.resolve().then(()=>a * 2);
case 1:
case "end":
return _ctx1.stop();
}
}, _callee1);
}))));
case 1:
case "end":
return _ctx.stop();
}
}, _callee);
});
"#
);
test_exec!(
Syntax::default(),
|_| tr(()),
issue_1036_3,
"
const x = function*() {
yield* [[1], [2], [3]].map(function([a]) {
return a * 2
})
}
const v = x();
expect(v.next()).toEqual({ value: 2, done: false})
expect(v.next()).toEqual({ value: 4, done: false})
expect(v.next()).toEqual({ value: 6, done: false})
expect(v.next()).toEqual({ done: true})
"
);
test_exec!(
Syntax::default(),
|_| chain!(async_to_generator(), tr(())),
issue_1125_1,
"
async function test() {
try {
await 1
} finally {
console.log(2)
}
}
test()
"
);
test!(
Syntax::default(),
|_| tr(()),
issue_1125_2,
"
function _test() {
_test = _asyncToGenerator(function* () {
try {
yield 1;
} finally {
console.log(2);
}
});
return _test.apply(this, arguments);
}
function test() {
return _test.apply(this, arguments);
}
test();
",
"
var regeneratorRuntime = require('regenerator-runtime');
var _marked = regeneratorRuntime.mark(_test);
function _test() {
_test = _asyncToGenerator(regeneratorRuntime.mark(function _callee() {
return regeneratorRuntime.wrap(function _callee$(_ctx) {
while (1)
switch (_ctx.prev = _ctx.next) {
case 0:
_ctx.prev = 0;
_ctx.next = 3;
return 1;
case 3:
_ctx.prev = 3;
console.log(2);
return _ctx.finish(3);
case 6:
case 'end':
return _ctx.stop();
}
}, _callee, null, [[0,, 3, 6]]);
}));
return _test.apply(this, arguments);
}
function test() {
return _test.apply(this, arguments);
}
test();
"
);
test!(
Syntax::default(),
|_| tr(()),
issue_1125_3,
"
function* foo() {
try {
yield 1;
} finally {
console.log(2);
}
}
",
"
var regeneratorRuntime = require('regenerator-runtime');
var _marked = regeneratorRuntime.mark(foo);
function foo() {
return regeneratorRuntime.wrap(function foo$(_ctx) {
while (1)
switch (_ctx.prev = _ctx.next) {
case 0:
_ctx.prev = 0;
_ctx.next = 3;
return 1;
case 3:
_ctx.prev = 3;
console.log(2);
return _ctx.finish(3);
case 6:
case 'end':
return _ctx.stop();
}
}, _marked, null, [[0,, 3, 6]]);
}
"
);
test!(
Syntax::default(),
|_| tr(()),
issue_1125_4,
"
function* foo() {
try {
yield 1;
} catch(e) {
console.log(2);
}
}
",
"
var regeneratorRuntime = require('regenerator-runtime');
var _marked = regeneratorRuntime.mark(foo);
function foo() {
return regeneratorRuntime.wrap(function foo$(_ctx) {
while (1)
switch (_ctx.prev = _ctx.next) {
case 0:
_ctx.prev = 0;
_ctx.next = 3;
return 1;
case 3:
_ctx.next = 8;
break;
case 5:
_ctx.prev = 5;
_ctx.t0 = _ctx['catch'](0);
console.log(2);
case 8:
case 'end':
return _ctx.stop();
}
}, _marked, null, [[0, 5]]);
}
"
);