summaryrefslogtreecommitdiff
path: root/crates/typst-syntax/src
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2024-02-27 12:12:43 +0100
committerGitHub <noreply@github.com>2024-02-27 11:12:43 +0000
commit0aa925435628f5a6f29478e7e19ed2d4f50eabf8 (patch)
treec977b46f5f005f178393d53a3236b8629817ff38 /crates/typst-syntax/src
parent9646a132a80d11b37649b82c419833003ac7f455 (diff)
Fix bugs with parenthesized expression parsing (#3505)
Diffstat (limited to 'crates/typst-syntax/src')
-rw-r--r--crates/typst-syntax/src/parser.rs19
1 files changed, 14 insertions, 5 deletions
diff --git a/crates/typst-syntax/src/parser.rs b/crates/typst-syntax/src/parser.rs
index d37b552f..0a740b62 100644
--- a/crates/typst-syntax/src/parser.rs
+++ b/crates/typst-syntax/src/parser.rs
@@ -746,7 +746,7 @@ fn code_primary(p: &mut Parser, atomic: bool) {
SyntaxKind::LeftBrace => code_block(p),
SyntaxKind::LeftBracket => content_block(p),
- SyntaxKind::LeftParen => expr_with_paren(p),
+ SyntaxKind::LeftParen => expr_with_paren(p, atomic),
SyntaxKind::Dollar => equation(p),
SyntaxKind::Let => let_binding(p),
SyntaxKind::Set => set_rule(p),
@@ -1020,13 +1020,16 @@ fn return_stmt(p: &mut Parser) {
}
/// An expression that starts with a parenthesis.
-fn expr_with_paren(p: &mut Parser) {
+fn expr_with_paren(p: &mut Parser, atomic: bool) {
// If we've seen this position before and have a memoized result, just use
// it. See below for more explanation about this memoization.
let start = p.current_start();
- if let Some((range, end_point)) = p.memo.get(&start) {
- p.nodes.extend(p.memo_arena[range.clone()].iter().cloned());
- p.restore(end_point.clone());
+ if let Some((range, end_point)) = p.memo.get(&start).cloned() {
+ // Restore the end point first, so that it doesn't truncate our freshly
+ // pushed nodes. If the current length of `p.nodes` doesn't match what
+ // we had in the memoized run, this might otherwise happen.
+ p.restore(end_point);
+ p.nodes.extend(p.memo_arena[range].iter().cloned());
return;
}
@@ -1038,6 +1041,9 @@ fn expr_with_paren(p: &mut Parser) {
// these are the most likely things. We can handle all of those in a single
// pass.
let kind = parenthesized_or_array_or_dict(p);
+ if atomic {
+ return;
+ }
// If, however, '=>' or '=' follows, we must backtrack and reparse as either
// a parameter list or a destructuring. To be able to do that, we created a
@@ -1553,6 +1559,7 @@ impl<'s> Parser<'s> {
self.skip();
}
+ #[track_caller]
fn eat_and_get(&mut self) -> &mut SyntaxNode {
let offset = self.nodes.len();
self.save();
@@ -1622,6 +1629,7 @@ impl<'s> Parser<'s> {
m.0 > 0 && self.nodes[m.0 - 1].kind().is_error()
}
+ #[track_caller]
fn post_process(&mut self, m: Marker) -> impl Iterator<Item = &mut SyntaxNode> {
self.nodes[m.0..]
.iter_mut()
@@ -1762,6 +1770,7 @@ impl<'s> Parser<'s> {
/// Consume the given closing delimiter or produce an error for the matching
/// opening delimiter at `open`.
+ #[track_caller]
fn expect_closing_delimiter(&mut self, open: Marker, kind: SyntaxKind) {
if !self.eat_if(kind) {
self.nodes[open.0].convert_to_error("unclosed delimiter");