mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-02 16:21:11 +00:00
Merge remote-tracking branch 'origin/main' into roc-dev-inline-expects
This commit is contained in:
commit
ebac056814
67 changed files with 851 additions and 1952 deletions
|
@ -201,9 +201,9 @@ pub fn build_zig_host_native(
|
|||
if let Some(shared_lib_path) = shared_lib_path {
|
||||
command.args(&[
|
||||
"build-exe",
|
||||
"-fPIE",
|
||||
// "-fPIE", PIE seems to fail on windows
|
||||
shared_lib_path.to_str().unwrap(),
|
||||
&bitcode::get_builtins_host_obj_path(),
|
||||
&bitcode::get_builtins_windows_obj_path(),
|
||||
]);
|
||||
} else {
|
||||
command.args(&["build-obj", "-fPIC"]);
|
||||
|
@ -221,6 +221,7 @@ pub fn build_zig_host_native(
|
|||
// include libc
|
||||
"--library",
|
||||
"c",
|
||||
"-dynamic",
|
||||
// cross-compile?
|
||||
"-target",
|
||||
target,
|
||||
|
|
|
@ -745,37 +745,54 @@ pub fn listConcat(list_a: RocList, list_b: RocList, alignment: u32, element_widt
|
|||
} else if (list_a.isUnique()) {
|
||||
const total_length: usize = list_a.len() + list_b.len();
|
||||
|
||||
if (list_a.bytes) |source| {
|
||||
const new_source = if (list_a.capacity >= total_length)
|
||||
source
|
||||
else
|
||||
utils.unsafeReallocate(
|
||||
source,
|
||||
alignment,
|
||||
list_a.len(),
|
||||
total_length,
|
||||
element_width,
|
||||
);
|
||||
const resized_list_a = list_a.reallocate(alignment, total_length, element_width);
|
||||
|
||||
if (list_b.bytes) |source_b| {
|
||||
@memcpy(new_source + list_a.len() * element_width, source_b, list_b.len() * element_width);
|
||||
}
|
||||
// These must exist, otherwise, the lists would have been empty.
|
||||
const source_a = resized_list_a.bytes orelse unreachable;
|
||||
const source_b = list_b.bytes orelse unreachable;
|
||||
@memcpy(source_a + list_a.len() * element_width, source_b, list_b.len() * element_width);
|
||||
|
||||
return RocList{ .bytes = new_source, .length = total_length, .capacity = total_length };
|
||||
}
|
||||
// decrement list b.
|
||||
utils.decref(source_b, list_b.len(), alignment);
|
||||
|
||||
return resized_list_a;
|
||||
} else if (list_b.isUnique()) {
|
||||
const total_length: usize = list_a.len() + list_b.len();
|
||||
|
||||
const resized_list_b = list_b.reallocate(alignment, total_length, element_width);
|
||||
|
||||
// These must exist, otherwise, the lists would have been empty.
|
||||
const source_a = list_a.bytes orelse unreachable;
|
||||
const source_b = resized_list_b.bytes orelse unreachable;
|
||||
|
||||
// This is a bit special, we need to first copy the elements of list_b to the end,
|
||||
// then copy the elements of list_a to the beginning.
|
||||
// This first call must use mem.copy because the slices might overlap.
|
||||
const byte_count_a = list_a.len() * element_width;
|
||||
const byte_count_b = list_b.len() * element_width;
|
||||
mem.copy(u8, source_b[byte_count_a .. byte_count_a + byte_count_b], source_b[0..byte_count_b]);
|
||||
@memcpy(source_b, source_a, byte_count_a);
|
||||
|
||||
// decrement list a.
|
||||
utils.decref(source_a, list_a.len(), alignment);
|
||||
|
||||
return resized_list_b;
|
||||
}
|
||||
const total_length: usize = list_a.len() + list_b.len();
|
||||
|
||||
const output = RocList.allocate(alignment, total_length, element_width);
|
||||
|
||||
if (output.bytes) |target| {
|
||||
if (list_a.bytes) |source| {
|
||||
@memcpy(target, source, list_a.len() * element_width);
|
||||
}
|
||||
if (list_b.bytes) |source| {
|
||||
@memcpy(target + list_a.len() * element_width, source, list_b.len() * element_width);
|
||||
}
|
||||
}
|
||||
// These must exist, otherwise, the lists would have been empty.
|
||||
const target = output.bytes orelse unreachable;
|
||||
const source_a = list_a.bytes orelse unreachable;
|
||||
const source_b = list_b.bytes orelse unreachable;
|
||||
|
||||
@memcpy(target, source_a, list_a.len() * element_width);
|
||||
@memcpy(target + list_a.len() * element_width, source_b, list_b.len() * element_width);
|
||||
|
||||
// decrement list a and b.
|
||||
utils.decref(source_a, list_a.len(), alignment);
|
||||
utils.decref(source_b, list_b.len(), alignment);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
|
|
@ -224,11 +224,6 @@ LowLevelHasher := { originalSeed : U64, state : U64 } has [
|
|||
addU32,
|
||||
addU64,
|
||||
addU128,
|
||||
addI8,
|
||||
addI16,
|
||||
addI32,
|
||||
addI64,
|
||||
addI128,
|
||||
complete,
|
||||
},
|
||||
]
|
||||
|
@ -250,17 +245,6 @@ combineState = \@LowLevelHasher { originalSeed, state }, { a, b, seed, length }
|
|||
|
||||
complete = \@LowLevelHasher { state } -> state
|
||||
|
||||
addI8 = \hasher, i8 ->
|
||||
addU8 hasher (Num.toU8 i8)
|
||||
addI16 = \hasher, i16 ->
|
||||
addU16 hasher (Num.toU16 i16)
|
||||
addI32 = \hasher, i32 ->
|
||||
addU32 hasher (Num.toU32 i32)
|
||||
addI64 = \hasher, i64 ->
|
||||
addU64 hasher (Num.toU64 i64)
|
||||
addI128 = \hasher, i128 ->
|
||||
addU128 hasher (Num.toU128 i128)
|
||||
|
||||
# These implementations hash each value individually with the seed and then mix
|
||||
# the resulting hash with the state. There are other options that may be faster
|
||||
# like using the output of the last hash as the seed to the current hash.
|
||||
|
|
|
@ -9,11 +9,11 @@ interface Hash
|
|||
addU32,
|
||||
addU64,
|
||||
addU128,
|
||||
addI8,
|
||||
addI16,
|
||||
addI32,
|
||||
addI64,
|
||||
addI128,
|
||||
hashI8,
|
||||
hashI16,
|
||||
hashI32,
|
||||
hashI64,
|
||||
hashI128,
|
||||
complete,
|
||||
hashStrBytes,
|
||||
hashList,
|
||||
|
@ -55,21 +55,6 @@ Hasher has
|
|||
## Adds a single U128 to the hasher.
|
||||
addU128 : a, U128 -> a | a has Hasher
|
||||
|
||||
## Adds a single I8 to the hasher.
|
||||
addI8 : a, I8 -> a | a has Hasher
|
||||
|
||||
## Adds a single I16 to the hasher.
|
||||
addI16 : a, I16 -> a | a has Hasher
|
||||
|
||||
## Adds a single I32 to the hasher.
|
||||
addI32 : a, I32 -> a | a has Hasher
|
||||
|
||||
## Adds a single I64 to the hasher.
|
||||
addI64 : a, I64 -> a | a has Hasher
|
||||
|
||||
## Adds a single I128 to the hasher.
|
||||
addI128 : a, I128 -> a | a has Hasher
|
||||
|
||||
## Completes the hasher, extracting a hash value from its
|
||||
## accumulated hash state.
|
||||
complete : a -> U64 | a has Hasher
|
||||
|
@ -83,6 +68,26 @@ hashList = \hasher, lst ->
|
|||
List.walk lst hasher \accumHasher, elem ->
|
||||
hash accumHasher elem
|
||||
|
||||
## Adds a single I8 to a hasher.
|
||||
hashI8 : a, I8 -> a | a has Hasher
|
||||
hashI8 = \hasher, n -> addU8 hasher (Num.toU8 n)
|
||||
|
||||
## Adds a single I16 to a hasher.
|
||||
hashI16 : a, I16 -> a | a has Hasher
|
||||
hashI16 = \hasher, n -> addU16 hasher (Num.toU16 n)
|
||||
|
||||
## Adds a single I32 to a hasher.
|
||||
hashI32 : a, I32 -> a | a has Hasher
|
||||
hashI32 = \hasher, n -> addU32 hasher (Num.toU32 n)
|
||||
|
||||
## Adds a single I64 to a hasher.
|
||||
hashI64 : a, I64 -> a | a has Hasher
|
||||
hashI64 = \hasher, n -> addU64 hasher (Num.toU64 n)
|
||||
|
||||
## Adds a single I128 to a hasher.
|
||||
hashI128 : a, I128 -> a | a has Hasher
|
||||
hashI128 = \hasher, n -> addU128 hasher (Num.toU128 n)
|
||||
|
||||
## Adds a container of [Hash]able elements to a [Hasher] by hashing each element.
|
||||
## The container is iterated using the walk method passed in.
|
||||
## The order of the elements does not affect the final hash.
|
||||
|
|
|
@ -29,6 +29,8 @@ interface List
|
|||
map3,
|
||||
product,
|
||||
walkUntil,
|
||||
walkFrom,
|
||||
walkFromUntil,
|
||||
range,
|
||||
sortWith,
|
||||
drop,
|
||||
|
@ -443,6 +445,22 @@ walkBackwardsUntil = \list, initial, func ->
|
|||
Continue new -> new
|
||||
Break new -> new
|
||||
|
||||
## Walks to the end of the list from a specified starting index
|
||||
walkFrom : List elem, Nat, state, (state, elem -> state) -> state
|
||||
walkFrom = \list, index, state, func ->
|
||||
walkHelp : _, _ -> [Continue _, Break []]
|
||||
walkHelp = \currentState, element -> Continue (func currentState element)
|
||||
|
||||
when List.iterHelp list state walkHelp index (List.len list) is
|
||||
Continue new -> new
|
||||
|
||||
## A combination of [List.walkFrom] and [List.walkUntil]
|
||||
walkFromUntil : List elem, Nat, state, (state, elem -> [Continue state, Break state]) -> state
|
||||
walkFromUntil = \list, index, state, func ->
|
||||
when List.iterHelp list state func index (List.len list) is
|
||||
Continue new -> new
|
||||
Break new -> new
|
||||
|
||||
sum : List (Num a) -> Num a
|
||||
sum = \list ->
|
||||
List.walk list 0 Num.add
|
||||
|
|
|
@ -314,7 +314,10 @@ fn to_encoder_record(
|
|||
record_var,
|
||||
ext_var: env.subs.fresh_unnamed_flex_var(),
|
||||
field_var,
|
||||
loc_expr: Box::new(Loc::at_zero(Var(rcd_sym, record_var))),
|
||||
loc_expr: Box::new(Loc::at_zero(Var(
|
||||
rcd_sym,
|
||||
env.subs.fresh_unnamed_flex_var(),
|
||||
))),
|
||||
field: field_name,
|
||||
};
|
||||
|
||||
|
|
|
@ -99,7 +99,10 @@ fn hash_record(env: &mut Env<'_>, fn_name: Symbol, fields: Vec<Lowercase>) -> (V
|
|||
record_var,
|
||||
field_var,
|
||||
ext_var: env.subs.fresh_unnamed_flex_var(),
|
||||
loc_expr: Box::new(Loc::at_zero(Expr::Var(rcd_sym, record_var))),
|
||||
loc_expr: Box::new(Loc::at_zero(Expr::Var(
|
||||
rcd_sym,
|
||||
env.subs.fresh_unnamed_flex_var(),
|
||||
))),
|
||||
field: field_name,
|
||||
};
|
||||
|
||||
|
|
|
@ -123,19 +123,19 @@ impl FlatHash {
|
|||
Ok(SingleLambdaSetImmediate(Symbol::HASH_ADD_U128))
|
||||
}
|
||||
Symbol::NUM_I8 | Symbol::NUM_SIGNED8 => {
|
||||
Ok(SingleLambdaSetImmediate(Symbol::HASH_ADD_I8))
|
||||
Ok(SingleLambdaSetImmediate(Symbol::HASH_HASH_I8))
|
||||
}
|
||||
Symbol::NUM_I16 | Symbol::NUM_SIGNED16 => {
|
||||
Ok(SingleLambdaSetImmediate(Symbol::HASH_ADD_I16))
|
||||
Ok(SingleLambdaSetImmediate(Symbol::HASH_HASH_I16))
|
||||
}
|
||||
Symbol::NUM_I32 | Symbol::NUM_SIGNED32 => {
|
||||
Ok(SingleLambdaSetImmediate(Symbol::HASH_ADD_I32))
|
||||
Ok(SingleLambdaSetImmediate(Symbol::HASH_HASH_I32))
|
||||
}
|
||||
Symbol::NUM_I64 | Symbol::NUM_SIGNED64 => {
|
||||
Ok(SingleLambdaSetImmediate(Symbol::HASH_ADD_I64))
|
||||
Ok(SingleLambdaSetImmediate(Symbol::HASH_HASH_I64))
|
||||
}
|
||||
Symbol::NUM_I128 | Symbol::NUM_SIGNED128 => {
|
||||
Ok(SingleLambdaSetImmediate(Symbol::HASH_ADD_I128))
|
||||
Ok(SingleLambdaSetImmediate(Symbol::HASH_HASH_I128))
|
||||
}
|
||||
// NB: I believe it is okay to unwrap opaques here because derivers are only used
|
||||
// by the backend, and the backend treats opaques like structural aliases.
|
||||
|
|
|
@ -3492,6 +3492,65 @@ mod test_fmt {
|
|||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn def_when() {
|
||||
expr_formats_same(indoc!(
|
||||
r#"
|
||||
myLongFunctionName = \x ->
|
||||
when b is
|
||||
1 | 2 ->
|
||||
when c is
|
||||
6 | 7 ->
|
||||
8
|
||||
|
||||
3 | 4 ->
|
||||
5
|
||||
|
||||
123
|
||||
"#
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore] // TODO: reformat when-in-function-body with extra newline
|
||||
fn def_when_with_python_indentation() {
|
||||
expr_formats_to(
|
||||
// vvv Currently this input formats to _itself_ :( vvv
|
||||
// Instead, if the body of the `when` is multiline (the overwhelmingly common case)
|
||||
// we want to make sure the `when` is at the beginning of the line, inserting
|
||||
// a newline if necessary.
|
||||
indoc!(
|
||||
r#"
|
||||
myLongFunctionName = \x -> when b is
|
||||
1 | 2 ->
|
||||
when c is
|
||||
6 | 7 ->
|
||||
8
|
||||
|
||||
3 | 4 ->
|
||||
5
|
||||
|
||||
123
|
||||
"#
|
||||
),
|
||||
indoc!(
|
||||
r#"
|
||||
myLongFunctionName = \x ->
|
||||
when b is
|
||||
1 | 2 ->
|
||||
when c is
|
||||
6 | 7 ->
|
||||
8
|
||||
|
||||
3 | 4 ->
|
||||
5
|
||||
|
||||
123
|
||||
"#
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn when_with_alternatives_1() {
|
||||
expr_formats_same(indoc!(
|
||||
|
|
|
@ -1398,6 +1398,8 @@ define_builtins! {
|
|||
75 LIST_WALK_TRY: "walkTry"
|
||||
76 LIST_WALK_BACKWARDS_UNTIL: "walkBackwardsUntil"
|
||||
77 LIST_COUNT_IF: "countIf"
|
||||
78 LIST_WALK_FROM: "walkFrom"
|
||||
79 LIST_WALK_FROM_UNTIL: "walkFromUntil"
|
||||
}
|
||||
7 RESULT: "Result" => {
|
||||
0 RESULT_RESULT: "Result" exposed_type=true // the Result.Result type alias
|
||||
|
@ -1526,11 +1528,11 @@ define_builtins! {
|
|||
6 HASH_ADD_U32: "addU32"
|
||||
7 HASH_ADD_U64: "addU64"
|
||||
8 HASH_ADD_U128: "addU128"
|
||||
9 HASH_ADD_I8: "addI8"
|
||||
10 HASH_ADD_I16: "addI16"
|
||||
11 HASH_ADD_I32: "addI32"
|
||||
12 HASH_ADD_I64: "addI64"
|
||||
13 HASH_ADD_I128: "addI128"
|
||||
9 HASH_HASH_I8: "hashI8"
|
||||
10 HASH_HASH_I16: "hashI16"
|
||||
11 HASH_HASH_I32: "hashI32"
|
||||
12 HASH_HASH_I64: "hashI64"
|
||||
13 HASH_HASH_I128: "hashI128"
|
||||
14 HASH_COMPLETE: "complete"
|
||||
15 HASH_HASH_STR_BYTES: "hashStrBytes"
|
||||
16 HASH_HASH_LIST: "hashList"
|
||||
|
|
|
@ -2080,7 +2080,7 @@ mod when {
|
|||
/// Parsing when with indentation.
|
||||
fn when_with_indent<'a>() -> impl Parser<'a, u32, EWhen<'a>> {
|
||||
move |arena, state: State<'a>| {
|
||||
let min_indent = state.column();
|
||||
let min_indent = state.line_indent() + 1;
|
||||
parser::keyword_e(keyword::WHEN, EWhen::When)
|
||||
.parse(arena, state)
|
||||
.map(|(progress, (), state)| (progress, min_indent, state))
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
Defs(
|
||||
Defs {
|
||||
tags: [
|
||||
Index(2147483648),
|
||||
],
|
||||
regions: [
|
||||
@0-33,
|
||||
],
|
||||
space_before: [
|
||||
Slice(start = 0, length = 0),
|
||||
],
|
||||
space_after: [
|
||||
Slice(start = 0, length = 0),
|
||||
],
|
||||
spaces: [],
|
||||
type_defs: [],
|
||||
value_defs: [
|
||||
Body(
|
||||
@0-4 Identifier(
|
||||
"func",
|
||||
),
|
||||
@7-33 Closure(
|
||||
[
|
||||
@8-9 Identifier(
|
||||
"x",
|
||||
),
|
||||
],
|
||||
@13-33 When(
|
||||
@18-19 Var {
|
||||
module_name: "",
|
||||
ident: "n",
|
||||
},
|
||||
[
|
||||
WhenBranch {
|
||||
patterns: [
|
||||
@27-28 SpaceBefore(
|
||||
NumLiteral(
|
||||
"0",
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
],
|
||||
value: @32-33 Num(
|
||||
"0",
|
||||
),
|
||||
guard: None,
|
||||
},
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
},
|
||||
@34-36 SpaceBefore(
|
||||
Num(
|
||||
"42",
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
)
|
|
@ -0,0 +1,3 @@
|
|||
func = \x -> when n is
|
||||
0 -> 0
|
||||
42
|
|
@ -284,6 +284,7 @@ mod test_parse {
|
|||
pass/when_if_guard.expr,
|
||||
pass/when_in_assignment.expr,
|
||||
pass/when_in_function.expr,
|
||||
pass/when_in_function_python_style_indent.expr,
|
||||
pass/when_in_parens_indented.expr,
|
||||
pass/when_in_parens.expr,
|
||||
pass/when_with_alternative_patterns.expr,
|
||||
|
|
|
@ -66,11 +66,11 @@ fn immediates() {
|
|||
check_single_lset_immediate(Hash, v!(U32), Symbol::HASH_ADD_U32);
|
||||
check_single_lset_immediate(Hash, v!(U64), Symbol::HASH_ADD_U64);
|
||||
check_single_lset_immediate(Hash, v!(U128), Symbol::HASH_ADD_U128);
|
||||
check_single_lset_immediate(Hash, v!(I8), Symbol::HASH_ADD_I8);
|
||||
check_single_lset_immediate(Hash, v!(I16), Symbol::HASH_ADD_I16);
|
||||
check_single_lset_immediate(Hash, v!(I32), Symbol::HASH_ADD_I32);
|
||||
check_single_lset_immediate(Hash, v!(I64), Symbol::HASH_ADD_I64);
|
||||
check_single_lset_immediate(Hash, v!(I128), Symbol::HASH_ADD_I128);
|
||||
check_single_lset_immediate(Hash, v!(I8), Symbol::HASH_HASH_I8);
|
||||
check_single_lset_immediate(Hash, v!(I16), Symbol::HASH_HASH_I16);
|
||||
check_single_lset_immediate(Hash, v!(I32), Symbol::HASH_HASH_I32);
|
||||
check_single_lset_immediate(Hash, v!(I64), Symbol::HASH_HASH_I64);
|
||||
check_single_lset_immediate(Hash, v!(I128), Symbol::HASH_HASH_I128);
|
||||
check_single_lset_immediate(Hash, v!(STR), Symbol::HASH_HASH_STR_BYTES);
|
||||
check_single_lset_immediate(Hash, v!(Symbol::LIST_LIST v!(U8)), Symbol::HASH_HASH_LIST);
|
||||
check_single_lset_immediate(Hash, v!(Symbol::LIST_LIST v!(STR)), Symbol::HASH_HASH_LIST);
|
||||
|
|
|
@ -1122,11 +1122,6 @@ mod hash {
|
|||
addU32: tAddU32,
|
||||
addU64: tAddU64,
|
||||
addU128: tAddU128,
|
||||
addI8: tAddI8,
|
||||
addI16: tAddI16,
|
||||
addI32: tAddI32,
|
||||
addI64: tAddI64,
|
||||
addI128: tAddI128,
|
||||
complete: tComplete,
|
||||
}]
|
||||
|
||||
|
@ -1165,11 +1160,6 @@ mod hash {
|
|||
tAddU32 = \@THasher total, n -> @THasher (do32 total n)
|
||||
tAddU64 = \@THasher total, n -> @THasher (do64 total n)
|
||||
tAddU128 = \@THasher total, n -> @THasher (do128 total n)
|
||||
tAddI8 = \@THasher total, n -> @THasher (do8 total (Num.toU8 n))
|
||||
tAddI16 = \@THasher total, n -> @THasher (do16 total (Num.toU16 n))
|
||||
tAddI32 = \@THasher total, n -> @THasher (do32 total (Num.toU32 n))
|
||||
tAddI64 = \@THasher total, n -> @THasher (do64 total (Num.toU64 n))
|
||||
tAddI128 = \@THasher total, n -> @THasher (do128 total (Num.toU128 n))
|
||||
tComplete = \@THasher _ -> Num.maxU64
|
||||
|
||||
tRead = \@THasher bytes -> bytes
|
||||
|
|
|
@ -956,6 +956,12 @@ fn list_walk_until_even_prefix_sum() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_walk_from_sum() {
|
||||
assert_evals_to!(r#"List.walkFrom [1, 2, 3] 1 0 Num.add"#, 5, i64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_keep_if_empty_list_of_int() {
|
||||
|
@ -3482,16 +3488,6 @@ fn list_let_generalization() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_walk_backwards_until_sum() {
|
||||
assert_evals_to!(
|
||||
r#"List.walkBackwardsUntil [1, 2] 0 \a,b -> Continue (a + b)"#,
|
||||
3,
|
||||
i64
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_walk_backwards_implements_position() {
|
||||
|
@ -3520,6 +3516,16 @@ fn list_walk_backwards_implements_position() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_walk_backwards_until_sum() {
|
||||
assert_evals_to!(
|
||||
r#"List.walkBackwardsUntil [1, 2] 0 \a,b -> Continue (a + b)"#,
|
||||
3,
|
||||
i64
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_walk_backwards_until_even_prefix_sum() {
|
||||
|
@ -3537,3 +3543,31 @@ fn list_walk_backwards_until_even_prefix_sum() {
|
|||
i64
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_walk_from_until_sum() {
|
||||
assert_evals_to!(
|
||||
r#"List.walkFromUntil [1, 2, 3, 4] 2 0 \a,b -> Continue (a + b)"#,
|
||||
7,
|
||||
i64
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn list_walk_from_even_prefix_sum() {
|
||||
assert_evals_to!(
|
||||
r#"
|
||||
helper = \a, b ->
|
||||
if Num.isEven b then
|
||||
Continue (a + b)
|
||||
|
||||
else
|
||||
Break a
|
||||
|
||||
List.walkFromUntil [2, 4, 8, 9] 1 0 helper"#,
|
||||
4 + 8,
|
||||
i64
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue