LibJS: Evaluate AssignmentExpression LHS before RHS according to the spec

Fixes #3689.
This commit is contained in:
Linus Groh 2020-10-05 12:30:08 +01:00 committed by Andreas Kling
parent 7fd4646acb
commit 2d4cd5b49b
Notes: sideshowbarker 2024-07-19 02:02:22 +09:00
2 changed files with 63 additions and 39 deletions

View file

@ -1198,84 +1198,67 @@ void ThisExpression::dump(int indent) const
Value AssignmentExpression::execute(Interpreter& interpreter, GlobalObject& global_object) const
{
auto rhs_result = m_rhs->execute(interpreter, global_object);
if (interpreter.exception())
return {};
#define EXECUTE_LHS_AND_RHS() \
do { \
lhs_result = m_lhs->execute(interpreter, global_object); \
if (interpreter.exception()) \
return {}; \
rhs_result = m_rhs->execute(interpreter, global_object); \
if (interpreter.exception()) \
return {}; \
} while (0)
Value lhs_result;
Value rhs_result;
switch (m_op) {
case AssignmentOp::Assignment:
break;
case AssignmentOp::AdditionAssignment:
lhs_result = m_lhs->execute(interpreter, global_object);
if (interpreter.exception())
return {};
EXECUTE_LHS_AND_RHS();
rhs_result = add(global_object, lhs_result, rhs_result);
break;
case AssignmentOp::SubtractionAssignment:
lhs_result = m_lhs->execute(interpreter, global_object);
if (interpreter.exception())
return {};
EXECUTE_LHS_AND_RHS();
rhs_result = sub(global_object, lhs_result, rhs_result);
break;
case AssignmentOp::MultiplicationAssignment:
lhs_result = m_lhs->execute(interpreter, global_object);
if (interpreter.exception())
return {};
EXECUTE_LHS_AND_RHS();
rhs_result = mul(global_object, lhs_result, rhs_result);
break;
case AssignmentOp::DivisionAssignment:
lhs_result = m_lhs->execute(interpreter, global_object);
if (interpreter.exception())
return {};
EXECUTE_LHS_AND_RHS();
rhs_result = div(global_object, lhs_result, rhs_result);
break;
case AssignmentOp::ModuloAssignment:
lhs_result = m_lhs->execute(interpreter, global_object);
if (interpreter.exception())
return {};
EXECUTE_LHS_AND_RHS();
rhs_result = mod(global_object, lhs_result, rhs_result);
break;
case AssignmentOp::ExponentiationAssignment:
lhs_result = m_lhs->execute(interpreter, global_object);
if (interpreter.exception())
return {};
EXECUTE_LHS_AND_RHS();
rhs_result = exp(global_object, lhs_result, rhs_result);
break;
case AssignmentOp::BitwiseAndAssignment:
lhs_result = m_lhs->execute(interpreter, global_object);
if (interpreter.exception())
return {};
EXECUTE_LHS_AND_RHS();
rhs_result = bitwise_and(global_object, lhs_result, rhs_result);
break;
case AssignmentOp::BitwiseOrAssignment:
lhs_result = m_lhs->execute(interpreter, global_object);
if (interpreter.exception())
return {};
EXECUTE_LHS_AND_RHS();
rhs_result = bitwise_or(global_object, lhs_result, rhs_result);
break;
case AssignmentOp::BitwiseXorAssignment:
lhs_result = m_lhs->execute(interpreter, global_object);
if (interpreter.exception())
return {};
EXECUTE_LHS_AND_RHS();
rhs_result = bitwise_xor(global_object, lhs_result, rhs_result);
break;
case AssignmentOp::LeftShiftAssignment:
lhs_result = m_lhs->execute(interpreter, global_object);
if (interpreter.exception())
return {};
EXECUTE_LHS_AND_RHS();
rhs_result = left_shift(global_object, lhs_result, rhs_result);
break;
case AssignmentOp::RightShiftAssignment:
lhs_result = m_lhs->execute(interpreter, global_object);
if (interpreter.exception())
return {};
EXECUTE_LHS_AND_RHS();
rhs_result = right_shift(global_object, lhs_result, rhs_result);
break;
case AssignmentOp::UnsignedRightShiftAssignment:
lhs_result = m_lhs->execute(interpreter, global_object);
if (interpreter.exception())
return {};
EXECUTE_LHS_AND_RHS();
rhs_result = unsigned_right_shift(global_object, lhs_result, rhs_result);
break;
}
@ -1286,6 +1269,12 @@ Value AssignmentExpression::execute(Interpreter& interpreter, GlobalObject& glob
if (interpreter.exception())
return {};
if (m_op == AssignmentOp::Assignment) {
rhs_result = m_rhs->execute(interpreter, global_object);
if (interpreter.exception())
return {};
}
if (reference.is_unresolvable()) {
interpreter.vm().throw_exception<ReferenceError>(global_object, ErrorType::InvalidLeftHandAssignment);
return {};

View file

@ -53,3 +53,38 @@ test("basic functionality", () => {
expect((x >>>= 2)).toBe(2);
expect(x).toBe(2);
});
test("evaluation order", () => {
for (const op of [
"=",
"+=",
"-=",
"*=",
"/=",
"%=",
"**=",
"&=",
"|=",
"^=",
"<<=",
">>=",
">>>=",
]) {
var a = [];
function b() {
b.hasBeenCalled = true;
throw Error();
}
function c() {
c.hasBeenCalled = true;
throw Error();
}
b.hasBeenCalled = false;
c.hasBeenCalled = false;
expect(() => {
new Function(`a[b()] ${op} c()`)();
}).toThrow(Error);
expect(b.hasBeenCalled).toBeTrue();
expect(c.hasBeenCalled).toBeFalse();
}
});