From f797c81155e9b7371b24801efac3fcbd236fc9ab Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 7 Jan 2018 12:13:01 +0300 Subject: Smart eof for blocks --- src/parser/event_parser/grammar.rs | 12 ++++++++-- src/parser/event_parser/mod.rs | 5 +++- src/parser/event_parser/parser.rs | 48 ++++++++++++++++++++++++++++++++++---- src/parser/mod.rs | 2 ++ src/tree/file_builder.rs | 2 +- src/tree/mod.rs | 7 +++--- tests/parser.rs | 8 +++++-- 7 files changed, 70 insertions(+), 14 deletions(-) diff --git a/src/parser/event_parser/grammar.rs b/src/parser/event_parser/grammar.rs index d09579881..7425526ef 100644 --- a/src/parser/event_parser/grammar.rs +++ b/src/parser/event_parser/grammar.rs @@ -74,7 +74,7 @@ fn many bool>(p: &mut Parser, f: F) { fn comma_list bool>(p: &mut Parser, f: F) { many(p, |p| { f(p); - p.expect(COMMA) + p.is_eof() || p.expect(COMMA) }) } @@ -101,6 +101,14 @@ impl<'p> Parser<'p> { } pub(crate) fn expect(&mut self, kind: SyntaxKind) -> bool { - self.current_is(kind) && { self.bump(); true } + if self.current_is(kind) { + self.bump(); + true + } else { + self.error() + .message(format!("expected {:?}", kind)) + .emit(); + false + } } } \ No newline at end of file diff --git a/src/parser/event_parser/mod.rs b/src/parser/event_parser/mod.rs index 3c3654b6b..87b317c84 100644 --- a/src/parser/event_parser/mod.rs +++ b/src/parser/event_parser/mod.rs @@ -10,7 +10,10 @@ pub(crate) enum Event { Token { kind: SyntaxKind, n_raw_tokens: u8, - } + }, + Error { + message: String, + }, } pub(crate) fn parse<'t>(text: &'t str, raw_tokens: &'t [Token]) -> Vec { diff --git a/src/parser/event_parser/parser.rs b/src/parser/event_parser/parser.rs index 07e3ccc23..eafa03521 100644 --- a/src/parser/event_parser/parser.rs +++ b/src/parser/event_parser/parser.rs @@ -10,7 +10,9 @@ pub struct Parser<'t> { pos: usize, events: Vec, + curly_level: i32, + curly_limit: Option, } impl<'t> Parser<'t> { @@ -32,6 +34,7 @@ impl<'t> Parser<'t> { pos: 0, events: Vec::new(), curly_level: 0, + curly_limit: None, } } @@ -41,7 +44,14 @@ impl<'t> Parser<'t> { } pub(crate) fn is_eof(&self) -> bool { - self.pos == self.non_ws_tokens.len() + if self.pos == self.non_ws_tokens.len() { + return true + } + if let Some(limit) = self.curly_limit { + let idx = self.non_ws_tokens[self.pos].0; + return limit == self.curly_level && self.raw_tokens[idx].kind == R_CURLY; + } + false } pub(crate) fn start(&mut self, kind: SyntaxKind) { @@ -52,6 +62,10 @@ impl<'t> Parser<'t> { self.event(Event::Finish); } + pub(crate) fn error<'p>(&'p mut self) -> ErrorBuilder<'p, 't> { + ErrorBuilder::new(self) + } + pub(crate) fn current(&self) -> Option { if self.is_eof() { return None; @@ -73,15 +87,18 @@ impl<'t> Parser<'t> { } pub(crate) fn curly_block(&mut self, f: F) -> bool { - let level = self.curly_level; + let old_level = self.curly_level; + let old_limit = self.curly_limit; if !self.expect(L_CURLY) { return false } + self.curly_limit = Some(self.curly_level); f(self); - assert!(self.curly_level > level); + assert!(self.curly_level > old_level); + self.curly_limit = old_limit; if !self.expect(R_CURLY) { self.start(ERROR); - while self.curly_level > level { + while self.curly_level > old_level { if self.bump().is_none() { break; } @@ -94,4 +111,25 @@ impl<'t> Parser<'t> { fn event(&mut self, event: Event) { self.events.push(event) } -} \ No newline at end of file +} + +pub(crate) struct ErrorBuilder<'p, 't: 'p> { + message: Option, + parser: &'p mut Parser<'t> +} + +impl<'t, 'p> ErrorBuilder<'p, 't> { + fn new(parser: &'p mut Parser<'t>) -> Self { + ErrorBuilder { message: None, parser } + } + + pub fn message>(mut self, m: M) -> Self { + self.message = Some(m.into()); + self + } + + pub fn emit(self) { + let message = self.message.expect("Error message not set"); + self.parser.event(Event::Error { message }); + } +} diff --git a/src/parser/mod.rs b/src/parser/mod.rs index a632fbc01..a76356eb5 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -44,6 +44,8 @@ fn from_events_to_file( break; } }, + Event::Error { message } => builder.error().message(message).emit(), + } } builder.finish() diff --git a/src/tree/file_builder.rs b/src/tree/file_builder.rs index a1b004892..ddb29a6b9 100644 --- a/src/tree/file_builder.rs +++ b/src/tree/file_builder.rs @@ -154,7 +154,7 @@ impl<'f> ErrorBuilder<'f> { self } - pub fn build(self) { + 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 }) diff --git a/src/tree/mod.rs b/src/tree/mod.rs index 00d33cbc7..3980b23ce 100644 --- a/src/tree/mod.rs +++ b/src/tree/mod.rs @@ -73,7 +73,7 @@ impl<'f> Node<'f> { Children { next: self.as_node(self.data().first_child) } } - pub fn SyntaxErrors(&self) -> SyntaxErrors<'f> { + pub fn errors(&self) -> SyntaxErrors<'f> { let pos = self.file.errors.iter().position(|e| e.node == self.idx); let next = pos .map(|i| ErrorIdx(i as u32)) @@ -112,12 +112,13 @@ impl<'f> SyntaxError<'f> { } fn next(&self) -> Option> { - if self.file.errors.len() == self.idx.0 as usize { + let next_idx = self.idx.0 + 1; + if !((next_idx as usize) < self.file.errors.len()) { return None; } let result = SyntaxError { file: self.file, - idx: ErrorIdx(self.idx.0 + 1) + idx: ErrorIdx(next_idx) }; if result.data().node != self.data().node { return None; diff --git a/tests/parser.rs b/tests/parser.rs index 6c31463ad..7fde365c9 100644 --- a/tests/parser.rs +++ b/tests/parser.rs @@ -61,8 +61,12 @@ fn dump_tree(file: &File) -> String { fn go(node: Node, buff: &mut String, level: usize) { buff.push_str(&String::from(" ").repeat(level)); - write!(buff, "{:?}\n", node) - .unwrap(); + write!(buff, "{:?}", node).unwrap(); + for err in node.errors() { + write!(buff, " err: `{}`", err.message()).unwrap(); + } + write!(buff, "\n").unwrap(); + for child in node.children() { go(child, buff, level + 1) } -- cgit v1.2.3