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

Commit

Permalink
feat: support for of loop label
Browse files Browse the repository at this point in the history
  • Loading branch information
axetroy committed Mar 28, 2018
1 parent 3bbe9e7 commit c4229bf
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 5 deletions.
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,16 @@ try {
* [ ] Try with optional catch
* [ ] Decorator

## Test

I have write a lot of test case for this, look at [here](https://github.com/axetroy/vm.js/tree/master/test)

Now it still in development, got a lot of work to do and more detail to resolve.

I will release the first stable version after write 500 test case.

If you want to join it. welcome to PR.

## Contributors

<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
Expand Down
56 changes: 51 additions & 5 deletions src/evaluate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -466,11 +466,19 @@ const visitors: EvaluateMap = {
},
// @es2015 for of
ForOfStatement(path) {
const { node, scope } = path;
const { node, scope, ctx } = path;
const labelName: string | void = ctx.labelName;
const entity = evaluate(path.createChild(node.right));
const SymbolConst: any =
typeof Symbol !== "undefined"
? Symbol
: (() => {
const $var = scope.hasBinding("Symbol");
return $var ? $var.value : undefined;
})();
// not support for of, it mean not support native for of
if (typeof Symbol !== "undefined") {
if (!entity || !entity[Symbol.iterator]) {
if (SymbolConst) {
if (!entity || !entity[SymbolConst.iterator]) {
// FIXME: how to get function name
// for (let value of get()){}
throw ErrInvalidIterable((node.right as types.Identifier).name);
Expand All @@ -490,7 +498,26 @@ const visitors: EvaluateMap = {
forOfScope.invasive = true;
forOfScope.isolated = false;
forOfScope.declare(node.left.kind, varName, value); // define in current scope
evaluate(path.createChild(node.body, forOfScope));
const signal = evaluate(path.createChild(node.body, forOfScope));
if (Signal.isBreak(signal)) {
if (!signal.value) {
break;
}
if (signal.value === labelName) {
break;
}
return signal;
} else if (Signal.isContinue(signal)) {
if (!signal.value) {
continue;
}
if (signal.value === labelName) {
continue;
}
return signal;
} else if (Signal.isReturn(signal)) {
return signal;
}
}
} else if (isIdentifier(node.left)) {
/**
Expand All @@ -503,7 +530,26 @@ const visitors: EvaluateMap = {
const forOfScope = scope.createChild("forOf");
forOfScope.invasive = true;
scope.var(varName, value); // define in parent scope
evaluate(path.createChild(node.body, forOfScope));
const signal = evaluate(path.createChild(node.body, forOfScope));
if (Signal.isBreak(signal)) {
if (!signal.value) {
break;
}
if (signal.value === labelName) {
break;
}
return signal;
} else if (Signal.isContinue(signal)) {
if (!signal.value) {
continue;
}
if (signal.value === labelName) {
continue;
}
return signal;
} else if (Signal.isReturn(signal)) {
return signal;
}
}
}
},
Expand Down
43 changes: 43 additions & 0 deletions test/es2015/for-of/label.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import test from "ava";
import { ErrDuplicateDeclard } from "../../../src/error";
import vm from "../../../src/vm";

test("break with label", t => {
const sandbox: any = vm.createContext({});

const index: any = vm.runInContext(
`
loop1:
for (var index of [0, 1, 2, 3]){
if (index===2){
break loop1;
}
}
module.exports = index;
`,
sandbox
);
t.deepEqual(index, 2);
});

test("continue with label", t => {
const sandbox: any = vm.createContext({});

const list: any = vm.runInContext(
`
var list = [];
loop1:
for (var index of [0, 1, 2, 3]){
if (index%2 === 0){
continue;
}
list.push(index);
}
module.exports = list;
`,
sandbox
);
t.deepEqual(list, [1, 3]);
});

0 comments on commit c4229bf

Please sign in to comment.