aboutsummaryrefslogtreecommitdiff
path: root/src/lisp
diff options
context:
space:
mode:
Diffstat (limited to 'src/lisp')
-rw-r--r--src/lisp/env.rs88
-rw-r--r--src/lisp/expr.rs19
-rw-r--r--src/lisp/lex.rs5
-rw-r--r--src/lisp/mod.rs2
4 files changed, 57 insertions, 57 deletions
diff --git a/src/lisp/env.rs b/src/lisp/env.rs
index ad7cc2b..94c0e05 100644
--- a/src/lisp/env.rs
+++ b/src/lisp/env.rs
@@ -1,8 +1,11 @@
1use crate::{ 1use crate::{
2 app::AppState, 2 app::AppState,
3 lisp::{error::LispError, expr::LispExpr, number::LispNumber, Environment}, 3 lisp::{error::LispError, expr::LispExpr, number::LispNumber, Environment},
4 primitive,
4}; 5};
5 6
7use log::warn;
8
6pub fn is_bound<S: AsRef<str>>(env: &mut Environment, name: S) -> bool { 9pub fn is_bound<S: AsRef<str>>(env: &mut Environment, name: S) -> bool {
7 env.get(name.as_ref()).is_some() 10 env.get(name.as_ref()).is_some()
8} 11}
@@ -13,21 +16,39 @@ pub fn new_binding<S: AsRef<str>>(env: &mut Environment, name: S, value: LispExp
13 16
14pub fn with_prelude() -> Environment { 17pub fn with_prelude() -> Environment {
15 let mut env = Environment::new(); 18 let mut env = Environment::new();
16 new_binding( 19 primitive!(env, Some(2), "+", |args, _| {
17 &mut env, 20 if args.iter().any(|arg| !matches!(arg, LispExpr::Number(_))) {
18 "+", 21 Err(LispError::EvalError)
19 LispExpr::PrimitiveFunc(|args, _| { 22 } else {
20 if args.iter().any(|arg| !matches!(arg, LispExpr::Number(_))) { 23 Ok(LispExpr::Number(
21 Err(LispError::EvalError) 24 args.iter()
22 } else { 25 .map(|arg| unwrap_number(arg))
23 let result = args 26 .fold(LispNumber::Integer(0), |acc, x| acc + *x),
24 .iter() 27 ))
25 .map(|n| unwrap_number(n)) 28 }
26 .fold(LispNumber::Integer(0), |acc, x| acc + *x); 29 });
27 Ok(LispExpr::Number(result)) 30 primitive!(env, Some(2), "sub", |args, _| {
31 if args.iter().any(|arg| !matches!(arg, LispExpr::Number(_))) {
32 Err(LispError::EvalError)
33 } else {
34 let mut acc = unwrap_number(&args[0]).clone();
35 for arg in args.into_iter().skip(1) {
36 acc = acc - *unwrap_number(&arg);
28 } 37 }
29 }), 38 Ok(LispExpr::Number(acc))
30 ); 39 }
40 });
41 primitive!(env, Some(2), "*", |args, _| {
42 if args.iter().any(|arg| !matches!(arg, LispExpr::Number(_))) {
43 Err(LispError::EvalError)
44 } else {
45 Ok(LispExpr::Number(
46 args.iter()
47 .map(|arg| unwrap_number(arg))
48 .fold(LispNumber::Integer(1), |acc, x| acc * *x),
49 ))
50 }
51 });
31 env 52 env
32} 53}
33 54
@@ -56,7 +77,7 @@ pub fn eval(expr: &LispExpr, app: &mut AppState) -> Result<LispExpr, LispError>
56 for item in li[1..].iter() { 77 for item in li[1..].iter() {
57 args.push(eval(item, app)?); 78 args.push(eval(item, app)?);
58 } 79 }
59 (f)(&args, None) 80 f.call(&args, app)
60 } 81 }
61 _ => Err(LispError::EvalError), 82 _ => Err(LispError::EvalError),
62 } 83 }
@@ -78,40 +99,3 @@ pub fn unwrap_number(n: &LispExpr) -> &LispNumber {
78 _ => panic!("unwrap_number expected number"), 99 _ => panic!("unwrap_number expected number"),
79 } 100 }
80} 101}
81
82#[cfg(test)]
83mod tests {
84 use super::*;
85
86 #[test]
87 fn eval_primitive_call() {
88 let mut env = Environment::new();
89 new_binding(&mut env, "age", LispExpr::Number(LispNumber::Float(1.4)));
90 new_binding(
91 &mut env,
92 "+",
93 LispExpr::PrimitiveFunc(|args, _| {
94 if args.iter().any(|arg| !matches!(arg, LispExpr::Number(_))) {
95 Err(LispError::EvalError)
96 } else {
97 let result = args
98 .iter()
99 .map(|n| unwrap_number(n))
100 .fold(LispNumber::Integer(0), |acc, x| acc + *x);
101 Ok(LispExpr::Number(result))
102 }
103 }),
104 );
105 let mut numbers = (1..=3)
106 .map(LispNumber::Integer)
107 .map(LispExpr::Number)
108 .collect::<Vec<_>>();
109 let mut expr = Vec::new();
110 expr.push(LispExpr::Ident("+".into()));
111 expr.append(&mut numbers);
112 // assert!(matches!(
113 // eval(&LispExpr::List(expr), ).unwrap(),
114 // LispExpr::Number(LispNumber::Integer(6))
115 // ));
116 }
117}
diff --git a/src/lisp/expr.rs b/src/lisp/expr.rs
index 4676a3e..adacc1c 100644
--- a/src/lisp/expr.rs
+++ b/src/lisp/expr.rs
@@ -11,7 +11,7 @@ pub enum LispExpr {
11 StringLit(String), 11 StringLit(String),
12 BoolLit(bool), 12 BoolLit(bool),
13 Ident(String), 13 Ident(String),
14 PrimitiveFunc(fn(&[LispExpr], Option<&mut AppState>) -> Result<LispExpr, LispError>), 14 PrimitiveFunc(PrimitiveFunc),
15 Function(LispFunction), 15 Function(LispFunction),
16 16
17 // none of these depths should be zero 17 // none of these depths should be zero
@@ -21,6 +21,23 @@ pub enum LispExpr {
21 Quote(Box<LispExpr>, u32), 21 Quote(Box<LispExpr>, u32),
22} 22}
23 23
24#[derive(Clone)]
25pub struct PrimitiveFunc {
26 pub arity: Option<usize>,
27 pub closure: fn(&[LispExpr], &mut AppState) -> Result<LispExpr, LispError>,
28}
29
30impl PrimitiveFunc {
31 pub fn call(&self, args: &[LispExpr], app: &mut AppState) -> Result<LispExpr, LispError> {
32 if let Some(arity) = self.arity {
33 if args.len() < arity {
34 return Err(LispError::EvalError);
35 }
36 }
37 (self.closure)(args, app)
38 }
39}
40
24impl LispExpr { 41impl LispExpr {
25 pub fn comma(self, n: u32) -> LispExpr { 42 pub fn comma(self, n: u32) -> LispExpr {
26 match self { 43 match self {
diff --git a/src/lisp/lex.rs b/src/lisp/lex.rs
index 3b1389d..30f49fa 100644
--- a/src/lisp/lex.rs
+++ b/src/lisp/lex.rs
@@ -94,10 +94,7 @@ impl<'a> Lexer<'a> {
94 self.cur_pos += ch.len_utf8() as u32; 94 self.cur_pos += ch.len_utf8() as u32;
95 continue; 95 continue;
96 } 96 }
97 ch => { 97 _ => Err(LispError::ParseError),
98 eprintln!("some unexpected character: {}", ch);
99 Err(LispError::ParseError)
100 }
101 }; 98 };
102 let (size, token) = match res { 99 let (size, token) = match res {
103 Ok(v) => v, 100 Ok(v) => v,
diff --git a/src/lisp/mod.rs b/src/lisp/mod.rs
index 5166a04..2a19314 100644
--- a/src/lisp/mod.rs
+++ b/src/lisp/mod.rs
@@ -4,6 +4,8 @@ pub mod expr;
4pub mod lex; 4pub mod lex;
5pub mod number; 5pub mod number;
6pub mod parse; 6pub mod parse;
7#[macro_use]
8mod primitives;
7 9
8use std::collections::HashMap; 10use std::collections::HashMap;
9 11