mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-25 20:43:21 +00:00
Smart eof for blocks
This commit is contained in:
parent
8671a892c5
commit
f797c81155
7 changed files with 70 additions and 14 deletions
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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> {
|
||||
|
|
|
@ -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 });
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,6 +44,8 @@ fn from_events_to_file(
|
|||
break;
|
||||
}
|
||||
},
|
||||
Event::Error { message } => builder.error().message(message).emit(),
|
||||
|
||||
}
|
||||
}
|
||||
builder.finish()
|
||||
|
|
|
@ -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 })
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue