diff --git a/Libraries/LibJS/AST.cpp b/Libraries/LibJS/AST.cpp index 2540bdd2fd..198f1b297f 100644 --- a/Libraries/LibJS/AST.cpp +++ b/Libraries/LibJS/AST.cpp @@ -755,6 +755,12 @@ Value AssignmentExpression::execute(Interpreter& interpreter) const return {}; rhs_result = left_shift(interpreter, lhs_result, rhs_result); break; + case AssignmentOp::RightShiftAssignment: + lhs_result = m_lhs->execute(interpreter); + if (interpreter.exception()) + return {}; + rhs_result = right_shift(interpreter, lhs_result, rhs_result); + break; } if (interpreter.exception()) return {}; @@ -825,6 +831,9 @@ void AssignmentExpression::dump(int indent) const case AssignmentOp::LeftShiftAssignment: op_string = "<<="; break; + case AssignmentOp::RightShiftAssignment: + op_string = ">>="; + break; } ASTNode::dump(indent); diff --git a/Libraries/LibJS/AST.h b/Libraries/LibJS/AST.h index 156d69395b..acb78abe74 100644 --- a/Libraries/LibJS/AST.h +++ b/Libraries/LibJS/AST.h @@ -568,6 +568,7 @@ enum class AssignmentOp { MultiplicationAssignment, DivisionAssignment, LeftShiftAssignment, + RightShiftAssignment, }; class AssignmentExpression : public Expression { diff --git a/Libraries/LibJS/Parser.cpp b/Libraries/LibJS/Parser.cpp index 548d916ad3..182d76653a 100644 --- a/Libraries/LibJS/Parser.cpp +++ b/Libraries/LibJS/Parser.cpp @@ -583,6 +583,12 @@ NonnullRefPtr Parser::parse_secondary_expression(NonnullRefPtr(AssignmentOp::LeftShiftAssignment, move(lhs), parse_expression(min_precedence, associativity)); + case TokenType::ShiftRight: + consume(); + return create_ast_node(BinaryOp::RightShift, move(lhs), parse_expression(min_precedence, associativity)); + case TokenType::ShiftRightEquals: + consume(); + return create_ast_node(AssignmentOp::RightShiftAssignment, move(lhs), parse_expression(min_precedence, associativity)); case TokenType::ParenOpen: return parse_call_expression(move(lhs)); case TokenType::Equals: @@ -1070,6 +1076,8 @@ bool Parser::match_secondary_expression() const || type == TokenType::Caret || type == TokenType::ShiftLeft || type == TokenType::ShiftLeftEquals + || type == TokenType::ShiftRight + || type == TokenType::ShiftRightEquals || type == TokenType::DoubleAmpersand || type == TokenType::DoublePipe || type == TokenType::DoubleQuestionMark; diff --git a/Libraries/LibJS/Runtime/Value.cpp b/Libraries/LibJS/Runtime/Value.cpp index e3729317c6..5da5c5765f 100644 --- a/Libraries/LibJS/Runtime/Value.cpp +++ b/Libraries/LibJS/Runtime/Value.cpp @@ -264,7 +264,13 @@ Value left_shift(Interpreter&, Value lhs, Value rhs) Value right_shift(Interpreter&, Value lhs, Value rhs) { - return Value((i32)lhs.to_number().as_double() >> (i32)rhs.to_number().as_double()); + auto lhs_number = lhs.to_number(); + if (!lhs_number.is_finite_number()) + return Value(0); + auto rhs_number = rhs.to_number(); + if (!rhs_number.is_finite_number()) + return lhs_number; + return Value((i32)lhs_number.as_double() >> (i32)rhs_number.as_double()); } Value add(Interpreter& interpreter, Value lhs, Value rhs) diff --git a/Libraries/LibJS/Tests/binary-bitwise-right-shift.js b/Libraries/LibJS/Tests/binary-bitwise-right-shift.js new file mode 100644 index 0000000000..4338d09652 --- /dev/null +++ b/Libraries/LibJS/Tests/binary-bitwise-right-shift.js @@ -0,0 +1,63 @@ +load("test-common.js"); + +try { + assert((0 >> 0) === 0); + assert((0 >> 1) === 0); + assert((0 >> 2) === 0); + assert((0 >> 3) === 0); + assert((0 >> 4) === 0); + assert((0 >> 5) === 0); + + assert((1 >> 0) === 1); + assert((1 >> 1) === 0); + assert((1 >> 2) === 0); + assert((1 >> 3) === 0); + assert((1 >> 4) === 0); + assert((1 >> 5) === 0); + + assert((5 >> 0) === 5); + assert((5 >> 1) === 2); + assert((5 >> 2) === 1); + assert((5 >> 3) === 0); + assert((5 >> 4) === 0); + assert((5 >> 5) === 0); + + assert((42 >> 0) === 42); + assert((42 >> 1) === 21); + assert((42 >> 2) === 10); + assert((42 >> 3) === 5); + assert((42 >> 4) === 2); + assert((42 >> 5) === 1); + + assert((-1 >> 0) === -1); + assert((-1 >> 1) === -1); + assert((-1 >> 2) === -1); + assert((-1 >> 3) === -1); + assert((-1 >> 4) === -1); + assert((-1 >> 5) === -1); + + assert((-5 >> 0) === -5); + assert((-5 >> 1) === -3); + assert((-5 >> 2) === -2); + assert((-5 >> 3) === -1); + assert((-5 >> 4) === -1); + assert((-5 >> 5) === -1); + + var x = 67; + var y = 4; + assert(("42" >> 3) === 5); + assert((x >> y) === 4); + assert((x >> [[[[5]]]]) === 2); + assert((undefined >> y) === 0); + assert(("a" >> "b") === 0); + assert((null >> null) === 0); + assert((undefined >> undefined) === 0); + assert((NaN >> NaN) === 0); + assert((6 >> NaN) === 6); + assert((Infinity >> Infinity) === 0); + assert((-Infinity >> Infinity) === 0); + + console.log("PASS"); +} catch (e) { + console.log("FAIL: " + e); +}