Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,22 @@ class Array<T> {
$rust_function
}

/// Returns a new array containing the non-null results of `fn` applied to
/// every element. The function is called once per element, left-to-right.
/// Does not mutate `self`. For a lazy version, use `iter().filter_map(fn)`.
function filter_map<U, E>(self, fn: (T) -> U? throws E) -> U[] throws E {
let out: U[] = [];
for (let x in self.slice(0, self.length())) {
match (fn(x)) {
null => {},
let y: U => {
out.push(y);
},
}
}
out
}

/// Returns a new array with the elements in reverse order. Does not mutate `self`.
function reverse(self) -> T[] throws never {
$rust_function
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,12 +150,16 @@ class ArrayIterator<T> {
type Error = never

function next(self) -> T | Done throws never {
match (self.arr.at(self.idx)) {
null => Done {},
let item: T => {
self.idx += 1;
item
},
// Bounds-check by index, not by matching `at()` against null: when T is
// itself nullable, a stored null element must be yielded, not treated as
// the end of iteration.
if (self.idx >= self.arr.length()) {
return Done {};
}
let item = self.arr.at(self.idx);
self.idx += 1;
match (item) {
let value: T => value,
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ function _float_total_cmp <builtin>/baml/comparable.baml
function _is_primitive_array <builtin>/baml/comparable.baml:151
function _rust_sort <builtin>/baml/comparable.baml:172
class Array <builtin>/baml/containers.baml:2
class Map <builtin>/baml/containers.baml:441
class Map <builtin>/baml/containers.baml:457
function deep_copy <builtin>/baml/core.baml:3
function deep_equals <builtin>/baml/core.baml:9
class Float <builtin>/baml/float.baml:2
Expand Down Expand Up @@ -121,16 +121,16 @@ interface iter.Iterable <builtin>/baml/ns_iter/iter.ba
interface iter.Iterator <builtin>/baml/ns_iter/iter.baml:10
function iter.flatten <builtin>/baml/ns_iter/iter.baml:129
class iter.ArrayIterator <builtin>/baml/ns_iter/iter.baml:133
class iter.Range <builtin>/baml/ns_iter/iter.baml:164
class iter.Repeat <builtin>/baml/ns_iter/iter.baml:196
class iter.Map <builtin>/baml/ns_iter/iter.baml:228
class iter.Filter <builtin>/baml/ns_iter/iter.baml:252
class iter.FilterMap <builtin>/baml/ns_iter/iter.baml:283
class iter.FlatMap <builtin>/baml/ns_iter/iter.baml:315
class iter.Flatten <builtin>/baml/ns_iter/iter.baml:356
class iter.Peekable <builtin>/baml/ns_iter/iter.baml:396
class iter.StepBy <builtin>/baml/ns_iter/iter.baml:434
class iter.Chain <builtin>/baml/ns_iter/iter.baml:466
class iter.Range <builtin>/baml/ns_iter/iter.baml:168
class iter.Repeat <builtin>/baml/ns_iter/iter.baml:200
class iter.Map <builtin>/baml/ns_iter/iter.baml:232
class iter.Filter <builtin>/baml/ns_iter/iter.baml:256
class iter.FilterMap <builtin>/baml/ns_iter/iter.baml:287
class iter.FlatMap <builtin>/baml/ns_iter/iter.baml:319
class iter.Flatten <builtin>/baml/ns_iter/iter.baml:360
class iter.Peekable <builtin>/baml/ns_iter/iter.baml:400
class iter.StepBy <builtin>/baml/ns_iter/iter.baml:438
class iter.Chain <builtin>/baml/ns_iter/iter.baml:470
type json.json <builtin>/baml/ns_json/json.baml:2
class json.JsonParseError <builtin>/baml/ns_json/json.baml:5
class json.JsonDecodeError <builtin>/baml/ns_json/json.baml:9
Expand Down
67 changes: 67 additions & 0 deletions baml_language/crates/baml_tests/baml_src/ns_iter/iter.baml
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,73 @@ test "iter_array_iter_lazy_over_source" {
assert.is_true(baml.deep_equals(iter_array_iter_lazy_over_source_details(), [3, 2, 1, 3]))
}

function iter_for_loop_sees_push_during_iteration() -> int[] throws unknown {
let xs = [1, 2];
let visited: int[] = [];
for (let x in xs) {
visited.push(x);
if (x == 1) {
xs.push(3);
}
}
visited
}

test "iter_for_loop_sees_push_during_iteration" {
assert.is_true(baml.deep_equals(iter_for_loop_sees_push_during_iteration(), [1, 2, 3]))
}

function iter_for_loop_pop_during_iteration() -> int[] throws unknown {
let xs = [1, 2, 3, 4];
let visited: int[] = [];
for (let x in xs) {
visited.push(x);
xs.pop();
}
visited
}

test "iter_for_loop_pop_during_iteration" {
assert.is_true(baml.deep_equals(iter_for_loop_pop_during_iteration(), [1, 2]))
}

function iter_array_eager_filter_map() -> int[] throws unknown {
[1, 2, 3, 4].filter_map((x: int) -> int? {
if (x % 2 == 0) {
x * 10
} else {
null
}
})
}

test "iter_array_eager_filter_map" {
assert.is_true(baml.deep_equals(iter_array_eager_filter_map(), [20, 40]))
}

function iter_array_nullable_elements_details() -> int[] throws unknown {
let xs: int?[] = [1, null, 3];
let visited = 0;
let nulls = 0;
let sum = 0;
for (let x in xs) {
visited += 1;
match (x) {
null => {
nulls += 1;
},
let v: int => {
sum += v;
},
}
}
[visited, nulls, sum, xs.iter().count()]
}

test "iter_array_nullable_elements" {
assert.is_true(baml.deep_equals(iter_array_nullable_elements_details(), [3, 1, 4, 3]))
}

function iter_array_lazy_filter_map_collect() -> int[] throws unknown {
[1, 2, 3, 4].iter().filter((x: int) -> bool {
x % 2 == 0
Expand Down
Loading
Loading