ksl 0.1.5

KSL core library and interpreter
Documentation
use crate::{Environment, eval::apply::eval_apply, is_number_eq, value::Value};

pub(crate) fn builtin(args: &[Value], env: &Environment) -> Option<(Value, Environment)> {
    if let [val, idx] = &args[..] {
        match eval_apply(idx, env) {
            Some((Value::Number(n), _))
                if is_number_eq(n.round(), n) && (n > 0.0 || is_number_eq(n, -1.0)) =>
            {
                match eval_apply(val, env) {
                    Some((Value::List(elements), new_env)) => {
                        if (n as usize) > elements.len() {
                            eprintln!(
                                concat!(
                                    "Error[ksl::builtin::index]: ",
                                    "Index `{}` out of bounds `{}`."
                                ),
                                n,
                                elements.len()
                            );
                            None
                        } else if is_number_eq(n, -1.0) {
                            if elements.is_empty() {
                                eprintln!(concat!(
                                    "Error[ksl::builtin::index]: ",
                                    "Empty list."
                                ));
                                None
                            } else {
                                Some((elements[elements.len() - 1].clone(), new_env))
                            }
                        } else {
                            Some((elements[(n - 1.0) as usize].clone(), new_env))
                        }
                    }
                    Some((Value::String(s), _)) => {
                        if (n as usize) > s.chars().count() {
                            eprintln!(concat!(
                                "Error[ksl::builtin::index]: ",
                                "Index out of bounds."
                            ));
                            None
                        } else if is_number_eq(n, -1.0) {
                            if let Some(ch) = s.chars().last() {
                                Some((Value::String(String::from(ch)), Environment::new()))
                            } else {
                                eprintln!(concat!(
                                    "Error[ksl::builtin::index]: ",
                                    "Empty string."
                                ));
                                None
                            }
                        } else {
                            Some((
                                Value::String(
                                    s.chars()
                                        .enumerate()
                                        .filter(|(idx, _)| {
                                            &((n - 1.0) as usize) <= idx && idx < &(n as usize)
                                        })
                                        .map(|(_, ch)| ch)
                                        .collect::<String>(),
                                ),
                                Environment::new(),
                            ))
                        }
                    }
                    Some((e, _)) => {
                        eprintln!(
                            concat!(
                                "Error[ksl::builtin::index]: ",
                                "Expected a list or a string, but got `{:?}`."
                            ),
                            e
                        );
                        None
                    }
                    None => {
                        eprintln!(
                            concat!(
                                "Error[ksl::builtin::index]: ",
                                "Cannot evaluate expression {:?}."
                            ),
                            val
                        );
                        None
                    }
                }
            }
            Some((Value::Number(n), _)) => {
                eprintln!(
                    concat!(
                        "Error[ksl::builtin::index]: ",
                        "Index (`{}`) error. Index must be an integer, starting from 1. ",
                        "Specifically, -1 is the only acceptable negative index, ",
                        "indicating the last position.",
                    ),
                    n
                );
                None
            }
            Some((e, _)) => {
                eprintln!(
                    concat!(
                        "Error[ksl::builtin::index]: ",
                        "Expected a number, but got `{:?}`."
                    ),
                    e
                );
                None
            }
            None => {
                eprintln!(
                    concat!(
                        "Error[ksl::builtin::index]: ",
                        "Cannot evaluate expression {:?}."
                    ),
                    idx
                );
                None
            }
        }
    } else {
        eprintln!(
            concat!(
                "Error[ksl::builtin::index]: ",
                "Only accepts 2 arguments, but {} were passed."
            ),
            args.len()
        );
        None
    }
}