diff --git a/src/tree/file_builder.rs b/src/tree/file_builder.rs index ddb29a6b98..b07f4027b4 100644 --- a/src/tree/file_builder.rs +++ b/src/tree/file_builder.rs @@ -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 }) } } diff --git a/src/tree/mod.rs b/src/tree/mod.rs index 3980b23cee..7f4d427ba9 100644 --- a/src/tree/mod.rs +++ b/src/tree/mod.rs @@ -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> 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> { + 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, } impl ::std::ops::Index for Vec { diff --git a/tests/data/parser/err/0000_struct_field_missing_comma.txt b/tests/data/parser/err/0000_struct_field_missing_comma.txt index e2e99bb635..55a4ad9150 100644 --- a/tests/data/parser/err/0000_struct_field_missing_comma.txt +++ b/tests/data/parser/err/0000_struct_field_missing_comma.txt @@ -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; \ No newline at end of file + WHITESPACE@[32; 33) + R_CURLY@[33; 34) diff --git a/tests/parser.rs b/tests/parser.rs index 206da2a647..43d04e4919 100644 --- a/tests/parser.rs +++ b/tests/parser.rs @@ -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(); + } } }