diff options
-rw-r--r-- | Libraries/LibJS/AST.cpp | 9 | ||||
-rw-r--r-- | Libraries/LibJS/AST.h | 1 | ||||
-rw-r--r-- | Libraries/LibJS/Parser.cpp | 8 | ||||
-rw-r--r-- | Libraries/LibJS/Runtime/Value.cpp | 8 | ||||
-rw-r--r-- | Libraries/LibJS/Runtime/Value.h | 7 | ||||
-rw-r--r-- | Libraries/LibJS/Tests/binary-bitwise-left-shift.js | 63 | ||||
-rw-r--r-- | Libraries/LibJS/Tests/binary-bitwise-or.js (renamed from Libraries/LibJS/Tests/binary-bitwise-operators-basic.js) | 0 |
7 files changed, 95 insertions, 1 deletions
diff --git a/Libraries/LibJS/AST.cpp b/Libraries/LibJS/AST.cpp index ed8e790df2..2540bdd2fd 100644 --- a/Libraries/LibJS/AST.cpp +++ b/Libraries/LibJS/AST.cpp @@ -749,6 +749,12 @@ Value AssignmentExpression::execute(Interpreter& interpreter) const return {}; rhs_result = div(interpreter, lhs_result, rhs_result); break; + case AssignmentOp::LeftShiftAssignment: + lhs_result = m_lhs->execute(interpreter); + if (interpreter.exception()) + return {}; + rhs_result = left_shift(interpreter, lhs_result, rhs_result); + break; } if (interpreter.exception()) return {}; @@ -816,6 +822,9 @@ void AssignmentExpression::dump(int indent) const case AssignmentOp::DivisionAssignment: op_string = "/="; break; + case AssignmentOp::LeftShiftAssignment: + op_string = "<<="; + break; } ASTNode::dump(indent); diff --git a/Libraries/LibJS/AST.h b/Libraries/LibJS/AST.h index 58c1bbe8ca..156d69395b 100644 --- a/Libraries/LibJS/AST.h +++ b/Libraries/LibJS/AST.h @@ -567,6 +567,7 @@ enum class AssignmentOp { SubtractionAssignment, MultiplicationAssignment, DivisionAssignment, + LeftShiftAssignment, }; class AssignmentExpression : public Expression { diff --git a/Libraries/LibJS/Parser.cpp b/Libraries/LibJS/Parser.cpp index d40b2fc1e2..548d916ad3 100644 --- a/Libraries/LibJS/Parser.cpp +++ b/Libraries/LibJS/Parser.cpp @@ -577,6 +577,12 @@ NonnullRefPtr<Expression> Parser::parse_secondary_expression(NonnullRefPtr<Expre case TokenType::Caret: consume(); return create_ast_node<BinaryExpression>(BinaryOp::BitwiseXor, 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)); + case TokenType::ShiftLeftEquals: + consume(); + return create_ast_node<AssignmentExpression>(AssignmentOp::LeftShiftAssignment, move(lhs), parse_expression(min_precedence, associativity)); case TokenType::ParenOpen: return parse_call_expression(move(lhs)); case TokenType::Equals: @@ -1062,6 +1068,8 @@ bool Parser::match_secondary_expression() const || type == TokenType::Ampersand || type == TokenType::Pipe || type == TokenType::Caret + || type == TokenType::ShiftLeft + || type == TokenType::ShiftLeftEquals || type == TokenType::DoubleAmpersand || type == TokenType::DoublePipe || type == TokenType::DoubleQuestionMark; diff --git a/Libraries/LibJS/Runtime/Value.cpp b/Libraries/LibJS/Runtime/Value.cpp index 08fe1d67b0..e3729317c6 100644 --- a/Libraries/LibJS/Runtime/Value.cpp +++ b/Libraries/LibJS/Runtime/Value.cpp @@ -253,7 +253,13 @@ Value unary_minus(Interpreter&, Value lhs) Value left_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)lhs_number.as_double()); } Value right_shift(Interpreter&, Value lhs, Value rhs) diff --git a/Libraries/LibJS/Runtime/Value.h b/Libraries/LibJS/Runtime/Value.h index 691e15f487..3eccd5cfbe 100644 --- a/Libraries/LibJS/Runtime/Value.h +++ b/Libraries/LibJS/Runtime/Value.h @@ -57,6 +57,13 @@ public: bool is_nan() const { return is_number() && __builtin_isnan(as_double()); } bool is_infinity() const { return is_number() && __builtin_isinf(as_double()); } + bool is_finite_number() const + { + if (!is_number()) + return false; + auto number = as_double(); + return !__builtin_isnan(number) && !__builtin_isinf(number); + } Value() : m_type(Type::Empty) diff --git a/Libraries/LibJS/Tests/binary-bitwise-left-shift.js b/Libraries/LibJS/Tests/binary-bitwise-left-shift.js new file mode 100644 index 0000000000..7eca53f10f --- /dev/null +++ b/Libraries/LibJS/Tests/binary-bitwise-left-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) === 2); + assert((1 << 2) === 4); + assert((1 << 3) === 8); + assert((1 << 4) === 16); + assert((1 << 5) === 32); + + assert((2 << 0) === 2); + assert((2 << 1) === 4); + assert((2 << 2) === 8); + assert((2 << 3) === 16); + assert((2 << 4) === 32); + assert((2 << 5) === 64); + + assert((3 << 0) === 3); + assert((3 << 1) === 6); + assert((3 << 2) === 12); + assert((3 << 3) === 24); + assert((3 << 4) === 48); + assert((3 << 5) === 96); + + assert((4 << 0) === 4); + assert((4 << 1) === 8); + assert((4 << 2) === 16); + assert((4 << 3) === 32); + assert((4 << 4) === 64); + assert((4 << 5) === 128); + + assert((5 << 0) === 5); + assert((5 << 1) === 10); + assert((5 << 2) === 20); + assert((5 << 3) === 40); + assert((5 << 4) === 80); + assert((5 << 5) === 160); + + var x = 3; + var y = 7; + assert(("42" << 6) === 2688); + assert((x << y) === 384); + assert((x << [[[[12]]]]) === 12288); + assert((undefined << y) === 0); + assert(("a" << "b") === 0); + assert((null << null) === 0); + assert((undefined << undefined) === 0); + assert((NaN << NaN) === 0); + assert((NaN << 6) === 0); + assert((Infinity << Infinity) === 0); + assert((-Infinity << Infinity) === 0); + + console.log("PASS"); +} catch (e) { + console.log("FAIL: " + e); +} diff --git a/Libraries/LibJS/Tests/binary-bitwise-operators-basic.js b/Libraries/LibJS/Tests/binary-bitwise-or.js index 09eb1ae036..09eb1ae036 100644 --- a/Libraries/LibJS/Tests/binary-bitwise-operators-basic.js +++ b/Libraries/LibJS/Tests/binary-bitwise-or.js |