Fix another parser bug

This commit is contained in:
Laurenz 2022-01-31 13:44:58 +01:00
parent 8f37189d6f
commit fa57d86ed9
4 changed files with 54 additions and 56 deletions

View File

@ -644,6 +644,7 @@ mod tests {
test("a #let rect with (fill: eastern)\nb", 16 .. 31, " (stroke: conifer", 2 .. 34); test("a #let rect with (fill: eastern)\nb", 16 .. 31, " (stroke: conifer", 2 .. 34);
test(r#"a ```typst hello``` b"#, 16 .. 17, "", 0 .. 20); test(r#"a ```typst hello``` b"#, 16 .. 17, "", 0 .. 20);
test(r#"a ```typst hello```"#, 16 .. 17, "", 0 .. 18); test(r#"a ```typst hello```"#, 16 .. 17, "", 0 .. 18);
test("#for", 4 .. 4, "//", 0 .. 6);
} }
#[test] #[test]

View File

@ -311,7 +311,7 @@ fn markup_expr(p: &mut Parser) {
p.start_group(Group::Expr); p.start_group(Group::Expr);
let res = expr_prec(p, true, 0); let res = expr_prec(p, true, 0);
if stmt && res.is_ok() && !p.eof() { if stmt && res.is_ok() && !p.eof() {
p.expected_at("semicolon or line break"); p.expected("semicolon or line break");
} }
p.end_group(); p.end_group();
} }
@ -435,7 +435,7 @@ fn primary(p: &mut Parser, atomic: bool) -> ParseResult {
// Nothing. // Nothing.
_ => { _ => {
p.expected("expression"); p.expected_found("expression");
Err(ParseError) Err(ParseError)
} }
} }
@ -538,7 +538,7 @@ fn collection(p: &mut Parser) -> (CollectionKind, usize) {
items += 1; items += 1;
if let Some(marker) = missing_coma.take() { if let Some(marker) = missing_coma.take() {
marker.expected(p, "comma"); p.expected_at(marker, "comma");
} }
if p.eof() { if p.eof() {
@ -651,7 +651,7 @@ fn block(p: &mut Parser) {
while !p.eof() { while !p.eof() {
p.start_group(Group::Expr); p.start_group(Group::Expr);
if expr(p).is_ok() && !p.eof() { if expr(p).is_ok() && !p.eof() {
p.expected_at("semicolon or line break"); p.expected("semicolon or line break");
} }
p.end_group(); p.end_group();
@ -673,7 +673,7 @@ fn args(p: &mut Parser, direct: bool, brackets: bool) -> ParseResult {
Some(NodeKind::LeftParen) => {} Some(NodeKind::LeftParen) => {}
Some(NodeKind::LeftBracket) if brackets => {} Some(NodeKind::LeftBracket) if brackets => {}
_ => { _ => {
p.expected("argument list"); p.expected_found("argument list");
return Err(ParseError); return Err(ParseError);
} }
} }
@ -726,7 +726,7 @@ fn let_expr(p: &mut Parser) -> ParseResult {
expr(p)?; expr(p)?;
} else if has_params { } else if has_params {
// Function definitions must have a body. // Function definitions must have a body.
p.expected_at("body"); p.expected("body");
} }
// Rewrite into a closure expression if it's a function definition. // Rewrite into a closure expression if it's a function definition.
@ -831,7 +831,7 @@ fn import_expr(p: &mut Parser) -> ParseResult {
let marker = p.marker(); let marker = p.marker();
let items = collection(p).1; let items = collection(p).1;
if items == 0 { if items == 0 {
p.expected_at("import items"); p.expected("import items");
} }
p.end_group(); p.end_group();
@ -890,7 +890,7 @@ fn ident(p: &mut Parser) -> ParseResult {
Ok(()) Ok(())
} }
_ => { _ => {
p.expected("identifier"); p.expected_found("identifier");
Err(ParseError) Err(ParseError)
} }
} }
@ -902,7 +902,7 @@ fn body(p: &mut Parser) -> ParseResult {
Some(NodeKind::LeftBracket) => template(p), Some(NodeKind::LeftBracket) => template(p),
Some(NodeKind::LeftBrace) => block(p), Some(NodeKind::LeftBrace) => block(p),
_ => { _ => {
p.expected_at("body"); p.expected("body");
return Err(ParseError); return Err(ParseError);
} }
} }

View File

@ -4,7 +4,6 @@ use std::mem;
use super::{Scanner, TokenMode, Tokens}; use super::{Scanner, TokenMode, Tokens};
use crate::syntax::{ErrorPos, Green, GreenData, GreenNode, NodeKind}; use crate::syntax::{ErrorPos, Green, GreenData, GreenNode, NodeKind};
use crate::util::EcoString;
/// A convenient token-based parser. /// A convenient token-based parser.
pub struct Parser<'s> { pub struct Parser<'s> {
@ -81,7 +80,7 @@ impl<'s> Parser<'s> {
Marker(self.children.len()) Marker(self.children.len())
} }
/// Create a markup right before the trailing trivia. /// Create a marker right before the trailing trivia.
pub fn trivia_start(&self) -> Marker { pub fn trivia_start(&self) -> Marker {
let count = self let count = self
.children .children
@ -155,7 +154,7 @@ impl<'s> Parser<'s> {
pub fn eat_expect(&mut self, t: &NodeKind) -> ParseResult { pub fn eat_expect(&mut self, t: &NodeKind) -> ParseResult {
let eaten = self.eat_if(t); let eaten = self.eat_if(t);
if !eaten { if !eaten {
self.expected_at(t.as_str()); self.expected(t.as_str());
} }
if eaten { Ok(()) } else { Err(ParseError) } if eaten { Ok(()) } else { Err(ParseError) }
} }
@ -298,18 +297,22 @@ impl<'s> Parser<'s> {
self.stray_terminator = s; self.stray_terminator = s;
rescan = false; rescan = false;
} else if required { } else if required {
self.push_error(format_eco!("expected {}", end)); self.expected(end.as_str());
self.unterminated_group = true; self.unterminated_group = true;
} }
} }
// Rescan the peeked token if the mode changed. // Rescan the peeked token if the mode changed.
if rescan { if rescan {
let mut target = self.prev_end();
if group_mode == TokenMode::Code { if group_mode == TokenMode::Code {
self.children.truncate(self.trivia_start().0); let start = self.trivia_start().0;
target = self.current_start
- self.children[start ..].iter().map(Green::len).sum::<usize>();
self.children.truncate(start);
} }
self.tokens.jump(self.prev_end()); self.tokens.jump(target);
self.prev_end = self.tokens.index(); self.prev_end = self.tokens.index();
self.current_start = self.tokens.index(); self.current_start = self.tokens.index();
self.current = self.tokens.next(); self.current = self.tokens.next();
@ -385,42 +388,40 @@ impl<'s> Parser<'s> {
/// Error handling. /// Error handling.
impl Parser<'_> { impl Parser<'_> {
/// Push an error into the children list.
pub fn push_error(&mut self, msg: impl Into<EcoString>) {
let error = NodeKind::Error(ErrorPos::Full, msg.into());
let idx = self.trivia_start();
self.children.insert(idx.0, GreenData::new(error, 0).into());
}
/// Eat the current token and add an error that it is unexpected. /// Eat the current token and add an error that it is unexpected.
pub fn unexpected(&mut self) { pub fn unexpected(&mut self) {
match self.peek() { if let Some(found) = self.peek() {
Some(found) => { let msg = format_eco!("unexpected {}", found);
let msg = format_eco!("unexpected {}", found); let error = NodeKind::Error(ErrorPos::Full, msg);
let error = NodeKind::Error(ErrorPos::Full, msg); self.perform(error, Self::eat);
self.perform(error, Self::eat);
}
None => self.push_error("unexpected end of file"),
} }
} }
/// Eat the current token and add an error that it is not the expected `thing`. /// Add an error that the `thing` was expected at the end of the last
/// non-trivia token.
pub fn expected(&mut self, thing: &str) { pub fn expected(&mut self, thing: &str) {
self.expected_at(self.trivia_start(), thing);
}
/// Insert an error message that `what` was expected at the marker position.
pub fn expected_at(&mut self, marker: Marker, what: &str) {
let msg = format_eco!("expected {}", what);
let error = NodeKind::Error(ErrorPos::Full, msg);
self.children.insert(marker.0, GreenData::new(error, 0).into());
}
/// Eat the current token and add an error that it is not the expected
/// `thing`.
pub fn expected_found(&mut self, thing: &str) {
match self.peek() { match self.peek() {
Some(found) => { Some(found) => {
let msg = format_eco!("expected {}, found {}", thing, found); let msg = format_eco!("expected {}, found {}", thing, found);
let error = NodeKind::Error(ErrorPos::Full, msg); let error = NodeKind::Error(ErrorPos::Full, msg);
self.perform(error, Self::eat); self.perform(error, Self::eat);
} }
None => self.expected_at(thing), None => self.expected(thing),
} }
} }
/// Add an error that the `thing` was expected at the end of the last
/// non-trivia token.
pub fn expected_at(&mut self, thing: &str) {
self.trivia_start().expected(self, thing);
}
} }
/// A marker that indicates where a node may start. /// A marker that indicates where a node may start.
@ -428,6 +429,18 @@ impl Parser<'_> {
pub struct Marker(usize); pub struct Marker(usize);
impl Marker { impl Marker {
/// Peek at the child directly after the marker.
pub fn peek<'a>(self, p: &'a Parser) -> Option<&'a Green> {
p.children.get(self.0)
}
/// Convert the child directly after marker.
pub fn convert(self, p: &mut Parser, kind: NodeKind) {
if let Some(child) = p.children.get_mut(self.0) {
child.convert(kind);
}
}
/// Perform a subparse that wraps all children after the marker in a node /// Perform a subparse that wraps all children after the marker in a node
/// with the given kind. /// with the given kind.
pub fn perform<T, F>(self, p: &mut Parser, kind: NodeKind, f: F) -> T pub fn perform<T, F>(self, p: &mut Parser, kind: NodeKind, f: F) -> T
@ -471,25 +484,6 @@ impl Marker {
} }
} }
} }
/// Insert an error message that `what` was expected at the marker position.
pub fn expected(self, p: &mut Parser, what: &str) {
let msg = format_eco!("expected {}", what);
let error = NodeKind::Error(ErrorPos::Full, msg);
p.children.insert(self.0, GreenData::new(error, 0).into());
}
/// Peek at the child directly after the marker.
pub fn peek<'a>(self, p: &'a Parser) -> Option<&'a Green> {
p.children.get(self.0)
}
/// Convert the child directly after marker.
pub fn convert(self, p: &mut Parser, kind: NodeKind) {
if let Some(child) = p.children.get_mut(self.0) {
child.convert(kind);
}
}
} }
/// A logical group of tokens, e.g. `[...]`. /// A logical group of tokens, e.g. `[...]`.

View File

@ -94,6 +94,9 @@
// Error: 5 expected identifier // Error: 5 expected identifier
#for #for
// Error: 7 expected identifier
#for//
// Error: 5 expected identifier // Error: 5 expected identifier
{for} {for}