ksl 0.1.30

KSL core library and interpreter
Documentation
//! # ksl::eval::sentence
//!
//! Defines a function that evaluates a KSL sentence.

use crate::{
    Environment,
    eval::pair::{PairType, eval_pair},
    token::{Token, TokenType},
    value::Value,
};

/// Parses a primary value followed by optional function application chains.
pub(crate) fn eval_expression(tokens: &[Token], env: Environment) -> Result<(Value, usize), std::sync::Arc<str>> {
    let mut current_idx = 0;
    let first_token = tokens.get(current_idx).ok_or_else(|| {
        std::sync::Arc::from(concat!(
            "Error[ksl::eval::sentence::eval_expression]: ",
            "Unexpected end of tokens."
        ))
    })?;

    // parse the base value
    let mut val = match &first_token.value {
        TokenType::Atom(a) => Value::Atom(std::sync::Arc::from(a.iter().collect::<String>())),
        TokenType::String(s) => Value::String(std::sync::Arc::from(s.iter().collect::<String>())),
        TokenType::Char(c) => Value::String(std::sync::Arc::from(String::from(*c))),
        TokenType::Number(n) => Value::Number(*n),
        TokenType::Symbol(sym) => Value::Symbol(std::sync::Arc::from(sym.iter().collect::<String>())),
        TokenType::ListOpen => {
            let (list_vals, bias) = eval_pair(&tokens[1..], env.clone(), PairType::List)?;
            current_idx += bias;
            Value::List(std::sync::Arc::from(list_vals))
        }
        _ => {
            return Err(std::sync::Arc::from(format!(
                concat!(
                    "Error[ksl::eval::sentence::eval_expression]: ",
                    "Invalid token type `{:?}` at `({}, {})`."
                ),
                first_token.value, first_token.location.0.0, first_token.location.0.1
            )));
        }
    };
    current_idx += 1;

    // consume chained applications
    while let Some(next_tok) = tokens.get(current_idx) {
        if matches!(next_tok.value, TokenType::FuncListOpen) {
            let (args, bias) = eval_pair(&tokens[current_idx + 1..], env.clone(), PairType::Function)?;
            val = Value::Apply(args, std::sync::Arc::new(val));
            current_idx += bias + 1;
        } else {
            break;
        }
    }

    Ok((val, current_idx))
}

/// Evaluation of a KSL sentence.
pub(crate) fn eval_sentence(tokens: &[Token], env: Environment) -> Result<Value, std::sync::Arc<str>> {
    let (val, consumed) = eval_expression(tokens, env)?;

    // ensure no trailing tokens exist in the sentence
    if let Some(extra) = tokens.get(consumed) {
        return Err(std::sync::Arc::from(format!(
            concat!(
                "Error[ksl::eval::sentence::eval_sentence]: ",
                "Invalid token type `{:?}` at `({}, {})`."
            ),
            extra.value, extra.location.0.0, extra.location.0.1
        )));
    }
    Ok(val)
}