1pub mod builtin;
2pub mod env;
3pub mod eval;
4pub mod parser;
5
6extern crate wasm_bindgen;
7use wasm_bindgen::prelude::*;
8
9use crate::env::{Lenv, Lookup};
10use std::{error::Error, fmt};
11
12#[derive(Clone)]
13pub enum Lval {
14 Sym(String),
15 Num(f64),
16 Sexpr(Vec<Lval>),
17 Qexpr(Vec<Lval>),
18 Fun(Lfun),
19 Lambda(Llambda),
20 Str(String),
21}
22
23impl PartialEq for Lval {
24 fn eq(&self, other: &Self) -> bool {
25 match self {
26 Lval::Sym(a) => match other {
27 Lval::Sym(b) => a == b,
28 _ => false,
29 },
30 Lval::Num(a) => match other {
31 Lval::Num(b) => a == b,
32 _ => false,
33 },
34 Lval::Sexpr(a) => match other {
35 Lval::Sexpr(b) => a == b,
36 _ => false,
37 },
38 Lval::Qexpr(a) => match other {
39 Lval::Qexpr(b) => a == b,
40 _ => false,
41 },
42 Lval::Fun(_) => match other {
43 Lval::Fun(_) => true,
44 _ => false,
45 },
46 Lval::Str(_) => match other {
47 Lval::Str(_) => true,
48 _ => false,
49 },
50 Lval::Lambda(a) => match other {
51 Lval::Lambda(b) => a.body == b.body && a.args == b.args,
52 _ => false,
53 },
54 }
55 }
56}
57
58impl fmt::Debug for Lval {
59 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60 match &self {
61 Lval::Sym(s) => {
62 let sym = if s == &String::from("\\") {
63 "\\\\\\\\"
64 } else {
65 s
66 };
67 write!(f, "{{\"type\": \"symbol\", \"value\": \"{}\"}}", sym)
68 }
69 Lval::Num(n) => write!(f, "{}", n),
70 Lval::Sexpr(s) => write!(f, "{{\"type\": \"sexpression\", \"value\": {:?}}}", s),
71 Lval::Qexpr(q) => write!(f, "{{\"type\": \"qexpression\", \"value\": {:?}}}", q),
72 Lval::Fun(_) => write!(f, "{{\"type\": \"builtin\"}}"),
73 Lval::Str(s) => write!(f, "\"{}\"", s),
74 Lval::Lambda(l) => write!(
75 f,
76 "{{\"type\": \"lambda\", \"args\":{:?}, \"body\":{:?}}}",
77 l.args, l.body
78 ),
79 }
80 }
81}
82
83#[derive(Clone)]
84pub struct Llambda {
85 args: Vec<String>,
86 body: Vec<Lval>,
87 env: Lenv,
88}
89
90impl Llambda {
91 fn new(args: Vec<String>, body: Vec<Lval>, lookup: Lookup) -> Self {
92 let mut lenv = Lenv::new();
93 lenv.push(lookup);
94 Llambda {
95 args,
96 body,
97 env: lenv,
98 }
99 }
100}
101
102#[derive(Clone, PartialEq)]
103pub struct Lerr {
104 etype: LerrType,
105 details: String,
106 message: String,
107}
108
109impl Lerr {
110 fn new(etype: LerrType, message: String) -> Lerr {
111 let msg = match &etype {
112 LerrType::DivZero => "Cannot Divide By Zero",
113 LerrType::BadOp => "Invalid Operator",
114 LerrType::BadNum => "Invalid Operand",
115 LerrType::IncorrectParamCount => "Incorrect Number of Params passed to function",
116 LerrType::WrongType => "Incorrect Data Type used",
117 LerrType::EmptyList => "Empty List passed to function",
118 LerrType::UnboundSymbol => "This Symbol has not been Defined",
119 LerrType::Interrupt => "User defined Error",
120 };
121
122 Lerr {
123 details: msg.to_string(),
124 message,
125 etype,
126 }
127 }
128}
129
130impl fmt::Debug for Lerr {
131 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
132 write!(
133 f,
134 "{{\"type\": \"error\", \"etype\":\"{:?}\", \"details\":{:?}, \"message\":{:?}}}",
135 self.etype, self.details, self.message
136 )
137 }
138}
139
140impl fmt::Display for Lerr {
141 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
142 write!(f, "{}", self.details)
143 }
144}
145
146impl Error for Lerr {
147 fn description(&self) -> &str {
148 &self.details
149 }
150}
151
152#[derive(Clone, Debug, PartialEq)]
153pub enum LerrType {
154 DivZero,
155 BadOp,
156 BadNum,
157 IncorrectParamCount,
158 EmptyList,
159 WrongType,
160 UnboundSymbol,
161 Interrupt,
162}
163
164pub type Lfun = fn(&mut Lenv, Vec<Lval>) -> Result<Lval, Lerr>;
165
166pub fn add_builtin(env: &mut Lenv, sym: &str, fun: Lfun) {
167 env.insert(sym, Lval::Fun(fun));
168}
169
170fn to_num(expr: Lval) -> Option<f64> {
171 if let Lval::Num(n) = expr {
172 Some(n)
173 } else {
174 None
175 }
176}
177
178fn to_sym(expr: Lval) -> Option<String> {
179 if let Lval::Sym(s) = expr {
180 Some(s.clone())
181 } else {
182 None
183 }
184}
185
186fn to_str(expr: Lval) -> Option<String> {
187 if let Lval::Str(s) = expr {
188 Some(s.clone())
189 } else {
190 None
191 }
192}
193
194fn to_qexpr(expr: Lval) -> Option<Vec<Lval>> {
195 if let Lval::Qexpr(s) = expr {
196 Some(s.clone())
197 } else {
198 None
199 }
200}
201
202#[cfg(test)]
203fn to_lambda(expr: &Lval) -> Option<Llambda> {
204 if let Lval::Lambda(s) = expr {
205 Some(s.clone())
206 } else {
207 None
208 }
209}
210
211#[wasm_bindgen]
212pub fn lisp(env: &mut Lenv, input: &str) -> String {
213 if "env" == input {
214 return format!("{:#?}", env.peek().unwrap());
215 }
216
217 let ast = parser::parse(input);
218 match ast {
219 Ok(tree) => match eval::eval(env, tree.1) {
220 Ok(r) => format!("{:?}", r),
221 Err(r) => format!("{:?}", r),
222 },
223 Err(e) => format!("{{\"type\": \"error\", \"etype\":\"Parsing Error\", \"details\":\"Could not parse the input\", \"message\":{:?}}}", e),
224 }
225}