Add Num.(min/max)(I/U)(8/16) builtins

This commit is contained in:
Jan Van Bruggen 2022-01-21 23:23:40 -07:00
parent 38f0a3717f
commit 9a8a4c6ed7
5 changed files with 276 additions and 12 deletions

View File

@ -62,12 +62,20 @@ interface Num
isZero,
log,
maxFloat,
maxI8,
maxU8,
maxI16,
maxU16,
maxI32,
maxU32,
maxI64,
maxU64,
maxI128,
minFloat,
minI8,
minU8,
minI16,
minU16,
minI32,
minU32,
minI64,
@ -791,6 +799,72 @@ minNat : Nat
## 32-bit system, this will be equal to #Num.maxU32.
maxNat : Nat
## The lowest number that can be stored in an #I8 without underflowing its
## available memory and crashing.
##
## For reference, this number is `-128`.
##
## Note that the positive version of this number is larger than #Int.maxI8,
## which means if you call #Num.abs on #Int.minI8, it will overflow and crash!
minI8 : I8
## The highest number that can be stored in an #I8 without overflowing its
## available memory and crashing.
##
## For reference, this number is `127`.
##
## Note that this is smaller than the positive version of #Int.minI8,
## which means if you call #Num.abs on #Int.minI8, it will overflow and crash!
maxI8 : I8
## The lowest number that can be stored in a #U8 without underflowing its
## available memory and crashing.
##
## For reference, this number is zero, because #U8 is
## [unsigned](https://en.wikipedia.org/wiki/Signed_number_representations),
## and zero is the lowest unsigned number.
## Unsigned numbers cannot be negative.
minU8 : U8
## The highest number that can be stored in a #U8 without overflowing its
## available memory and crashing.
##
## For reference, this number is `255`.
maxU8 : U8
## The lowest number that can be stored in an #I16 without underflowing its
## available memory and crashing.
##
## For reference, this number is `-32_768`.
##
## Note that the positive version of this number is larger than #Int.maxI16,
## which means if you call #Num.abs on #Int.minI16, it will overflow and crash!
minI16 : I16
## The highest number that can be stored in an #I16 without overflowing its
## available memory and crashing.
##
## For reference, this number is `32_767`.
##
## Note that this is smaller than the positive version of #Int.minI16,
## which means if you call #Num.abs on #Int.minI16, it will overflow and crash!
maxI16 : I16
## The lowest number that can be stored in a #U16 without underflowing its
## available memory and crashing.
##
## For reference, this number is zero, because #U16 is
## [unsigned](https://en.wikipedia.org/wiki/Signed_number_representations),
## and zero is the lowest unsigned number.
## Unsigned numbers cannot be negative.
minU16 : U16
## The highest number that can be stored in a #U16 without overflowing its
## available memory and crashing.
##
## For reference, this number is `65_535`.
maxU16 : U16
## The lowest number that can be stored in an #I32 without underflowing its
## available memory and crashing.
##

View File

@ -391,6 +391,30 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
Box::new(bool_type()),
);
// minI8 : I8
add_type!(Symbol::NUM_MIN_I8, i8_type());
// maxI8 : I8
add_type!(Symbol::NUM_MAX_I8, i8_type());
// minU8 : U8
add_type!(Symbol::NUM_MIN_U8, u8_type());
// maxU8 : U8
add_type!(Symbol::NUM_MAX_U8, u8_type());
// minI16 : I16
add_type!(Symbol::NUM_MIN_I16, i16_type());
// maxI16 : I16
add_type!(Symbol::NUM_MAX_I16, i16_type());
// minU16 : U16
add_type!(Symbol::NUM_MIN_U16, u16_type());
// maxU16 : U16
add_type!(Symbol::NUM_MAX_U16, u16_type());
// minI32 : I32
add_type!(Symbol::NUM_MIN_I32, i32_type());

View File

@ -223,6 +223,14 @@ pub fn builtin_defs_map(symbol: Symbol, var_store: &mut VarStore) -> Option<Def>
NUM_SHIFT_RIGHT => num_shift_right_by,
NUM_SHIFT_RIGHT_ZERO_FILL => num_shift_right_zf_by,
NUM_INT_CAST=> num_int_cast,
NUM_MIN_I8=> num_min_i8,
NUM_MAX_I8=> num_max_i8,
NUM_MIN_U8=> num_min_u8,
NUM_MAX_U8=> num_max_u8,
NUM_MIN_I16=> num_min_i16,
NUM_MAX_I16=> num_max_i16,
NUM_MIN_U16=> num_min_u16,
NUM_MAX_U16=> num_max_u16,
NUM_MIN_I32=> num_min_i32,
NUM_MAX_I32=> num_max_i32,
NUM_MIN_U32=> num_min_u32,
@ -1236,56 +1244,94 @@ fn num_int_cast(symbol: Symbol, var_store: &mut VarStore) -> Def {
lowlevel_1(symbol, LowLevel::NumIntCast, var_store)
}
/// Num.minI8: I8
fn num_min_i8(symbol: Symbol, var_store: &mut VarStore) -> Def {
int_min_or_max::<i8>(symbol, var_store, i8::MIN)
}
/// Num.maxI8: I8
fn num_max_i8(symbol: Symbol, var_store: &mut VarStore) -> Def {
int_min_or_max::<i8>(symbol, var_store, i8::MAX)
}
/// Num.minU8: U8
fn num_min_u8(symbol: Symbol, var_store: &mut VarStore) -> Def {
int_min_or_max::<u8>(symbol, var_store, u8::MIN)
}
/// Num.maxU8: U8
fn num_max_u8(symbol: Symbol, var_store: &mut VarStore) -> Def {
int_min_or_max::<u8>(symbol, var_store, u8::MAX)
}
/// Num.minI16: I16
fn num_min_i16(symbol: Symbol, var_store: &mut VarStore) -> Def {
int_min_or_max::<i16>(symbol, var_store, i16::MIN)
}
/// Num.maxI16: I16
fn num_max_i16(symbol: Symbol, var_store: &mut VarStore) -> Def {
int_min_or_max::<i16>(symbol, var_store, i16::MAX)
}
/// Num.minU16: U16
fn num_min_u16(symbol: Symbol, var_store: &mut VarStore) -> Def {
int_min_or_max::<u16>(symbol, var_store, u16::MIN)
}
/// Num.maxU16: U16
fn num_max_u16(symbol: Symbol, var_store: &mut VarStore) -> Def {
int_min_or_max::<u16>(symbol, var_store, u16::MAX)
}
/// Num.minI32: I32
fn num_min_i32(symbol: Symbol, var_store: &mut VarStore) -> Def {
int_min_or_max::<i32>(symbol, var_store, i32::MIN);
int_min_or_max::<i32>(symbol, var_store, i32::MIN)
}
/// Num.maxI32: I32
fn num_max_i32(symbol: Symbol, var_store: &mut VarStore) -> Def {
int_min_or_max::<i32>(symbol, var_store, i32::MAX);
int_min_or_max::<i32>(symbol, var_store, i32::MAX)
}
/// Num.minU32: U32
fn num_min_u32(symbol: Symbol, var_store: &mut VarStore) -> Def {
int_min_or_max::<u32>(symbol, var_store, u32::MIN);
int_min_or_max::<u32>(symbol, var_store, u32::MIN)
}
/// Num.maxU32: U32
fn num_max_u32(symbol: Symbol, var_store: &mut VarStore) -> Def {
int_min_or_max::<u32>(symbol, var_store, u32::MAX);
int_min_or_max::<u32>(symbol, var_store, u32::MAX)
}
/// Num.minI64: I64
fn num_min_i64(symbol: Symbol, var_store: &mut VarStore) -> Def {
int_min_or_max::<i64>(symbol, var_store, i64::MIN);
int_min_or_max::<i64>(symbol, var_store, i64::MIN)
}
/// Num.maxI64: I64
fn num_max_i64(symbol: Symbol, var_store: &mut VarStore) -> Def {
int_min_or_max::<i64>(symbol, var_store, i64::MAX);
int_min_or_max::<i64>(symbol, var_store, i64::MAX)
}
/// Num.minU64: U64
fn num_min_u64(symbol: Symbol, var_store: &mut VarStore) -> Def {
int_min_or_max::<u64>(symbol, var_store, u64::MIN);
int_min_or_max::<u64>(symbol, var_store, u64::MIN)
}
/// Num.maxU64: U64
fn num_max_u64(symbol: Symbol, var_store: &mut VarStore) -> Def {
int_min_or_max::<u64>(symbol, var_store, iu64::MAX);
int_min_or_max::<u64>(symbol, var_store, u64::MAX)
}
/// Num.minI128: I128
fn num_min_i128(symbol: Symbol, var_store: &mut VarStore) -> Def {
int_min_or_max::<i128>(symbol, var_store, i128::MIN);
pattern_vars: SendMap::default(),
}
int_min_or_max::<i128>(symbol, var_store, i128::MIN)
}
/// Num.maxI128: I128
fn num_max_i128(symbol: Symbol, var_store: &mut VarStore) -> Def {
int_min_or_max::<i128>(symbol, var_store, i128::MIN);
int_min_or_max::<i128>(symbol, var_store, i128::MAX)
}
/// List.isEmpty : List * -> Bool

View File

@ -1002,6 +1002,14 @@ define_builtins! {
114 NUM_MAX_I64: "maxI64"
115 NUM_MIN_U64: "minU64"
116 NUM_MAX_U64: "maxU64"
117 NUM_MIN_I8: "minI8"
118 NUM_MAX_I8: "maxI8"
119 NUM_MIN_U8: "minU8"
120 NUM_MAX_U8: "maxU8"
121 NUM_MIN_I16: "minI16"
122 NUM_MAX_I16: "maxI16"
123 NUM_MIN_U16: "minU16"
124 NUM_MAX_U16: "maxU16"
}
2 BOOL: "Bool" => {
0 BOOL_BOOL: "Bool" imported // the Bool.Bool type alias

View File

@ -1941,6 +1941,118 @@ fn max_u32() {
);
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
fn min_i16() {
assert_evals_to!(
indoc!(
r#"
Num.minI16
"#
),
i16::MIN,
i16
);
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
fn max_i16() {
assert_evals_to!(
indoc!(
r#"
Num.maxI16
"#
),
i16::MAX,
i16
);
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
fn min_u16() {
assert_evals_to!(
indoc!(
r#"
Num.minU16
"#
),
u16::MIN,
u16
);
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
fn max_u16() {
assert_evals_to!(
indoc!(
r#"
Num.maxU16
"#
),
u16::MAX,
u16
);
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
fn min_i8() {
assert_evals_to!(
indoc!(
r#"
Num.minI8
"#
),
i8::MIN,
i8
);
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
fn max_i8() {
assert_evals_to!(
indoc!(
r#"
Num.maxI8
"#
),
i8::MAX,
i8
);
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
fn min_u8() {
assert_evals_to!(
indoc!(
r#"
Num.minU8
"#
),
u8::MIN,
u8
);
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
fn max_u8() {
assert_evals_to!(
indoc!(
r#"
Num.maxU8
"#
),
u8::MAX,
u8
);
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn is_multiple_of() {