oolisp/
lib.rs

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}