fix: logical expression short-circuiting
This commit is contained in:
parent
387e36613f
commit
b1df45baa9
|
@ -149,7 +149,6 @@ export default class Sandbox {
|
|||
case 'ChainExpression':
|
||||
case 'ObjectExpression':
|
||||
case 'Identifier':
|
||||
case 'LogicalExpression':
|
||||
case 'MemberExpression':
|
||||
case 'UnaryExpression':
|
||||
case 'UpdateExpression': {
|
||||
|
@ -174,6 +173,45 @@ export default class Sandbox {
|
|||
/* v8 ignore next 2 */
|
||||
break;
|
||||
}
|
||||
case 'LogicalExpression': {
|
||||
const shouldVisitChild = (child) => (
|
||||
isReplaying
|
||||
? (!this.$$execution.stack[depth + 1] || this.$$execution.stack[depth + 1] === child)
|
||||
: true
|
||||
);
|
||||
if (shouldVisitChild(node.left)) {
|
||||
const left = this.executeSync(node.left, depth + 1);
|
||||
if (left.yield) {
|
||||
return left;
|
||||
}
|
||||
this.$$execution.deferred.set(node.left, left);
|
||||
}
|
||||
const left = this.$$execution.deferred.get(node.left);
|
||||
this.$$execution.deferred.delete(node.left);
|
||||
if ('||' === node.operator && left.value) {
|
||||
result = {
|
||||
value: true,
|
||||
yield: YIELD_NONE,
|
||||
};
|
||||
break;
|
||||
}
|
||||
if ('&&' === node.operator && !left.value) {
|
||||
result = {
|
||||
value: false,
|
||||
yield: YIELD_NONE,
|
||||
};
|
||||
break;
|
||||
}
|
||||
const right = this.executeSync(node.right, depth + 1);
|
||||
if (right.yield) {
|
||||
return right;
|
||||
}
|
||||
result = {
|
||||
value: !!right.value,
|
||||
yield: YIELD_NONE,
|
||||
};
|
||||
break;
|
||||
}
|
||||
case 'BlockStatement': {
|
||||
result = {
|
||||
value: undefined,
|
||||
|
|
|
@ -631,3 +631,45 @@ test('breaks loops', async () => {
|
|||
)
|
||||
.to.deep.include({value: [1, 1, 2, 2, 3, 3]});
|
||||
});
|
||||
|
||||
test('short-circuits logical expressions', async () => {
|
||||
let x = 0;
|
||||
expect(
|
||||
(new Sandbox(
|
||||
await parse(`
|
||||
let y = 0;
|
||||
if (test || test()) {
|
||||
y = 1;
|
||||
}
|
||||
y
|
||||
`),
|
||||
{
|
||||
test: () => {
|
||||
x = 1;
|
||||
},
|
||||
}
|
||||
)).run()
|
||||
)
|
||||
.to.deep.include({value: 1});
|
||||
expect(x)
|
||||
.to.equal(0);
|
||||
expect(
|
||||
(new Sandbox(
|
||||
await parse(`
|
||||
let y = 0;
|
||||
if (!test && test()) {
|
||||
y = 1;
|
||||
}
|
||||
y
|
||||
`),
|
||||
{
|
||||
test: () => {
|
||||
x = 1;
|
||||
},
|
||||
}
|
||||
)).run()
|
||||
)
|
||||
.to.deep.include({value: 0});
|
||||
expect(x)
|
||||
.to.equal(0);
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue
Block a user