summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/parse/incremental.rs1
-rw-r--r--src/parse/mod.rs18
-rw-r--r--src/parse/parser.rs88
3 files changed, 51 insertions, 56 deletions
diff --git a/src/parse/incremental.rs b/src/parse/incremental.rs
index 7ddad3cd..c1da9698 100644
--- a/src/parse/incremental.rs
+++ b/src/parse/incremental.rs
@@ -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]
diff --git a/src/parse/mod.rs b/src/parse/mod.rs
index f666f4ad..38a08ab8 100644
--- a/src/parse/mod.rs
+++ b/src/parse/mod.rs
@@ -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);
}
}
diff --git a/src/parse/parser.rs b/src/parse/parser.rs
index 6771d007..6c73d7dd 100644
--- a/src/parse/parser.rs
+++ b/src/parse/parser.rs
@@ -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. `[...]`.