diff --git a/Libraries/LibJS/AST.cpp b/Libraries/LibJS/AST.cpp index 38e44e1edb..763c799170 100644 --- a/Libraries/LibJS/AST.cpp +++ b/Libraries/LibJS/AST.cpp @@ -279,17 +279,21 @@ Value BinaryExpression::execute(Interpreter& interpreter) const Value LogicalExpression::execute(Interpreter& interpreter) const { - auto lhs_result = m_lhs->execute(interpreter).to_boolean(); + auto lhs_result = m_lhs->execute(interpreter); if (interpreter.exception()) return {}; - auto rhs_result = m_rhs->execute(interpreter).to_boolean(); + auto rhs_result = m_rhs->execute(interpreter); if (interpreter.exception()) return {}; switch (m_op) { case LogicalOp::And: - return Value(lhs_result && rhs_result); + if (lhs_result.to_boolean()) + return Value(rhs_result); + return Value(lhs_result); case LogicalOp::Or: - return Value(lhs_result || rhs_result); + if (lhs_result.to_boolean()) + return Value(lhs_result); + return Value(rhs_result); } ASSERT_NOT_REACHED(); diff --git a/Libraries/LibJS/Parser.cpp b/Libraries/LibJS/Parser.cpp index a212969c02..d9d1cbd7a4 100644 --- a/Libraries/LibJS/Parser.cpp +++ b/Libraries/LibJS/Parser.cpp @@ -889,7 +889,9 @@ bool Parser::match_secondary_expression() const || type == TokenType::QuestionMark || type == TokenType::Ampersand || type == TokenType::Pipe - || type == TokenType::Caret; + || type == TokenType::Caret + || type == TokenType::DoubleAmpersand + || type == TokenType::DoublePipe; } bool Parser::match_statement() const diff --git a/Libraries/LibJS/Tests/logical-expressions-basic.js b/Libraries/LibJS/Tests/logical-expressions-basic.js new file mode 100644 index 0000000000..58d05e1111 --- /dev/null +++ b/Libraries/LibJS/Tests/logical-expressions-basic.js @@ -0,0 +1,83 @@ +function assert(x) { if (!x) throw 1; } + +try { + assert((true && true) === true); + assert((false && false) === false); + assert((true && false) === false); + assert((false && true) === false); + assert((false && (1 === 2)) === false); + assert((true && (1 === 2)) === false); + assert(("" && "") === ""); + assert(("" && false) === ""); + assert(("" && true) === ""); + assert((false && "") === false); + assert((true && "") === ""); + assert(("foo" && "bar") === "bar"); + assert(("foo" && false) === false); + assert(("foo" && true) === true); + assert((false && "bar") === false); + assert((true && "bar") === "bar"); + assert((null && true) === null); + assert((0 && false) === 0); + assert((0 && true) === 0); + assert((42 && false) === false); + assert((42 && true) === true); + assert((false && 0) === false); + assert((true && 0) === 0); + assert((false && 42) === false); + assert((true && 42) === 42); + assert(([] && false) === false); + assert(([] && true) === true); + assert((false && []) === false); + assert((true && []).length === 0); + assert((null && false) === null); + assert((null && true) === null); + assert((false && null) === false); + assert((true && null) === null); + assert((undefined && false) === undefined); + assert((undefined && true) === undefined); + assert((false && undefined) === false); + assert((true && undefined) === undefined); + + assert((true || true) === true); + assert((false || false) === false); + assert((true || false) === true); + assert((false || true) === true); + assert((false || (1 === 2)) === false); + assert((true || (1 === 2)) === true); + assert(("" || "") === ""); + assert(("" || false) === false); + assert(("" || true) === true); + assert((false || "") === ""); + assert((true || "") === true); + assert(("foo" || "bar") === "foo"); + assert(("foo" || false) === "foo"); + assert(("foo" || true) === "foo"); + assert((false || "bar") === "bar"); + assert((true || "bar") === true); + assert((null || true) === true); + assert((0 || false) === false); + assert((0 || true) === true); + assert((42 || false) === 42); + assert((42 || true) === 42); + assert((false || 0) === 0); + assert((true || 0) === true); + assert((false || 42) === 42); + assert((true || 42) === true); + assert(([] || false).length === 0); + assert(([] || true).length === 0); + assert((false || []).length === 0); + assert((true || []) === true); + assert((null || false) === false); + assert((null || true) === true); + assert((false || null) === null); + assert((true || null) === true); + assert((undefined || false) === false); + assert((undefined || true) === true); + assert((false || undefined) === undefined); + assert((true || undefined) === true); + + console.log("PASS"); +} catch (e) { + console.log("FAIL: " + e); +}