1use crate::env::Environment;
4use crate::error::LispError;
5use crate::eval;
6use dyn_clone::DynClone;
7
8use std::fmt::{Debug, Display};
9
10#[derive(Debug, Clone)]
12pub enum Ast {
13 Atom(LispAtom),
15
16 List(Vec<Ast>),
18
19 Function(Box<dyn LispCallable>),
21
22 Unspecified,
24}
25
26impl PartialEq for Ast {
27 fn eq(&self, other: &Self) -> bool {
28 match self {
29 Ast::Atom(val) => match other {
30 Ast::Atom(other) => val == other,
31 _ => false,
32 },
33 Ast::List(items) => match other {
34 Ast::List(other) => items == other,
35 _ => false,
36 },
37 Ast::Function(_) => false,
39 Ast::Unspecified => false,
40 }
41 }
42}
43
44impl Display for Ast {
45 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
46 match self {
47 Self::Atom(atom) => write!(f, "{}", atom),
48 Self::List(list) => {
49 write!(f, "(")?;
50
51 let mut list = list.iter();
53 if let Some(ast) = list.next() {
54 write!(f, "{}", ast)?;
55
56 for ast in list {
57 write!(f, " {}", ast)?;
58 }
59 }
60
61 write!(f, ")")
62 }
63 Self::Function(_) => write!(f, "<function>"),
64 Self::Unspecified => Ok(()), }
66 }
67}
68
69#[derive(Clone, Debug, PartialEq)]
71pub enum LispAtom {
72 Symbol(String),
74
75 String(String),
77
78 Bool(bool),
80
81 Number(f64),
83}
84
85impl Display for LispAtom {
86 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
87 match self {
88 Self::Symbol(symbol) => write!(f, "{}", symbol),
89 Self::String(s) => write!(f, "\"{}\"", s),
90 Self::Number(num) => write!(f, "{}", num),
91 Self::Bool(b) => write!(f, "{}", b),
92 }
93 }
94}
95
96impl Clone for Box<dyn LispCallable> {
97 fn clone(&self) -> Self {
98 dyn_clone::clone_box(&**self)
99 }
100}
101
102#[derive(Debug, Clone)]
105pub enum FunctionArity {
106 AtLeast(usize),
109
110 Exactly(usize),
112
113 Multi(Vec<usize>),
115}
116
117impl FunctionArity {
118 pub fn check_arity(&self, num_args: usize) -> Result<(), LispError> {
120 match self {
121 Self::AtLeast(num_params) => {
122 if num_args >= *num_params {
123 Ok(())
124 } else {
125 Err(LispError::Type)
126 }
127 }
128 Self::Exactly(num_params) => {
129 if num_args == *num_params {
130 Ok(())
131 } else {
132 Err(LispError::Type)
133 }
134 }
135 Self::Multi(options) => {
136 if options.contains(&num_args) {
137 Ok(())
138 } else {
139 Err(LispError::Type)
140 }
141 }
142 }
143 }
144}
145
146pub trait LispCallable: Debug + DynClone {
148 fn arity(&self) -> &FunctionArity;
150
151 fn call(&self, args: Vec<Ast>, env: &mut Environment) -> Result<Ast, LispError>;
153}
154
155#[derive(Debug, Clone)]
157pub struct LispLambda {
158 arity: FunctionArity,
159 bindings: Vec<String>,
160 body: Ast,
161}
162
163impl LispLambda {
164 pub fn new(arity: FunctionArity, bindings: Vec<String>, body: Ast) -> Self {
166 Self {
167 arity,
168 bindings,
169 body,
170 }
171 }
172}
173
174impl LispCallable for LispLambda {
175 fn arity(&self) -> &FunctionArity {
176 &self.arity
177 }
178
179 fn call(&self, args: Vec<Ast>, env: &mut Environment) -> Result<Ast, LispError> {
180 env.new_scope(self.bindings.iter().cloned().zip(args).collect());
182
183 let res = eval::eval_expr(self.body.clone(), env);
185
186 env.pop_scope();
187
188 res
189 }
190}