diff --git a/compiler/builtins/src/std.rs b/compiler/builtins/src/std.rs index 8a4ee50b2a..3c8df4ac00 100644 --- a/compiler/builtins/src/std.rs +++ b/compiler/builtins/src/std.rs @@ -445,6 +445,156 @@ pub fn types() -> MutMap { // maxI128 : I128 add_type!(Symbol::NUM_MAX_I128, i128_type()); + // toI8 : Int * -> I8 + add_top_level_function_type!( + Symbol::NUM_TO_I8, + vec![int_type(flex(TVAR1))], + Box::new(i8_type()), + ); + + let out_of_bounds = SolvedType::TagUnion( + vec![(TagName::Global("OutOfBounds".into()), vec![])], + Box::new(SolvedType::Wildcard), + ); + + // toI8Checked : Int * -> Result I8 [ OutOfBounds ]* + add_top_level_function_type!( + Symbol::NUM_TO_I8_CHECKED, + vec![int_type(flex(TVAR1))], + Box::new(result_type(i8_type(), out_of_bounds.clone())), + ); + + // toI16 : Int * -> I16 + add_top_level_function_type!( + Symbol::NUM_TO_I16, + vec![int_type(flex(TVAR1))], + Box::new(i16_type()), + ); + + // toI16Checked : Int * -> Result I16 [ OutOfBounds ]* + add_top_level_function_type!( + Symbol::NUM_TO_I16_CHECKED, + vec![int_type(flex(TVAR1))], + Box::new(result_type(i16_type(), out_of_bounds.clone())), + ); + + // toI32 : Int * -> I32 + add_top_level_function_type!( + Symbol::NUM_TO_I32, + vec![int_type(flex(TVAR1))], + Box::new(i32_type()), + ); + + // toI32Checked : Int * -> Result I32 [ OutOfBounds ]* + add_top_level_function_type!( + Symbol::NUM_TO_I32_CHECKED, + vec![int_type(flex(TVAR1))], + Box::new(result_type(i32_type(), out_of_bounds.clone())), + ); + + // toI64 : Int * -> I64 + add_top_level_function_type!( + Symbol::NUM_TO_I64, + vec![int_type(flex(TVAR1))], + Box::new(i64_type()), + ); + + // toI64Checked : Int * -> Result I64 [ OutOfBounds ]* + add_top_level_function_type!( + Symbol::NUM_TO_I64_CHECKED, + vec![int_type(flex(TVAR1))], + Box::new(result_type(i64_type(), out_of_bounds.clone())), + ); + + // toI128 : Int * -> I128 + add_top_level_function_type!( + Symbol::NUM_TO_I128, + vec![int_type(flex(TVAR1))], + Box::new(i128_type()), + ); + + // toI128Checked : Int * -> Result I128 [ OutOfBounds ]* + add_top_level_function_type!( + Symbol::NUM_TO_I128_CHECKED, + vec![int_type(flex(TVAR1))], + Box::new(result_type(i128_type(), out_of_bounds.clone())), + ); + + // toU8 : Int * -> U8 + add_top_level_function_type!( + Symbol::NUM_TO_U8, + vec![int_type(flex(TVAR1))], + Box::new(u8_type()), + ); + + let out_of_bounds = SolvedType::TagUnion( + vec![(TagName::Global("OutOfBounds".into()), vec![])], + Box::new(SolvedType::Wildcard), + ); + + // toU8Checked : Int * -> Result U8 [ OutOfBounds ]* + add_top_level_function_type!( + Symbol::NUM_TO_U8_CHECKED, + vec![int_type(flex(TVAR1))], + Box::new(result_type(u8_type(), out_of_bounds.clone())), + ); + + // toU16 : Int * -> U16 + add_top_level_function_type!( + Symbol::NUM_TO_U16, + vec![int_type(flex(TVAR1))], + Box::new(u16_type()), + ); + + // toU16Checked : Int * -> Result U16 [ OutOfBounds ]* + add_top_level_function_type!( + Symbol::NUM_TO_U16_CHECKED, + vec![int_type(flex(TVAR1))], + Box::new(result_type(u16_type(), out_of_bounds.clone())), + ); + + // toU32 : Int * -> U32 + add_top_level_function_type!( + Symbol::NUM_TO_U32, + vec![int_type(flex(TVAR1))], + Box::new(u32_type()), + ); + + // toU32Checked : Int * -> Result U32 [ OutOfBounds ]* + add_top_level_function_type!( + Symbol::NUM_TO_U32_CHECKED, + vec![int_type(flex(TVAR1))], + Box::new(result_type(u32_type(), out_of_bounds.clone())), + ); + + // toU64 : Int * -> U64 + add_top_level_function_type!( + Symbol::NUM_TO_U64, + vec![int_type(flex(TVAR1))], + Box::new(u64_type()), + ); + + // toU64Checked : Int * -> Result U64 [ OutOfBounds ]* + add_top_level_function_type!( + Symbol::NUM_TO_U64_CHECKED, + vec![int_type(flex(TVAR1))], + Box::new(result_type(u64_type(), out_of_bounds.clone())), + ); + + // toU128 : Int * -> U128 + add_top_level_function_type!( + Symbol::NUM_TO_U128, + vec![int_type(flex(TVAR1))], + Box::new(u128_type()), + ); + + // toU128Checked : Int * -> Result U128 [ OutOfBounds ]* + add_top_level_function_type!( + Symbol::NUM_TO_U128_CHECKED, + vec![int_type(flex(TVAR1))], + Box::new(result_type(u128_type(), out_of_bounds.clone())), + ); + // toStr : Num a -> Str add_top_level_function_type!( Symbol::NUM_TO_STR, diff --git a/compiler/can/src/builtins.rs b/compiler/can/src/builtins.rs index 3c21b53b9a..dc93d5b06f 100644 --- a/compiler/can/src/builtins.rs +++ b/compiler/can/src/builtins.rs @@ -242,6 +242,26 @@ pub fn builtin_defs_map(symbol: Symbol, var_store: &mut VarStore) -> Option NUM_MAX_U64=> num_max_u64, NUM_MIN_I128=> num_min_i128, NUM_MAX_I128=> num_max_i128, + NUM_TO_I8 => num_to_i8, + NUM_TO_I8_CHECKED => num_to_i8_checked, + NUM_TO_I16 => num_to_i16, + NUM_TO_I16_CHECKED => num_to_i16_checked, + NUM_TO_I32 => num_to_i32, + NUM_TO_I32_CHECKED => num_to_i32_checked, + NUM_TO_I64 => num_to_i64, + NUM_TO_I64_CHECKED => num_to_i64_checked, + NUM_TO_I128 => num_to_i128, + NUM_TO_I128_CHECKED => num_to_i128_checked, + NUM_TO_U8 => num_to_u8, + NUM_TO_U8_CHECKED => num_to_u8_checked, + NUM_TO_U16 => num_to_u16, + NUM_TO_U16_CHECKED => num_to_u16_checked, + NUM_TO_U32 => num_to_u32, + NUM_TO_U32_CHECKED => num_to_u32_checked, + NUM_TO_U64 => num_to_u64, + NUM_TO_U64_CHECKED => num_to_u64_checked, + NUM_TO_U128 => num_to_u128, + NUM_TO_U128_CHECKED => num_to_u128_checked, NUM_TO_STR => num_to_str, RESULT_MAP => result_map, RESULT_MAP_ERR => result_map_err, @@ -390,6 +410,256 @@ fn lowlevel_5(symbol: Symbol, op: LowLevel, var_store: &mut VarStore) -> Def { ) } +// Num.toI8 : Int * -> I8 +fn num_to_i8(symbol: Symbol, var_store: &mut VarStore) -> Def { + let int_var = var_store.fresh(); + let i8_var = var_store.fresh(); + + let body = RunLowLevel { + op: LowLevel::NumToStr, + args: vec![(int_var, Var(Symbol::ARG_1))], + ret_var: i8_var, + }; + + defn( + symbol, + vec![(int_var, Symbol::ARG_1)], + var_store, + body, + i8_var, + ) +} + +// 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 { + let int_var = var_store.fresh(); + let i16_var = var_store.fresh(); + + let body = RunLowLevel { + op: LowLevel::NumToStr, + args: vec![(int_var, Var(Symbol::ARG_1))], + ret_var: i16_var, + }; + + defn( + symbol, + vec![(int_var, Symbol::ARG_1)], + var_store, + body, + i16_var, + ) +} + +// 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 { + let int_var = var_store.fresh(); + let i32_var = var_store.fresh(); + + let body = RunLowLevel { + op: LowLevel::NumToStr, + args: vec![(int_var, Var(Symbol::ARG_1))], + ret_var: i32_var, + }; + + defn( + symbol, + vec![(int_var, Symbol::ARG_1)], + var_store, + body, + i32_var, + ) +} + +// 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 { + let int_var = var_store.fresh(); + let i64_var = var_store.fresh(); + + let body = RunLowLevel { + op: LowLevel::NumToStr, + args: vec![(int_var, Var(Symbol::ARG_1))], + ret_var: i64_var, + }; + + defn( + symbol, + vec![(int_var, Symbol::ARG_1)], + var_store, + body, + i64_var, + ) +} + +// 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 { + let int_var = var_store.fresh(); + let i128_var = var_store.fresh(); + + let body = RunLowLevel { + op: LowLevel::NumToStr, + args: vec![(int_var, Var(Symbol::ARG_1))], + ret_var: i128_var, + }; + + defn( + symbol, + vec![(int_var, Symbol::ARG_1)], + var_store, + body, + i128_var, + ) +} + +// 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 { + let int_var = var_store.fresh(); + let u8_var = var_store.fresh(); + + let body = RunLowLevel { + op: LowLevel::NumToStr, + args: vec![(int_var, Var(Symbol::ARG_1))], + ret_var: u8_var, + }; + + defn( + symbol, + vec![(int_var, Symbol::ARG_1)], + var_store, + body, + u8_var, + ) +} + +// 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 { + let int_var = var_store.fresh(); + let u16_var = var_store.fresh(); + + let body = RunLowLevel { + op: LowLevel::NumToStr, + args: vec![(int_var, Var(Symbol::ARG_1))], + ret_var: u16_var, + }; + + defn( + symbol, + vec![(int_var, Symbol::ARG_1)], + var_store, + body, + u16_var, + ) +} + +// 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 { + let int_var = var_store.fresh(); + let u32_var = var_store.fresh(); + + let body = RunLowLevel { + op: LowLevel::NumToStr, + args: vec![(int_var, Var(Symbol::ARG_1))], + ret_var: u32_var, + }; + + defn( + symbol, + vec![(int_var, Symbol::ARG_1)], + var_store, + body, + u32_var, + ) +} + +// 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 { + let int_var = var_store.fresh(); + let u64_var = var_store.fresh(); + + let body = RunLowLevel { + op: LowLevel::NumToStr, + args: vec![(int_var, Var(Symbol::ARG_1))], + ret_var: u64_var, + }; + + defn( + symbol, + vec![(int_var, Symbol::ARG_1)], + var_store, + body, + u64_var, + ) +} + +// 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 { + let int_var = var_store.fresh(); + let u128_var = var_store.fresh(); + + let body = RunLowLevel { + op: LowLevel::NumToStr, + args: vec![(int_var, Var(Symbol::ARG_1))], + ret_var: u128_var, + }; + + defn( + symbol, + vec![(int_var, Symbol::ARG_1)], + var_store, + body, + u128_var, + ) +} + +// Num.toU128Checked : Int * -> Result U128 [ OutOfBounds ]* +fn num_to_u128_checked(symbol: Symbol, var_store: &mut VarStore) -> Def { + // TODO +} + // Num.toStr : Num a -> Str fn num_to_str(symbol: Symbol, var_store: &mut VarStore) -> Def { let num_var = var_store.fresh(); diff --git a/compiler/module/src/symbol.rs b/compiler/module/src/symbol.rs index 6d9c7461cd..82778fa6d0 100644 --- a/compiler/module/src/symbol.rs +++ b/compiler/module/src/symbol.rs @@ -1010,6 +1010,26 @@ define_builtins! { 122 NUM_MAX_U64: "maxU64" 123 NUM_MIN_I128: "minI128" 124 NUM_MAX_I128: "maxI128" + 125 NUM_TO_I8: "toI8" + 126 NUM_TO_I8_CHECKED: "toI8Checked" + 127 NUM_TO_I16: "toI16" + 128 NUM_TO_I16_CHECKED: "toI16Checked" + 129 NUM_TO_I32: "toI32" + 130 NUM_TO_I32_CHECKED: "toI32Checked" + 131 NUM_TO_I64: "toI64" + 132 NUM_TO_I64_CHECKED: "toI64Checked" + 133 NUM_TO_I128: "toI128" + 134 NUM_TO_I128_CHECKED: "toI128Checked" + 135 NUM_TO_U8: "toU8" + 136 NUM_TO_U8_CHECKED: "toU8Checked" + 137 NUM_TO_U16: "toU16" + 138 NUM_TO_U16_CHECKED: "toU16Checked" + 139 NUM_TO_U32: "toU32" + 140 NUM_TO_U32_CHECKED: "toU32Checked" + 141 NUM_TO_U64: "toU64" + 142 NUM_TO_U64_CHECKED: "toU64Checked" + 143 NUM_TO_U128: "toU128" + 144 NUM_TO_U128_CHECKED: "toU128Checked" } 2 BOOL: "Bool" => { 0 BOOL_BOOL: "Bool" imported // the Bool.Bool type alias diff --git a/compiler/test_gen/src/gen_num.rs b/compiler/test_gen/src/gen_num.rs index 3a4951a36d..ffc928324b 100644 --- a/compiler/test_gen/src/gen_num.rs +++ b/compiler/test_gen/src/gen_num.rs @@ -2053,6 +2053,286 @@ fn max_u8() { ); } +#[test] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] +fn to_i8() { + assert_evals_to!( + indoc!( + r#" + Num.toI8 TODO + "# + ), + i8::MAX, // TODO + i8 + ); +} + +#[test] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] +fn to_i8_checked() { + assert_evals_to!( + indoc!( + r#" + Num.toI8Checked TODO + "# + ), + i8::MAX, // TODO + i8 + ); +} + +#[test] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] +fn to_i16() { + assert_evals_to!( + indoc!( + r#" + Num.toI16 TODO + "# + ), + i16::MAX, // TODO + i16 + ); +} + +#[test] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] +fn to_i16_checked() { + assert_evals_to!( + indoc!( + r#" + Num.toI16Checked TODO + "# + ), + i16::MAX, // TODO + i16 + ); +} + +#[test] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] +fn to_i32() { + assert_evals_to!( + indoc!( + r#" + Num.toI32 TODO + "# + ), + i32::MAX, // TODO + i32 + ); +} + +#[test] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] +fn to_i32_checked() { + assert_evals_to!( + indoc!( + r#" + Num.toI32Checked TODO + "# + ), + i32::MAX, // TODO + i32 + ); +} + +#[test] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] +fn to_i64() { + assert_evals_to!( + indoc!( + r#" + Num.toI64 TODO + "# + ), + i64::MAX, // TODO + i64 + ); +} + +#[test] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] +fn to_i64_checked() { + assert_evals_to!( + indoc!( + r#" + Num.toI64Checked TODO + "# + ), + i64::MAX, // TODO + i64 + ); +} + +#[test] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] +fn to_i128() { + assert_evals_to!( + indoc!( + r#" + Num.toI128 TODO + "# + ), + i128::MAX, // TODO + i128 + ); +} + +#[test] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] +fn to_i128_checked() { + assert_evals_to!( + indoc!( + r#" + Num.toI128Checked TODO + "# + ), + i128::MAX, // TODO + i128 + ); +} + +#[test] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] +fn to_u8() { + assert_evals_to!( + indoc!( + r#" + Num.toU8 TODO + "# + ), + u8::MAX, // TODO + u8 + ); +} + +#[test] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] +fn to_u8_checked() { + assert_evals_to!( + indoc!( + r#" + Num.toU8Checked TODO + "# + ), + u8::MAX, // TODO + u8 + ); +} + +#[test] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] +fn to_u16() { + assert_evals_to!( + indoc!( + r#" + Num.toU16 TODO + "# + ), + u16::MAX, // TODO + u16 + ); +} + +#[test] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] +fn to_u16_checked() { + assert_evals_to!( + indoc!( + r#" + Num.toU16Checked TODO + "# + ), + u16::MAX, // TODO + u16 + ); +} + +#[test] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] +fn to_u32() { + assert_evals_to!( + indoc!( + r#" + Num.toU32 TODO + "# + ), + u32::MAX, // TODO + u32 + ); +} + +#[test] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] +fn to_u32_checked() { + assert_evals_to!( + indoc!( + r#" + Num.toU32Checked TODO + "# + ), + u32::MAX, // TODO + u32 + ); +} + +#[test] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] +fn to_u64() { + assert_evals_to!( + indoc!( + r#" + Num.toU64 TODO + "# + ), + u64::MAX, // TODO + u64 + ); +} + +#[test] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] +fn to_u64_checked() { + assert_evals_to!( + indoc!( + r#" + Num.toU64Checked TODO + "# + ), + u64::MAX, // TODO + u64 + ); +} + +#[test] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] +fn to_u128() { + assert_evals_to!( + indoc!( + r#" + Num.toU128 TODO + "# + ), + u128::MAX, // TODO + u128 + ); +} + +#[test] +#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] +fn to_u128_checked() { + assert_evals_to!( + indoc!( + r#" + Num.toU128Checked TODO + "# + ), + u128::MAX, // TODO + u128 + ); +} + #[test] #[cfg(any(feature = "gen-llvm"))] fn is_multiple_of() {