diff options
Diffstat (limited to 'src/lisp')
-rw-r--r-- | src/lisp/expr.rs | 94 | ||||
-rw-r--r-- | src/lisp/number.rs | 21 |
2 files changed, 108 insertions, 7 deletions
diff --git a/src/lisp/expr.rs b/src/lisp/expr.rs index acd3365..40420a1 100644 --- a/src/lisp/expr.rs +++ b/src/lisp/expr.rs | |||
@@ -3,21 +3,45 @@ use std::{convert::TryFrom, fmt}; | |||
3 | use crate::app::AppState; | 3 | use crate::app::AppState; |
4 | use crate::lisp::{ | 4 | use crate::lisp::{ |
5 | error::{EvalError, LispError}, | 5 | error::{EvalError, LispError}, |
6 | eval::lookup_extended, | ||
6 | number::LispNumber, | 7 | number::LispNumber, |
8 | EnvList, Environment, | ||
7 | }; | 9 | }; |
8 | 10 | ||
11 | #[derive(Debug, Copy, PartialEq, Clone)] | ||
12 | pub enum Arity { | ||
13 | Exact(usize), | ||
14 | Atleast(usize), | ||
15 | Atmost(usize), | ||
16 | Range(usize, usize), | ||
17 | None, | ||
18 | } | ||
19 | |||
20 | impl Arity { | ||
21 | pub fn is_valid<T>(self, args: &[T]) -> bool { | ||
22 | match self { | ||
23 | Arity::Exact(a) => args.len() == a, | ||
24 | Arity::Atleast(a) => args.len() >= a, | ||
25 | Arity::Atmost(a) => args.len() <= a, | ||
26 | Arity::Range(low, high) => args.len() >= low && args.len() <= high, | ||
27 | Arity::None => true, | ||
28 | } | ||
29 | } | ||
30 | pub fn to_error(self) -> LispError { | ||
31 | LispError::Eval(EvalError::ArgumentCount(self)) | ||
32 | } | ||
33 | } | ||
34 | |||
9 | #[derive(Clone)] | 35 | #[derive(Clone)] |
10 | pub struct PrimitiveFunc { | 36 | pub struct PrimitiveFunc { |
11 | pub arity: Option<usize>, // minimim arity | 37 | pub arity: Arity, // minimim arity |
12 | pub closure: fn(&[LispExpr], &mut AppState) -> Result<LispExpr, LispError>, | 38 | pub closure: fn(&[LispExpr], &mut AppState) -> Result<LispExpr, LispError>, |
13 | } | 39 | } |
14 | 40 | ||
15 | impl PrimitiveFunc { | 41 | impl PrimitiveFunc { |
16 | pub fn call(&self, args: &[LispExpr], app: &mut AppState) -> Result<LispExpr, LispError> { | 42 | pub fn call(&self, args: &[LispExpr], app: &mut AppState) -> Result<LispExpr, LispError> { |
17 | if let Some(arity) = self.arity { | 43 | if !self.arity.is_valid(args) { |
18 | if args.len() < arity { | 44 | return Err(EvalError::ArgumentCount(self.arity).into()); |
19 | return Err(EvalError::ArgumentCount(self.arity.map(|u| u as u32)).into()); | ||
20 | } | ||
21 | } | 45 | } |
22 | (self.closure)(args, app) | 46 | (self.closure)(args, app) |
23 | } | 47 | } |
@@ -42,6 +66,7 @@ pub enum LispExpr { | |||
42 | Ident(Ident), | 66 | Ident(Ident), |
43 | PrimitiveFunc(PrimitiveFunc), | 67 | PrimitiveFunc(PrimitiveFunc), |
44 | Function(LispFunction), | 68 | Function(LispFunction), |
69 | Char(char), | ||
45 | 70 | ||
46 | // none of these depths should be zero | 71 | // none of these depths should be zero |
47 | Quasiquote(Box<LispExpr>, u32), | 72 | Quasiquote(Box<LispExpr>, u32), |
@@ -83,6 +108,40 @@ impl LispExpr { | |||
83 | v => LispExpr::Quasiquote(Box::new(v), n), | 108 | v => LispExpr::Quasiquote(Box::new(v), n), |
84 | } | 109 | } |
85 | } | 110 | } |
111 | |||
112 | pub fn compare(&self, other: &Self, envs: &EnvList) -> Result<BoolLit, LispError> { | ||
113 | match (self, other) { | ||
114 | (LispExpr::Unit, LispExpr::Unit) => Ok(true), | ||
115 | (LispExpr::Number(s), LispExpr::Number(o)) => Ok(s == o), | ||
116 | (LispExpr::List(s), LispExpr::List(o)) => Ok(s | ||
117 | .iter() | ||
118 | .zip(o) | ||
119 | .all(|(a, b)| matches!(a.compare(b, envs), Ok(true)))), | ||
120 | (LispExpr::StringLit(s), LispExpr::StringLit(o)) => Ok(s == o), | ||
121 | (LispExpr::Char(s), LispExpr::Char(o)) => Ok(s == o), | ||
122 | (LispExpr::BoolLit(s), LispExpr::BoolLit(o)) => Ok(s == o), | ||
123 | (LispExpr::Ident(s), LispExpr::Ident(o)) => { | ||
124 | let s = lookup_extended(envs, s)?; | ||
125 | let o = lookup_extended(envs, o)?; | ||
126 | s.compare(&o, envs) | ||
127 | } | ||
128 | (LispExpr::PrimitiveFunc(s), LispExpr::PrimitiveFunc(o)) => { | ||
129 | let PrimitiveFunc { closure: s, .. } = s; | ||
130 | let PrimitiveFunc { closure: o, .. } = o; | ||
131 | Ok(*s as usize == *o as usize) | ||
132 | } | ||
133 | (LispExpr::Function(_), LispExpr::Function(_)) => Err(EvalError::BadForm.into()), | ||
134 | (LispExpr::Quasiquote(s, sd), LispExpr::Quasiquote(o, od)) => { | ||
135 | Ok(s.compare(o, envs)? && sd == od) | ||
136 | } | ||
137 | (LispExpr::Comma(s, sd), LispExpr::Comma(o, od)) => Ok(s.compare(o, envs)? && sd == od), | ||
138 | (LispExpr::CommaAt(s, sd), LispExpr::CommaAt(o, od)) => { | ||
139 | Ok(s.compare(o, envs)? && sd == od) | ||
140 | } | ||
141 | (LispExpr::Quote(s, sd), LispExpr::Quote(o, od)) => Ok(s.compare(o, envs)? && sd == od), | ||
142 | _ => Err(EvalError::TypeMismatch.into()), | ||
143 | } | ||
144 | } | ||
86 | } | 145 | } |
87 | 146 | ||
88 | impl fmt::Display for LispExpr { | 147 | impl fmt::Display for LispExpr { |
@@ -96,6 +155,7 @@ impl fmt::Display for LispExpr { | |||
96 | } | 155 | } |
97 | } | 156 | } |
98 | LispExpr::StringLit(s) => write!(f, "{}", s)?, | 157 | LispExpr::StringLit(s) => write!(f, "{}", s)?, |
158 | LispExpr::Char(c) => write!(f, "{}", c)?, | ||
99 | LispExpr::BoolLit(b) => { | 159 | LispExpr::BoolLit(b) => { |
100 | if *b { | 160 | if *b { |
101 | write!(f, "#t")? | 161 | write!(f, "#t")? |
@@ -137,16 +197,36 @@ impl<'a> TryFrom<&'a LispExpr> for &'a LispNumber { | |||
137 | } | 197 | } |
138 | } | 198 | } |
139 | 199 | ||
140 | impl TryFrom<LispExpr> for Ident { | 200 | //impl TryFrom<LispExpr> for Ident { |
201 | // type Error = LispError; | ||
202 | // fn try_from(value: LispExpr) -> Result<Self, Self::Error> { | ||
203 | // match value { | ||
204 | // LispExpr::Ident(i) => Ok(i), | ||
205 | // _ => Err(LispError::Eval(EvalError::TypeMismatch)), | ||
206 | // } | ||
207 | // } | ||
208 | //} | ||
209 | // | ||
210 | // | ||
211 | impl TryFrom<LispExpr> for String { | ||
141 | type Error = LispError; | 212 | type Error = LispError; |
142 | fn try_from(value: LispExpr) -> Result<Self, Self::Error> { | 213 | fn try_from(value: LispExpr) -> Result<Self, Self::Error> { |
143 | match value { | 214 | match value { |
144 | LispExpr::Ident(i) => Ok(i), | 215 | LispExpr::StringLit(i) => Ok(i), |
145 | _ => Err(LispError::Eval(EvalError::TypeMismatch)), | 216 | _ => Err(LispError::Eval(EvalError::TypeMismatch)), |
146 | } | 217 | } |
147 | } | 218 | } |
148 | } | 219 | } |
149 | 220 | ||
221 | impl AsRef<str> for LispExpr { | ||
222 | fn as_ref(&self) -> &str { | ||
223 | match self { | ||
224 | LispExpr::StringLit(i) => &i, | ||
225 | _ => panic!("invalid downcast!"), | ||
226 | } | ||
227 | } | ||
228 | } | ||
229 | |||
150 | impl TryFrom<LispExpr> for BoolLit { | 230 | impl TryFrom<LispExpr> for BoolLit { |
151 | type Error = LispError; | 231 | type Error = LispError; |
152 | fn try_from(value: LispExpr) -> Result<Self, Self::Error> { | 232 | fn try_from(value: LispExpr) -> Result<Self, Self::Error> { |
diff --git a/src/lisp/number.rs b/src/lisp/number.rs index 23d7997..0ce5ac0 100644 --- a/src/lisp/number.rs +++ b/src/lisp/number.rs | |||
@@ -1,4 +1,5 @@ | |||
1 | use std::{ | 1 | use std::{ |
2 | cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd}, | ||
2 | fmt, | 3 | fmt, |
3 | ops::{Add, Mul, Sub}, | 4 | ops::{Add, Mul, Sub}, |
4 | }; | 5 | }; |
@@ -78,6 +79,26 @@ impl PartialEq for LispNumber { | |||
78 | } | 79 | } |
79 | } | 80 | } |
80 | 81 | ||
82 | impl Eq for LispNumber {} | ||
83 | |||
84 | impl Ord for LispNumber { | ||
85 | fn cmp(&self, other: &Self) -> Ordering { | ||
86 | use LispNumber::*; | ||
87 | match (*self, *other) { | ||
88 | (Integer(a), Integer(b)) => a.cmp(&b), | ||
89 | (Float(a), Integer(b)) => (a as i64).cmp(&b), | ||
90 | (Integer(a), Float(b)) => a.cmp(&(b as i64)), | ||
91 | (Float(a), Float(b)) => (a as i64).cmp(&(b as i64)), | ||
92 | } | ||
93 | } | ||
94 | } | ||
95 | |||
96 | impl PartialOrd for LispNumber { | ||
97 | fn partial_cmp(&self, other: &Self) -> Option<Ordering> { | ||
98 | Some(self.cmp(other)) | ||
99 | } | ||
100 | } | ||
101 | |||
81 | impl fmt::Display for LispNumber { | 102 | impl fmt::Display for LispNumber { |
82 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | 103 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
83 | match self { | 104 | match self { |