mirror of
https://github.com/roc-lang/roc.git
synced 2024-09-21 07:49:17 +03:00
Merge branch 'trunk' into drop-libcxx
This commit is contained in:
commit
cd27c4c7d6
@ -79,6 +79,8 @@ comptime {
|
||||
exportNumFn(num.powInt, "pow_int");
|
||||
exportNumFn(num.acos, "acos");
|
||||
exportNumFn(num.asin, "asin");
|
||||
exportNumFn(num.bytesToU16C, "bytes_to_u16");
|
||||
exportNumFn(num.bytesToU32C, "bytes_to_u32");
|
||||
exportNumFn(num.round, "round");
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
const std = @import("std");
|
||||
const always_inline = std.builtin.CallOptions.Modifier.always_inline;
|
||||
const math = std.math;
|
||||
const RocList = @import("list.zig").RocList;
|
||||
|
||||
pub fn atan(num: f64) callconv(.C) f64 {
|
||||
return @call(.{ .modifier = always_inline }, math.atan, .{num});
|
||||
@ -22,6 +23,24 @@ pub fn asin(num: f64) callconv(.C) f64 {
|
||||
return @call(.{ .modifier = always_inline }, math.asin, .{num});
|
||||
}
|
||||
|
||||
pub fn bytesToU16C(arg: RocList, position: usize) callconv(.C) u16 {
|
||||
return @call(.{ .modifier = always_inline }, bytesToU16, .{ arg, position });
|
||||
}
|
||||
|
||||
fn bytesToU16(arg: RocList, position: usize) u16 {
|
||||
const bytes = @ptrCast([*]const u8, arg.bytes);
|
||||
return @bitCast(u16, [_]u8{ bytes[position], bytes[position + 1] });
|
||||
}
|
||||
|
||||
pub fn bytesToU32C(arg: RocList, position: usize) callconv(.C) u32 {
|
||||
return @call(.{ .modifier = always_inline }, bytesToU32, .{ arg, position });
|
||||
}
|
||||
|
||||
fn bytesToU32(arg: RocList, position: usize) u32 {
|
||||
const bytes = @ptrCast([*]const u8, arg.bytes);
|
||||
return @bitCast(u32, [_]u8{ bytes[position], bytes[position + 1], bytes[position + 2], bytes[position + 3] });
|
||||
}
|
||||
|
||||
pub fn round(num: f64) callconv(.C) i64 {
|
||||
return @floatToInt(i32, (@round(num)));
|
||||
}
|
||||
|
@ -8,6 +8,8 @@ pub const NUM_ACOS: &str = "roc_builtins.num.acos";
|
||||
pub const NUM_ATAN: &str = "roc_builtins.num.atan";
|
||||
pub const NUM_IS_FINITE: &str = "roc_builtins.num.is_finite";
|
||||
pub const NUM_POW_INT: &str = "roc_builtins.num.pow_int";
|
||||
pub const NUM_BYTES_TO_U16: &str = "roc_builtins.num.bytes_to_u16";
|
||||
pub const NUM_BYTES_TO_U32: &str = "roc_builtins.num.bytes_to_u32";
|
||||
pub const NUM_ROUND: &str = "roc_builtins.num.round";
|
||||
|
||||
pub const STR_INIT: &str = "roc_builtins.str.init";
|
||||
|
@ -4,8 +4,8 @@ use roc_module::symbol::Symbol;
|
||||
use roc_region::all::Region;
|
||||
use roc_types::builtin_aliases::{
|
||||
bool_type, dict_type, float_type, i128_type, int_type, list_type, nat_type, num_type,
|
||||
ordering_type, result_type, set_type, str_type, str_utf8_byte_problem_type, u32_type, u64_type,
|
||||
u8_type,
|
||||
ordering_type, result_type, set_type, str_type, str_utf8_byte_problem_type, u16_type, u32_type,
|
||||
u64_type, u8_type,
|
||||
};
|
||||
use roc_types::solved_types::SolvedType;
|
||||
use roc_types::subs::VarId;
|
||||
@ -501,6 +501,32 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
|
||||
Box::new(float_type(flex(TVAR1))),
|
||||
);
|
||||
|
||||
// bytesToU16 : List U8, Nat -> Result U16 [ OutOfBounds ]
|
||||
{
|
||||
let position_out_of_bounds = SolvedType::TagUnion(
|
||||
vec![(TagName::Global("OutOfBounds".into()), vec![])],
|
||||
Box::new(SolvedType::Wildcard),
|
||||
);
|
||||
add_top_level_function_type!(
|
||||
Symbol::NUM_BYTES_TO_U16,
|
||||
vec![list_type(u8_type()), nat_type()],
|
||||
Box::new(result_type(u16_type(), position_out_of_bounds)),
|
||||
);
|
||||
}
|
||||
|
||||
// bytesToU32 : List U8, Nat -> Result U32 [ OutOfBounds ]
|
||||
{
|
||||
let position_out_of_bounds = SolvedType::TagUnion(
|
||||
vec![(TagName::Global("OutOfBounds".into()), vec![])],
|
||||
Box::new(SolvedType::Wildcard),
|
||||
);
|
||||
add_top_level_function_type!(
|
||||
Symbol::NUM_BYTES_TO_U32,
|
||||
vec![list_type(u8_type()), nat_type()],
|
||||
Box::new(result_type(u32_type(), position_out_of_bounds)),
|
||||
);
|
||||
}
|
||||
|
||||
// Bool module
|
||||
|
||||
// and : Bool, Bool -> Bool
|
||||
|
@ -161,6 +161,8 @@ pub fn builtin_defs_map(symbol: Symbol, var_store: &mut VarStore) -> Option<Def>
|
||||
NUM_ATAN => num_atan,
|
||||
NUM_ACOS => num_acos,
|
||||
NUM_ASIN => num_asin,
|
||||
NUM_BYTES_TO_U16 => num_bytes_to_u16,
|
||||
NUM_BYTES_TO_U32 => num_bytes_to_u32,
|
||||
NUM_MAX_INT => num_max_int,
|
||||
NUM_MIN_INT => num_min_int,
|
||||
NUM_BITWISE_AND => num_bitwise_and,
|
||||
@ -1088,6 +1090,16 @@ fn num_asin(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||
)
|
||||
}
|
||||
|
||||
/// Num.bytesToU16 : List U8, Nat -> Result U16 [ OutOfBounds ]
|
||||
fn num_bytes_to_u16(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||
num_bytes_to(symbol, var_store, 1, LowLevel::NumBytesToU16)
|
||||
}
|
||||
|
||||
/// Num.bytesToU32 : List U8, Nat -> Result U32 [ OutOfBounds ]
|
||||
fn num_bytes_to_u32(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||
num_bytes_to(symbol, var_store, 3, LowLevel::NumBytesToU32)
|
||||
}
|
||||
|
||||
/// Num.bitwiseAnd : Int a, Int a -> Int a
|
||||
fn num_bitwise_and(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||
num_binop(symbol, var_store, LowLevel::NumBitwiseAnd)
|
||||
@ -3359,6 +3371,97 @@ fn defn(
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn num_bytes_to(symbol: Symbol, var_store: &mut VarStore, offset: i64, low_level: LowLevel) -> Def {
|
||||
let len_var = var_store.fresh();
|
||||
let list_var = var_store.fresh();
|
||||
let elem_var = var_store.fresh();
|
||||
|
||||
let ret_var = var_store.fresh();
|
||||
let bool_var = var_store.fresh();
|
||||
let add_var = var_store.fresh();
|
||||
let cast_var = var_store.fresh();
|
||||
|
||||
// Perform a bounds check. If it passes, run LowLevel::low_level
|
||||
let body = If {
|
||||
cond_var: bool_var,
|
||||
branch_var: var_store.fresh(),
|
||||
branches: vec![(
|
||||
// if-condition
|
||||
no_region(
|
||||
// index + offset < List.len list
|
||||
RunLowLevel {
|
||||
op: LowLevel::NumLt,
|
||||
args: vec![
|
||||
(
|
||||
len_var,
|
||||
RunLowLevel {
|
||||
op: LowLevel::NumAdd,
|
||||
args: vec![
|
||||
(add_var, Var(Symbol::ARG_2)),
|
||||
(
|
||||
add_var,
|
||||
RunLowLevel {
|
||||
ret_var: cast_var,
|
||||
args: vec![(cast_var, Num(var_store.fresh(), offset))],
|
||||
op: LowLevel::NumIntCast,
|
||||
},
|
||||
),
|
||||
],
|
||||
ret_var: add_var,
|
||||
},
|
||||
),
|
||||
(
|
||||
len_var,
|
||||
RunLowLevel {
|
||||
op: LowLevel::ListLen,
|
||||
args: vec![(list_var, Var(Symbol::ARG_1))],
|
||||
ret_var: len_var,
|
||||
},
|
||||
),
|
||||
],
|
||||
ret_var: bool_var,
|
||||
},
|
||||
),
|
||||
// then-branch
|
||||
no_region(
|
||||
// Ok
|
||||
tag(
|
||||
"Ok",
|
||||
vec![RunLowLevel {
|
||||
op: low_level,
|
||||
args: vec![
|
||||
(list_var, Var(Symbol::ARG_1)),
|
||||
(len_var, Var(Symbol::ARG_2)),
|
||||
],
|
||||
ret_var: elem_var,
|
||||
}],
|
||||
var_store,
|
||||
),
|
||||
),
|
||||
)],
|
||||
final_else: Box::new(
|
||||
// else-branch
|
||||
no_region(
|
||||
// Err
|
||||
tag(
|
||||
"Err",
|
||||
vec![tag("OutOfBounds", Vec::new(), var_store)],
|
||||
var_store,
|
||||
),
|
||||
),
|
||||
),
|
||||
};
|
||||
|
||||
defn(
|
||||
symbol,
|
||||
vec![(list_var, Symbol::ARG_1), (len_var, Symbol::ARG_2)],
|
||||
var_store,
|
||||
body,
|
||||
ret_var,
|
||||
)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn defn_help(
|
||||
fn_name: Symbol,
|
||||
|
@ -4746,6 +4746,42 @@ fn run_low_level<'a, 'ctx, 'env>(
|
||||
}
|
||||
}
|
||||
}
|
||||
NumBytesToU16 => {
|
||||
debug_assert_eq!(args.len(), 2);
|
||||
let list = load_symbol(scope, &args[0]).into_struct_value();
|
||||
let position = load_symbol(scope, &args[1]);
|
||||
call_bitcode_fn(
|
||||
env,
|
||||
&[
|
||||
complex_bitcast(
|
||||
env.builder,
|
||||
list.into(),
|
||||
env.context.i128_type().into(),
|
||||
"to_i128",
|
||||
),
|
||||
position,
|
||||
],
|
||||
bitcode::NUM_BYTES_TO_U16,
|
||||
)
|
||||
}
|
||||
NumBytesToU32 => {
|
||||
debug_assert_eq!(args.len(), 2);
|
||||
let list = load_symbol(scope, &args[0]).into_struct_value();
|
||||
let position = load_symbol(scope, &args[1]);
|
||||
call_bitcode_fn(
|
||||
env,
|
||||
&[
|
||||
complex_bitcast(
|
||||
env.builder,
|
||||
list.into(),
|
||||
env.context.i128_type().into(),
|
||||
"to_i128",
|
||||
),
|
||||
position,
|
||||
],
|
||||
bitcode::NUM_BYTES_TO_U32,
|
||||
)
|
||||
}
|
||||
NumCompare => {
|
||||
use inkwell::FloatPredicate;
|
||||
|
||||
|
@ -87,6 +87,8 @@ pub enum LowLevel {
|
||||
NumAtan,
|
||||
NumAcos,
|
||||
NumAsin,
|
||||
NumBytesToU16,
|
||||
NumBytesToU32,
|
||||
NumBitwiseAnd,
|
||||
NumBitwiseXor,
|
||||
NumBitwiseOr,
|
||||
@ -122,10 +124,9 @@ impl LowLevel {
|
||||
| NumRemUnchecked | NumIsMultipleOf | NumAbs | NumNeg | NumSin | NumCos
|
||||
| NumSqrtUnchecked | NumLogUnchecked | NumRound | NumToFloat | NumPow | NumCeiling
|
||||
| NumPowInt | NumFloor | NumIsFinite | NumAtan | NumAcos | NumAsin | NumBitwiseAnd
|
||||
| NumBitwiseXor | NumBitwiseOr | NumShiftLeftBy | NumShiftRightBy
|
||||
| NumShiftRightZfBy | NumIntCast | Eq | NotEq | And | Or | Not | Hash | ExpectTrue => {
|
||||
false
|
||||
}
|
||||
| NumBitwiseXor | NumBitwiseOr | NumShiftLeftBy | NumShiftRightBy | NumBytesToU16
|
||||
| NumBytesToU32 | NumShiftRightZfBy | NumIntCast | Eq | NotEq | And | Or | Not
|
||||
| Hash | ExpectTrue => false,
|
||||
|
||||
ListMap | ListMap2 | ListMap3 | ListMapWithIndex | ListKeepIf | ListWalk
|
||||
| ListWalkUntil | ListWalkBackwards | ListKeepOks | ListKeepErrs | ListSortWith
|
||||
|
@ -891,7 +891,9 @@ define_builtins! {
|
||||
100 NUM_AT_DECIMAL: "@Decimal"
|
||||
101 NUM_DECIMAL: "Decimal" imported
|
||||
102 NUM_DEC: "Dec" imported // the Num.Dectype alias
|
||||
|
||||
103 NUM_BYTES_TO_U16: "bytesToU16"
|
||||
104 NUM_BYTES_TO_U32: "bytesToU32"
|
||||
105 NUM_CAST_TO_NAT: "#castToNat"
|
||||
}
|
||||
2 BOOL: "Bool" => {
|
||||
0 BOOL_BOOL: "Bool" imported // the Bool.Bool type alias
|
||||
|
@ -1009,6 +1009,8 @@ pub fn lowlevel_borrow_signature(arena: &Bump, op: LowLevel) -> &[bool] {
|
||||
NumAbs | NumNeg | NumSin | NumCos | NumSqrtUnchecked | NumLogUnchecked | NumRound
|
||||
| NumCeiling | NumFloor | NumToFloat | Not | NumIsFinite | NumAtan | NumAcos | NumAsin
|
||||
| NumIntCast => arena.alloc_slice_copy(&[irrelevant]),
|
||||
NumBytesToU16 => arena.alloc_slice_copy(&[borrowed, irrelevant]),
|
||||
NumBytesToU32 => arena.alloc_slice_copy(&[borrowed, irrelevant]),
|
||||
StrStartsWith | StrEndsWith => arena.alloc_slice_copy(&[owned, borrowed]),
|
||||
StrStartsWithCodePt => arena.alloc_slice_copy(&[borrowed, irrelevant]),
|
||||
StrFromUtf8 => arena.alloc_slice_copy(&[owned]),
|
||||
|
@ -1624,4 +1624,158 @@ mod gen_num {
|
||||
// overflow
|
||||
assert_evals_to!("Num.isMultipleOf -9223372036854775808 -1", true, bool);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bytes_to_u16_clearly_out_of_bounds() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
bytes = Str.toUtf8 "hello"
|
||||
when Num.bytesToU16 bytes 234 is
|
||||
Ok v -> v
|
||||
Err OutOfBounds -> 1
|
||||
"#
|
||||
),
|
||||
1,
|
||||
u16
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bytes_to_u16_subtly_out_of_bounds() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
bytes = Str.toUtf8 "hello"
|
||||
when Num.bytesToU16 bytes 4 is
|
||||
Ok v -> v
|
||||
Err OutOfBounds -> 1
|
||||
"#
|
||||
),
|
||||
1,
|
||||
u16
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bytes_to_u32_clearly_out_of_bounds() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
bytes = Str.toUtf8 "hello"
|
||||
when Num.bytesToU32 bytes 234 is
|
||||
Ok v -> v
|
||||
Err OutOfBounds -> 1
|
||||
"#
|
||||
),
|
||||
1,
|
||||
u32
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bytes_to_u32_subtly_out_of_bounds() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
bytes = Str.toUtf8 "hello"
|
||||
when Num.bytesToU32 bytes 2 is
|
||||
Ok v -> v
|
||||
Err OutOfBounds -> 1
|
||||
"#
|
||||
),
|
||||
1,
|
||||
u32
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bytes_to_u16_max_u8s() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
when Num.bytesToU16 [255, 255] 0 is
|
||||
Ok v -> v
|
||||
Err OutOfBounds -> 1
|
||||
"#
|
||||
),
|
||||
65535,
|
||||
u16
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bytes_to_u16_min_u8s() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
when Num.bytesToU16 [0, 0] 0 is
|
||||
Ok v -> v
|
||||
Err OutOfBounds -> 1
|
||||
"#
|
||||
),
|
||||
0,
|
||||
u16
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bytes_to_u16_random_u8s() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
when Num.bytesToU16 [164, 215] 0 is
|
||||
Ok v -> v
|
||||
Err OutOfBounds -> 1
|
||||
"#
|
||||
),
|
||||
55_204,
|
||||
u16
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bytes_to_u32_min_u8s() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
when Num.bytesToU32 [0, 0, 0, 0] 0 is
|
||||
Ok v -> v
|
||||
Err OutOfBounds -> 1
|
||||
"#
|
||||
),
|
||||
0,
|
||||
u32
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bytes_to_u32_max_u8s() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
when Num.bytesToU32 [255, 255, 255, 255] 0 is
|
||||
Ok v -> v
|
||||
Err OutOfBounds -> 1
|
||||
"#
|
||||
),
|
||||
4_294_967_295,
|
||||
u32
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bytes_to_u32_random_u8s() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
when Num.bytesToU32 [252, 124, 128, 121] 0 is
|
||||
Ok v -> v
|
||||
Err OutOfBounds -> 1
|
||||
"#
|
||||
),
|
||||
2_038_463_740,
|
||||
u32
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -521,6 +521,16 @@ pub fn u8_type() -> SolvedType {
|
||||
)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn u16_type() -> SolvedType {
|
||||
SolvedType::Alias(
|
||||
Symbol::NUM_U16,
|
||||
vec![],
|
||||
vec![],
|
||||
Box::new(int_alias_content(unsigned16_type())),
|
||||
)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn binary64_type() -> SolvedType {
|
||||
SolvedType::Alias(
|
||||
|
Loading…
Reference in New Issue
Block a user