use crate::parser::{elist, Expr};
use std::cell::Cell;
use std::rc::Rc;
const SPECIALS: &[&str] = &[
"llm", "deftool", "tool-call", "list-tools", "react-loop",
"load", "load-relative", "checkpoint", "command-registry",
"try-catch", "match", "quote", "eval", "quasiquote",
"if", "when", "unless", "cond", "and", "or", "begin", "eval-when",
"define", "def", "set!", "set", "lambda", "fn", "λ",
"defmacro", "define-macro", "defrust", "defrust*",
"let", "let*", "letrec", "letrec*", "do",
];
fn is_special(name: &str) -> bool {
SPECIALS.contains(&name)
}
struct Scope {
names: Vec<String>,
}
const SMALL_MAX: usize = 8;
struct Resolver {
scopes: Vec<Scope>,
}
impl Resolver {
fn push_names(&mut self, names: Vec<String>) {
let mut deduped: Vec<String> = Vec::new();
for n in names {
if !deduped.contains(&n) { deduped.push(n); }
}
self.scopes.push(Scope { names: deduped });
}
fn resolve_symbol(&self, s: &str) -> Expr {
for (up, scope) in self.scopes.iter().rev().enumerate() {
if let Some(slot) = scope.names.iter().position(|n| n == s) {
if scope.names.len() <= SMALL_MAX {
return Expr::LocalRef {
depth: up as u16,
slot: slot as u16,
name: Rc::from(s),
};
}
return Expr::Symbol(s.to_string());
}
}
Expr::GlobalRef { name: Rc::from(s), idx: Cell::new(u32::MAX) }
}
fn resolve_expr(&mut self, e: &Expr) -> Expr {
match e {
Expr::Symbol(s) => self.resolve_symbol(s),
Expr::List(items) => self.resolve_list(items),
other => other.clone(),
}
}
fn resolve_all(&mut self, exprs: &[Expr]) -> Vec<Expr> {
exprs.iter().map(|e| self.resolve_expr(e)).collect()
}
fn resolve_list(&mut self, items: &Rc<Vec<Expr>>) -> Expr {
if items.is_empty() {
return Expr::List(items.clone());
}
let head = match &items[0] {
Expr::Symbol(s) => s.as_str(),
_ => {
return elist(self.resolve_all(items));
}
};
if !is_special(head) {
return elist(self.resolve_all(items));
}
match head {
"quote" | "quasiquote" | "lambda" | "fn" | "λ"
| "defmacro" | "define-macro" | "deftool" | "defrust" | "defrust*"
| "try-catch" | "match" | "do"
| "llm" | "tool-call" | "list-tools" | "react-loop"
| "load" | "load-relative" | "checkpoint" | "command-registry"
| "eval-when" => Expr::List(items.clone()),
"define" | "def" => {
let value_form = matches!(items.get(1), Some(Expr::Symbol(_)))
&& if head == "def" { items.len() == 3 } else { items.len() >= 3 };
if value_form {
let mut out = vec![items[0].clone(), items[1].clone()];
out.extend(self.resolve_all(&items[2..]));
elist(out)
} else {
Expr::List(items.clone())
}
}
"set!" | "set" => {
if items.len() >= 3 {
let mut out = vec![items[0].clone(), items[1].clone()];
out.extend(self.resolve_all(&items[2..]));
elist(out)
} else {
Expr::List(items.clone())
}
}
"if" | "when" | "unless" | "begin" | "and" | "or" | "eval" => {
let mut out = vec![items[0].clone()];
out.extend(self.resolve_all(&items[1..]));
elist(out)
}
"cond" => {
let mut out = vec![items[0].clone()];
for clause in &items[1..] {
match clause {
Expr::List(c) if !c.is_empty() => {
let mut nc = Vec::with_capacity(c.len());
if matches!(&c[0], Expr::Symbol(s) if s == "else") {
nc.push(c[0].clone());
} else {
nc.push(self.resolve_expr(&c[0]));
}
nc.extend(self.resolve_all(&c[1..]));
out.push(elist(nc));
}
other => out.push(self.resolve_expr(other)),
}
}
elist(out)
}
"let" => {
if let Some(Expr::Symbol(lname)) = items.get(1) {
if items.len() >= 4 {
return self.resolve_named_let(items, lname.clone());
}
return Expr::List(items.clone());
}
let Some((names, resolved_bindings)) = self.resolve_bindings(items, false) else {
return Expr::List(items.clone());
};
self.push_names(names);
let body = self.resolve_all(&items[2..]);
self.scopes.pop();
let mut out = vec![items[0].clone(), resolved_bindings];
out.extend(body);
elist(out)
}
"let*" | "letrec" | "letrec*" => {
let Some(binding_list) = as_binding_list(items) else {
return Expr::List(items.clone());
};
let seq = head == "let*";
if seq {
self.push_names(Vec::new());
} else {
let mut names = Vec::new();
for b in binding_list.iter() {
match binding_name(b) {
Some(n) => names.push(n),
None => return Expr::List(items.clone()),
}
}
self.push_names(names);
}
let mut nb = Vec::with_capacity(binding_list.len());
let mut ok = true;
for b in binding_list.iter() {
let (Expr::List(pair), Some(n)) = (b, binding_name(b)) else {
ok = false;
break;
};
let init = self.resolve_expr(&pair[1]);
nb.push(elist(vec![pair[0].clone(), init]));
if seq {
let scope = self.scopes.last_mut().unwrap();
if !scope.names.contains(&n) { scope.names.push(n); }
}
}
if !ok {
self.scopes.pop();
return Expr::List(items.clone());
}
let body = self.resolve_all(&items[2..]);
self.scopes.pop();
let mut out = vec![items[0].clone(), elist(nb)];
out.extend(body);
elist(out)
}
_ => Expr::List(items.clone()),
}
}
fn resolve_named_let(&mut self, items: &Rc<Vec<Expr>>, lname: String) -> Expr {
let Some((names, resolved_bindings)) = self.resolve_bindings_at(items, 2) else {
return Expr::List(items.clone());
};
self.push_names(vec![lname]);
self.push_names(names);
let body = self.resolve_all(&items[3..]);
self.scopes.pop();
self.scopes.pop();
let mut out = vec![items[0].clone(), items[1].clone(), resolved_bindings];
out.extend(body);
elist(out)
}
fn resolve_bindings(&mut self, items: &Rc<Vec<Expr>>, _seq: bool) -> Option<(Vec<String>, Expr)> {
self.resolve_bindings_at(items, 1)
}
fn resolve_bindings_at(&mut self, items: &Rc<Vec<Expr>>, pos: usize) -> Option<(Vec<String>, Expr)> {
let Some(Expr::List(bs)) = items.get(pos) else { return None; };
let mut names = Vec::with_capacity(bs.len());
let mut nb = Vec::with_capacity(bs.len());
for b in bs.iter() {
let Expr::List(pair) = b else { return None; };
if pair.len() != 2 { return None; }
let Expr::Symbol(n) = &pair[0] else { return None; };
names.push(n.clone());
let init = self.resolve_expr(&pair[1]);
nb.push(elist(vec![pair[0].clone(), init]));
}
Some((names, elist(nb)))
}
}
fn as_binding_list(items: &Rc<Vec<Expr>>) -> Option<Rc<Vec<Expr>>> {
match items.get(1) {
Some(Expr::List(bs)) => Some(bs.clone()),
_ => None,
}
}
fn binding_name(b: &Expr) -> Option<String> {
match b {
Expr::List(pair) if pair.len() == 2 => match &pair[0] {
Expr::Symbol(n) => Some(n.clone()),
_ => None,
},
_ => None,
}
}
pub fn resolve_body(params: &[String], rest: &Option<String>, body: &[Expr]) -> Vec<Expr> {
let mut frame: Vec<String> = params.to_vec();
if let Some(r) = rest {
frame.push(r.clone());
}
let mut r = Resolver { scopes: Vec::new() };
r.push_names(frame);
r.resolve_all(body)
}