use crate::executor::Environment;
use crate::value::Value;
pub fn register(env: &mut Environment) {
env.register_builtin("array.length", |args, _| {
Ok(Value::Number(
args.first()
.and_then(|v| v.as_array())
.map_or(0.0, |a| a.len() as f64),
))
});
env.register_builtin("array.get", |args, _| {
let arr = args.first().and_then(|v| v.as_array());
let idx = args.get(1).and_then(|v| v.as_number()).unwrap_or(0.0) as usize;
Ok(arr
.and_then(|a| a.get(idx))
.cloned()
.unwrap_or(Value::Null))
});
env.register_builtin("array.push", |args, _| {
if let Some(Value::Array(arr)) = args.first() {
let mut new_arr = arr.clone();
for arg in &args[1..] {
new_arr.push(arg.clone());
}
Ok(Value::Array(new_arr))
} else {
Ok(Value::Null)
}
});
env.register_builtin("array.pop", |args, _| {
if let Some(Value::Array(arr)) = args.first() {
let mut new_arr = arr.clone();
new_arr.pop();
Ok(Value::Array(new_arr))
} else {
Ok(Value::Null)
}
});
env.register_builtin("array.slice", |args, _| {
if let Some(Value::Array(arr)) = args.first() {
let start = args.get(1).and_then(|v| v.as_number()).unwrap_or(0.0) as usize;
let end = args
.get(2)
.and_then(|v| v.as_number())
.map(|n| n as usize)
.unwrap_or(arr.len());
let start = start.min(arr.len());
let end = end.min(arr.len());
Ok(Value::Array(arr[start..end].to_vec()))
} else {
Ok(Value::Array(Vec::new()))
}
});
env.register_builtin("array.concat", |args, _| {
let mut result = Vec::new();
for arg in args {
match arg {
Value::Array(arr) => result.extend(arr.iter().cloned()),
other => result.push(other.clone()),
}
}
Ok(Value::Array(result))
});
env.register_builtin("array.join", |args, _| {
let arr = args.first().and_then(|v| v.as_array());
let delim = args.get(1).and_then(|v| v.as_str()).unwrap_or(",");
match arr {
Some(items) => {
let strs: Vec<String> = items.iter().map(|v| v.to_display_string()).collect();
Ok(Value::String(strs.join(delim)))
}
None => Ok(Value::String(String::new())),
}
});
env.register_builtin("array.reverse", |args, _| {
if let Some(Value::Array(arr)) = args.first() {
let mut new_arr = arr.clone();
new_arr.reverse();
Ok(Value::Array(new_arr))
} else {
Ok(Value::Null)
}
});
env.register_builtin("array.includes", |args, _| {
if let Some(Value::Array(arr)) = args.first() {
if let Some(search) = args.get(1) {
Ok(Value::Bool(arr.iter().any(|v| v.deep_eq(search))))
} else {
Ok(Value::Bool(false))
}
} else {
Ok(Value::Bool(false))
}
});
env.register_builtin("array.indexOf", |args, _| {
if let Some(Value::Array(arr)) = args.first() {
if let Some(search) = args.get(1) {
Ok(Value::Number(
arr.iter()
.position(|v| v.deep_eq(search))
.map_or(-1.0, |i| i as f64),
))
} else {
Ok(Value::Number(-1.0))
}
} else {
Ok(Value::Number(-1.0))
}
});
env.register_builtin("array.create", |args, _| {
Ok(Value::Array(args.to_vec()))
});
env.register_builtin("array.sort", |args, _| {
if let Some(Value::Array(arr)) = args.first() {
let mut new_arr = arr.clone();
new_arr.sort_by(|a, b| {
a.to_number()
.partial_cmp(&b.to_number())
.unwrap_or(std::cmp::Ordering::Equal)
});
Ok(Value::Array(new_arr))
} else {
Ok(Value::Null)
}
});
env.register_builtin("array.flat", |args, _| {
if let Some(Value::Array(arr)) = args.first() {
let mut result = Vec::new();
for item in arr {
match item {
Value::Array(inner) => result.extend(inner.iter().cloned()),
other => result.push(other.clone()),
}
}
Ok(Value::Array(result))
} else {
Ok(Value::Null)
}
});
env.register_builtin("array.unique", |args, _| {
if let Some(Value::Array(arr)) = args.first() {
let mut result: Vec<Value> = Vec::new();
for item in arr {
if !result.iter().any(|v| v.deep_eq(item)) {
result.push(item.clone());
}
}
Ok(Value::Array(result))
} else {
Ok(Value::Null)
}
});
}