Implement Num.toNNNChecked

Closes #2411
This commit is contained in:
ayazhafiz 2022-02-19 16:20:07 -05:00
parent d90915a8cd
commit 13067f2908
11 changed files with 531 additions and 213 deletions

View file

@ -416,108 +416,166 @@ fn num_to_i8(symbol: Symbol, var_store: &mut VarStore) -> Def {
lowlevel_1(symbol, LowLevel::NumIntCast, var_store)
}
// Num.toI8Checked : Int * -> Result I8 [ OutOfBounds ]*
fn num_to_i8_checked(symbol: Symbol, var_store: &mut VarStore) -> Def {
todo!();
}
// Num.toI16 : Int * -> I16
fn num_to_i16(symbol: Symbol, var_store: &mut VarStore) -> Def {
// Defer to IntCast
lowlevel_1(symbol, LowLevel::NumIntCast, var_store)
}
// Num.toI16Checked : Int * -> Result I16 [ OutOfBounds ]*
fn num_to_i16_checked(symbol: Symbol, var_store: &mut VarStore) -> Def {
todo!()
}
// Num.toI32 : Int * -> I32
fn num_to_i32(symbol: Symbol, var_store: &mut VarStore) -> Def {
// Defer to IntCast
lowlevel_1(symbol, LowLevel::NumIntCast, var_store)
}
// Num.toI32Checked : Int * -> Result I32 [ OutOfBounds ]*
fn num_to_i32_checked(symbol: Symbol, var_store: &mut VarStore) -> Def {
todo!()
}
// Num.toI64 : Int * -> I64
fn num_to_i64(symbol: Symbol, var_store: &mut VarStore) -> Def {
// Defer to IntCast
lowlevel_1(symbol, LowLevel::NumIntCast, var_store)
}
// Num.toI64Checked : Int * -> Result I64 [ OutOfBounds ]*
fn num_to_i64_checked(symbol: Symbol, var_store: &mut VarStore) -> Def {
todo!()
}
// Num.toI128 : Int * -> I128
fn num_to_i128(symbol: Symbol, var_store: &mut VarStore) -> Def {
// Defer to IntCast
lowlevel_1(symbol, LowLevel::NumIntCast, var_store)
}
// Num.toI128Checked : Int * -> Result I128 [ OutOfBounds ]*
fn num_to_i128_checked(symbol: Symbol, var_store: &mut VarStore) -> Def {
todo!()
}
// Num.toU8 : Int * -> U8
fn num_to_u8(symbol: Symbol, var_store: &mut VarStore) -> Def {
// Defer to IntCast
lowlevel_1(symbol, LowLevel::NumIntCast, var_store)
}
// Num.toU8Checked : Int * -> Result U8 [ OutOfBounds ]*
fn num_to_u8_checked(symbol: Symbol, var_store: &mut VarStore) -> Def {
todo!()
}
// Num.toU16 : Int * -> U16
fn num_to_u16(symbol: Symbol, var_store: &mut VarStore) -> Def {
// Defer to IntCast
lowlevel_1(symbol, LowLevel::NumIntCast, var_store)
}
// Num.toU16Checked : Int * -> Result U16 [ OutOfBounds ]*
fn num_to_u16_checked(symbol: Symbol, var_store: &mut VarStore) -> Def {
todo!()
}
// Num.toU32 : Int * -> U32
fn num_to_u32(symbol: Symbol, var_store: &mut VarStore) -> Def {
// Defer to IntCast
lowlevel_1(symbol, LowLevel::NumIntCast, var_store)
}
// Num.toU32Checked : Int * -> Result U32 [ OutOfBounds ]*
fn num_to_u32_checked(symbol: Symbol, var_store: &mut VarStore) -> Def {
todo!()
}
// Num.toU64 : Int * -> U64
fn num_to_u64(symbol: Symbol, var_store: &mut VarStore) -> Def {
// Defer to IntCast
lowlevel_1(symbol, LowLevel::NumIntCast, var_store)
}
// Num.toU64Checked : Int * -> Result U64 [ OutOfBounds ]*
fn num_to_u64_checked(symbol: Symbol, var_store: &mut VarStore) -> Def {
todo!()
}
// Num.toU128 : Int * -> U128
fn num_to_u128(symbol: Symbol, var_store: &mut VarStore) -> Def {
// Defer to IntCast
lowlevel_1(symbol, LowLevel::NumIntCast, var_store)
}
// Num.toU128Checked : Int * -> Result U128 [ OutOfBounds ]*
fn num_to_u128_checked(symbol: Symbol, var_store: &mut VarStore) -> Def {
todo!()
fn to_num_checked(symbol: Symbol, var_store: &mut VarStore, lowlevel: LowLevel) -> Def {
let bool_var = var_store.fresh();
let num_var_1 = var_store.fresh();
let num_var_2 = var_store.fresh();
let ret_var = var_store.fresh();
let record_var = var_store.fresh();
// let arg_2 = RunLowLevel NumToXXXChecked arg_1
// if arg_2.b then
// Err OutOfBounds
// else
// Ok arg_2.a
//
// "a" and "b" because the lowlevel return value looks like { converted_val: XXX, out_of_bounds: bool },
// and codegen will sort by alignment, so "a" will be the first key, etc.
let cont = If {
branch_var: ret_var,
cond_var: bool_var,
branches: vec![(
// if-condition
no_region(
// arg_2.b
Access {
record_var,
ext_var: var_store.fresh(),
field: "b".into(),
field_var: var_store.fresh(),
loc_expr: Box::new(no_region(Var(Symbol::ARG_2))),
},
),
// out of bounds!
no_region(tag(
"Err",
vec![tag("OutOfBounds", Vec::new(), var_store)],
var_store,
)),
)],
final_else: Box::new(
// all is well
no_region(
// Ok arg_2.a
tag(
"Ok",
vec![
// arg_2.a
Access {
record_var,
ext_var: var_store.fresh(),
field: "a".into(),
field_var: num_var_2,
loc_expr: Box::new(no_region(Var(Symbol::ARG_2))),
},
],
var_store,
),
),
),
};
// arg_2 = RunLowLevel NumToXXXChecked arg_1
let def = crate::def::Def {
loc_pattern: no_region(Pattern::Identifier(Symbol::ARG_2)),
loc_expr: no_region(RunLowLevel {
op: lowlevel,
args: vec![(num_var_1, Var(Symbol::ARG_1))],
ret_var: record_var,
}),
expr_var: record_var,
pattern_vars: SendMap::default(),
annotation: None,
};
let body = LetNonRec(Box::new(def), Box::new(no_region(cont)), ret_var);
defn(
symbol,
vec![(num_var_1, Symbol::ARG_1)],
var_store,
body,
ret_var,
)
}
macro_rules! num_to_checked {
($($fn:ident)*) => {$(
// Num.toXXXChecked : Int * -> Result XXX [ OutOfBounds ]*
fn $fn(symbol: Symbol, var_store: &mut VarStore) -> Def {
// Use the generic `NumToIntChecked`; we'll figure out exactly what layout(s) we need
// during code generation after types are resolved.
to_num_checked(symbol, var_store, LowLevel::NumToIntChecked)
}
)*}
}
num_to_checked! {
num_to_i8_checked
num_to_i16_checked
num_to_i32_checked
num_to_i64_checked
num_to_i128_checked
num_to_u8_checked
num_to_u16_checked
num_to_u32_checked
num_to_u64_checked
num_to_u128_checked
}
// Num.toStr : Num a -> Str