feat: switch to using a builtin per num type to convert from a string

This commit is contained in:
rvcas 2021-12-06 22:24:00 -05:00
parent bc5b1abcba
commit e587e20de2
6 changed files with 122 additions and 25 deletions

View file

@ -3,9 +3,9 @@ use roc_module::ident::TagName;
use roc_module::symbol::Symbol; use roc_module::symbol::Symbol;
use roc_region::all::Region; use roc_region::all::Region;
use roc_types::builtin_aliases::{ use roc_types::builtin_aliases::{
bool_type, dict_type, float_type, i128_type, int_type, list_type, nat_type, num_type, bool_type, dec_type, dict_type, f32_type, f64_type, float_type, i128_type, int_type, list_type,
ordering_type, result_type, set_type, str_type, str_utf8_byte_problem_type, u16_type, u32_type, nat_type, num_type, ordering_type, result_type, set_type, str_type, str_utf8_byte_problem_type,
u8_type, u16_type, u32_type, u64_type, u8_type,
}; };
use roc_types::solved_types::SolvedType; use roc_types::solved_types::SolvedType;
use roc_types::subs::VarId; use roc_types::subs::VarId;
@ -702,16 +702,52 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
Box::new(list_type(u8_type())) Box::new(list_type(u8_type()))
); );
// toNum : Str -> Result (Num a) {} // toNum : Str -> Result (Num a) [ InvalidNumStr ]
let invalid_str = SolvedType::TagUnion( // Because toNum doesn't work with floats & decimals by default without
// a point of usage to be able to infer the proper layout
// we decided that separate functions for each sub num type
// is the best approach. These below all end up mapping to
// `str_to_num` in can `builtins.rs`
let invalid_str = || {
SolvedType::TagUnion(
vec![(TagName::Global("InvalidNumStr".into()), vec![])], vec![(TagName::Global("InvalidNumStr".into()), vec![])],
Box::new(SolvedType::Wildcard), Box::new(SolvedType::Wildcard),
)
};
// toDec : Str -> Result Dec [ InvalidNumStr ]
add_top_level_function_type!(
Symbol::STR_TO_DEC,
vec![str_type()],
Box::new(result_type(dec_type(), invalid_str()))
); );
// toF64 : Str -> Result F64 [ InvalidNumStr ]
add_top_level_function_type!( add_top_level_function_type!(
Symbol::STR_TO_NUM, Symbol::STR_TO_F64,
vec![str_type()], vec![str_type()],
Box::new(result_type(num_type(flex(TVAR1)), invalid_str)) Box::new(result_type(f64_type(), invalid_str()))
);
// toF32 : Str -> Result F32 [ InvalidNumStr ]
add_top_level_function_type!(
Symbol::STR_TO_F32,
vec![str_type()],
Box::new(result_type(f32_type(), invalid_str()))
);
// toNat : Str -> Result Nat [ InvalidNumStr ]
add_top_level_function_type!(
Symbol::STR_TO_NAT,
vec![str_type()],
Box::new(result_type(nat_type(), invalid_str()))
);
// toU64 : Str -> Result U64 [ InvalidNumStr ]
add_top_level_function_type!(
Symbol::STR_TO_U64,
vec![str_type()],
Box::new(result_type(u64_type(), invalid_str()))
); );
// List module // List module

View file

@ -68,7 +68,11 @@ pub fn builtin_defs_map(symbol: Symbol, var_store: &mut VarStore) -> Option<Def>
STR_TRIM => str_trim, STR_TRIM => str_trim,
STR_TRIM_LEFT => str_trim_left, STR_TRIM_LEFT => str_trim_left,
STR_TRIM_RIGHT => str_trim_right, STR_TRIM_RIGHT => str_trim_right,
STR_TO_NUM => str_to_num, STR_TO_DEC => str_to_num,
STR_TO_F64 => str_to_num,
STR_TO_F32 => str_to_num,
STR_TO_NAT => str_to_num,
STR_TO_U64 => str_to_num,
LIST_LEN => list_len, LIST_LEN => list_len,
LIST_GET => list_get, LIST_GET => list_get,
LIST_SET => list_set, LIST_SET => list_set,

View file

@ -195,7 +195,11 @@ impl LowLevel {
Symbol::STR_TRIM => Some(StrTrim), Symbol::STR_TRIM => Some(StrTrim),
Symbol::STR_TRIM_LEFT => Some(StrTrimLeft), Symbol::STR_TRIM_LEFT => Some(StrTrimLeft),
Symbol::STR_TRIM_RIGHT => Some(StrTrimRight), Symbol::STR_TRIM_RIGHT => Some(StrTrimRight),
Symbol::STR_TO_NUM => Some(StrToNum), Symbol::STR_TO_DEC => Some(StrToNum),
Symbol::STR_TO_F64 => Some(StrToNum),
Symbol::STR_TO_F32 => Some(StrToNum),
Symbol::STR_TO_NAT => Some(StrToNum),
Symbol::STR_TO_U64 => Some(StrToNum),
Symbol::LIST_LEN => Some(ListLen), Symbol::LIST_LEN => Some(ListLen),
Symbol::LIST_GET => None, Symbol::LIST_GET => None,
Symbol::LIST_SET => None, Symbol::LIST_SET => None,

View file

@ -1029,7 +1029,12 @@ define_builtins! {
18 STR_TRIM: "trim" 18 STR_TRIM: "trim"
19 STR_TRIM_LEFT: "trimLeft" 19 STR_TRIM_LEFT: "trimLeft"
20 STR_TRIM_RIGHT: "trimRight" 20 STR_TRIM_RIGHT: "trimRight"
21 STR_TO_NUM: "toNum" 21 STR_TO_DEC: "toDec"
22 STR_TO_F64: "toF64"
23 STR_TO_F32: "toF32"
24 STR_TO_NAT: "toNat"
25 STR_TO_U64: "toU64"
} }
4 LIST: "List" => { 4 LIST: "List" => {
0 LIST_LIST: "List" imported // the List.List type alias 0 LIST_LIST: "List" imported // the List.List type alias

View file

@ -1300,56 +1300,53 @@ fn str_trim_right_small_to_small_shared() {
#[test] #[test]
#[cfg(any(feature = "gen-llvm"))] #[cfg(any(feature = "gen-llvm"))]
fn str_to_num() { fn str_to_nat() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r#"
when Str.toNum "1" is when Str.toNat "1" is
Ok n -> n Ok n -> n
Err _ -> 0 Err _ -> 0
"# "#
), ),
1, 1,
i64 usize
); );
} }
#[test] #[test]
#[cfg(any(feature = "gen-llvm"))] #[cfg(any(feature = "gen-llvm"))]
fn str_to_num_float() { fn str_to_f64() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r#"
when Str.toNum "1.0" is when Str.toF64 "1.0" is
Ok n -> n + 2.0 Ok n -> n
Err _ -> 0 Err _ -> 0
"# "#
), ),
3.0, 1.0,
f64 f64
); );
} }
#[test] #[test]
#[cfg(any(feature = "gen-llvm"))] #[cfg(any(feature = "gen-llvm"))]
fn str_to_num_dec() { fn str_to_dec() {
use roc_std::RocDec; use roc_std::RocDec;
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r#"
x : Dec when Str.toDec "1.0" is
x = 2.0
when Str.toNum "1.0" is
Ok n -> n + x Ok n -> n + x
Err _ -> 0 Err _ -> 0
"# "#
), ),
RocDec::from_str("3.0").unwrap(), RocDec::from_str("1.0").unwrap(),
RocDec RocDec
); );
} }

View file

@ -409,6 +409,40 @@ fn float_alias_content(range: SolvedType) -> SolvedType {
num_type(floatingpoint_type(range)) num_type(floatingpoint_type(range))
} }
// F64
#[inline(always)]
pub fn f64_type() -> SolvedType {
SolvedType::Alias(
Symbol::NUM_F64,
vec![],
vec![],
Box::new(f64_alias_content()),
)
}
#[inline(always)]
fn f64_alias_content() -> SolvedType {
float_alias_content(binary64_type())
}
// F32
#[inline(always)]
pub fn f32_type() -> SolvedType {
SolvedType::Alias(
Symbol::NUM_F32,
vec![],
vec![],
Box::new(f32_alias_content()),
)
}
#[inline(always)]
fn f32_alias_content() -> SolvedType {
float_alias_content(binary32_type())
}
// Nat // Nat
#[inline(always)] #[inline(always)]
@ -731,6 +765,23 @@ fn decimal_alias_content() -> SolvedType {
single_private_tag(Symbol::NUM_AT_DECIMAL, vec![]) single_private_tag(Symbol::NUM_AT_DECIMAL, vec![])
} }
// Dec
#[inline(always)]
pub fn dec_type() -> SolvedType {
SolvedType::Alias(
Symbol::NUM_DEC,
vec![],
vec![],
Box::new(dec_alias_content()),
)
}
#[inline(always)]
fn dec_alias_content() -> SolvedType {
float_alias_content(decimal_type())
}
#[inline(always)] #[inline(always)]
pub fn decimal_type() -> SolvedType { pub fn decimal_type() -> SolvedType {
SolvedType::Alias( SolvedType::Alias(