typst_syntax/
parser.rs

1use std::mem;
2use std::ops::{Index, IndexMut, Range};
3
4use ecow::{EcoString, eco_format};
5use rustc_hash::{FxHashMap, FxHashSet};
6use typst_utils::default_math_class;
7use unicode_math_class::MathClass;
8
9use crate::set::{SyntaxSet, syntax_set};
10use crate::{Lexer, SyntaxError, SyntaxKind, SyntaxMode, SyntaxNode, ast, set};
11
12/// Parses a source file as top-level markup.
13pub fn parse(text: &str) -> SyntaxNode {
14    let _scope = typst_timing::TimingScope::new("parse");
15    let mut p = Parser::new(text, 0, SyntaxMode::Markup);
16    markup_exprs(&mut p, true, syntax_set!(End));
17    p.finish_into(SyntaxKind::Markup)
18}
19
20/// Parses top-level code.
21pub fn parse_code(text: &str) -> SyntaxNode {
22    let _scope = typst_timing::TimingScope::new("parse code");
23    let mut p = Parser::new(text, 0, SyntaxMode::Code);
24    code_exprs(&mut p, syntax_set!(End));
25    p.finish_into(SyntaxKind::Code)
26}
27
28/// Parses top-level math.
29pub fn parse_math(text: &str) -> SyntaxNode {
30    let _scope = typst_timing::TimingScope::new("parse math");
31    let mut p = Parser::new(text, 0, SyntaxMode::Math);
32    math_exprs(&mut p, syntax_set!(End));
33    p.finish_into(SyntaxKind::Math)
34}
35
36/// Parses markup expressions until a stop condition is met.
37fn markup(p: &mut Parser, at_start: bool, wrap_trivia: bool, stop_set: SyntaxSet) {
38    let m = if wrap_trivia { p.before_trivia() } else { p.marker() };
39    markup_exprs(p, at_start, stop_set);
40    if wrap_trivia {
41        p.flush_trivia();
42    }
43    p.wrap(m, SyntaxKind::Markup);
44}
45
46/// Parses a sequence of markup expressions.
47fn markup_exprs(p: &mut Parser, mut at_start: bool, stop_set: SyntaxSet) {
48    debug_assert!(stop_set.contains(SyntaxKind::End));
49    at_start |= p.had_newline();
50    let mut nesting: usize = 0;
51    // Keep going if we're at a nested right-bracket regardless of the stop set.
52    while !p.at_set(stop_set) || (nesting > 0 && p.at(SyntaxKind::RightBracket)) {
53        markup_expr(p, at_start, &mut nesting);
54        at_start = p.had_newline();
55    }
56}
57
58/// Reparses a subsection of markup incrementally.
59pub(super) fn reparse_markup(
60    text: &str,
61    range: Range<usize>,
62    at_start: &mut bool,
63    nesting: &mut usize,
64    top_level: bool,
65) -> Option<Vec<SyntaxNode>> {
66    let mut p = Parser::new(text, range.start, SyntaxMode::Markup);
67    *at_start |= p.had_newline();
68    while !p.end() && p.current_start() < range.end {
69        // If not top-level and at a new RightBracket, stop the reparse.
70        if !top_level && *nesting == 0 && p.at(SyntaxKind::RightBracket) {
71            break;
72        }
73        markup_expr(&mut p, *at_start, nesting);
74        *at_start = p.had_newline();
75    }
76    (p.balanced && p.current_start() == range.end).then(|| p.finish())
77}
78
79/// Parses a single markup expression. This includes markup elements like text,
80/// headings, strong/emph, lists/enums, etc. This is also the entry point for
81/// parsing math equations and embedded code expressions.
82fn markup_expr(p: &mut Parser, at_start: bool, nesting: &mut usize) {
83    match p.current() {
84        SyntaxKind::LeftBracket => {
85            *nesting += 1;
86            p.convert_and_eat(SyntaxKind::Text);
87        }
88        SyntaxKind::RightBracket if *nesting > 0 => {
89            *nesting -= 1;
90            p.convert_and_eat(SyntaxKind::Text);
91        }
92        SyntaxKind::RightBracket => {
93            p.unexpected();
94            p.hint("try using a backslash escape: \\]");
95        }
96
97        SyntaxKind::Shebang => p.eat(),
98
99        SyntaxKind::Text
100        | SyntaxKind::Linebreak
101        | SyntaxKind::Escape
102        | SyntaxKind::Shorthand
103        | SyntaxKind::SmartQuote
104        | SyntaxKind::Link
105        | SyntaxKind::Label => p.eat(),
106
107        SyntaxKind::Raw => p.eat(), // Raw is handled entirely in the Lexer.
108
109        SyntaxKind::Hash => embedded_code_expr(p),
110        SyntaxKind::Star => strong(p),
111        SyntaxKind::Underscore => emph(p),
112        SyntaxKind::HeadingMarker if at_start => heading(p),
113        SyntaxKind::ListMarker if at_start => list_item(p),
114        SyntaxKind::EnumMarker if at_start => enum_item(p),
115        SyntaxKind::TermMarker if at_start => term_item(p),
116        SyntaxKind::RefMarker => reference(p),
117        SyntaxKind::Dollar => equation(p),
118
119        SyntaxKind::HeadingMarker
120        | SyntaxKind::ListMarker
121        | SyntaxKind::EnumMarker
122        | SyntaxKind::TermMarker
123        | SyntaxKind::Colon => p.convert_and_eat(SyntaxKind::Text),
124
125        _ => p.unexpected(),
126    }
127}
128
129/// Parses strong content: `*Strong*`.
130fn strong(p: &mut Parser) {
131    p.with_nl_mode(AtNewline::StopParBreak, |p| {
132        let m = p.marker();
133        p.assert(SyntaxKind::Star);
134        markup(p, false, true, syntax_set!(Star, RightBracket, End));
135        p.expect_closing_delimiter(m, SyntaxKind::Star);
136        p.wrap(m, SyntaxKind::Strong);
137    });
138}
139
140/// Parses emphasized content: `_Emphasized_`.
141fn emph(p: &mut Parser) {
142    p.with_nl_mode(AtNewline::StopParBreak, |p| {
143        let m = p.marker();
144        p.assert(SyntaxKind::Underscore);
145        markup(p, false, true, syntax_set!(Underscore, RightBracket, End));
146        p.expect_closing_delimiter(m, SyntaxKind::Underscore);
147        p.wrap(m, SyntaxKind::Emph);
148    });
149}
150
151/// Parses a section heading: `= Introduction`.
152fn heading(p: &mut Parser) {
153    p.with_nl_mode(AtNewline::Stop, |p| {
154        let m = p.marker();
155        p.assert(SyntaxKind::HeadingMarker);
156        markup(p, false, false, syntax_set!(Label, RightBracket, End));
157        p.wrap(m, SyntaxKind::Heading);
158    });
159}
160
161/// Parses an item in a bullet list: `- ...`.
162fn list_item(p: &mut Parser) {
163    p.with_nl_mode(AtNewline::RequireColumn(p.current_column()), |p| {
164        let m = p.marker();
165        p.assert(SyntaxKind::ListMarker);
166        markup(p, true, false, syntax_set!(RightBracket, End));
167        p.wrap(m, SyntaxKind::ListItem);
168    });
169}
170
171/// Parses an item in an enumeration (numbered list): `+ ...` or `1. ...`.
172fn enum_item(p: &mut Parser) {
173    p.with_nl_mode(AtNewline::RequireColumn(p.current_column()), |p| {
174        let m = p.marker();
175        p.assert(SyntaxKind::EnumMarker);
176        markup(p, true, false, syntax_set!(RightBracket, End));
177        p.wrap(m, SyntaxKind::EnumItem);
178    });
179}
180
181/// Parses an item in a term list: `/ Term: Details`.
182fn term_item(p: &mut Parser) {
183    p.with_nl_mode(AtNewline::RequireColumn(p.current_column()), |p| {
184        let m = p.marker();
185        p.with_nl_mode(AtNewline::Stop, |p| {
186            p.assert(SyntaxKind::TermMarker);
187            markup(p, false, false, syntax_set!(Colon, RightBracket, End));
188        });
189        p.expect(SyntaxKind::Colon);
190        markup(p, true, false, syntax_set!(RightBracket, End));
191        p.wrap(m, SyntaxKind::TermItem);
192    });
193}
194
195/// Parses a reference: `@target`, `@target[..]`.
196fn reference(p: &mut Parser) {
197    let m = p.marker();
198    p.assert(SyntaxKind::RefMarker);
199    if p.directly_at(SyntaxKind::LeftBracket) {
200        content_block(p);
201    }
202    p.wrap(m, SyntaxKind::Ref);
203}
204
205/// Parses a mathematical equation: `$x$`, `$ x^2 $`.
206fn equation(p: &mut Parser) {
207    let m = p.marker();
208    p.enter_modes(SyntaxMode::Math, AtNewline::Continue, |p| {
209        p.assert(SyntaxKind::Dollar);
210        math(p, syntax_set!(Dollar, End));
211        p.expect_closing_delimiter(m, SyntaxKind::Dollar);
212    });
213    p.wrap(m, SyntaxKind::Equation);
214}
215
216/// Parses the contents of a mathematical equation: `x^2 + 1`.
217fn math(p: &mut Parser, stop_set: SyntaxSet) {
218    let m = p.marker();
219    math_exprs(p, stop_set);
220    p.wrap(m, SyntaxKind::Math);
221}
222
223/// Parses a sequence of math expressions. Returns the number of expressions
224/// parsed.
225fn math_exprs(p: &mut Parser, stop_set: SyntaxSet) -> usize {
226    debug_assert!(stop_set.contains(SyntaxKind::End));
227    let mut count = 0;
228    while !p.at_set(stop_set) {
229        if p.at_set(set::MATH_EXPR) {
230            math_expr(p);
231            count += 1;
232        } else {
233            p.unexpected();
234        }
235    }
236    count
237}
238
239/// Parses a single math expression: This includes math elements like
240/// attachment, fractions, and roots, and embedded code expressions.
241fn math_expr(p: &mut Parser) {
242    math_expr_prec(p, 0, SyntaxKind::End)
243}
244
245/// Parses a math expression with at least the given precedence.
246fn math_expr_prec(p: &mut Parser, min_prec: usize, stop: SyntaxKind) {
247    let m = p.marker();
248    let mut continuable = false;
249    match p.current() {
250        SyntaxKind::Hash => embedded_code_expr(p),
251        // The lexer manages creating full FieldAccess nodes if needed.
252        SyntaxKind::MathIdent | SyntaxKind::FieldAccess => {
253            continuable = true;
254            p.eat();
255            // Parse a function call for an identifier or field access.
256            if min_prec < 3
257                && p.directly_at(SyntaxKind::MathText)
258                && p.current_text() == "("
259            {
260                math_args(p);
261                p.wrap(m, SyntaxKind::FuncCall);
262                continuable = false;
263            }
264        }
265
266        SyntaxKind::Dot
267        | SyntaxKind::Comma
268        | SyntaxKind::Semicolon
269        | SyntaxKind::RightParen => {
270            p.convert_and_eat(SyntaxKind::MathText);
271        }
272
273        SyntaxKind::Text | SyntaxKind::MathText | SyntaxKind::MathShorthand => {
274            // `a(b)/c` parses as `(a(b))/c` if `a` is continuable.
275            continuable = math_class(p.current_text()) == Some(MathClass::Alphabetic)
276                || p.current_text().chars().all(char::is_alphabetic);
277            if !maybe_delimited(p) {
278                p.eat();
279            }
280        }
281
282        SyntaxKind::Linebreak | SyntaxKind::MathAlignPoint => p.eat(),
283        SyntaxKind::Escape | SyntaxKind::Str => {
284            continuable = true;
285            p.eat();
286        }
287
288        SyntaxKind::Root => {
289            if min_prec < 3 {
290                p.eat();
291                let m2 = p.marker();
292                math_expr_prec(p, 2, stop);
293                math_unparen(p, m2);
294                p.wrap(m, SyntaxKind::MathRoot);
295            }
296        }
297
298        SyntaxKind::Prime => {
299            // Means that there is nothing to attach the prime to.
300            continuable = true;
301            while p.at(SyntaxKind::Prime) {
302                let m2 = p.marker();
303                p.eat();
304                // Eat the group until the space.
305                while p.eat_if_direct(SyntaxKind::Prime) {}
306                p.wrap(m2, SyntaxKind::MathPrimes);
307            }
308        }
309
310        _ => p.expected("expression"),
311    }
312
313    if continuable && min_prec < 3 && !p.had_trivia() && maybe_delimited(p) {
314        p.wrap(m, SyntaxKind::Math);
315    }
316
317    // Whether there were _any_ primes in the loop.
318    let mut primed = false;
319
320    while !p.end() && !p.at(stop) {
321        if p.directly_at(SyntaxKind::MathText) && p.current_text() == "!" {
322            p.eat();
323            p.wrap(m, SyntaxKind::Math);
324            continue;
325        }
326
327        let prime_marker = p.marker();
328        if p.eat_if_direct(SyntaxKind::Prime) {
329            // Eat as many primes as possible.
330            while p.eat_if_direct(SyntaxKind::Prime) {}
331            p.wrap(prime_marker, SyntaxKind::MathPrimes);
332
333            // Will not be continued, so need to wrap the prime as attachment.
334            if p.at(stop) {
335                p.wrap(m, SyntaxKind::MathAttach);
336            }
337
338            primed = true;
339            continue;
340        }
341
342        let Some((kind, stop, assoc, mut prec)) = math_op(p.current()) else {
343            // No attachments, so we need to wrap primes as attachment.
344            if primed {
345                p.wrap(m, SyntaxKind::MathAttach);
346            }
347
348            break;
349        };
350
351        if primed && kind == SyntaxKind::MathFrac {
352            p.wrap(m, SyntaxKind::MathAttach);
353        }
354
355        if prec < min_prec {
356            break;
357        }
358
359        match assoc {
360            ast::Assoc::Left => prec += 1,
361            ast::Assoc::Right => {}
362        }
363
364        if kind == SyntaxKind::MathFrac {
365            math_unparen(p, m);
366        }
367
368        p.eat();
369        let m2 = p.marker();
370        math_expr_prec(p, prec, stop);
371        math_unparen(p, m2);
372
373        if p.eat_if(SyntaxKind::Underscore) || p.eat_if(SyntaxKind::Hat) {
374            let m3 = p.marker();
375            math_expr_prec(p, prec, SyntaxKind::End);
376            math_unparen(p, m3);
377        }
378
379        p.wrap(m, kind);
380    }
381}
382
383/// Precedence and wrapper kinds for the binary math operators.
384fn math_op(kind: SyntaxKind) -> Option<(SyntaxKind, SyntaxKind, ast::Assoc, usize)> {
385    match kind {
386        SyntaxKind::Underscore => {
387            Some((SyntaxKind::MathAttach, SyntaxKind::Hat, ast::Assoc::Right, 2))
388        }
389        SyntaxKind::Hat => {
390            Some((SyntaxKind::MathAttach, SyntaxKind::Underscore, ast::Assoc::Right, 2))
391        }
392        SyntaxKind::Slash => {
393            Some((SyntaxKind::MathFrac, SyntaxKind::End, ast::Assoc::Left, 1))
394        }
395        _ => None,
396    }
397}
398
399/// Try to parse delimiters based on the current token's unicode math class.
400fn maybe_delimited(p: &mut Parser) -> bool {
401    let open = math_class(p.current_text()) == Some(MathClass::Opening);
402    if open {
403        math_delimited(p);
404    }
405    open
406}
407
408/// Parse matched delimiters in math: `[x + y]`.
409fn math_delimited(p: &mut Parser) {
410    let m = p.marker();
411    p.eat();
412    let m2 = p.marker();
413    while !p.at_set(syntax_set!(Dollar, End)) {
414        if math_class(p.current_text()) == Some(MathClass::Closing) {
415            p.wrap(m2, SyntaxKind::Math);
416            // We could be at the shorthand `|]`, which shouldn't be converted
417            // to a `Text` kind.
418            if p.at(SyntaxKind::RightParen) {
419                p.convert_and_eat(SyntaxKind::MathText);
420            } else {
421                p.eat();
422            }
423            p.wrap(m, SyntaxKind::MathDelimited);
424            return;
425        }
426
427        if p.at_set(set::MATH_EXPR) {
428            math_expr(p);
429        } else {
430            p.unexpected();
431        }
432    }
433
434    p.wrap(m, SyntaxKind::Math);
435}
436
437/// Remove one set of parentheses (if any) from a previously parsed expression
438/// by converting to non-expression SyntaxKinds.
439fn math_unparen(p: &mut Parser, m: Marker) {
440    let Some(node) = p.nodes.get_mut(m.0) else { return };
441    if node.kind() != SyntaxKind::MathDelimited {
442        return;
443    }
444
445    if let [first, .., last] = node.children_mut()
446        && first.text() == "("
447        && last.text() == ")"
448    {
449        first.convert_to_kind(SyntaxKind::LeftParen);
450        last.convert_to_kind(SyntaxKind::RightParen);
451        // Only convert if we did have regular parens.
452        node.convert_to_kind(SyntaxKind::Math);
453    }
454}
455
456/// The unicode math class of a string. Only returns `Some` if `text` has
457/// exactly one unicode character or is a math shorthand string (currently just
458/// `[|`, `||`, `|]`) and then only returns `Some` if there is a math class
459/// defined for that character.
460fn math_class(text: &str) -> Option<MathClass> {
461    match text {
462        "[|" => return Some(MathClass::Opening),
463        "|]" => return Some(MathClass::Closing),
464        "||" => return Some(MathClass::Fence),
465        _ => {}
466    }
467
468    let mut chars = text.chars();
469    chars
470        .next()
471        .filter(|_| chars.next().is_none())
472        .and_then(default_math_class)
473}
474
475/// Parse an argument list in math: `(a, b; c, d; size: #50%)`.
476fn math_args(p: &mut Parser) {
477    let m = p.marker();
478    p.convert_and_eat(SyntaxKind::LeftParen);
479
480    let mut positional = true;
481    let mut has_arrays = false;
482
483    let mut maybe_array_start = p.marker();
484    let mut seen = FxHashSet::default();
485    while !p.at_set(syntax_set!(End, Dollar, RightParen)) {
486        positional = math_arg(p, &mut seen);
487
488        match p.current() {
489            SyntaxKind::Comma => {
490                p.eat();
491                if !positional {
492                    maybe_array_start = p.marker();
493                }
494            }
495            SyntaxKind::Semicolon => {
496                if !positional {
497                    maybe_array_start = p.marker();
498                }
499
500                // Parses an array: `a, b, c;`.
501                // The semicolon merges preceding arguments separated by commas
502                // into an array argument.
503                p.wrap(maybe_array_start, SyntaxKind::Array);
504                p.eat();
505                maybe_array_start = p.marker();
506                has_arrays = true;
507            }
508            SyntaxKind::End | SyntaxKind::Dollar | SyntaxKind::RightParen => {}
509            _ => p.expected("comma or semicolon"),
510        }
511    }
512
513    // Check if we need to wrap the preceding arguments in an array.
514    if maybe_array_start != p.marker() && has_arrays && positional {
515        p.wrap(maybe_array_start, SyntaxKind::Array);
516    }
517
518    p.expect_closing_delimiter(m, SyntaxKind::RightParen);
519    p.wrap(m, SyntaxKind::Args);
520}
521
522/// Parses a single argument in a math argument list.
523///
524/// Returns whether the parsed argument was positional or not.
525fn math_arg<'s>(p: &mut Parser<'s>, seen: &mut FxHashSet<&'s str>) -> bool {
526    let m = p.marker();
527    let start = p.current_start();
528
529    if p.at(SyntaxKind::Dot) {
530        // Parses a spread argument: `..args`.
531        if let Some(spread) = p.lexer.maybe_math_spread_arg(start) {
532            p.token.node = spread;
533            p.eat();
534            let m_arg = p.marker();
535            // TODO: Refactor to combine with the other call to `math_exprs`.
536            let count =
537                math_exprs(p, syntax_set!(End, Dollar, Comma, Semicolon, RightParen));
538            if count == 0 {
539                let dots = vec![
540                    SyntaxNode::leaf(SyntaxKind::MathText, "."),
541                    SyntaxNode::leaf(SyntaxKind::MathText, "."),
542                ];
543                p[m] = SyntaxNode::inner(SyntaxKind::Math, dots);
544            } else {
545                if count > 1 {
546                    p.wrap(m_arg, SyntaxKind::Math);
547                }
548                p.wrap(m, SyntaxKind::Spread);
549            }
550            return true;
551        }
552    }
553
554    let mut positional = true;
555    if p.at_set(syntax_set!(MathText, MathIdent, Underscore)) {
556        // Parses a named argument: `thickness: #12pt`.
557        if let Some(named) = p.lexer.maybe_math_named_arg(start) {
558            p.token.node = named;
559            let text = p.current_text();
560            p.eat();
561            p.convert_and_eat(SyntaxKind::Colon);
562            if !seen.insert(text) {
563                p[m].convert_to_error(eco_format!("duplicate argument: {text}"));
564            }
565            positional = false;
566        }
567    }
568
569    // Parses a normal positional argument.
570    let arg = p.marker();
571    let count = math_exprs(p, syntax_set!(End, Dollar, Comma, Semicolon, RightParen));
572    if count == 0 {
573        // Named argument requires a value.
574        if !positional {
575            p.expected("expression");
576        }
577
578        // Flush trivia so that the new empty Math node will be wrapped _inside_
579        // any `SyntaxKind::Array` elements created in `math_args`.
580        // (And if we don't follow by wrapping in an array, it has no effect.)
581        // The difference in node layout without this would look like:
582        // Expression: `$ mat( ;) $`
583        // - Correct:   [ .., Space(" "), Array[Math[], ], Semicolon(";"), .. ]
584        // - Incorrect: [ .., Math[], Array[], Space(" "), Semicolon(";"), .. ]
585        p.flush_trivia();
586    }
587
588    // Wrap math function arguments to join adjacent math content or create an
589    // empty 'Math' node for when we have 0 args. We don't wrap when
590    // `count == 1`, since wrapping would change the type of the expression
591    // from potentially non-content to content. Ex: `$ func(#12pt) $` would
592    // change the type from size to content if wrapped.
593    if count != 1 {
594        p.wrap(arg, SyntaxKind::Math);
595    }
596
597    if !positional {
598        p.wrap(m, SyntaxKind::Named);
599    }
600    positional
601}
602
603/// Parses the contents of a code block.
604fn code(p: &mut Parser, stop_set: SyntaxSet) {
605    let m = p.marker();
606    code_exprs(p, stop_set);
607    p.wrap(m, SyntaxKind::Code);
608}
609
610/// Parses a sequence of code expressions.
611fn code_exprs(p: &mut Parser, stop_set: SyntaxSet) {
612    debug_assert!(stop_set.contains(SyntaxKind::End));
613    while !p.at_set(stop_set) {
614        p.with_nl_mode(AtNewline::ContextualContinue, |p| {
615            if !p.at_set(set::CODE_EXPR) {
616                p.unexpected();
617                return;
618            }
619            code_expr(p);
620            if !p.at_set(stop_set) && !p.eat_if(SyntaxKind::Semicolon) {
621                p.expected("semicolon or line break");
622                if p.at(SyntaxKind::Label) {
623                    p.hint("labels can only be applied in markup mode");
624                    p.hint("try wrapping your code in a markup block (`[ ]`)");
625                }
626            }
627        });
628    }
629}
630
631/// Parses an atomic code expression embedded in markup or math.
632fn embedded_code_expr(p: &mut Parser) {
633    p.enter_modes(SyntaxMode::Code, AtNewline::Stop, |p| {
634        p.assert(SyntaxKind::Hash);
635        if p.had_trivia() || p.end() {
636            p.expected("expression");
637            return;
638        }
639
640        let stmt = p.at_set(set::STMT);
641        let at = p.at_set(set::ATOMIC_CODE_EXPR);
642        code_expr_prec(p, true, 0);
643
644        // Consume error for things like `#12p` or `#"abc\"`.#
645        if !at {
646            p.unexpected();
647        }
648
649        let semi = (stmt || p.directly_at(SyntaxKind::Semicolon))
650            && p.eat_if(SyntaxKind::Semicolon);
651
652        if stmt && !semi && !p.end() && !p.at(SyntaxKind::RightBracket) {
653            p.expected("semicolon or line break");
654        }
655    });
656}
657
658/// Parses a single code expression.
659fn code_expr(p: &mut Parser) {
660    code_expr_prec(p, false, 0)
661}
662
663/// Parses a code expression with at least the given precedence.
664fn code_expr_prec(p: &mut Parser, atomic: bool, min_prec: u8) {
665    let m = p.marker();
666    if !atomic && p.at_set(set::UNARY_OP) {
667        let op = ast::UnOp::from_kind(p.current()).unwrap();
668        p.eat();
669        code_expr_prec(p, atomic, op.precedence());
670        p.wrap(m, SyntaxKind::Unary);
671    } else {
672        code_primary(p, atomic);
673    }
674
675    loop {
676        if p.directly_at(SyntaxKind::LeftParen) || p.directly_at(SyntaxKind::LeftBracket)
677        {
678            args(p);
679            p.wrap(m, SyntaxKind::FuncCall);
680            continue;
681        }
682
683        let at_field_or_method = p.directly_at(SyntaxKind::Dot)
684            && p.lexer.clone().next().0 == SyntaxKind::Ident;
685
686        if atomic && !at_field_or_method {
687            break;
688        }
689
690        if p.eat_if(SyntaxKind::Dot) {
691            p.expect(SyntaxKind::Ident);
692            p.wrap(m, SyntaxKind::FieldAccess);
693            continue;
694        }
695
696        let binop = if p.at_set(set::BINARY_OP) {
697            ast::BinOp::from_kind(p.current())
698        } else if min_prec <= ast::BinOp::NotIn.precedence() && p.eat_if(SyntaxKind::Not)
699        {
700            if p.at(SyntaxKind::In) {
701                Some(ast::BinOp::NotIn)
702            } else {
703                p.expected("keyword `in`");
704                break;
705            }
706        } else {
707            None
708        };
709
710        if let Some(op) = binop {
711            let mut prec = op.precedence();
712            if prec < min_prec {
713                break;
714            }
715
716            match op.assoc() {
717                ast::Assoc::Left => prec += 1,
718                ast::Assoc::Right => {}
719            }
720
721            p.eat();
722            code_expr_prec(p, false, prec);
723            p.wrap(m, SyntaxKind::Binary);
724            continue;
725        }
726
727        break;
728    }
729}
730
731/// Parses an primary in a code expression. These are the atoms that unary and
732/// binary operations, functions calls, and field accesses start with / are
733/// composed of.
734fn code_primary(p: &mut Parser, atomic: bool) {
735    let m = p.marker();
736    match p.current() {
737        SyntaxKind::Ident => {
738            p.eat();
739            if !atomic && p.at(SyntaxKind::Arrow) {
740                p.wrap(m, SyntaxKind::Params);
741                p.assert(SyntaxKind::Arrow);
742                code_expr(p);
743                p.wrap(m, SyntaxKind::Closure);
744            }
745        }
746        SyntaxKind::Underscore if !atomic => {
747            p.eat();
748            if p.at(SyntaxKind::Arrow) {
749                p.wrap(m, SyntaxKind::Params);
750                p.eat();
751                code_expr(p);
752                p.wrap(m, SyntaxKind::Closure);
753            } else if p.eat_if(SyntaxKind::Eq) {
754                code_expr(p);
755                p.wrap(m, SyntaxKind::DestructAssignment);
756            } else {
757                p[m].expected("expression");
758            }
759        }
760
761        SyntaxKind::LeftBrace => code_block(p),
762        SyntaxKind::LeftBracket => content_block(p),
763        SyntaxKind::LeftParen => expr_with_paren(p, atomic),
764        SyntaxKind::Dollar => equation(p),
765        SyntaxKind::Let => let_binding(p),
766        SyntaxKind::Set => set_rule(p),
767        SyntaxKind::Show => show_rule(p),
768        SyntaxKind::Context => contextual(p, atomic),
769        SyntaxKind::If => conditional(p),
770        SyntaxKind::While => while_loop(p),
771        SyntaxKind::For => for_loop(p),
772        SyntaxKind::Import => module_import(p),
773        SyntaxKind::Include => module_include(p),
774        SyntaxKind::Break => break_stmt(p),
775        SyntaxKind::Continue => continue_stmt(p),
776        SyntaxKind::Return => return_stmt(p),
777
778        SyntaxKind::Raw => p.eat(), // Raw is handled entirely in the Lexer.
779
780        SyntaxKind::None
781        | SyntaxKind::Auto
782        | SyntaxKind::Int
783        | SyntaxKind::Float
784        | SyntaxKind::Bool
785        | SyntaxKind::Numeric
786        | SyntaxKind::Str
787        | SyntaxKind::Label => p.eat(),
788
789        _ => p.expected("expression"),
790    }
791}
792
793/// Reparses a full content or code block.
794pub(super) fn reparse_block(text: &str, range: Range<usize>) -> Option<SyntaxNode> {
795    let mut p = Parser::new(text, range.start, SyntaxMode::Code);
796    assert!(p.at(SyntaxKind::LeftBracket) || p.at(SyntaxKind::LeftBrace));
797    block(&mut p);
798    (p.balanced && p.prev_end() == range.end)
799        .then(|| p.finish().into_iter().next().unwrap())
800}
801
802/// Parses a content or code block.
803fn block(p: &mut Parser) {
804    match p.current() {
805        SyntaxKind::LeftBracket => content_block(p),
806        SyntaxKind::LeftBrace => code_block(p),
807        _ => p.expected("block"),
808    }
809}
810
811/// Parses a code block: `{ let x = 1; x + 2 }`.
812fn code_block(p: &mut Parser) {
813    let m = p.marker();
814    p.enter_modes(SyntaxMode::Code, AtNewline::Continue, |p| {
815        p.assert(SyntaxKind::LeftBrace);
816        code(p, syntax_set!(RightBrace, RightBracket, RightParen, End));
817        p.expect_closing_delimiter(m, SyntaxKind::RightBrace);
818    });
819    p.wrap(m, SyntaxKind::CodeBlock);
820}
821
822/// Parses a content block: `[*Hi* there!]`.
823fn content_block(p: &mut Parser) {
824    let m = p.marker();
825    p.enter_modes(SyntaxMode::Markup, AtNewline::Continue, |p| {
826        p.assert(SyntaxKind::LeftBracket);
827        markup(p, true, true, syntax_set!(RightBracket, End));
828        p.expect_closing_delimiter(m, SyntaxKind::RightBracket);
829    });
830    p.wrap(m, SyntaxKind::ContentBlock);
831}
832
833/// Parses a let binding: `let x = 1`.
834fn let_binding(p: &mut Parser) {
835    let m = p.marker();
836    p.assert(SyntaxKind::Let);
837
838    let m2 = p.marker();
839    let mut closure = false;
840    let mut other = false;
841
842    if p.eat_if(SyntaxKind::Ident) {
843        if p.directly_at(SyntaxKind::LeftParen) {
844            params(p);
845            closure = true;
846        }
847    } else {
848        pattern(p, false, &mut FxHashSet::default(), None);
849        other = true;
850    }
851
852    let f = if closure || other { Parser::expect } else { Parser::eat_if };
853    if f(p, SyntaxKind::Eq) {
854        code_expr(p);
855    }
856
857    if closure {
858        p.wrap(m2, SyntaxKind::Closure);
859    }
860
861    p.wrap(m, SyntaxKind::LetBinding);
862}
863
864/// Parses a set rule: `set text(...)`.
865fn set_rule(p: &mut Parser) {
866    let m = p.marker();
867    p.assert(SyntaxKind::Set);
868
869    let m2 = p.marker();
870    p.expect(SyntaxKind::Ident);
871    while p.eat_if(SyntaxKind::Dot) {
872        p.expect(SyntaxKind::Ident);
873        p.wrap(m2, SyntaxKind::FieldAccess);
874    }
875
876    args(p);
877    if p.eat_if(SyntaxKind::If) {
878        code_expr(p);
879    }
880    p.wrap(m, SyntaxKind::SetRule);
881}
882
883/// Parses a show rule: `show heading: it => emph(it.body)`.
884fn show_rule(p: &mut Parser) {
885    let m = p.marker();
886    p.assert(SyntaxKind::Show);
887    let m2 = p.before_trivia();
888
889    if !p.at(SyntaxKind::Colon) {
890        code_expr(p);
891    }
892
893    if p.eat_if(SyntaxKind::Colon) {
894        code_expr(p);
895    } else {
896        p.expected_at(m2, "colon");
897    }
898
899    p.wrap(m, SyntaxKind::ShowRule);
900}
901
902/// Parses a contextual expression: `context text.lang`.
903fn contextual(p: &mut Parser, atomic: bool) {
904    let m = p.marker();
905    p.assert(SyntaxKind::Context);
906    code_expr_prec(p, atomic, 0);
907    p.wrap(m, SyntaxKind::Contextual);
908}
909
910/// Parses an if-else conditional: `if x { y } else { z }`.
911fn conditional(p: &mut Parser) {
912    let m = p.marker();
913    p.assert(SyntaxKind::If);
914    code_expr(p);
915    block(p);
916    if p.eat_if(SyntaxKind::Else) {
917        if p.at(SyntaxKind::If) {
918            conditional(p);
919        } else {
920            block(p);
921        }
922    }
923    p.wrap(m, SyntaxKind::Conditional);
924}
925
926/// Parses a while loop: `while x { y }`.
927fn while_loop(p: &mut Parser) {
928    let m = p.marker();
929    p.assert(SyntaxKind::While);
930    code_expr(p);
931    block(p);
932    p.wrap(m, SyntaxKind::WhileLoop);
933}
934
935/// Parses a for loop: `for x in y { z }`.
936fn for_loop(p: &mut Parser) {
937    let m = p.marker();
938    p.assert(SyntaxKind::For);
939
940    let mut seen = FxHashSet::default();
941    pattern(p, false, &mut seen, None);
942
943    if p.at(SyntaxKind::Comma) {
944        let node = p.eat_and_get();
945        node.unexpected();
946        node.hint("destructuring patterns must be wrapped in parentheses");
947        if p.at_set(set::PATTERN) {
948            pattern(p, false, &mut seen, None);
949        }
950    }
951
952    p.expect(SyntaxKind::In);
953    code_expr(p);
954    block(p);
955    p.wrap(m, SyntaxKind::ForLoop);
956}
957
958/// Parses a module import: `import "utils.typ": a, b, c`.
959fn module_import(p: &mut Parser) {
960    let m = p.marker();
961    p.assert(SyntaxKind::Import);
962    code_expr(p);
963    if p.eat_if(SyntaxKind::As) {
964        // Allow renaming a full module import.
965        // If items are included, both the full module and the items are
966        // imported at the same time.
967        p.expect(SyntaxKind::Ident);
968    }
969
970    if p.eat_if(SyntaxKind::Colon) {
971        if p.at(SyntaxKind::LeftParen) {
972            p.with_nl_mode(AtNewline::Continue, |p| {
973                let m2 = p.marker();
974                p.assert(SyntaxKind::LeftParen);
975
976                import_items(p);
977
978                p.expect_closing_delimiter(m2, SyntaxKind::RightParen);
979            });
980        } else if !p.eat_if(SyntaxKind::Star) {
981            import_items(p);
982        }
983    }
984
985    p.wrap(m, SyntaxKind::ModuleImport);
986}
987
988/// Parses items to import from a module: `a, b, c`.
989fn import_items(p: &mut Parser) {
990    let m = p.marker();
991    while !p.current().is_terminator() {
992        let item_marker = p.marker();
993        if !p.eat_if(SyntaxKind::Ident) {
994            p.unexpected();
995        }
996
997        // Nested import path: `a.b.c`
998        while p.eat_if(SyntaxKind::Dot) {
999            p.expect(SyntaxKind::Ident);
1000        }
1001
1002        p.wrap(item_marker, SyntaxKind::ImportItemPath);
1003
1004        // Rename imported item.
1005        if p.eat_if(SyntaxKind::As) {
1006            p.expect(SyntaxKind::Ident);
1007            p.wrap(item_marker, SyntaxKind::RenamedImportItem);
1008        }
1009
1010        if !p.current().is_terminator() {
1011            p.expect(SyntaxKind::Comma);
1012        }
1013    }
1014
1015    p.wrap(m, SyntaxKind::ImportItems);
1016}
1017
1018/// Parses a module include: `include "chapter1.typ"`.
1019fn module_include(p: &mut Parser) {
1020    let m = p.marker();
1021    p.assert(SyntaxKind::Include);
1022    code_expr(p);
1023    p.wrap(m, SyntaxKind::ModuleInclude);
1024}
1025
1026/// Parses a break from a loop: `break`.
1027fn break_stmt(p: &mut Parser) {
1028    let m = p.marker();
1029    p.assert(SyntaxKind::Break);
1030    p.wrap(m, SyntaxKind::LoopBreak);
1031}
1032
1033/// Parses a continue in a loop: `continue`.
1034fn continue_stmt(p: &mut Parser) {
1035    let m = p.marker();
1036    p.assert(SyntaxKind::Continue);
1037    p.wrap(m, SyntaxKind::LoopContinue);
1038}
1039
1040/// Parses a return from a function: `return`, `return x + 1`.
1041fn return_stmt(p: &mut Parser) {
1042    let m = p.marker();
1043    p.assert(SyntaxKind::Return);
1044    if p.at_set(set::CODE_EXPR) {
1045        code_expr(p);
1046    }
1047    p.wrap(m, SyntaxKind::FuncReturn);
1048}
1049
1050/// An expression that starts with a parenthesis.
1051fn expr_with_paren(p: &mut Parser, atomic: bool) {
1052    if atomic {
1053        // Atomic expressions aren't modified by operators that follow them, so
1054        // our first guess of array/dict will be correct.
1055        parenthesized_or_array_or_dict(p);
1056        return;
1057    }
1058
1059    // If we've seen this position before and have a memoized result, restore it
1060    // and return. Otherwise, get a key to this position and a checkpoint to
1061    // restart from in case we make a wrong prediction.
1062    let Some((memo_key, checkpoint)) = p.restore_memo_or_checkpoint() else { return };
1063    // The node length from when we restored.
1064    let prev_len = checkpoint.node_len;
1065
1066    // When we reach a '(', we can't be sure what it is. First, we attempt to
1067    // parse as a simple parenthesized expression, array, or dictionary as
1068    // these are the most likely things. We can handle all of those in a single
1069    // pass.
1070    let kind = parenthesized_or_array_or_dict(p);
1071
1072    // If, however, '=>' or '=' follows, we must backtrack and reparse as either
1073    // a parameter list or a destructuring. To be able to do that, we created a
1074    // parser checkpoint before our speculative parse, which we can restore.
1075    //
1076    // However, naive backtracking has a fatal flaw: It can lead to exponential
1077    // parsing time if we are constantly getting things wrong in a nested
1078    // scenario. The particular failure case for parameter parsing is the
1079    // following: `(x: (x: (x) => y) => y) => y`
1080    //
1081    // Such a structure will reparse over and over again recursively, leading to
1082    // a running time of O(2^n) for nesting depth n. To prevent this, we perform
1083    // a simple trick: When we have done the mistake of picking the wrong path
1084    // once and have subsequently parsed correctly, we save the result of that
1085    // correct parsing in the `p.memo` map. When we reach the same position
1086    // again, we can then just restore this result. In this way, no
1087    // parenthesized expression is parsed more than twice, leading to a worst
1088    // case running time of O(2n).
1089    if p.at(SyntaxKind::Arrow) {
1090        p.restore(checkpoint);
1091        let m = p.marker();
1092        params(p);
1093        if !p.expect(SyntaxKind::Arrow) {
1094            return;
1095        }
1096        code_expr(p);
1097        p.wrap(m, SyntaxKind::Closure);
1098    } else if p.at(SyntaxKind::Eq) && kind != SyntaxKind::Parenthesized {
1099        p.restore(checkpoint);
1100        let m = p.marker();
1101        destructuring_or_parenthesized(p, true, &mut FxHashSet::default());
1102        if !p.expect(SyntaxKind::Eq) {
1103            return;
1104        }
1105        code_expr(p);
1106        p.wrap(m, SyntaxKind::DestructAssignment);
1107    } else {
1108        return;
1109    }
1110
1111    // Memoize result if we backtracked.
1112    p.memoize_parsed_nodes(memo_key, prev_len);
1113}
1114
1115/// Parses either
1116/// - a parenthesized expression: `(1 + 2)`, or
1117/// - an array: `(1, "hi", 12cm)`, or
1118/// - a dictionary: `(thickness: 3pt, dash: "solid")`.
1119fn parenthesized_or_array_or_dict(p: &mut Parser) -> SyntaxKind {
1120    let mut state = GroupState {
1121        count: 0,
1122        maybe_just_parens: true,
1123        kind: None,
1124        seen: FxHashSet::default(),
1125    };
1126
1127    // An edge case with parens is whether we can interpret a leading spread
1128    // expression as a dictionary, e.g. if we want `(..dict1, ..dict2)` to join
1129    // the two dicts.
1130    //
1131    // The issue is that we decide on the type of the parenthesized expression
1132    // here in the parser by the `SyntaxKind` we wrap with, instead of in eval
1133    // based on the type of the spread item.
1134    //
1135    // The current fix is that we allow a leading colon to force the
1136    // parenthesized value into a dict:
1137    // - `(..arr1, ..arr2)` is wrapped as an `Array`.
1138    // - `(: ..dict1, ..dict2)` is wrapped as a `Dict`.
1139    //
1140    // This does allow some unexpected expressions, such as `(: key: val)`, but
1141    // it's currently intentional.
1142    let m = p.marker();
1143    p.with_nl_mode(AtNewline::Continue, |p| {
1144        p.assert(SyntaxKind::LeftParen);
1145        if p.eat_if(SyntaxKind::Colon) {
1146            state.kind = Some(SyntaxKind::Dict);
1147        }
1148
1149        while !p.current().is_terminator() {
1150            if !p.at_set(set::ARRAY_OR_DICT_ITEM) {
1151                p.unexpected();
1152                continue;
1153            }
1154
1155            array_or_dict_item(p, &mut state);
1156            state.count += 1;
1157
1158            if !p.current().is_terminator() && p.expect(SyntaxKind::Comma) {
1159                state.maybe_just_parens = false;
1160            }
1161        }
1162
1163        p.expect_closing_delimiter(m, SyntaxKind::RightParen);
1164    });
1165
1166    let kind = if state.maybe_just_parens && state.count == 1 {
1167        SyntaxKind::Parenthesized
1168    } else {
1169        state.kind.unwrap_or(SyntaxKind::Array)
1170    };
1171
1172    p.wrap(m, kind);
1173    kind
1174}
1175
1176/// State for array/dictionary parsing.
1177struct GroupState {
1178    count: usize,
1179    /// Whether this is just a single expression in parens: `(a)`. Single
1180    /// element arrays require an explicit comma: `(a,)`, unless we're
1181    /// spreading: `(..a)`.
1182    maybe_just_parens: bool,
1183    /// The `SyntaxKind` to wrap as (if we've figured it out yet).
1184    kind: Option<SyntaxKind>,
1185    /// Store named arguments so we can give an error if they're repeated.
1186    seen: FxHashSet<EcoString>,
1187}
1188
1189/// Parses a single item in an array or dictionary.
1190fn array_or_dict_item(p: &mut Parser, state: &mut GroupState) {
1191    let m = p.marker();
1192
1193    if p.eat_if(SyntaxKind::Dots) {
1194        // Parses a spread item: `..item`.
1195        code_expr(p);
1196        p.wrap(m, SyntaxKind::Spread);
1197        state.maybe_just_parens = false;
1198        return;
1199    }
1200
1201    code_expr(p);
1202
1203    if p.eat_if(SyntaxKind::Colon) {
1204        // Parses a named/keyed pair: `name: item` or `"key": item`.
1205        code_expr(p);
1206
1207        let node = &mut p[m];
1208        let pair_kind = match node.kind() {
1209            SyntaxKind::Ident => SyntaxKind::Named,
1210            _ => SyntaxKind::Keyed,
1211        };
1212
1213        if let Some(key) = match node.cast::<ast::Expr>() {
1214            Some(ast::Expr::Ident(ident)) => Some(ident.get().clone()),
1215            Some(ast::Expr::Str(s)) => Some(s.get()),
1216            _ => None,
1217        } && !state.seen.insert(key.clone())
1218        {
1219            node.convert_to_error(eco_format!("duplicate key: {key}"));
1220        }
1221
1222        p.wrap(m, pair_kind);
1223        state.maybe_just_parens = false;
1224
1225        if state.kind == Some(SyntaxKind::Array) {
1226            p[m].expected("expression");
1227        } else {
1228            state.kind = Some(SyntaxKind::Dict);
1229        }
1230    } else {
1231        // Parses a positional item.
1232        if state.kind == Some(SyntaxKind::Dict) {
1233            p[m].expected("named or keyed pair");
1234        } else {
1235            state.kind = Some(SyntaxKind::Array)
1236        }
1237    }
1238}
1239
1240/// Parses a function call's argument list: `(12pt, y)`.
1241fn args(p: &mut Parser) {
1242    if !p.directly_at(SyntaxKind::LeftParen) && !p.directly_at(SyntaxKind::LeftBracket) {
1243        p.expected("argument list");
1244        if p.at(SyntaxKind::LeftParen) || p.at(SyntaxKind::LeftBracket) {
1245            p.hint("there may not be any spaces before the argument list");
1246        }
1247    }
1248
1249    let m = p.marker();
1250    if p.at(SyntaxKind::LeftParen) {
1251        let m2 = p.marker();
1252        p.with_nl_mode(AtNewline::Continue, |p| {
1253            p.assert(SyntaxKind::LeftParen);
1254
1255            let mut seen = FxHashSet::default();
1256            while !p.current().is_terminator() {
1257                if !p.at_set(set::ARG) {
1258                    p.unexpected();
1259                    continue;
1260                }
1261
1262                arg(p, &mut seen);
1263
1264                if !p.current().is_terminator() {
1265                    p.expect(SyntaxKind::Comma);
1266                }
1267            }
1268
1269            p.expect_closing_delimiter(m2, SyntaxKind::RightParen);
1270        });
1271    }
1272
1273    while p.directly_at(SyntaxKind::LeftBracket) {
1274        content_block(p);
1275    }
1276
1277    p.wrap(m, SyntaxKind::Args);
1278}
1279
1280/// Parses a single argument in an argument list.
1281fn arg<'s>(p: &mut Parser<'s>, seen: &mut FxHashSet<&'s str>) {
1282    let m = p.marker();
1283
1284    // Parses a spread argument: `..args`.
1285    if p.eat_if(SyntaxKind::Dots) {
1286        code_expr(p);
1287        p.wrap(m, SyntaxKind::Spread);
1288        return;
1289    }
1290
1291    // Parses a normal positional argument or an argument name.
1292    let was_at_expr = p.at_set(set::CODE_EXPR);
1293    let text = p.current_text();
1294    code_expr(p);
1295
1296    // Parses a named argument: `thickness: 12pt`.
1297    if p.eat_if(SyntaxKind::Colon) {
1298        // Recover from bad argument name.
1299        if was_at_expr {
1300            if p[m].kind() != SyntaxKind::Ident {
1301                p[m].expected("identifier");
1302            } else if !seen.insert(text) {
1303                p[m].convert_to_error(eco_format!("duplicate argument: {text}"));
1304            }
1305        }
1306
1307        code_expr(p);
1308        p.wrap(m, SyntaxKind::Named);
1309    }
1310}
1311
1312/// Parses a closure's parameters: `(x, y)`.
1313fn params(p: &mut Parser) {
1314    let m = p.marker();
1315    p.with_nl_mode(AtNewline::Continue, |p| {
1316        p.assert(SyntaxKind::LeftParen);
1317
1318        let mut seen = FxHashSet::default();
1319        let mut sink = false;
1320
1321        while !p.current().is_terminator() {
1322            if !p.at_set(set::PARAM) {
1323                p.unexpected();
1324                continue;
1325            }
1326
1327            param(p, &mut seen, &mut sink);
1328
1329            if !p.current().is_terminator() {
1330                p.expect(SyntaxKind::Comma);
1331            }
1332        }
1333
1334        p.expect_closing_delimiter(m, SyntaxKind::RightParen);
1335    });
1336    p.wrap(m, SyntaxKind::Params);
1337}
1338
1339/// Parses a single parameter in a parameter list.
1340fn param<'s>(p: &mut Parser<'s>, seen: &mut FxHashSet<&'s str>, sink: &mut bool) {
1341    let m = p.marker();
1342
1343    // Parses argument sink: `..sink`.
1344    if p.eat_if(SyntaxKind::Dots) {
1345        if p.at_set(set::PATTERN_LEAF) {
1346            pattern_leaf(p, false, seen, Some("parameter"));
1347        }
1348        p.wrap(m, SyntaxKind::Spread);
1349        if mem::replace(sink, true) {
1350            p[m].convert_to_error("only one argument sink is allowed");
1351        }
1352        return;
1353    }
1354
1355    // Parses a normal positional parameter or a parameter name.
1356    let was_at_pat = p.at_set(set::PATTERN);
1357    pattern(p, false, seen, Some("parameter"));
1358
1359    // Parses a named parameter: `thickness: 12pt`.
1360    if p.eat_if(SyntaxKind::Colon) {
1361        // Recover from bad parameter name.
1362        if was_at_pat && p[m].kind() != SyntaxKind::Ident {
1363            p[m].expected("identifier");
1364        }
1365
1366        code_expr(p);
1367        p.wrap(m, SyntaxKind::Named);
1368    }
1369}
1370
1371/// Parses a binding or reassignment pattern.
1372fn pattern<'s>(
1373    p: &mut Parser<'s>,
1374    reassignment: bool,
1375    seen: &mut FxHashSet<&'s str>,
1376    dupe: Option<&'s str>,
1377) {
1378    match p.current() {
1379        SyntaxKind::Underscore => p.eat(),
1380        SyntaxKind::LeftParen => destructuring_or_parenthesized(p, reassignment, seen),
1381        _ => pattern_leaf(p, reassignment, seen, dupe),
1382    }
1383}
1384
1385/// Parses a destructuring pattern or just a parenthesized pattern.
1386fn destructuring_or_parenthesized<'s>(
1387    p: &mut Parser<'s>,
1388    reassignment: bool,
1389    seen: &mut FxHashSet<&'s str>,
1390) {
1391    let mut sink = false;
1392    let mut count = 0;
1393    let mut maybe_just_parens = true;
1394
1395    let m = p.marker();
1396    p.with_nl_mode(AtNewline::Continue, |p| {
1397        p.assert(SyntaxKind::LeftParen);
1398
1399        while !p.current().is_terminator() {
1400            if !p.at_set(set::DESTRUCTURING_ITEM) {
1401                p.unexpected();
1402                continue;
1403            }
1404
1405            destructuring_item(p, reassignment, seen, &mut maybe_just_parens, &mut sink);
1406            count += 1;
1407
1408            if !p.current().is_terminator() && p.expect(SyntaxKind::Comma) {
1409                maybe_just_parens = false;
1410            }
1411        }
1412
1413        p.expect_closing_delimiter(m, SyntaxKind::RightParen);
1414    });
1415
1416    if maybe_just_parens && count == 1 && !sink {
1417        p.wrap(m, SyntaxKind::Parenthesized);
1418    } else {
1419        p.wrap(m, SyntaxKind::Destructuring);
1420    }
1421}
1422
1423/// Parses an item in a destructuring pattern.
1424fn destructuring_item<'s>(
1425    p: &mut Parser<'s>,
1426    reassignment: bool,
1427    seen: &mut FxHashSet<&'s str>,
1428    maybe_just_parens: &mut bool,
1429    sink: &mut bool,
1430) {
1431    let m = p.marker();
1432
1433    // Parse destructuring sink: `..rest`.
1434    if p.eat_if(SyntaxKind::Dots) {
1435        if p.at_set(set::PATTERN_LEAF) {
1436            pattern_leaf(p, reassignment, seen, None);
1437        }
1438        p.wrap(m, SyntaxKind::Spread);
1439        if mem::replace(sink, true) {
1440            p[m].convert_to_error("only one destructuring sink is allowed");
1441        }
1442        return;
1443    }
1444
1445    // Parse a normal positional pattern or a destructuring key.
1446    let was_at_pat = p.at_set(set::PATTERN);
1447
1448    // We must use a full checkpoint here (can't just clone the lexer) because
1449    // there may be trivia between the identifier and the colon we need to skip.
1450    let checkpoint = p.checkpoint();
1451    if !(p.eat_if(SyntaxKind::Ident) && p.at(SyntaxKind::Colon)) {
1452        p.restore(checkpoint);
1453        pattern(p, reassignment, seen, None);
1454    }
1455
1456    // Parse named destructuring item.
1457    if p.eat_if(SyntaxKind::Colon) {
1458        // Recover from bad named destructuring.
1459        if was_at_pat && p[m].kind() != SyntaxKind::Ident {
1460            p[m].expected("identifier");
1461        }
1462
1463        pattern(p, reassignment, seen, None);
1464        p.wrap(m, SyntaxKind::Named);
1465        *maybe_just_parens = false;
1466    }
1467}
1468
1469/// Parses a leaf in a pattern - either an identifier or an expression
1470/// depending on whether it's a binding or reassignment pattern.
1471fn pattern_leaf<'s>(
1472    p: &mut Parser<'s>,
1473    reassignment: bool,
1474    seen: &mut FxHashSet<&'s str>,
1475    dupe: Option<&'s str>,
1476) {
1477    if p.current().is_keyword() {
1478        p.eat_and_get().expected("pattern");
1479        return;
1480    } else if !p.at_set(set::PATTERN_LEAF) {
1481        p.expected("pattern");
1482        return;
1483    }
1484
1485    let m = p.marker();
1486    let text = p.current_text();
1487
1488    // We parse an atomic expression even though we only want an identifier for
1489    // better error recovery. We can mark the whole expression as unexpected
1490    // instead of going through its pieces one by one.
1491    code_expr_prec(p, true, 0);
1492
1493    if !reassignment {
1494        let node = &mut p[m];
1495        if node.kind() == SyntaxKind::Ident {
1496            if !seen.insert(text) {
1497                node.convert_to_error(eco_format!(
1498                    "duplicate {}: {text}",
1499                    dupe.unwrap_or("binding"),
1500                ));
1501            }
1502        } else {
1503            node.expected("pattern");
1504        }
1505    }
1506}
1507
1508/// Manages parsing a stream of tokens into a tree of [`SyntaxNode`]s.
1509///
1510/// The implementation presents an interface that investigates a current `token`
1511/// with a [`SyntaxKind`] and can take one of the following actions:
1512///
1513/// 1. Eat a token: push `token` onto the `nodes` vector as a [leaf
1514///    node](`SyntaxNode::leaf`) and prepare a new `token` by calling into the
1515///    lexer.
1516/// 2. Wrap nodes from a marker to the end of `nodes` (excluding `token` and any
1517///    attached trivia) into an [inner node](`SyntaxNode::inner`) of a specific
1518///    `SyntaxKind`.
1519/// 3. Produce or convert nodes into an [error node](`SyntaxNode::error`) when
1520///    something expected is missing or something unexpected is found.
1521///
1522/// Overall the parser produces a nested tree of SyntaxNodes as a "_Concrete_
1523/// Syntax Tree." The raw Concrete Syntax Tree should contain the entire source
1524/// text, and is used as-is for e.g. syntax highlighting and IDE features. In
1525/// `ast.rs` the CST is interpreted as a lazy view over an "_Abstract_ Syntax
1526/// Tree." The AST module skips over irrelevant tokens -- whitespace, comments,
1527/// code parens, commas in function args, etc. -- as it iterates through the
1528/// tree.
1529///
1530/// ### Modes
1531///
1532/// The parser manages the transitions between the three modes of Typst through
1533/// [syntax modes](`SyntaxMode`) and [newline modes](`AtNewline`).
1534///
1535/// The syntax modes map to the three Typst modes and are stored in the lexer,
1536/// changing which `SyntaxKind`s it will generate.
1537///
1538/// The newline mode is used to determine whether a newline should end the
1539/// current expression. If so, the parser temporarily changes `token`'s kind to
1540/// a fake [`SyntaxKind::End`]. When the parser exits the mode the original
1541/// `SyntaxKind` is restored.
1542struct Parser<'s> {
1543    /// The source text shared with the lexer.
1544    text: &'s str,
1545    /// A lexer over the source text with multiple modes. Defines the boundaries
1546    /// of tokens and determines their [`SyntaxKind`]. Contains the [`SyntaxMode`]
1547    /// defining our current Typst mode.
1548    lexer: Lexer<'s>,
1549    /// The newline mode: whether to insert a temporary end at newlines.
1550    nl_mode: AtNewline,
1551    /// The current token under inspection, not yet present in `nodes`. This
1552    /// acts like a single item of lookahead for the parser.
1553    ///
1554    /// When wrapping, this is _not_ included in the wrapped nodes.
1555    token: Token,
1556    /// Whether the parser has the expected set of open/close delimiters. This
1557    /// only ever transitions from `true` to `false`.
1558    balanced: bool,
1559    /// Nodes representing the concrete syntax tree of previously parsed text.
1560    /// In Code and Math, includes previously parsed trivia, but not `token`.
1561    nodes: Vec<SyntaxNode>,
1562    /// Parser checkpoints for a given text index. Used for efficient parser
1563    /// backtracking similar to packrat parsing. See comments above in
1564    /// [`expr_with_paren`].
1565    memo: MemoArena,
1566}
1567
1568/// A single token returned from the lexer with a cached [`SyntaxKind`] and a
1569/// record of preceding trivia.
1570#[derive(Debug, Clone)]
1571struct Token {
1572    /// The [`SyntaxKind`] of the current token.
1573    kind: SyntaxKind,
1574    /// The [`SyntaxNode`] of the current token, ready to be eaten and pushed
1575    /// onto the end of `nodes`.
1576    node: SyntaxNode,
1577    /// The number of preceding trivia before this token.
1578    n_trivia: usize,
1579    /// Whether this token's preceding trivia contained a newline.
1580    newline: Option<Newline>,
1581    /// The index into `text` of the start of our current token (the end is
1582    /// stored as the lexer's cursor).
1583    start: usize,
1584    /// The index into `text` of the end of the previous token.
1585    prev_end: usize,
1586}
1587
1588/// Information about newlines in a group of trivia.
1589#[derive(Debug, Copy, Clone)]
1590struct Newline {
1591    /// The column of the start of the next token in its line.
1592    column: Option<usize>,
1593    /// Whether any of our newlines were paragraph breaks.
1594    parbreak: bool,
1595}
1596
1597/// How to proceed with parsing when at a newline.
1598#[derive(Debug, Copy, Clone, Eq, PartialEq)]
1599enum AtNewline {
1600    /// Continue at newlines.
1601    Continue,
1602    /// Stop at any newline.
1603    Stop,
1604    /// Continue only if there is a continuation with `else` or `.` (Code only).
1605    ContextualContinue,
1606    /// Stop only at a parbreak, not normal newlines (Markup only).
1607    StopParBreak,
1608    /// Require that the token's column be greater or equal to a column (Markup
1609    /// only). If this is `0`, acts like `Continue`; if this is `usize::MAX`,
1610    /// acts like `Stop`.
1611    RequireColumn(usize),
1612}
1613
1614impl AtNewline {
1615    /// Whether to stop at a newline or continue based on the current context.
1616    fn stop_at(self, Newline { column, parbreak }: Newline, kind: SyntaxKind) -> bool {
1617        #[allow(clippy::match_like_matches_macro)]
1618        match self {
1619            AtNewline::Continue => false,
1620            AtNewline::Stop => true,
1621            AtNewline::ContextualContinue => match kind {
1622                SyntaxKind::Else | SyntaxKind::Dot => false,
1623                _ => true,
1624            },
1625            AtNewline::StopParBreak => parbreak,
1626            AtNewline::RequireColumn(min_col) => {
1627                // When the column is `None`, the newline doesn't start a
1628                // column, and we continue parsing. This may happen on the
1629                // boundary of syntax modes, since we only report a column in
1630                // Markup.
1631                column.is_some_and(|column| column <= min_col)
1632            }
1633        }
1634    }
1635}
1636
1637/// A marker representing a node's position in the parser. Mainly used for
1638/// wrapping, but can also index into the parser to access the node, like
1639/// `p[m]`.
1640#[derive(Debug, Copy, Clone, Eq, PartialEq)]
1641struct Marker(usize);
1642
1643// Index into the parser with markers.
1644impl Index<Marker> for Parser<'_> {
1645    type Output = SyntaxNode;
1646
1647    fn index(&self, m: Marker) -> &Self::Output {
1648        &self.nodes[m.0]
1649    }
1650}
1651
1652impl IndexMut<Marker> for Parser<'_> {
1653    fn index_mut(&mut self, m: Marker) -> &mut Self::Output {
1654        &mut self.nodes[m.0]
1655    }
1656}
1657
1658/// Creating/Consuming the parser and getting info about the current token.
1659impl<'s> Parser<'s> {
1660    /// Create a new parser starting from the given text offset and syntax mode.
1661    fn new(text: &'s str, offset: usize, mode: SyntaxMode) -> Self {
1662        let mut lexer = Lexer::new(text, mode);
1663        lexer.jump(offset);
1664        let nl_mode = AtNewline::Continue;
1665        let mut nodes = vec![];
1666        let token = Self::lex(&mut nodes, &mut lexer, nl_mode);
1667        Self {
1668            text,
1669            lexer,
1670            nl_mode,
1671            token,
1672            balanced: true,
1673            nodes,
1674            memo: Default::default(),
1675        }
1676    }
1677
1678    /// Consume the parser, yielding the full vector of parsed SyntaxNodes.
1679    fn finish(self) -> Vec<SyntaxNode> {
1680        self.nodes
1681    }
1682
1683    /// Consume the parser, generating a single top-level node.
1684    fn finish_into(self, kind: SyntaxKind) -> SyntaxNode {
1685        assert!(self.at(SyntaxKind::End));
1686        SyntaxNode::inner(kind, self.finish())
1687    }
1688
1689    /// Similar to a `peek()` function: returns the `kind` of the next token to
1690    /// be eaten.
1691    fn current(&self) -> SyntaxKind {
1692        self.token.kind
1693    }
1694
1695    /// Whether the current token is a given [`SyntaxKind`].
1696    fn at(&self, kind: SyntaxKind) -> bool {
1697        self.token.kind == kind
1698    }
1699
1700    /// Whether the current token is contained in a [`SyntaxSet`].
1701    fn at_set(&self, set: SyntaxSet) -> bool {
1702        set.contains(self.token.kind)
1703    }
1704
1705    /// Whether we're at the end of the token stream.
1706    ///
1707    /// Note: This might be a fake end due to the newline mode.
1708    fn end(&self) -> bool {
1709        self.at(SyntaxKind::End)
1710    }
1711
1712    /// If we're at the given `kind` with no preceding trivia tokens.
1713    fn directly_at(&self, kind: SyntaxKind) -> bool {
1714        self.token.kind == kind && !self.had_trivia()
1715    }
1716
1717    /// Whether `token` had any preceding trivia.
1718    fn had_trivia(&self) -> bool {
1719        self.token.n_trivia > 0
1720    }
1721
1722    /// Whether `token` had a newline among any of its preceding trivia.
1723    fn had_newline(&self) -> bool {
1724        self.token.newline.is_some()
1725    }
1726
1727    /// The number of characters until the most recent newline from the start of
1728    /// the current token. Uses a cached value from the newline mode if present.
1729    fn current_column(&self) -> usize {
1730        self.token
1731            .newline
1732            .and_then(|newline| newline.column)
1733            .unwrap_or_else(|| self.lexer.column(self.token.start))
1734    }
1735
1736    /// The current token's text.
1737    fn current_text(&self) -> &'s str {
1738        &self.text[self.token.start..self.current_end()]
1739    }
1740
1741    /// The offset into `text` of the current token's start.
1742    fn current_start(&self) -> usize {
1743        self.token.start
1744    }
1745
1746    /// The offset into `text` of the current token's end.
1747    fn current_end(&self) -> usize {
1748        self.lexer.cursor()
1749    }
1750
1751    /// The offset into `text` of the previous token's end.
1752    fn prev_end(&self) -> usize {
1753        self.token.prev_end
1754    }
1755}
1756
1757// The main parsing interface for generating tokens and eating/modifying nodes.
1758impl<'s> Parser<'s> {
1759    /// A marker that will point to the current token in the parser once it's
1760    /// been eaten.
1761    fn marker(&self) -> Marker {
1762        Marker(self.nodes.len())
1763    }
1764
1765    /// A marker that will point to first trivia before this token in the
1766    /// parser (or the token itself if no trivia precede it).
1767    fn before_trivia(&self) -> Marker {
1768        Marker(self.nodes.len() - self.token.n_trivia)
1769    }
1770
1771    /// Eat the current node and return a reference for in-place mutation.
1772    #[track_caller]
1773    fn eat_and_get(&mut self) -> &mut SyntaxNode {
1774        let offset = self.nodes.len();
1775        self.eat();
1776        &mut self.nodes[offset]
1777    }
1778
1779    /// Eat the token if at `kind`. Returns `true` if eaten.
1780    ///
1781    /// Note: In Math and Code, this will ignore trivia in front of the
1782    /// `kind`, To forbid skipping trivia, consider using `eat_if_direct`.
1783    fn eat_if(&mut self, kind: SyntaxKind) -> bool {
1784        let at = self.at(kind);
1785        if at {
1786            self.eat();
1787        }
1788        at
1789    }
1790
1791    /// Eat the token only if at `kind` with no preceding trivia. Returns `true`
1792    /// if eaten.
1793    fn eat_if_direct(&mut self, kind: SyntaxKind) -> bool {
1794        let at = self.directly_at(kind);
1795        if at {
1796            self.eat();
1797        }
1798        at
1799    }
1800
1801    /// Assert that we are at the given [`SyntaxKind`] and eat it. This should
1802    /// be used when moving between functions that expect to start with a
1803    /// specific token.
1804    #[track_caller]
1805    fn assert(&mut self, kind: SyntaxKind) {
1806        assert_eq!(self.token.kind, kind);
1807        self.eat();
1808    }
1809
1810    /// Convert the current token's [`SyntaxKind`] and eat it.
1811    fn convert_and_eat(&mut self, kind: SyntaxKind) {
1812        // Only need to replace the node here.
1813        self.token.node.convert_to_kind(kind);
1814        self.eat();
1815    }
1816
1817    /// Eat the current token by saving it to the `nodes` vector, then move
1818    /// the lexer forward to prepare a new token.
1819    fn eat(&mut self) {
1820        self.nodes.push(std::mem::take(&mut self.token.node));
1821        self.token = Self::lex(&mut self.nodes, &mut self.lexer, self.nl_mode);
1822    }
1823
1824    /// Detach the parsed trivia nodes from this token (but not newline info) so
1825    /// that subsequent wrapping will include the trivia.
1826    fn flush_trivia(&mut self) {
1827        self.token.n_trivia = 0;
1828        self.token.prev_end = self.token.start;
1829    }
1830
1831    /// Wrap the nodes from a marker up to (but excluding) the current token in
1832    /// a new [inner node](`SyntaxNode::inner`) of the given kind. This is an
1833    /// easy interface for creating nested syntax nodes _after_ having parsed
1834    /// their children.
1835    fn wrap(&mut self, from: Marker, kind: SyntaxKind) {
1836        let to = self.before_trivia().0;
1837        let from = from.0.min(to);
1838        let children = self.nodes.drain(from..to).collect();
1839        self.nodes.insert(from, SyntaxNode::inner(kind, children));
1840    }
1841
1842    /// Parse within the [`SyntaxMode`] for subsequent tokens (does not change the
1843    /// current token). This may re-lex the final token on exit.
1844    ///
1845    /// This function effectively repurposes the call stack as a stack of modes.
1846    fn enter_modes(
1847        &mut self,
1848        mode: SyntaxMode,
1849        stop: AtNewline,
1850        func: impl FnOnce(&mut Parser<'s>),
1851    ) {
1852        let previous = self.lexer.mode();
1853        self.lexer.set_mode(mode);
1854        self.with_nl_mode(stop, func);
1855        if mode != previous {
1856            self.lexer.set_mode(previous);
1857            self.lexer.jump(self.token.prev_end);
1858            self.nodes.truncate(self.nodes.len() - self.token.n_trivia);
1859            self.token = Self::lex(&mut self.nodes, &mut self.lexer, self.nl_mode);
1860        }
1861    }
1862
1863    /// Parse within the [`AtNewline`] mode for subsequent tokens (does not
1864    /// change the current token). This may re-lex the final token on exit.
1865    ///
1866    /// This function effectively repurposes the call stack as a stack of modes.
1867    fn with_nl_mode(&mut self, mode: AtNewline, func: impl FnOnce(&mut Parser<'s>)) {
1868        let previous = self.nl_mode;
1869        self.nl_mode = mode;
1870        func(self);
1871        self.nl_mode = previous;
1872        if let Some(newline) = self.token.newline
1873            && mode != previous
1874        {
1875            // Restore our actual token's kind or insert a fake end.
1876            let actual_kind = self.token.node.kind();
1877            if self.nl_mode.stop_at(newline, actual_kind) {
1878                self.token.kind = SyntaxKind::End;
1879            } else {
1880                self.token.kind = actual_kind;
1881            }
1882        }
1883    }
1884
1885    /// Move the lexer forward and prepare the current token. In Code, this
1886    /// might insert a temporary [`SyntaxKind::End`] based on our newline mode.
1887    ///
1888    /// This is not a method on `self` because we need a valid token before we
1889    /// can initialize the parser.
1890    fn lex(nodes: &mut Vec<SyntaxNode>, lexer: &mut Lexer, nl_mode: AtNewline) -> Token {
1891        let prev_end = lexer.cursor();
1892        let mut start = prev_end;
1893        let (mut kind, mut node) = lexer.next();
1894        let mut n_trivia = 0;
1895        let mut had_newline = false;
1896        let mut parbreak = false;
1897
1898        while kind.is_trivia() {
1899            had_newline |= lexer.newline(); // Newlines are always trivia.
1900            parbreak |= kind == SyntaxKind::Parbreak;
1901            n_trivia += 1;
1902            nodes.push(node);
1903            start = lexer.cursor();
1904            (kind, node) = lexer.next();
1905        }
1906
1907        let newline = if had_newline {
1908            let column =
1909                (lexer.mode() == SyntaxMode::Markup).then(|| lexer.column(start));
1910            let newline = Newline { column, parbreak };
1911            if nl_mode.stop_at(newline, kind) {
1912                // Insert a temporary `SyntaxKind::End` to halt the parser.
1913                // The actual kind will be restored from `node` later.
1914                kind = SyntaxKind::End;
1915            }
1916            Some(newline)
1917        } else {
1918            None
1919        };
1920
1921        Token { kind, node, n_trivia, newline, start, prev_end }
1922    }
1923}
1924
1925/// Extra parser state for efficiently recovering from mispredicted parses.
1926///
1927/// This is the same idea as packrat parsing, but we use it only in the limited
1928/// case of parenthesized structures. See [`expr_with_paren`] for more.
1929#[derive(Default)]
1930struct MemoArena {
1931    /// A single arena of previously parsed nodes (to reduce allocations).
1932    /// Memoized ranges refer to unique sections of the arena.
1933    arena: Vec<SyntaxNode>,
1934    /// A map from the parser's current position to a range of previously parsed
1935    /// nodes in the arena and a checkpoint of the parser's state. These allow
1936    /// us to reset the parser to avoid parsing the same location again.
1937    memo_map: FxHashMap<MemoKey, (Range<usize>, PartialState)>,
1938}
1939
1940/// A type alias for the memo key so it doesn't get confused with other usizes.
1941///
1942/// The memo is keyed by the index into `text` of the current token's start.
1943type MemoKey = usize;
1944
1945/// A checkpoint of the parser which can fully restore it to a previous state.
1946struct Checkpoint {
1947    node_len: usize,
1948    state: PartialState,
1949}
1950
1951/// State needed to restore the parser's current token and the lexer (but not
1952/// the nodes vector).
1953#[derive(Clone)]
1954struct PartialState {
1955    cursor: usize,
1956    lex_mode: SyntaxMode,
1957    token: Token,
1958}
1959
1960/// The Memoization interface.
1961impl Parser<'_> {
1962    /// Store the already parsed nodes and the parser state into the memo map by
1963    /// extending the arena and storing the extended range and a checkpoint.
1964    fn memoize_parsed_nodes(&mut self, key: MemoKey, prev_len: usize) {
1965        let Checkpoint { state, node_len } = self.checkpoint();
1966        let memo_start = self.memo.arena.len();
1967        self.memo.arena.extend_from_slice(&self.nodes[prev_len..node_len]);
1968        let arena_range = memo_start..self.memo.arena.len();
1969        self.memo.memo_map.insert(key, (arena_range, state));
1970    }
1971
1972    /// Try to load a memoized result, return `None` if we did or `Some` (with a
1973    /// checkpoint and a key for the memo map) if we didn't.
1974    fn restore_memo_or_checkpoint(&mut self) -> Option<(MemoKey, Checkpoint)> {
1975        // We use the starting index of the current token as our key.
1976        let key: MemoKey = self.current_start();
1977        match self.memo.memo_map.get(&key).cloned() {
1978            Some((range, state)) => {
1979                self.nodes.extend_from_slice(&self.memo.arena[range]);
1980                // It's important that we don't truncate the nodes vector since
1981                // it may have grown or shrunk (due to other memoization or
1982                // error reporting) since we made this checkpoint.
1983                self.restore_partial(state);
1984                None
1985            }
1986            None => Some((key, self.checkpoint())),
1987        }
1988    }
1989
1990    /// Restore the parser to the state at a checkpoint.
1991    fn restore(&mut self, checkpoint: Checkpoint) {
1992        self.nodes.truncate(checkpoint.node_len);
1993        self.restore_partial(checkpoint.state);
1994    }
1995
1996    /// Restore parts of the checkpoint excluding the nodes vector.
1997    fn restore_partial(&mut self, state: PartialState) {
1998        self.lexer.jump(state.cursor);
1999        self.lexer.set_mode(state.lex_mode);
2000        self.token = state.token;
2001    }
2002
2003    /// Save a checkpoint of the parser state.
2004    fn checkpoint(&self) -> Checkpoint {
2005        let node_len = self.nodes.len();
2006        let state = PartialState {
2007            cursor: self.lexer.cursor(),
2008            lex_mode: self.lexer.mode(),
2009            token: self.token.clone(),
2010        };
2011        Checkpoint { node_len, state }
2012    }
2013}
2014
2015/// Functions for eating expected or unexpected tokens and generating errors if
2016/// we don't get what we expect.
2017impl Parser<'_> {
2018    /// Consume the given `kind` or produce an error.
2019    fn expect(&mut self, kind: SyntaxKind) -> bool {
2020        let at = self.at(kind);
2021        if at {
2022            self.eat();
2023        } else if kind == SyntaxKind::Ident && self.token.kind.is_keyword() {
2024            self.trim_errors();
2025            self.eat_and_get().expected(kind.name());
2026        } else {
2027            self.balanced &= !kind.is_grouping();
2028            self.expected(kind.name());
2029        }
2030        at
2031    }
2032
2033    /// Consume the given closing delimiter or produce an error for the matching
2034    /// opening delimiter at `open`.
2035    #[track_caller]
2036    fn expect_closing_delimiter(&mut self, open: Marker, kind: SyntaxKind) {
2037        if !self.eat_if(kind) {
2038            self.nodes[open.0].convert_to_error("unclosed delimiter");
2039        }
2040    }
2041
2042    /// Produce an error that the given `thing` was expected.
2043    fn expected(&mut self, thing: &str) {
2044        if !self.after_error() {
2045            self.expected_at(self.before_trivia(), thing);
2046        }
2047    }
2048
2049    /// Whether the last non-trivia node is an error.
2050    fn after_error(&mut self) -> bool {
2051        let m = self.before_trivia();
2052        m.0 > 0 && self.nodes[m.0 - 1].kind().is_error()
2053    }
2054
2055    /// Produce an error that the given `thing` was expected at the position
2056    /// of the marker `m`.
2057    fn expected_at(&mut self, m: Marker, thing: &str) {
2058        let error =
2059            SyntaxNode::error(SyntaxError::new(eco_format!("expected {thing}")), "");
2060        self.nodes.insert(m.0, error);
2061    }
2062
2063    /// Add a hint to a trailing error.
2064    fn hint(&mut self, hint: &str) {
2065        let m = self.before_trivia();
2066        if let Some(error) = self.nodes.get_mut(m.0 - 1) {
2067            error.hint(hint);
2068        }
2069    }
2070
2071    /// Consume the next token (if any) and produce an error stating that it was
2072    /// unexpected.
2073    fn unexpected(&mut self) {
2074        self.trim_errors();
2075        self.balanced &= !self.token.kind.is_grouping();
2076        self.eat_and_get().unexpected();
2077    }
2078
2079    /// Remove trailing errors with zero length.
2080    fn trim_errors(&mut self) {
2081        let Marker(end) = self.before_trivia();
2082        let mut start = end;
2083        while start > 0
2084            && self.nodes[start - 1].kind().is_error()
2085            && self.nodes[start - 1].is_empty()
2086        {
2087            start -= 1;
2088        }
2089        self.nodes.drain(start..end);
2090    }
2091}