瀏覽代碼

LibJS: Implement bitwise left shift operator (<<)

Linus Groh 5 年之前
父節點
當前提交
f0e7404480

+ 9 - 0
Libraries/LibJS/AST.cpp

@@ -749,6 +749,12 @@ Value AssignmentExpression::execute(Interpreter& interpreter) const
             return {};
             return {};
         rhs_result = div(interpreter, lhs_result, rhs_result);
         rhs_result = div(interpreter, lhs_result, rhs_result);
         break;
         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())
     if (interpreter.exception())
         return {};
         return {};
@@ -816,6 +822,9 @@ void AssignmentExpression::dump(int indent) const
     case AssignmentOp::DivisionAssignment:
     case AssignmentOp::DivisionAssignment:
         op_string = "/=";
         op_string = "/=";
         break;
         break;
+    case AssignmentOp::LeftShiftAssignment:
+        op_string = "<<=";
+        break;
     }
     }
 
 
     ASTNode::dump(indent);
     ASTNode::dump(indent);

+ 1 - 0
Libraries/LibJS/AST.h

@@ -567,6 +567,7 @@ enum class AssignmentOp {
     SubtractionAssignment,
     SubtractionAssignment,
     MultiplicationAssignment,
     MultiplicationAssignment,
     DivisionAssignment,
     DivisionAssignment,
+    LeftShiftAssignment,
 };
 };
 
 
 class AssignmentExpression : public Expression {
 class AssignmentExpression : public Expression {

+ 8 - 0
Libraries/LibJS/Parser.cpp

@@ -577,6 +577,12 @@ NonnullRefPtr<Expression> Parser::parse_secondary_expression(NonnullRefPtr<Expre
     case TokenType::Caret:
     case TokenType::Caret:
         consume();
         consume();
         return create_ast_node<BinaryExpression>(BinaryOp::BitwiseXor, move(lhs), parse_expression(min_precedence, associativity));
         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:
     case TokenType::ParenOpen:
         return parse_call_expression(move(lhs));
         return parse_call_expression(move(lhs));
     case TokenType::Equals:
     case TokenType::Equals:
@@ -1062,6 +1068,8 @@ bool Parser::match_secondary_expression() const
         || type == TokenType::Ampersand
         || type == TokenType::Ampersand
         || type == TokenType::Pipe
         || type == TokenType::Pipe
         || type == TokenType::Caret
         || type == TokenType::Caret
+        || type == TokenType::ShiftLeft
+        || type == TokenType::ShiftLeftEquals
         || type == TokenType::DoubleAmpersand
         || type == TokenType::DoubleAmpersand
         || type == TokenType::DoublePipe
         || type == TokenType::DoublePipe
         || type == TokenType::DoubleQuestionMark;
         || type == TokenType::DoubleQuestionMark;

+ 7 - 1
Libraries/LibJS/Runtime/Value.cpp

@@ -253,7 +253,13 @@ Value unary_minus(Interpreter&, Value lhs)
 
 
 Value left_shift(Interpreter&, Value lhs, Value rhs)
 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)
 Value right_shift(Interpreter&, Value lhs, Value rhs)

+ 7 - 0
Libraries/LibJS/Runtime/Value.h

@@ -57,6 +57,13 @@ public:
 
 
     bool is_nan() const { return is_number() && __builtin_isnan(as_double()); }
     bool is_nan() const { return is_number() && __builtin_isnan(as_double()); }
     bool is_infinity() const { return is_number() && __builtin_isinf(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()
     Value()
         : m_type(Type::Empty)
         : m_type(Type::Empty)

+ 63 - 0
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);
+}

+ 0 - 0
Libraries/LibJS/Tests/binary-bitwise-operators-basic.js → Libraries/LibJS/Tests/binary-bitwise-or.js