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
}
}