ksl 0.1.30

KSL core library and interpreter
Documentation
//! # ksl::builtin::range
//!
//! Built-in function `Range` and `Many`.

use crate::{Environment, eval::apply::eval_apply, is_number_eq, value::Value};

pub(crate) fn builtin(args: &[Value], env: Environment) -> Result<Value, std::sync::Arc<str>> {
    // Validate argument count (Fixed typo: Range instead of Print)
    let [v1, v2, v3] = if let [a, b, c] = args {
        [a, b, c]
    } else {
        return Err(std::sync::Arc::from(format!(
            "Error[ksl::builtin::Range]: Expected 3 parameters, but {} were passed.",
            args.len()
        )));
    };

    // Evaluate all arguments
    let start = eval_apply(v1, env.clone())?;
    let step_val = eval_apply(v2, env.clone())?;
    let bound_val = eval_apply(v3, env)?;

    match (start, step_val, bound_val) {
        (Value::Number(s), Value::Number(step), Value::Number(b)) => {
            if is_number_eq(step, 0.0) {
                return if is_number_eq(s, b) {
                    Ok(Value::List(std::sync::Arc::new([Value::Number(s)])))
                } else {
                    Err(std::sync::Arc::from(
                        "Error[ksl::builtin::Range]: No terminating range.",
                    ))
                };
            }

            let diff = b - s;

            // (bound - start) * step >= 0
            if diff.signum() != step.signum() && !is_number_eq(diff, 0.0) {
                return Err(std::sync::Arc::from(
                    "Error[ksl::builtin::Range]: No terminating range.",
                ));
            }

            // Calculate estimated count and collect elements
            // Using (i as f64 * step) instead of cumulative addition to maintain precision
            let mut elements = Vec::with_capacity(((diff / step).floor() as usize) + 1);
            let mut i = 0usize;
            loop {
                let current = s + (i as f64) * step;

                // Termination condition: current passed bound
                let remaining = b - current;
                if step.signum() != remaining.signum() && !is_number_eq(remaining, 0.0) {
                    break;
                }

                elements.push(Value::Number(current));
                i += 1;
            }

            Ok(Value::List(std::sync::Arc::from(elements)))
        }
        // Unified error handling for type mismatch
        (Value::Number(_), Value::Number(_), e) | (Value::Number(_), e, _) | (e, _, _) => Err(std::sync::Arc::from(format!(
            "Error[ksl::builtin::Range]: Unexpected value: `{}`.",
            e
        ))),
    }
}

pub(crate) fn many(args: &[Value], env: Environment) -> Result<Value, std::sync::Arc<str>> {
    if let [val, count] = args {
        match eval_apply(count, env.clone())? {
            Value::Number(n) if is_number_eq(n, n.trunc()) && n.is_sign_positive() => Ok(Value::List(
                std::iter::repeat_n(eval_apply(val, env)?, n as usize).collect::<std::sync::Arc<[Value]>>(),
            )),
            e => Err(std::sync::Arc::from(format!(
                concat!(
                    "Error[ksl::builtin::Many]: ",
                    "Expeced a positive integer, but got: `{}`."
                ),
                e
            ))),
        }
    } else {
        Err(std::sync::Arc::from(format!(
            concat!(
                "Error[ksl::builtin::Many]: ",
                "Expected 2 parameters, but {} were passed."
            ),
            args.len()
        )))
    }
}