mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-27 22:09:09 +00:00
add equality for strings
This commit is contained in:
parent
3e1d6d0965
commit
2ac19fb6e3
7 changed files with 84 additions and 20 deletions
|
@ -23,6 +23,7 @@ comptime {
|
|||
exportStrFn(str.strConcatC, "concat");
|
||||
exportStrFn(str.strNumberOfBytes, "number_of_bytes");
|
||||
exportStrFn(str.strFromIntC, "from_int");
|
||||
exportStrFn(str.strEqual, "equal");
|
||||
}
|
||||
|
||||
// Export helpers - Must be run inside a comptime
|
||||
|
|
|
@ -260,6 +260,11 @@ pub const RocStr = extern struct {
|
|||
}
|
||||
};
|
||||
|
||||
// Str.equal
|
||||
pub fn strEqual(self: RocStr, other: RocStr) callconv(.C) bool {
|
||||
return self.eq(other);
|
||||
}
|
||||
|
||||
// Str.numberOfBytes
|
||||
pub fn strNumberOfBytes(string: RocStr) callconv(.C) usize {
|
||||
return string.len();
|
||||
|
|
|
@ -31,3 +31,4 @@ pub const STR_STARTS_WITH: &str = "roc_builtins.str.starts_with";
|
|||
pub const STR_ENDS_WITH: &str = "roc_builtins.str.ends_with";
|
||||
pub const STR_NUMBER_OF_BYTES: &str = "roc_builtins.str.number_of_bytes";
|
||||
pub const STR_FROM_INT: &str = "roc_builtins.str.from_int";
|
||||
pub const STR_EQUAL: &str = "roc_builtins.str.equal";
|
||||
|
|
|
@ -77,6 +77,28 @@ fn str_symbol_to_i128<'a, 'ctx, 'env>(
|
|||
.into_int_value()
|
||||
}
|
||||
|
||||
fn str_to_i128<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
value: BasicValueEnum<'ctx>,
|
||||
) -> IntValue<'ctx> {
|
||||
let cell = env.builder.build_alloca(value.get_type(), "cell");
|
||||
|
||||
env.builder.build_store(cell, value);
|
||||
|
||||
let i128_ptr = env
|
||||
.builder
|
||||
.build_bitcast(
|
||||
cell,
|
||||
env.context.i128_type().ptr_type(AddressSpace::Generic),
|
||||
"cast",
|
||||
)
|
||||
.into_pointer_value();
|
||||
|
||||
env.builder
|
||||
.build_load(i128_ptr, "load_as_i128")
|
||||
.into_int_value()
|
||||
}
|
||||
|
||||
fn zig_str_to_struct<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
zig_str: StructValue<'ctx>,
|
||||
|
@ -222,3 +244,19 @@ pub fn str_from_int<'a, 'ctx, 'env>(
|
|||
|
||||
zig_str_to_struct(env, zig_result).into()
|
||||
}
|
||||
|
||||
/// Str.equal : Str, Str -> Bool
|
||||
pub fn str_equal<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
value1: BasicValueEnum<'ctx>,
|
||||
value2: BasicValueEnum<'ctx>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
let str1_i128 = str_to_i128(env, value1);
|
||||
let str2_i128 = str_to_i128(env, value2);
|
||||
|
||||
call_bitcode_fn(
|
||||
env,
|
||||
&[str1_i128.into(), str2_i128.into()],
|
||||
&bitcode::STR_EQUAL,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::llvm::build::Env;
|
||||
use inkwell::values::BasicValueEnum;
|
||||
use crate::llvm::build_str::str_equal;
|
||||
use inkwell::values::{BasicValueEnum, IntValue};
|
||||
use inkwell::{FloatPredicate, IntPredicate};
|
||||
use roc_mono::layout::{Builtin, Layout};
|
||||
|
||||
|
@ -43,6 +44,7 @@ pub fn build_eq<'a, 'ctx, 'env>(
|
|||
(Builtin::Int1, Builtin::Int1) => int_cmp(IntPredicate::EQ, "eq_i1"),
|
||||
(Builtin::Float64, Builtin::Float64) => float_cmp(FloatPredicate::OEQ, "eq_f64"),
|
||||
(Builtin::Float32, Builtin::Float32) => float_cmp(FloatPredicate::OEQ, "eq_f32"),
|
||||
(Builtin::Str, Builtin::Str) => str_equal(env, lhs_val, rhs_val),
|
||||
(b1, b2) => {
|
||||
todo!("Handle equals for builtin layouts {:?} == {:?}", b1, b2);
|
||||
}
|
||||
|
@ -95,6 +97,12 @@ pub fn build_neq<'a, 'ctx, 'env>(
|
|||
(Builtin::Int1, Builtin::Int1) => int_cmp(IntPredicate::NE, "neq_i1"),
|
||||
(Builtin::Float64, Builtin::Float64) => float_cmp(FloatPredicate::ONE, "neq_f64"),
|
||||
(Builtin::Float32, Builtin::Float32) => float_cmp(FloatPredicate::ONE, "neq_f32"),
|
||||
(Builtin::Str, Builtin::Str) => {
|
||||
let is_equal = str_equal(env, lhs_val, rhs_val).into_int_value();
|
||||
let result: IntValue = env.builder.build_not(is_equal, "negate");
|
||||
|
||||
result.into()
|
||||
}
|
||||
(b1, b2) => {
|
||||
todo!("Handle not equals for builtin layouts {:?} == {:?}", b1, b2);
|
||||
}
|
||||
|
|
|
@ -415,25 +415,24 @@ mod gen_list {
|
|||
);
|
||||
}
|
||||
|
||||
//
|
||||
// "panicked at 'not yet implemented: Handle equals for builtin layouts Str == Str'"
|
||||
//
|
||||
// #[test]
|
||||
// fn list_keep_if_str_is_hello() {
|
||||
// assert_evals_to!(
|
||||
// indoc!(
|
||||
// r#"
|
||||
// strIsHello : Str -> Bool
|
||||
// strIsHello = \str ->
|
||||
// str == "Hello"
|
||||
//
|
||||
// List.keepIf ["Hello", "Hello", "Goodbye"] strIsHello
|
||||
// "#
|
||||
// ),
|
||||
// RocList::from_slice(&["Hello", "Hello"]),
|
||||
// RocList<&'static str>
|
||||
// );
|
||||
// }
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn list_keep_if_str_is_hello() {
|
||||
// keepIf causes a segfault with this function
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
strIsHello : Str -> Bool
|
||||
strIsHello = \str ->
|
||||
str == "Hello"
|
||||
|
||||
List.keepIf ["Hello", "Hello", "Goodbye"] strIsHello
|
||||
"#
|
||||
),
|
||||
RocList::from_slice(&["Hello", "Hello"]),
|
||||
RocList<&'static str>
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn list_map_on_empty_list_with_int_layout() {
|
||||
|
|
|
@ -514,4 +514,16 @@ mod gen_str {
|
|||
let min = format!("{}", i64::MIN);
|
||||
assert_evals_to!(r#"Str.fromInt Num.minInt"#, &min, &'static str);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn str_equality() {
|
||||
assert_evals_to!(r#""a" == "a""#, true, bool);
|
||||
assert_evals_to!(
|
||||
r#""loremipsumdolarsitamet" == "loremipsumdolarsitamet""#,
|
||||
true,
|
||||
bool
|
||||
);
|
||||
assert_evals_to!(r#""a" != "b""#, true, bool);
|
||||
assert_evals_to!(r#""a" == "b""#, false, bool);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue