Better error messages for # expressions

This commit is contained in:
Laurenz 2023-07-06 15:59:20 +02:00
parent adcc6e5506
commit db09a5a712
2 changed files with 67 additions and 44 deletions

View File

@ -21,7 +21,7 @@ pub fn parse_code(text: &str) -> SyntaxNode {
let m = p.marker(); let m = p.marker();
p.skip(); p.skip();
code_exprs(&mut p, |_| false); code_exprs(&mut p, |_| false);
p.wrap_skipless(m, SyntaxKind::Code); p.wrap_all(m, SyntaxKind::Code);
p.finish().into_iter().next().unwrap() p.finish().into_iter().next().unwrap()
} }
@ -567,10 +567,14 @@ fn embedded_code_expr(p: &mut Parser) {
let prev = p.prev_end(); let prev = p.prev_end();
code_expr_prec(p, true, 0, false); code_expr_prec(p, true, 0, false);
// Consume error for things like `#12p` or `#"abc\"`. // Consume error for things like `#12p` or `#"abc\"`.#
if !p.progress(prev) { if !p.progress(prev) {
if p.current().is_trivia() {
// p.unskip();
} else if !p.eof() {
p.unexpected(); p.unexpected();
} }
}
let semi = let semi =
(stmt || p.directly_at(SyntaxKind::Semicolon)) && p.eat_if(SyntaxKind::Semicolon); (stmt || p.directly_at(SyntaxKind::Semicolon)) && p.eat_if(SyntaxKind::Semicolon);
@ -1021,9 +1025,7 @@ fn set_rule(p: &mut Parser) {
fn show_rule(p: &mut Parser) { fn show_rule(p: &mut Parser) {
let m = p.marker(); let m = p.marker();
p.assert(SyntaxKind::Show); p.assert(SyntaxKind::Show);
p.unskip(); let m2 = p.before_trivia();
let m2 = p.marker();
p.skip();
if !p.at(SyntaxKind::Colon) { if !p.at(SyntaxKind::Colon) {
code_expr(p); code_expr(p);
@ -1488,16 +1490,20 @@ impl<'s> Parser<'s> {
.filter(|child| !child.kind().is_error() && !child.kind().is_trivia()) .filter(|child| !child.kind().is_error() && !child.kind().is_trivia())
} }
fn wrap(&mut self, m: Marker, kind: SyntaxKind) { fn wrap(&mut self, from: Marker, kind: SyntaxKind) {
self.unskip(); self.wrap_within(from, self.before_trivia(), kind);
self.wrap_skipless(m, kind);
self.skip();
} }
fn wrap_skipless(&mut self, m: Marker, kind: SyntaxKind) { fn wrap_all(&mut self, from: Marker, kind: SyntaxKind) {
let from = m.0.min(self.nodes.len()); self.wrap_within(from, Marker(self.nodes.len()), kind)
let children = self.nodes.drain(from..).collect(); }
self.nodes.push(SyntaxNode::inner(kind, children));
fn wrap_within(&mut self, from: Marker, to: Marker, kind: SyntaxKind) {
let len = self.nodes.len();
let to = to.0.min(len);
let from = from.0.min(to);
let children = self.nodes.drain(from..to).collect();
self.nodes.insert(from, SyntaxNode::inner(kind, children));
} }
fn progress(&self, offset: usize) -> bool { fn progress(&self, offset: usize) -> bool {
@ -1602,24 +1608,17 @@ impl<'s> Parser<'s> {
/// Produce an error that the given `thing` was expected. /// Produce an error that the given `thing` was expected.
fn expected(&mut self, thing: &str) { fn expected(&mut self, thing: &str) {
self.unskip();
if !self.after_error() { if !self.after_error() {
let message = eco_format!("expected {thing}"); self.expected_at(self.before_trivia(), thing);
self.nodes.push(SyntaxNode::error(message, ""));
} }
self.skip();
} }
/// Produce an error that the given `thing` was expected but another /// Produce an error that the given `thing` was expected but another
/// thing was `found` and consumethe next token. /// thing was `found` and consume the next token.
fn expected_found(&mut self, thing: &str, found: &str) { fn expected_found(&mut self, thing: &str, found: &str) {
self.unskip(); self.trim_errors();
if !self.after_error() {
self.skip();
self.convert_to_error(eco_format!("expected {thing}, found {found}")); self.convert_to_error(eco_format!("expected {thing}, found {found}"));
} }
self.skip();
}
/// Produce an error that the given `thing` was expected at the position /// Produce an error that the given `thing` was expected at the position
/// of the marker `m`. /// of the marker `m`.
@ -1637,26 +1636,13 @@ impl<'s> Parser<'s> {
} }
} }
/// Consume the next token and produce an error stating that it was /// Consume the next token (if any) and produce an error stating that it was
/// unexpected. /// unexpected.
fn unexpected(&mut self) { fn unexpected(&mut self) {
self.unskip(); self.trim_errors();
while self
.nodes
.last()
.map_or(false, |child| child.kind().is_error() && child.is_empty())
{
self.nodes.pop();
}
self.skip();
self.convert_to_error(eco_format!("unexpected {}", self.current.name())); self.convert_to_error(eco_format!("unexpected {}", self.current.name()));
} }
/// Whether the last node is an error.
fn after_error(&self) -> bool {
self.nodes.last().map_or(false, |child| child.kind().is_error())
}
/// Consume the next token and turn it into an error. /// Consume the next token and turn it into an error.
fn convert_to_error(&mut self, message: EcoString) { fn convert_to_error(&mut self, message: EcoString) {
let kind = self.current; let kind = self.current;
@ -1670,10 +1656,39 @@ impl<'s> Parser<'s> {
/// Adds a hint to the last node, if the last node is an error. /// Adds a hint to the last node, if the last node is an error.
fn hint(&mut self, hint: impl Into<EcoString>) { fn hint(&mut self, hint: impl Into<EcoString>) {
self.unskip(); let m = self.before_trivia();
if let Some(last) = self.nodes.last_mut() { if m.0 > 0 {
last.hint(hint); self.nodes[m.0 - 1].hint(hint);
} }
self.skip(); }
/// Get a marker after the last non-trivia node.
fn before_trivia(&self) -> Marker {
let mut i = self.nodes.len();
if self.lexer.mode() != LexMode::Markup && self.prev_end != self.current_start {
while i > 0 && self.nodes[i - 1].kind().is_trivia() {
i -= 1;
}
}
Marker(i)
}
/// Whether the last non-trivia node is an error.
fn after_error(&mut self) -> bool {
let m = self.before_trivia();
m.0 > 0 && self.nodes[m.0 - 1].kind().is_error()
}
/// Remove trailing errors with zero length.
fn trim_errors(&mut self) {
let Marker(end) = self.before_trivia();
let mut start = end;
while start > 0
&& self.nodes[start - 1].kind().is_error()
&& self.nodes[start - 1].is_empty()
{
start -= 1;
}
self.nodes.drain(start..end);
} }
} }

View File

@ -10,3 +10,11 @@
// Error: 7-9 expected identifier, found keyword `as` // Error: 7-9 expected identifier, found keyword `as`
let as = 10 let as = 10
} }
---
// Error: 2-2 expected expression
#
---
// Error: 2-2 expected expression
# hello