add equality for strings

This commit is contained in:
Folkert 2021-01-02 18:50:29 +01:00
parent 3e1d6d0965
commit 2ac19fb6e3
7 changed files with 84 additions and 20 deletions

View file

@ -23,6 +23,7 @@ comptime {
exportStrFn(str.strConcatC, "concat"); exportStrFn(str.strConcatC, "concat");
exportStrFn(str.strNumberOfBytes, "number_of_bytes"); exportStrFn(str.strNumberOfBytes, "number_of_bytes");
exportStrFn(str.strFromIntC, "from_int"); exportStrFn(str.strFromIntC, "from_int");
exportStrFn(str.strEqual, "equal");
} }
// Export helpers - Must be run inside a comptime // Export helpers - Must be run inside a comptime

View file

@ -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 // Str.numberOfBytes
pub fn strNumberOfBytes(string: RocStr) callconv(.C) usize { pub fn strNumberOfBytes(string: RocStr) callconv(.C) usize {
return string.len(); return string.len();

View file

@ -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_ENDS_WITH: &str = "roc_builtins.str.ends_with";
pub const STR_NUMBER_OF_BYTES: &str = "roc_builtins.str.number_of_bytes"; 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_FROM_INT: &str = "roc_builtins.str.from_int";
pub const STR_EQUAL: &str = "roc_builtins.str.equal";

View file

@ -77,6 +77,28 @@ fn str_symbol_to_i128<'a, 'ctx, 'env>(
.into_int_value() .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>( fn zig_str_to_struct<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>, env: &Env<'a, 'ctx, 'env>,
zig_str: StructValue<'ctx>, zig_str: StructValue<'ctx>,
@ -222,3 +244,19 @@ pub fn str_from_int<'a, 'ctx, 'env>(
zig_str_to_struct(env, zig_result).into() 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,
)
}

View file

@ -1,5 +1,6 @@
use crate::llvm::build::Env; 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 inkwell::{FloatPredicate, IntPredicate};
use roc_mono::layout::{Builtin, Layout}; 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::Int1, Builtin::Int1) => int_cmp(IntPredicate::EQ, "eq_i1"),
(Builtin::Float64, Builtin::Float64) => float_cmp(FloatPredicate::OEQ, "eq_f64"), (Builtin::Float64, Builtin::Float64) => float_cmp(FloatPredicate::OEQ, "eq_f64"),
(Builtin::Float32, Builtin::Float32) => float_cmp(FloatPredicate::OEQ, "eq_f32"), (Builtin::Float32, Builtin::Float32) => float_cmp(FloatPredicate::OEQ, "eq_f32"),
(Builtin::Str, Builtin::Str) => str_equal(env, lhs_val, rhs_val),
(b1, b2) => { (b1, b2) => {
todo!("Handle equals for builtin layouts {:?} == {:?}", 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::Int1, Builtin::Int1) => int_cmp(IntPredicate::NE, "neq_i1"),
(Builtin::Float64, Builtin::Float64) => float_cmp(FloatPredicate::ONE, "neq_f64"), (Builtin::Float64, Builtin::Float64) => float_cmp(FloatPredicate::ONE, "neq_f64"),
(Builtin::Float32, Builtin::Float32) => float_cmp(FloatPredicate::ONE, "neq_f32"), (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) => { (b1, b2) => {
todo!("Handle not equals for builtin layouts {:?} == {:?}", b1, b2); todo!("Handle not equals for builtin layouts {:?} == {:?}", b1, b2);
} }

View file

@ -415,25 +415,24 @@ mod gen_list {
); );
} }
// #[test]
// "panicked at 'not yet implemented: Handle equals for builtin layouts Str == Str'" #[ignore]
// fn list_keep_if_str_is_hello() {
// #[test] // keepIf causes a segfault with this function
// fn list_keep_if_str_is_hello() { assert_evals_to!(
// assert_evals_to!( indoc!(
// indoc!( r#"
// r#" strIsHello : Str -> Bool
// strIsHello : Str -> Bool strIsHello = \str ->
// strIsHello = \str -> str == "Hello"
// str == "Hello"
// List.keepIf ["Hello", "Hello", "Goodbye"] strIsHello
// List.keepIf ["Hello", "Hello", "Goodbye"] strIsHello "#
// "# ),
// ), RocList::from_slice(&["Hello", "Hello"]),
// RocList::from_slice(&["Hello", "Hello"]), RocList<&'static str>
// RocList<&'static str> );
// ); }
// }
#[test] #[test]
fn list_map_on_empty_list_with_int_layout() { fn list_map_on_empty_list_with_int_layout() {

View file

@ -514,4 +514,16 @@ mod gen_str {
let min = format!("{}", i64::MIN); let min = format!("{}", i64::MIN);
assert_evals_to!(r#"Str.fromInt Num.minInt"#, &min, &'static str); 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);
}
} }