aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAkshay <[email protected]>2021-03-29 05:54:49 +0100
committerAkshay <[email protected]>2021-03-29 05:54:49 +0100
commit992141878227439cd517d05b68f15e57d77452a5 (patch)
treed754797718cbe3b551e2abd737ccd1d0986d6b55
parent9632fdd69442b10972cc1f71f7a2f11ecc1ca47a (diff)
fix: handle unterminated strings gracefully
-rw-r--r--src/app.rs13
-rw-r--r--src/lisp/error.rs4
-rw-r--r--src/lisp/lex.rs8
3 files changed, 20 insertions, 5 deletions
diff --git a/src/app.rs b/src/app.rs
index 016349b..eef896d 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -4,7 +4,7 @@ use crate::{
4 command::CommandBox, 4 command::CommandBox,
5 consts::{colors::*, FONT_PATH}, 5 consts::{colors::*, FONT_PATH},
6 dither, 6 dither,
7 lisp::{eval, lex::Lexer, parse::Parser, prelude, EnvList}, 7 lisp::{error::LispError, eval, lex::Lexer, parse::Parser, prelude, EnvList},
8 message::Message, 8 message::Message,
9 rect, 9 rect,
10 symmetry::Symmetry, 10 symmetry::Symmetry,
@@ -284,7 +284,7 @@ impl<'ctx, 'file> AppState<'ctx, 'file> {
284 Ok(val) => self.message.set_info(format!("{}", val)), 284 Ok(val) => self.message.set_info(format!("{}", val)),
285 Err(eval_err) => self.message.set_error(format!("{}", eval_err)), 285 Err(eval_err) => self.message.set_error(format!("{}", eval_err)),
286 }, 286 },
287 Err(parse_err) => self.message.set_error(format!("{}", parse_err)), 287 Err(err) => self.message = AppState::handle_error(err, &lisp_expr),
288 } 288 }
289 self.command_box.hist_append(); 289 self.command_box.hist_append();
290 290
@@ -292,6 +292,15 @@ impl<'ctx, 'file> AppState<'ctx, 'file> {
292 self.mode = Mode::Draw; 292 self.mode = Mode::Draw;
293 } 293 }
294 294
295 fn handle_error(err: LispError, src: &str) -> Message {
296 let mut message = Message::new();
297 match err {
298 LispError::Parse(p) => message.set_error(p.display(&src)),
299 eval_err => message.set_error(eval_err.to_string()),
300 }
301 message
302 }
303
295 fn draw_grid(&mut self) { 304 fn draw_grid(&mut self) {
296 let cs = self.zoom as u32; 305 let cs = self.zoom as u32;
297 let (width, height) = (self.width(), self.height()); 306 let (width, height) = (self.width(), self.height());
diff --git a/src/lisp/error.rs b/src/lisp/error.rs
index a360eb2..6d28c22 100644
--- a/src/lisp/error.rs
+++ b/src/lisp/error.rs
@@ -30,9 +30,9 @@ impl ParseError {
30 pub fn new(span: Span, kind: ParseErrorKind) -> Self { 30 pub fn new(span: Span, kind: ParseErrorKind) -> Self {
31 Self { span, kind } 31 Self { span, kind }
32 } 32 }
33 pub fn fmt(&self, f: &mut fmt::Formatter<'_>, text: &str) -> fmt::Result { 33 pub fn display(&self, text: &str) -> String {
34 let SpanDisplay { line, col, .. } = SpanDisplay::highlight_span(self.span, text); 34 let SpanDisplay { line, col, .. } = SpanDisplay::highlight_span(self.span, text);
35 write!(f, "line {}, col {}: {}", line, col, self.kind) 35 format!("line {}, col {}: {}", line, col, self.kind)
36 } 36 }
37} 37}
38 38
diff --git a/src/lisp/lex.rs b/src/lisp/lex.rs
index 1a34e53..e514d7f 100644
--- a/src/lisp/lex.rs
+++ b/src/lisp/lex.rs
@@ -210,6 +210,7 @@ fn parse_number<'a>(mut input: &'a str) -> Result<(usize, Token<'a>), ParseError
210fn parse_string<'a>(input: &'a str) -> Result<(usize, Token<'a>), ParseErrorKind> { 210fn parse_string<'a>(input: &'a str) -> Result<(usize, Token<'a>), ParseErrorKind> {
211 // count opening quote 211 // count opening quote
212 let mut size = 1; 212 let mut size = 1;
213 let mut closed = false;
213 let mut chars = input.char_indices().skip(1); 214 let mut chars = input.char_indices().skip(1);
214 while let Some((ind, chr)) = chars.next() { 215 while let Some((ind, chr)) = chars.next() {
215 match chr { 216 match chr {
@@ -218,12 +219,17 @@ fn parse_string<'a>(input: &'a str) -> Result<(usize, Token<'a>), ParseErrorKind
218 } 219 }
219 '"' => { 220 '"' => {
220 size += ind; 221 size += ind;
222 closed = true;
221 break; 223 break;
222 } 224 }
223 _ => (), 225 _ => (),
224 } 226 }
225 } 227 }
226 return Ok((size, Token::String(&input[..size]))); 228 if !closed {
229 Err(ParseErrorKind::UnterminatedString)
230 } else {
231 Ok((size, Token::String(&input[..size])))
232 }
227} 233}
228 234
229fn is_ident(ch: char) -> bool { 235fn is_ident(ch: char) -> bool {