mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-04 12:18:19 +00:00
new approach for defining our builtins
This commit is contained in:
parent
98c55ba30c
commit
41768bfa97
11 changed files with 450 additions and 8 deletions
|
@ -68,14 +68,27 @@ interface Dict
|
|||
## `fn dict1 == fn dict2` also being `True`, even if `fn` relies on the dictionary's ordering.
|
||||
## An empty dictionary.
|
||||
empty : Dict k v
|
||||
single : k, v -> Dict k v
|
||||
get : Dict k v, k -> Result v [KeyNotFound]*
|
||||
get = \dict, key ->
|
||||
result = getLowlevel dict key
|
||||
|
||||
when result.flag is
|
||||
True -> Ok result.value
|
||||
False -> Err KeyNotFound
|
||||
|
||||
getLowlevel : Dict k v, k -> { flag : Bool, value : v }
|
||||
|
||||
walk : Dict k v, state, (state, k, v -> state) -> state
|
||||
insert : Dict k v, k, v -> Dict k v
|
||||
len : Dict k v -> Nat
|
||||
remove : Dict k v, k -> Dict k v
|
||||
contains : Dict k v, k -> Bool
|
||||
|
||||
single : k, v -> Dict k v
|
||||
single = \key, value ->
|
||||
Dict.empty
|
||||
|> Dict.insert key value
|
||||
|
||||
## Returns a [List] of the dictionary's keys.
|
||||
keys : Dict k v -> List k
|
||||
|
||||
|
|
|
@ -717,6 +717,10 @@ takeLast = \list, outputLength ->
|
|||
|
||||
## Drops n elements from the beginning of the list.
|
||||
drop : List elem, Nat -> List elem
|
||||
drop = \list, n ->
|
||||
remaining = Num.subSaturated (List.len list) n
|
||||
|
||||
List.takeLast list remaining
|
||||
|
||||
## Drops the element at the given index from the list.
|
||||
##
|
||||
|
@ -835,6 +839,13 @@ intersperse = \list, sep ->
|
|||
## means if you give an index of 0, the `before` list will be empty and the
|
||||
## `others` list will have the same elements as the original list.)
|
||||
split : List elem, Nat -> { before : List elem, others : List elem }
|
||||
split = \elements, userSplitIndex ->
|
||||
length = List.len elements
|
||||
splitIndex = if length > userSplitIndex then userSplitIndex else length
|
||||
before = List.sublist elements { start: 0, len: splitIndex }
|
||||
others = List.sublist elements { start: splitIndex, len: length - splitIndex }
|
||||
|
||||
{ before, others }
|
||||
|
||||
## Primitive for iterating over a List, being able to decide at every element whether to continue
|
||||
iterate : List elem, s, (s, elem -> [Continue s, Break b]) -> [Continue s, Break b]
|
||||
|
|
|
@ -509,8 +509,28 @@ Dec : Num (FloatingPoint Decimal)
|
|||
toStr : Num * -> Str
|
||||
intCast : Int a -> Int b
|
||||
|
||||
bytesToU16Lowlevel : List U8, Nat -> U16
|
||||
bytesToU32Lowlevel : List U8, Nat -> U32
|
||||
|
||||
bytesToU16 : List U8, Nat -> Result U16 [OutOfBounds]
|
||||
bytesToU16 = \bytes, index ->
|
||||
# we need at least 1 more byte
|
||||
offset = 1
|
||||
|
||||
if index + offset < List.len bytes then
|
||||
Ok (bytesToU16Lowlevel bytes index)
|
||||
else
|
||||
Err OutOfBounds
|
||||
|
||||
bytesToU32 : List U8, Nat -> Result U32 [OutOfBounds]
|
||||
bytesToU32 = \bytes, index ->
|
||||
# we need at least 3 more bytes
|
||||
offset = 3
|
||||
|
||||
if index + offset < List.len bytes then
|
||||
Ok (bytesToU32Lowlevel bytes index)
|
||||
else
|
||||
Err OutOfBounds
|
||||
|
||||
compare : Num a, Num a -> [LT, EQ, GT]
|
||||
|
||||
|
@ -554,22 +574,27 @@ isGte : Num a, Num a -> Bool
|
|||
|
||||
## Returns `True` if the number is `0`, and `False` otherwise.
|
||||
isZero : Num a -> Bool
|
||||
isZero = \x -> x == 0
|
||||
|
||||
## A number is even if dividing it by 2 gives a remainder of 0.
|
||||
##
|
||||
## Examples of even numbers: 0, 2, 4, 6, 8, -2, -4, -6, -8
|
||||
isEven : Int a -> Bool
|
||||
isEven = \x -> Num.isMultipleOf x 2
|
||||
|
||||
## A number is odd if dividing it by 2 gives a remainder of 1.
|
||||
##
|
||||
## Examples of odd numbers: 1, 3, 5, 7, -1, -3, -5, -7
|
||||
isOdd : Int a -> Bool
|
||||
isOdd = \x -> Bool.not (Num.isMultipleOf x 2)
|
||||
|
||||
## Positive numbers are greater than `0`.
|
||||
isPositive : Num a -> Bool
|
||||
isPositive = \x -> x > 0
|
||||
|
||||
## Negative numbers are less than `0`.
|
||||
isNegative : Num a -> Bool
|
||||
isNegative = \x -> x < 0
|
||||
|
||||
toFrac : Num * -> Frac *
|
||||
|
||||
|
@ -682,7 +707,11 @@ mul : Num a, Num a -> Num a
|
|||
|
||||
sin : Frac a -> Frac a
|
||||
cos : Frac a -> Frac a
|
||||
|
||||
tan : Frac a -> Frac a
|
||||
tan = \x ->
|
||||
# `tan` is not available as an intrinsic in LLVM
|
||||
Num.div (Num.sin x) (Num.cos x)
|
||||
|
||||
asin : Frac a -> Frac a
|
||||
acos : Frac a -> Frac a
|
||||
|
@ -713,9 +742,22 @@ atan : Frac a -> Frac a
|
|||
##
|
||||
## >>> Num.sqrt -4.0f64
|
||||
sqrt : Frac a -> Frac a
|
||||
|
||||
sqrtChecked : Frac a -> Result (Frac a) [SqrtOfNegative]*
|
||||
sqrtChecked = \x ->
|
||||
if x < 0.0 then
|
||||
Err SqrtOfNegative
|
||||
else
|
||||
Ok (Num.sqrt x)
|
||||
|
||||
log : Frac a -> Frac a
|
||||
|
||||
logChecked : Frac a -> Result (Frac a) [LogNeedsPositive]*
|
||||
logChecked = \x ->
|
||||
if x <= 0.0 then
|
||||
Err LogNeedsPositive
|
||||
else
|
||||
Ok (Num.log x)
|
||||
|
||||
## Divide one [Frac] by another.
|
||||
##
|
||||
|
@ -748,9 +790,22 @@ logChecked : Frac a -> Result (Frac a) [LogNeedsPositive]*
|
|||
## >>> Num.pi
|
||||
## >>> |> Num.div 2.0
|
||||
div : Frac a, Frac a -> Frac a
|
||||
|
||||
divChecked : Frac a, Frac a -> Result (Frac a) [DivByZero]*
|
||||
divChecked = \a, b ->
|
||||
if b == 0 then
|
||||
Err DivByZero
|
||||
else
|
||||
Ok (Num.div a b)
|
||||
|
||||
divCeil : Int a, Int a -> Int a
|
||||
|
||||
divCeilChecked : Int a, Int a -> Result (Int a) [DivByZero]*
|
||||
divCeilChecked = \a, b ->
|
||||
if b == 0 then
|
||||
Err DivByZero
|
||||
else
|
||||
Ok (Num.divCeil a b)
|
||||
|
||||
## Divide two integers, truncating the result towards zero.
|
||||
##
|
||||
|
@ -769,7 +824,13 @@ divCeilChecked : Int a, Int a -> Result (Int a) [DivByZero]*
|
|||
## >>> Num.divTrunc 8 -3
|
||||
##
|
||||
divTrunc : Int a, Int a -> Int a
|
||||
|
||||
divTruncChecked : Int a, Int a -> Result (Int a) [DivByZero]*
|
||||
divTruncChecked = \a, b ->
|
||||
if b == 0 then
|
||||
Err DivByZero
|
||||
else
|
||||
Ok (Num.divTrunc a b)
|
||||
|
||||
## Obtain the remainder (truncating modulo) from the division of two integers.
|
||||
##
|
||||
|
@ -783,7 +844,13 @@ divTruncChecked : Int a, Int a -> Result (Int a) [DivByZero]*
|
|||
##
|
||||
## >>> Num.rem -8 -3
|
||||
rem : Int a, Int a -> Int a
|
||||
|
||||
remChecked : Int a, Int a -> Result (Int a) [DivByZero]*
|
||||
remChecked = \a, b ->
|
||||
if b == 0 then
|
||||
Err DivByZero
|
||||
else
|
||||
Ok (Num.rem a b)
|
||||
|
||||
isMultipleOf : Int a, Int a -> Bool
|
||||
|
||||
|
@ -842,6 +909,15 @@ addSaturated : Num a, Num a -> Num a
|
|||
## This is the same as [Num.add] except if the operation overflows, instead of
|
||||
## panicking or returning ∞ or -∞, it will return `Err Overflow`.
|
||||
addChecked : Num a, Num a -> Result (Num a) [Overflow]*
|
||||
addChecked = \a, b ->
|
||||
result = addCheckedLowlevel a b
|
||||
|
||||
if result.b then
|
||||
Err Overflow
|
||||
else
|
||||
Ok result.a
|
||||
|
||||
addCheckedLowlevel : Num a, Num a -> {b: Bool, a : Num a}
|
||||
|
||||
subWrap : Int range, Int range -> Int range
|
||||
|
||||
|
@ -859,6 +935,15 @@ subSaturated : Num a, Num a -> Num a
|
|||
## This is the same as [Num.sub] except if the operation overflows, instead of
|
||||
## panicking or returning ∞ or -∞, it will return `Err Overflow`.
|
||||
subChecked : Num a, Num a -> Result (Num a) [Overflow]*
|
||||
subChecked = \a, b ->
|
||||
result = subCheckedLowlevel a b
|
||||
|
||||
if result.b then
|
||||
Err Overflow
|
||||
else
|
||||
Ok result.a
|
||||
|
||||
subCheckedLowlevel : Num a, Num a -> {b: Bool, a : Num a}
|
||||
|
||||
mulWrap : Int range, Int range -> Int range
|
||||
|
||||
|
@ -874,6 +959,15 @@ mulSaturated : Num a, Num a -> Num a
|
|||
## This is the same as [Num.mul] except if the operation overflows, instead of
|
||||
## panicking or returning ∞ or -∞, it will return `Err Overflow`.
|
||||
mulChecked : Num a, Num a -> Result (Num a) [Overflow]*
|
||||
mulChecked = \a, b ->
|
||||
result = mulCheckedLowlevel a b
|
||||
|
||||
if result.b then
|
||||
Err Overflow
|
||||
else
|
||||
Ok result.a
|
||||
|
||||
mulCheckedLowlevel : Num a, Num a -> {b: Bool, a : Num a}
|
||||
|
||||
## The lowest number that can be stored in an [I8] without underflowing its
|
||||
## available memory and crashing.
|
||||
|
|
|
@ -24,10 +24,19 @@ single : k -> Set k
|
|||
## retrieved or removed from the [Set].
|
||||
insert : Set k, k -> Set k
|
||||
len : Set k -> Nat
|
||||
len = \set ->
|
||||
set
|
||||
|> Set.toDict
|
||||
|> Dict.len
|
||||
|
||||
## Drops the given element from the set.
|
||||
remove : Set k, k -> Set k
|
||||
|
||||
contains : Set k, k -> Bool
|
||||
contains = \set, key ->
|
||||
set
|
||||
|> Set.toDict
|
||||
|> Dict.contains key
|
||||
|
||||
# toList = \set -> Dict.keys (toDict set)
|
||||
toList : Set k -> List k
|
||||
|
|
|
@ -202,7 +202,36 @@ toUtf8 : Str -> List U8
|
|||
# fromUtf8 : List U8 -> Result Str [BadUtf8 Utf8Problem]*
|
||||
# fromUtf8Range : List U8 -> Result Str [BadUtf8 Utf8Problem Nat, OutOfBounds]*
|
||||
fromUtf8 : List U8 -> Result Str [BadUtf8 Utf8ByteProblem Nat]*
|
||||
fromUtf8 = \bytes ->
|
||||
result = fromUtf8RangeLowlevel bytes { start: 0, count: List.len bytes }
|
||||
|
||||
if result.cIsOk then
|
||||
Ok result.bString
|
||||
else
|
||||
Err (BadUtf8 result.dProblemCode result.aByteIndex)
|
||||
|
||||
|
||||
fromUtf8Range : List U8, { start : Nat, count : Nat } -> Result Str [BadUtf8 Utf8ByteProblem Nat, OutOfBounds]*
|
||||
fromUtf8Range = \bytes, config ->
|
||||
if config.start + config.count <= List.len bytes then
|
||||
result = fromUtf8RangeLowlevel bytes config
|
||||
|
||||
if result.cIsOk then
|
||||
Ok result.bString
|
||||
else
|
||||
Err (BadUtf8 result.dProblemCode result.aByteIndex)
|
||||
else
|
||||
Err OutOfBounds
|
||||
|
||||
FromUtf8Result : {
|
||||
aByteIndex: Nat,
|
||||
bString: Str,
|
||||
cIsOk: Bool,
|
||||
dProblemCode: Utf8ByteProblem,
|
||||
}
|
||||
|
||||
fromUtf8RangeLowlevel : List U8, { start : Nat, count : Nat } -> FromUtf8Result
|
||||
|
||||
|
||||
startsWith : Str, Str -> Bool
|
||||
endsWith : Str, Str -> Bool
|
||||
|
@ -214,19 +243,33 @@ trimLeft : Str -> Str
|
|||
trimRight : Str -> Str
|
||||
|
||||
toDec : Str -> Result Dec [InvalidNumStr]*
|
||||
toDec = \string -> strToNumHelp string
|
||||
toF64 : Str -> Result F64 [InvalidNumStr]*
|
||||
toF64 = \string -> strToNumHelp string
|
||||
toF32 : Str -> Result F32 [InvalidNumStr]*
|
||||
toF32 = \string -> strToNumHelp string
|
||||
toNat : Str -> Result Nat [InvalidNumStr]*
|
||||
toNat = \string -> strToNumHelp string
|
||||
toU128 : Str -> Result U128 [InvalidNumStr]*
|
||||
toU128 = \string -> strToNumHelp string
|
||||
toI128 : Str -> Result I128 [InvalidNumStr]*
|
||||
toI128 = \string -> strToNumHelp string
|
||||
toU64 : Str -> Result U64 [InvalidNumStr]*
|
||||
toU64 = \string -> strToNumHelp string
|
||||
toI64 : Str -> Result I64 [InvalidNumStr]*
|
||||
toI64 = \string -> strToNumHelp string
|
||||
toU32 : Str -> Result U32 [InvalidNumStr]*
|
||||
toU32 = \string -> strToNumHelp string
|
||||
toI32 : Str -> Result I32 [InvalidNumStr]*
|
||||
toI32 = \string -> strToNumHelp string
|
||||
toU16 : Str -> Result U16 [InvalidNumStr]*
|
||||
toU16 = \string -> strToNumHelp string
|
||||
toI16 : Str -> Result I16 [InvalidNumStr]*
|
||||
toI16 = \string -> strToNumHelp string
|
||||
toU8 : Str -> Result U8 [InvalidNumStr]*
|
||||
toU8 = \string -> strToNumHelp string
|
||||
toI8 : Str -> Result I8 [InvalidNumStr]*
|
||||
toI8 = \string -> strToNumHelp string
|
||||
|
||||
## Gets the byte at the given index, without performing a bounds check
|
||||
getUnsafe : Str, Nat -> U8
|
||||
|
@ -393,3 +436,15 @@ walkScalarsUntilHelp = \string, state, step, index, length ->
|
|||
newState
|
||||
else
|
||||
state
|
||||
|
||||
strToNum : Str -> { berrorcode: U8, aresult : Num * }
|
||||
|
||||
strToNumHelp : Str -> Result (Num a) [InvalidNumStr]*
|
||||
strToNumHelp = \string ->
|
||||
result : { berrorcode : U8, aresult : Num a }
|
||||
result = strToNum string
|
||||
|
||||
if result.berrorcode == 0 then
|
||||
Ok result.aresult
|
||||
else
|
||||
Err InvalidNumStr
|
||||
|
|
|
@ -28,6 +28,223 @@ macro_rules! macro_magic {
|
|||
};
|
||||
}
|
||||
|
||||
struct DefMap;
|
||||
|
||||
impl DefMap {
|
||||
fn arity(n: usize) -> fn(Symbol, LowLevel, &mut VarStore) -> Def {
|
||||
match n {
|
||||
0 => lowlevel_0,
|
||||
1 => lowlevel_1,
|
||||
2 => lowlevel_2,
|
||||
3 => lowlevel_3,
|
||||
4 => lowlevel_4,
|
||||
5 => lowlevel_5,
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! more_macro_magic {
|
||||
($($lowlevel:ident; $symbol:ident; $number_of_args:literal,)+) => { more_macro_magic!{$($lowlevel; $symbol; $number_of_args),+} };
|
||||
($($lowlevel:ident; $symbol:ident; $number_of_args:literal),*) => {
|
||||
impl DefMap {
|
||||
fn for_symbol(symbol: Symbol, var_store: &mut VarStore) -> Option<Def> {
|
||||
match symbol {
|
||||
$(
|
||||
Symbol::$symbol => Some((DefMap::arity($number_of_args))(Symbol::$symbol, LowLevel::$lowlevel, var_store)),
|
||||
|
||||
)*
|
||||
|
||||
Symbol::NUM_TO_I8 => Some(lowlevel_1(Symbol::NUM_TO_I8, LowLevel::NumIntCast, var_store)),
|
||||
Symbol::NUM_TO_I16 => Some(lowlevel_1(Symbol::NUM_TO_I16, LowLevel::NumIntCast, var_store)),
|
||||
Symbol::NUM_TO_I32 => Some(lowlevel_1(Symbol::NUM_TO_I32, LowLevel::NumIntCast, var_store)),
|
||||
Symbol::NUM_TO_I64 => Some(lowlevel_1(Symbol::NUM_TO_I64, LowLevel::NumIntCast, var_store)),
|
||||
Symbol::NUM_TO_I128 => Some(lowlevel_1(Symbol::NUM_TO_I128, LowLevel::NumIntCast, var_store)),
|
||||
Symbol::NUM_TO_U8 => Some(lowlevel_1(Symbol::NUM_TO_U8, LowLevel::NumIntCast, var_store)),
|
||||
Symbol::NUM_TO_U16 => Some(lowlevel_1(Symbol::NUM_TO_U16, LowLevel::NumIntCast, var_store)),
|
||||
Symbol::NUM_TO_U32 => Some(lowlevel_1(Symbol::NUM_TO_U32, LowLevel::NumIntCast, var_store)),
|
||||
Symbol::NUM_TO_U64 => Some(lowlevel_1(Symbol::NUM_TO_U64, LowLevel::NumIntCast, var_store)),
|
||||
Symbol::NUM_TO_U128 => Some(lowlevel_1(Symbol::NUM_TO_U128, LowLevel::NumIntCast, var_store)),
|
||||
Symbol::NUM_TO_NAT => Some(lowlevel_1(Symbol::NUM_TO_NAT, LowLevel::NumIntCast, var_store)),
|
||||
|
||||
Symbol::NUM_INT_CAST => Some(lowlevel_1(Symbol::NUM_INT_CAST, LowLevel::NumIntCast, var_store)),
|
||||
|
||||
Symbol::NUM_TO_F32 => Some(lowlevel_1(Symbol::NUM_TO_F32, LowLevel::NumToFloatCast, var_store)),
|
||||
Symbol::NUM_TO_F64 => Some(lowlevel_1(Symbol::NUM_TO_F64, LowLevel::NumToFloatCast, var_store)),
|
||||
|
||||
Symbol::NUM_TO_I8_CHECKED => Some(to_num_checked(Symbol::NUM_TO_I8_CHECKED, var_store, LowLevel::NumToIntChecked)),
|
||||
Symbol::NUM_TO_I16_CHECKED => Some(to_num_checked(Symbol::NUM_TO_I16_CHECKED, var_store, LowLevel::NumToIntChecked)),
|
||||
Symbol::NUM_TO_I32_CHECKED => Some(to_num_checked(Symbol::NUM_TO_I32_CHECKED, var_store, LowLevel::NumToIntChecked)),
|
||||
Symbol::NUM_TO_I64_CHECKED => Some(to_num_checked(Symbol::NUM_TO_I64_CHECKED, var_store, LowLevel::NumToIntChecked)),
|
||||
Symbol::NUM_TO_I128_CHECKED => Some(to_num_checked(Symbol::NUM_TO_I128_CHECKED, var_store, LowLevel::NumToIntChecked)),
|
||||
Symbol::NUM_TO_U8_CHECKED => Some(to_num_checked(Symbol::NUM_TO_U8_CHECKED, var_store, LowLevel::NumToIntChecked)),
|
||||
Symbol::NUM_TO_U16_CHECKED => Some(to_num_checked(Symbol::NUM_TO_U16_CHECKED, var_store, LowLevel::NumToIntChecked)),
|
||||
Symbol::NUM_TO_U32_CHECKED => Some(to_num_checked(Symbol::NUM_TO_U32_CHECKED, var_store, LowLevel::NumToIntChecked)),
|
||||
Symbol::NUM_TO_U64_CHECKED => Some(to_num_checked(Symbol::NUM_TO_U64_CHECKED, var_store, LowLevel::NumToIntChecked)),
|
||||
Symbol::NUM_TO_U128_CHECKED => Some(to_num_checked(Symbol::NUM_TO_U128_CHECKED, var_store, LowLevel::NumToIntChecked)),
|
||||
Symbol::NUM_TO_NAT_CHECKED => Some(to_num_checked(Symbol::NUM_TO_NAT_CHECKED, var_store, LowLevel::NumToIntChecked)),
|
||||
|
||||
Symbol::NUM_TO_F32_CHECKED => Some(to_num_checked(Symbol::NUM_TO_F32_CHECKED, var_store, LowLevel::NumToFloatChecked)),
|
||||
Symbol::NUM_TO_F64_CHECKED => Some(to_num_checked(Symbol::NUM_TO_F64_CHECKED, var_store, LowLevel::NumToFloatChecked)),
|
||||
|
||||
Symbol::NUM_DIV_FRAC => Some(lowlevel_2(Symbol::NUM_DIV_FRAC, LowLevel::NumDivUnchecked, var_store)),
|
||||
Symbol::NUM_DIV_TRUNC => Some(lowlevel_2(Symbol::NUM_DIV_TRUNC, LowLevel::NumDivUnchecked, var_store)),
|
||||
|
||||
Symbol::DICT_EMPTY => Some(dict_empty(Symbol::DICT_EMPTY, var_store)),
|
||||
|
||||
Symbol::SET_UNION => Some(lowlevel_2(Symbol::SET_UNION, LowLevel::DictUnion, var_store)),
|
||||
Symbol::SET_DIFFERENCE => Some(lowlevel_2(Symbol::SET_DIFFERENCE, LowLevel::DictDifference, var_store)),
|
||||
Symbol::SET_INTERSECTION => Some(lowlevel_2(Symbol::SET_INTERSECTION, LowLevel::DictIntersection, var_store)),
|
||||
|
||||
Symbol::SET_TO_LIST => Some(lowlevel_1(Symbol::SET_TO_LIST, LowLevel::DictKeys, var_store)),
|
||||
Symbol::SET_REMOVE => Some(lowlevel_2(Symbol::SET_REMOVE, LowLevel::DictRemove, var_store)),
|
||||
Symbol::SET_INSERT => Some(set_insert(Symbol::SET_INSERT, var_store)),
|
||||
Symbol::SET_EMPTY => Some(set_empty(Symbol::SET_EMPTY, var_store)),
|
||||
Symbol::SET_SINGLE => Some(set_single(Symbol::SET_SINGLE, var_store)),
|
||||
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn _enforce_exhaustiveness(lowlevel: LowLevel) -> Symbol {
|
||||
match lowlevel {
|
||||
$(
|
||||
LowLevel::$lowlevel => Symbol::$symbol,
|
||||
)*
|
||||
|
||||
// these are implemented explicitly in for_symbol because they are polymorphic
|
||||
LowLevel::NumIntCast => unreachable!(),
|
||||
LowLevel::NumToFloatCast => unreachable!(),
|
||||
LowLevel::NumToIntChecked => unreachable!(),
|
||||
LowLevel::NumToFloatChecked => unreachable!(),
|
||||
LowLevel::NumDivUnchecked => unreachable!(),
|
||||
LowLevel::DictEmpty => unreachable!(),
|
||||
|
||||
// these are used internally and not tied to a symbol
|
||||
LowLevel::Hash => unimplemented!(),
|
||||
LowLevel::PtrCast => unimplemented!(),
|
||||
LowLevel::RefCountInc => unimplemented!(),
|
||||
LowLevel::RefCountDec => unimplemented!(),
|
||||
|
||||
// these are not implemented, not sure why
|
||||
LowLevel::StrFromInt => unimplemented!(),
|
||||
LowLevel::StrFromFloat => unimplemented!(),
|
||||
LowLevel::NumIsFinite => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
more_macro_magic! {
|
||||
StrConcat; STR_CONCAT; 2,
|
||||
StrJoinWith; STR_JOIN_WITH; 2,
|
||||
StrIsEmpty; STR_IS_EMPTY; 1,
|
||||
StrStartsWith; STR_STARTS_WITH; 2,
|
||||
StrStartsWithScalar; STR_STARTS_WITH_SCALAR; 2,
|
||||
StrEndsWith; STR_ENDS_WITH; 2,
|
||||
StrSplit; STR_SPLIT; 2,
|
||||
StrCountGraphemes; STR_COUNT_GRAPHEMES; 1,
|
||||
StrCountUtf8Bytes; STR_COUNT_UTF8_BYTES; 1,
|
||||
StrFromUtf8; STR_FROM_UTF8; 1,
|
||||
StrFromUtf8Range; STR_FROM_UTF8_RANGE_LOWLEVEL; 2,
|
||||
StrToUtf8; STR_TO_UTF8; 1,
|
||||
StrRepeat; STR_REPEAT; 2,
|
||||
StrTrim; STR_TRIM; 1,
|
||||
StrTrimLeft; STR_TRIM_LEFT; 1,
|
||||
StrTrimRight; STR_TRIM_RIGHT; 1,
|
||||
StrToScalars; STR_TO_SCALARS; 1,
|
||||
StrGetUnsafe; STR_GET_UNSAFE; 2,
|
||||
StrSubstringUnsafe; STR_SUBSTRING_UNSAFE; 3,
|
||||
StrReserve; STR_RESERVE; 1,
|
||||
StrAppendScalar; STR_APPEND_SCALAR_UNSAFE; 2,
|
||||
StrGetScalarUnsafe; STR_GET_SCALAR_UNSAFE; 2,
|
||||
StrToNum; STR_TO_NUM; 1,
|
||||
ListLen; LIST_LEN; 1,
|
||||
ListWithCapacity; LIST_WITH_CAPACITY; 1,
|
||||
ListReserve; LIST_RESERVE; 2,
|
||||
ListIsUnique; LIST_IS_UNIQUE; 1,
|
||||
ListAppendUnsafe; LIST_APPEND_UNSAFE; 2,
|
||||
ListPrepend; LIST_PREPEND; 2,
|
||||
ListGetUnsafe; LIST_GET_UNSAFE; 2,
|
||||
ListReplaceUnsafe; LIST_REPLACE_UNSAFE; 3,
|
||||
ListConcat; LIST_CONCAT; 2,
|
||||
ListMap; LIST_MAP; 2,
|
||||
ListMap2; LIST_MAP2; 3,
|
||||
ListMap3; LIST_MAP3; 4,
|
||||
ListMap4; LIST_MAP4; 5,
|
||||
ListSortWith; LIST_SORT_WITH; 2,
|
||||
ListSublist; LIST_SUBLIST; 2,
|
||||
ListDropAt; LIST_DROP_AT; 2,
|
||||
ListSwap; LIST_SWAP; 3,
|
||||
DictSize; DICT_LEN; 1,
|
||||
DictInsert; DICT_INSERT; 3,
|
||||
DictRemove; DICT_REMOVE; 2,
|
||||
DictContains; DICT_CONTAINS; 2,
|
||||
DictGetUnsafe; DICT_GET_LOWLEVEL; 2,
|
||||
DictKeys; DICT_KEYS; 1,
|
||||
DictValues; DICT_VALUES; 1,
|
||||
DictUnion; DICT_UNION; 2,
|
||||
DictIntersection; DICT_INTERSECTION; 2,
|
||||
DictDifference; DICT_DIFFERENCE; 2,
|
||||
DictWalk; DICT_WALK; 3,
|
||||
SetFromList; SET_FROM_LIST; 1,
|
||||
SetToDict; SET_TO_DICT; 1,
|
||||
NumAdd; NUM_ADD; 2,
|
||||
NumAddWrap; NUM_ADD_WRAP; 2,
|
||||
NumAddChecked; NUM_ADD_CHECKED_LOWLEVEL; 2,
|
||||
NumAddSaturated; NUM_ADD_SATURATED; 2,
|
||||
NumSub; NUM_SUB; 2,
|
||||
NumSubWrap; NUM_SUB_WRAP; 2,
|
||||
NumSubChecked; NUM_SUB_CHECKED_LOWLEVEL; 2,
|
||||
NumSubSaturated; NUM_SUB_SATURATED; 2,
|
||||
NumMul; NUM_MUL; 2,
|
||||
NumMulWrap; NUM_MUL_WRAP; 2,
|
||||
NumMulSaturated; NUM_MUL_SATURATED; 2,
|
||||
NumMulChecked; NUM_MUL_CHECKED_LOWLEVEL; 2,
|
||||
|
||||
NumGt; NUM_GT; 2,
|
||||
NumGte; NUM_GTE; 2,
|
||||
NumLt; NUM_LT; 2,
|
||||
NumLte; NUM_LTE; 2,
|
||||
NumCompare; NUM_COMPARE; 2,
|
||||
NumDivCeilUnchecked; NUM_DIV_CEIL; 2,
|
||||
NumRemUnchecked; NUM_REM; 2,
|
||||
NumIsMultipleOf; NUM_IS_MULTIPLE_OF; 2,
|
||||
NumAbs; NUM_ABS; 1,
|
||||
NumNeg; NUM_NEG; 1,
|
||||
NumSin; NUM_SIN; 1,
|
||||
NumCos; NUM_COS; 1,
|
||||
NumSqrtUnchecked; NUM_SQRT; 1,
|
||||
NumLogUnchecked; NUM_LOG; 1,
|
||||
NumRound; NUM_ROUND; 1,
|
||||
NumToFrac; NUM_TO_FRAC; 1,
|
||||
NumPow; NUM_POW; 2,
|
||||
NumCeiling; NUM_CEILING; 1,
|
||||
NumPowInt; NUM_POW_INT; 2,
|
||||
NumFloor; NUM_FLOOR; 1,
|
||||
NumAtan; NUM_ATAN; 1,
|
||||
NumAcos; NUM_ACOS; 1,
|
||||
NumAsin; NUM_ASIN; 1,
|
||||
NumBytesToU16; NUM_BYTES_TO_U16_LOWLEVEL; 2,
|
||||
NumBytesToU32; NUM_BYTES_TO_U32_LOWLEVEL; 2,
|
||||
NumBitwiseAnd; NUM_BITWISE_AND; 2,
|
||||
NumBitwiseXor; NUM_BITWISE_XOR; 2,
|
||||
NumBitwiseOr; NUM_BITWISE_OR; 2,
|
||||
NumShiftLeftBy; NUM_SHIFT_LEFT; 2,
|
||||
NumShiftRightBy; NUM_SHIFT_RIGHT; 2,
|
||||
NumShiftRightZfBy; NUM_SHIFT_RIGHT_ZERO_FILL; 2,
|
||||
NumToStr; NUM_TO_STR; 1,
|
||||
Eq; BOOL_EQ; 2,
|
||||
NotEq; BOOL_NEQ; 2,
|
||||
And; BOOL_AND; 2,
|
||||
Or; BOOL_OR; 2,
|
||||
Not; BOOL_NOT; 1,
|
||||
BoxExpr; BOX_BOX_FUNCTION; 1,
|
||||
UnboxExpr; BOX_UNBOX; 1,
|
||||
Unreachable; LIST_UNREACHABLE; 1,
|
||||
}
|
||||
|
||||
/// Some builtins cannot be constructed in code gen alone, and need to be defined
|
||||
/// as separate Roc defs. For example, List.get has this type:
|
||||
///
|
||||
|
@ -65,6 +282,8 @@ pub fn builtin_dependencies(symbol: Symbol) -> &'static [Symbol] {
|
|||
pub fn builtin_defs_map(symbol: Symbol, var_store: &mut VarStore) -> Option<Def> {
|
||||
debug_assert!(symbol.is_builtin());
|
||||
|
||||
return DefMap::for_symbol(symbol, var_store);
|
||||
|
||||
macro_magic! { symbol; var_store;
|
||||
BOOL_EQ => bool_eq,
|
||||
BOOL_NEQ => bool_neq,
|
||||
|
@ -250,6 +469,18 @@ pub fn builtin_defs_map(symbol: Symbol, var_store: &mut VarStore) -> Option<Def>
|
|||
}
|
||||
}
|
||||
|
||||
fn lowlevel_0(symbol: Symbol, op: LowLevel, var_store: &mut VarStore) -> Def {
|
||||
let ret_var = var_store.fresh();
|
||||
|
||||
let body = RunLowLevel {
|
||||
op,
|
||||
args: vec![],
|
||||
ret_var,
|
||||
};
|
||||
|
||||
defn(symbol, vec![], var_store, body, ret_var)
|
||||
}
|
||||
|
||||
fn lowlevel_1(symbol: Symbol, op: LowLevel, var_store: &mut VarStore) -> Def {
|
||||
let arg1_var = var_store.fresh();
|
||||
let ret_var = var_store.fresh();
|
||||
|
|
|
@ -5575,13 +5575,22 @@ fn run_low_level<'a, 'ctx, 'env>(
|
|||
//
|
||||
// As a low-level, record is destructed
|
||||
// List.sublist : List elem, start : Nat, len : Nat -> List elem
|
||||
debug_assert_eq!(args.len(), 3);
|
||||
debug_assert_eq!(args.len(), 2);
|
||||
|
||||
let (list, list_layout) = load_symbol_and_layout(scope, &args[0]);
|
||||
let original_wrapper = list.into_struct_value();
|
||||
|
||||
let start = load_symbol(scope, &args[1]);
|
||||
let len = load_symbol(scope, &args[2]);
|
||||
let record = load_symbol(scope, &args[1]).into_struct_value();
|
||||
|
||||
let len = env
|
||||
.builder
|
||||
.build_extract_value(record, 0, "get_len")
|
||||
.unwrap();
|
||||
|
||||
let start = env
|
||||
.builder
|
||||
.build_extract_value(record, 1, "get_start")
|
||||
.unwrap();
|
||||
|
||||
let element_layout = list_element_layout!(list_layout);
|
||||
list_sublist(
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
use bumpalo::Bump;
|
||||
use roc_load_internal::file::Threading;
|
||||
use roc_load_internal::file::{LoadingProblem, Threading};
|
||||
use roc_module::symbol::ModuleId;
|
||||
|
||||
const MODULES: &[(ModuleId, &str)] = &[
|
||||
|
@ -47,7 +47,16 @@ fn write_subs_for_module(module_id: ModuleId, filename: &str) {
|
|||
Threading::AllAvailable,
|
||||
);
|
||||
|
||||
let module = res_module.unwrap();
|
||||
let module = match res_module {
|
||||
Ok(v) => v,
|
||||
Err(LoadingProblem::FormattedReport(report)) => {
|
||||
panic!("{}", report);
|
||||
}
|
||||
Err(other) => {
|
||||
panic!("build_file failed with error:\n{:?}", other);
|
||||
}
|
||||
};
|
||||
|
||||
let subs = module.solved.inner();
|
||||
let exposed_vars_by_symbol: Vec<_> = module.exposed_to_host.into_iter().collect();
|
||||
|
||||
|
|
|
@ -997,6 +997,8 @@ define_builtins! {
|
|||
28 DEV_TMP3: "#dev_tmp3"
|
||||
29 DEV_TMP4: "#dev_tmp4"
|
||||
30 DEV_TMP5: "#dev_tmp5"
|
||||
|
||||
31 ATTR_INVALID: "#attr_invalid"
|
||||
}
|
||||
// Fake module for storing derived function symbols
|
||||
1 DERIVED: "#Derived" => {
|
||||
|
@ -1143,6 +1145,11 @@ define_builtins! {
|
|||
138 NUM_TO_F64_CHECKED: "toF64Checked"
|
||||
139 NUM_MAX_F64: "maxF64"
|
||||
140 NUM_MIN_F64: "minF64"
|
||||
141 NUM_ADD_CHECKED_LOWLEVEL: "addCheckedLowlevel"
|
||||
142 NUM_SUB_CHECKED_LOWLEVEL: "subCheckedLowlevel"
|
||||
143 NUM_MUL_CHECKED_LOWLEVEL: "mulCheckedLowlevel"
|
||||
144 NUM_BYTES_TO_U16_LOWLEVEL: "bytesToU16Lowlevel"
|
||||
145 NUM_BYTES_TO_U32_LOWLEVEL: "bytesToU32Lowlevel"
|
||||
}
|
||||
3 BOOL: "Bool" => {
|
||||
0 BOOL_BOOL: "Bool" // the Bool.Bool type alias
|
||||
|
@ -1205,6 +1212,8 @@ define_builtins! {
|
|||
44 STR_GET_SCALAR_UNSAFE: "getScalarUnsafe"
|
||||
45 STR_WALK_SCALARS: "walkScalars"
|
||||
46 STR_WALK_SCALARS_UNTIL: "walkScalarsUntil"
|
||||
47 STR_TO_NUM: "strToNum"
|
||||
48 STR_FROM_UTF8_RANGE_LOWLEVEL: "fromUtf8RangeLowlevel"
|
||||
}
|
||||
5 LIST: "List" => {
|
||||
0 LIST_LIST: "List" imported // the List.List type alias
|
||||
|
@ -1306,6 +1315,8 @@ define_builtins! {
|
|||
12 DICT_UNION: "union"
|
||||
13 DICT_INTERSECTION: "intersection"
|
||||
14 DICT_DIFFERENCE: "difference"
|
||||
|
||||
15 DICT_GET_LOWLEVEL: "getLowlevel"
|
||||
}
|
||||
8 SET: "Set" => {
|
||||
0 SET_SET: "Set" imported // the Set.Set type alias
|
||||
|
|
|
@ -912,7 +912,7 @@ pub fn lowlevel_borrow_signature(arena: &Bump, op: LowLevel) -> &[bool] {
|
|||
|
||||
ListAppendUnsafe => arena.alloc_slice_copy(&[owned, owned]),
|
||||
ListReserve => arena.alloc_slice_copy(&[owned, irrelevant]),
|
||||
ListSublist => arena.alloc_slice_copy(&[owned, irrelevant, irrelevant]),
|
||||
ListSublist => arena.alloc_slice_copy(&[owned, irrelevant]),
|
||||
ListDropAt => arena.alloc_slice_copy(&[owned, irrelevant]),
|
||||
ListSwap => arena.alloc_slice_copy(&[owned, irrelevant, irrelevant]),
|
||||
|
||||
|
|
|
@ -84,7 +84,7 @@ impl SubsHeader {
|
|||
fn from_subs(subs: &Subs, exposed_vars_by_symbol: usize) -> Self {
|
||||
// TODO what do we do with problems? they should
|
||||
// be reported and then removed from Subs I think
|
||||
debug_assert!(subs.problems.is_empty());
|
||||
debug_assert!(subs.problems.is_empty(), "{:?}", &subs.problems);
|
||||
|
||||
Self {
|
||||
utable: subs.utable.len() as u64,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue