///|
fn int64_max() -> Int64 {
9223372036854775807L
}
///|
fn int64_min() -> Int64 {
-9223372036854775807L - 1L
}
///|
fn uint64_max() -> UInt64 {
18446744073709551615UL
}
///|
fn safe_negate_int(value : Int64, span : SourceSpan) -> Value raise EvalError {
if value == int64_min() {
raise NumericOverflow(span~)
}
Value::Int(-value)
}
///|
fn safe_add_int(
left : Int64,
right : Int64,
span : SourceSpan,
) -> Value raise EvalError {
if (right > 0L && left > int64_max() - right) ||
(right < 0L && left < int64_min() - right) {
raise NumericOverflow(span~)
}
Value::Int(left + right)
}
///|
fn safe_add_uint(
left : UInt64,
right : UInt64,
span : SourceSpan,
) -> Value raise EvalError {
if left > uint64_max() - right {
raise NumericOverflow(span~)
}
Value::UInt(left + right)
}
///|
fn safe_subtract_int(
left : Int64,
right : Int64,
span : SourceSpan,
) -> Value raise EvalError {
if (right < 0L && left > int64_max() + right) ||
(right > 0L && left < int64_min() + right) {
raise NumericOverflow(span~)
}
Value::Int(left - right)
}
///|
fn safe_subtract_uint(
left : UInt64,
right : UInt64,
span : SourceSpan,
) -> Value raise EvalError {
if left < right {
raise NumericOverflow(span~)
}
Value::UInt(left - right)
}
///|
fn int_multiply_overflows(left : Int64, right : Int64) -> Bool {
if left == 0L || right == 0L {
return false
}
if (left == int64_min() && right == -1L) ||
(right == int64_min() && left == -1L) {
return true
}
if left > 0L {
if right > 0L {
left > int64_max() / right
} else {
right < int64_min() / left
}
} else if right > 0L {
left < int64_min() / right
} else {
right < int64_max() / left
}
}
///|
fn safe_multiply_int(
left : Int64,
right : Int64,
span : SourceSpan,
) -> Value raise EvalError {
if int_multiply_overflows(left, right) {
raise NumericOverflow(span~)
}
Value::Int(left * right)
}
///|
fn safe_multiply_uint(
left : UInt64,
right : UInt64,
span : SourceSpan,
) -> Value raise EvalError {
if right != 0UL && left > uint64_max() / right {
raise NumericOverflow(span~)
}
Value::UInt(left * right)
}
///|
fn safe_divide_int(
left : Int64,
right : Int64,
span : SourceSpan,
) -> Value raise EvalError {
if right == 0L {
raise DivisionByZero(span~)
}
if left == int64_min() && right == -1L {
raise NumericOverflow(span~)
}
Value::Int(left / right)
}
///|
fn safe_modulo_int(
left : Int64,
right : Int64,
span : SourceSpan,
) -> Value raise EvalError {
if right == 0L {
raise DivisionByZero(span~)
}
if left == int64_min() && right == -1L {
return Value::Int(0L)
}
Value::Int(left % right)
}