LibJS: Implement bitwise left shift operator (<<)

This commit is contained in:
Linus Groh 2020-04-23 13:36:14 +01:00 committed by Andreas Kling
parent 97366f4dd4
commit f0e7404480
Notes: sideshowbarker 2024-07-19 07:21:43 +09:00
7 changed files with 95 additions and 1 deletions

View file

@ -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);

View file

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

View file

@ -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;

View file

@ -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)

View file

@ -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)

View file

@ -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);
}