feat: add List.findIndex, List.zip, List.flatten, List.contains
Add missing List operations requested by ergon game engine project: - findIndex(list, predicate) -> Option<Int> - zip(list1, list2) -> List<(A, B)> - flatten(listOfLists) -> List<A> - contains(list, element) -> Bool Resolves ergon porting blocker #4. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -83,10 +83,14 @@ pub enum BuiltinFn {
|
||||
// Additional List operations
|
||||
ListIsEmpty,
|
||||
ListFind,
|
||||
ListFindIndex,
|
||||
ListAny,
|
||||
ListAll,
|
||||
ListTake,
|
||||
ListDrop,
|
||||
ListZip,
|
||||
ListFlatten,
|
||||
ListContains,
|
||||
|
||||
// Additional String operations
|
||||
StringStartsWith,
|
||||
@@ -974,10 +978,14 @@ impl Interpreter {
|
||||
Value::Builtin(BuiltinFn::ListIsEmpty),
|
||||
),
|
||||
("find".to_string(), Value::Builtin(BuiltinFn::ListFind)),
|
||||
("findIndex".to_string(), Value::Builtin(BuiltinFn::ListFindIndex)),
|
||||
("any".to_string(), Value::Builtin(BuiltinFn::ListAny)),
|
||||
("all".to_string(), Value::Builtin(BuiltinFn::ListAll)),
|
||||
("take".to_string(), Value::Builtin(BuiltinFn::ListTake)),
|
||||
("drop".to_string(), Value::Builtin(BuiltinFn::ListDrop)),
|
||||
("zip".to_string(), Value::Builtin(BuiltinFn::ListZip)),
|
||||
("flatten".to_string(), Value::Builtin(BuiltinFn::ListFlatten)),
|
||||
("contains".to_string(), Value::Builtin(BuiltinFn::ListContains)),
|
||||
(
|
||||
"forEach".to_string(),
|
||||
Value::Builtin(BuiltinFn::ListForEach),
|
||||
@@ -2723,6 +2731,55 @@ impl Interpreter {
|
||||
Ok(EvalResult::Value(Value::Bool(true)))
|
||||
}
|
||||
|
||||
BuiltinFn::ListFindIndex => {
|
||||
let (list, func) = Self::expect_args_2::<Vec<Value>, Value>(&args, "List.findIndex", span)?;
|
||||
for (i, item) in list.iter().enumerate() {
|
||||
let v = self.eval_call_to_value(func.clone(), vec![item.clone()], span)?;
|
||||
match v {
|
||||
Value::Bool(true) => {
|
||||
return Ok(EvalResult::Value(Value::Constructor {
|
||||
name: "Some".to_string(),
|
||||
fields: vec![Value::Int(i as i64)],
|
||||
}));
|
||||
}
|
||||
Value::Bool(false) => {}
|
||||
_ => return Err(err("List.findIndex predicate must return Bool")),
|
||||
}
|
||||
}
|
||||
Ok(EvalResult::Value(Value::Constructor {
|
||||
name: "None".to_string(),
|
||||
fields: vec![],
|
||||
}))
|
||||
}
|
||||
|
||||
BuiltinFn::ListZip => {
|
||||
let (list1, list2) = Self::expect_args_2::<Vec<Value>, Vec<Value>>(&args, "List.zip", span)?;
|
||||
let result: Vec<Value> = list1
|
||||
.into_iter()
|
||||
.zip(list2.into_iter())
|
||||
.map(|(a, b)| Value::Tuple(vec![a, b]))
|
||||
.collect();
|
||||
Ok(EvalResult::Value(Value::List(result)))
|
||||
}
|
||||
|
||||
BuiltinFn::ListFlatten => {
|
||||
let list = Self::expect_arg_1::<Vec<Value>>(&args, "List.flatten", span)?;
|
||||
let mut result = Vec::new();
|
||||
for item in list {
|
||||
match item {
|
||||
Value::List(inner) => result.extend(inner),
|
||||
other => result.push(other),
|
||||
}
|
||||
}
|
||||
Ok(EvalResult::Value(Value::List(result)))
|
||||
}
|
||||
|
||||
BuiltinFn::ListContains => {
|
||||
let (list, target) = Self::expect_args_2::<Vec<Value>, Value>(&args, "List.contains", span)?;
|
||||
let found = list.iter().any(|item| Value::values_equal(item, &target));
|
||||
Ok(EvalResult::Value(Value::Bool(found)))
|
||||
}
|
||||
|
||||
BuiltinFn::ListTake => {
|
||||
let (list, n) = Self::expect_args_2::<Vec<Value>, i64>(&args, "List.take", span)?;
|
||||
let n = n.max(0) as usize;
|
||||
|
||||
Reference in New Issue
Block a user