diff --git a/Libraries/LibGUI/JSSyntaxHighlighter.cpp b/Libraries/LibGUI/JSSyntaxHighlighter.cpp index 30aa6d7e13..0747a92142 100644 --- a/Libraries/LibGUI/JSSyntaxHighlighter.cpp +++ b/Libraries/LibGUI/JSSyntaxHighlighter.cpp @@ -62,7 +62,7 @@ static TextStyle style_for_token_type(Gfx::Palette palette, JS::TokenType type) case JS::TokenType::Ampersand: case JS::TokenType::AmpersandEquals: case JS::TokenType::Asterisk: - case JS::TokenType::AsteriskAsteriskEquals: + case JS::TokenType::DoubleAsteriskEquals: case JS::TokenType::AsteriskEquals: case JS::TokenType::Caret: case JS::TokenType::CaretEquals: diff --git a/Libraries/LibJS/AST.cpp b/Libraries/LibJS/AST.cpp index 25b22d154a..5579e3cd68 100644 --- a/Libraries/LibJS/AST.cpp +++ b/Libraries/LibJS/AST.cpp @@ -850,6 +850,12 @@ Value AssignmentExpression::execute(Interpreter& interpreter) const return {}; rhs_result = div(interpreter, lhs_result, rhs_result); break; + case AssignmentOp::ExponentiationAssignment: + lhs_result = m_lhs->execute(interpreter); + if (interpreter.exception()) + return {}; + rhs_result = exp(interpreter, lhs_result, rhs_result); + break; case AssignmentOp::BitwiseAndAssignment: lhs_result = m_lhs->execute(interpreter); if (interpreter.exception()) @@ -954,6 +960,9 @@ void AssignmentExpression::dump(int indent) const case AssignmentOp::DivisionAssignment: op_string = "/="; break; + case AssignmentOp::ExponentiationAssignment: + op_string = "**="; + break; case AssignmentOp::BitwiseAndAssignment: op_string = "&="; break; diff --git a/Libraries/LibJS/AST.h b/Libraries/LibJS/AST.h index a1c2c9960f..ab02e02572 100644 --- a/Libraries/LibJS/AST.h +++ b/Libraries/LibJS/AST.h @@ -604,6 +604,7 @@ enum class AssignmentOp { SubtractionAssignment, MultiplicationAssignment, DivisionAssignment, + ExponentiationAssignment, BitwiseAndAssignment, BitwiseOrAssignment, BitwiseXorAssignment, diff --git a/Libraries/LibJS/Lexer.cpp b/Libraries/LibJS/Lexer.cpp index 388ec424da..29c0a8d586 100644 --- a/Libraries/LibJS/Lexer.cpp +++ b/Libraries/LibJS/Lexer.cpp @@ -81,7 +81,7 @@ Lexer::Lexer(StringView source) if (s_three_char_tokens.is_empty()) { s_three_char_tokens.set("===", TokenType::EqualsEqualsEquals); s_three_char_tokens.set("!==", TokenType::ExclamationMarkEqualsEquals); - s_three_char_tokens.set("**=", TokenType::AsteriskAsteriskEquals); + s_three_char_tokens.set("**=", TokenType::DoubleAsteriskEquals); s_three_char_tokens.set("<<=", TokenType::ShiftLeftEquals); s_three_char_tokens.set(">>=", TokenType::ShiftRightEquals); s_three_char_tokens.set(">>>", TokenType::UnsignedShiftRight); diff --git a/Libraries/LibJS/Parser.cpp b/Libraries/LibJS/Parser.cpp index 64eb68a4c9..c98a827056 100644 --- a/Libraries/LibJS/Parser.cpp +++ b/Libraries/LibJS/Parser.cpp @@ -133,7 +133,7 @@ Parser::Parser(Lexer lexer) g_operator_precedence.set(TokenType::Equals, 3); g_operator_precedence.set(TokenType::PlusEquals, 3); g_operator_precedence.set(TokenType::MinusEquals, 3); - g_operator_precedence.set(TokenType::AsteriskAsteriskEquals, 3); + g_operator_precedence.set(TokenType::DoubleAsteriskEquals, 3); g_operator_precedence.set(TokenType::AsteriskEquals, 3); g_operator_precedence.set(TokenType::SlashEquals, 3); g_operator_precedence.set(TokenType::PercentEquals, 3); @@ -637,6 +637,9 @@ NonnullRefPtr Parser::parse_secondary_expression(NonnullRefPtr(BinaryOp::Exponentiation, move(lhs), parse_expression(min_precedence, associativity)); + case TokenType::DoubleAsteriskEquals: + consume(); + return create_ast_node(AssignmentOp::ExponentiationAssignment, move(lhs), parse_expression(min_precedence, associativity)); case TokenType::GreaterThan: consume(); return create_ast_node(BinaryOp::GreaterThan, move(lhs), parse_expression(min_precedence, associativity)); @@ -1192,6 +1195,7 @@ bool Parser::match_secondary_expression() const || type == TokenType::SlashEquals || type == TokenType::Percent || type == TokenType::DoubleAsterisk + || type == TokenType::DoubleAsteriskEquals || type == TokenType::Equals || type == TokenType::EqualsEqualsEquals || type == TokenType::ExclamationMarkEqualsEquals diff --git a/Libraries/LibJS/Tests/assignment-operators.js b/Libraries/LibJS/Tests/assignment-operators.js index 23443186e4..ec2a693988 100644 --- a/Libraries/LibJS/Tests/assignment-operators.js +++ b/Libraries/LibJS/Tests/assignment-operators.js @@ -23,6 +23,10 @@ try { assert((x /= 2) === 3); assert(x === 3); + x = 2; + assert((x **= 3) === 8); + assert(x === 8); + x = 3; assert((x &= 2) === 2); assert(x === 2); diff --git a/Libraries/LibJS/Token.h b/Libraries/LibJS/Token.h index db0109c50d..669d2ed1bb 100644 --- a/Libraries/LibJS/Token.h +++ b/Libraries/LibJS/Token.h @@ -36,7 +36,7 @@ namespace JS { __ENUMERATE_JS_TOKEN(AmpersandEquals) \ __ENUMERATE_JS_TOKEN(Arrow) \ __ENUMERATE_JS_TOKEN(Asterisk) \ - __ENUMERATE_JS_TOKEN(AsteriskAsteriskEquals) \ + __ENUMERATE_JS_TOKEN(DoubleAsteriskEquals) \ __ENUMERATE_JS_TOKEN(AsteriskEquals) \ __ENUMERATE_JS_TOKEN(Await) \ __ENUMERATE_JS_TOKEN(BoolLiteral) \ diff --git a/Userland/js.cpp b/Userland/js.cpp index 36b71bcf91..0389a5318f 100644 --- a/Userland/js.cpp +++ b/Userland/js.cpp @@ -567,7 +567,7 @@ int main(int argc, char** argv) case JS::TokenType::Ampersand: case JS::TokenType::AmpersandEquals: case JS::TokenType::Asterisk: - case JS::TokenType::AsteriskAsteriskEquals: + case JS::TokenType::DoubleAsteriskEquals: case JS::TokenType::AsteriskEquals: case JS::TokenType::Caret: case JS::TokenType::CaretEquals: