///|
/// Evaluate indices_of
fn eval_indices_of(
expr : Expr,
input : Json,
env : Env,
) -> Iter[Json] raise InterpreterError {
match eval_with_env(expr, input, env).collect() {
[] => Iter::singleton(Json::array([]))
[needle, ..] =>
match input {
Array(arr) =>
Iter::singleton(Json::array(indices_of_array(arr, needle)))
String(s) =>
match needle {
String(substr) =>
Iter::singleton(Json::array(indices_of_string(s, substr)))
_ => Iter::singleton(Json::array([]))
}
_ =>
raise TypeMismatch(
"array/string",
@ast_internal.json_type_name(input),
)
}
}
}
///|
/// Evaluate index_of
fn eval_index_of(
expr : Expr,
input : Json,
env : Env,
) -> Iter[Json] raise InterpreterError {
match eval_with_env(expr, input, env).collect() {
[] => Iter::singleton(null)
[needle, ..] =>
match input {
Array(arr) =>
match find_first_index(arr, needle) {
Some(idx) => Iter::singleton(Json::number(idx.to_double()))
None => Iter::singleton(null)
}
String(s) =>
match needle {
String(substr) if substr.is_empty() => Iter::singleton(null)
String(substr) =>
Iter::singleton(
s
.find(substr)
.map(fn(pos) { Json::number(pos.to_double()) })
.unwrap_or(null),
)
_ => Iter::singleton(null)
}
_ =>
raise TypeMismatch(
"array/string",
@ast_internal.json_type_name(input),
)
}
}
}
///|
/// Evaluate nth
fn eval_nth(n : Int, input : Json) -> Iter[Json] raise InterpreterError {
guard input is Array(arr) else {
raise TypeMismatch("array", @ast_internal.json_type_name(input))
}
if n >= 0 && n < arr.length() {
Iter::singleton(arr[n])
} else if n < 0 && -n <= arr.length() {
Iter::singleton(arr[arr.length() + n])
} else {
Iter::empty()
}
}
///|
/// Evaluate rindex
fn eval_rindex(
search_expr : Expr,
input : Json,
env : Env,
) -> Iter[Json] raise InterpreterError {
match eval_with_env(search_expr, input, env).collect() {
[] => Iter::singleton(null)
[needle, ..] =>
match input {
Array(arr) =>
match find_last_index(arr, needle) {
Some(idx) => Iter::singleton(Json::number(idx.to_double()))
None => Iter::singleton(null)
}
String(s) =>
match needle {
String(substr) =>
match s.rev_find(substr) {
Some(pos) => Iter::singleton(Json::number(pos.to_double()))
None => Iter::singleton(null)
}
_ => Iter::singleton(null)
}
_ =>
raise TypeMismatch(
"array or string",
@ast_internal.json_type_name(input),
)
}
}
}
///|
fn indices_of_array(arr : ArrayView[Json], needle : Json) -> Array[Json] {
let result : Array[Json] = []
for i in 0.. Int? {
for i in 0.. Int? {
for i in (arr.length() - 1)>=..0 {
if arr[i] == needle {
return Some(i)
}
}
None
}
///|
fn indices_of_string(s : String, substr : String) -> Array[Json] {
let result : Array[Json] = []
let slen = s.length()
let substr_len = substr.length()
guard substr_len > 0 else { return result }
let mut pos = 0
while pos <= slen - substr_len {
let slice = s[pos:].to_owned()
match slice.find(substr) {
Some(idx) => {
let actual_idx = pos + idx
result.push(Json::number(actual_idx.to_double()))
pos = actual_idx + 1 // Advance by 1 to find overlapping matches
}
None => break
}
}
result
}