aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/app.rs62
-rw-r--r--src/lisp/lex.rs64
-rw-r--r--src/lisp/mod.rs3
-rw-r--r--src/lisp/number.rs6
-rw-r--r--src/lisp/parse.rs55
5 files changed, 120 insertions, 70 deletions
diff --git a/src/app.rs b/src/app.rs
index d35febf..09f52f9 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -3,7 +3,7 @@ use crate::{
3 command::CommandBox, 3 command::CommandBox,
4 consts::{colors::*, FONT_PATH}, 4 consts::{colors::*, FONT_PATH},
5 dither, 5 dither,
6 lisp::{eval, lex::Lexer, parse::Parser, Environment}, 6 lisp::{eval, lex::Lexer, parse::Parser, prelude, EnvList, Environment},
7 message::Message, 7 message::Message,
8 rect, 8 rect,
9 symmetry::Symmetry, 9 symmetry::Symmetry,
@@ -11,7 +11,12 @@ use crate::{
11 utils::{draw_text, is_copy_event, is_paste_event}, 11 utils::{draw_text, is_copy_event, is_paste_event},
12}; 12};
13 13
14use std::{convert::From, fs::File, io::prelude::*}; 14use std::{
15 convert::From,
16 fs::File,
17 io::prelude::*,
18 path::{Path, PathBuf},
19};
15 20
16use obi::Image; 21use obi::Image;
17use sdl2::{ 22use sdl2::{
@@ -32,7 +37,7 @@ pub enum Mode {
32 Command, 37 Command,
33} 38}
34 39
35pub struct AppState<'ctx> { 40pub struct AppState<'ctx, 'file> {
36 pub active_color: bool, 41 pub active_color: bool,
37 pub brush_size: u8, 42 pub brush_size: u8,
38 pub canvas: Canvas<Window>, 43 pub canvas: Canvas<Window>,
@@ -40,9 +45,10 @@ pub struct AppState<'ctx> {
40 pub context: &'ctx Sdl, 45 pub context: &'ctx Sdl,
41 pub current_operation: Operation, 46 pub current_operation: Operation,
42 pub dither_level: u8, 47 pub dither_level: u8,
48 pub file_name: Option<&'file Path>,
43 pub grid: Grid, 49 pub grid: Grid,
44 pub last_point: Option<MapPoint>, 50 pub last_point: Option<MapPoint>,
45 pub lisp_env: Environment, 51 pub lisp_env: EnvList,
46 pub message: Message, 52 pub message: Message,
47 pub mode: Mode, 53 pub mode: Mode,
48 pub mouse: (i32, i32), 54 pub mouse: (i32, i32),
@@ -69,7 +75,7 @@ impl Grid {
69} 75}
70 76
71// private actions on appstate 77// private actions on appstate
72impl<'ctx> AppState<'ctx> { 78impl<'ctx, 'file> AppState<'ctx, 'file> {
73 fn pan<P: Into<Point>>(&mut self, direction: P) { 79 fn pan<P: Into<Point>>(&mut self, direction: P) {
74 self.start += direction.into(); 80 self.start += direction.into();
75 } 81 }
@@ -280,22 +286,22 @@ impl<'ctx> AppState<'ctx> {
280 let lisp_expr = &self.command_box.text; 286 let lisp_expr = &self.command_box.text;
281 let mut parser = Parser::new(Lexer::new(lisp_expr, 0)); 287 let mut parser = Parser::new(Lexer::new(lisp_expr, 0));
282 let res = parser.parse_single_expr(); 288 let res = parser.parse_single_expr();
283 match eval::eval(&res.unwrap(), self, None) { 289 match res {
284 Ok(val) => { 290 Ok(expr) => match eval::eval(&expr, self) {
285 self.message.text = format!("{}", val); 291 Ok(val) => self.message.set_info(format!("{}", val)),
286 } 292 Err(eval_err) => self.message.set_error(format!("{}", eval_err)),
287 Err(_) => { 293 },
288 self.message.text = format!("Lisp Error!"); 294 Err(parse_err) => self.message.set_error(format!("{}", parse_err)),
289 }
290 }
291
292 if let Some(path) = self.command_box.text.strip_prefix("(save ") {
293 let image = self.export();
294 let encoded = image.encode().unwrap();
295 let mut buffer = File::create(path).unwrap();
296 buffer.write_all(&encoded[..]).unwrap();
297 self.command_box.hist_append();
298 } 295 }
296 self.command_box.hist_append();
297
298 // if let Some(path) = self.command_box.text.strip_prefix("(save ") {
299 // let image = self.export();
300 // let encoded = image.encode().unwrap();
301 // let mut buffer = File::create(path).unwrap();
302 // buffer.write_all(&encoded[..]).unwrap();
303 // self.command_box.hist_append();
304 // }
299 self.command_box.clear(); 305 self.command_box.clear();
300 self.mode = Mode::Draw; 306 self.mode = Mode::Draw;
301 } 307 }
@@ -371,7 +377,7 @@ impl<'ctx> AppState<'ctx> {
371 &mut self.canvas, 377 &mut self.canvas,
372 self.ttf_context, 378 self.ttf_context,
373 &self.message.text[..], 379 &self.message.text[..],
374 WHITE, 380 self.message.kind.into(),
375 (0, winsize_y - cmd_height), 381 (0, winsize_y - cmd_height),
376 ); 382 );
377 return; 383 return;
@@ -473,18 +479,19 @@ impl<'ctx> AppState<'ctx> {
473 479
474 pub fn quit(&mut self) { 480 pub fn quit(&mut self) {
475 let ev = self.context.event().unwrap(); 481 let ev = self.context.event().unwrap();
476 ev.push_event(Event::Quit { timestamp: 0u32 }); 482 ev.push_event(Event::Quit { timestamp: 0u32 })
483 .expect("ohno unable to quit");
477 } 484 }
478} 485}
479 486
480// publicly available functions on appstate 487impl<'ctx, 'file> AppState<'ctx, 'file> {
481impl<'ctx> AppState<'ctx> {
482 pub fn init( 488 pub fn init(
483 width: u32, 489 width: u32,
484 height: u32, 490 height: u32,
485 context: &'ctx Sdl, 491 context: &'ctx Sdl,
486 ttf_context: &'ctx Sdl2TtfContext, 492 ttf_context: &'ctx Sdl2TtfContext,
487 start_data: Option<Vec<bool>>, 493 start_data: Option<Vec<bool>>,
494 file_name: Option<&'file Path>,
488 ) -> Self { 495 ) -> Self {
489 let video_subsystem = context.video().unwrap(); 496 let video_subsystem = context.video().unwrap();
490 497
@@ -509,21 +516,22 @@ impl<'ctx> AppState<'ctx> {
509 active_color: true, 516 active_color: true,
510 brush_size: 0, 517 brush_size: 0,
511 canvas, 518 canvas,
512 context,
513 command_box: CommandBox::new(), 519 command_box: CommandBox::new(),
520 context,
514 current_operation: Vec::new(), 521 current_operation: Vec::new(),
515 dither_level: 16, 522 dither_level: 16,
523 file_name,
516 grid: Grid::new(), 524 grid: Grid::new(),
517 last_point: None, 525 last_point: None,
518 mode: Mode::Draw, 526 lisp_env: vec![prelude::new_env()],
519 message: Message::new().text(" "), 527 message: Message::new().text(" "),
528 mode: Mode::Draw,
520 mouse: (0, 0), 529 mouse: (0, 0),
521 pixmap, 530 pixmap,
522 start: Point::new(60, 60), 531 start: Point::new(60, 60),
523 symmetry: Default::default(), 532 symmetry: Default::default(),
524 ttf_context, 533 ttf_context,
525 undo_stack: UndoStack::new(), 534 undo_stack: UndoStack::new(),
526 lisp_env: eval::with_prelude(),
527 zoom: 5, 535 zoom: 5,
528 } 536 }
529 } 537 }
diff --git a/src/lisp/lex.rs b/src/lisp/lex.rs
index a7b9586..b307e80 100644
--- a/src/lisp/lex.rs
+++ b/src/lisp/lex.rs
@@ -1,6 +1,6 @@
1use std::{fmt, str::CharIndices}; 1use std::{fmt, str::CharIndices};
2 2
3use super::error::LispError; 3use crate::lisp::error::{LispError, ParseError, ParseErrorKind};
4 4
5#[derive(Copy, Clone, Debug, Eq, PartialEq)] 5#[derive(Copy, Clone, Debug, Eq, PartialEq)]
6pub enum Token<'a> { 6pub enum Token<'a> {
@@ -19,6 +19,26 @@ pub enum Token<'a> {
19 End, 19 End,
20} 20}
21 21
22impl<'a> Token<'a> {
23 pub fn name(&self) -> &'static str {
24 match self {
25 Token::LeftParen => "(",
26 Token::RightParen => ")",
27 Token::Float(_) => "float",
28 Token::Integer(_) => "integer",
29 // Token::Char(_) => "char",
30 Token::String(_) => "string",
31 Token::Name(_) => "name",
32 // Token::Keyword(_) => "keyword",
33 Token::BackQuote => "`",
34 Token::Comma => ",",
35 Token::CommaAt => ",@",
36 Token::Quote => "'",
37 Token::End => "EOF",
38 }
39 }
40}
41
22impl<'a> fmt::Display for Token<'a> { 42impl<'a> fmt::Display for Token<'a> {
23 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 43 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
24 match self { 44 match self {
@@ -54,6 +74,25 @@ impl Span {
54 } 74 }
55} 75}
56 76
77#[derive(Debug, Clone)]
78pub struct SpanDisplay<'src> {
79 pub source: &'src str,
80 pub line: usize,
81 pub col: usize,
82}
83
84impl<'src> SpanDisplay<'src> {
85 pub fn highlight_span(span: Span, source: &'src str) -> Self {
86 let line_start = match source[..span.low as usize].rfind('\n') {
87 Some(pos) => pos + 1,
88 None => 0,
89 };
90 let line = source[..line_start].chars().filter(|&c| c == '\n').count() + 1;
91 let col = source[line_start..span.low as usize].chars().count();
92 Self { source, line, col }
93 }
94}
95
57pub struct Lexer<'input> { 96pub struct Lexer<'input> {
58 input: &'input str, 97 input: &'input str,
59 cur_pos: u32, 98 cur_pos: u32,
@@ -68,6 +107,7 @@ impl<'a> Lexer<'a> {
68 offset, 107 offset,
69 } 108 }
70 } 109 }
110
71 pub fn next_token(&mut self) -> Result<(Span, Token<'a>), LispError> { 111 pub fn next_token(&mut self) -> Result<(Span, Token<'a>), LispError> {
72 let mut chars = self.input.char_indices(); 112 let mut chars = self.input.char_indices();
73 113
@@ -94,11 +134,19 @@ impl<'a> Lexer<'a> {
94 self.cur_pos += ch.len_utf8() as u32; 134 self.cur_pos += ch.len_utf8() as u32;
95 continue; 135 continue;
96 } 136 }
97 _ => Err(LispError::ParseError), 137 ch => Err(ParseErrorKind::InvalidChar(ch)),
98 }; 138 };
99 let (size, token) = match res { 139 let (size, token) = match res {
100 Ok(v) => v, 140 Ok(v) => v,
101 Err(_) => return Err(LispError::ParseError), 141 Err(kind) => {
142 return Err(LispError::Parse(ParseError {
143 span: Span {
144 low,
145 high: low + chr.len_utf8() as u32,
146 },
147 kind,
148 }))
149 }
102 }; 150 };
103 self.cur_pos += size as u32; 151 self.cur_pos += size as u32;
104 self.input = &self.input[ind + size..]; 152 self.input = &self.input[ind + size..];
@@ -113,7 +161,7 @@ impl<'a> Lexer<'a> {
113 } 161 }
114} 162}
115 163
116fn parse_number<'a>(mut input: &'a str) -> Result<(usize, Token<'a>), LispError> { 164fn parse_number<'a>(mut input: &'a str) -> Result<(usize, Token<'a>), ParseErrorKind> {
117 let mut dot = false; 165 let mut dot = false;
118 let mut minus = false; 166 let mut minus = false;
119 let mut size = 0; 167 let mut size = 0;
@@ -137,12 +185,12 @@ fn parse_number<'a>(mut input: &'a str) -> Result<(usize, Token<'a>), LispError>
137 dot = true; 185 dot = true;
138 size += 1; 186 size += 1;
139 } else { 187 } else {
140 return Err(LispError::ParseError); 188 return Err(ParseErrorKind::InvalidChar(chr));
141 } 189 }
142 } else if !is_ident(chr) { 190 } else if !is_ident(chr) {
143 break; 191 break;
144 } else { 192 } else {
145 return Err(LispError::ParseError); 193 return Err(ParseErrorKind::InvalidChar(chr));
146 } 194 }
147 } 195 }
148 196
@@ -156,7 +204,7 @@ fn parse_number<'a>(mut input: &'a str) -> Result<(usize, Token<'a>), LispError>
156 return Ok((size, tok)); 204 return Ok((size, tok));
157} 205}
158 206
159fn parse_string<'a>(input: &'a str) -> Result<(usize, Token<'a>), LispError> { 207fn parse_string<'a>(input: &'a str) -> Result<(usize, Token<'a>), ParseErrorKind> {
160 // count opening quote 208 // count opening quote
161 let mut size = 1; 209 let mut size = 1;
162 let mut chars = input.char_indices().skip(1); 210 let mut chars = input.char_indices().skip(1);
@@ -197,7 +245,7 @@ fn consume_comment(start: usize, chars: &mut CharIndices) -> usize {
197 last - start + 1 245 last - start + 1
198} 246}
199 247
200fn parse_name<'a>(input: &'a str) -> Result<(usize, Token<'a>), LispError> { 248fn parse_name<'a>(input: &'a str) -> Result<(usize, Token<'a>), ParseErrorKind> {
201 for (ind, chr) in input.char_indices() { 249 for (ind, chr) in input.char_indices() {
202 if !is_ident(chr) { 250 if !is_ident(chr) {
203 return Ok((ind, Token::Name(&input[..ind]))); 251 return Ok((ind, Token::Name(&input[..ind])));
diff --git a/src/lisp/mod.rs b/src/lisp/mod.rs
index a52baa0..87a2720 100644
--- a/src/lisp/mod.rs
+++ b/src/lisp/mod.rs
@@ -4,10 +4,11 @@ pub mod expr;
4pub mod lex; 4pub mod lex;
5pub mod number; 5pub mod number;
6pub mod parse; 6pub mod parse;
7mod primitives; 7pub mod prelude;
8 8
9use std::collections::HashMap; 9use std::collections::HashMap;
10 10
11use expr::LispExpr; 11use expr::LispExpr;
12 12
13pub type Environment = HashMap<String, LispExpr>; 13pub type Environment = HashMap<String, LispExpr>;
14pub type EnvList = Vec<Environment>;
diff --git a/src/lisp/number.rs b/src/lisp/number.rs
index 18a41f7..23d7997 100644
--- a/src/lisp/number.rs
+++ b/src/lisp/number.rs
@@ -1,9 +1,9 @@
1use std::{ 1use std::{
2 fmt, 2 fmt,
3 ops::{Add, Div, Mul, Sub}, 3 ops::{Add, Mul, Sub},
4}; 4};
5 5
6use crate::lisp::error::LispError; 6use crate::lisp::error::{EvalError, LispError};
7 7
8#[derive(Debug, Copy, Clone)] 8#[derive(Debug, Copy, Clone)]
9pub enum LispNumber { 9pub enum LispNumber {
@@ -15,7 +15,7 @@ impl LispNumber {
15 pub fn div(self, rhs: Self) -> Result<LispNumber, LispError> { 15 pub fn div(self, rhs: Self) -> Result<LispNumber, LispError> {
16 use LispNumber::*; 16 use LispNumber::*;
17 if rhs == Integer(0) || rhs == Float(0.) { 17 if rhs == Integer(0) || rhs == Float(0.) {
18 return Err(LispError::EvalError); 18 return Err(EvalError::DivByZero.into());
19 } else { 19 } else {
20 return Ok(match (self, rhs) { 20 return Ok(match (self, rhs) {
21 (Integer(a), Integer(b)) => Float(a as f64 / b as f64), 21 (Integer(a), Integer(b)) => Float(a as f64 / b as f64),
diff --git a/src/lisp/parse.rs b/src/lisp/parse.rs
index 89a272a..4e0f427 100644
--- a/src/lisp/parse.rs
+++ b/src/lisp/parse.rs
@@ -1,5 +1,5 @@
1use crate::lisp::{ 1use crate::lisp::{
2 error::LispError, 2 error::{LispError, ParseError, ParseErrorKind},
3 lex::{Lexer, Span, Token}, 3 lex::{Lexer, Span, Token},
4 number::LispNumber, 4 number::LispNumber,
5 LispExpr, 5 LispExpr,
@@ -10,26 +10,6 @@ pub struct Parser<'lex> {
10 cur_token: Option<(Span, Token<'lex>)>, 10 cur_token: Option<(Span, Token<'lex>)>,
11} 11}
12 12
13// pub struct ParseError {
14// pub span: Span,
15// pub kind: ParseErrorKind,
16// }
17//
18// pub enum ParseErrorKind {
19// InvalidLiteral,
20// InvalidToken,
21// LiteralParseError,
22// MissingCloseParen,
23// UnbalancedComma,
24// UnexpectedEof,
25// UnexpectedToken {
26// expected: &'static str,
27// found: &'static str,
28// },
29// UnmatchedParen,
30// UnterminatedString,
31// }
32
33enum Group { 13enum Group {
34 Backticks(i32), 14 Backticks(i32),
35 CommaAt, 15 CommaAt,
@@ -49,7 +29,7 @@ impl<'lex> Parser<'lex> {
49 let mut stack = Vec::new(); 29 let mut stack = Vec::new();
50 let mut total_backticks = 0; 30 let mut total_backticks = 0;
51 loop { 31 loop {
52 let (_, token) = self.next()?; 32 let (span, token) = self.next()?;
53 let r: Result<LispExpr, LispError> = match token { 33 let r: Result<LispExpr, LispError> = match token {
54 Token::LeftParen => { 34 Token::LeftParen => {
55 stack.push(Group::Parens(Vec::new())); 35 stack.push(Group::Parens(Vec::new()));
@@ -57,21 +37,27 @@ impl<'lex> Parser<'lex> {
57 } 37 }
58 Token::RightParen => { 38 Token::RightParen => {
59 let group = stack.pop().ok_or_else( 39 let group = stack.pop().ok_or_else(
60 || LispError::ParseError, // unmatched paren here 40 || (ParseError::new(span, ParseErrorKind::UnmatchedParen)), // unmatched paren here
61 )?; 41 )?;
62 match group { 42 match group {
63 Group::Parens(v) => Ok(LispExpr::List(v)), 43 Group::Parens(v) => Ok(LispExpr::List(v)),
64 _ => Err(LispError::ParseError), 44 _ => Err(From::from(ParseError::new(
45 span,
46 ParseErrorKind::UnexpectedToken {
47 expected: "expression",
48 found: "(",
49 },
50 ))),
65 } 51 }
66 } 52 }
67 Token::Float(f) => f 53 Token::Float(f) => f
68 .parse::<f64>() 54 .parse::<f64>()
69 .map(|n| LispExpr::Number(LispNumber::Float(n))) 55 .map(|n| LispExpr::Number(LispNumber::Float(n)))
70 .map_err(|_| LispError::ParseError), 56 .map_err(|_| ParseError::new(span, ParseErrorKind::LiteralParseError).into()),
71 Token::Integer(i) => i 57 Token::Integer(i) => i
72 .parse::<i64>() 58 .parse::<i64>()
73 .map(|n| LispExpr::Number(LispNumber::Integer(n))) 59 .map(|n| LispExpr::Number(LispNumber::Integer(n)))
74 .map_err(|_| LispError::ParseError), 60 .map_err(|_| ParseError::new(span, ParseErrorKind::LiteralParseError).into()),
75 Token::String(s) => Ok(LispExpr::StringLit(s.into())), 61 Token::String(s) => Ok(LispExpr::StringLit(s.into())),
76 Token::Name(n) => Ok(name_expr(n)), 62 Token::Name(n) => Ok(name_expr(n)),
77 Token::BackQuote => { 63 Token::BackQuote => {
@@ -85,7 +71,7 @@ impl<'lex> Parser<'lex> {
85 } 71 }
86 Token::Comma => { 72 Token::Comma => {
87 if total_backticks <= 0 { 73 if total_backticks <= 0 {
88 return Err(LispError::ParseError); // unbalanced comma 74 return Err(ParseError::new(span, ParseErrorKind::UnbalancedComma).into());
89 } 75 }
90 total_backticks -= 1; 76 total_backticks -= 1;
91 if let Some(&mut Group::Backticks(ref mut n)) = stack.last_mut() { 77 if let Some(&mut Group::Backticks(ref mut n)) = stack.last_mut() {
@@ -97,7 +83,7 @@ impl<'lex> Parser<'lex> {
97 } 83 }
98 Token::CommaAt => { 84 Token::CommaAt => {
99 if total_backticks <= 0 { 85 if total_backticks <= 0 {
100 return Err(LispError::ParseError); // unbalanced comma 86 return Err(ParseError::new(span, ParseErrorKind::UnbalancedComma).into());
101 } 87 }
102 total_backticks -= 1; 88 total_backticks -= 1;
103 stack.push(Group::CommaAt); 89 stack.push(Group::CommaAt);
@@ -118,9 +104,9 @@ impl<'lex> Parser<'lex> {
118 }); 104 });
119 105
120 if any_paren { 106 if any_paren {
121 Err(LispError::ParseError) // unbalanced paren 107 Err(ParseError::new(span, ParseErrorKind::MissingCloseParen).into())
122 } else { 108 } else {
123 Err(LispError::ParseError) // unexpected eof 109 Err(ParseError::new(span, ParseErrorKind::UnexpectedEof).into())
124 } 110 }
125 } 111 }
126 }; 112 };
@@ -178,7 +164,14 @@ impl<'lex> Parser<'lex> {
178 164
179 match self.next()? { 165 match self.next()? {
180 (_, Token::End) => Ok(expr), 166 (_, Token::End) => Ok(expr),
181 _ => Err(LispError::ParseError), // too many tokens 167 (span, token) => Err(ParseError::new(
168 span,
169 ParseErrorKind::UnexpectedToken {
170 expected: "EOF",
171 found: token.name(),
172 },
173 )
174 .into()),
182 } 175 }
183 } 176 }
184 177