Fix another parser bug
This commit is contained in:
parent
8f37189d6f
commit
fa57d86ed9
@ -644,6 +644,7 @@ mod tests {
|
||||
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```"#, 16 .. 17, "", 0 .. 18);
|
||||
test("#for", 4 .. 4, "//", 0 .. 6);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -311,7 +311,7 @@ fn markup_expr(p: &mut Parser) {
|
||||
p.start_group(Group::Expr);
|
||||
let res = expr_prec(p, true, 0);
|
||||
if stmt && res.is_ok() && !p.eof() {
|
||||
p.expected_at("semicolon or line break");
|
||||
p.expected("semicolon or line break");
|
||||
}
|
||||
p.end_group();
|
||||
}
|
||||
@ -435,7 +435,7 @@ fn primary(p: &mut Parser, atomic: bool) -> ParseResult {
|
||||
|
||||
// Nothing.
|
||||
_ => {
|
||||
p.expected("expression");
|
||||
p.expected_found("expression");
|
||||
Err(ParseError)
|
||||
}
|
||||
}
|
||||
@ -538,7 +538,7 @@ fn collection(p: &mut Parser) -> (CollectionKind, usize) {
|
||||
items += 1;
|
||||
|
||||
if let Some(marker) = missing_coma.take() {
|
||||
marker.expected(p, "comma");
|
||||
p.expected_at(marker, "comma");
|
||||
}
|
||||
|
||||
if p.eof() {
|
||||
@ -651,7 +651,7 @@ fn block(p: &mut Parser) {
|
||||
while !p.eof() {
|
||||
p.start_group(Group::Expr);
|
||||
if expr(p).is_ok() && !p.eof() {
|
||||
p.expected_at("semicolon or line break");
|
||||
p.expected("semicolon or line break");
|
||||
}
|
||||
p.end_group();
|
||||
|
||||
@ -673,7 +673,7 @@ fn args(p: &mut Parser, direct: bool, brackets: bool) -> ParseResult {
|
||||
Some(NodeKind::LeftParen) => {}
|
||||
Some(NodeKind::LeftBracket) if brackets => {}
|
||||
_ => {
|
||||
p.expected("argument list");
|
||||
p.expected_found("argument list");
|
||||
return Err(ParseError);
|
||||
}
|
||||
}
|
||||
@ -726,7 +726,7 @@ fn let_expr(p: &mut Parser) -> ParseResult {
|
||||
expr(p)?;
|
||||
} else if has_params {
|
||||
// Function definitions must have a body.
|
||||
p.expected_at("body");
|
||||
p.expected("body");
|
||||
}
|
||||
|
||||
// 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 items = collection(p).1;
|
||||
if items == 0 {
|
||||
p.expected_at("import items");
|
||||
p.expected("import items");
|
||||
}
|
||||
p.end_group();
|
||||
|
||||
@ -890,7 +890,7 @@ fn ident(p: &mut Parser) -> ParseResult {
|
||||
Ok(())
|
||||
}
|
||||
_ => {
|
||||
p.expected("identifier");
|
||||
p.expected_found("identifier");
|
||||
Err(ParseError)
|
||||
}
|
||||
}
|
||||
@ -902,7 +902,7 @@ fn body(p: &mut Parser) -> ParseResult {
|
||||
Some(NodeKind::LeftBracket) => template(p),
|
||||
Some(NodeKind::LeftBrace) => block(p),
|
||||
_ => {
|
||||
p.expected_at("body");
|
||||
p.expected("body");
|
||||
return Err(ParseError);
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,6 @@ use std::mem;
|
||||
|
||||
use super::{Scanner, TokenMode, Tokens};
|
||||
use crate::syntax::{ErrorPos, Green, GreenData, GreenNode, NodeKind};
|
||||
use crate::util::EcoString;
|
||||
|
||||
/// A convenient token-based parser.
|
||||
pub struct Parser<'s> {
|
||||
@ -81,7 +80,7 @@ impl<'s> Parser<'s> {
|
||||
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 {
|
||||
let count = self
|
||||
.children
|
||||
@ -155,7 +154,7 @@ impl<'s> Parser<'s> {
|
||||
pub fn eat_expect(&mut self, t: &NodeKind) -> ParseResult {
|
||||
let eaten = self.eat_if(t);
|
||||
if !eaten {
|
||||
self.expected_at(t.as_str());
|
||||
self.expected(t.as_str());
|
||||
}
|
||||
if eaten { Ok(()) } else { Err(ParseError) }
|
||||
}
|
||||
@ -298,18 +297,22 @@ impl<'s> Parser<'s> {
|
||||
self.stray_terminator = s;
|
||||
rescan = false;
|
||||
} else if required {
|
||||
self.push_error(format_eco!("expected {}", end));
|
||||
self.expected(end.as_str());
|
||||
self.unterminated_group = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Rescan the peeked token if the mode changed.
|
||||
if rescan {
|
||||
let mut target = self.prev_end();
|
||||
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.current_start = self.tokens.index();
|
||||
self.current = self.tokens.next();
|
||||
@ -385,42 +388,40 @@ impl<'s> Parser<'s> {
|
||||
|
||||
/// Error handling.
|
||||
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.
|
||||
pub fn unexpected(&mut self) {
|
||||
match self.peek() {
|
||||
Some(found) => {
|
||||
let msg = format_eco!("unexpected {}", found);
|
||||
let error = NodeKind::Error(ErrorPos::Full, msg);
|
||||
self.perform(error, Self::eat);
|
||||
}
|
||||
None => self.push_error("unexpected end of file"),
|
||||
if let Some(found) = self.peek() {
|
||||
let msg = format_eco!("unexpected {}", found);
|
||||
let error = NodeKind::Error(ErrorPos::Full, msg);
|
||||
self.perform(error, Self::eat);
|
||||
}
|
||||
}
|
||||
|
||||
/// 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) {
|
||||
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() {
|
||||
Some(found) => {
|
||||
let msg = format_eco!("expected {}, found {}", thing, found);
|
||||
let error = NodeKind::Error(ErrorPos::Full, msg);
|
||||
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.
|
||||
@ -428,6 +429,18 @@ impl Parser<'_> {
|
||||
pub struct Marker(usize);
|
||||
|
||||
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
|
||||
/// with the given kind.
|
||||
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. `[...]`.
|
||||
|
@ -94,6 +94,9 @@
|
||||
// Error: 5 expected identifier
|
||||
#for
|
||||
|
||||
// Error: 7 expected identifier
|
||||
#for//
|
||||
|
||||
// Error: 5 expected identifier
|
||||
{for}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user