aboutsummaryrefslogtreecommitdiff
path: root/src/lisp
diff options
context:
space:
mode:
Diffstat (limited to 'src/lisp')
-rw-r--r--src/lisp/expr.rs94
-rw-r--r--src/lisp/number.rs21
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};
3use crate::app::AppState; 3use crate::app::AppState;
4use crate::lisp::{ 4use 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)]
12pub enum Arity {
13 Exact(usize),
14 Atleast(usize),
15 Atmost(usize),
16 Range(usize, usize),
17 None,
18}
19
20impl 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)]
10pub struct PrimitiveFunc { 36pub 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
15impl PrimitiveFunc { 41impl 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
88impl fmt::Display for LispExpr { 147impl 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
140impl 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//
211impl 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
221impl 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
150impl TryFrom<LispExpr> for BoolLit { 230impl 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 @@
1use std::{ 1use 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
82impl Eq for LispNumber {}
83
84impl 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
96impl PartialOrd for LispNumber {
97 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
98 Some(self.cmp(other))
99 }
100}
101
81impl fmt::Display for LispNumber { 102impl 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 {