diff --git a/src/eval/interpreter.zig b/src/eval/interpreter.zig index 39ecb9bcba..7b53a4d961 100644 --- a/src/eval/interpreter.zig +++ b/src/eval/interpreter.zig @@ -97,6 +97,7 @@ pub const EvalError = error{ StringInterpolationFailed, StringSegmentEvaluationFailed, StringConversionFailed, + StringOrderingNotSupported, UnsupportedWorkItem, UnexpectedWorkItem, RuntimeCrash, @@ -1526,8 +1527,32 @@ pub const Interpreter = struct { self.traceError("comparison operations on fractional types only support Dec precision", .{}); return error.TypeMismatch; } + } + // Check if both operands are strings + else if (lhs_scalar.tag == .str and rhs_scalar.tag == .str) { + const lhs_ptr = @as(*const RocStr, @ptrCast(@alignCast(lhs.ptr.?))); + const rhs_ptr = @as(*const RocStr, @ptrCast(@alignCast(rhs.ptr.?))); + const lhs_str = lhs_ptr.*; + const rhs_str = rhs_ptr.*; + + const result_layout = Layout.boolType(); + var result_value = try self.pushStackValue(result_layout); + + const bool_result: u8 = switch (kind) { + .w_binop_eq => if (lhs_str.eq(rhs_str)) 1 else 0, + .w_binop_ne => if (!lhs_str.eq(rhs_str)) 1 else 0, + // String ordering comparisons are not implemented yet + .w_binop_gt, .w_binop_lt, .w_binop_ge, .w_binop_le => { + self.traceError("string ordering comparisons (>, <, >=, <=) are not supported", .{}); + return error.StringOrderingNotSupported; + }, + else => unreachable, + }; + + result_value.setBool(bool_result); + self.traceInfo("String comparison: \"{s}\" {s} \"{s}\" = {}", .{ lhs_str.asSlice(), @tagName(kind), rhs_str.asSlice(), bool_result }); } else { - self.traceError("comparison operations require operands of the same type (both integers or both decimals)", .{}); + self.traceError("comparison operations require operands of the same type (both integers, both decimals, or both strings)", .{}); return error.TypeMismatch; } }, diff --git a/test/snapshots/repl/string_edge_cases.md b/test/snapshots/repl/string_edge_cases.md new file mode 100644 index 0000000000..88584883b2 --- /dev/null +++ b/test/snapshots/repl/string_edge_cases.md @@ -0,0 +1,43 @@ +# META +~~~ini +description=String comparison edge cases and longer strings +type=repl +~~~ +# SOURCE +~~~roc +» longStr1 = "This is a very long string that should test the comparison of larger strings that might not fit in small string optimization" +» longStr2 = "This is a very long string that should test the comparison of larger strings that might not fit in small string optimization" +» longStr3 = "This is a very long string that should test the comparison of larger strings that might not fit in small string optimizatioN" +» longStr1 == longStr2 +» longStr1 == longStr3 +» whitespace1 = "hello " +» whitespace2 = "hello" +» whitespace1 == whitespace2 +» specialChars1 = "hello\nworld" +» specialChars2 = "hello\nworld" +» specialChars1 == specialChars2 +~~~ +# OUTPUT +assigned `longStr1` +--- +assigned `longStr2` +--- +assigned `longStr3` +--- +True +--- +False +--- +assigned `whitespace1` +--- +assigned `whitespace2` +--- +False +--- +assigned `specialChars1` +--- +assigned `specialChars2` +--- +True +# PROBLEMS +NIL diff --git a/test/snapshots/repl/string_equality_basic.md b/test/snapshots/repl/string_equality_basic.md new file mode 100644 index 0000000000..fbf05deee3 --- /dev/null +++ b/test/snapshots/repl/string_equality_basic.md @@ -0,0 +1,31 @@ +# META +~~~ini +description=Basic string equality comparisons +type=repl +~~~ +# SOURCE +~~~roc +» "hello" == "hello" +» "hello" == "world" +» "hello" != "world" +» "hello" != "hello" +» "" == "" +» "" == "not empty" +» "same length" == "different.." +~~~ +# OUTPUT +True +--- +False +--- +True +--- +False +--- +True +--- +False +--- +False +# PROBLEMS +NIL diff --git a/test/snapshots/repl/string_interpolation_comparison.md b/test/snapshots/repl/string_interpolation_comparison.md new file mode 100644 index 0000000000..4ff2e4155e --- /dev/null +++ b/test/snapshots/repl/string_interpolation_comparison.md @@ -0,0 +1,31 @@ +# META +~~~ini +description=String interpolation and concatenation comparisons +type=repl +~~~ +# SOURCE +~~~roc +» name = "World" +» "Hello, ${name}!" == "Hello, World!" +» "Hello, ${name}!" == "Hello, Earth!" +» prefix = "Got: " +» suffix = "test" +» "${prefix}${suffix}" == "Got: test" +» "${prefix}${suffix}" != "Got: different" +~~~ +# OUTPUT +assigned `name` +--- +True +--- +False +--- +assigned `prefix` +--- +assigned `suffix` +--- +True +--- +True +# PROBLEMS +NIL diff --git a/test/snapshots/repl/string_multiline_comparison.md b/test/snapshots/repl/string_multiline_comparison.md new file mode 100644 index 0000000000..4ead87c0b6 --- /dev/null +++ b/test/snapshots/repl/string_multiline_comparison.md @@ -0,0 +1,18 @@ +# META +~~~ini +description=Simple multiline string comparison +type=repl +~~~ +# SOURCE +~~~roc +» foo = +"""first line +"""second line +» foo == "first line\nsecond line" +~~~ +# OUTPUT +assigned `foo` +--- +True +# PROBLEMS +NIL diff --git a/test/snapshots/repl/string_ordering_unsupported.md b/test/snapshots/repl/string_ordering_unsupported.md new file mode 100644 index 0000000000..40866213df --- /dev/null +++ b/test/snapshots/repl/string_ordering_unsupported.md @@ -0,0 +1,22 @@ +# META +~~~ini +description=String ordering operations should fail gracefully (not supported) +type=repl +~~~ +# SOURCE +~~~roc +» "apple" > "banana" +» "zoo" < "aardvark" +» "equal" >= "equal" +» "first" <= "second" +~~~ +# OUTPUT +Evaluation error: error.StringOrderingNotSupported +--- +Evaluation error: error.StringOrderingNotSupported +--- +Evaluation error: error.StringOrderingNotSupported +--- +Evaluation error: error.StringOrderingNotSupported +# PROBLEMS +NIL