LibJS: Implement bitwise assignment operators (&=, |=, ^=)

This commit is contained in:
Linus Groh 2020-05-04 22:34:45 +01:00 committed by Andreas Kling
parent 8e4301dea6
commit 3e754a15d4
Notes: sideshowbarker 2024-07-19 06:58:00 +09:00
8 changed files with 62 additions and 2 deletions

View file

@ -50,7 +50,6 @@ static TextStyle style_for_token_type(Gfx::Palette palette, JS::TokenType type)
return { palette.syntax_string() };
case JS::TokenType::BracketClose:
case JS::TokenType::BracketOpen:
case JS::TokenType::Caret:
case JS::TokenType::Comma:
case JS::TokenType::CurlyClose:
case JS::TokenType::CurlyOpen:
@ -65,6 +64,8 @@ static TextStyle style_for_token_type(Gfx::Palette palette, JS::TokenType type)
case JS::TokenType::Asterisk:
case JS::TokenType::AsteriskAsteriskEquals:
case JS::TokenType::AsteriskEquals:
case JS::TokenType::Caret:
case JS::TokenType::CaretEquals:
case JS::TokenType::DoubleAmpersand:
case JS::TokenType::DoubleAsterisk:
case JS::TokenType::DoublePipe:

View file

@ -850,6 +850,24 @@ Value AssignmentExpression::execute(Interpreter& interpreter) const
return {};
rhs_result = div(interpreter, lhs_result, rhs_result);
break;
case AssignmentOp::BitwiseAndAssignment:
lhs_result = m_lhs->execute(interpreter);
if (interpreter.exception())
return {};
rhs_result = bitwise_and(interpreter, lhs_result, rhs_result);
break;
case AssignmentOp::BitwiseOrAssignment:
lhs_result = m_lhs->execute(interpreter);
if (interpreter.exception())
return {};
rhs_result = bitwise_or(interpreter, lhs_result, rhs_result);
break;
case AssignmentOp::BitwiseXorAssignment:
lhs_result = m_lhs->execute(interpreter);
if (interpreter.exception())
return {};
rhs_result = bitwise_xor(interpreter, lhs_result, rhs_result);
break;
case AssignmentOp::LeftShiftAssignment:
lhs_result = m_lhs->execute(interpreter);
if (interpreter.exception())
@ -936,6 +954,15 @@ void AssignmentExpression::dump(int indent) const
case AssignmentOp::DivisionAssignment:
op_string = "/=";
break;
case AssignmentOp::BitwiseAndAssignment:
op_string = "&=";
break;
case AssignmentOp::BitwiseOrAssignment:
op_string = "|=";
break;
case AssignmentOp::BitwiseXorAssignment:
op_string = "^=";
break;
case AssignmentOp::LeftShiftAssignment:
op_string = "<<=";
break;

View file

@ -604,6 +604,9 @@ enum class AssignmentOp {
SubtractionAssignment,
MultiplicationAssignment,
DivisionAssignment,
BitwiseAndAssignment,
BitwiseOrAssignment,
BitwiseXorAssignment,
LeftShiftAssignment,
RightShiftAssignment,
UnsignedRightShiftAssignment,

View file

@ -97,6 +97,7 @@ Lexer::Lexer(StringView source)
s_two_char_tokens.set("%=", TokenType::PercentEquals);
s_two_char_tokens.set("&=", TokenType::AmpersandEquals);
s_two_char_tokens.set("|=", TokenType::PipeEquals);
s_two_char_tokens.set("^=", TokenType::CaretEquals);
s_two_char_tokens.set("&&", TokenType::DoubleAmpersand);
s_two_char_tokens.set("||", TokenType::DoublePipe);
s_two_char_tokens.set("??", TokenType::DoubleQuestionMark);

View file

@ -140,7 +140,9 @@ Parser::Parser(Lexer lexer)
g_operator_precedence.set(TokenType::ShiftLeftEquals, 3);
g_operator_precedence.set(TokenType::ShiftRightEquals, 3);
g_operator_precedence.set(TokenType::UnsignedShiftRightEquals, 3);
g_operator_precedence.set(TokenType::AmpersandEquals, 3);
g_operator_precedence.set(TokenType::PipeEquals, 3);
g_operator_precedence.set(TokenType::CaretEquals, 3);
g_operator_precedence.set(TokenType::Yield, 2);
@ -668,12 +670,21 @@ NonnullRefPtr<Expression> Parser::parse_secondary_expression(NonnullRefPtr<Expre
case TokenType::Ampersand:
consume();
return create_ast_node<BinaryExpression>(BinaryOp::BitwiseAnd, move(lhs), parse_expression(min_precedence, associativity));
case TokenType::AmpersandEquals:
consume();
return create_ast_node<AssignmentExpression>(AssignmentOp::BitwiseAndAssignment, move(lhs), parse_expression(min_precedence, associativity));
case TokenType::Pipe:
consume();
return create_ast_node<BinaryExpression>(BinaryOp::BitwiseOr, move(lhs), parse_expression(min_precedence, associativity));
case TokenType::PipeEquals:
consume();
return create_ast_node<AssignmentExpression>(AssignmentOp::BitwiseOrAssignment, move(lhs), parse_expression(min_precedence, associativity));
case TokenType::Caret:
consume();
return create_ast_node<BinaryExpression>(BinaryOp::BitwiseXor, move(lhs), parse_expression(min_precedence, associativity));
case TokenType::CaretEquals:
consume();
return create_ast_node<AssignmentExpression>(AssignmentOp::BitwiseXorAssignment, move(lhs), parse_expression(min_precedence, associativity));
case TokenType::ShiftLeft:
consume();
return create_ast_node<BinaryExpression>(BinaryOp::LeftShift, move(lhs), parse_expression(min_precedence, associativity));
@ -1199,8 +1210,11 @@ bool Parser::match_secondary_expression() const
|| type == TokenType::Instanceof
|| type == TokenType::QuestionMark
|| type == TokenType::Ampersand
|| type == TokenType::AmpersandEquals
|| type == TokenType::Pipe
|| type == TokenType::PipeEquals
|| type == TokenType::Caret
|| type == TokenType::CaretEquals
|| type == TokenType::ShiftLeft
|| type == TokenType::ShiftLeftEquals
|| type == TokenType::ShiftRight

View file

@ -23,6 +23,18 @@ try {
assert((x /= 2) === 3);
assert(x === 3);
x = 3;
assert((x &= 2) === 2);
assert(x === 2);
x = 3;
assert((x |= 4) === 7);
assert(x === 7);
x = 6;
assert((x ^= 2) === 4);
assert(x === 4);
x = 2;
assert((x <<= 2) === 8);
assert(x === 8);

View file

@ -44,6 +44,7 @@ namespace JS {
__ENUMERATE_JS_TOKEN(BracketOpen) \
__ENUMERATE_JS_TOKEN(Break) \
__ENUMERATE_JS_TOKEN(Caret) \
__ENUMERATE_JS_TOKEN(CaretEquals) \
__ENUMERATE_JS_TOKEN(Case) \
__ENUMERATE_JS_TOKEN(Catch) \
__ENUMERATE_JS_TOKEN(Class) \

View file

@ -556,7 +556,6 @@ int main(int argc, char** argv)
break;
case JS::TokenType::BracketClose:
case JS::TokenType::BracketOpen:
case JS::TokenType::Caret:
case JS::TokenType::Comma:
case JS::TokenType::CurlyClose:
case JS::TokenType::CurlyOpen:
@ -570,6 +569,8 @@ int main(int argc, char** argv)
case JS::TokenType::Asterisk:
case JS::TokenType::AsteriskAsteriskEquals:
case JS::TokenType::AsteriskEquals:
case JS::TokenType::Caret:
case JS::TokenType::CaretEquals:
case JS::TokenType::DoubleAmpersand:
case JS::TokenType::DoubleAsterisk:
case JS::TokenType::DoublePipe: