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 'ChainExpression':
|
||||||
case 'ObjectExpression':
|
case 'ObjectExpression':
|
||||||
case 'Identifier':
|
case 'Identifier':
|
||||||
case 'LogicalExpression':
|
|
||||||
case 'MemberExpression':
|
case 'MemberExpression':
|
||||||
case 'UnaryExpression':
|
case 'UnaryExpression':
|
||||||
case 'UpdateExpression': {
|
case 'UpdateExpression': {
|
||||||
|
@ -174,6 +173,45 @@ export default class Sandbox {
|
||||||
/* v8 ignore next 2 */
|
/* v8 ignore next 2 */
|
||||||
break;
|
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': {
|
case 'BlockStatement': {
|
||||||
result = {
|
result = {
|
||||||
value: undefined,
|
value: undefined,
|
||||||
|
|
|
@ -631,3 +631,45 @@ test('breaks loops', async () => {
|
||||||
)
|
)
|
||||||
.to.deep.include({value: [1, 1, 2, 2, 3, 3]});
|
.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