mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-04-21 20:15:17 +00:00
LibJS: Add new bitwise and relational operators
Do note that when it comes to evaluating binary expressions, we are asserting in multiple contexts that the values we're operating on are numbers, we should probably handle other value types to be more tolerant in the future, since for example, adding a number and a string, in which case the number is converted to a string implicitly which is then concatenated, although ugly, is valid javascript.
This commit is contained in:
parent
11aac6fdce
commit
65343388b8
Notes:
sideshowbarker
2024-07-19 08:48:57 +09:00
Author: https://github.com/0xtechnobabble Commit: https://github.com/SerenityOS/serenity/commit/65343388b84 Pull-request: https://github.com/SerenityOS/serenity/pull/1397 Reviewed-by: https://github.com/sunverwerth
2 changed files with 152 additions and 0 deletions
|
@ -118,6 +118,61 @@ const Value typed_eq(const Value lhs, const Value rhs)
|
|||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
Value greater(Value lhs, Value rhs)
|
||||
{
|
||||
ASSERT(lhs.is_number());
|
||||
ASSERT(rhs.is_number());
|
||||
return Value(lhs.as_double() > rhs.as_double());
|
||||
}
|
||||
|
||||
Value smaller(Value lhs, Value rhs)
|
||||
{
|
||||
ASSERT(lhs.is_number());
|
||||
ASSERT(rhs.is_number());
|
||||
return Value(lhs.as_double() < rhs.as_double());
|
||||
}
|
||||
|
||||
Value bit_and(Value lhs, Value rhs)
|
||||
{
|
||||
ASSERT(lhs.is_number());
|
||||
ASSERT(rhs.is_number());
|
||||
return Value((i32)lhs.as_double() & (i32)rhs.as_double());
|
||||
}
|
||||
|
||||
Value bit_or(Value lhs, Value rhs)
|
||||
{
|
||||
ASSERT(lhs.is_number());
|
||||
ASSERT(rhs.is_number());
|
||||
return Value((i32)lhs.as_double() | (i32)rhs.as_double());
|
||||
}
|
||||
|
||||
Value bit_xor(Value lhs, Value rhs)
|
||||
{
|
||||
ASSERT(lhs.is_number());
|
||||
ASSERT(rhs.is_number());
|
||||
return Value((i32)lhs.as_double() ^ (i32)rhs.as_double());
|
||||
}
|
||||
|
||||
Value bit_not(Value lhs)
|
||||
{
|
||||
ASSERT(lhs.is_number());
|
||||
return Value(~(i32)lhs.as_double());
|
||||
}
|
||||
|
||||
Value bit_left(Value lhs, Value rhs)
|
||||
{
|
||||
ASSERT(lhs.is_number());
|
||||
ASSERT(rhs.is_number());
|
||||
return Value((i32)lhs.as_double() << (i32)rhs.as_double());
|
||||
}
|
||||
|
||||
Value bit_right(Value lhs, Value rhs)
|
||||
{
|
||||
ASSERT(lhs.is_number());
|
||||
ASSERT(rhs.is_number());
|
||||
return Value((i32)lhs.as_double() >> (i32)rhs.as_double());
|
||||
}
|
||||
|
||||
Value BinaryExpression::execute(Interpreter& interpreter) const
|
||||
{
|
||||
auto lhs_result = m_lhs->execute(interpreter);
|
||||
|
@ -130,6 +185,22 @@ Value BinaryExpression::execute(Interpreter& interpreter) const
|
|||
return sub(lhs_result, rhs_result);
|
||||
case BinaryOp::TypedEquals:
|
||||
return typed_eq(lhs_result, rhs_result);
|
||||
case BinaryOp::TypedInequals:
|
||||
return Value(!typed_eq(lhs_result, rhs_result).as_bool());
|
||||
case BinaryOp::Greater:
|
||||
return greater(lhs_result, rhs_result);
|
||||
case BinaryOp::Smaller:
|
||||
return smaller(lhs_result, rhs_result);
|
||||
case BinaryOp::BitAnd:
|
||||
return bit_and(lhs_result, rhs_result);
|
||||
case BinaryOp::BitOr:
|
||||
return bit_or(lhs_result, rhs_result);
|
||||
case BinaryOp::BitXor:
|
||||
return bit_xor(lhs_result, rhs_result);
|
||||
case BinaryOp::BitLeftShift:
|
||||
return bit_left(lhs_result, rhs_result);
|
||||
case BinaryOp::BitRightShift:
|
||||
return bit_right(lhs_result, rhs_result);
|
||||
}
|
||||
|
||||
ASSERT_NOT_REACHED();
|
||||
|
@ -155,6 +226,17 @@ Value LogicalExpression::execute(Interpreter& interpreter) const
|
|||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
Value UnaryExpression::execute(Interpreter& interpreter) const
|
||||
{
|
||||
auto lhs_result = m_lhs->execute(interpreter);
|
||||
switch (m_op) {
|
||||
case UnaryOp::BitNot:
|
||||
return bit_not(lhs_result);
|
||||
}
|
||||
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
static void print_indent(int indent)
|
||||
{
|
||||
for (int i = 0; i < indent * 2; ++i)
|
||||
|
@ -187,6 +269,30 @@ void BinaryExpression::dump(int indent) const
|
|||
case BinaryOp::TypedEquals:
|
||||
op_string = "===";
|
||||
break;
|
||||
case BinaryOp::TypedInequals:
|
||||
op_string = "!==";
|
||||
break;
|
||||
case BinaryOp::Greater:
|
||||
op_string = ">";
|
||||
break;
|
||||
case BinaryOp::Smaller:
|
||||
op_string = "<";
|
||||
break;
|
||||
case BinaryOp::BitAnd:
|
||||
op_string = "&";
|
||||
break;
|
||||
case BinaryOp::BitOr:
|
||||
op_string = "|";
|
||||
break;
|
||||
case BinaryOp::BitXor:
|
||||
op_string = "^";
|
||||
break;
|
||||
case BinaryOp::BitLeftShift:
|
||||
op_string = "<<";
|
||||
break;
|
||||
case BinaryOp::BitRightShift:
|
||||
op_string = ">>";
|
||||
break;
|
||||
}
|
||||
|
||||
print_indent(indent);
|
||||
|
@ -225,6 +331,22 @@ void LogicalExpression::dump(int indent) const
|
|||
m_rhs->dump(indent + 1);
|
||||
}
|
||||
|
||||
void UnaryExpression::dump(int indent) const
|
||||
{
|
||||
const char* op_string = nullptr;
|
||||
switch (m_op) {
|
||||
case UnaryOp::BitNot:
|
||||
op_string = "~";
|
||||
break;
|
||||
}
|
||||
|
||||
print_indent(indent);
|
||||
printf("%s\n", class_name());
|
||||
print_indent(indent + 1);
|
||||
printf("%s\n", op_string);
|
||||
m_lhs->dump(indent + 1);
|
||||
}
|
||||
|
||||
void CallExpression::dump(int indent) const
|
||||
{
|
||||
print_indent(indent);
|
||||
|
|
|
@ -176,6 +176,14 @@ enum class BinaryOp {
|
|||
Plus,
|
||||
Minus,
|
||||
TypedEquals,
|
||||
TypedInequals,
|
||||
Greater,
|
||||
Smaller,
|
||||
BitAnd,
|
||||
BitOr,
|
||||
BitXor,
|
||||
BitLeftShift,
|
||||
BitRightShift,
|
||||
};
|
||||
|
||||
class BinaryExpression : public Expression {
|
||||
|
@ -231,6 +239,28 @@ private:
|
|||
OwnPtr<Expression> m_rhs;
|
||||
};
|
||||
|
||||
enum class UnaryOp {
|
||||
BitNot,
|
||||
};
|
||||
|
||||
class UnaryExpression : public Expression {
|
||||
public:
|
||||
UnaryExpression(UnaryOp op, NonnullOwnPtr<Expression> lhs)
|
||||
: m_op(op)
|
||||
, m_lhs(move(lhs))
|
||||
{
|
||||
}
|
||||
|
||||
virtual Value execute(Interpreter&) const override;
|
||||
virtual void dump(int indent) const override;
|
||||
|
||||
private:
|
||||
virtual const char* class_name() const override { return "UnaryExpression"; }
|
||||
|
||||
UnaryOp m_op;
|
||||
NonnullOwnPtr<Expression> m_lhs;
|
||||
};
|
||||
|
||||
class Literal : public Expression {
|
||||
public:
|
||||
explicit Literal(Value value)
|
||||
|
|
Loading…
Add table
Reference in a new issue