ksl 0.1.5

KSL core library and interpreter
Documentation
use crate::{
    Environment,
    token::{Token, TokenType},
    value::Value,
};

#[derive(Debug, PartialEq)]
pub(crate) enum PairType {
    Function,
    List,
}

pub(crate) fn eval_pair(
    tokens: &[Token],
    env: &Environment,
    pair_type: PairType,
) -> Option<(Vec<Value>, usize)> {
    let mut token_index: usize = 0;
    let mut is_closed = false;
    let mut is_checked = false;
    let mut vals: Vec<Value> = Vec::new();
    while let Some(token) = tokens.get(token_index) {
        match &token.value {
            TokenType::Atom(a) if !is_checked => {
                is_checked = true;
                token_index += 1;
                vals.push(Value::Atom(a.clone()));
            }
            TokenType::Number(n) if !is_checked => {
                is_checked = true;
                token_index += 1;
                vals.push(Value::Number(n.clone()));
            }
            TokenType::String(s) if !is_checked => {
                is_checked = true;
                token_index += 1;
                vals.push(Value::String(s.clone()));
            }
            TokenType::Char(c) if !is_checked => {
                is_checked = true;
                token_index += 1;
                vals.push(Value::String(String::from(*c as char)));
            }
            TokenType::Identity(id) if !is_checked => {
                is_checked = true;
                if let Some(tok) = tokens.get(token_index + 1) {
                    match tok.value {
                        TokenType::FuncListOpen => {
                            token_index += 1;
                            let arguments = eval_pair(
                                &tokens[(token_index + 1)..],
                                env,
                                PairType::Function,
                            );
                            if let Some((args, bias)) = arguments {
                                token_index += bias + 1;
                                vals.push(Value::Apply(
                                    args,
                                    Box::new(Value::Identity(id.clone())),
                                ));
                            } else {
                                eprintln!(
                                    concat!(
                                        "Error[ksl::eval::eval_pair]: ",
                                        "Failed to apply function `{}`."
                                    ),
                                    id
                                );
                                return None;
                            }
                        }
                        _ => {
                            token_index += 1;
                            vals.push(Value::Identity(id.clone()));
                        }
                    }
                }
            }
            TokenType::ListOpen if !is_checked => {
                is_checked = true;
                let inner_list = eval_pair(&tokens[(token_index + 1)..], env, PairType::List);
                if let Some((contents, bias)) = inner_list {
                    token_index += bias + 1;
                    vals.push(Value::List(contents));
                } else {
                    eprintln!(concat!(
                        "Error[ksl::eval::eval_pair]: ",
                        "Failed to get nested list."
                    ),);
                    return None;
                }
            }
            TokenType::Seperator if is_checked => {
                is_checked = false;
                token_index += 1;
            }
            TokenType::FuncListClose if pair_type == PairType::Function => {
                is_closed = true;
                token_index += 1;
                break;
            }
            TokenType::ListClose if pair_type == PairType::List => {
                is_closed = true;
                token_index += 1;
                break;
            }
            _ => {
                eprintln!(
                    concat!(
                        "Error[ksl::eval::eval_pair]: ",
                        "Unknown token `{:?}` at ({}, {})."
                    ),
                    token.value, token.position.0.0, token.position.0.1
                );
                return None;
            }
        }
    }
    if is_closed {
        Some((vals, token_index))
    } else {
        eprintln!(
            concat!("Error[ksl::eval::eval_pair]: ", "Unclosed pair of {:?}."),
            pair_type
        );
        None
    }
}