aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAkshay <[email protected]>2021-03-23 13:26:25 +0000
committerAkshay <[email protected]>2021-03-23 13:26:25 +0000
commit305bf638f823a41f391936712eef302bc6733d00 (patch)
tree6a9cc8a41c691bed2027c8debdc4391aab837c89
parenta0fce05399b3ee284b6c60a409fad74c23432ce8 (diff)
expose functions to lisp interface, add primitives with macros
-rw-r--r--src/app.rs51
-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
5 files changed, 80 insertions, 85 deletions
diff --git a/src/app.rs b/src/app.rs
index 9730cf2..ef299cd 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -13,6 +13,7 @@ use crate::{
13 13
14use std::{convert::From, fs::File, io::prelude::*}; 14use std::{convert::From, fs::File, io::prelude::*};
15 15
16use log::{info, warn};
16use obi::Image; 17use obi::Image;
17use sdl2::{ 18use sdl2::{
18 event::Event, 19 event::Event,
@@ -74,11 +75,11 @@ impl<'ctx> AppState<'ctx> {
74 self.start += direction.into(); 75 self.start += direction.into();
75 } 76 }
76 77
77 fn width(&self) -> u32 { 78 pub fn width(&self) -> u32 {
78 self.pixmap.width 79 self.pixmap.width
79 } 80 }
80 81
81 fn height(&self) -> u32 { 82 pub fn height(&self) -> u32 {
82 self.pixmap.height 83 self.pixmap.height
83 } 84 }
84 85
@@ -93,11 +94,11 @@ impl<'ctx> AppState<'ctx> {
93 ); 94 );
94 } 95 }
95 96
96 fn change_active_color(&mut self) { 97 pub fn change_active_color(&mut self) {
97 self.active_color = !self.active_color; 98 self.active_color = !self.active_color;
98 } 99 }
99 100
100 fn idx_at_coord<P: Into<Point>>(&self, p: P) -> Option<(u32, u32)> { 101 pub fn idx_at_coord<P: Into<Point>>(&self, p: P) -> Option<(u32, u32)> {
101 let p: Point = p.into(); 102 let p: Point = p.into();
102 if self.within_canvas(p) { 103 if self.within_canvas(p) {
103 // convert p relative to start of drawing area 104 // convert p relative to start of drawing area
@@ -110,17 +111,17 @@ impl<'ctx> AppState<'ctx> {
110 } 111 }
111 } 112 }
112 113
113 fn within_canvas<P: Into<Point>>(&self, p: P) -> bool { 114 pub fn within_canvas<P: Into<Point>>(&self, p: P) -> bool {
114 let p: Point = p.into(); 115 let p: Point = p.into();
115 let (mini, maxi) = self.bounds(); 116 let (mini, maxi) = self.bounds();
116 p.x() < maxi.x() && p.y() < maxi.y() && p.x() >= mini.x() && p.y() >= mini.y() 117 p.x() < maxi.x() && p.y() < maxi.y() && p.x() >= mini.x() && p.y() >= mini.y()
117 } 118 }
118 119
119 fn toggle_grid(&mut self) { 120 pub fn toggle_grid(&mut self) {
120 self.grid.enabled = !self.grid.enabled; 121 self.grid.enabled = !self.grid.enabled;
121 } 122 }
122 123
123 fn cycle_symmetry(&mut self) { 124 pub fn cycle_symmetry(&mut self) {
124 let Symmetry { x, y } = self.symmetry; 125 let Symmetry { x, y } = self.symmetry;
125 self.symmetry = match (x, y) { 126 self.symmetry = match (x, y) {
126 (None, None) => Symmetry { 127 (None, None) => Symmetry {
@@ -139,7 +140,7 @@ impl<'ctx> AppState<'ctx> {
139 } 140 }
140 } 141 }
141 142
142 fn paint_point<P: Into<Point>>( 143 pub fn paint_point<P: Into<Point>>(
143 &mut self, 144 &mut self,
144 center: P, 145 center: P,
145 val: bool, 146 val: bool,
@@ -164,7 +165,7 @@ impl<'ctx> AppState<'ctx> {
164 Ok(modify_record) 165 Ok(modify_record)
165 } 166 }
166 167
167 fn paint_line<P: Into<Point>>( 168 pub fn paint_line<P: Into<Point>>(
168 &mut self, 169 &mut self,
169 start: MapPoint, 170 start: MapPoint,
170 end: P, 171 end: P,
@@ -191,7 +192,7 @@ impl<'ctx> AppState<'ctx> {
191 Ok(line_modify_record) 192 Ok(line_modify_record)
192 } 193 }
193 194
194 fn apply_operation(&mut self, op: Operation, op_kind: OpKind) { 195 pub fn apply_operation(&mut self, op: Operation, op_kind: OpKind) {
195 for ModifyRecord { 196 for ModifyRecord {
196 point, 197 point,
197 old_val, 198 old_val,
@@ -207,7 +208,7 @@ impl<'ctx> AppState<'ctx> {
207 } 208 }
208 } 209 }
209 210
210 fn commit_operation(&mut self) { 211 pub fn commit_operation(&mut self) {
211 if !self.current_operation.is_empty() { 212 if !self.current_operation.is_empty() {
212 let op = self 213 let op = self
213 .current_operation 214 .current_operation
@@ -218,7 +219,7 @@ impl<'ctx> AppState<'ctx> {
218 } 219 }
219 } 220 }
220 221
221 fn zoom_in(&mut self, p: (i32, i32)) { 222 pub fn zoom_in(&mut self, p: (i32, i32)) {
222 // attempt to center around cursor 223 // attempt to center around cursor
223 if let Some(p) = self.idx_at_coord(p) { 224 if let Some(p) = self.idx_at_coord(p) {
224 let (x1, y1) = (p.0 * (self.zoom as u32), p.1 * (self.zoom as u32)); 225 let (x1, y1) = (p.0 * (self.zoom as u32), p.1 * (self.zoom as u32));
@@ -230,7 +231,7 @@ impl<'ctx> AppState<'ctx> {
230 self.zoom += 1; 231 self.zoom += 1;
231 } 232 }
232 233
233 fn zoom_out(&mut self, p: (i32, i32)) { 234 pub fn zoom_out(&mut self, p: (i32, i32)) {
234 if self.zoom > 1 { 235 if self.zoom > 1 {
235 // attempt to center around cursor 236 // attempt to center around cursor
236 if let Some(p) = self.idx_at_coord(p) { 237 if let Some(p) = self.idx_at_coord(p) {
@@ -244,7 +245,7 @@ impl<'ctx> AppState<'ctx> {
244 } 245 }
245 } 246 }
246 247
247 fn center_grid(&mut self) { 248 pub fn center_grid(&mut self) {
248 let (winsize_x, winsize_y) = self.canvas.window().size(); 249 let (winsize_x, winsize_y) = self.canvas.window().size();
249 let grid_width = self.width() * self.zoom as u32; 250 let grid_width = self.width() * self.zoom as u32;
250 let grid_height = self.height() * self.zoom as u32; 251 let grid_height = self.height() * self.zoom as u32;
@@ -254,29 +255,29 @@ impl<'ctx> AppState<'ctx> {
254 ); 255 );
255 } 256 }
256 257
257 fn increase_brush_size(&mut self) { 258 pub fn increase_brush_size(&mut self) {
258 self.brush_size += 1; 259 self.brush_size += 1;
259 } 260 }
260 261
261 fn decrease_brush_size(&mut self) { 262 pub fn decrease_brush_size(&mut self) {
262 if self.brush_size > 0 { 263 if self.brush_size > 0 {
263 self.brush_size -= 1; 264 self.brush_size -= 1;
264 } 265 }
265 } 266 }
266 267
267 fn reduce_intensity(&mut self) { 268 pub fn reduce_intensity(&mut self) {
268 if self.dither_level > 0 { 269 if self.dither_level > 0 {
269 self.dither_level -= 1; 270 self.dither_level -= 1;
270 } 271 }
271 } 272 }
272 273
273 fn increase_intensity(&mut self) { 274 pub fn increase_intensity(&mut self) {
274 if self.dither_level < 16 { 275 if self.dither_level < 16 {
275 self.dither_level += 1; 276 self.dither_level += 1;
276 } 277 }
277 } 278 }
278 279
279 fn eval_command(&mut self) { 280 pub fn eval_command(&mut self) {
280 let lisp_expr = &self.command_box.text; 281 let lisp_expr = &self.command_box.text;
281 let mut parser = Parser::new(Lexer::new(lisp_expr, 0)); 282 let mut parser = Parser::new(Lexer::new(lisp_expr, 0));
282 let res = parser.parse_single_expr(); 283 let res = parser.parse_single_expr();
@@ -293,11 +294,8 @@ impl<'ctx> AppState<'ctx> {
293 let image = self.export(); 294 let image = self.export();
294 let encoded = image.encode().unwrap(); 295 let encoded = image.encode().unwrap();
295 let mut buffer = File::create(path).unwrap(); 296 let mut buffer = File::create(path).unwrap();
296 eprintln!("writing to file");
297 buffer.write_all(&encoded[..]).unwrap(); 297 buffer.write_all(&encoded[..]).unwrap();
298 self.command_box.hist_append(); 298 self.command_box.hist_append();
299 } else {
300 eprintln!("cmd: {}", self.command_box.text);
301 } 299 }
302 self.command_box.clear(); 300 self.command_box.clear();
303 self.mode = Mode::Draw; 301 self.mode = Mode::Draw;
@@ -332,7 +330,7 @@ impl<'ctx> AppState<'ctx> {
332 self.canvas 330 self.canvas
333 .fill_rect(rect!( 331 .fill_rect(rect!(
334 0, 332 0,
335 winsize_y - status_height, 333 winsize_y - status_height - 20,
336 status_width, 334 status_width,
337 status_height 335 status_height
338 )) 336 ))
@@ -355,7 +353,7 @@ impl<'ctx> AppState<'ctx> {
355 self.ttf_context, 353 self.ttf_context,
356 status_text, 354 status_text,
357 BLACK, 355 BLACK,
358 (0, winsize_y - status_height), 356 (0, winsize_y - status_height - 20),
359 ); 357 );
360 } 358 }
361 359
@@ -462,11 +460,8 @@ impl<'ctx> AppState<'ctx> {
462 .draw_line((line_coord, 0), (line_coord, winsize_y as i32)) 460 .draw_line((line_coord, 0), (line_coord, winsize_y as i32))
463 .unwrap(); 461 .unwrap();
464 } 462 }
465 // if self.mode == Mode::Draw { 463 self.draw_statusline();
466 // self.draw_statusline();
467 // } else {
468 self.draw_command_box(); 464 self.draw_command_box();
469 // }
470 self.draw_mouse(); 465 self.draw_mouse();
471 } 466 }
472 467
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