mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-03 08:34:33 +00:00
rem, sqrt, log are unchecked but have checked variants
mod exists but is not implemented due to lack of hardware support (emulation, possibly in terms of rem, is needed).
This commit is contained in:
parent
d23d5f249f
commit
1908ff41c3
15 changed files with 208 additions and 75 deletions
|
@ -61,6 +61,7 @@ interface Num
|
||||||
isPositive,
|
isPositive,
|
||||||
isZero,
|
isZero,
|
||||||
log,
|
log,
|
||||||
|
logChecked,
|
||||||
maxFloat,
|
maxFloat,
|
||||||
maxI8,
|
maxI8,
|
||||||
maxU8,
|
maxU8,
|
||||||
|
@ -81,8 +82,8 @@ interface Num
|
||||||
minI64,
|
minI64,
|
||||||
minU64,
|
minU64,
|
||||||
minI128,
|
minI128,
|
||||||
modInt,
|
mod,
|
||||||
modFloat,
|
modChecked,
|
||||||
mul,
|
mul,
|
||||||
mulChecked,
|
mulChecked,
|
||||||
mulWrap,
|
mulWrap,
|
||||||
|
@ -90,6 +91,7 @@ interface Num
|
||||||
pow,
|
pow,
|
||||||
powInt,
|
powInt,
|
||||||
rem,
|
rem,
|
||||||
|
remChecked,
|
||||||
round,
|
round,
|
||||||
shiftLeftBy,
|
shiftLeftBy,
|
||||||
shiftRightBy,
|
shiftRightBy,
|
||||||
|
@ -99,6 +101,7 @@ interface Num
|
||||||
subChecked,
|
subChecked,
|
||||||
subWrap,
|
subWrap,
|
||||||
sqrt,
|
sqrt,
|
||||||
|
sqrtChecked,
|
||||||
tan,
|
tan,
|
||||||
toI8,
|
toI8,
|
||||||
toI8Checked,
|
toI8Checked,
|
||||||
|
@ -1316,7 +1319,7 @@ isInfinite : Float * -> Bool
|
||||||
##
|
##
|
||||||
## >>> Num.isNaN 12.3
|
## >>> Num.isNaN 12.3
|
||||||
##
|
##
|
||||||
## >>> Num.isNaN (Num.sqrt -2)
|
## >>> Num.isNaN (Num.pow -1 0.5)
|
||||||
##
|
##
|
||||||
## *NaN* is unusual from other numberic values in that:
|
## *NaN* is unusual from other numberic values in that:
|
||||||
## * *NaN* is not equal to any other number, even itself. [Bool.isEq] always returns `False` if either argument is *NaN*.
|
## * *NaN* is not equal to any other number, even itself. [Bool.isEq] always returns `False` if either argument is *NaN*.
|
||||||
|
|
|
@ -68,12 +68,15 @@ interface Num
|
||||||
isPositive,
|
isPositive,
|
||||||
isNegative,
|
isNegative,
|
||||||
rem,
|
rem,
|
||||||
|
remChecked,
|
||||||
div,
|
div,
|
||||||
divChecked,
|
divChecked,
|
||||||
modInt,
|
mod,
|
||||||
modFloat,
|
modChecked,
|
||||||
sqrt,
|
sqrt,
|
||||||
|
sqrtChecked,
|
||||||
log,
|
log,
|
||||||
|
logChecked,
|
||||||
round,
|
round,
|
||||||
ceiling,
|
ceiling,
|
||||||
floor,
|
floor,
|
||||||
|
@ -230,19 +233,23 @@ asin : Float a -> Float a
|
||||||
acos : Float a -> Float a
|
acos : Float a -> Float a
|
||||||
atan : Float a -> Float a
|
atan : Float a -> Float a
|
||||||
|
|
||||||
sqrt : Float a -> Result (Float a) [ SqrtOfNegative ]*
|
sqrt : Float a -> Float a
|
||||||
log : Float a -> Result (Float a) [ LogNeedsPositive ]*
|
sqrtChecked : Float a -> Result (Float a) [ SqrtOfNegative ]*
|
||||||
|
log : Float a -> Float a
|
||||||
|
logChecked : Float a -> Result (Float a) [ LogNeedsPositive ]*
|
||||||
|
|
||||||
div : Float a, Float a -> Float a
|
div : Float a, Float a -> Float a
|
||||||
divChecked : Float a, Float a -> Result (Float a) [ DivByZero ]*
|
divChecked : Float a, Float a -> Result (Float a) [ DivByZero ]*
|
||||||
|
|
||||||
divCeil : Int a, Int a -> Int a
|
divCeil : Int a, Int a -> Int a
|
||||||
divCeilChecked : Int a, Int a -> Result (Int a) [ DivByZero ]*
|
divCeilChecked : Int a, Int a -> Result (Int a) [ DivByZero ]*
|
||||||
divFloor : Int a, Int a -> Int a
|
divFloor : Int a, Int a -> Int a
|
||||||
divFloorChecked : Int a, Int a -> Result (Int a) [ DivByZero ]*
|
divFloorChecked : Int a, Int a -> Result (Int a) [ DivByZero ]*
|
||||||
# mod : Float a, Float a -> Result (Float a) [ DivByZero ]*
|
|
||||||
|
|
||||||
rem : Int a, Int a -> Result (Int a) [ DivByZero ]*
|
rem : Int a, Int a -> Int a
|
||||||
# mod : Int a, Int a -> Result (Int a) [ DivByZero ]*
|
remChecked : Int a, Int a -> Result (Int a) [ DivByZero ]*
|
||||||
|
mod : Int a, Int a -> Int a
|
||||||
|
modChecked : Int a, Int a -> Result (Int a) [ DivByZero ]*
|
||||||
|
|
||||||
isMultipleOf : Int a, Int a -> Bool
|
isMultipleOf : Int a, Int a -> Bool
|
||||||
|
|
||||||
bitwiseAnd : Int a, Int a -> Int a
|
bitwiseAnd : Int a, Int a -> Int a
|
||||||
|
|
|
@ -393,16 +393,30 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
|
||||||
Box::new(int_type(flex(TVAR2)))
|
Box::new(int_type(flex(TVAR2)))
|
||||||
);
|
);
|
||||||
|
|
||||||
// rem : Int a, Int a -> Result (Int a) [ DivByZero ]*
|
// rem : Int a, Int a -> Int a
|
||||||
add_top_level_function_type!(
|
add_top_level_function_type!(
|
||||||
Symbol::NUM_REM,
|
Symbol::NUM_REM,
|
||||||
vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))],
|
vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))],
|
||||||
|
Box::new(int_type(flex(TVAR1))),
|
||||||
|
);
|
||||||
|
|
||||||
|
// remChecked : Int a, Int a -> Result (Int a) [ DivByZero ]*
|
||||||
|
add_top_level_function_type!(
|
||||||
|
Symbol::NUM_REM_CHECKED,
|
||||||
|
vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))],
|
||||||
Box::new(result_type(int_type(flex(TVAR1)), div_by_zero.clone())),
|
Box::new(result_type(int_type(flex(TVAR1)), div_by_zero.clone())),
|
||||||
);
|
);
|
||||||
|
|
||||||
// mod : Int a, Int a -> Result (Int a) [ DivByZero ]*
|
// mod : Int a, Int a -> Int a
|
||||||
add_top_level_function_type!(
|
add_top_level_function_type!(
|
||||||
Symbol::NUM_MOD_INT,
|
Symbol::NUM_MOD,
|
||||||
|
vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))],
|
||||||
|
Box::new(int_type(flex(TVAR1))),
|
||||||
|
);
|
||||||
|
|
||||||
|
// modChecked : Int a, Int a -> Result (Int a) [ DivByZero ]*
|
||||||
|
add_top_level_function_type!(
|
||||||
|
Symbol::NUM_MOD_CHECKED,
|
||||||
vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))],
|
vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))],
|
||||||
Box::new(result_type(int_type(flex(TVAR1)), div_by_zero.clone())),
|
Box::new(result_type(int_type(flex(TVAR1)), div_by_zero.clone())),
|
||||||
);
|
);
|
||||||
|
@ -680,36 +694,43 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
|
||||||
add_top_level_function_type!(
|
add_top_level_function_type!(
|
||||||
Symbol::NUM_DIV_FLOAT_CHECKED,
|
Symbol::NUM_DIV_FLOAT_CHECKED,
|
||||||
vec![float_type(flex(TVAR1)), float_type(flex(TVAR1))],
|
vec![float_type(flex(TVAR1)), float_type(flex(TVAR1))],
|
||||||
Box::new(result_type(float_type(flex(TVAR1)), div_by_zero.clone())),
|
|
||||||
);
|
|
||||||
|
|
||||||
// mod : Float a, Float a -> Result (Float a) [ DivByZero ]*
|
|
||||||
add_top_level_function_type!(
|
|
||||||
Symbol::NUM_MOD_FLOAT,
|
|
||||||
vec![float_type(flex(TVAR1)), float_type(flex(TVAR1))],
|
|
||||||
Box::new(result_type(float_type(flex(TVAR1)), div_by_zero)),
|
Box::new(result_type(float_type(flex(TVAR1)), div_by_zero)),
|
||||||
);
|
);
|
||||||
|
|
||||||
// sqrt : Float a -> Float a
|
// sqrt : Float a -> Float a
|
||||||
|
add_top_level_function_type!(
|
||||||
|
Symbol::NUM_SQRT,
|
||||||
|
vec![float_type(flex(TVAR1))],
|
||||||
|
Box::new(float_type(flex(TVAR1))),
|
||||||
|
);
|
||||||
|
|
||||||
|
// sqrtChecked : Float a -> Result (Float a) [ SqrtOfNegative ]*
|
||||||
let sqrt_of_negative = SolvedType::TagUnion(
|
let sqrt_of_negative = SolvedType::TagUnion(
|
||||||
vec![(TagName::Global("SqrtOfNegative".into()), vec![])],
|
vec![(TagName::Global("SqrtOfNegative".into()), vec![])],
|
||||||
Box::new(SolvedType::Wildcard),
|
Box::new(SolvedType::Wildcard),
|
||||||
);
|
);
|
||||||
|
|
||||||
add_top_level_function_type!(
|
add_top_level_function_type!(
|
||||||
Symbol::NUM_SQRT,
|
Symbol::NUM_SQRT_CHECKED,
|
||||||
vec![float_type(flex(TVAR1))],
|
vec![float_type(flex(TVAR1))],
|
||||||
Box::new(result_type(float_type(flex(TVAR1)), sqrt_of_negative)),
|
Box::new(result_type(float_type(flex(TVAR1)), sqrt_of_negative)),
|
||||||
);
|
);
|
||||||
|
|
||||||
// log : Float a -> Float a
|
// log : Float a -> Float a
|
||||||
|
add_top_level_function_type!(
|
||||||
|
Symbol::NUM_LOG,
|
||||||
|
vec![float_type(flex(TVAR1))],
|
||||||
|
Box::new(float_type(flex(TVAR1))),
|
||||||
|
);
|
||||||
|
|
||||||
|
// logChecked : Float a -> Result (Float a) [ LogNeedsPositive ]*
|
||||||
let log_needs_positive = SolvedType::TagUnion(
|
let log_needs_positive = SolvedType::TagUnion(
|
||||||
vec![(TagName::Global("LogNeedsPositive".into()), vec![])],
|
vec![(TagName::Global("LogNeedsPositive".into()), vec![])],
|
||||||
Box::new(SolvedType::Wildcard),
|
Box::new(SolvedType::Wildcard),
|
||||||
);
|
);
|
||||||
|
|
||||||
add_top_level_function_type!(
|
add_top_level_function_type!(
|
||||||
Symbol::NUM_LOG,
|
Symbol::NUM_LOG_CHECKED,
|
||||||
vec![float_type(flex(TVAR1))],
|
vec![float_type(flex(TVAR1))],
|
||||||
Box::new(result_type(float_type(flex(TVAR1)), log_needs_positive)),
|
Box::new(result_type(float_type(flex(TVAR1)), log_needs_positive)),
|
||||||
);
|
);
|
||||||
|
|
|
@ -203,9 +203,14 @@ pub fn builtin_defs_map(symbol: Symbol, var_store: &mut VarStore) -> Option<Def>
|
||||||
NUM_ABS => num_abs,
|
NUM_ABS => num_abs,
|
||||||
NUM_NEG => num_neg,
|
NUM_NEG => num_neg,
|
||||||
NUM_REM => num_rem,
|
NUM_REM => num_rem,
|
||||||
|
NUM_REM_CHECKED => num_rem_checked,
|
||||||
|
NUM_MOD => num_mod,
|
||||||
|
NUM_MOD_CHECKED => num_mod_checked,
|
||||||
NUM_IS_MULTIPLE_OF => num_is_multiple_of,
|
NUM_IS_MULTIPLE_OF => num_is_multiple_of,
|
||||||
NUM_SQRT => num_sqrt,
|
NUM_SQRT => num_sqrt,
|
||||||
|
NUM_SQRT_CHECKED => num_sqrt_checked,
|
||||||
NUM_LOG => num_log,
|
NUM_LOG => num_log,
|
||||||
|
NUM_LOG_CHECKED => num_log_checked,
|
||||||
NUM_ROUND => num_round,
|
NUM_ROUND => num_round,
|
||||||
NUM_IS_ODD => num_is_odd,
|
NUM_IS_ODD => num_is_odd,
|
||||||
NUM_IS_EVEN => num_is_even,
|
NUM_IS_EVEN => num_is_even,
|
||||||
|
@ -730,6 +735,23 @@ fn bool_and(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn num_unaryop(symbol: Symbol, var_store: &mut VarStore, op: LowLevel) -> Def {
|
||||||
|
let num_var = var_store.fresh();
|
||||||
|
let body = RunLowLevel {
|
||||||
|
op,
|
||||||
|
args: vec![(num_var, Var(Symbol::ARG_1))],
|
||||||
|
ret_var: num_var,
|
||||||
|
};
|
||||||
|
|
||||||
|
defn(
|
||||||
|
symbol,
|
||||||
|
vec![(num_var, Symbol::ARG_1)],
|
||||||
|
var_store,
|
||||||
|
body,
|
||||||
|
num_var,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/// Num a, Num a -> Num a
|
/// Num a, Num a -> Num a
|
||||||
fn num_binop(symbol: Symbol, var_store: &mut VarStore, op: LowLevel) -> Def {
|
fn num_binop(symbol: Symbol, var_store: &mut VarStore, op: LowLevel) -> Def {
|
||||||
let num_var = var_store.fresh();
|
let num_var = var_store.fresh();
|
||||||
|
@ -1169,8 +1191,13 @@ fn num_to_float(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Num.sqrt : Float -> Result Float [ SqrtOfNegative ]*
|
/// Num.sqrt : Float a -> Float a
|
||||||
fn num_sqrt(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
fn num_sqrt(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
|
num_unaryop(symbol, var_store, LowLevel::NumSqrtUnchecked)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Num.sqrtChecked : Float a -> Result (Float a) [ SqrtOfNegative ]*
|
||||||
|
fn num_sqrt_checked(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
let bool_var = var_store.fresh();
|
let bool_var = var_store.fresh();
|
||||||
let float_var = var_store.fresh();
|
let float_var = var_store.fresh();
|
||||||
let unbound_zero_var = var_store.fresh();
|
let unbound_zero_var = var_store.fresh();
|
||||||
|
@ -1218,8 +1245,13 @@ fn num_sqrt(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Num.log : Float -> Result Float [ LogNeedsPositive ]*
|
/// Num.log : Float a -> Float a
|
||||||
fn num_log(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
fn num_log(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
|
num_unaryop(symbol, var_store, LowLevel::NumLogUnchecked)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Num.logChecked : Float a -> Result (Float a) [ LogNeedsPositive ]*
|
||||||
|
fn num_log_checked(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
let bool_var = var_store.fresh();
|
let bool_var = var_store.fresh();
|
||||||
let float_var = var_store.fresh();
|
let float_var = var_store.fresh();
|
||||||
let unbound_zero_var = var_store.fresh();
|
let unbound_zero_var = var_store.fresh();
|
||||||
|
@ -4196,8 +4228,13 @@ fn set_walk(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Num.rem : Int a, Int a -> Result (Int a) [ DivByZero ]*
|
/// Num.rem : Int a, Int a -> Int a
|
||||||
fn num_rem(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
fn num_rem(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
|
num_binop(symbol, var_store, LowLevel::NumRemUnchecked)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Num.remChecked : Int a, Int a -> Result (Int a) [ DivByZero ]*
|
||||||
|
fn num_rem_checked(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
let num_var = var_store.fresh();
|
let num_var = var_store.fresh();
|
||||||
let unbound_zero_var = var_store.fresh();
|
let unbound_zero_var = var_store.fresh();
|
||||||
let bool_var = var_store.fresh();
|
let bool_var = var_store.fresh();
|
||||||
|
@ -4255,6 +4292,70 @@ fn num_rem(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Num.mod : Int a, Int a -> Int a
|
||||||
|
fn num_mod(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
|
num_binop(symbol, var_store, LowLevel::NumModUnchecked)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Num.modChecked : Int a, Int a -> Result (Int a) [ DivByZero ]*
|
||||||
|
fn num_mod_checked(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
|
let num_var = var_store.fresh();
|
||||||
|
let unbound_zero_var = var_store.fresh();
|
||||||
|
let bool_var = var_store.fresh();
|
||||||
|
let ret_var = var_store.fresh();
|
||||||
|
|
||||||
|
let body = If {
|
||||||
|
branch_var: ret_var,
|
||||||
|
cond_var: bool_var,
|
||||||
|
branches: vec![(
|
||||||
|
// if condition
|
||||||
|
no_region(
|
||||||
|
// Num.isNeq arg2 0
|
||||||
|
RunLowLevel {
|
||||||
|
op: LowLevel::NotEq,
|
||||||
|
args: vec![
|
||||||
|
(num_var, Var(Symbol::ARG_2)),
|
||||||
|
(num_var, num(unbound_zero_var, 0, num_no_bound())),
|
||||||
|
],
|
||||||
|
ret_var: bool_var,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
// arg1 was not zero
|
||||||
|
no_region(
|
||||||
|
// Ok (Int.#modUnsafe arg1 arg2)
|
||||||
|
tag(
|
||||||
|
"Ok",
|
||||||
|
vec![
|
||||||
|
// Num.#modUnsafe arg1 arg2
|
||||||
|
RunLowLevel {
|
||||||
|
op: LowLevel::NumModUnchecked,
|
||||||
|
args: vec![
|
||||||
|
(num_var, Var(Symbol::ARG_1)),
|
||||||
|
(num_var, Var(Symbol::ARG_2)),
|
||||||
|
],
|
||||||
|
ret_var: num_var,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
var_store,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)],
|
||||||
|
final_else: Box::new(no_region(tag(
|
||||||
|
"Err",
|
||||||
|
vec![tag("DivByZero", Vec::new(), var_store)],
|
||||||
|
var_store,
|
||||||
|
))),
|
||||||
|
};
|
||||||
|
|
||||||
|
defn(
|
||||||
|
symbol,
|
||||||
|
vec![(num_var, Symbol::ARG_1), (num_var, Symbol::ARG_2)],
|
||||||
|
var_store,
|
||||||
|
body,
|
||||||
|
ret_var,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/// Num.isMultipleOf : Int a, Int a -> Bool
|
/// Num.isMultipleOf : Int a, Int a -> Bool
|
||||||
fn num_is_multiple_of(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
fn num_is_multiple_of(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
lowlevel_2(symbol, LowLevel::NumIsMultipleOf, var_store)
|
lowlevel_2(symbol, LowLevel::NumIsMultipleOf, var_store)
|
||||||
|
|
|
@ -5814,9 +5814,9 @@ fn run_low_level<'a, 'ctx, 'env>(
|
||||||
}
|
}
|
||||||
|
|
||||||
NumAdd | NumSub | NumMul | NumLt | NumLte | NumGt | NumGte | NumRemUnchecked
|
NumAdd | NumSub | NumMul | NumLt | NumLte | NumGt | NumGte | NumRemUnchecked
|
||||||
| NumIsMultipleOf | NumAddWrap | NumAddChecked | NumAddSaturated | NumDivUnchecked
|
| NumModUnchecked | NumIsMultipleOf | NumAddWrap | NumAddChecked | NumAddSaturated
|
||||||
| NumDivCeilUnchecked | NumPow | NumPowInt | NumSubWrap | NumSubChecked
|
| NumDivUnchecked | NumDivCeilUnchecked | NumPow | NumPowInt | NumSubWrap
|
||||||
| NumSubSaturated | NumMulWrap | NumMulChecked => {
|
| NumSubChecked | NumSubSaturated | NumMulWrap | NumMulChecked => {
|
||||||
debug_assert_eq!(args.len(), 2);
|
debug_assert_eq!(args.len(), 2);
|
||||||
|
|
||||||
let (lhs_arg, lhs_layout) = load_symbol_and_layout(scope, &args[0]);
|
let (lhs_arg, lhs_layout) = load_symbol_and_layout(scope, &args[0]);
|
||||||
|
@ -6578,6 +6578,11 @@ fn build_int_binop<'a, 'ctx, 'env>(
|
||||||
bd.build_int_unsigned_rem(lhs, rhs, "rem_uint").into()
|
bd.build_int_unsigned_rem(lhs, rhs, "rem_uint").into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
NumModUnchecked => {
|
||||||
|
// there generally is not hardware support for flooring mod;
|
||||||
|
// it could probably be implemented in pure Roc in terms of Num.rem.
|
||||||
|
todo!("mod is not implemented")
|
||||||
|
}
|
||||||
NumIsMultipleOf => {
|
NumIsMultipleOf => {
|
||||||
// this builds the following construct
|
// this builds the following construct
|
||||||
//
|
//
|
||||||
|
@ -6908,7 +6913,6 @@ fn build_float_binop<'a, 'ctx, 'env>(
|
||||||
NumGte => bd.build_float_compare(OGE, lhs, rhs, "float_gte").into(),
|
NumGte => bd.build_float_compare(OGE, lhs, rhs, "float_gte").into(),
|
||||||
NumLt => bd.build_float_compare(OLT, lhs, rhs, "float_lt").into(),
|
NumLt => bd.build_float_compare(OLT, lhs, rhs, "float_lt").into(),
|
||||||
NumLte => bd.build_float_compare(OLE, lhs, rhs, "float_lte").into(),
|
NumLte => bd.build_float_compare(OLE, lhs, rhs, "float_lte").into(),
|
||||||
NumRemUnchecked => bd.build_float_rem(lhs, rhs, "rem_float").into(),
|
|
||||||
NumDivUnchecked => bd.build_float_div(lhs, rhs, "div_float").into(),
|
NumDivUnchecked => bd.build_float_div(lhs, rhs, "div_float").into(),
|
||||||
NumPow => env.call_intrinsic(&LLVM_POW[float_width], &[lhs.into(), rhs.into()]),
|
NumPow => env.call_intrinsic(&LLVM_POW[float_width], &[lhs.into(), rhs.into()]),
|
||||||
_ => {
|
_ => {
|
||||||
|
|
|
@ -434,6 +434,11 @@ impl<'a> LowLevelCall<'a> {
|
||||||
_ => todo!("{:?} for {:?}", self.lowlevel, self.ret_layout),
|
_ => todo!("{:?} for {:?}", self.lowlevel, self.ret_layout),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
NumModUnchecked => {
|
||||||
|
// wasm does not provide a flooring modulo instruction,
|
||||||
|
// so it would need to be emulated.
|
||||||
|
todo!("{:?}", self.lowlevel)
|
||||||
|
}
|
||||||
NumIsMultipleOf => todo!("{:?}", self.lowlevel),
|
NumIsMultipleOf => todo!("{:?}", self.lowlevel),
|
||||||
NumAbs => {
|
NumAbs => {
|
||||||
self.load_args(backend);
|
self.load_args(backend);
|
||||||
|
|
|
@ -85,6 +85,7 @@ pub enum LowLevel {
|
||||||
NumDivUnchecked,
|
NumDivUnchecked,
|
||||||
NumDivCeilUnchecked,
|
NumDivCeilUnchecked,
|
||||||
NumRemUnchecked,
|
NumRemUnchecked,
|
||||||
|
NumModUnchecked,
|
||||||
NumIsMultipleOf,
|
NumIsMultipleOf,
|
||||||
NumAbs,
|
NumAbs,
|
||||||
NumNeg,
|
NumNeg,
|
||||||
|
@ -293,14 +294,19 @@ impl LowLevelWrapperType {
|
||||||
Symbol::NUM_DIV_FLOAT_CHECKED => WrapperIsRequired,
|
Symbol::NUM_DIV_FLOAT_CHECKED => WrapperIsRequired,
|
||||||
Symbol::NUM_DIV_CEIL => CanBeReplacedBy(NumDivCeilUnchecked),
|
Symbol::NUM_DIV_CEIL => CanBeReplacedBy(NumDivCeilUnchecked),
|
||||||
Symbol::NUM_DIV_CEIL_CHECKED => WrapperIsRequired,
|
Symbol::NUM_DIV_CEIL_CHECKED => WrapperIsRequired,
|
||||||
Symbol::NUM_REM => WrapperIsRequired,
|
Symbol::NUM_REM => CanBeReplacedBy(NumRemUnchecked),
|
||||||
|
Symbol::NUM_REM_CHECKED => WrapperIsRequired,
|
||||||
|
Symbol::NUM_MOD => CanBeReplacedBy(NumModUnchecked),
|
||||||
|
Symbol::NUM_MOD_CHECKED => WrapperIsRequired,
|
||||||
Symbol::NUM_IS_MULTIPLE_OF => CanBeReplacedBy(NumIsMultipleOf),
|
Symbol::NUM_IS_MULTIPLE_OF => CanBeReplacedBy(NumIsMultipleOf),
|
||||||
Symbol::NUM_ABS => CanBeReplacedBy(NumAbs),
|
Symbol::NUM_ABS => CanBeReplacedBy(NumAbs),
|
||||||
Symbol::NUM_NEG => CanBeReplacedBy(NumNeg),
|
Symbol::NUM_NEG => CanBeReplacedBy(NumNeg),
|
||||||
Symbol::NUM_SIN => CanBeReplacedBy(NumSin),
|
Symbol::NUM_SIN => CanBeReplacedBy(NumSin),
|
||||||
Symbol::NUM_COS => CanBeReplacedBy(NumCos),
|
Symbol::NUM_COS => CanBeReplacedBy(NumCos),
|
||||||
Symbol::NUM_SQRT => WrapperIsRequired,
|
Symbol::NUM_SQRT => CanBeReplacedBy(NumSqrtUnchecked),
|
||||||
Symbol::NUM_LOG => WrapperIsRequired,
|
Symbol::NUM_SQRT_CHECKED => WrapperIsRequired,
|
||||||
|
Symbol::NUM_LOG => CanBeReplacedBy(NumLogUnchecked),
|
||||||
|
Symbol::NUM_LOG_CHECKED => WrapperIsRequired,
|
||||||
Symbol::NUM_ROUND => CanBeReplacedBy(NumRound),
|
Symbol::NUM_ROUND => CanBeReplacedBy(NumRound),
|
||||||
Symbol::NUM_TO_FLOAT => CanBeReplacedBy(NumToFloat),
|
Symbol::NUM_TO_FLOAT => CanBeReplacedBy(NumToFloat),
|
||||||
Symbol::NUM_POW => CanBeReplacedBy(NumPow),
|
Symbol::NUM_POW => CanBeReplacedBy(NumPow),
|
||||||
|
|
|
@ -950,8 +950,8 @@ define_builtins! {
|
||||||
41 NUM_DIV_FLOAT_CHECKED: "divChecked"
|
41 NUM_DIV_FLOAT_CHECKED: "divChecked"
|
||||||
42 NUM_DIV_FLOOR: "divFloor"
|
42 NUM_DIV_FLOOR: "divFloor"
|
||||||
43 NUM_DIV_FLOOR_CHECKED: "divFloorChecked"
|
43 NUM_DIV_FLOOR_CHECKED: "divFloorChecked"
|
||||||
44 NUM_MOD_INT: "modInt"
|
44 NUM_MOD: "mod"
|
||||||
45 NUM_MOD_INT_CHECKED: "modIntChecked"
|
45 NUM_MOD_CHECKED: "modChecked"
|
||||||
46 NUM_MOD_FLOAT: "modFloat"
|
46 NUM_MOD_FLOAT: "modFloat"
|
||||||
47 NUM_MOD_FLOAT_CHECKED: "modFloatChecked"
|
47 NUM_MOD_FLOAT_CHECKED: "modFloatChecked"
|
||||||
48 NUM_SQRT: "sqrt"
|
48 NUM_SQRT: "sqrt"
|
||||||
|
|
|
@ -994,10 +994,9 @@ pub fn lowlevel_borrow_signature(arena: &Bump, op: LowLevel) -> &[bool] {
|
||||||
And | Or | NumAdd | NumAddWrap | NumAddChecked | NumAddSaturated | NumSub | NumSubWrap
|
And | Or | NumAdd | NumAddWrap | NumAddChecked | NumAddSaturated | NumSub | NumSubWrap
|
||||||
| NumSubChecked | NumSubSaturated | NumMul | NumMulWrap | NumMulChecked | NumGt
|
| NumSubChecked | NumSubSaturated | NumMul | NumMulWrap | NumMulChecked | NumGt
|
||||||
| NumGte | NumLt | NumLte | NumCompare | NumDivUnchecked | NumDivCeilUnchecked
|
| NumGte | NumLt | NumLte | NumCompare | NumDivUnchecked | NumDivCeilUnchecked
|
||||||
| NumRemUnchecked | NumIsMultipleOf | NumPow | NumPowInt | NumBitwiseAnd
|
| NumRemUnchecked | NumModUnchecked | NumIsMultipleOf | NumPow | NumPowInt
|
||||||
| NumBitwiseXor | NumBitwiseOr | NumShiftLeftBy | NumShiftRightBy | NumShiftRightZfBy => {
|
| NumBitwiseAnd | NumBitwiseXor | NumBitwiseOr | NumShiftLeftBy | NumShiftRightBy
|
||||||
arena.alloc_slice_copy(&[irrelevant, irrelevant])
|
| NumShiftRightZfBy => arena.alloc_slice_copy(&[irrelevant, irrelevant]),
|
||||||
}
|
|
||||||
|
|
||||||
NumToStr | NumAbs | NumNeg | NumSin | NumCos | NumSqrtUnchecked | NumLogUnchecked
|
NumToStr | NumAbs | NumNeg | NumSin | NumCos | NumSqrtUnchecked | NumLogUnchecked
|
||||||
| NumRound | NumCeiling | NumFloor | NumToFloat | Not | NumIsFinite | NumAtan | NumAcos
|
| NumRound | NumCeiling | NumFloor | NumToFloat | Not | NumIsFinite | NumAtan | NumAcos
|
||||||
|
|
|
@ -144,6 +144,7 @@ enum FirstOrder {
|
||||||
NumCompare,
|
NumCompare,
|
||||||
NumDivUnchecked,
|
NumDivUnchecked,
|
||||||
NumRemUnchecked,
|
NumRemUnchecked,
|
||||||
|
NumModUnchecked,
|
||||||
NumIsMultipleOf,
|
NumIsMultipleOf,
|
||||||
NumAbs,
|
NumAbs,
|
||||||
NumNeg,
|
NumNeg,
|
||||||
|
|
|
@ -2534,7 +2534,7 @@ fn list_keep_oks() {
|
||||||
RocList<i64>
|
RocList<i64>
|
||||||
);
|
);
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
"List.keepOks [1,2] (\\x -> x % 2)",
|
"List.keepOks [1,2] (\\x -> Num.remChecked x 2)",
|
||||||
RocList::from_slice(&[1, 0]),
|
RocList::from_slice(&[1, 0]),
|
||||||
RocList<i64>
|
RocList<i64>
|
||||||
);
|
);
|
||||||
|
@ -2561,7 +2561,7 @@ fn list_keep_errs() {
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
List.keepErrs [0,1,2] (\x -> x % 0 |> Result.mapErr (\_ -> 32))
|
List.keepErrs [0,1,2] (\x -> Num.remChecked x 0 |> Result.mapErr (\_ -> 32))
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
RocList::from_slice(&[32, 32, 32]),
|
RocList::from_slice(&[32, 32, 32]),
|
||||||
|
|
|
@ -473,7 +473,7 @@ fn f64_sqrt() {
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
when Num.sqrt 100 is
|
when Num.sqrtChecked 100 is
|
||||||
Ok val -> val
|
Ok val -> val
|
||||||
Err _ -> -1
|
Err _ -> -1
|
||||||
"#
|
"#
|
||||||
|
@ -489,9 +489,7 @@ fn f64_log() {
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
when Num.log 7.38905609893 is
|
Num.log 7.38905609893
|
||||||
Ok val -> val
|
|
||||||
Err _ -> -1
|
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
1.999999999999912,
|
1.999999999999912,
|
||||||
|
@ -501,11 +499,11 @@ fn f64_log() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm"))]
|
#[cfg(any(feature = "gen-llvm"))]
|
||||||
fn f64_log_one() {
|
fn f64_log_checked_one() {
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
when Num.log 1 is
|
when Num.logChecked 1 is
|
||||||
Ok val -> val
|
Ok val -> val
|
||||||
Err _ -> -1
|
Err _ -> -1
|
||||||
"#
|
"#
|
||||||
|
@ -521,7 +519,7 @@ fn f64_sqrt_zero() {
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
when Num.sqrt 0 is
|
when Num.sqrtChecked 0 is
|
||||||
Ok val -> val
|
Ok val -> val
|
||||||
Err _ -> -1
|
Err _ -> -1
|
||||||
"#
|
"#
|
||||||
|
@ -533,11 +531,11 @@ fn f64_sqrt_zero() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm"))]
|
#[cfg(any(feature = "gen-llvm"))]
|
||||||
fn f64_sqrt_negative() {
|
fn f64_sqrt_checked_negative() {
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
when Num.sqrt -1 is
|
when Num.sqrtChecked -1 is
|
||||||
Err _ -> 42
|
Err _ -> 42
|
||||||
Ok val -> val
|
Ok val -> val
|
||||||
"#
|
"#
|
||||||
|
@ -549,11 +547,11 @@ fn f64_sqrt_negative() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm"))]
|
#[cfg(any(feature = "gen-llvm"))]
|
||||||
fn f64_log_zero() {
|
fn f64_log_checked_zero() {
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
when Num.log 0 is
|
when Num.logChecked 0 is
|
||||||
Err _ -> 42
|
Err _ -> 42
|
||||||
Ok val -> val
|
Ok val -> val
|
||||||
"#
|
"#
|
||||||
|
@ -569,13 +567,12 @@ fn f64_log_negative() {
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
when Num.log -1 is
|
Num.log -1
|
||||||
Err _ -> 42
|
|
||||||
Ok val -> val
|
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
42.0,
|
true,
|
||||||
f64
|
f64,
|
||||||
|
|f: f64| f.is_nan()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1082,9 +1079,7 @@ fn gen_rem_i64() {
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
when Num.rem 8 3 is
|
Num.rem 8 3
|
||||||
Ok val -> val
|
|
||||||
Err _ -> -1
|
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
2,
|
2,
|
||||||
|
@ -1094,11 +1089,11 @@ fn gen_rem_i64() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm"))]
|
#[cfg(any(feature = "gen-llvm"))]
|
||||||
fn gen_rem_div_by_zero_i64() {
|
fn gen_rem_checked_div_by_zero_i64() {
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
when Num.rem 8 0 is
|
when Num.remChecked 8 0 is
|
||||||
Err DivByZero -> 4
|
Err DivByZero -> 4
|
||||||
Ok _ -> -23
|
Ok _ -> -23
|
||||||
"#
|
"#
|
||||||
|
|
|
@ -41,7 +41,7 @@ Expr : [ Val I64, Var Str, Add Expr Expr, Mul Expr Expr, Pow Expr Expr, Ln Expr
|
||||||
|
|
||||||
divmod : I64, I64 -> Result { div : I64, mod : I64 } [ DivByZero ]*
|
divmod : I64, I64 -> Result { div : I64, mod : I64 } [ DivByZero ]*
|
||||||
divmod = \l, r ->
|
divmod = \l, r ->
|
||||||
when Pair (l // r) (l % r) is
|
when Pair (Num.divFloorChecked l r) (Num.remChecked l r) is
|
||||||
Pair div (Ok mod) ->
|
Pair div (Ok mod) ->
|
||||||
Ok { div, mod }
|
Ok { div, mod }
|
||||||
|
|
||||||
|
|
|
@ -23,12 +23,12 @@ makeMapHelp = \freq, n, m, acc ->
|
||||||
|
|
||||||
_ ->
|
_ ->
|
||||||
powerOf10 =
|
powerOf10 =
|
||||||
(n % 10 |> resultWithDefault 0) == 0
|
n % 10 == 0
|
||||||
|
|
||||||
m1 = insert m n powerOf10
|
m1 = insert m n powerOf10
|
||||||
|
|
||||||
isFrequency =
|
isFrequency =
|
||||||
(n % freq |> resultWithDefault 0) == 0
|
n % freq == 0
|
||||||
|
|
||||||
x = (if isFrequency then Cons m1 acc else acc)
|
x = (if isFrequency then Cons m1 acc else acc)
|
||||||
|
|
||||||
|
@ -43,15 +43,6 @@ fold = \f, tree, b ->
|
||||||
Node _ l k v r ->
|
Node _ l k v r ->
|
||||||
fold f r (f k v (fold f l b))
|
fold f r (f k v (fold f l b))
|
||||||
|
|
||||||
resultWithDefault : Result a e, a -> a
|
|
||||||
resultWithDefault = \res, default ->
|
|
||||||
when res is
|
|
||||||
Ok v ->
|
|
||||||
v
|
|
||||||
|
|
||||||
Err _ ->
|
|
||||||
default
|
|
||||||
|
|
||||||
main : Task.Task {} []
|
main : Task.Task {} []
|
||||||
main =
|
main =
|
||||||
Task.after
|
Task.after
|
||||||
|
|
|
@ -56,7 +56,7 @@ fn float_addition() {
|
||||||
#[cfg(not(feature = "wasm"))]
|
#[cfg(not(feature = "wasm"))]
|
||||||
#[test]
|
#[test]
|
||||||
fn num_rem() {
|
fn num_rem() {
|
||||||
expect_success("299 % 10", "Ok 9 : Result (Int *) [ DivByZero ]*");
|
expect_success("299 % 10", "9 : Int *");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "wasm"))]
|
#[cfg(not(feature = "wasm"))]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue