use std::rc::Rc;
use crate::sexpr::SExpr;
use super::env::{Env, EnvFrame};
use super::value::{value_to_sexpr, LispError, Params, Value};
enum Step {
Done(Value),
Tail(SExpr, Env),
}
pub fn eval(expr: SExpr, env: Env) -> Result<Value, LispError> {
let mut cur_expr = expr;
let mut cur_env = env;
loop {
match eval_step(cur_expr, Rc::clone(&cur_env))? {
Step::Done(v) => return Ok(v),
Step::Tail(e, new_env) => {
cur_expr = e;
cur_env = new_env;
}
}
}
}
pub fn eval_apply(func: &Value, args: &[Value]) -> Result<Value, LispError> {
match func {
Value::Lambda { params, body, env } => {
let frame = EnvFrame::child(env);
bind_params(params, args, &frame)?;
eval_body(body, frame)
}
Value::Native(_, f) => f(args),
other => Err(LispError::new(format!(
"not a procedure: {}",
other.type_name()
))),
}
}
fn eval_step(expr: SExpr, env: Env) -> Result<Step, LispError> {
match expr {
SExpr::Str(s) => Ok(Step::Done(Value::Str(s))),
SExpr::Atom(ref s) => {
if s == "#t" || s == "#true" {
return Ok(Step::Done(Value::Bool(true)));
}
if s == "#f" || s == "#false" {
return Ok(Step::Done(Value::Bool(false)));
}
if let Ok(n) = s.parse::<i64>() {
return Ok(Step::Done(Value::Int(n)));
}
if s.contains('.') || s.contains('e') || s.contains('E') {
if let Ok(f) = s.parse::<f64>() {
return Ok(Step::Done(Value::Float(f)));
}
}
if s.starts_with(':') {
return Ok(Step::Done(Value::Symbol(s.clone())));
}
let val = env.borrow().lookup(s)?;
Ok(Step::Done(val))
}
SExpr::List(ref items) if items.is_empty() => Ok(Step::Done(Value::Nil)),
SExpr::List(items) => eval_list(items, env),
SExpr::DottedList(_, _) => Err(LispError::new("cannot evaluate dotted list as expression")),
}
}
fn eval_list(items: Vec<SExpr>, env: Env) -> Result<Step, LispError> {
let head = items[0].clone();
let tail = &items[1..];
if let SExpr::Atom(ref name) = head {
match name.as_str() {
"quote" => return eval_quote(tail),
"quasiquote" => {
if tail.len() != 1 {
return Err(LispError::new("quasiquote: expected 1 argument"));
}
return Ok(Step::Done(eval_quasiquote(&tail[0], &env)?));
}
"if" => return eval_if(tail, env),
"cond" => return eval_cond(tail, env),
"when" => return eval_when(tail, env, false),
"unless" => return eval_when(tail, env, true),
"and" => return eval_and(tail, env),
"or" => return eval_or(tail, env),
"begin" => return eval_begin(tail, env),
"define" => return eval_define(tail, env),
"set!" => return eval_set(tail, env),
"lambda" => return eval_lambda(tail, env),
"defmacro" => return eval_defmacro(tail, env),
"let" => return eval_let(tail, env),
"let*" => return eval_let_star(tail, env),
"letrec" => return eval_letrec(tail, env),
"do" => return eval_do(tail, env),
"guard" => return eval_guard(tail, env),
_ => {}
}
}
let func = eval(head, Rc::clone(&env))?;
if let Value::Macro {
params,
body,
env: mac_env,
..
} = func.clone()
{
let raw_args: Vec<Value> = tail.iter().map(sexpr_to_datum).collect();
let mac_frame = EnvFrame::child(&mac_env);
bind_params(¶ms, &raw_args, &mac_frame)?;
let expansion = eval_body(&body, mac_frame)?;
let expansion_sexpr = value_to_sexpr(expansion)
.map_err(|e| LispError::new(format!("macro expansion error: {}", e.message)))?;
return Ok(Step::Tail(expansion_sexpr, env));
}
let args: Vec<Value> = tail
.iter()
.map(|e| eval(e.clone(), Rc::clone(&env)))
.collect::<Result<_, _>>()?;
match &func {
Value::Lambda {
params,
body,
env: closure_env,
} => {
let frame = EnvFrame::child(closure_env);
bind_params(params, &args, &frame)?;
let n = body.len();
for expr in &body[..n.saturating_sub(1)] {
eval(expr.clone(), Rc::clone(&frame))?;
}
if n == 0 {
Ok(Step::Done(Value::Nil))
} else {
Ok(Step::Tail(body[n - 1].clone(), frame))
}
}
Value::Native(_, f) => Ok(Step::Done(f(&args)?)),
other => Err(LispError::new(format!(
"not a procedure: {}",
other.type_name()
))),
}
}
fn eval_quote(tail: &[SExpr]) -> Result<Step, LispError> {
if tail.len() != 1 {
return Err(LispError::new("quote: expected 1 argument"));
}
Ok(Step::Done(sexpr_to_datum(&tail[0])))
}
pub fn sexpr_to_datum(expr: &SExpr) -> Value {
match expr {
SExpr::Atom(s) => {
if s == "#t" || s == "#true" {
return Value::Bool(true);
}
if s == "#f" || s == "#false" {
return Value::Bool(false);
}
if let Ok(n) = s.parse::<i64>() {
return Value::Int(n);
}
if s.contains('.') || s.contains('e') || s.contains('E') {
if let Ok(f) = s.parse::<f64>() {
return Value::Float(f);
}
}
Value::Symbol(s.clone())
}
SExpr::Str(s) => Value::Str(s.clone()),
SExpr::List(items) => Value::list(items.iter().map(sexpr_to_datum)),
SExpr::DottedList(items, tail) => {
let tail_val = sexpr_to_datum(tail);
items.iter().rev().fold(tail_val, |acc, item| {
Value::Pair(Rc::new((sexpr_to_datum(item), acc)))
})
}
}
}
fn eval_quasiquote(template: &SExpr, env: &Env) -> Result<Value, LispError> {
match template {
SExpr::Atom(s) => Ok(sexpr_to_datum(&SExpr::Atom(s.clone()))),
SExpr::Str(s) => Ok(Value::Str(s.clone())),
SExpr::List(items) => {
if items.is_empty() {
return Ok(Value::Nil);
}
if let SExpr::Atom(head) = &items[0] {
if head == "unquote" {
if items.len() != 2 {
return Err(LispError::new("unquote: expected 1 argument"));
}
return eval(items[1].clone(), Rc::clone(env));
}
}
let mut result = Value::Nil;
for item in items.iter().rev() {
if let SExpr::List(inner) = item {
if inner.len() == 2 {
if let SExpr::Atom(head) = &inner[0] {
if head == "unquote-splicing" {
let spliced = eval(inner[1].clone(), Rc::clone(env))?;
result = list_append(spliced, result)?;
continue;
}
}
}
}
let val = eval_quasiquote(item, env)?;
result = Value::Pair(Rc::new((val, result)));
}
Ok(result)
}
SExpr::DottedList(items, tail) => {
let tail_val = eval_quasiquote(tail, env)?;
let mut result = tail_val;
for item in items.iter().rev() {
if let SExpr::List(inner) = item {
if inner.len() == 2 {
if let SExpr::Atom(head) = &inner[0] {
if head == "unquote-splicing" {
let spliced = eval(inner[1].clone(), Rc::clone(env))?;
result = list_append(spliced, result)?;
continue;
}
}
}
}
let val = eval_quasiquote(item, env)?;
result = Value::Pair(Rc::new((val, result)));
}
Ok(result)
}
}
}
fn list_append(list: Value, tail: Value) -> Result<Value, LispError> {
match list {
Value::Nil => Ok(tail),
Value::Pair(p) => {
let new_tail = list_append(p.1.clone(), tail)?;
Ok(Value::Pair(Rc::new((p.0.clone(), new_tail))))
}
_ => Err(LispError::new("unquote-splicing: expected a list")),
}
}
fn eval_if(tail: &[SExpr], env: Env) -> Result<Step, LispError> {
if tail.len() < 2 || tail.len() > 3 {
return Err(LispError::new("if: expected 2 or 3 arguments"));
}
let cond_val = eval(tail[0].clone(), Rc::clone(&env))?;
if cond_val.is_truthy() {
Ok(Step::Tail(tail[1].clone(), env))
} else if tail.len() == 3 {
Ok(Step::Tail(tail[2].clone(), env))
} else {
Ok(Step::Done(Value::Nil))
}
}
fn eval_cond(tail: &[SExpr], env: Env) -> Result<Step, LispError> {
for clause in tail {
let items = clause
.as_list()
.ok_or_else(|| LispError::new("cond: clause must be a list"))?;
if items.is_empty() {
return Err(LispError::new("cond: empty clause"));
}
let is_else = matches!(&items[0], SExpr::Atom(s) if s == "else");
if is_else || eval(items[0].clone(), Rc::clone(&env))?.is_truthy() {
return eval_begin(&items[1..], env);
}
}
Ok(Step::Done(Value::Nil))
}
fn eval_when(tail: &[SExpr], env: Env, negate: bool) -> Result<Step, LispError> {
if tail.is_empty() {
return Err(LispError::new("when/unless: expected condition"));
}
let cond_val = eval(tail[0].clone(), Rc::clone(&env))?;
let matches = if negate {
!cond_val.is_truthy()
} else {
cond_val.is_truthy()
};
if matches {
eval_begin(&tail[1..], env)
} else {
Ok(Step::Done(Value::Nil))
}
}
fn eval_and(tail: &[SExpr], env: Env) -> Result<Step, LispError> {
if tail.is_empty() {
return Ok(Step::Done(Value::Bool(true)));
}
for expr in &tail[..tail.len() - 1] {
let v = eval(expr.clone(), Rc::clone(&env))?;
if !v.is_truthy() {
return Ok(Step::Done(Value::Bool(false)));
}
}
Ok(Step::Tail(tail[tail.len() - 1].clone(), env))
}
fn eval_or(tail: &[SExpr], env: Env) -> Result<Step, LispError> {
if tail.is_empty() {
return Ok(Step::Done(Value::Bool(false)));
}
for expr in &tail[..tail.len() - 1] {
let v = eval(expr.clone(), Rc::clone(&env))?;
if v.is_truthy() {
return Ok(Step::Done(v));
}
}
Ok(Step::Tail(tail[tail.len() - 1].clone(), env))
}
fn eval_begin(tail: &[SExpr], env: Env) -> Result<Step, LispError> {
if tail.is_empty() {
return Ok(Step::Done(Value::Nil));
}
for expr in &tail[..tail.len() - 1] {
eval(expr.clone(), Rc::clone(&env))?;
}
Ok(Step::Tail(tail[tail.len() - 1].clone(), env))
}
fn eval_define(tail: &[SExpr], env: Env) -> Result<Step, LispError> {
if tail.is_empty() {
return Err(LispError::new("define: expected name"));
}
match &tail[0] {
SExpr::Atom(name) | SExpr::Str(name) => {
let name = name.clone();
let val = if tail.len() >= 2 {
eval(tail[1].clone(), Rc::clone(&env))?
} else {
Value::Nil
};
env.borrow_mut().define(&name, val);
Ok(Step::Done(Value::Nil))
}
SExpr::List(sig) => {
if sig.is_empty() {
return Err(LispError::new("define: empty function signature"));
}
let name = sig[0]
.as_atom()
.ok_or_else(|| LispError::new("define: function name must be a symbol"))?
.to_string();
let params = parse_params_list(&sig[1..])?;
let body = tail[1..].to_vec();
let lambda = Value::Lambda {
params,
body,
env: Rc::clone(&env),
};
env.borrow_mut().define(&name, lambda);
Ok(Step::Done(Value::Nil))
}
SExpr::DottedList(sig, rest_param) => {
if sig.is_empty() {
return Err(LispError::new("define: empty function signature"));
}
let name = sig[0]
.as_atom()
.ok_or_else(|| LispError::new("define: function name must be a symbol"))?
.to_string();
let fixed: Result<Vec<_>, _> = sig[1..]
.iter()
.map(|e| {
e.as_atom()
.ok_or_else(|| LispError::new("lambda: parameter must be a symbol"))
.map(|s| s.to_string())
})
.collect();
let rest = rest_param
.as_atom()
.ok_or_else(|| LispError::new("lambda: rest parameter must be a symbol"))?
.to_string();
let params = Params::Variadic(fixed?, rest);
let body = tail[1..].to_vec();
let lambda = Value::Lambda {
params,
body,
env: Rc::clone(&env),
};
env.borrow_mut().define(&name, lambda);
Ok(Step::Done(Value::Nil))
}
}
}
fn eval_set(tail: &[SExpr], env: Env) -> Result<Step, LispError> {
if tail.len() != 2 {
return Err(LispError::new("set!: expected 2 arguments"));
}
let name = tail[0]
.as_atom()
.ok_or_else(|| LispError::new("set!: name must be a symbol"))?
.to_string();
let val = eval(tail[1].clone(), Rc::clone(&env))?;
env.borrow_mut().set(&name, val)?;
Ok(Step::Done(Value::Nil))
}
fn eval_lambda(tail: &[SExpr], env: Env) -> Result<Step, LispError> {
if tail.is_empty() {
return Err(LispError::new("lambda: expected parameter list"));
}
let params = parse_params(&tail[0])?;
let body = tail[1..].to_vec();
Ok(Step::Done(Value::Lambda { params, body, env }))
}
fn eval_defmacro(tail: &[SExpr], env: Env) -> Result<Step, LispError> {
if tail.len() < 2 {
return Err(LispError::new(
"defmacro: expected name, parameter list, and body",
));
}
let name = match &tail[0] {
SExpr::Atom(s) => s.clone(),
_ => return Err(LispError::new("defmacro: name must be a symbol")),
};
let params = parse_params(&tail[1])?;
let body = tail[2..].to_vec();
let mac = Value::Macro {
name: name.clone(),
params,
body,
env: Rc::clone(&env),
};
env.borrow_mut().define(&name, mac);
Ok(Step::Done(Value::Nil))
}
fn eval_let(tail: &[SExpr], env: Env) -> Result<Step, LispError> {
if tail.is_empty() {
return Err(LispError::new("let: expected bindings"));
}
if let SExpr::Atom(loop_name) = &tail[0] {
return eval_named_let(loop_name.clone(), &tail[1..], env);
}
let bindings = tail[0]
.as_list()
.ok_or_else(|| LispError::new("let: bindings must be a list"))?;
let frame = EnvFrame::child(&env);
for binding in bindings {
let pair = binding
.as_list()
.ok_or_else(|| LispError::new("let: each binding must be a list"))?;
if pair.len() < 2 {
return Err(LispError::new("let: binding must have name and value"));
}
let name = pair[0]
.as_atom()
.ok_or_else(|| LispError::new("let: binding name must be a symbol"))?
.to_string();
let val = eval(pair[1].clone(), Rc::clone(&env))?;
frame.borrow_mut().define(&name, val);
}
eval_begin(&tail[1..], frame)
}
fn eval_named_let(name: String, tail: &[SExpr], env: Env) -> Result<Step, LispError> {
if tail.is_empty() {
return Err(LispError::new("named let: expected bindings"));
}
let bindings = tail[0]
.as_list()
.ok_or_else(|| LispError::new("named let: bindings must be a list"))?;
let mut param_names: Vec<String> = Vec::new();
let mut init_vals: Vec<Value> = Vec::new();
for b in bindings {
let pair = b
.as_list()
.ok_or_else(|| LispError::new("named let: each binding must be a list"))?;
if pair.len() < 2 {
return Err(LispError::new(
"named let: binding must have name and value",
));
}
let pname = pair[0]
.as_atom()
.ok_or_else(|| LispError::new("named let: binding name must be a symbol"))?
.to_string();
let init = eval(pair[1].clone(), Rc::clone(&env))?;
param_names.push(pname);
init_vals.push(init);
}
let body = tail[1..].to_vec();
let params = Params::Fixed(param_names);
let frame = EnvFrame::child(&env);
let lambda = Value::Lambda {
params,
body,
env: Rc::clone(&frame),
};
frame.borrow_mut().define(&name, lambda.clone());
let call_frame = EnvFrame::child(&frame);
if let Value::Lambda { params, body, .. } = &lambda {
bind_params(params, &init_vals, &call_frame)?;
let n = body.len();
for expr in &body[..n.saturating_sub(1)] {
eval(expr.clone(), Rc::clone(&call_frame))?;
}
if n == 0 {
Ok(Step::Done(Value::Nil))
} else {
Ok(Step::Tail(body[n - 1].clone(), call_frame))
}
} else {
unreachable!()
}
}
fn eval_let_star(tail: &[SExpr], env: Env) -> Result<Step, LispError> {
if tail.is_empty() {
return Err(LispError::new("let*: expected bindings"));
}
let bindings = tail[0]
.as_list()
.ok_or_else(|| LispError::new("let*: bindings must be a list"))?;
let mut frame = env;
for binding in bindings {
let pair = binding
.as_list()
.ok_or_else(|| LispError::new("let*: each binding must be a list"))?;
if pair.len() < 2 {
return Err(LispError::new("let*: binding must have name and value"));
}
let name = pair[0]
.as_atom()
.ok_or_else(|| LispError::new("let*: binding name must be a symbol"))?
.to_string();
let val = eval(pair[1].clone(), Rc::clone(&frame))?;
let child = EnvFrame::child(&frame);
child.borrow_mut().define(&name, val);
frame = child;
}
eval_begin(&tail[1..], frame)
}
fn eval_letrec(tail: &[SExpr], env: Env) -> Result<Step, LispError> {
if tail.is_empty() {
return Err(LispError::new("letrec: expected bindings"));
}
let bindings = tail[0]
.as_list()
.ok_or_else(|| LispError::new("letrec: bindings must be a list"))?;
let frame = EnvFrame::child(&env);
let mut names = Vec::new();
for binding in bindings {
let pair = binding
.as_list()
.ok_or_else(|| LispError::new("letrec: each binding must be a list"))?;
let name = pair[0]
.as_atom()
.ok_or_else(|| LispError::new("letrec: binding name must be a symbol"))?
.to_string();
frame.borrow_mut().define(&name, Value::Nil);
names.push(name);
}
for (i, binding) in bindings.iter().enumerate() {
let pair = binding.as_list().unwrap();
if pair.len() < 2 {
return Err(LispError::new("letrec: binding must have name and value"));
}
let val = eval(pair[1].clone(), Rc::clone(&frame))?;
frame.borrow_mut().set(&names[i], val)?;
}
eval_begin(&tail[1..], frame)
}
fn eval_guard(tail: &[SExpr], env: Env) -> Result<Step, LispError> {
if tail.len() < 2 {
return Err(LispError::new(
"guard: expected (var clause...) and at least one body form",
));
}
let handler_spec = tail[0]
.as_list()
.ok_or_else(|| LispError::new("guard: first argument must be (var clause...)"))?;
if handler_spec.is_empty() {
return Err(LispError::new(
"guard: handler spec must start with variable name",
));
}
let var_name = handler_spec[0]
.as_atom()
.ok_or_else(|| LispError::new("guard: variable name must be a symbol"))?
.to_string();
let clauses = &handler_spec[1..];
let body = &tail[1..];
match eval_body(body, Rc::clone(&env)) {
Ok(v) => Ok(Step::Done(v)),
Err(err) => {
let handler_env = EnvFrame::child(&env);
handler_env
.borrow_mut()
.define(&var_name, Value::Str(err.message.clone()));
for clause in clauses {
let items = clause
.as_list()
.ok_or_else(|| LispError::new("guard: clause must be a list"))?;
if items.is_empty() {
return Err(LispError::new("guard: empty clause"));
}
let is_else = matches!(&items[0], SExpr::Atom(s) if s == "else");
let matched =
is_else || eval(items[0].clone(), Rc::clone(&handler_env))?.is_truthy();
if matched {
return eval_begin(&items[1..], handler_env);
}
}
Err(err)
}
}
}
fn eval_do(tail: &[SExpr], env: Env) -> Result<Step, LispError> {
if tail.len() < 2 {
return Err(LispError::new("do: expected var specs and test clause"));
}
let var_specs = tail[0]
.as_list()
.ok_or_else(|| LispError::new("do: var specs must be a list"))?;
let test_clause = tail[1]
.as_list()
.ok_or_else(|| LispError::new("do: test clause must be a list"))?;
let body = &tail[2..];
let mut vars: Vec<(String, SExpr, Option<SExpr>)> = Vec::new();
for spec in var_specs {
let parts = spec
.as_list()
.ok_or_else(|| LispError::new("do: each var spec must be a list"))?;
if parts.len() < 2 {
return Err(LispError::new("do: var spec needs at least (var init)"));
}
let name = parts[0]
.as_atom()
.ok_or_else(|| LispError::new("do: var name must be a symbol"))?
.to_string();
let init = parts[1].clone();
let step = parts.get(2).cloned();
vars.push((name, init, step));
}
let mut frame = EnvFrame::child(&env);
for (name, init, _) in &vars {
let val = eval(init.clone(), Rc::clone(&env))?;
frame.borrow_mut().define(name, val);
}
loop {
if test_clause.is_empty() {
return Err(LispError::new("do: test clause is empty"));
}
let test_val = eval(test_clause[0].clone(), Rc::clone(&frame))?;
if test_val.is_truthy() {
if test_clause.len() > 1 {
let result_exprs = &test_clause[1..];
for expr in &result_exprs[..result_exprs.len().saturating_sub(1)] {
eval(expr.clone(), Rc::clone(&frame))?;
}
if !result_exprs.is_empty() {
let last = result_exprs[result_exprs.len() - 1].clone();
return Ok(Step::Tail(last, frame));
}
}
return Ok(Step::Done(Value::Nil));
}
for expr in body {
eval(expr.clone(), Rc::clone(&frame))?;
}
let new_vals: Vec<Option<Value>> = vars
.iter()
.map(|(_, _, step)| {
step.as_ref()
.map(|s| eval(s.clone(), Rc::clone(&frame)))
.transpose()
})
.collect::<Result<Vec<_>, _>>()?;
let new_frame = EnvFrame::child(&env);
for (i, (name, _, _)) in vars.iter().enumerate() {
let val = new_vals[i]
.clone()
.unwrap_or_else(|| frame.borrow().lookup(name).unwrap_or(Value::Nil));
new_frame.borrow_mut().define(name, val);
}
frame = new_frame;
}
}
pub fn parse_params(expr: &SExpr) -> Result<Params, LispError> {
match expr {
SExpr::Atom(s) => Ok(Params::Rest(s.clone())),
SExpr::Str(s) => Ok(Params::Rest(s.clone())),
SExpr::List(items) => parse_params_list(items),
SExpr::DottedList(items, tail) => {
let fixed: Result<Vec<_>, _> = items
.iter()
.map(|e| {
e.as_atom()
.ok_or_else(|| LispError::new("lambda: parameter must be a symbol"))
.map(|s| s.to_string())
})
.collect();
let rest = tail
.as_atom()
.ok_or_else(|| LispError::new("lambda: rest parameter must be a symbol"))?
.to_string();
Ok(Params::Variadic(fixed?, rest))
}
}
}
pub fn parse_params_list(items: &[SExpr]) -> Result<Params, LispError> {
if let Some(dot_pos) = items
.iter()
.position(|e| matches!(e, SExpr::Atom(s) if s == "."))
{
let fixed: Result<Vec<_>, _> = items[..dot_pos]
.iter()
.map(|e| {
e.as_atom()
.ok_or_else(|| LispError::new("lambda: parameter must be a symbol"))
.map(|s| s.to_string())
})
.collect();
let rest_part = &items[dot_pos + 1..];
if rest_part.len() != 1 {
return Err(LispError::new(
"lambda: dotted params must have exactly one rest symbol",
));
}
let rest = rest_part[0]
.as_atom()
.ok_or_else(|| LispError::new("lambda: rest parameter must be a symbol"))?
.to_string();
Ok(Params::Variadic(fixed?, rest))
} else {
let fixed: Result<Vec<_>, _> = items
.iter()
.map(|e| {
e.as_atom()
.ok_or_else(|| LispError::new("lambda: parameter must be a symbol"))
.map(|s| s.to_string())
})
.collect();
Ok(Params::Fixed(fixed?))
}
}
pub fn bind_params(params: &Params, args: &[Value], frame: &Env) -> Result<(), LispError> {
match params {
Params::Fixed(names) => {
if args.len() != names.len() {
return Err(LispError::new(format!(
"arity mismatch: expected {} arguments, got {}",
names.len(),
args.len()
)));
}
for (name, val) in names.iter().zip(args.iter()) {
frame.borrow_mut().define(name, val.clone());
}
}
Params::Variadic(fixed, rest) => {
if args.len() < fixed.len() {
return Err(LispError::new(format!(
"arity mismatch: expected at least {} arguments, got {}",
fixed.len(),
args.len()
)));
}
for (name, val) in fixed.iter().zip(args.iter()) {
frame.borrow_mut().define(name, val.clone());
}
let rest_val = Value::list(args[fixed.len()..].iter().cloned());
frame.borrow_mut().define(rest, rest_val);
}
Params::Rest(name) => {
let rest_val = Value::list(args.iter().cloned());
frame.borrow_mut().define(name, rest_val);
}
}
Ok(())
}
pub fn eval_body(body: &[SExpr], env: Env) -> Result<Value, LispError> {
if body.is_empty() {
return Ok(Value::Nil);
}
for expr in &body[..body.len() - 1] {
eval(expr.clone(), Rc::clone(&env))?;
}
eval(body[body.len() - 1].clone(), env)
}