From fa295aab281c606db44b6b2dc656b03971620cba Mon Sep 17 00:00:00 2001 From: greg Date: Mon, 7 Jan 2019 01:52:31 -0800 Subject: [PATCH] Show location of error in parse error --- schala-lang/language/src/lib.rs | 40 ++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/schala-lang/language/src/lib.rs b/schala-lang/language/src/lib.rs index 02746c4..2992b6e 100644 --- a/schala-lang/language/src/lib.rs +++ b/schala-lang/language/src/lib.rs @@ -90,7 +90,8 @@ impl Schala { } //TODO rejigger the signature of these methods so you don't awkwardly have the input in the middle -fn load_source<'a>(_handle: &mut Schala, input: &'a str, comp: Option<&mut UnfinishedComputation>) -> Result<&'a str, String> { +fn load_source<'a>(handle: &mut Schala, input: &'a str, _comp: Option<&mut UnfinishedComputation>) -> Result<&'a str, String> { + handle.source_reference.load_new_source(input); Ok(input) } @@ -131,13 +132,25 @@ fn parsing(handle: &mut Schala, input: Vec, comp: Option<&mut Some(ref x) => println!("Bad parsing debug option: {}", x), }; }); - ast.map_err(|error: parsing::ParseError| { - let location_frag = match error.token { - Some(tok) => format!(" at line: {} column: {}", tok.offset.0, tok.offset.1), - None => "".into() - }; - format!("'{}'{}", error.msg, location_frag) - }) + ast.map_err(|err| format_parse_error(err, handle)) +} + +fn format_parse_error(error: parsing::ParseError, handle: &mut Schala) -> String { + //TODO make token no longer be Optoinal + if let Some(tok) = error.token { + let line = tok.offset.0; + let ch = tok.offset.1; + let line_from_program = handle.source_reference.get_line(line); + let location_pointer = format!("{}^", " ".repeat(ch)); + format!(r#" +{} +| +| {} +| {} +"#, error.msg, line_from_program, location_pointer) + } else { + format!("{}", error.msg) + } } fn symbol_table(handle: &mut Schala, input: ast::AST, comp: Option<&mut UnfinishedComputation>) -> Result { @@ -183,15 +196,20 @@ fn eval(handle: &mut Schala, input: reduced_ast::ReducedAST, comp: Option<&mut U } struct SourceReference { - + lines: Option> } impl SourceReference { fn new() -> SourceReference { - SourceReference { } + SourceReference { lines: None } } - fn load_new_source(&mut self, source: String) { + fn load_new_source(&mut self, source: &str) { + //TODO this is a lot of heap allocations - maybe there's a way to make it more efficient? + self.lines = Some(source.lines().map(|s| s.to_string()).collect()); + } + fn get_line(&self, line: usize) -> String { + self.lines.as_ref().and_then(|x| x.get(line).map(|s| s.to_string())).unwrap_or(format!("NO LINE FOUND")) } }