mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-02 00:01:16 +00:00
commit
ef4bb5e124
6 changed files with 272 additions and 24 deletions
|
@ -204,6 +204,8 @@ macro_rules! int_intrinsic {
|
|||
($name:literal) => {{
|
||||
let mut output = IntrinsicName::default();
|
||||
|
||||
// These are LLVM types which don't include
|
||||
// u64 for example
|
||||
output.options[4] = concat!($name, ".i8");
|
||||
output.options[5] = concat!($name, ".i16");
|
||||
output.options[6] = concat!($name, ".i32");
|
||||
|
|
|
@ -5321,13 +5321,15 @@ fn run_low_level<'a, 'ctx, 'env>(
|
|||
|
||||
let (string, _string_layout) = load_symbol_and_layout(scope, &args[0]);
|
||||
|
||||
if let Layout::Struct(struct_layout) = layout {
|
||||
let number_layout = match layout {
|
||||
Layout::Struct(fields) => fields[0], // TODO: why is it sometimes a struct?
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
// match on the return layout to figure out which zig builtin we need
|
||||
let intrinsic = match struct_layout[0] {
|
||||
let intrinsic = match number_layout {
|
||||
Layout::Builtin(Builtin::Int(int_width)) => &bitcode::STR_TO_INT[int_width],
|
||||
Layout::Builtin(Builtin::Float(float_width)) => {
|
||||
&bitcode::STR_TO_FLOAT[float_width]
|
||||
}
|
||||
Layout::Builtin(Builtin::Float(float_width)) => &bitcode::STR_TO_FLOAT[float_width],
|
||||
Layout::Builtin(Builtin::Decimal) => bitcode::DEC_FROM_STR,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
@ -5336,9 +5338,6 @@ fn run_low_level<'a, 'ctx, 'env>(
|
|||
complex_bitcast(env.builder, string, env.str_list_c_abi().into(), "to_utf8");
|
||||
|
||||
call_bitcode_fn(env, &[string], intrinsic)
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
StrFromInt => {
|
||||
// Str.fromInt : Int -> Str
|
||||
|
|
|
@ -599,6 +599,7 @@ impl<'a> WasmBackend<'a> {
|
|||
arguments,
|
||||
*sym,
|
||||
wasm_layout,
|
||||
layout,
|
||||
storage,
|
||||
);
|
||||
}
|
||||
|
@ -636,7 +637,7 @@ impl<'a> WasmBackend<'a> {
|
|||
}
|
||||
|
||||
CallType::LowLevel { op: lowlevel, .. } => {
|
||||
self.build_low_level(*lowlevel, arguments, *sym, wasm_layout, storage)
|
||||
self.build_low_level(*lowlevel, arguments, *sym, wasm_layout, layout, storage)
|
||||
}
|
||||
|
||||
x => todo!("call type {:?}", x),
|
||||
|
@ -1066,14 +1067,20 @@ impl<'a> WasmBackend<'a> {
|
|||
arguments: &'a [Symbol],
|
||||
return_sym: Symbol,
|
||||
return_layout: WasmLayout,
|
||||
mono_layout: &Layout<'a>,
|
||||
storage: &StoredValue,
|
||||
) {
|
||||
use LowLevel::*;
|
||||
|
||||
match lowlevel {
|
||||
Eq | NotEq => {
|
||||
self.build_eq_or_neq(lowlevel, arguments, return_sym, return_layout, storage)
|
||||
}
|
||||
Eq | NotEq => self.build_eq_or_neq(
|
||||
lowlevel,
|
||||
arguments,
|
||||
return_sym,
|
||||
return_layout,
|
||||
mono_layout,
|
||||
storage,
|
||||
),
|
||||
PtrCast => {
|
||||
// Don't want Zig calling convention when casting pointers.
|
||||
self.storage.load_symbols(&mut self.code_builder, arguments);
|
||||
|
@ -1099,6 +1106,7 @@ impl<'a> WasmBackend<'a> {
|
|||
lowlevel,
|
||||
arguments,
|
||||
&return_layout,
|
||||
mono_layout,
|
||||
);
|
||||
|
||||
// Handle the result
|
||||
|
@ -1122,6 +1130,7 @@ impl<'a> WasmBackend<'a> {
|
|||
arguments: &'a [Symbol],
|
||||
return_sym: Symbol,
|
||||
return_layout: WasmLayout,
|
||||
mono_layout: &Layout<'a>,
|
||||
storage: &StoredValue,
|
||||
) {
|
||||
let arg_layout = self.storage.symbol_layouts[&arguments[0]];
|
||||
|
@ -1134,7 +1143,7 @@ impl<'a> WasmBackend<'a> {
|
|||
match arg_layout {
|
||||
Layout::Builtin(
|
||||
Builtin::Int(_) | Builtin::Float(_) | Builtin::Bool | Builtin::Decimal,
|
||||
) => self.build_eq_or_neq_number(lowlevel, arguments, return_layout),
|
||||
) => self.build_eq_or_neq_number(lowlevel, arguments, return_layout, mono_layout),
|
||||
|
||||
Layout::Builtin(Builtin::Str) => {
|
||||
let (param_types, ret_type) = self.storage.load_symbols_for_call(
|
||||
|
@ -1189,6 +1198,7 @@ impl<'a> WasmBackend<'a> {
|
|||
lowlevel: LowLevel,
|
||||
arguments: &'a [Symbol],
|
||||
return_layout: WasmLayout,
|
||||
mono_layout: &Layout<'a>,
|
||||
) {
|
||||
use StoredValue::*;
|
||||
match self.storage.get(&arguments[0]).to_owned() {
|
||||
|
@ -1220,7 +1230,13 @@ impl<'a> WasmBackend<'a> {
|
|||
..
|
||||
} = self.storage.get(&arguments[1]).to_owned()
|
||||
{
|
||||
self.build_eq_num128(format, [location0, location1], arguments, return_layout);
|
||||
self.build_eq_num128(
|
||||
format,
|
||||
[location0, location1],
|
||||
arguments,
|
||||
return_layout,
|
||||
mono_layout,
|
||||
);
|
||||
if matches!(lowlevel, LowLevel::NotEq) {
|
||||
self.code_builder.i32_eqz();
|
||||
}
|
||||
|
@ -1235,6 +1251,7 @@ impl<'a> WasmBackend<'a> {
|
|||
locations: [StackMemoryLocation; 2],
|
||||
arguments: &'a [Symbol],
|
||||
return_layout: WasmLayout,
|
||||
mono_layout: &Layout<'a>,
|
||||
) {
|
||||
match format {
|
||||
StackMemoryFormat::Decimal => {
|
||||
|
@ -1247,6 +1264,7 @@ impl<'a> WasmBackend<'a> {
|
|||
LowLevel::NumIsFinite,
|
||||
&first,
|
||||
&return_layout,
|
||||
mono_layout,
|
||||
);
|
||||
dispatch_low_level(
|
||||
&mut self.code_builder,
|
||||
|
@ -1254,6 +1272,7 @@ impl<'a> WasmBackend<'a> {
|
|||
LowLevel::NumIsFinite,
|
||||
&second,
|
||||
&return_layout,
|
||||
mono_layout,
|
||||
);
|
||||
self.code_builder.i32_and();
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use roc_builtins::bitcode::{self, FloatWidth};
|
||||
use roc_module::low_level::{LowLevel, LowLevel::*};
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_mono::layout::{Builtin, Layout};
|
||||
use roc_reporting::internal_error;
|
||||
|
||||
use crate::layout::{StackMemoryFormat::*, WasmLayout};
|
||||
|
@ -20,6 +21,7 @@ pub fn dispatch_low_level<'a>(
|
|||
lowlevel: LowLevel,
|
||||
args: &[Symbol],
|
||||
ret_layout: &WasmLayout,
|
||||
mono_layout: &Layout<'a>,
|
||||
) -> LowlevelBuildResult {
|
||||
use LowlevelBuildResult::*;
|
||||
|
||||
|
@ -46,7 +48,21 @@ pub fn dispatch_low_level<'a>(
|
|||
return NotImplemented;
|
||||
}
|
||||
StrCountGraphemes => return BuiltinCall(bitcode::STR_COUNT_GRAPEHEME_CLUSTERS),
|
||||
StrToNum => return NotImplemented, // choose builtin based on storage size
|
||||
StrToNum => {
|
||||
let number_layout = match mono_layout {
|
||||
Layout::Struct(fields) => fields[0],
|
||||
_ => internal_error!("Unexpected mono layout {:?} for StrToNum", mono_layout),
|
||||
};
|
||||
// match on the return layout to figure out which zig builtin we need
|
||||
let intrinsic = match number_layout {
|
||||
Layout::Builtin(Builtin::Int(int_width)) => &bitcode::STR_TO_INT[int_width],
|
||||
Layout::Builtin(Builtin::Float(float_width)) => &bitcode::STR_TO_FLOAT[float_width],
|
||||
Layout::Builtin(Builtin::Decimal) => bitcode::DEC_FROM_STR,
|
||||
rest => internal_error!("Unexpected builtin {:?} for StrToNum", rest),
|
||||
};
|
||||
|
||||
return BuiltinCall(intrinsic);
|
||||
}
|
||||
StrFromInt => {
|
||||
// This does not get exposed in user space. We switched to NumToStr instead.
|
||||
// We can probably just leave this as NotImplemented. We may want remove this LowLevel.
|
||||
|
|
|
@ -114,7 +114,7 @@ wasm_test_result_primitive!(u64, i64_store, Align::Bytes8);
|
|||
wasm_test_result_primitive!(i64, i64_store, Align::Bytes8);
|
||||
wasm_test_result_primitive!(usize, i32_store, Align::Bytes4);
|
||||
|
||||
wasm_test_result_primitive!(f32, f32_store, Align::Bytes8);
|
||||
wasm_test_result_primitive!(f32, f32_store, Align::Bytes4);
|
||||
wasm_test_result_primitive!(f64, f64_store, Align::Bytes8);
|
||||
|
||||
wasm_test_result_stack_memory!(u128);
|
||||
|
|
|
@ -1121,3 +1121,215 @@ fn str_trim_right_small_to_small_shared() {
|
|||
(RocStr, RocStr)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn str_to_nat() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
when Str.toNat "1" is
|
||||
Ok n -> n
|
||||
Err _ -> 0
|
||||
"#
|
||||
),
|
||||
1,
|
||||
usize
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn str_to_i128() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
when Str.toI128 "1" is
|
||||
Ok n -> n
|
||||
Err _ -> 0
|
||||
"#
|
||||
),
|
||||
1,
|
||||
i128
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn str_to_u128() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
when Str.toU128 "1" is
|
||||
Ok n -> n
|
||||
Err _ -> 0
|
||||
"#
|
||||
),
|
||||
1,
|
||||
u128
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn str_to_i64() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
when Str.toI64 "1" is
|
||||
Ok n -> n
|
||||
Err _ -> 0
|
||||
"#
|
||||
),
|
||||
1,
|
||||
i64
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn str_to_u64() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
when Str.toU64 "1" is
|
||||
Ok n -> n
|
||||
Err _ -> 0
|
||||
"#
|
||||
),
|
||||
1,
|
||||
u64
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn str_to_i32() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
when Str.toI32 "1" is
|
||||
Ok n -> n
|
||||
Err _ -> 0
|
||||
"#
|
||||
),
|
||||
1,
|
||||
i32
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn str_to_u32() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
when Str.toU32 "1" is
|
||||
Ok n -> n
|
||||
Err _ -> 0
|
||||
"#
|
||||
),
|
||||
1,
|
||||
u32
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn str_to_i16() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
when Str.toI16 "1" is
|
||||
Ok n -> n
|
||||
Err _ -> 0
|
||||
"#
|
||||
),
|
||||
1,
|
||||
i16
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn str_to_u16() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
when Str.toU16 "1" is
|
||||
Ok n -> n
|
||||
Err _ -> 0
|
||||
"#
|
||||
),
|
||||
1,
|
||||
u16
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn str_to_i8() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
when Str.toI8 "1" is
|
||||
Ok n -> n
|
||||
Err _ -> 0
|
||||
"#
|
||||
),
|
||||
1,
|
||||
i8
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn str_to_u8() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
when Str.toU8 "1" is
|
||||
Ok n -> n
|
||||
Err _ -> 0
|
||||
"#
|
||||
),
|
||||
1,
|
||||
u8
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn str_to_f64() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
when Str.toF64 "1.0" is
|
||||
Ok n -> n
|
||||
Err _ -> 0
|
||||
"#
|
||||
),
|
||||
1.0,
|
||||
f64
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn str_to_f32() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
when Str.toF32 "1.0" is
|
||||
Ok n -> n
|
||||
Err _ -> 0
|
||||
"#
|
||||
),
|
||||
1.0,
|
||||
f32
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn str_to_dec() {
|
||||
use roc_std::RocDec;
|
||||
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
when Str.toDec "1.0" is
|
||||
Ok n -> n
|
||||
Err _ -> 0
|
||||
"#
|
||||
),
|
||||
RocDec::from_str("1.0").unwrap(),
|
||||
RocDec
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue