Show location of error in parse error

This commit is contained in:
greg 2019-01-07 01:52:31 -08:00
parent a0f4abb9a3
commit fa295aab28

View File

@ -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<tokenizing::Token>, 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<ast::AST, String> {
@ -183,15 +196,20 @@ fn eval(handle: &mut Schala, input: reduced_ast::ReducedAST, comp: Option<&mut U
}
struct SourceReference {
lines: Option<Vec<String>>
}
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"))
}
}