feat: break

This commit is contained in:
cha0s 2024-07-12 18:32:55 -05:00
parent 53f4d35717
commit 5365608f9f
4 changed files with 109 additions and 0 deletions

View File

@ -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);

View File

@ -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]});
});

View File

@ -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'],

View File

@ -15,6 +15,7 @@ for (const position of projected) {
for (const {Plant} of entities) {
if (Plant) {
hasPlant = true
break;
}
}
if (!hasPlant) {