feat: break
This commit is contained in:
parent
53f4d35717
commit
5365608f9f
|
@ -6,6 +6,7 @@ const YIELD_NONE = 0;
|
|||
const YIELD_PROMISE = 1;
|
||||
const YIELD_LOOP_UPDATE = 2;
|
||||
const YIELD_RETURN = 3;
|
||||
const YIELD_BREAK = 4;
|
||||
|
||||
export default class Sandbox {
|
||||
|
||||
|
@ -194,6 +195,24 @@ export default class Sandbox {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case 'BreakStatement': {
|
||||
walkUp: while (this.$$execution.stack.length > 0) {
|
||||
const frame = this.$$execution.stack[this.$$execution.stack.length - 1];
|
||||
switch (frame.type) {
|
||||
case 'ForStatement': {
|
||||
break walkUp;
|
||||
}
|
||||
case 'ForOfStatement': {
|
||||
break walkUp;
|
||||
}
|
||||
default: this.$$execution.stack.pop();
|
||||
}
|
||||
}
|
||||
return {
|
||||
value: undefined,
|
||||
yield: YIELD_BREAK,
|
||||
};
|
||||
}
|
||||
case 'ConditionalExpression': {
|
||||
const shouldVisitChild = (child) => (
|
||||
isReplaying
|
||||
|
@ -292,6 +311,10 @@ export default class Sandbox {
|
|||
if (shouldVisitChild(node.body)) {
|
||||
const body = this.executeSync(node.body, depth + 1);
|
||||
if (body.yield) {
|
||||
if (YIELD_BREAK === body.yield) {
|
||||
this.$$execution.deferred.delete(node.body);
|
||||
break;
|
||||
}
|
||||
return body;
|
||||
}
|
||||
this.$$execution.deferred.set(node.body, body);
|
||||
|
@ -338,6 +361,7 @@ export default class Sandbox {
|
|||
}
|
||||
const {done, value} = this.$$execution.deferred.get(node.left);
|
||||
if (done) {
|
||||
this.$$execution.deferred.delete(node.left);
|
||||
this.$$execution.deferred.delete(node.body);
|
||||
break;
|
||||
}
|
||||
|
@ -376,6 +400,11 @@ export default class Sandbox {
|
|||
if (shouldVisitChild(node.body)) {
|
||||
const body = this.executeSync(node.body, depth + 1);
|
||||
if (body.yield) {
|
||||
if (YIELD_BREAK === body.yield) {
|
||||
this.$$execution.deferred.delete(node.left);
|
||||
this.$$execution.deferred.delete(node.body);
|
||||
break;
|
||||
}
|
||||
return body;
|
||||
}
|
||||
this.$$execution.deferred.set(node.body, body);
|
||||
|
|
|
@ -553,3 +553,81 @@ test('implements for...of', async () => {
|
|||
)
|
||||
.to.deep.include({value: [2, 12, 30]});
|
||||
});
|
||||
|
||||
test('breaks loops', async () => {
|
||||
expect(
|
||||
(new Sandbox(
|
||||
await parse(`
|
||||
const out = [];
|
||||
for (let i = 0; i < 3; ++i) {
|
||||
out.push(i);
|
||||
break;
|
||||
}
|
||||
out
|
||||
`),
|
||||
)).run()
|
||||
)
|
||||
.to.deep.include({value: [0]});
|
||||
expect(
|
||||
(new Sandbox(
|
||||
await parse(`
|
||||
const out = [];
|
||||
for (let i = 0; i < 3; ++i) {
|
||||
out.push(i);
|
||||
if (i > 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
out
|
||||
`),
|
||||
)).run()
|
||||
)
|
||||
.to.deep.include({value: [0, 1]});
|
||||
expect(
|
||||
(new Sandbox(
|
||||
await parse(`
|
||||
const out = [];
|
||||
for (const x of [1, 2, 3]) {
|
||||
out.push(x);
|
||||
break;
|
||||
}
|
||||
out
|
||||
`),
|
||||
)).run()
|
||||
)
|
||||
.to.deep.include({value: [1]});
|
||||
expect(
|
||||
(new Sandbox(
|
||||
await parse(`
|
||||
const out = [];
|
||||
for (const x of [1, 2, 3]) {
|
||||
for (const y of [4, 5, 6]) {
|
||||
out.push(x);
|
||||
if (y > 4) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
out
|
||||
`),
|
||||
)).run()
|
||||
)
|
||||
.to.deep.include({value: [1, 1, 2, 2, 3, 3]});
|
||||
expect(
|
||||
(new Sandbox(
|
||||
await parse(`
|
||||
const out = [];
|
||||
for (let x = 1; x < 4; ++x) {
|
||||
for (let y = 4; y < 7; ++y) {
|
||||
out.push(x);
|
||||
if (y > 4) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
out
|
||||
`),
|
||||
)).run()
|
||||
)
|
||||
.to.deep.include({value: [1, 1, 2, 2, 3, 3]});
|
||||
});
|
||||
|
|
|
@ -5,6 +5,7 @@ export const TRAVERSAL_PATH = {
|
|||
AwaitExpression: ['argument'],
|
||||
BinaryExpression: ['left', 'right'],
|
||||
BlockStatement: ['body'],
|
||||
BreakStatement: [],
|
||||
CallExpression: ['arguments', 'callee'],
|
||||
ChainExpression: ['expression'],
|
||||
ConditionalExpression: ['alternate', 'consequent', 'test'],
|
||||
|
|
|
@ -15,6 +15,7 @@ for (const position of projected) {
|
|||
for (const {Plant} of entities) {
|
||||
if (Plant) {
|
||||
hasPlant = true
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!hasPlant) {
|
||||
|
|
Loading…
Reference in New Issue
Block a user