mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-28 06:14:46 +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.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
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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";
|
||||||
|
|
|
@ -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,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue