pipa-lang 1.0.0-alpha.1

A tiny template language
Documentation
// SPDX-FileCopyrightText: Copyright 2026 olav@occy.org
// SPDX-License-Identifier: MPL-2.0

use crate::lang::adapter::Adapter;
use crate::lang::args::eval_args;
use crate::lang::arity::Arity;
use crate::lang::arity::assert_func_arity;
use crate::lang::error::Error;
use crate::lang::machine::Machine;
use crate::lang::node::Node;
use crate::value::Value;
use crate::value::list::List;

pub(crate) fn slice(
    adapter: &impl Adapter,
    machine: &mut Machine<'_>,
    stdin: Option<&Value>,
    node: Node,
) -> Result<Value, Error> {
    assert_func_arity(adapter, machine, stdin, &node, &Arity::minmax(2, 3))?;

    let mut args = eval_args(adapter, machine, stdin, node)?;
    let list = args.pop().flatten().unwrap_or_default().into_parts();
    let len = list.len();

    let arg1 = pop_isize_arg(&mut args);
    let arg0 = pop_isize_arg(&mut args);
    let index0 = arg0.map(|a| resolve_reverse_arg(a, len));
    let index1 = arg1.map(|a| resolve_reverse_arg(a, len));

    let (start, end) = match (index0, index1) {
        (None, None) => (0, 0),
        (None, Some(a1)) => (a1, len),
        (Some(a0), None) => (a0, len),
        (Some(a0), Some(a1)) => (a0, a1),
    };

    let get0 = start.min(end);
    let get1 = end.min(len);
    let list = list.data.get(get0..get1).unwrap_or_default();
    let list = Value::from(List::from(list.to_vec()));

    Ok(list)
}

fn pop_isize_arg(args: &mut Vec<Option<Value>>) -> Option<isize> {
    args.pop()
        .flatten()
        .as_ref()
        .and_then(Value::as_number)
        .and_then(|a| isize::try_from(a).ok())
}

fn resolve_reverse_arg(mut index: isize, len: usize) -> usize {
    if index < 0 {
        index = isize::try_from(len)
            .unwrap_or_default()
            .saturating_sub(index.abs());
    }

    usize::try_from(index).unwrap_or_default()
}