Skip to content
This repository was archived by the owner on Sep 10, 2023. It is now read-only.

Commit c4229bf

Browse files
committed
feat: support for of loop label
1 parent 3bbe9e7 commit c4229bf

File tree

3 files changed

+104
-5
lines changed

3 files changed

+104
-5
lines changed

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,16 @@ try {
7171
* [ ] Try with optional catch
7272
* [ ] Decorator
7373

74+
## Test
75+
76+
I have write a lot of test case for this, look at [here](https://github.com/axetroy/vm.js/tree/master/test)
77+
78+
Now it still in development, got a lot of work to do and more detail to resolve.
79+
80+
I will release the first stable version after write 500 test case.
81+
82+
If you want to join it. welcome to PR.
83+
7484
## Contributors
7585

7686
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->

src/evaluate.ts

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -466,11 +466,19 @@ const visitors: EvaluateMap = {
466466
},
467467
// @es2015 for of
468468
ForOfStatement(path) {
469-
const { node, scope } = path;
469+
const { node, scope, ctx } = path;
470+
const labelName: string | void = ctx.labelName;
470471
const entity = evaluate(path.createChild(node.right));
472+
const SymbolConst: any =
473+
typeof Symbol !== "undefined"
474+
? Symbol
475+
: (() => {
476+
const $var = scope.hasBinding("Symbol");
477+
return $var ? $var.value : undefined;
478+
})();
471479
// not support for of, it mean not support native for of
472-
if (typeof Symbol !== "undefined") {
473-
if (!entity || !entity[Symbol.iterator]) {
480+
if (SymbolConst) {
481+
if (!entity || !entity[SymbolConst.iterator]) {
474482
// FIXME: how to get function name
475483
// for (let value of get()){}
476484
throw ErrInvalidIterable((node.right as types.Identifier).name);
@@ -490,7 +498,26 @@ const visitors: EvaluateMap = {
490498
forOfScope.invasive = true;
491499
forOfScope.isolated = false;
492500
forOfScope.declare(node.left.kind, varName, value); // define in current scope
493-
evaluate(path.createChild(node.body, forOfScope));
501+
const signal = evaluate(path.createChild(node.body, forOfScope));
502+
if (Signal.isBreak(signal)) {
503+
if (!signal.value) {
504+
break;
505+
}
506+
if (signal.value === labelName) {
507+
break;
508+
}
509+
return signal;
510+
} else if (Signal.isContinue(signal)) {
511+
if (!signal.value) {
512+
continue;
513+
}
514+
if (signal.value === labelName) {
515+
continue;
516+
}
517+
return signal;
518+
} else if (Signal.isReturn(signal)) {
519+
return signal;
520+
}
494521
}
495522
} else if (isIdentifier(node.left)) {
496523
/**
@@ -503,7 +530,26 @@ const visitors: EvaluateMap = {
503530
const forOfScope = scope.createChild("forOf");
504531
forOfScope.invasive = true;
505532
scope.var(varName, value); // define in parent scope
506-
evaluate(path.createChild(node.body, forOfScope));
533+
const signal = evaluate(path.createChild(node.body, forOfScope));
534+
if (Signal.isBreak(signal)) {
535+
if (!signal.value) {
536+
break;
537+
}
538+
if (signal.value === labelName) {
539+
break;
540+
}
541+
return signal;
542+
} else if (Signal.isContinue(signal)) {
543+
if (!signal.value) {
544+
continue;
545+
}
546+
if (signal.value === labelName) {
547+
continue;
548+
}
549+
return signal;
550+
} else if (Signal.isReturn(signal)) {
551+
return signal;
552+
}
507553
}
508554
}
509555
},

test/es2015/for-of/label.test.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import test from "ava";
2+
import { ErrDuplicateDeclard } from "../../../src/error";
3+
import vm from "../../../src/vm";
4+
5+
test("break with label", t => {
6+
const sandbox: any = vm.createContext({});
7+
8+
const index: any = vm.runInContext(
9+
`
10+
loop1:
11+
for (var index of [0, 1, 2, 3]){
12+
if (index===2){
13+
break loop1;
14+
}
15+
}
16+
17+
module.exports = index;
18+
`,
19+
sandbox
20+
);
21+
t.deepEqual(index, 2);
22+
});
23+
24+
test("continue with label", t => {
25+
const sandbox: any = vm.createContext({});
26+
27+
const list: any = vm.runInContext(
28+
`
29+
var list = [];
30+
loop1:
31+
for (var index of [0, 1, 2, 3]){
32+
if (index%2 === 0){
33+
continue;
34+
}
35+
list.push(index);
36+
}
37+
38+
module.exports = list;
39+
`,
40+
sandbox
41+
);
42+
t.deepEqual(list, [1, 3]);
43+
});

0 commit comments

Comments
 (0)