use crate::scheme::environment::Environment;
use crate::scheme::value::{Procedure, Value};
use crate::grove::{Grove, Node};
use crate::fot::FotBuilder;
use gc::Gc;
use std::rc::Rc;
use std::cell::RefCell;
thread_local! {
static EVALUATOR_CONTEXT: RefCell<Option<EvaluatorContext>> = RefCell::new(None);
}
#[derive(Clone)]
pub struct EvaluatorContext {
pub grove: Option<Rc<dyn Grove>>,
pub current_node: Option<Rc<Box<dyn Node>>>,
}
pub fn get_evaluator_context() -> Option<EvaluatorContext> {
EVALUATOR_CONTEXT.with(|ctx| ctx.borrow().clone())
}
fn set_evaluator_context(ctx: EvaluatorContext) {
EVALUATOR_CONTEXT.with(|c| *c.borrow_mut() = Some(ctx));
}
fn clear_evaluator_context() {
EVALUATOR_CONTEXT.with(|c| *c.borrow_mut() = None);
}
#[derive(Debug, Clone)]
pub struct EvalError {
pub message: String,
}
impl EvalError {
pub fn new(message: String) -> Self {
EvalError { message }
}
}
impl std::fmt::Display for EvalError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Eval error: {}", self.message)
}
}
impl std::error::Error for EvalError {}
pub type EvalResult = Result<Value, EvalError>;
#[derive(Clone)]
pub struct ConstructionRule {
pub element_name: String,
pub expr: Value,
}
pub struct ProcessingMode {
pub rules: Vec<ConstructionRule>,
}
impl ProcessingMode {
pub fn new() -> Self {
ProcessingMode {
rules: Vec::new(),
}
}
pub fn add_rule(&mut self, element_name: String, expr: Value) {
self.rules.push(ConstructionRule { element_name, expr });
}
pub fn find_match(&self, gi: &str) -> Option<&ConstructionRule> {
self.rules.iter().find(|rule| rule.element_name == gi)
}
}
pub struct Evaluator {
grove: Option<Rc<dyn Grove>>,
current_node: Option<Rc<Box<dyn Node>>>,
processing_mode: ProcessingMode,
backend: Option<Rc<RefCell<dyn FotBuilder>>>,
}
impl Evaluator {
pub fn new() -> Self {
Evaluator {
grove: None,
current_node: None,
processing_mode: ProcessingMode::new(),
backend: None,
}
}
pub fn with_grove(grove: Rc<dyn Grove>) -> Self {
Evaluator {
grove: Some(grove),
current_node: None,
processing_mode: ProcessingMode::new(),
backend: None,
}
}
pub fn set_backend(&mut self, backend: Rc<RefCell<dyn FotBuilder>>) {
self.backend = Some(backend);
}
pub fn set_grove(&mut self, grove: Rc<dyn Grove>) {
self.grove = Some(grove);
}
pub fn grove(&self) -> Option<&Rc<dyn Grove>> {
self.grove.as_ref()
}
pub fn set_current_node(&mut self, node: Box<dyn Node>) {
self.current_node = Some(Rc::new(node));
}
pub fn current_node(&self) -> Option<Rc<Box<dyn Node>>> {
self.current_node.clone()
}
pub fn clear_current_node(&mut self) {
self.current_node = None;
}
pub fn process_root(&mut self, env: Gc<Environment>) -> EvalResult {
let root_node = match &self.grove {
Some(grove) => grove.root(),
None => return Err(EvalError::new("No grove set".to_string())),
};
self.current_node = Some(Rc::new(root_node));
self.process_node(env)
}
pub fn process_node(&mut self, env: Gc<Environment>) -> EvalResult {
let node = match &self.current_node {
Some(n) => n.clone(),
None => return Err(EvalError::new("No current node".to_string())),
};
let gi = match node.gi() {
Some(gi) => gi,
None => {
return Ok(Value::Unspecified);
}
};
let rule = self.processing_mode.find_match(&gi);
if let Some(rule) = rule {
self.eval(rule.expr.clone(), env)
} else {
Ok(Value::Unspecified)
}
}
pub fn eval(&mut self, expr: Value, env: Gc<Environment>) -> EvalResult {
set_evaluator_context(EvaluatorContext {
grove: self.grove.clone(),
current_node: self.current_node.clone(),
});
let result = self.eval_inner(expr, env);
clear_evaluator_context();
result
}
fn eval_inner(&mut self, expr: Value, env: Gc<Environment>) -> EvalResult {
match expr {
Value::Nil => Ok(Value::Nil),
Value::Bool(_) => Ok(expr),
Value::Integer(_) => Ok(expr),
Value::Real(_) => Ok(expr),
Value::Char(_) => Ok(expr),
Value::String(_) => Ok(expr),
Value::Procedure(_) => Ok(expr),
Value::Vector(_) => Ok(expr), Value::Unspecified => Ok(expr),
Value::Error => Ok(expr),
Value::Node(_) => Ok(expr),
Value::NodeList(_) => Ok(expr),
Value::Sosofo => Ok(expr),
Value::Symbol(ref name) => env
.lookup(name)
.ok_or_else(|| EvalError::new(format!("Undefined variable: {}", name))),
Value::Keyword(_) => Ok(expr),
Value::Pair(_) => self.eval_list(expr, env),
}
}
fn eval_list(&mut self, expr: Value, env: Gc<Environment>) -> EvalResult {
let (operator, args) = self.list_car_cdr(&expr)?;
if let Value::Symbol(ref sym) = operator {
match &**sym {
"quote" => self.eval_quote(args),
"if" => self.eval_if(args, env),
"define" => self.eval_define(args, env),
"set!" => self.eval_set(args, env),
"lambda" => self.eval_lambda(args, env),
"let" => self.eval_let(args, env),
"let*" => self.eval_let_star(args, env),
"letrec" => self.eval_letrec(args, env),
"begin" => self.eval_begin(args, env),
"cond" => self.eval_cond(args, env),
"case" => self.eval_case(args, env),
"and" => self.eval_and(args, env),
"or" => self.eval_or(args, env),
"apply" => self.eval_apply(args, env),
"map" => self.eval_map(args, env),
"for-each" => self.eval_for_each(args, env),
"load" => self.eval_load(args, env),
"define-language" => self.eval_define_language(args, env),
"declare-flow-object-class" => self.eval_declare_flow_object_class(args, env),
"declare-characteristic" => self.eval_declare_characteristic(args, env),
"element" => self.eval_element(args, env),
"process-children" => self.eval_process_children(env),
"make" => self.eval_make(args, env),
_ => self.eval_application(operator, args, env),
}
} else {
self.eval_application(operator, args, env)
}
}
fn list_car_cdr(&self, list: &Value) -> Result<(Value, Value), EvalError> {
if let Value::Pair(ref p) = list {
let pair = p.borrow();
Ok((pair.car.clone(), pair.cdr.clone()))
} else {
Err(EvalError::new("Expected list".to_string()))
}
}
fn vec_to_list(&self, vec: Vec<Value>) -> Value {
let mut result = Value::Nil;
for val in vec.iter().rev() {
result = Value::cons(val.clone(), result);
}
result
}
fn list_to_vec(&self, list: Value) -> Result<Vec<Value>, EvalError> {
let mut result = Vec::new();
let mut current = list;
loop {
match current {
Value::Nil => break,
Value::Pair(ref p) => {
let pair = p.borrow();
result.push(pair.car.clone());
let cdr = pair.cdr.clone();
drop(pair); current = cdr;
}
_ => return Err(EvalError::new("Improper list".to_string())),
}
}
Ok(result)
}
fn eval_quote(&mut self, args: Value) -> EvalResult {
let args_vec = self.list_to_vec(args)?;
if args_vec.len() != 1 {
return Err(EvalError::new("quote requires exactly 1 argument".to_string()));
}
Ok(args_vec[0].clone())
}
fn eval_if(&mut self, args: Value, env: Gc<Environment>) -> EvalResult {
let args_vec = self.list_to_vec(args)?;
if args_vec.len() < 2 || args_vec.len() > 3 {
return Err(EvalError::new(
"if requires 2 or 3 arguments".to_string(),
));
}
let test = self.eval_inner(args_vec[0].clone(), env.clone())?;
if test.is_true() {
self.eval_inner(args_vec[1].clone(), env)
} else if args_vec.len() == 3 {
self.eval_inner(args_vec[2].clone(), env)
} else {
Ok(Value::Unspecified)
}
}
fn eval_define(&mut self, args: Value, env: Gc<Environment>) -> EvalResult {
let args_vec = self.list_to_vec(args)?;
if args_vec.len() < 2 {
return Err(EvalError::new(
"define requires at least 2 arguments".to_string(),
));
}
match &args_vec[0] {
Value::Symbol(ref name) => {
if args_vec.len() != 2 {
return Err(EvalError::new(
"define with symbol requires exactly 2 arguments".to_string(),
));
}
let value = self.eval_inner(args_vec[1].clone(), env.clone())?;
env.define(name, value);
Ok(Value::Unspecified)
}
Value::Pair(_) => {
let (name_val, params) = self.list_car_cdr(&args_vec[0])?;
if let Value::Symbol(ref name) = name_val {
let lambda_body = args_vec[1..].to_vec();
let mut body_list = Value::Nil;
for expr in lambda_body.into_iter().rev() {
body_list = Value::cons(expr, body_list);
}
let lambda_expr = Value::cons(
Value::symbol("lambda"),
Value::cons(params, body_list),
);
let lambda_value = self.eval_inner(lambda_expr, env.clone())?;
env.define(name, lambda_value);
Ok(Value::Unspecified)
} else {
Err(EvalError::new(
"First element of define must be a symbol".to_string(),
))
}
}
_ => Err(EvalError::new(
"First argument to define must be symbol or list".to_string(),
)),
}
}
fn eval_define_language(&mut self, args: Value, env: Gc<Environment>) -> EvalResult {
let args_vec = self.list_to_vec(args)?;
if args_vec.is_empty() {
return Err(EvalError::new(
"define-language requires at least 1 argument".to_string(),
));
}
if let Value::Symbol(ref name) = args_vec[0] {
env.define(name, args_vec[0].clone());
Ok(Value::Unspecified)
} else {
Err(EvalError::new(
"First argument to define-language must be a symbol".to_string(),
))
}
}
fn eval_declare_flow_object_class(&mut self, args: Value, env: Gc<Environment>) -> EvalResult {
let args_vec = self.list_to_vec(args)?;
if args_vec.is_empty() {
return Err(EvalError::new(
"declare-flow-object-class requires at least 1 argument".to_string(),
));
}
if let Value::Symbol(ref name) = args_vec[0] {
env.define(name, args_vec[0].clone());
Ok(Value::Unspecified)
} else {
Err(EvalError::new(
"First argument to declare-flow-object-class must be a symbol".to_string(),
))
}
}
fn eval_declare_characteristic(&mut self, args: Value, env: Gc<Environment>) -> EvalResult {
let args_vec = self.list_to_vec(args)?;
if args_vec.len() < 3 {
return Err(EvalError::new(
"declare-characteristic requires at least 3 arguments (name, public-id, default-value)".to_string(),
));
}
if let Value::Symbol(ref name) = args_vec[0] {
let default_value = self.eval(args_vec[2].clone(), env.clone())?;
env.define(name, default_value);
Ok(Value::Unspecified)
} else {
Err(EvalError::new(
"First argument to declare-characteristic must be a symbol".to_string(),
))
}
}
fn eval_element(&mut self, args: Value, env: Gc<Environment>) -> EvalResult {
let args_vec = self.list_to_vec(args)?;
if args_vec.len() < 2 {
return Err(EvalError::new(
"element requires at least 2 arguments (element-name and construction-expression)".to_string(),
));
}
let element_name = if let Value::Symbol(ref name) = args_vec[0] {
name.clone()
} else {
return Err(EvalError::new(
"First argument to element must be a symbol".to_string(),
));
};
self.processing_mode.add_rule(element_name.to_string(), args_vec[1].clone());
Ok(Value::Unspecified)
}
fn eval_process_children(&mut self, env: Gc<Environment>) -> EvalResult {
let current_node = match &self.current_node {
Some(node) => node.clone(),
None => return Err(EvalError::new("No current node".to_string())),
};
let mut children = current_node.children();
let mut result = Value::Unspecified;
while !children.is_empty() {
if let Some(child_node) = children.first() {
let saved_node = self.current_node.clone();
self.current_node = Some(Rc::new(child_node));
result = self.process_node(env.clone())?;
self.current_node = saved_node;
}
children = children.rest();
}
Ok(result)
}
fn eval_make(&mut self, args: Value, env: Gc<Environment>) -> EvalResult {
let args_vec = self.list_to_vec(args)?;
if args_vec.is_empty() {
return Err(EvalError::new(
"make requires at least a flow object type".to_string(),
));
}
let fo_type = match &args_vec[0] {
Value::Symbol(s) => s.as_ref(),
_ => return Err(EvalError::new(
"make: first argument must be a flow object type symbol".to_string(),
)),
};
let mut i = 1;
let mut system_id = None;
let mut data = None;
while i < args_vec.len() {
match &args_vec[i] {
Value::Keyword(kw) => {
if i + 1 >= args_vec.len() {
return Err(EvalError::new(
format!("make: keyword {} requires a value", kw),
));
}
let value = self.eval(args_vec[i + 1].clone(), env.clone())?;
match kw.as_ref() {
"system-id" => {
if let Value::String(s) = value {
system_id = Some(s);
} else {
return Err(EvalError::new(
"make: system-id must be a string".to_string(),
));
}
}
"data" => {
if let Value::String(s) = value {
data = Some(s);
} else {
return Err(EvalError::new(
"make: data must be a string".to_string(),
));
}
}
_ => {
}
}
i += 2;
}
_ => {
let _result = self.eval(args_vec[i].clone(), env.clone())?;
i += 1;
}
}
}
match self.backend {
Some(ref backend) => {
match fo_type {
"entity" => {
if let Some(sid) = system_id {
let content = backend.borrow().current_output().to_string();
backend.borrow_mut().entity(&sid, &content)
.map_err(|e| EvalError::new(format!("Backend error: {}", e)))?;
backend.borrow_mut().clear_buffer();
} else {
return Err(EvalError::new(
"make entity requires system-id: keyword".to_string(),
));
}
}
"formatting-instruction" => {
if let Some(d) = data {
backend.borrow_mut().formatting_instruction(&d)
.map_err(|e| EvalError::new(format!("Backend error: {}", e)))?;
} else {
return Err(EvalError::new(
"make formatting-instruction requires data: keyword".to_string(),
));
}
}
_ => {
return Ok(Value::Unspecified);
}
}
}
None => {
return Err(EvalError::new(
"make: no backend available".to_string(),
));
}
}
Ok(Value::Unspecified)
}
fn eval_set(&mut self, args: Value, env: Gc<Environment>) -> EvalResult {
let args_vec = self.list_to_vec(args)?;
if args_vec.len() != 2 {
return Err(EvalError::new(
"set! requires exactly 2 arguments".to_string(),
));
}
if let Value::Symbol(ref name) = args_vec[0] {
let value = self.eval(args_vec[1].clone(), env.clone())?;
env.set(name, value)
.map_err(|e| EvalError::new(e))?;
Ok(Value::Unspecified)
} else {
Err(EvalError::new(
"First argument to set! must be a symbol".to_string(),
))
}
}
fn eval_lambda(&mut self, args: Value, env: Gc<Environment>) -> EvalResult {
let args_vec = self.list_to_vec(args)?;
if args_vec.len() < 2 {
return Err(EvalError::new(
"lambda requires at least 2 arguments (params and body)".to_string(),
));
}
let params_list = &args_vec[0];
let params_vec = if params_list.is_nil() {
Vec::new()
} else {
self.list_to_vec(params_list.clone())?
};
let mut param_names = Vec::new();
for param in params_vec {
if let Value::Symbol(ref name) = param {
param_names.push(name.to_string());
} else {
return Err(EvalError::new(format!(
"Lambda parameter must be a symbol, got: {:?}",
param
)));
}
}
let body = if args_vec.len() == 2 {
args_vec[1].clone()
} else {
let mut body_list = Value::Nil;
for expr in args_vec[1..].iter().rev() {
body_list = Value::cons(expr.clone(), body_list);
}
Value::cons(Value::symbol("begin"), body_list)
};
Ok(Value::lambda(param_names, body, env))
}
fn eval_let(&mut self, args: Value, env: Gc<Environment>) -> EvalResult {
let args_vec = self.list_to_vec(args)?;
if args_vec.len() < 2 {
return Err(EvalError::new(
"let requires at least 2 arguments".to_string(),
));
}
if let Value::Symbol(ref loop_name) = args_vec[0] {
if args_vec.len() < 3 {
return Err(EvalError::new(
"named let requires at least 3 arguments".to_string(),
));
}
let bindings_list = &args_vec[1];
let bindings = self.list_to_vec(bindings_list.clone())?;
let body = &args_vec[2..];
let mut var_names = Vec::new();
let mut init_values = Vec::new();
for binding in &bindings {
let binding_vec = self.list_to_vec(binding.clone())?;
if binding_vec.len() != 2 {
return Err(EvalError::new(
"named let binding must have exactly 2 elements".to_string(),
));
}
var_names.push(binding_vec[0].clone());
init_values.push(binding_vec[1].clone());
}
let lambda_params = self.vec_to_list(var_names);
let mut lambda_body = vec![Value::symbol("lambda"), lambda_params];
lambda_body.extend_from_slice(body);
let lambda_expr = self.vec_to_list(lambda_body);
let letrec_binding = Value::cons(
Value::symbol(loop_name),
Value::cons(lambda_expr, Value::Nil),
);
let letrec_bindings = Value::cons(letrec_binding, Value::Nil);
let mut call_expr = vec![Value::symbol(loop_name)];
call_expr.extend_from_slice(&init_values);
let call = self.vec_to_list(call_expr);
return self.eval_letrec(self.vec_to_list(vec![letrec_bindings, call]), env);
}
let bindings_list = &args_vec[0];
let bindings = self.list_to_vec(bindings_list.clone())?;
let new_env = Environment::extend(env.clone());
for binding in bindings {
let binding_vec = self.list_to_vec(binding)?;
if binding_vec.len() != 2 {
return Err(EvalError::new(
"let binding must have exactly 2 elements".to_string(),
));
}
if let Value::Symbol(ref name) = binding_vec[0] {
let value = self.eval_inner(binding_vec[1].clone(), env.clone())?;
new_env.define(name, value);
} else {
return Err(EvalError::new(
"Binding variable must be a symbol".to_string(),
));
}
}
let body = &args_vec[1..];
self.eval_sequence(body, new_env)
}
fn eval_let_star(&mut self, args: Value, env: Gc<Environment>) -> EvalResult {
let args_vec = self.list_to_vec(args)?;
if args_vec.len() < 2 {
return Err(EvalError::new(
"let* requires at least 2 arguments".to_string(),
));
}
let bindings_list = &args_vec[0];
let bindings = self.list_to_vec(bindings_list.clone())?;
let current_env = Environment::extend(env);
for binding in bindings {
let binding_vec = self.list_to_vec(binding)?;
if binding_vec.len() != 2 {
return Err(EvalError::new(
"let* binding must have exactly 2 elements".to_string(),
));
}
if let Value::Symbol(ref name) = binding_vec[0] {
let value = self.eval_inner(binding_vec[1].clone(), current_env.clone())?;
current_env.define(name, value);
} else {
return Err(EvalError::new(
"Binding variable must be a symbol".to_string(),
));
}
}
let body = &args_vec[1..];
self.eval_sequence(body, current_env)
}
fn eval_letrec(&mut self, args: Value, env: Gc<Environment>) -> EvalResult {
let args_vec = self.list_to_vec(args)?;
if args_vec.len() < 2 {
return Err(EvalError::new(
"letrec requires at least 2 arguments".to_string(),
));
}
let bindings_list = &args_vec[0];
let bindings = self.list_to_vec(bindings_list.clone())?;
let new_env = Environment::extend(env);
let mut var_names = Vec::new();
for binding in &bindings {
let binding_vec = self.list_to_vec(binding.clone())?;
if binding_vec.len() != 2 {
return Err(EvalError::new(
"letrec binding must have exactly 2 elements".to_string(),
));
}
if let Value::Symbol(ref name) = binding_vec[0] {
var_names.push(name.to_string());
new_env.define(name, Value::Unspecified);
} else {
return Err(EvalError::new(
"Binding variable must be a symbol".to_string(),
));
}
}
for (i, binding) in bindings.iter().enumerate() {
let binding_vec = self.list_to_vec(binding.clone())?;
let value = self.eval_inner(binding_vec[1].clone(), new_env.clone())?;
new_env.set(&var_names[i], value)
.map_err(|e| EvalError::new(e))?;
}
let body = &args_vec[1..];
self.eval_sequence(body, new_env)
}
fn eval_begin(&mut self, args: Value, env: Gc<Environment>) -> EvalResult {
let args_vec = self.list_to_vec(args)?;
self.eval_sequence(&args_vec, env)
}
fn eval_cond(&mut self, args: Value, env: Gc<Environment>) -> EvalResult {
let clauses = self.list_to_vec(args)?;
for clause in clauses {
let clause_vec = self.list_to_vec(clause)?;
if clause_vec.is_empty() {
return Err(EvalError::new("Empty cond clause".to_string()));
}
if let Value::Symbol(ref sym) = clause_vec[0] {
if &**sym == "else" {
return self.eval_sequence(&clause_vec[1..], env);
}
}
let test = self.eval_inner(clause_vec[0].clone(), env.clone())?;
if test.is_true() {
if clause_vec.len() == 1 {
return Ok(test);
} else {
return self.eval_sequence(&clause_vec[1..], env);
}
}
}
Ok(Value::Unspecified)
}
fn eval_case(&mut self, args: Value, env: Gc<Environment>) -> EvalResult {
let args_vec = self.list_to_vec(args)?;
if args_vec.is_empty() {
return Err(EvalError::new("case requires at least 1 argument".to_string()));
}
let key = self.eval_inner(args_vec[0].clone(), env.clone())?;
for clause in &args_vec[1..] {
let clause_vec = self.list_to_vec(clause.clone())?;
if clause_vec.is_empty() {
return Err(EvalError::new("Empty case clause".to_string()));
}
if let Value::Symbol(ref sym) = clause_vec[0] {
if &**sym == "else" {
return self.eval_sequence(&clause_vec[1..], env);
}
}
let datums = self.list_to_vec(clause_vec[0].clone())?;
for datum in datums {
if key.eqv(&datum) {
if clause_vec.len() == 1 {
return Ok(Value::Unspecified);
} else {
return self.eval_sequence(&clause_vec[1..], env);
}
}
}
}
Ok(Value::Unspecified)
}
fn eval_and(&mut self, args: Value, env: Gc<Environment>) -> EvalResult {
let args_vec = self.list_to_vec(args)?;
if args_vec.is_empty() {
return Ok(Value::bool(true));
}
let mut result = Value::bool(true);
for expr in args_vec {
result = self.eval_inner(expr, env.clone())?;
if !result.is_true() {
return Ok(Value::bool(false));
}
}
Ok(result)
}
fn eval_or(&mut self, args: Value, env: Gc<Environment>) -> EvalResult {
let args_vec = self.list_to_vec(args)?;
for expr in args_vec {
let result = self.eval_inner(expr, env.clone())?;
if result.is_true() {
return Ok(result);
}
}
Ok(Value::bool(false))
}
fn eval_sequence(&mut self, exprs: &[Value], env: Gc<Environment>) -> EvalResult {
if exprs.is_empty() {
return Ok(Value::Unspecified);
}
let mut result = Value::Unspecified;
for expr in exprs {
result = self.eval_inner(expr.clone(), env.clone())?;
}
Ok(result)
}
fn eval_apply(&mut self, args: Value, env: Gc<Environment>) -> EvalResult {
let args_vec = self.list_to_vec(args)?;
if args_vec.len() != 2 {
return Err(EvalError::new(
"apply requires exactly 2 arguments".to_string(),
));
}
let proc = self.eval_inner(args_vec[0].clone(), env.clone())?;
let arg_list = self.eval_inner(args_vec[1].clone(), env)?;
let arg_values = self.list_to_vec(arg_list)?;
self.apply(proc, arg_values)
}
fn eval_map(&mut self, args: Value, env: Gc<Environment>) -> EvalResult {
let args_vec = self.list_to_vec(args)?;
if args_vec.len() < 2 {
return Err(EvalError::new("map requires at least 2 arguments".to_string()));
}
let proc = self.eval_inner(args_vec[0].clone(), env.clone())?;
let mut lists = Vec::new();
for i in 1..args_vec.len() {
let list = self.eval_inner(args_vec[i].clone(), env.clone())?;
let list_vec = self.list_to_vec(list)?;
lists.push(list_vec);
}
if lists.is_empty() {
return Ok(Value::Nil);
}
let length = lists[0].len();
for list in &lists[1..] {
if list.len() != length {
return Err(EvalError::new(
"map: all lists must have the same length".to_string(),
));
}
}
let mut result_vec = Vec::new();
for i in 0..length {
let mut proc_args = Vec::new();
for list in &lists {
proc_args.push(list[i].clone());
}
let result = self.apply(proc.clone(), proc_args)?;
result_vec.push(result);
}
let mut result_list = Value::Nil;
for elem in result_vec.into_iter().rev() {
result_list = Value::cons(elem, result_list);
}
Ok(result_list)
}
fn eval_for_each(&mut self, args: Value, env: Gc<Environment>) -> EvalResult {
let args_vec = self.list_to_vec(args)?;
if args_vec.len() < 2 {
return Err(EvalError::new(
"for-each requires at least 2 arguments".to_string(),
));
}
let proc = self.eval_inner(args_vec[0].clone(), env.clone())?;
let mut lists = Vec::new();
for i in 1..args_vec.len() {
let list = self.eval_inner(args_vec[i].clone(), env.clone())?;
let list_vec = self.list_to_vec(list)?;
lists.push(list_vec);
}
if lists.is_empty() {
return Ok(Value::Unspecified);
}
let length = lists[0].len();
for list in &lists[1..] {
if list.len() != length {
return Err(EvalError::new(
"for-each: all lists must have the same length".to_string(),
));
}
}
for i in 0..length {
let mut proc_args = Vec::new();
for list in &lists {
proc_args.push(list[i].clone());
}
self.apply(proc.clone(), proc_args)?;
}
Ok(Value::Unspecified)
}
fn eval_load(&mut self, args: Value, env: Gc<Environment>) -> EvalResult {
let args_vec = self.list_to_vec(args)?;
if args_vec.len() != 1 {
return Err(EvalError::new(
"load requires exactly 1 argument".to_string(),
));
}
let filename_val = self.eval_inner(args_vec[0].clone(), env.clone())?;
let filename = match filename_val {
Value::String(s) => s.to_string(),
_ => return Err(EvalError::new(
format!("load: filename must be a string, got {:?}", filename_val)
)),
};
let contents = std::fs::read_to_string(&filename)
.map_err(|e| EvalError::new(format!("load: cannot read file '{}': {}", filename, e)))?;
let mut parser = crate::scheme::parser::Parser::new(&contents);
let mut result = Value::Unspecified;
loop {
match parser.parse() {
Ok(expr) => {
result = self.eval_inner(expr, env.clone())?;
}
Err(e) => {
let error_msg = e.to_string();
if error_msg.contains("Unexpected end of input")
|| error_msg.contains("Expected")
|| error_msg.contains("EOF") {
break;
}
return Err(EvalError::new(
format!("load: parse error in '{}': {}", filename, e)
));
}
}
}
Ok(result)
}
fn eval_application(
&mut self,
operator: Value,
args: Value,
env: Gc<Environment>,
) -> EvalResult {
let proc = self.eval_inner(operator, env.clone())?;
let args_vec = self.list_to_vec(args)?;
let mut evaled_args = Vec::new();
for arg in args_vec {
evaled_args.push(self.eval_inner(arg, env.clone())?);
}
self.apply(proc, evaled_args)
}
fn apply(&mut self, proc: Value, args: Vec<Value>) -> EvalResult {
if let Value::Procedure(ref p) = proc {
match &**p {
Procedure::Primitive { func, .. } => {
func(&args).map_err(|e| EvalError::new(e))
}
Procedure::Lambda { params, body, env } => {
if args.len() != params.len() {
return Err(EvalError::new(format!(
"Lambda expects {} arguments, got {}",
params.len(),
args.len()
)));
}
let lambda_env = Environment::extend(env.clone());
for (param_name, arg_value) in params.iter().zip(args.iter()) {
lambda_env.define(param_name, arg_value.clone());
}
self.eval_inner((**body).clone(), lambda_env)
}
}
} else {
Err(EvalError::new(format!(
"Not a procedure: {:?}",
proc
)))
}
}
}
impl Default for Evaluator {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
fn make_env() -> Gc<Environment> {
Environment::new_global()
}
#[test]
fn test_eval_self_evaluating() {
let mut eval = Evaluator::new();
let env = make_env();
assert!(eval.eval(Value::integer(42), env.clone()).unwrap().is_integer());
assert!(eval.eval(Value::bool(true), env.clone()).unwrap().is_bool());
assert!(eval.eval(Value::string("hello".to_string()), env).unwrap().is_string());
}
#[test]
fn test_eval_quote() {
let mut eval = Evaluator::new();
let env = make_env();
let expr = Value::cons(
Value::symbol("quote"),
Value::cons(
Value::cons(
Value::integer(1),
Value::cons(Value::integer(2), Value::cons(Value::integer(3), Value::Nil)),
),
Value::Nil,
),
);
let result = eval.eval(expr, env).unwrap();
assert!(result.is_list());
}
#[test]
fn test_eval_if_true() {
let mut eval = Evaluator::new();
let env = make_env();
let expr = Value::cons(
Value::symbol("if"),
Value::cons(
Value::bool(true),
Value::cons(Value::integer(1), Value::cons(Value::integer(2), Value::Nil)),
),
);
let result = eval.eval(expr, env).unwrap();
if let Value::Integer(n) = result {
assert_eq!(n, 1);
} else {
panic!("Expected integer 1");
}
}
#[test]
fn test_eval_if_false() {
let mut eval = Evaluator::new();
let env = make_env();
let expr = Value::cons(
Value::symbol("if"),
Value::cons(
Value::bool(false),
Value::cons(Value::integer(1), Value::cons(Value::integer(2), Value::Nil)),
),
);
let result = eval.eval(expr, env).unwrap();
if let Value::Integer(n) = result {
assert_eq!(n, 2);
} else {
panic!("Expected integer 2");
}
}
#[test]
fn test_eval_define() {
let mut eval = Evaluator::new();
let env = make_env();
let expr = Value::cons(
Value::symbol("define"),
Value::cons(Value::symbol("x"), Value::cons(Value::integer(42), Value::Nil)),
);
eval.eval(expr, env.clone()).unwrap();
assert!(env.is_defined("x"));
if let Value::Integer(n) = env.lookup("x").unwrap() {
assert_eq!(n, 42);
}
}
#[test]
fn test_eval_symbol_lookup() {
let mut eval = Evaluator::new();
let env = make_env();
env.define("x", Value::integer(99));
let result = eval.eval(Value::symbol("x"), env).unwrap();
if let Value::Integer(n) = result {
assert_eq!(n, 99);
} else {
panic!("Expected integer 99");
}
}
#[test]
fn test_eval_and() {
let mut eval = Evaluator::new();
let env = make_env();
let expr = Value::cons(
Value::symbol("and"),
Value::cons(Value::bool(true), Value::cons(Value::bool(true), Value::Nil)),
);
let result = eval.eval(expr, env.clone()).unwrap();
assert!(result.is_true());
let expr = Value::cons(
Value::symbol("and"),
Value::cons(Value::bool(true), Value::cons(Value::bool(false), Value::Nil)),
);
let result = eval.eval(expr, env).unwrap();
assert!(!result.is_true());
}
#[test]
fn test_eval_or() {
let mut eval = Evaluator::new();
let env = make_env();
let expr = Value::cons(
Value::symbol("or"),
Value::cons(Value::bool(false), Value::cons(Value::bool(true), Value::Nil)),
);
let result = eval.eval(expr, env.clone()).unwrap();
assert!(result.is_true());
let expr = Value::cons(
Value::symbol("or"),
Value::cons(Value::bool(false), Value::cons(Value::bool(false), Value::Nil)),
);
let result = eval.eval(expr, env).unwrap();
assert!(!result.is_true());
}
#[test]
fn test_eval_lambda_creation() {
let mut eval = Evaluator::new();
let env = make_env();
let expr = Value::cons(
Value::symbol("lambda"),
Value::cons(
Value::cons(Value::symbol("x"), Value::Nil),
Value::cons(Value::symbol("x"), Value::Nil),
),
);
let result = eval.eval(expr, env).unwrap();
assert!(result.is_procedure());
}
#[test]
fn test_eval_lambda_application() {
let mut eval = Evaluator::new();
let env = make_env();
let lambda_expr = Value::cons(
Value::symbol("lambda"),
Value::cons(
Value::cons(Value::symbol("x"), Value::Nil),
Value::cons(Value::symbol("x"), Value::Nil),
),
);
let app_expr = Value::cons(lambda_expr, Value::cons(Value::integer(42), Value::Nil));
let result = eval.eval(app_expr, env).unwrap();
if let Value::Integer(n) = result {
assert_eq!(n, 42);
} else {
panic!("Expected integer 42");
}
}
#[test]
fn test_eval_lambda_multiple_params() {
let mut eval = Evaluator::new();
let env = make_env();
let params = Value::cons(Value::symbol("x"), Value::cons(Value::symbol("y"), Value::Nil));
let body = Value::symbol("x");
let lambda_expr = Value::cons(Value::symbol("lambda"), Value::cons(params, Value::cons(body, Value::Nil)));
let app_expr = Value::cons(
lambda_expr,
Value::cons(Value::integer(1), Value::cons(Value::integer(2), Value::Nil)),
);
let result = eval.eval(app_expr, env).unwrap();
if let Value::Integer(n) = result {
assert_eq!(n, 1);
} else {
panic!("Expected integer 1");
}
}
#[test]
fn test_eval_lambda_wrong_arg_count() {
let mut eval = Evaluator::new();
let env = make_env();
let lambda_expr = Value::cons(
Value::symbol("lambda"),
Value::cons(
Value::cons(Value::symbol("x"), Value::Nil),
Value::cons(Value::symbol("x"), Value::Nil),
),
);
let app_expr = Value::cons(
lambda_expr,
Value::cons(Value::integer(1), Value::cons(Value::integer(2), Value::Nil)),
);
let result = eval.eval(app_expr, env);
assert!(result.is_err());
}
#[test]
fn test_eval_lambda_closure() {
let mut eval = Evaluator::new();
let env = make_env();
env.define("x", Value::integer(10));
let lambda_expr = Value::cons(
Value::symbol("lambda"),
Value::cons(
Value::cons(Value::symbol("y"), Value::Nil),
Value::cons(Value::symbol("x"), Value::Nil),
),
);
let app_expr = Value::cons(lambda_expr, Value::cons(Value::integer(20), Value::Nil));
let result = eval.eval(app_expr, env).unwrap();
if let Value::Integer(n) = result {
assert_eq!(n, 10); } else {
panic!("Expected integer 10 from closure");
}
}
#[test]
fn test_eval_lambda_no_params() {
let mut eval = Evaluator::new();
let env = make_env();
let lambda_expr = Value::cons(
Value::symbol("lambda"),
Value::cons(Value::Nil, Value::cons(Value::integer(42), Value::Nil)),
);
let app_expr = Value::cons(lambda_expr, Value::Nil);
let result = eval.eval(app_expr, env).unwrap();
if let Value::Integer(n) = result {
assert_eq!(n, 42);
} else {
panic!("Expected integer 42");
}
}
#[test]
fn test_eval_lambda_multiple_body_expressions() {
let mut eval = Evaluator::new();
let env = make_env();
let params = Value::cons(Value::symbol("x"), Value::Nil);
let body1 = Value::integer(1);
let body2 = Value::integer(2);
let body3 = Value::symbol("x");
let lambda_expr = Value::cons(
Value::symbol("lambda"),
Value::cons(
params,
Value::cons(body1, Value::cons(body2, Value::cons(body3, Value::Nil))),
),
);
let app_expr = Value::cons(lambda_expr, Value::cons(Value::integer(99), Value::Nil));
let result = eval.eval(app_expr, env).unwrap();
if let Value::Integer(n) = result {
assert_eq!(n, 99);
} else {
panic!("Expected integer 99");
}
}
}