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.strNumberOfBytes, "number_of_bytes");
exportStrFn(str.strFromIntC, "from_int");
exportStrFn(str.strEqual, "equal");
}
// 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
pub fn strNumberOfBytes(string: RocStr) callconv(.C) usize {
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_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";

View file

@ -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,
)
}

View file

@ -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);
}

View file

@ -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() {

View file

@ -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);
}
}