Error placement

This commit is contained in:
Aleksey Kladov 2018-01-07 13:09:13 +03:00
parent efcfaae34a
commit 18f9e50b2d
4 changed files with 37 additions and 9 deletions

View file

@ -156,7 +156,7 @@ impl<'f> ErrorBuilder<'f> {
pub fn emit(self) {
let message = self.message.expect("Error message not set");
let node = self.builder.current_id();
self.builder.errors.push(SyntaxErrorData { node, message })
let &(node, after_child) = self.builder.in_progress.last().unwrap();
self.builder.errors.push(SyntaxErrorData { node, message, after_child })
}
}

View file

@ -2,6 +2,7 @@ use text::{TextUnit, TextRange};
use syntax_kinds::syntax_info;
use std::fmt;
use std::cmp;
mod file_builder;
pub use self::file_builder::{FileBuilder, Sink};
@ -96,6 +97,15 @@ impl<'f> fmt::Debug for Node<'f> {
}
}
impl<'f> cmp::PartialEq<Node<'f>> for Node<'f> {
fn eq(&self, other: &Node<'f>) -> bool {
self.idx == other.idx && ::std::ptr::eq(self.file, other.file)
}
}
impl<'f> cmp::Eq for Node<'f> {
}
#[derive(Clone, Copy)]
pub struct SyntaxError<'f> {
file: &'f File,
@ -107,6 +117,11 @@ impl<'f> SyntaxError<'f> {
self.data().message.as_str()
}
pub fn after_child(&self) -> Option<Node<'f>> {
let idx = self.data().after_child?;
Some(Node { file: self.file, idx })
}
fn data(&self) -> &'f SyntaxErrorData {
&self.file.errors[self.idx]
}
@ -187,6 +202,7 @@ struct ErrorIdx(u32);
struct SyntaxErrorData {
node: NodeIdx,
message: String,
after_child: Option<NodeIdx>,
}
impl ::std::ops::Index<ErrorIdx> for Vec<SyntaxErrorData> {

View file

@ -1,5 +1,5 @@
FILE@[0; 34)
STRUCT_ITEM@[0; 34) err: `expected COMMA`
STRUCT_ITEM@[0; 34)
STRUCT_KW@[0; 6)
WHITESPACE@[6; 7)
IDENT@[7; 8)
@ -12,9 +12,11 @@ FILE@[0; 34)
WHITESPACE@[17; 18)
IDENT@[18; 21)
WHITESPACE@[21; 26)
err: `expected COMMA`
STRUCT_FIELD@[26; 33)
IDENT@[26; 27)
COLON@[27; 28)
WHITESPACE@[28; 29)
IDENT@[29; 32)
WHITESPACE@[32;
WHITESPACE@[32; 33)
R_CURLY@[33; 34)

View file

@ -7,7 +7,7 @@ use std::path::{PathBuf, Path};
use std::fs::read_dir;
use std::fmt::Write;
use libsyntax2::{tokenize, parse, Token, Node, File, FileBuilder};
use libsyntax2::{tokenize, parse, Node, File};
#[test]
fn parser_tests() {
@ -70,14 +70,24 @@ fn dump_tree(file: &File) -> String {
fn go(node: Node, buff: &mut String, level: usize) {
buff.push_str(&String::from(" ").repeat(level));
write!(buff, "{:?}", node).unwrap();
for err in node.errors() {
write!(buff, " err: `{}`", err.message()).unwrap();
write!(buff, "{:?}\n", node).unwrap();
let my_errors = node.errors().filter(|e| e.after_child().is_none());
let parent_errors = node.parent().into_iter()
.flat_map(|n| n.errors())
.filter(|e| e.after_child() == Some(node));
for err in my_errors {
buff.push_str(&String::from(" ").repeat(level));
write!(buff, "err: `{}`\n", err.message()).unwrap();
}
write!(buff, "\n").unwrap();
for child in node.children() {
go(child, buff, level + 1)
}
for err in parent_errors {
buff.push_str(&String::from(" ").repeat(level));
write!(buff, "err: `{}`\n", err.message()).unwrap();
}
}
}