diff --git a/Libraries/LibJS/Runtime/Value.cpp b/Libraries/LibJS/Runtime/Value.cpp index c003b29485..07521777a2 100644 --- a/Libraries/LibJS/Runtime/Value.cpp +++ b/Libraries/LibJS/Runtime/Value.cpp @@ -100,6 +100,13 @@ bool Value::to_boolean() const } } +Value Value::to_primitive(Interpreter&) const +{ + if (is_object()) + return as_object().to_primitive(); + return *this; +} + Object* Value::to_object(Heap& heap) const { if (is_object()) @@ -256,10 +263,13 @@ Value right_shift(Interpreter&, Value lhs, Value rhs) Value add(Interpreter& interpreter, Value lhs, Value rhs) { - if (lhs.is_string() || rhs.is_string()) - return js_string(interpreter.heap(), String::format("%s%s", lhs.to_string().characters(), rhs.to_string().characters())); + auto lhs_primitive = lhs.to_primitive(interpreter); + auto rhs_primitive = rhs.to_primitive(interpreter); - return Value(lhs.to_number().as_double() + rhs.to_number().as_double()); + if (lhs_primitive.is_string() || rhs_primitive.is_string()) + return js_string(interpreter.heap(), String::format("%s%s", lhs_primitive.to_string().characters(), rhs_primitive.to_string().characters())); + + return Value(lhs_primitive.to_number().as_double() + rhs_primitive.to_number().as_double()); } Value sub(Interpreter&, Value lhs, Value rhs) diff --git a/Libraries/LibJS/Runtime/Value.h b/Libraries/LibJS/Runtime/Value.h index c62f5239a9..e92684f8f2 100644 --- a/Libraries/LibJS/Runtime/Value.h +++ b/Libraries/LibJS/Runtime/Value.h @@ -147,6 +147,7 @@ public: Value to_number() const; i32 to_i32() const; double to_double() const; + Value to_primitive(Interpreter&) const; Object* to_object(Heap&) const; diff --git a/Libraries/LibJS/Tests/add-values-to-primitive.js b/Libraries/LibJS/Tests/add-values-to-primitive.js new file mode 100644 index 0000000000..c42f94d4a6 --- /dev/null +++ b/Libraries/LibJS/Tests/add-values-to-primitive.js @@ -0,0 +1,12 @@ +load("test-common.js"); + +try { + // Note that these will give different results in the REPL due to parsing behavior. + assert([] + [] === ""); + assert([] + {} === "[object Object]"); + assert({} + {} === "[object Object][object Object]"); + assert({} + [] === "[object Object]"); + console.log("PASS"); +} catch (e) { + console.log("FAIL: " + e); +}