diff options
author | Akshay <[email protected]> | 2021-03-29 05:54:49 +0100 |
---|---|---|
committer | Akshay <[email protected]> | 2021-03-29 05:54:49 +0100 |
commit | 992141878227439cd517d05b68f15e57d77452a5 (patch) | |
tree | d754797718cbe3b551e2abd737ccd1d0986d6b55 | |
parent | 9632fdd69442b10972cc1f71f7a2f11ecc1ca47a (diff) |
fix: handle unterminated strings gracefully
-rw-r--r-- | src/app.rs | 13 | ||||
-rw-r--r-- | src/lisp/error.rs | 4 | ||||
-rw-r--r-- | src/lisp/lex.rs | 8 |
3 files changed, 20 insertions, 5 deletions
@@ -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 | |||
210 | fn parse_string<'a>(input: &'a str) -> Result<(usize, Token<'a>), ParseErrorKind> { | 210 | fn 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 | ||
229 | fn is_ident(ch: char) -> bool { | 235 | fn is_ident(ch: char) -> bool { |