pub mod apply;
mod pair;
mod sentence;
use crate::{
Environment,
eval::{apply::eval_apply, sentence::eval_sentence},
token::{TokenType, source_to_token},
value::Value,
};
pub fn eval(source: &str, env: &Environment) -> Option<(Value, Environment)> {
let mut current_val = Value::Unit;
let mut current_environment = env.clone();
let mut local_environment = Environment::new();
if let Some(tokens) = source_to_token(source) {
for sentence in tokens
.split(|token| match token.value {
TokenType::SentenceSeperator => true,
_ => false,
})
.filter(|s| !s.is_empty())
{
if let Some((val, new_env)) = eval_sentence(sentence, ¤t_environment)
.map(|val| eval_apply(&val, ¤t_environment))
.flatten()
{
local_environment.extend(new_env.clone());
current_environment.extend(new_env.clone());
current_val = val;
} else {
return None;
}
}
} else {
return None;
}
Some((current_val, local_environment))
}
pub(crate) fn extract_lambda_env(params: &[String], body: &Value, env: &Environment) -> Environment {
let mut local_environment = Environment::new();
let mut current_environment = env.clone();
match body {
Value::Identity(id) => {
if !(params.contains(id) || local_environment.contains_key(id)) {
if let Some(val) = current_environment.get(id) {
let _ = local_environment.insert(id.clone(), val.clone());
}
}
}
Value::List(elements) => {
for element in elements.iter() {
let new_env = extract_lambda_env(params, element, ¤t_environment);
local_environment.extend(new_env.clone());
current_environment.extend(new_env);
}
}
Value::Lambda(inner_params, sub_func, inner_env) => {
let mut capture = current_environment.clone();
capture.extend(inner_env.clone());
let mut all_params = params.to_vec();
all_params.extend(inner_params.clone());
let new_env = extract_lambda_env(&all_params, sub_func, &capture);
local_environment.extend(new_env);
}
Value::Apply(arguments, sub_func) => {
for argument in arguments.iter() {
let new_env = extract_lambda_env(params, argument, ¤t_environment);
local_environment.extend(new_env.clone());
current_environment.extend(new_env);
}
let new_env = extract_lambda_env(params, sub_func, ¤t_environment);
local_environment.extend(new_env);
}
_ => (),
}
local_environment
}