Smart eof for blocks

This commit is contained in:
Aleksey Kladov 2018-01-07 12:13:01 +03:00
parent 8671a892c5
commit f797c81155
7 changed files with 70 additions and 14 deletions

View file

@ -74,7 +74,7 @@ fn many<F: Fn(&mut Parser) -> bool>(p: &mut Parser, f: F) {
fn comma_list<F: Fn(&mut Parser) -> 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
}
}
}

View file

@ -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<Event> {

View file

@ -10,7 +10,9 @@ pub struct Parser<'t> {
pos: usize,
events: Vec<Event>,
curly_level: i32,
curly_limit: Option<i32>,
}
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<SyntaxKind> {
if self.is_eof() {
return None;
@ -73,15 +87,18 @@ impl<'t> Parser<'t> {
}
pub(crate) fn curly_block<F: FnOnce(&mut Parser)>(&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)
}
}
}
pub(crate) struct ErrorBuilder<'p, 't: 'p> {
message: Option<String>,
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<M: Into<String>>(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 });
}
}

View file

@ -44,6 +44,8 @@ fn from_events_to_file(
break;
}
},
Event::Error { message } => builder.error().message(message).emit(),
}
}
builder.finish()

View file

@ -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 })

View file

@ -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<SyntaxError<'f>> {
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;

View file

@ -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)
}