robinpath 0.2.0

RobinPath - A lightweight, fast scripting language interpreter for automation and data processing
Documentation
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)
        }
    });
}