Skip to main content

cove_syntax/
parser.rs

1//! The Cove parser.
2//!
3//! Turns a token stream into an [`ast::SourceUnit`](crate::ast::SourceUnit). Cove has no statement
4//! terminators: `;` is not part of the language. Instead, as in Go and Swift,
5//! a newline ends a statement when the line could have ended there. The last
6//! expression of a block is still that block's value.
7//!
8//! # The newline rule
9//!
10//! A line break ends the current expression when all of the following hold:
11//!
12//! 1. the token after the break carries [`Token::preceded_by_newline`];
13//! 2. the token before the break can end an expression — an identifier,
14//!    `self`, a literal, `)`, `]`, `}`, `?`, or `...` (see
15//!    `ends_expression`);
16//! 3. the parser is at a point where continuing is optional: a postfix `(`,
17//!    `<` generic argument list, or `{` trailing closure, or a binary,
18//!    range, or assignment operator;
19//! 4. the parser is not inside a `(`, `[`, or `<` group (see
20//!    `Parser::grouped`). `{` is not such a group: the statements of a
21//!    block do end at newlines.
22//!
23//! Two exceptions keep familiar code working. A line that starts with `.`
24//! continues the previous expression, so a method chain may be split across
25//! lines; this falls out of rule 3, because `.` is never an optional
26//! continuation. And the continuation keywords `else` and `=>` are read
27//! across a line break as well, so `}` followed by a newline and `else` still
28//! attaches.
29//!
30//! Because rule 3 looks at the operator rather than the operand, an operator
31//! at the *end* of a line continues onto the next line (`a +` / `b` is one
32//! expression) while an operator at the *start* of a line does not (`a` /
33//! `+ b` is two statements).
34//!
35//! # Keywords whose operand is optional
36//!
37//! `break` and `return` take an operand or take none, and `continue` never
38//! takes one. For those, a line break is decisive rather than optional: the
39//! operand must *begin* on the keyword's own line, so a `break` written alone
40//! on its line is a `break` with no operand and the next line is the next
41//! statement. This is the same rule Go states as inserting a semicolon after
42//! `break`, `continue`, and `return` at the end of a line, and it holds
43//! inside a group as well, unlike rule 4 — a keyword that is already complete
44//! has nothing for the next line to finish. An operand that starts on the
45//! keyword's line may still run over onto further lines, so `return f(` /
46//! `a,` / `)` is one `return`.
47//!
48//! # The nesting limit
49//!
50//! Recursive descent spends native stack per level of nesting, so the parser
51//! bounds nesting rather than discovering the bound when the stack runs out.
52//! Source that nests deeper than `MAX_NESTING_DEPTH` levels is a
53//! `cove::parse::nesting_too_deep` diagnostic like any other and the file is
54//! refused, instead of the process ending in a stack overflow that no caller
55//! can catch. A level is any construct written inside another, and also each
56//! link of a left-associative chain, because the tree such a chain builds is
57//! as deep as the chain is long and everything downstream walks that tree by
58//! recursing. See the constant for what the number is calibrated against.
59//!
60//! Parsing never stops at the first error. Every diagnostic is collected and
61//! the parser resynchronises at the next plausible declaration or statement,
62//! so a single run reports as many independent problems as it can find.
63
64use cove_diag::{Diagnostic, FileId, SourceMap, Span, Spanned};
65
66use crate::ast::*;
67use crate::lexer;
68use crate::token::{Keyword, StringPart, Token, TokenKind};
69
70/// Parses `tokens`, which must be the token stream lexed from `file`.
71///
72/// Returns every diagnostic found in the file rather than only the first.
73pub fn parse(
74    sources: &SourceMap,
75    file: FileId,
76    tokens: Vec<Token>,
77) -> Result<SourceUnit, Vec<Diagnostic>> {
78    let mut parser = Parser::new(sources, file, tokens);
79    let unit = parser.parse_source_unit();
80    if parser.diagnostics.is_empty() {
81        Ok(unit)
82    } else {
83        Err(parser.diagnostics)
84    }
85}
86
87/// Signals that a diagnostic was recorded and the current construct was
88/// abandoned. Recovery happens at the nearest declaration or statement.
89struct Bail;
90
91/// The modifiers written in front of a declaration.
92struct ItemModifiers {
93    exported: bool,
94    is_test: bool,
95    /// Where `opaque` was written, kept rather than reduced to a flag
96    /// because the checks that reject it — on a declaration that is not an
97    /// exported struct — can only run once the declaration itself is read.
98    opaque: Option<Span>,
99}
100
101type PResult<T> = Result<T, Bail>;
102
103/// The smallest native stack the parser promises to read a file on.
104///
105/// Recursive descent spends stack per level of nesting in the file it reads,
106/// so a bound on nesting is only worth as much as the stack it is calibrated
107/// against. The toolchain gives the parser a generous one — every `cove`
108/// command runs its whole dispatch on `cove_runtime::STACK_SIZE`, which is
109/// about 106 MiB in a debug build — but that number is unreachable from here
110/// and must stay so: `cove-runtime` depends on `cove-syntax`, not the other
111/// way round, and [`parse`] is a library entry point that an editor plugin, a
112/// language server, or a test may call on any thread it likes.
113///
114/// So the promise is made against the smallest stack such a caller plausibly
115/// has: the platform default for a thread nobody sized, which is 2 MiB on
116/// macOS, Linux, and Windows alike, and is also what Rust's test harness
117/// gives each test. A process main thread is larger than that everywhere
118/// except Windows, where it is 1 MiB — the one stack this figure does not
119/// cover, and only in a debug build, since a release build spends a fifth as
120/// much per level and fits the limit into 400 KiB. No `cove` command parses on a main thread, because
121/// `main` hands the whole dispatch to `cove_runtime::on_cove_stack`, so what
122/// is left uncovered is an embedder that both builds without optimizations
123/// and parses on the main thread of a Windows process.
124const NESTING_STACK: usize = 2 * 1024 * 1024;
125
126/// The native stack one level of nesting costs the parser in a debug build.
127///
128/// Measured on macOS the way `cove_runtime::STACK_PER_FRAME` was: files of
129/// increasing nesting are parsed on threads of two known sizes and the
130/// deepest that parses cleanly is binary-searched on each, so the figure is
131/// the slope between the two sizes and whatever the parser spends before the
132/// nesting starts cancels out. Eighteen shapes were measured, at 4 MiB and 16
133/// MiB in a debug build and at 1 MiB and 4 MiB in a release one. Per level of
134/// [`Parser::depth`], which is what [`MAX_NESTING_DEPTH`] counts, the worst of
135/// them were:
136///
137/// | nesting                       | debug    | release |
138/// |-------------------------------|----------|---------|
139/// | `"a{"a{ ... }"}"`             | 28.8 KiB | 5.3 KiB |
140/// | `match x { _ => ... }`        | 28.6 KiB | 6.2 KiB |
141/// | `[[[ ... ]]]`                 | 26.4 KiB | 5.3 KiB |
142/// | `((( ... )))`                 | 25.7 KiB | 5.3 KiB |
143/// | `g(g( ... ))`                 | 21.7 KiB | 4.4 KiB |
144/// | `if true { ... } else { 0 }`  | 16.4 KiB | 3.7 KiB |
145/// | `fn g() { fn g() { ... } }`   | 12.0 KiB | 3.7 KiB |
146/// | `Some(Some( ... ))`           |  3.4 KiB | 0.8 KiB |
147/// | `Array<Array< ... >>`         |  2.8 KiB | 0.6 KiB |
148///
149/// The cheap shapes at the bottom are the ones whose level is a single frame:
150/// a type argument list or a pattern payload re-enters one function, while a
151/// parenthesised expression re-enters the whole precedence chain from
152/// `parse_expr` down to `parse_primary`. The braced forms look cheap per
153/// source level and are not: a block raises the depth twice per level, once
154/// for the block and once for the expression it is the body of, so the figure
155/// per level of nesting a reader would count is double what this table shows.
156///
157/// The figure is the parser's, and the parser is the most expensive stage of
158/// the toolchain per level: measured the same way, `cove check` and `cove
159/// fmt` over the same files show the same slope to within a fifth of a
160/// kibibyte, so what the resolver, the type checker, and the formatter spend
161/// walking a tree of a given depth is less than what the parser spent
162/// building it. That is why one limit here bounds the whole pipeline and none
163/// of them needs a limit of its own. A chain link is cheaper still — it costs
164/// the parser nothing, because a chain is parsed by a loop, and the walkers
165/// about 2 KiB — and [`MAX_NESTING_DEPTH`] charges it a whole level anyway,
166/// which is margin rather than measurement.
167///
168/// The number here is 32 KiB, the worst measured figure rounded up, and it is
169/// deliberately not `#[cfg(debug_assertions)]`-conditional as its runtime
170/// counterpart is. [`MAX_NESTING_DEPTH`] is derived from it and is visible to
171/// whoever writes the file, so a file that parses in a release build must
172/// parse in a debug build; taking the worse profile for both is what makes
173/// that true, and it leaves a release build five times the headroom it needs.
174const STACK_PER_LEVEL: usize = 32 * 1024;
175
176/// How deeply source may nest before the parser reports a limit instead of
177/// exhausting its native stack.
178///
179/// Sixty-four, and derived rather than chosen: [`NESTING_STACK`] is the stack
180/// the parser promises to work on and [`STACK_PER_LEVEL`] is what a level of
181/// it costs, so this is how many levels fit.
182///
183/// A level is anything that puts one construct inside another, counted in one
184/// place — [`Parser::depth`] — rather than once per construct, because
185/// expressions, blocks, types, and patterns all spend the same stack and a
186/// file that alternates between them would pass four separate limits while
187/// exhausting the stack anyway. Two things raise it. Every point at which the
188/// parser re-enters itself raises it through [`Parser::nested`], which is
189/// what bounds the parser's own recursion. And every link of a
190/// left-associative chain raises it through [`Parser::link`], which is not
191/// recursion at all — `a.b.c` and `1 + 2 + 3` are parsed by a loop — but
192/// builds a tree as deep as the chain is long, and the resolver, the type
193/// checker, the formatter, and the interpreter all recurse over that tree
194/// afterwards. Counting both in one number is what makes the bound hold along
195/// a path: a chain hanging off a nested expression is as deep as its links
196/// plus the nesting above it, and that is the sum this counter carries.
197///
198/// So the limit is spent by more than parentheses, and this is the one place
199/// where it is a constraint on source anyone would write: a chain of more
200/// than sixty-four operands, `1 + 2 + ... + 65`, is refused, as is a method
201/// chain of more than thirty-two calls, since a call is a `.` and a `(`. The
202/// deepest file in this repository reaches twenty-four levels —
203/// `examples/callbacks/main.cove`, whose server loop nests a `scope`, a
204/// spawned closure, a callback given to `clock.every`, a `lock` closure, and
205/// an interpolated string inside a call, with the field and call links of
206/// those chains counted in. Sixty-four is not a lot of room above that, and
207/// the alternative was worse: the number is what a 2 MiB stack holds, and
208/// raising it means promising a stack no unsized thread has. Raising it later
209/// is a compatible change and lowering it is not, which is the direction to
210/// err in.
211///
212/// Past the limit the parser reports `cove::parse::nesting_too_deep` and
213/// recovers as it does from any other parse error, so a file that nests a
214/// million parentheses produces a diagnostic rather than ending the process.
215///
216/// This is the parser's half of the promise `cove_runtime::MAX_CALL_DEPTH`
217/// makes at run time, and the two are calibrated in opposite directions for
218/// the same reason. The runtime owns the thread it evaluates on, so it sizes
219/// the stack to fit the limit; the parser is handed a thread by whoever calls
220/// it, so it fits the limit to the stack.
221const MAX_NESTING_DEPTH: u32 = (NESTING_STACK / STACK_PER_LEVEL) as u32;
222
223struct Parser<'a> {
224    sources: &'a SourceMap,
225    file: FileId,
226    tokens: Vec<Token>,
227    pos: usize,
228    diagnostics: Vec<Diagnostic>,
229    /// Set while parsing the header expression of `if`, `while`, `for`,
230    /// `match`, or `scope`, where a following `{` opens the body instead of a
231    /// trailing closure.
232    no_trailing_closure: bool,
233    /// How many `(`, `[`, or `<` groups enclose the cursor. A newline inside
234    /// such a group never ends a statement, so argument lists, array
235    /// literals, and generic argument lists may span lines.
236    ///
237    /// This is not [`Parser::depth`] and the two must not be merged. This one
238    /// answers a question about the language — whether a line break here ends
239    /// a statement — and so it counts only the three bracket kinds the
240    /// newline rule names, and [`Parser::ungrouped`] resets it to zero inside
241    /// a `{ }` block because the rule says a block's statements do end at
242    /// newlines. The other answers a question about the machine, counts every
243    /// kind of nesting there is, and may never be reset. A counter that did
244    /// both jobs would have to be wrong about one of them.
245    group_depth: u32,
246    /// How deep the tree under construction is at the cursor, bounded by
247    /// [`MAX_NESTING_DEPTH`].
248    ///
249    /// One counter serves every construct that can contain another —
250    /// expressions, blocks, types, and patterns alike, and the links of a
251    /// chain besides — because they all end up on the same native stack, and
252    /// a counter for each would let a file that alternates between them pass
253    /// every limit while exhausting that stack anyway.
254    depth: u32,
255}
256
257/// Builds an expression with no id yet.
258///
259/// The parser does not number expressions: `number_unit` does, in one pass
260/// over the finished tree, so that the numbering is a property of the file
261/// rather than of the order the parser happened to build things in.
262fn expr(kind: ExprKind, span: Span) -> Expr {
263    Expr {
264        id: ExprId::UNSET,
265        kind,
266        span,
267    }
268}
269
270/// A place expression names storage: a variable or a field of a place.
271fn is_place_expr(target: &Expr) -> bool {
272    match &target.kind {
273        ExprKind::Ident(_) => true,
274        ExprKind::Field { base, .. } => is_place_expr(base),
275        _ => false,
276    }
277}
278
279/// Only a callee-shaped expression can take a braced trailing closure, so
280/// `tasks.spawn { ... }` is a call while `[1, 2] { ... }` is not.
281fn can_take_trailing_closure(callee: &Expr) -> bool {
282    matches!(
283        callee.kind,
284        ExprKind::Ident(_) | ExprKind::Field { .. } | ExprKind::Call { trailing: None, .. }
285    )
286}
287
288/// The rule an operator at the start of a line breaks, stated for the reader.
289const NEWLINE_OPERATOR_RULE: &str = "A newline ends a statement when the expression before it is \
290     complete, so an operator that continues an expression stays on the line it continues.";
291
292/// Whether a token can be the last token of an expression.
293///
294/// This is the first half of the newline rule: a line break only ends a
295/// statement when the line so far reads as a complete expression.
296///
297/// `break`, `continue`, and `return` end an expression on their own, because
298/// an operand of theirs has to begin on their own line (see
299/// [`Parser::at_operand`]). One of them at the end of a line is therefore
300/// finished, and the line break after it ends the statement instead of
301/// letting an operator on the next line continue it.
302fn ends_expression(kind: &TokenKind) -> bool {
303    matches!(
304        kind,
305        TokenKind::Ident(_)
306            | TokenKind::Keyword(
307                Keyword::SelfValue | Keyword::Break | Keyword::Continue | Keyword::Return
308            )
309            | TokenKind::Int(_)
310            | TokenKind::Float(_)
311            | TokenKind::Bool(_)
312            | TokenKind::Duration(_)
313            | TokenKind::Str(_)
314            | TokenKind::RParen
315            | TokenKind::RBracket
316            | TokenKind::RBrace
317            | TokenKind::Question
318            | TokenKind::Ellipsis
319    )
320}
321
322/// Whether a token can only ever continue an expression, never begin one.
323///
324/// Such a token at the start of a line is always a statement that the newline
325/// rule has just cut in two, which [`Parser::expected_expression`] explains.
326fn continues_expression_only(kind: &TokenKind) -> bool {
327    matches!(
328        kind,
329        TokenKind::Plus
330            | TokenKind::Star
331            | TokenKind::Slash
332            | TokenKind::Percent
333            | TokenKind::EqEq
334            | TokenKind::BangEq
335            | TokenKind::Lt
336            | TokenKind::LtEq
337            | TokenKind::Gt
338            | TokenKind::GtEq
339            | TokenKind::AmpAmp
340            | TokenKind::PipePipe
341            | TokenKind::Eq
342            | TokenKind::PlusEq
343            | TokenKind::MinusEq
344            | TokenKind::StarEq
345            | TokenKind::SlashEq
346            | TokenKind::PercentEq
347            | TokenKind::DotDot
348            | TokenKind::DotDotLt
349            | TokenKind::Keyword(Keyword::Is)
350    )
351}
352
353fn rebase_span(span: Span, file: FileId, offset: u32) -> Span {
354    Span::new(file, offset + span.start, offset + span.end)
355}
356
357/// Moves a token lexed out of an interpolation's source text back onto the
358/// file that contains the string literal.
359fn rebase_token(mut token: Token, file: FileId, offset: u32) -> Token {
360    token.span = rebase_span(token.span, file, offset);
361    if let TokenKind::Str(parts) = &mut token.kind {
362        for part in parts {
363            if let StringPart::Interpolation { span, .. } = part {
364                *span = rebase_span(*span, file, offset);
365            }
366        }
367    }
368    token
369}
370
371fn rebase_diagnostic(mut diagnostic: Diagnostic, file: FileId, offset: u32) -> Diagnostic {
372    if let Some(span) = diagnostic.primary {
373        diagnostic.primary = Some(rebase_span(span, file, offset));
374    }
375    for label in &mut diagnostic.labels {
376        label.span = rebase_span(label.span, file, offset);
377    }
378    diagnostic
379}
380
381impl<'a> Parser<'a> {
382    fn new(sources: &'a SourceMap, file: FileId, tokens: Vec<Token>) -> Self {
383        let tokens = if tokens.is_empty() {
384            vec![Token {
385                kind: TokenKind::Eof,
386                span: Span::new(file, 0, 0),
387                preceded_by_newline: false,
388            }]
389        } else {
390            tokens
391        };
392        Parser {
393            sources,
394            file,
395            tokens,
396            pos: 0,
397            diagnostics: Vec::new(),
398            no_trailing_closure: false,
399            group_depth: 0,
400            depth: 0,
401        }
402    }
403
404    fn peek(&self) -> &TokenKind {
405        &self.tokens[self.pos].kind
406    }
407
408    fn peek_at(&self, offset: usize) -> &TokenKind {
409        let index = (self.pos + offset).min(self.tokens.len() - 1);
410        &self.tokens[index].kind
411    }
412
413    fn span(&self) -> Span {
414        self.tokens[self.pos].span
415    }
416
417    /// The span of the token most recently consumed, used to close the span of
418    /// a node that ends at the current position.
419    fn prev_span(&self) -> Span {
420        self.tokens[self.pos.saturating_sub(1)].span
421    }
422
423    fn is_eof(&self) -> bool {
424        matches!(self.peek(), TokenKind::Eof)
425    }
426
427    fn bump(&mut self) -> Token {
428        let token = self.tokens[self.pos].clone();
429        if self.pos + 1 < self.tokens.len() {
430            self.pos += 1;
431        }
432        token
433    }
434
435    fn at(&self, kind: &TokenKind) -> bool {
436        self.peek() == kind
437    }
438
439    fn eat(&mut self, kind: &TokenKind) -> bool {
440        if self.at(kind) {
441            self.bump();
442            true
443        } else {
444            false
445        }
446    }
447
448    fn at_keyword(&self, keyword: Keyword) -> bool {
449        matches!(self.peek(), TokenKind::Keyword(found) if *found == keyword)
450    }
451
452    fn eat_keyword(&mut self, keyword: Keyword) -> bool {
453        if self.at_keyword(keyword) {
454            self.bump();
455            true
456        } else {
457            false
458        }
459    }
460
461    fn error(&mut self, diagnostic: Diagnostic) {
462        self.diagnostics.push(diagnostic);
463    }
464
465    fn unexpected(&mut self, expected: &str) -> Bail {
466        let found = self.peek().describe();
467        let span = self.span();
468        let mut diagnostic = Diagnostic::error(
469            "cove::parse::unexpected_token",
470            format!("expected {expected}, found {found}"),
471        )
472        .at(span);
473        diagnostic = self.note_newline_rule(diagnostic);
474        self.error(diagnostic);
475        Bail
476    }
477
478    /// Adds the newline rule to `diagnostic` when the token it reports was cut
479    /// off from the previous line, which is otherwise easy to misread as a
480    /// problem with the token itself.
481    fn note_newline_rule(&self, diagnostic: Diagnostic) -> Diagnostic {
482        if !(self.at_statement_break() && continues_expression_only(self.peek())) {
483            return diagnostic;
484        }
485        diagnostic
486            .label(self.prev_span(), "a newline ended the statement here")
487            .rule(NEWLINE_OPERATOR_RULE)
488            .help("Move this operator to the end of the previous line.")
489    }
490
491    /// Reports a token that cannot begin an expression.
492    ///
493    /// When the token could only have continued the previous line, the
494    /// diagnostic explains that the newline ended that statement instead of
495    /// repeating the generic "expected an expression".
496    fn expected_expression(&mut self) -> Bail {
497        if !(self.at_statement_break() && continues_expression_only(self.peek())) {
498            return self.unexpected("an expression");
499        }
500        let operator = self.peek().describe();
501        let span = self.span();
502        let previous = self.prev_span();
503        self.error(
504            Diagnostic::error(
505                "cove::parse::newline_ended_statement",
506                format!("{operator} cannot start a statement"),
507            )
508            .at(span)
509            .label(previous, "the previous statement ended here")
510            .rule(NEWLINE_OPERATOR_RULE)
511            .help("Move this operator to the end of the previous line."),
512        );
513        Bail
514    }
515
516    fn expect(&mut self, kind: &TokenKind, expected: &str) -> PResult<Token> {
517        if self.at(kind) {
518            Ok(self.bump())
519        } else {
520            Err(self.unexpected(expected))
521        }
522    }
523
524    fn expect_keyword(&mut self, keyword: Keyword, expected: &str) -> PResult<Span> {
525        if self.at_keyword(keyword) {
526            Ok(self.bump().span)
527        } else {
528            Err(self.unexpected(expected))
529        }
530    }
531
532    fn expect_ident(&mut self) -> PResult<Ident> {
533        let span = self.span();
534        match self.peek() {
535            TokenKind::Ident(name) => {
536                let name = name.clone();
537                self.bump();
538                Ok(Spanned::new(name, span))
539            }
540            _ => Err(self.unexpected("identifier")),
541        }
542    }
543
544    /// After `.`, a keyword names an ordinary member: `task.await()` reads the
545    /// member `await`, not the `await` operator.
546    fn expect_member_name(&mut self) -> PResult<Ident> {
547        let span = self.span();
548        let name = match self.peek() {
549            TokenKind::Ident(name) => name.clone(),
550            TokenKind::Keyword(keyword) => keyword.as_str().to_string(),
551            _ => return Err(self.unexpected("a field or method name")),
552        };
553        self.bump();
554        Ok(Spanned::new(name, span))
555    }
556
557    /// Runs `parse` with the trailing-closure rule temporarily set. Header
558    /// expressions forbid trailing closures; everything nested inside
559    /// parentheses, brackets, or braces allows them again.
560    fn scoped<T>(&mut self, no_trailing_closure: bool, parse: impl FnOnce(&mut Self) -> T) -> T {
561        let saved = self.no_trailing_closure;
562        self.no_trailing_closure = no_trailing_closure;
563        let result = parse(self);
564        self.no_trailing_closure = saved;
565        result
566    }
567
568    /// Runs `parse` inside a `(`, `[`, or `<` group, where line breaks never
569    /// end a statement.
570    fn grouped<T>(&mut self, parse: impl FnOnce(&mut Self) -> T) -> T {
571        self.group_depth += 1;
572        let result = parse(self);
573        self.group_depth -= 1;
574        result
575    }
576
577    /// Runs `parse` as the body of a `{ ... }` block, where line breaks end
578    /// statements again even when the block itself sits inside a group, as in
579    /// a lambda passed as an argument.
580    fn ungrouped<T>(&mut self, parse: impl FnOnce(&mut Self) -> T) -> T {
581        let saved = self.group_depth;
582        self.group_depth = 0;
583        let result = parse(self);
584        self.group_depth = saved;
585        result
586    }
587
588    /// Runs `parse` one level of nesting deeper, refusing to descend past
589    /// [`MAX_NESTING_DEPTH`].
590    ///
591    /// Every place the parser re-enters itself goes through here, which is
592    /// what bounds the native stack a file can spend: [`Parser::depth`] is
593    /// raised before `parse` runs and lowered after it, and the two cannot
594    /// come apart because a parser that gives up returns `Err(Bail)` as an
595    /// ordinary value rather than unwinding, so the failing path leaves
596    /// through the same line as the succeeding one.
597    fn nested<T>(&mut self, parse: impl FnOnce(&mut Self) -> PResult<T>) -> PResult<T> {
598        if self.depth >= MAX_NESTING_DEPTH {
599            return Err(self.nesting_too_deep());
600        }
601        self.depth += 1;
602        let result = parse(self);
603        self.depth -= 1;
604        result
605    }
606
607    /// Raises the depth for one more link of a left-associative chain.
608    ///
609    /// A chain is built by a loop rather than by recursion, so it costs the
610    /// parser nothing, but the tree it builds is as deep as the chain is
611    /// long and everything that walks that tree afterwards recurses over it.
612    /// A link therefore costs a level exactly as nesting does, and it is held
613    /// for as long as the chain is being built: the loop runs inside
614    /// [`Parser::chained`], which puts the depth back when the chain is done.
615    fn link(&mut self) -> PResult<()> {
616        if self.depth >= MAX_NESTING_DEPTH {
617            return Err(self.nesting_too_deep());
618        }
619        self.depth += 1;
620        Ok(())
621    }
622
623    /// Runs `parse`, which builds a left-associative chain by repeated
624    /// [`Parser::link`], and restores the depth those links raised.
625    fn chained<T>(&mut self, parse: impl FnOnce(&mut Self) -> PResult<T>) -> PResult<T> {
626        let saved = self.depth;
627        let result = parse(self);
628        self.depth = saved;
629        result
630    }
631
632    /// Reports source that nests deeper than the parser will descend.
633    fn nesting_too_deep(&mut self) -> Bail {
634        let span = self.span();
635        self.error(
636            Diagnostic::error(
637                "cove::parse::nesting_too_deep",
638                format!("this nests more than {MAX_NESTING_DEPTH} levels deep"),
639            )
640            .at(span)
641            .rule(format!(
642                "Source nests no more than {MAX_NESTING_DEPTH} levels deep, counting each link \
643                 of a chain such as `a.b.c` or `1 + 2 + 3` as a level of its own."
644            ))
645            .help("Give an inner part a name of its own with `let`, or lift it into a function."),
646        );
647        Bail
648    }
649
650    /// Whether a line break at the cursor ends the current statement.
651    ///
652    /// Callers ask this only where continuing the expression is optional, so
653    /// the answer decides between one expression and two statements. See the
654    /// module documentation for the full rule.
655    fn at_statement_break(&self) -> bool {
656        if self.group_depth > 0 || self.pos == 0 {
657            return false;
658        }
659        let next = &self.tokens[self.pos];
660        if !next.preceded_by_newline {
661            return false;
662        }
663        // A line starting with `.` continues a method chain.
664        if matches!(next.kind, TokenKind::Dot) {
665            return false;
666        }
667        ends_expression(&self.tokens[self.pos - 1].kind)
668    }
669
670    fn dangling_doc(&mut self, span: Span) {
671        self.error(
672            Diagnostic::error(
673                "cove::parse::dangling_doc_comment",
674                "doc comment is not attached to a declaration",
675            )
676            .at(span)
677            .rule("A `///` doc comment documents the declaration that follows it.")
678            .help("Move the comment above a declaration, or write it as an ordinary `//` comment."),
679        );
680    }
681
682    /// Joins the run of `///` comments at the cursor into one doc string.
683    fn collect_doc(&mut self) -> Option<(String, Span)> {
684        let mut lines: Vec<String> = Vec::new();
685        let mut span: Option<Span> = None;
686        while let TokenKind::DocComment(text) = self.peek() {
687            let text = text.clone();
688            let line_span = self.span();
689            span = Some(match span {
690                Some(previous) => previous.to(line_span),
691                None => line_span,
692            });
693            lines.push(text);
694            self.bump();
695        }
696        span.map(|span| (lines.join("\n"), span))
697    }
698
699    /// Whether the cursor begins a declaration. `fn` and `async fn` only start
700    /// a declaration when a name follows; otherwise they open a lambda.
701    fn at_item_start(&self) -> bool {
702        match self.peek() {
703            TokenKind::Keyword(
704                Keyword::Export
705                | Keyword::Test
706                | Keyword::Opaque
707                | Keyword::Struct
708                | Keyword::Enum
709                | Keyword::Trait
710                | Keyword::Impl
711                | Keyword::Type,
712            ) => true,
713            TokenKind::Keyword(Keyword::Fn) => matches!(self.peek_at(1), TokenKind::Ident(_)),
714            TokenKind::Keyword(Keyword::Async) => {
715                matches!(self.peek_at(1), TokenKind::Keyword(Keyword::Fn))
716                    && matches!(self.peek_at(2), TokenKind::Ident(_))
717            }
718            _ => false,
719        }
720    }
721
722    fn at_stmt_start(&self) -> bool {
723        self.at_item_start()
724            || matches!(
725                self.peek(),
726                TokenKind::Keyword(
727                    Keyword::Let
728                        | Keyword::Var
729                        | Keyword::Return
730                        | Keyword::Break
731                        | Keyword::Continue
732                ) | TokenKind::DocComment(_)
733            )
734    }
735
736    /// Skips tokens until the next declaration at brace depth zero. When
737    /// `in_braces`, the `}` closing the enclosing group also stops recovery and
738    /// is left for the caller. At least one token is always consumed unless
739    /// recovery stops immediately at such a `}`.
740    fn recover_to_item(&mut self, in_braces: bool) {
741        let mut depth = 0i32;
742        let mut consumed = false;
743        while !self.is_eof() {
744            if depth == 0 && self.at(&TokenKind::RBrace) && (in_braces || consumed) {
745                if in_braces {
746                    return;
747                }
748                self.bump();
749                return;
750            }
751            if depth == 0
752                && consumed
753                && (self.at_item_start()
754                    || self.at_keyword(Keyword::Use)
755                    || matches!(self.peek(), TokenKind::DocComment(_)))
756            {
757                return;
758            }
759            match self.peek() {
760                TokenKind::LBrace => depth += 1,
761                TokenKind::RBrace => depth -= 1,
762                _ => {}
763            }
764            self.bump();
765            consumed = true;
766        }
767    }
768
769    /// Skips tokens until the next statement inside a block, or the `}` that
770    /// closes it. The closing brace is left for [`Parser::parse_block`].
771    fn recover_in_block(&mut self) {
772        let mut depth = 0i32;
773        let mut consumed = false;
774        while !self.is_eof() {
775            if depth == 0 && self.at(&TokenKind::RBrace) {
776                return;
777            }
778            if depth == 0 && consumed && self.at_stmt_start() {
779                return;
780            }
781            match self.peek() {
782                TokenKind::LBrace => depth += 1,
783                TokenKind::RBrace => depth -= 1,
784                _ => {}
785            }
786            self.bump();
787            consumed = true;
788        }
789    }
790}
791
792/// Declarations.
793impl Parser<'_> {
794    fn parse_source_unit(&mut self) -> SourceUnit {
795        let start = self.span();
796        let mut uses = Vec::new();
797        let mut items = Vec::new();
798
799        while !self.is_eof() {
800            let doc = self.collect_doc();
801
802            if self.at_keyword(Keyword::Use) {
803                if let Some((_, span)) = doc {
804                    self.dangling_doc(span);
805                }
806                match self.parse_use() {
807                    Ok(use_decl) => uses.push(use_decl),
808                    Err(Bail) => self.recover_to_item(false),
809                }
810                continue;
811            }
812
813            if !self.at_item_start() {
814                match doc {
815                    Some((_, span)) => self.dangling_doc(span),
816                    None => {
817                        self.unexpected("a declaration");
818                    }
819                }
820                self.recover_to_item(false);
821                continue;
822            }
823
824            match self.parse_item(doc.map(|(text, _)| text)) {
825                Ok(item) => items.push(item),
826                Err(Bail) => self.recover_to_item(false),
827            }
828        }
829
830        SourceUnit {
831            uses,
832            items,
833            span: start.to(self.span()),
834        }
835    }
836
837    /// `use http` and `use console.println`.
838    fn parse_use(&mut self) -> PResult<Use> {
839        let start = self.expect_keyword(Keyword::Use, "`use`")?;
840        let mut path = vec![self.expect_ident()?];
841        while self.eat(&TokenKind::Dot) {
842            path.push(self.expect_ident()?);
843        }
844        Ok(Use {
845            path,
846            span: start.to(self.prev_span()),
847        })
848    }
849
850    fn parse_item(&mut self, doc: Option<String>) -> PResult<Item> {
851        let start = self.span();
852        let modifiers = self.parse_item_modifiers();
853        let keyword = match self.peek() {
854            TokenKind::Keyword(keyword) => Some(*keyword),
855            _ => None,
856        };
857        let kind = match keyword {
858            Some(Keyword::Fn | Keyword::Async) => ItemKind::Fn(self.parse_fn_decl()?),
859            Some(Keyword::Struct) => ItemKind::Struct(self.parse_struct_decl()?),
860            Some(Keyword::Enum) => ItemKind::Enum(self.parse_enum_decl()?),
861            Some(Keyword::Trait) => ItemKind::Trait(self.parse_trait_decl()?),
862            Some(Keyword::Impl) => ItemKind::Impl(self.parse_impl_block()?),
863            Some(Keyword::Type) => ItemKind::TypeAlias(self.parse_type_alias()?),
864            _ => return Err(self.unexpected("a declaration")),
865        };
866        let span = start.to(self.prev_span());
867        if modifiers.is_test && !matches!(kind, ItemKind::Fn(_)) {
868            self.error(
869                Diagnostic::error(
870                    "cove::parse::test_not_a_function",
871                    "`test` marks a function, not this declaration",
872                )
873                .at(span)
874                .rule("`test` marks a `fn` the test runner calls; no other declaration is a test.")
875                .help("Remove `test`, or move the behaviour into a `test fn`."),
876            );
877        }
878        let is_opaque = self.check_opaque(&modifiers, &kind, span);
879        Ok(Item {
880            doc,
881            exported: modifiers.exported,
882            is_test: modifiers.is_test,
883            is_opaque,
884            kind,
885            span,
886        })
887    }
888
889    /// Reads the `export`, `test`, and `opaque` in front of a declaration.
890    ///
891    /// `export` and `test` occupy one position and answer one question —
892    /// who may call this — so a declaration carries at most one of them,
893    /// written once. `opaque` answers the next question rather than the same
894    /// one — how much of an export a caller sees — so it joins an `export`
895    /// instead of competing with it, and [`Parser::check_opaque`] judges it
896    /// once the declaration it describes has been read.
897    ///
898    /// Every modifier is read before anything is reported, rather than
899    /// stopping at the first, so recovery continues at the declaration
900    /// itself however the mistake was written.
901    fn parse_item_modifiers(&mut self) -> ItemModifiers {
902        let mut exported: Option<Span> = None;
903        let mut is_test: Option<Span> = None;
904        let mut opaque: Option<Span> = None;
905        loop {
906            let span = self.span();
907            let (seen, keyword) = if self.at_keyword(Keyword::Export) {
908                (&mut exported, Keyword::Export)
909            } else if self.at_keyword(Keyword::Test) {
910                (&mut is_test, Keyword::Test)
911            } else if self.at_keyword(Keyword::Opaque) {
912                (&mut opaque, Keyword::Opaque)
913            } else {
914                break;
915            };
916            self.bump();
917            let repeated = seen.is_some();
918            seen.get_or_insert(span);
919            if repeated {
920                self.error(
921                    Diagnostic::error(
922                        "cove::parse::repeated_modifier",
923                        format!("`{}` is written twice", keyword.as_str()),
924                    )
925                    .at(span)
926                    .rule("A declaration carries each modifier at most once.")
927                    .help(format!("Remove the second `{}`.", keyword.as_str())),
928                );
929            }
930        }
931        if let (Some(exported), Some(is_test)) = (exported, is_test) {
932            self.error(
933                Diagnostic::error(
934                    "cove::parse::exported_test",
935                    "a `test fn` may not be exported",
936                )
937                .at(exported.to(is_test))
938                .rule(
939                    "A test's whole contract is that the test runner is its only caller, so `test` and `export` cannot both apply to one declaration.",
940                )
941                .help("Remove `export`, or remove `test` and call it like any other declaration."),
942            );
943        }
944        ItemModifiers {
945            // A rejected `export` is dropped rather than kept, so nothing
946            // downstream sees a declaration that is both.
947            exported: exported.is_some() && is_test.is_none(),
948            is_test: is_test.is_some(),
949            opaque,
950        }
951    }
952
953    /// Reports an `opaque` that does not describe an exported struct.
954    ///
955    /// `opaque` says what an `export` hides, so it has nothing to say about
956    /// a declaration that is not exported — that one is module-private
957    /// already — and nothing to say about an enum, whose cases are the
958    /// interface a caller matches on.
959    fn check_opaque(&mut self, modifiers: &ItemModifiers, kind: &ItemKind, span: Span) -> bool {
960        let Some(opaque) = modifiers.opaque else {
961            return false;
962        };
963        if !matches!(kind, ItemKind::Struct(_)) {
964            self.error(
965                Diagnostic::error(
966                    "cove::parse::opaque_not_a_struct",
967                    "`opaque` marks a struct, not this declaration",
968                )
969                .at(span)
970                .rule("`opaque` hides a struct's representation; an exported enum always exports its cases, and every other declaration is its own interface.")
971                .help("Remove `opaque`, or wrap the representation in a struct and export that."),
972            );
973            return false;
974        }
975        if !modifiers.exported {
976            self.error(
977                Diagnostic::error(
978                    "cove::parse::opaque_not_exported",
979                    "`opaque` describes an export, and this declaration is not exported",
980                )
981                .at(opaque)
982                .rule("A declaration without `export` is module-private, so there is no boundary for `opaque` to draw.")
983                .help("Write `export opaque struct`, or remove `opaque`."),
984            );
985            return false;
986        }
987        true
988    }
989
990    /// Reports a `test fn` written anywhere but at the top level of a file.
991    ///
992    /// A test belongs to a module, which is what lets it see the module's
993    /// private declarations; a method or a local function is reached through
994    /// something else, and the runner cannot call it.
995    fn reject_nested_test(&mut self, item: &Item, place: &str) {
996        if !item.is_test {
997            return;
998        }
999        self.error(
1000            Diagnostic::error(
1001                "cove::parse::nested_test",
1002                format!("a `test fn` may not be declared {place}"),
1003            )
1004            .at(item.span)
1005            .rule("A test is a top-level declaration of its module, which is what the test runner calls.")
1006            .help("Move the `test fn` to the top level of the file."),
1007        );
1008    }
1009
1010    fn parse_fn_decl(&mut self) -> PResult<FnDecl> {
1011        let start = self.span();
1012        let is_async = self.eat_keyword(Keyword::Async);
1013        self.expect_keyword(Keyword::Fn, "`fn`")?;
1014        let name = self.expect_ident()?;
1015        let generics = self.parse_generic_params()?;
1016        self.expect(&TokenKind::LParen, "`(`")?;
1017        let (receiver, params) = self.parse_param_list()?;
1018        let return_type = if self.eat(&TokenKind::Arrow) {
1019            Some(self.parse_type()?)
1020        } else {
1021            None
1022        };
1023        let body = self.parse_block()?;
1024        Ok(FnDecl {
1025            name,
1026            is_async,
1027            generics,
1028            receiver,
1029            params,
1030            return_type,
1031            body,
1032            span: start.to(self.prev_span()),
1033        })
1034    }
1035
1036    /// `<T, U: Display + Ordered>`, or nothing.
1037    ///
1038    /// A bound names a trait the type argument must conform to, and is
1039    /// checked at the call site that instantiates the parameter.
1040    fn parse_generic_params(&mut self) -> PResult<Vec<GenericParam>> {
1041        if !self.eat(&TokenKind::Lt) {
1042            return Ok(Vec::new());
1043        }
1044        self.grouped(|parser| {
1045            let mut generics = Vec::new();
1046            while !parser.at(&TokenKind::Gt) && !parser.is_eof() {
1047                generics.push(parser.parse_generic_param()?);
1048                if !parser.eat(&TokenKind::Comma) {
1049                    break;
1050                }
1051            }
1052            parser.expect(&TokenKind::Gt, "`>`")?;
1053            Ok(generics)
1054        })
1055    }
1056
1057    /// `T`, or `T: Display`, or `T: Display + Ordered`.
1058    fn parse_generic_param(&mut self) -> PResult<GenericParam> {
1059        let start = self.span();
1060        let name = self.expect_ident()?;
1061        let mut bounds = Vec::new();
1062        if self.eat(&TokenKind::Colon) {
1063            loop {
1064                bounds.push(self.expect_ident()?);
1065                if !self.eat(&TokenKind::Plus) {
1066                    break;
1067                }
1068            }
1069        }
1070        Ok(GenericParam {
1071            name,
1072            bounds,
1073            span: start.to(self.prev_span()),
1074        })
1075    }
1076
1077    /// Parses a parameter list up to and including its `)`. A leading `self`
1078    /// or `var self` is the method receiver rather than a parameter.
1079    fn parse_param_list(&mut self) -> PResult<(Option<Receiver>, Vec<Param>)> {
1080        self.grouped(Parser::parse_param_list_inner)
1081    }
1082
1083    fn parse_param_list_inner(&mut self) -> PResult<(Option<Receiver>, Vec<Param>)> {
1084        let mut receiver = None;
1085        let mut params = Vec::new();
1086        let mut first = true;
1087
1088        while !self.at(&TokenKind::RParen) && !self.is_eof() {
1089            if first {
1090                first = false;
1091                if let Some(parsed) = self.try_receiver() {
1092                    receiver = Some(parsed);
1093                    if !self.eat(&TokenKind::Comma) {
1094                        break;
1095                    }
1096                    continue;
1097                }
1098            }
1099            params.push(self.parse_param()?);
1100            if !self.eat(&TokenKind::Comma) {
1101                break;
1102            }
1103        }
1104
1105        self.expect(&TokenKind::RParen, "`)`")?;
1106        Ok((receiver, params))
1107    }
1108
1109    fn try_receiver(&mut self) -> Option<Receiver> {
1110        let start = self.span();
1111        if self.at_keyword(Keyword::SelfValue) {
1112            self.bump();
1113            return Some(Receiver {
1114                is_var: false,
1115                span: start,
1116            });
1117        }
1118        if self.at_keyword(Keyword::Var)
1119            && matches!(self.peek_at(1), TokenKind::Keyword(Keyword::SelfValue))
1120        {
1121            self.bump();
1122            self.bump();
1123            return Some(Receiver {
1124                is_var: true,
1125                span: start.to(self.prev_span()),
1126            });
1127        }
1128        None
1129    }
1130
1131    /// `[var] name [: Type] [...] [= default]`.
1132    fn parse_param(&mut self) -> PResult<Param> {
1133        let start = self.span();
1134        let is_var = self.eat_keyword(Keyword::Var);
1135        let name = self.expect_ident()?;
1136        let ty = if self.eat(&TokenKind::Colon) {
1137            Some(self.parse_type()?)
1138        } else {
1139            None
1140        };
1141        let variadic = self.eat(&TokenKind::Ellipsis);
1142        let default = if self.eat(&TokenKind::Eq) {
1143            Some(self.parse_expr()?)
1144        } else {
1145            None
1146        };
1147        Ok(Param {
1148            is_var,
1149            name,
1150            ty,
1151            variadic,
1152            default,
1153            span: start.to(self.prev_span()),
1154        })
1155    }
1156
1157    /// `struct Name { field: Type ... }`, and the parenthesised
1158    /// `struct Name(field: Type, ...)` form. Fields are separated by newlines,
1159    /// commas, or both.
1160    fn parse_struct_decl(&mut self) -> PResult<StructDecl> {
1161        let start = self.expect_keyword(Keyword::Struct, "`struct`")?;
1162        let name = self.expect_ident()?;
1163        let generics = self.parse_generic_params()?;
1164        let close = if self.eat(&TokenKind::LBrace) {
1165            TokenKind::RBrace
1166        } else if self.eat(&TokenKind::LParen) {
1167            TokenKind::RParen
1168        } else {
1169            return Err(self.unexpected("`{` or `(`"));
1170        };
1171
1172        let mut fields = Vec::new();
1173        while !self.at(&close) && !self.is_eof() {
1174            let doc = self.collect_doc();
1175            if self.at(&close) {
1176                if let Some((_, span)) = doc {
1177                    self.dangling_doc(span);
1178                }
1179                break;
1180            }
1181            let field_start = self.span();
1182            let field_name = self.expect_ident()?;
1183            self.expect(&TokenKind::Colon, "`:`")?;
1184            let ty = self.parse_type()?;
1185            fields.push(Field {
1186                doc: doc.map(|(text, _)| text),
1187                name: field_name,
1188                ty,
1189                span: field_start.to(self.prev_span()),
1190            });
1191            self.eat(&TokenKind::Comma);
1192        }
1193        self.expect(&close, "`}`")?;
1194
1195        Ok(StructDecl {
1196            name,
1197            generics,
1198            fields,
1199            span: start.to(self.prev_span()),
1200        })
1201    }
1202
1203    /// `enum Name { Case  Case(Type, Type) ... }`, with cases separated by
1204    /// newlines, commas, or both.
1205    fn parse_enum_decl(&mut self) -> PResult<EnumDecl> {
1206        let start = self.expect_keyword(Keyword::Enum, "`enum`")?;
1207        let name = self.expect_ident()?;
1208        let generics = self.parse_generic_params()?;
1209        self.expect(&TokenKind::LBrace, "`{`")?;
1210
1211        let mut cases = Vec::new();
1212        while !self.at(&TokenKind::RBrace) && !self.is_eof() {
1213            let doc = self.collect_doc();
1214            if self.at(&TokenKind::RBrace) {
1215                if let Some((_, span)) = doc {
1216                    self.dangling_doc(span);
1217                }
1218                break;
1219            }
1220            let case_start = self.span();
1221            let case_name = self.expect_ident()?;
1222            let mut payload = Vec::new();
1223            if self.eat(&TokenKind::LParen) {
1224                while !self.at(&TokenKind::RParen) && !self.is_eof() {
1225                    payload.push(self.parse_type()?);
1226                    if !self.eat(&TokenKind::Comma) {
1227                        break;
1228                    }
1229                }
1230                self.expect(&TokenKind::RParen, "`)`")?;
1231            }
1232            cases.push(EnumCase {
1233                doc: doc.map(|(text, _)| text),
1234                name: case_name,
1235                payload,
1236                span: case_start.to(self.prev_span()),
1237            });
1238            self.eat(&TokenKind::Comma);
1239        }
1240        self.expect(&TokenKind::RBrace, "`}`")?;
1241
1242        Ok(EnumDecl {
1243            name,
1244            generics,
1245            cases,
1246            span: start.to(self.prev_span()),
1247        })
1248    }
1249
1250    /// `trait Name { fn method(self) -> T ... }`.
1251    ///
1252    /// A method may end at its signature, which makes it required, or carry a
1253    /// `{ ... }` default body, which makes it optional for a conformance.
1254    fn parse_trait_decl(&mut self) -> PResult<TraitDecl> {
1255        let start = self.expect_keyword(Keyword::Trait, "`trait`")?;
1256        let name = self.expect_ident()?;
1257        self.expect(&TokenKind::LBrace, "`{`")?;
1258
1259        let mut methods = Vec::new();
1260        while !self.at(&TokenKind::RBrace) && !self.is_eof() {
1261            let doc = self.collect_doc();
1262            if self.at(&TokenKind::RBrace) {
1263                if let Some((_, span)) = doc {
1264                    self.dangling_doc(span);
1265                }
1266                break;
1267            }
1268            match self.parse_trait_method(doc.map(|(text, _)| text)) {
1269                Ok(method) => methods.push(method),
1270                Err(Bail) => self.recover_to_item(true),
1271            }
1272        }
1273        self.expect(&TokenKind::RBrace, "`}`")?;
1274
1275        Ok(TraitDecl {
1276            name,
1277            methods,
1278            span: start.to(self.prev_span()),
1279        })
1280    }
1281
1282    /// One method of a trait. A trait declares no generic methods in the MVP,
1283    /// so a method binds no type parameters of its own.
1284    fn parse_trait_method(&mut self, doc: Option<String>) -> PResult<TraitMethod> {
1285        let start = self.span();
1286        let is_async = self.eat_keyword(Keyword::Async);
1287        self.expect_keyword(Keyword::Fn, "`fn`")?;
1288        let name = self.expect_ident()?;
1289        self.expect(&TokenKind::LParen, "`(`")?;
1290        let (receiver, params) = self.parse_param_list()?;
1291        let return_type = if self.eat(&TokenKind::Arrow) {
1292            Some(self.parse_type()?)
1293        } else {
1294            None
1295        };
1296        // A `{` on the same logical line opens a default body; a signature
1297        // that ends at the line break declares the method without one.
1298        let default = if self.at(&TokenKind::LBrace) && !self.at_statement_break() {
1299            Some(self.parse_block()?)
1300        } else {
1301            None
1302        };
1303        Ok(TraitMethod {
1304            doc,
1305            name,
1306            is_async,
1307            receiver,
1308            params,
1309            return_type,
1310            default,
1311            span: start.to(self.prev_span()),
1312        })
1313    }
1314
1315    /// `impl Type { ... }`, or `impl Trait for Type { ... }`.
1316    fn parse_impl_block(&mut self) -> PResult<ImplBlock> {
1317        let start = self.expect_keyword(Keyword::Impl, "`impl`")?;
1318        let mut trait_name = None;
1319        let mut type_name = self.expect_ident()?;
1320        if self.eat_keyword(Keyword::For) {
1321            trait_name = Some(type_name);
1322            type_name = self.expect_ident()?;
1323        }
1324        let generics = self.parse_generic_params()?;
1325        self.expect(&TokenKind::LBrace, "`{`")?;
1326
1327        let mut items = Vec::new();
1328        while !self.at(&TokenKind::RBrace) && !self.is_eof() {
1329            let doc = self.collect_doc();
1330            if !self.at_item_start() {
1331                match doc {
1332                    Some((_, span)) => self.dangling_doc(span),
1333                    None => {
1334                        self.unexpected("a declaration");
1335                    }
1336                }
1337                self.recover_to_item(true);
1338                continue;
1339            }
1340            match self.parse_item(doc.map(|(text, _)| text)) {
1341                Ok(item) => {
1342                    self.reject_nested_test(&item, "inside an `impl` block");
1343                    items.push(item);
1344                }
1345                Err(Bail) => self.recover_to_item(true),
1346            }
1347        }
1348        self.expect(&TokenKind::RBrace, "`}`")?;
1349
1350        Ok(ImplBlock {
1351            trait_name,
1352            type_name,
1353            generics,
1354            items,
1355            span: start.to(self.prev_span()),
1356        })
1357    }
1358
1359    fn parse_type_alias(&mut self) -> PResult<TypeAlias> {
1360        let start = self.expect_keyword(Keyword::Type, "`type`")?;
1361        let name = self.expect_ident()?;
1362        let generics = self.parse_generic_params()?;
1363        self.expect(&TokenKind::Eq, "`=`")?;
1364        let ty = self.parse_type()?;
1365        Ok(TypeAlias {
1366            name,
1367            generics,
1368            ty,
1369            span: start.to(self.prev_span()),
1370        })
1371    }
1372}
1373
1374/// Types.
1375impl Parser<'_> {
1376    fn parse_type(&mut self) -> PResult<Type> {
1377        self.nested(Parser::parse_type_inner)
1378    }
1379
1380    fn parse_type_inner(&mut self) -> PResult<Type> {
1381        let start = self.span();
1382        let kind = match self.peek() {
1383            TokenKind::LParen => {
1384                self.bump();
1385                self.expect(&TokenKind::RParen, "`)`")?;
1386                TypeKind::Unit
1387            }
1388            TokenKind::Keyword(Keyword::Async | Keyword::Fn) => self.parse_fn_type()?,
1389            TokenKind::Keyword(Keyword::Dyn) => {
1390                self.bump();
1391                TypeKind::Dyn(self.expect_ident()?)
1392            }
1393            TokenKind::Ident(_) => {
1394                let mut path = vec![self.expect_ident()?];
1395                while self.at(&TokenKind::Dot) && matches!(self.peek_at(1), TokenKind::Ident(_)) {
1396                    self.bump();
1397                    path.push(self.expect_ident()?);
1398                }
1399                let args = if self.at(&TokenKind::Lt) {
1400                    self.parse_type_args()?
1401                } else {
1402                    Vec::new()
1403                };
1404                TypeKind::Named { path, args }
1405            }
1406            _ => return Err(self.unexpected("a type")),
1407        };
1408        Ok(Type {
1409            kind,
1410            span: start.to(self.prev_span()),
1411        })
1412    }
1413
1414    fn parse_fn_type(&mut self) -> PResult<TypeKind> {
1415        let is_async = self.eat_keyword(Keyword::Async);
1416        self.expect_keyword(Keyword::Fn, "`fn`")?;
1417        self.expect(&TokenKind::LParen, "`(`")?;
1418        let params = self.grouped(|parser| {
1419            let mut params = Vec::new();
1420            while !parser.at(&TokenKind::RParen) && !parser.is_eof() {
1421                params.push(parser.parse_fn_type_param()?);
1422                if !parser.eat(&TokenKind::Comma) {
1423                    break;
1424                }
1425            }
1426            parser.expect(&TokenKind::RParen, "`)`")?;
1427            Ok(params)
1428        })?;
1429        let return_type = if self.eat(&TokenKind::Arrow) {
1430            Some(Box::new(self.parse_type()?))
1431        } else {
1432            None
1433        };
1434        Ok(TypeKind::Fn {
1435            is_async,
1436            params,
1437            return_type,
1438        })
1439    }
1440
1441    /// A function-type parameter is either named (`request: http.Request`) or
1442    /// bare (`String`); a bare parameter has an empty name.
1443    fn parse_fn_type_param(&mut self) -> PResult<Param> {
1444        let start = self.span();
1445        let is_var = self.eat_keyword(Keyword::Var);
1446        if matches!(self.peek(), TokenKind::Ident(_)) && self.peek_at(1) == &TokenKind::Colon {
1447            let name = self.expect_ident()?;
1448            self.bump();
1449            let ty = self.parse_type()?;
1450            let variadic = self.eat(&TokenKind::Ellipsis);
1451            return Ok(Param {
1452                is_var,
1453                name,
1454                ty: Some(ty),
1455                variadic,
1456                default: None,
1457                span: start.to(self.prev_span()),
1458            });
1459        }
1460        let ty = self.parse_type()?;
1461        let variadic = self.eat(&TokenKind::Ellipsis);
1462        let span = start.to(self.prev_span());
1463        Ok(Param {
1464            is_var,
1465            name: Spanned::new(String::new(), span),
1466            ty: Some(ty),
1467            variadic,
1468            default: None,
1469            span,
1470        })
1471    }
1472
1473    /// `<T, Result<U, E>>`. The lexer never joins `>>`, so nested generic
1474    /// arguments close naturally.
1475    fn parse_type_args(&mut self) -> PResult<Vec<Type>> {
1476        self.expect(&TokenKind::Lt, "`<`")?;
1477        self.grouped(|parser| {
1478            let mut args = Vec::new();
1479            while !parser.at(&TokenKind::Gt) && !parser.is_eof() {
1480                args.push(parser.parse_type()?);
1481                if !parser.eat(&TokenKind::Comma) {
1482                    break;
1483                }
1484            }
1485            parser.expect(&TokenKind::Gt, "`>`")?;
1486            Ok(args)
1487        })
1488    }
1489}
1490
1491/// Blocks and statements.
1492impl Parser<'_> {
1493    /// Parses `{ ... }`. The last statement, when it is an expression,
1494    /// becomes the block's value.
1495    fn parse_block(&mut self) -> PResult<Block> {
1496        self.nested(Parser::parse_block_inner)
1497    }
1498
1499    fn parse_block_inner(&mut self) -> PResult<Block> {
1500        let start = self.span();
1501        self.expect(&TokenKind::LBrace, "`{`")?;
1502
1503        let mut statements = Vec::new();
1504        self.ungrouped(|parser| {
1505            parser.scoped(false, |parser| {
1506                while !parser.at(&TokenKind::RBrace) && !parser.is_eof() {
1507                    match parser.parse_stmt() {
1508                        Ok(stmt) => {
1509                            parser.check_detached_trailing_closure(&stmt);
1510                            statements.push(stmt);
1511                        }
1512                        Err(Bail) => parser.recover_in_block(),
1513                    }
1514                }
1515            })
1516        });
1517
1518        let end = self.span();
1519        self.expect(&TokenKind::RBrace, "`}`")?;
1520
1521        let mut tail = None;
1522        if matches!(
1523            statements.last(),
1524            Some(Stmt {
1525                kind: StmtKind::Expr(_),
1526                ..
1527            })
1528        ) {
1529            if let Some(Stmt {
1530                kind: StmtKind::Expr(value),
1531                ..
1532            }) = statements.pop()
1533            {
1534                tail = Some(Box::new(value));
1535            }
1536        }
1537
1538        Ok(Block {
1539            statements,
1540            tail,
1541            span: start.to(end),
1542        })
1543    }
1544
1545    /// Reports the one shape the newline rule silently changes the meaning
1546    /// of: a statement that is only a name or a field access, followed by a
1547    /// `{` on the next line. Such a statement computes nothing on its own, so
1548    /// the block was meant to be its trailing closure and must start on the
1549    /// same line.
1550    fn check_detached_trailing_closure(&mut self, stmt: &Stmt) {
1551        if !matches!(
1552            &stmt.kind,
1553            StmtKind::Expr(Expr {
1554                kind: ExprKind::Ident(_) | ExprKind::Field { .. },
1555                ..
1556            })
1557        ) {
1558            return;
1559        }
1560        if !self.at(&TokenKind::LBrace) || !self.at_statement_break() {
1561            return;
1562        }
1563        let span = self.span();
1564        self.error(
1565            Diagnostic::error(
1566                "cove::parse::newline_before_trailing_closure",
1567                "a newline ended the statement before this `{`",
1568            )
1569            .at(span)
1570            .label(stmt.span, "this expression is already complete")
1571            .rule(
1572                "A newline ends a statement when the expression before it is complete, so a \
1573                 trailing closure begins on the same line as the call it belongs to.",
1574            )
1575            .help("Move `{` up onto the previous line."),
1576        );
1577    }
1578
1579    fn parse_stmt(&mut self) -> PResult<Stmt> {
1580        let doc = self.collect_doc();
1581
1582        if self.at_item_start() {
1583            let item = self.parse_item(doc.map(|(text, _)| text))?;
1584            self.reject_nested_test(&item, "inside a block");
1585            let span = item.span;
1586            return Ok(Stmt {
1587                kind: StmtKind::Item(Box::new(item)),
1588                span,
1589            });
1590        }
1591        if let Some((_, span)) = doc {
1592            self.dangling_doc(span);
1593        }
1594
1595        if self.at_keyword(Keyword::Let) || self.at_keyword(Keyword::Var) {
1596            return self.parse_let_stmt();
1597        }
1598
1599        let value = self.parse_expr()?;
1600        Ok(Stmt {
1601            span: value.span,
1602            kind: StmtKind::Expr(value),
1603        })
1604    }
1605
1606    /// `let name: T = value` and `var name = value`.
1607    fn parse_let_stmt(&mut self) -> PResult<Stmt> {
1608        let start = self.span();
1609        let is_var = self.at_keyword(Keyword::Var);
1610        self.bump();
1611        let name = self.expect_ident()?;
1612        let ty = if self.eat(&TokenKind::Colon) {
1613            Some(self.parse_type()?)
1614        } else {
1615            None
1616        };
1617        self.expect(&TokenKind::Eq, "`=`")?;
1618        let value = self.parse_expr()?;
1619        Ok(Stmt {
1620            kind: StmtKind::Let {
1621                is_var,
1622                name,
1623                ty,
1624                value,
1625            },
1626            span: start.to(self.prev_span()),
1627        })
1628    }
1629}
1630
1631/// Expressions.
1632impl Parser<'_> {
1633    fn parse_expr(&mut self) -> PResult<Expr> {
1634        self.nested(Parser::parse_assign)
1635    }
1636
1637    fn parse_assign(&mut self) -> PResult<Expr> {
1638        let target = self.parse_or()?;
1639        if self.at_statement_break() {
1640            return Ok(target);
1641        }
1642        let op = match self.peek() {
1643            TokenKind::Eq => None,
1644            TokenKind::PlusEq => Some(BinaryOp::Add),
1645            TokenKind::MinusEq => Some(BinaryOp::Sub),
1646            TokenKind::StarEq => Some(BinaryOp::Mul),
1647            TokenKind::SlashEq => Some(BinaryOp::Div),
1648            TokenKind::PercentEq => Some(BinaryOp::Rem),
1649            _ => return Ok(target),
1650        };
1651        self.bump();
1652        let value = self.nested(Parser::parse_assign)?;
1653
1654        if !is_place_expr(&target) {
1655            self.error(
1656                Diagnostic::error(
1657                    "cove::parse::invalid_assignment_target",
1658                    "this expression cannot be assigned to",
1659                )
1660                .at(target.span)
1661                .rule("Assignment writes to a place: a name, or a field of a place.")
1662                .help("Assign to a variable or a field, such as `self.count = 1`."),
1663            );
1664        }
1665
1666        let span = target.span.to(value.span);
1667        Ok(expr(
1668            ExprKind::Assign {
1669                op,
1670                target: Box::new(target),
1671                value: Box::new(value),
1672            },
1673            span,
1674        ))
1675    }
1676
1677    fn parse_or(&mut self) -> PResult<Expr> {
1678        self.chained(|parser| {
1679            let mut lhs = parser.parse_and()?;
1680            while parser.at(&TokenKind::PipePipe) && !parser.at_statement_break() {
1681                parser.bump();
1682                parser.link()?;
1683                let rhs = parser.parse_and()?;
1684                lhs = binary(BinaryOp::Or, lhs, rhs);
1685            }
1686            Ok(lhs)
1687        })
1688    }
1689
1690    fn parse_and(&mut self) -> PResult<Expr> {
1691        self.chained(|parser| {
1692            let mut lhs = parser.parse_comparison()?;
1693            while parser.at(&TokenKind::AmpAmp) && !parser.at_statement_break() {
1694                parser.bump();
1695                parser.link()?;
1696                let rhs = parser.parse_comparison()?;
1697                lhs = binary(BinaryOp::And, lhs, rhs);
1698            }
1699            Ok(lhs)
1700        })
1701    }
1702
1703    fn parse_comparison(&mut self) -> PResult<Expr> {
1704        self.chained(|parser| {
1705            let mut lhs = parser.parse_range()?;
1706            loop {
1707                if parser.at_statement_break() {
1708                    return Ok(lhs);
1709                }
1710                let op = match parser.peek() {
1711                    TokenKind::EqEq => BinaryOp::Eq,
1712                    TokenKind::BangEq => BinaryOp::Ne,
1713                    TokenKind::Lt => BinaryOp::Lt,
1714                    TokenKind::LtEq => BinaryOp::Le,
1715                    TokenKind::Gt => BinaryOp::Gt,
1716                    TokenKind::GtEq => BinaryOp::Ge,
1717                    // `is` compares identity at the same precedence as `==`: the
1718                    // Language Card lists it alongside value equality, and giving
1719                    // it a different tier would make `a == b is c` guess which
1720                    // question is asked first.
1721                    TokenKind::Keyword(Keyword::Is) => BinaryOp::Is,
1722                    _ => return Ok(lhs),
1723                };
1724                parser.bump();
1725                parser.link()?;
1726                let rhs = parser.parse_range()?;
1727                lhs = binary(op, lhs, rhs);
1728            }
1729        })
1730    }
1731
1732    /// `0..<attempts` excludes its end; `0..n` includes it.
1733    fn parse_range(&mut self) -> PResult<Expr> {
1734        let start = self.parse_additive()?;
1735        if self.at_statement_break() {
1736            return Ok(start);
1737        }
1738        let inclusive_end = match self.peek() {
1739            TokenKind::DotDot => true,
1740            TokenKind::DotDotLt => false,
1741            _ => return Ok(start),
1742        };
1743        self.bump();
1744        let end = self.parse_additive()?;
1745        let span = start.span.to(end.span);
1746        Ok(expr(
1747            ExprKind::Range {
1748                start: Box::new(start),
1749                end: Box::new(end),
1750                inclusive_end,
1751            },
1752            span,
1753        ))
1754    }
1755
1756    fn parse_additive(&mut self) -> PResult<Expr> {
1757        self.chained(|parser| {
1758            let mut lhs = parser.parse_multiplicative()?;
1759            loop {
1760                if parser.at_statement_break() {
1761                    return Ok(lhs);
1762                }
1763                let op = match parser.peek() {
1764                    TokenKind::Plus => BinaryOp::Add,
1765                    TokenKind::Minus => BinaryOp::Sub,
1766                    _ => return Ok(lhs),
1767                };
1768                parser.bump();
1769                parser.link()?;
1770                let rhs = parser.parse_multiplicative()?;
1771                lhs = binary(op, lhs, rhs);
1772            }
1773        })
1774    }
1775
1776    fn parse_multiplicative(&mut self) -> PResult<Expr> {
1777        self.chained(|parser| {
1778            let mut lhs = parser.parse_unary()?;
1779            loop {
1780                if parser.at_statement_break() {
1781                    return Ok(lhs);
1782                }
1783                let op = match parser.peek() {
1784                    TokenKind::Star => BinaryOp::Mul,
1785                    TokenKind::Slash => BinaryOp::Div,
1786                    TokenKind::Percent => BinaryOp::Rem,
1787                    _ => return Ok(lhs),
1788                };
1789                parser.bump();
1790                parser.link()?;
1791                let rhs = parser.parse_unary()?;
1792                lhs = binary(op, lhs, rhs);
1793            }
1794        })
1795    }
1796
1797    /// `await` binds tighter than any binary operator and tighter than a
1798    /// trailing `?`, so `await handler(event)?` awaits the call and then
1799    /// propagates the error from the `Result` the task produced: `Try(Await(Call))`.
1800    /// A `?` in the middle of the chain, followed by more postfix operators,
1801    /// stays part of the operand instead: `await f()?.g()` is
1802    /// `Await(Field(Try(Call), g))`, not `Try(Await(...))`, because only a `?`
1803    /// that ends the whole chain escapes outside the `Await`.
1804    fn parse_unary(&mut self) -> PResult<Expr> {
1805        let start = self.span();
1806        let op = match self.peek() {
1807            TokenKind::Bang => Some(UnaryOp::Not),
1808            TokenKind::Minus => Some(UnaryOp::Neg),
1809            TokenKind::Keyword(Keyword::Await) => None,
1810            _ => return self.parse_postfix(),
1811        };
1812        match op {
1813            Some(op) => {
1814                self.bump();
1815                let operand = self.nested(Parser::parse_unary)?;
1816                let span = start.to(operand.span);
1817                Ok(expr(
1818                    ExprKind::Unary {
1819                        op,
1820                        operand: Box::new(operand),
1821                    },
1822                    span,
1823                ))
1824            }
1825            None => {
1826                self.bump();
1827                let operand = self.parse_postfix()?;
1828                let operand_span = operand.span;
1829                Ok(match operand.kind {
1830                    ExprKind::Try(inner) => {
1831                        let await_span = start.to(inner.span);
1832                        let awaited = expr(ExprKind::Await(inner), await_span);
1833                        expr(ExprKind::Try(Box::new(awaited)), start.to(operand_span))
1834                    }
1835                    _ => expr(ExprKind::Await(Box::new(operand)), start.to(operand_span)),
1836                })
1837            }
1838        }
1839    }
1840
1841    fn parse_postfix(&mut self) -> PResult<Expr> {
1842        self.chained(|parser| {
1843            let mut value = parser.parse_primary()?;
1844            loop {
1845                // `(`, `<`, and `{` continue the expression only optionally, so a
1846                // line break before them ends the statement instead. `.` and `?`
1847                // can never start one, so they always continue.
1848                let stop = parser.at_statement_break();
1849                match parser.peek() {
1850                    TokenKind::Dot => {
1851                        parser.link()?;
1852                        parser.bump();
1853                        let name = parser.expect_member_name()?;
1854                        let span = value.span.to(name.span);
1855                        value = expr(
1856                            ExprKind::Field {
1857                                base: Box::new(value),
1858                                name,
1859                            },
1860                            span,
1861                        );
1862                    }
1863                    TokenKind::LParen if !stop => {
1864                        parser.link()?;
1865                        parser.bump();
1866                        let args = parser.parse_args()?;
1867                        value = parser.finish_call(value, Vec::new(), args)?;
1868                    }
1869                    TokenKind::Question => {
1870                        parser.link()?;
1871                        let span = value.span.to(parser.span());
1872                        parser.bump();
1873                        value = expr(ExprKind::Try(Box::new(value)), span);
1874                    }
1875                    TokenKind::Lt if !stop => {
1876                        parser.link()?;
1877                        match parser.try_generic_call(value)? {
1878                            Ok(call) => value = call,
1879                            Err(unchanged) => return Ok(unchanged),
1880                        }
1881                    }
1882                    TokenKind::LBrace
1883                        if !stop
1884                            && !parser.no_trailing_closure
1885                            && can_take_trailing_closure(&value) =>
1886                    {
1887                        parser.link()?;
1888                        let closure = parser.parse_trailing_closure()?;
1889                        let span = value.span.to(closure.span);
1890                        value = expr(
1891                            ExprKind::Call {
1892                                callee: Box::new(value),
1893                                generics: Vec::new(),
1894                                args: Vec::new(),
1895                                trailing: Some(Box::new(closure)),
1896                            },
1897                            span,
1898                        );
1899                    }
1900                    _ => return Ok(value),
1901                }
1902            }
1903        })
1904    }
1905
1906    /// Builds a call, attaching `f(x) { ... }`-style trailing closures.
1907    fn finish_call(&mut self, callee: Expr, generics: Vec<Type>, args: Vec<Arg>) -> PResult<Expr> {
1908        let mut span = callee.span.to(self.prev_span());
1909        let trailing = if !self.no_trailing_closure
1910            && self.at(&TokenKind::LBrace)
1911            && !self.at_statement_break()
1912        {
1913            let closure = self.parse_trailing_closure()?;
1914            span = span.to(closure.span);
1915            Some(Box::new(closure))
1916        } else {
1917            None
1918        };
1919        Ok(expr(
1920            ExprKind::Call {
1921                callee: Box::new(callee),
1922                generics,
1923                args,
1924                trailing,
1925            },
1926            span,
1927        ))
1928    }
1929
1930    /// A trailing closure is a parameterless lambda written as a block.
1931    fn parse_trailing_closure(&mut self) -> PResult<Expr> {
1932        let body = self.parse_block()?;
1933        let span = body.span;
1934        Ok(expr(
1935            ExprKind::Lambda {
1936                is_async: false,
1937                params: Vec::new(),
1938                body,
1939            },
1940            span,
1941        ))
1942    }
1943
1944    /// Resolves the `<` ambiguity by speculation: `api.fetch<Array<Booking>>(...)`
1945    /// is a generic call only when a type list closed by `>` is immediately
1946    /// followed by `(`. Otherwise the cursor rewinds and `<` stays a
1947    /// comparison operator.
1948    #[allow(clippy::type_complexity)]
1949    fn try_generic_call(&mut self, callee: Expr) -> PResult<Result<Expr, Expr>> {
1950        let saved_pos = self.pos;
1951        let saved_diagnostics = self.diagnostics.len();
1952
1953        let generics = match self.parse_type_args() {
1954            Ok(generics) if self.at(&TokenKind::LParen) => generics,
1955            _ => {
1956                self.pos = saved_pos;
1957                self.diagnostics.truncate(saved_diagnostics);
1958                return Ok(Err(callee));
1959            }
1960        };
1961
1962        self.bump();
1963        let args = self.parse_args()?;
1964        Ok(Ok(self.finish_call(callee, generics, args)?))
1965    }
1966
1967    /// Parses arguments up to and including `)`. Line breaks inside the
1968    /// parentheses never end a statement, so an argument list may span lines.
1969    fn parse_args(&mut self) -> PResult<Vec<Arg>> {
1970        self.grouped(|parser| parser.scoped(false, Parser::parse_arg_list))
1971    }
1972
1973    fn parse_arg_list(&mut self) -> PResult<Vec<Arg>> {
1974        let mut args: Vec<Arg> = Vec::new();
1975        let mut first_label: Option<Span> = None;
1976
1977        while !self.at(&TokenKind::RParen) && !self.is_eof() {
1978            let start = self.span();
1979            let label = if matches!(self.peek(), TokenKind::Ident(_))
1980                && self.peek_at(1) == &TokenKind::Colon
1981            {
1982                let label = self.expect_ident()?;
1983                self.bump();
1984                Some(label)
1985            } else {
1986                None
1987            };
1988
1989            match (&label, first_label) {
1990                (Some(label), None) => first_label = Some(label.span),
1991                (None, Some(previous)) => self.error(
1992                    Diagnostic::error(
1993                        "cove::parse::positional_after_label",
1994                        "a positional argument cannot follow a labeled argument",
1995                    )
1996                    .at(start)
1997                    .label(previous, "the first labeled argument is here")
1998                    .rule(
1999                        "Positional arguments may precede labeled arguments; after the first \
2000                         label, every remaining argument is labeled.",
2001                    )
2002                    .help("Give this argument its parameter label, such as `name: value`."),
2003                ),
2004                _ => {}
2005            }
2006
2007            let is_var = self.eat_keyword(Keyword::Var);
2008            let spread = self.eat(&TokenKind::Ellipsis);
2009            let value = self.parse_expr()?;
2010            args.push(Arg {
2011                label,
2012                is_var,
2013                spread,
2014                value,
2015                span: start.to(self.prev_span()),
2016            });
2017
2018            if !self.eat(&TokenKind::Comma) {
2019                break;
2020            }
2021        }
2022
2023        self.expect(&TokenKind::RParen, "`)`")?;
2024        Ok(args)
2025    }
2026
2027    /// Parses the elements of an array literal up to and including `]`.
2028    fn parse_array_elements(&mut self) -> PResult<Vec<Expr>> {
2029        let mut elements = Vec::new();
2030        while !self.at(&TokenKind::RBracket) && !self.is_eof() {
2031            elements.push(self.parse_expr()?);
2032            if !self.eat(&TokenKind::Comma) {
2033                break;
2034            }
2035        }
2036        self.expect(&TokenKind::RBracket, "`]`")?;
2037        Ok(elements)
2038    }
2039
2040    fn parse_primary(&mut self) -> PResult<Expr> {
2041        let start = self.span();
2042        let kind = self.peek().clone();
2043        match kind {
2044            TokenKind::Int(value) => {
2045                self.bump();
2046                Ok(expr(ExprKind::Int(value), start))
2047            }
2048            TokenKind::Float(value) => {
2049                self.bump();
2050                Ok(expr(ExprKind::Float(value), start))
2051            }
2052            TokenKind::Bool(value) => {
2053                self.bump();
2054                Ok(expr(ExprKind::Bool(value), start))
2055            }
2056            TokenKind::Duration(value) => {
2057                self.bump();
2058                Ok(expr(ExprKind::Duration(value), start))
2059            }
2060            TokenKind::Str(parts) => {
2061                self.bump();
2062                let parts = self.parse_str_parts(&parts);
2063                Ok(expr(ExprKind::Str(parts), start))
2064            }
2065            TokenKind::Ident(name) => {
2066                self.bump();
2067                Ok(expr(ExprKind::Ident(name), start))
2068            }
2069            TokenKind::Keyword(Keyword::SelfValue) => {
2070                self.bump();
2071                Ok(expr(ExprKind::Ident("self".into()), start))
2072            }
2073            TokenKind::LParen => {
2074                self.bump();
2075                if self.at(&TokenKind::RParen) {
2076                    self.bump();
2077                    return Ok(expr(ExprKind::Unit, start.to(self.prev_span())));
2078                }
2079                let inner = self.grouped(|parser| parser.scoped(false, Parser::parse_expr))?;
2080                self.expect(&TokenKind::RParen, "`)`")?;
2081                Ok(expr(inner.kind, start.to(self.prev_span())))
2082            }
2083            TokenKind::LBracket => {
2084                self.bump();
2085                let elements =
2086                    self.grouped(|parser| parser.scoped(false, Parser::parse_array_elements))?;
2087                Ok(expr(
2088                    ExprKind::ArrayLit(elements),
2089                    start.to(self.prev_span()),
2090                ))
2091            }
2092            TokenKind::LBrace => {
2093                let block = self.parse_block()?;
2094                let span = block.span;
2095                Ok(expr(ExprKind::Block(block), span))
2096            }
2097            TokenKind::Keyword(Keyword::If) => self.parse_if(),
2098            TokenKind::Keyword(Keyword::Match) => self.parse_match(),
2099            TokenKind::Keyword(Keyword::For) => self.parse_for(),
2100            TokenKind::Keyword(Keyword::While) => self.parse_while(),
2101            TokenKind::Keyword(Keyword::Scope) => self.parse_scope(),
2102            TokenKind::Keyword(Keyword::Return) => {
2103                self.bump();
2104                let value = if self.at_operand() {
2105                    Some(Box::new(self.parse_expr()?))
2106                } else {
2107                    None
2108                };
2109                Ok(expr(ExprKind::Return(value), start.to(self.prev_span())))
2110            }
2111            TokenKind::Keyword(Keyword::Break) => {
2112                self.bump();
2113                let value = if self.at_operand() {
2114                    Some(Box::new(self.parse_expr()?))
2115                } else {
2116                    None
2117                };
2118                Ok(expr(ExprKind::Break(value), start.to(self.prev_span())))
2119            }
2120            TokenKind::Keyword(Keyword::Continue) => {
2121                self.bump();
2122                Ok(expr(ExprKind::Continue, start.to(self.prev_span())))
2123            }
2124            TokenKind::Keyword(Keyword::Fn | Keyword::Async) => self.parse_lambda(),
2125            _ => Err(self.expected_expression()),
2126        }
2127    }
2128
2129    /// Whether the operand of a keyword that takes an optional one — `break`
2130    /// or `return` — begins at the cursor.
2131    ///
2132    /// The operand must *start* on the keyword's own line. A line break
2133    /// between the keyword and the next token ends the statement, exactly as
2134    /// Go inserts a semicolon after `break`, `continue`, and `return` at the
2135    /// end of a line. Without this, a `break` alone on its line reaches across
2136    /// the line ending and takes the statement after it as its operand, which
2137    /// nothing downstream complains about, because a `break` operand is
2138    /// discarded — and then the formatter writes the misreading back into the
2139    /// source, where it is no longer visible as a mistake.
2140    ///
2141    /// Only the operand's *first* token is constrained, so an operand that
2142    /// opens on the keyword's line may run over as many further lines as it
2143    /// likes: `return f(` / `a,` / `)` is one `return` with one operand.
2144    ///
2145    /// This holds inside `(`, `[`, and `<` groups too, unlike the rest of the
2146    /// newline rule, because a keyword whose operand is optional needs no
2147    /// grouping to be complete: there is nothing for the next line to finish.
2148    fn at_operand(&self) -> bool {
2149        !self.tokens[self.pos].preceded_by_newline && self.can_start_expr()
2150    }
2151
2152    fn can_start_expr(&self) -> bool {
2153        matches!(
2154            self.peek(),
2155            TokenKind::Int(_)
2156                | TokenKind::Float(_)
2157                | TokenKind::Bool(_)
2158                | TokenKind::Duration(_)
2159                | TokenKind::Str(_)
2160                | TokenKind::Ident(_)
2161                | TokenKind::LParen
2162                | TokenKind::LBracket
2163                | TokenKind::LBrace
2164                | TokenKind::Bang
2165                | TokenKind::Minus
2166                | TokenKind::Keyword(
2167                    Keyword::If
2168                        | Keyword::Match
2169                        | Keyword::For
2170                        | Keyword::While
2171                        | Keyword::Scope
2172                        | Keyword::Fn
2173                        | Keyword::Async
2174                        | Keyword::Await
2175                        | Keyword::Return
2176                        | Keyword::Break
2177                        | Keyword::Continue
2178                        | Keyword::SelfValue
2179                )
2180        )
2181    }
2182
2183    fn parse_if(&mut self) -> PResult<Expr> {
2184        let start = self.expect_keyword(Keyword::If, "`if`")?;
2185        let condition = self.scoped(true, |parser| parser.parse_expr())?;
2186        let then_branch = self.parse_block()?;
2187        let else_branch = if self.eat_keyword(Keyword::Else) {
2188            if self.at_keyword(Keyword::If) {
2189                Some(Box::new(self.parse_if()?))
2190            } else {
2191                let block = self.parse_block()?;
2192                let span = block.span;
2193                Some(Box::new(expr(ExprKind::Block(block), span)))
2194            }
2195        } else {
2196            None
2197        };
2198        Ok(expr(
2199            ExprKind::If {
2200                condition: Box::new(condition),
2201                then_branch,
2202                else_branch,
2203            },
2204            start.to(self.prev_span()),
2205        ))
2206    }
2207
2208    fn parse_match(&mut self) -> PResult<Expr> {
2209        let start = self.expect_keyword(Keyword::Match, "`match`")?;
2210        let scrutinee = self.scoped(true, |parser| parser.parse_expr())?;
2211        self.expect(&TokenKind::LBrace, "`{`")?;
2212        let arms = self.scoped(false, |parser| {
2213            let mut arms = Vec::new();
2214            while !parser.at(&TokenKind::RBrace) && !parser.is_eof() {
2215                let arm_start = parser.span();
2216                let pattern = parser.parse_pattern()?;
2217                parser.expect(&TokenKind::FatArrow, "`=>`")?;
2218                let body = parser.parse_expr()?;
2219                arms.push(MatchArm {
2220                    pattern,
2221                    body,
2222                    span: arm_start.to(parser.prev_span()),
2223                });
2224                parser.eat(&TokenKind::Comma);
2225            }
2226            Ok(arms)
2227        })?;
2228        self.expect(&TokenKind::RBrace, "`}`")?;
2229        Ok(expr(
2230            ExprKind::Match {
2231                scrutinee: Box::new(scrutinee),
2232                arms,
2233            },
2234            start.to(self.prev_span()),
2235        ))
2236    }
2237
2238    fn parse_for(&mut self) -> PResult<Expr> {
2239        let start = self.expect_keyword(Keyword::For, "`for`")?;
2240        let binding = self.expect_ident()?;
2241        self.expect_keyword(Keyword::In, "`in`")?;
2242        let iterable = self.scoped(true, |parser| parser.parse_expr())?;
2243        let body = self.parse_block()?;
2244        Ok(expr(
2245            ExprKind::For {
2246                binding,
2247                iterable: Box::new(iterable),
2248                body,
2249            },
2250            start.to(self.prev_span()),
2251        ))
2252    }
2253
2254    fn parse_while(&mut self) -> PResult<Expr> {
2255        let start = self.expect_keyword(Keyword::While, "`while`")?;
2256        let condition = self.scoped(true, |parser| parser.parse_expr())?;
2257        let body = self.parse_block()?;
2258        Ok(expr(
2259            ExprKind::While {
2260                condition: Box::new(condition),
2261                body,
2262            },
2263            start.to(self.prev_span()),
2264        ))
2265    }
2266
2267    fn parse_scope(&mut self) -> PResult<Expr> {
2268        let start = self.expect_keyword(Keyword::Scope, "`scope`")?;
2269        let name = self.expect_ident()?;
2270        let body = self.parse_block()?;
2271        Ok(expr(
2272            ExprKind::Scope { name, body },
2273            start.to(self.prev_span()),
2274        ))
2275    }
2276
2277    /// `fn(x) { ... }`, `async fn(x) { ... }`, and the parameterless
2278    /// `async fn { ... }`.
2279    fn parse_lambda(&mut self) -> PResult<Expr> {
2280        let start = self.span();
2281        let is_async = self.eat_keyword(Keyword::Async);
2282        self.expect_keyword(Keyword::Fn, "`fn`")?;
2283        let params = if self.eat(&TokenKind::LParen) {
2284            let (receiver, params) = self.scoped(false, |parser| parser.parse_param_list())?;
2285            if let Some(receiver) = receiver {
2286                self.error(
2287                    Diagnostic::error(
2288                        "cove::parse::self_outside_method",
2289                        "`self` is only a parameter of a method",
2290                    )
2291                    .at(receiver.span)
2292                    .rule("A `self` receiver belongs to a function declared inside `impl`.")
2293                    .help("Remove `self`, or move this function into an `impl` block."),
2294                );
2295            }
2296            params
2297        } else {
2298            Vec::new()
2299        };
2300        let body = self.scoped(false, |parser| parser.parse_block())?;
2301        Ok(expr(
2302            ExprKind::Lambda {
2303                is_async,
2304                params,
2305                body,
2306            },
2307            start.to(self.prev_span()),
2308        ))
2309    }
2310}
2311
2312fn binary(op: BinaryOp, lhs: Expr, rhs: Expr) -> Expr {
2313    let span = lhs.span.to(rhs.span);
2314    expr(
2315        ExprKind::Binary {
2316            op,
2317            lhs: Box::new(lhs),
2318            rhs: Box::new(rhs),
2319        },
2320        span,
2321    )
2322}
2323
2324/// Patterns.
2325impl Parser<'_> {
2326    /// Parses one `match` pattern.
2327    ///
2328    /// A name is a variant when it is dotted or begins with an uppercase
2329    /// letter (`Ok(value)`, `LogLevel.Debug`, `ConfigError.InvalidPort(raw)`).
2330    /// A lone name that begins with a lowercase letter binds the scrutinee
2331    /// (`other`), and `_` matches without binding.
2332    fn parse_pattern(&mut self) -> PResult<Pattern> {
2333        self.nested(Parser::parse_pattern_inner)
2334    }
2335
2336    fn parse_pattern_inner(&mut self) -> PResult<Pattern> {
2337        let start = self.span();
2338        match self.peek() {
2339            TokenKind::Underscore => {
2340                self.bump();
2341                Ok(Pattern {
2342                    kind: PatternKind::Wildcard,
2343                    span: start,
2344                })
2345            }
2346            TokenKind::Int(_)
2347            | TokenKind::Float(_)
2348            | TokenKind::Bool(_)
2349            | TokenKind::Duration(_)
2350            | TokenKind::Str(_) => {
2351                let literal = self.parse_primary()?;
2352                let span = literal.span;
2353                Ok(Pattern {
2354                    kind: PatternKind::Literal(literal),
2355                    span,
2356                })
2357            }
2358            TokenKind::Minus => {
2359                let literal = self.parse_unary()?;
2360                let span = literal.span;
2361                Ok(Pattern {
2362                    kind: PatternKind::Literal(literal),
2363                    span,
2364                })
2365            }
2366            TokenKind::Ident(_) => {
2367                let mut path = vec![self.expect_ident()?];
2368                while self.at(&TokenKind::Dot) {
2369                    self.bump();
2370                    path.push(self.expect_ident()?);
2371                }
2372
2373                let mut payload = Vec::new();
2374                let has_payload = self.at(&TokenKind::LParen);
2375                if has_payload {
2376                    self.bump();
2377                    self.grouped(|parser| {
2378                        while !parser.at(&TokenKind::RParen) && !parser.is_eof() {
2379                            payload.push(parser.parse_pattern()?);
2380                            if !parser.eat(&TokenKind::Comma) {
2381                                break;
2382                            }
2383                        }
2384                        parser.expect(&TokenKind::RParen, "`)`")
2385                    })?;
2386                }
2387
2388                let is_variant = path.len() > 1
2389                    || has_payload
2390                    || path[0]
2391                        .node
2392                        .chars()
2393                        .next()
2394                        .is_some_and(|first| first.is_uppercase());
2395
2396                let span = start.to(self.prev_span());
2397                let kind = if is_variant {
2398                    PatternKind::Variant { path, payload }
2399                } else {
2400                    PatternKind::Binding(path.remove(0).node)
2401                };
2402                Ok(Pattern { kind, span })
2403            }
2404            _ => Err(self.unexpected("a pattern")),
2405        }
2406    }
2407}
2408
2409/// String literals and their interpolations.
2410impl Parser<'_> {
2411    fn parse_str_parts(&mut self, parts: &[StringPart]) -> Vec<StrPart> {
2412        let mut resolved = Vec::new();
2413        for part in parts {
2414            match part {
2415                StringPart::Text(text) => resolved.push(StrPart::Text(text.clone())),
2416                StringPart::Interpolation { source, span } => {
2417                    if let Some(value) = self.parse_interpolation(source, *span) {
2418                        resolved.push(StrPart::Interpolation(value));
2419                    }
2420                }
2421            }
2422        }
2423        resolved
2424    }
2425
2426    /// Parses the expression inside `"... {expr} ..."`.
2427    ///
2428    /// The interpolation is lexed as its own scratch source and every span it
2429    /// produces is rebased onto the file that contains the string, so a
2430    /// diagnostic points at the real position of the code.
2431    fn parse_interpolation(&mut self, source: &str, span: Span) -> Option<Expr> {
2432        if source.trim().is_empty() {
2433            self.error(
2434                Diagnostic::error(
2435                    "cove::parse::empty_interpolation",
2436                    "string interpolation contains no expression",
2437                )
2438                .at(span)
2439                .rule("`{ }` inside a string literal interpolates exactly one expression.")
2440                .help("Write an expression between the braces, or escape them as `\\{` and `\\}`."),
2441            );
2442            return None;
2443        }
2444
2445        let mut scratch = SourceMap::new();
2446        let scratch_file = scratch.add("<interpolation>", source.to_string());
2447        let tokens = match lexer::lex(&scratch, scratch_file) {
2448            Ok(tokens) => tokens,
2449            Err(diagnostics) => {
2450                for diagnostic in diagnostics {
2451                    let rebased = rebase_diagnostic(diagnostic, self.file, span.start);
2452                    self.error(rebased);
2453                }
2454                return None;
2455            }
2456        };
2457        let tokens = tokens
2458            .into_iter()
2459            .map(|token| rebase_token(token, self.file, span.start))
2460            .collect();
2461
2462        let mut inner = Parser::new(self.sources, self.file, tokens);
2463        // The interpolation gets a parser of its own, but it is nested inside
2464        // this file and spends the same stack, so it starts from the depth
2465        // this parser has reached rather than from zero. Otherwise a string
2466        // interpolating a string interpolating a string would reset the limit
2467        // at every level and never reach it.
2468        inner.depth = self.depth;
2469        let value = inner.parse_expr().ok();
2470        if value.is_some() && !inner.is_eof() {
2471            let found = inner.peek().describe();
2472            let rest = inner.span();
2473            inner.error(
2474                Diagnostic::error(
2475                    "cove::parse::unexpected_token",
2476                    format!("expected end of interpolation, found {found}"),
2477                )
2478                .at(rest)
2479                .rule("`{ }` inside a string literal interpolates exactly one expression."),
2480            );
2481        }
2482        let failed = !inner.diagnostics.is_empty();
2483        self.diagnostics.append(&mut inner.diagnostics);
2484        if failed {
2485            None
2486        } else {
2487            value
2488        }
2489    }
2490}
2491
2492#[cfg(test)]
2493mod tests {
2494    use super::*;
2495    use std::path::{Path, PathBuf};
2496
2497    fn parse_source(source: &str) -> (SourceMap, Result<SourceUnit, Vec<Diagnostic>>) {
2498        let mut sources = SourceMap::new();
2499        let file = sources.add("test.cove", source);
2500        let result = match lexer::lex(&sources, file) {
2501            Ok(tokens) => parse(&sources, file, tokens),
2502            Err(diagnostics) => Err(diagnostics),
2503        };
2504        (sources, result)
2505    }
2506
2507    fn ok(source: &str) -> SourceUnit {
2508        let (sources, result) = parse_source(source);
2509        match result {
2510            Ok(unit) => unit,
2511            Err(diagnostics) => {
2512                let rendered: String = diagnostics
2513                    .iter()
2514                    .map(|diagnostic| cove_diag::render(&sources, diagnostic))
2515                    .collect();
2516                panic!("expected `{source}` to parse:\n{rendered}");
2517            }
2518        }
2519    }
2520
2521    fn errors(source: &str) -> Vec<Diagnostic> {
2522        let (_, result) = parse_source(source);
2523        match result {
2524            Ok(_) => panic!("expected `{source}` to fail"),
2525            Err(diagnostics) => diagnostics,
2526        }
2527    }
2528
2529    fn codes(diagnostics: &[Diagnostic]) -> Vec<&str> {
2530        diagnostics.iter().map(|d| d.code.as_str()).collect()
2531    }
2532
2533    fn fn_decl(item: &Item) -> &FnDecl {
2534        match &item.kind {
2535            ItemKind::Fn(decl) => decl,
2536            other => panic!("expected a function, found {other:?}"),
2537        }
2538    }
2539
2540    /// Parses `source` as the body of `fn main`, returning the block's value.
2541    fn tail_expr(source: &str) -> Expr {
2542        let unit = ok(&format!("fn main() {{\n{source}\n}}"));
2543        let decl = fn_decl(&unit.items[0]);
2544        *decl
2545            .body
2546            .tail
2547            .clone()
2548            .unwrap_or_else(|| panic!("`{source}` produced no tail expression"))
2549    }
2550
2551    #[test]
2552    fn parses_a_test_declaration() {
2553        let unit = ok("test fn greetsByName() -> Result<Unit, Error> { Ok(()) }");
2554        let item = &unit.items[0];
2555        assert!(item.is_test);
2556        assert!(!item.exported);
2557        assert_eq!(fn_decl(item).name.node, "greetsByName");
2558    }
2559
2560    #[test]
2561    fn rejects_an_exported_test_written_either_way_round() {
2562        for source in [
2563            "export test fn t() -> Result<Unit, Error> { Ok(()) }",
2564            "test export fn t() -> Result<Unit, Error> { Ok(()) }",
2565        ] {
2566            let diagnostics = errors(source);
2567            assert_eq!(
2568                codes(&diagnostics),
2569                ["cove::parse::exported_test"],
2570                "{source}"
2571            );
2572            assert!(diagnostics[0].message.contains("may not be exported"));
2573            assert!(diagnostics[0]
2574                .rule
2575                .as_ref()
2576                .expect("the diagnostic states its rule")
2577                .contains("only caller"));
2578        }
2579    }
2580
2581    #[test]
2582    fn rejects_a_modifier_written_twice() {
2583        let diagnostics = errors("export export fn f() {}");
2584        assert_eq!(codes(&diagnostics), ["cove::parse::repeated_modifier"]);
2585        assert!(diagnostics[0].message.contains("`export` is written twice"));
2586    }
2587
2588    /// `opaque` is read as a modifier wherever it is written, and `cove fmt`
2589    /// is what settles the order it is written in.
2590    #[test]
2591    fn parses_an_opaque_export_written_either_way_round() {
2592        for source in [
2593            "export opaque struct User { id: Int }",
2594            "opaque export struct User { id: Int }",
2595        ] {
2596            let unit = ok(source);
2597            let item = &unit.items[0];
2598            assert!(item.exported, "{source}");
2599            assert!(item.is_opaque, "{source}");
2600        }
2601    }
2602
2603    #[test]
2604    fn a_plain_export_is_not_opaque() {
2605        let unit = ok("export struct User { id: Int }");
2606        assert!(!unit.items[0].is_opaque);
2607    }
2608
2609    #[test]
2610    fn rejects_opaque_on_a_declaration_that_is_not_a_struct() {
2611        for source in [
2612            "export opaque enum Status { Pending }",
2613            "export opaque fn f() {}",
2614            "export opaque type Handler = fn() -> Int",
2615        ] {
2616            let diagnostics = errors(source);
2617            assert_eq!(
2618                codes(&diagnostics),
2619                ["cove::parse::opaque_not_a_struct"],
2620                "{source}"
2621            );
2622        }
2623    }
2624
2625    /// A declaration without `export` is module-private already, so
2626    /// `opaque` would draw a boundary that is already drawn.
2627    #[test]
2628    fn rejects_opaque_without_export() {
2629        let diagnostics = errors("opaque struct User { id: Int }");
2630        assert_eq!(codes(&diagnostics), ["cove::parse::opaque_not_exported"]);
2631        assert!(diagnostics[0].message.contains("not exported"));
2632    }
2633
2634    #[test]
2635    fn rejects_opaque_written_twice() {
2636        let diagnostics = errors("export opaque opaque struct User { id: Int }");
2637        assert_eq!(codes(&diagnostics), ["cove::parse::repeated_modifier"]);
2638        assert!(diagnostics[0].message.contains("`opaque` is written twice"));
2639    }
2640
2641    #[test]
2642    fn rejects_test_on_a_declaration_that_is_not_a_function() {
2643        let diagnostics = errors("test struct Point { x: Int }");
2644        assert_eq!(codes(&diagnostics), ["cove::parse::test_not_a_function"]);
2645    }
2646
2647    #[test]
2648    fn rejects_a_test_declared_inside_an_impl_block() {
2649        let diagnostics = errors(
2650            "impl Point {
2651  test fn t() -> Result<Unit, Error> { Ok(()) }
2652}",
2653        );
2654        assert_eq!(codes(&diagnostics), ["cove::parse::nested_test"]);
2655        assert!(diagnostics[0].message.contains("`impl` block"));
2656    }
2657
2658    #[test]
2659    fn rejects_a_test_declared_inside_a_block() {
2660        let diagnostics = errors(
2661            "fn main() {
2662  test fn t() -> Result<Unit, Error> { Ok(()) }
2663}",
2664        );
2665        assert_eq!(codes(&diagnostics), ["cove::parse::nested_test"]);
2666    }
2667
2668    #[test]
2669    fn test_is_a_keyword_only_in_front_of_a_declaration() {
2670        // `test` after `.` names an ordinary member, as every keyword does.
2671        let unit = ok("fn main() {
2672  suite.test()
2673}");
2674        assert_eq!(unit.items.len(), 1);
2675    }
2676
2677    #[test]
2678    fn parses_uses_and_items_in_any_order() {
2679        let unit = ok("use http\nfn a() {}\nuse console.println\nfn b() {}");
2680        assert_eq!(unit.uses.len(), 2);
2681        assert_eq!(unit.uses[0].path.len(), 1);
2682        assert_eq!(unit.uses[1].path[1].node, "println");
2683        assert_eq!(unit.items.len(), 2);
2684    }
2685
2686    #[test]
2687    fn parses_function_declarations() {
2688        let unit = ok("export async fn run<T, U>(name: String, items: T... , retries: Int = 3) -> Result<Unit, Error> { Ok(()) }");
2689        let item = &unit.items[0];
2690        assert!(item.exported);
2691        let decl = fn_decl(item);
2692        assert!(decl.is_async);
2693        assert_eq!(decl.name.node, "run");
2694        assert_eq!(decl.generics.len(), 2);
2695        assert!(decl.receiver.is_none());
2696        assert_eq!(decl.params.len(), 3);
2697        assert!(decl.params[1].variadic);
2698        assert!(decl.params[2].default.is_some());
2699        assert!(decl.return_type.is_some());
2700    }
2701
2702    #[test]
2703    fn parses_struct_in_brace_and_paren_form() {
2704        let braced = ok("export struct App {\n  repository: Repo\n  metrics: Shared<Metrics>\n}");
2705        let ItemKind::Struct(decl) = &braced.items[0].kind else {
2706            panic!("expected a struct");
2707        };
2708        assert_eq!(decl.fields.len(), 2);
2709
2710        let parens = ok("export struct Booking(id: BookingId, status: BookingStatus)");
2711        let ItemKind::Struct(decl) = &parens.items[0].kind else {
2712            panic!("expected a struct");
2713        };
2714        assert_eq!(decl.fields.len(), 2);
2715        assert_eq!(decl.fields[1].name.node, "status");
2716    }
2717
2718    #[test]
2719    fn parses_enum_cases_with_and_without_commas() {
2720        let unit =
2721            ok("enum ConfigError {\n  InvalidPort(String)\n  Missing,\n  Pair(Int, String)\n}");
2722        let ItemKind::Enum(decl) = &unit.items[0].kind else {
2723            panic!("expected an enum");
2724        };
2725        assert_eq!(decl.cases.len(), 3);
2726        assert_eq!(decl.cases[0].payload.len(), 1);
2727        assert!(decl.cases[1].payload.is_empty());
2728        assert_eq!(decl.cases[2].payload.len(), 2);
2729    }
2730
2731    #[test]
2732    fn parses_impl_blocks_with_receivers() {
2733        let unit = ok("impl Metrics {\n  /// Records one request.\n  fn record(var self, failed: Bool) { self.requests += 1 }\n  fn read(self) -> Int { self.requests }\n}");
2734        let ItemKind::Impl(block) = &unit.items[0].kind else {
2735            panic!("expected an impl");
2736        };
2737        assert_eq!(block.type_name.node, "Metrics");
2738        assert_eq!(block.items.len(), 2);
2739        let first = fn_decl(&block.items[0]);
2740        assert_eq!(block.items[0].doc.as_deref(), Some("Records one request."));
2741        assert!(first.receiver.expect("receiver").is_var);
2742        assert_eq!(first.params.len(), 1);
2743        assert!(!fn_decl(&block.items[1]).receiver.expect("receiver").is_var);
2744    }
2745
2746    #[test]
2747    fn parses_a_trait_with_required_and_defaulted_methods() {
2748        let unit = ok(
2749            "/// Renders itself.\nexport trait Display {\n  /// The full form.\n  fn describe(self) -> String\n\n  /// A short form.\n  fn label(self) -> String { self.describe() }\n\n  fn make(width: Int) -> Int\n}",
2750        );
2751        let item = &unit.items[0];
2752        assert!(item.exported);
2753        assert_eq!(item.doc.as_deref(), Some("Renders itself."));
2754        let ItemKind::Trait(decl) = &item.kind else {
2755            panic!("expected a trait");
2756        };
2757        assert_eq!(decl.name.node, "Display");
2758        assert_eq!(decl.methods.len(), 3);
2759        assert_eq!(decl.methods[0].doc.as_deref(), Some("The full form."));
2760        assert!(decl.methods[0].receiver.is_some());
2761        assert!(decl.methods[0].default.is_none());
2762        assert!(decl.methods[1].default.is_some());
2763        // A method with no `self` is an associated function.
2764        assert!(decl.methods[2].receiver.is_none());
2765        assert_eq!(decl.methods[2].params.len(), 1);
2766    }
2767
2768    #[test]
2769    fn parses_a_conformance_and_an_inherent_impl() {
2770        let unit = ok("impl Display for Booking {\n  fn describe(self) -> String { \"b\" }\n}\n\nimpl Booking {\n  fn id(self) -> Int { 1 }\n}");
2771        let ItemKind::Impl(conformance) = &unit.items[0].kind else {
2772            panic!("expected an impl");
2773        };
2774        assert_eq!(
2775            conformance.trait_name.as_ref().map(|n| n.node.as_str()),
2776            Some("Display")
2777        );
2778        assert_eq!(conformance.type_name.node, "Booking");
2779        let ItemKind::Impl(inherent) = &unit.items[1].kind else {
2780            panic!("expected an impl");
2781        };
2782        assert!(inherent.trait_name.is_none());
2783        assert_eq!(inherent.type_name.node, "Booking");
2784    }
2785
2786    #[test]
2787    fn parses_one_bound_and_several_bounds_on_a_type_parameter() {
2788        let unit = ok("fn render<T: Display, U, V: Display + Ordered>(value: T) { }");
2789        let decl = fn_decl(&unit.items[0]);
2790        assert_eq!(decl.generics.len(), 3);
2791        assert_eq!(decl.generics[0].name.node, "T");
2792        assert_eq!(decl.generics[0].bounds.len(), 1);
2793        assert_eq!(decl.generics[0].bounds[0].node, "Display");
2794        assert!(decl.generics[1].bounds.is_empty());
2795        assert_eq!(decl.generics[2].bounds.len(), 2);
2796        assert_eq!(decl.generics[2].bounds[1].node, "Ordered");
2797    }
2798
2799    #[test]
2800    fn parses_dyn_as_a_type() {
2801        let unit = ok("fn renderAll(values: Array<dyn Display>) -> dyn Display { values }");
2802        let decl = fn_decl(&unit.items[0]);
2803        let ty = decl.params[0].ty.as_ref().expect("a written type");
2804        assert_eq!(ty.to_string(), "Array<dyn Display>");
2805        let TypeKind::Dyn(name) = &decl.return_type.as_ref().expect("a return type").kind else {
2806            panic!("expected a `dyn` return type");
2807        };
2808        assert_eq!(name.node, "Display");
2809    }
2810
2811    #[test]
2812    fn rejects_dyn_without_a_trait_name() {
2813        assert_eq!(
2814            codes(&errors("fn go(value: dyn) { }")),
2815            ["cove::parse::unexpected_token"]
2816        );
2817    }
2818
2819    #[test]
2820    fn parses_type_alias_with_function_type() {
2821        let unit = ok(
2822            "export type Handler = async fn(request: http.Request) -> Result<http.Response, Error>",
2823        );
2824        let ItemKind::TypeAlias(alias) = &unit.items[0].kind else {
2825            panic!("expected a type alias");
2826        };
2827        let TypeKind::Fn {
2828            is_async,
2829            params,
2830            return_type,
2831        } = &alias.ty.kind
2832        else {
2833            panic!("expected a function type");
2834        };
2835        assert!(is_async);
2836        assert_eq!(params.len(), 1);
2837        assert_eq!(params[0].name.node, "request");
2838        assert!(return_type.is_some());
2839    }
2840
2841    #[test]
2842    fn parses_unnamed_function_type_parameters_and_unit() {
2843        let unit = ok("type Predicate = fn(String, Int) -> ()");
2844        let ItemKind::TypeAlias(alias) = &unit.items[0].kind else {
2845            panic!("expected a type alias");
2846        };
2847        let TypeKind::Fn {
2848            params,
2849            return_type,
2850            ..
2851        } = &alias.ty.kind
2852        else {
2853            panic!("expected a function type");
2854        };
2855        assert_eq!(params.len(), 2);
2856        assert!(params[0].name.node.is_empty());
2857        assert!(matches!(
2858            return_type.as_deref().map(|ty| &ty.kind),
2859            Some(TypeKind::Unit)
2860        ));
2861    }
2862
2863    #[test]
2864    fn joins_consecutive_doc_comments() {
2865        let unit = ok("/// First line.\n/// Second line.\nexport fn a() {}");
2866        assert_eq!(
2867            unit.items[0].doc.as_deref(),
2868            Some("First line.\nSecond line.")
2869        );
2870    }
2871
2872    #[test]
2873    fn attaches_doc_comments_to_fields_and_cases() {
2874        let unit =
2875            ok("struct S {\n  /// The port.\n  port: Int\n}\nenum E {\n  /// A case.\n  Case\n}");
2876        let ItemKind::Struct(decl) = &unit.items[0].kind else {
2877            panic!("expected a struct");
2878        };
2879        assert_eq!(decl.fields[0].doc.as_deref(), Some("The port."));
2880        let ItemKind::Enum(decl) = &unit.items[1].kind else {
2881            panic!("expected an enum");
2882        };
2883        assert_eq!(decl.cases[0].doc.as_deref(), Some("A case."));
2884    }
2885
2886    #[test]
2887    fn dangling_doc_comment_is_an_error() {
2888        let diagnostics = errors("/// Nothing follows this.\n");
2889        assert_eq!(codes(&diagnostics), ["cove::parse::dangling_doc_comment"]);
2890    }
2891
2892    #[test]
2893    fn parses_nested_generic_types() {
2894        let unit = ok("struct S { field: Map<String, Array<Result<Vector<Int>, Error>>> }");
2895        let ItemKind::Struct(decl) = &unit.items[0].kind else {
2896            panic!("expected a struct");
2897        };
2898        let TypeKind::Named { path, args } = &decl.fields[0].ty.kind else {
2899            panic!("expected a named type");
2900        };
2901        assert_eq!(path[0].node, "Map");
2902        assert_eq!(args.len(), 2);
2903        let TypeKind::Named { args: inner, .. } = &args[1].kind else {
2904            panic!("expected a named type");
2905        };
2906        let TypeKind::Named { args: inner, .. } = &inner[0].kind else {
2907            panic!("expected a named type");
2908        };
2909        assert_eq!(inner.len(), 2);
2910    }
2911
2912    #[test]
2913    fn parses_dotted_type_paths() {
2914        let unit = ok("fn f(request: http.Request) -> http.Response<Body> { request }");
2915        let decl = fn_decl(&unit.items[0]);
2916        let TypeKind::Named { path, .. } = &decl.params[0].ty.as_ref().unwrap().kind else {
2917            panic!("expected a named type");
2918        };
2919        assert_eq!(path.len(), 2);
2920        assert_eq!(path[1].node, "Request");
2921    }
2922
2923    #[test]
2924    fn parses_labeled_var_and_spread_arguments() {
2925        let positional = tail_expr("f(a, var d, ...e)");
2926        let ExprKind::Call { args, .. } = &positional.kind else {
2927            panic!("expected a call");
2928        };
2929        assert_eq!(args.len(), 3);
2930        assert!(args.iter().all(|arg| arg.label.is_none()));
2931        assert!(args[1].is_var);
2932        assert!(args[2].spread);
2933
2934        let labeled = tail_expr("f(a, b: c, d: var e, rest: ...g)");
2935        let ExprKind::Call { args, .. } = &labeled.kind else {
2936            panic!("expected a call");
2937        };
2938        assert_eq!(args.len(), 4);
2939        assert!(args[0].label.is_none());
2940        assert_eq!(args[1].label.as_ref().unwrap().node, "b");
2941        assert!(args[2].is_var);
2942        assert!(args[3].spread);
2943        assert_eq!(args[3].label.as_ref().unwrap().node, "rest");
2944    }
2945
2946    #[test]
2947    fn positional_argument_after_label_is_an_error() {
2948        let diagnostics = errors("fn main() { f(a: 1, 2) }");
2949        assert_eq!(codes(&diagnostics), ["cove::parse::positional_after_label"]);
2950        assert!(diagnostics[0].rule.is_some());
2951        assert!(diagnostics[0].help.is_some());
2952    }
2953
2954    #[test]
2955    fn generic_call_arguments_are_disambiguated_from_comparison() {
2956        let call = tail_expr("api.fetch<Array<Booking>>(\"/bookings\")");
2957        let ExprKind::Call { generics, args, .. } = &call.kind else {
2958            panic!("expected a call");
2959        };
2960        assert_eq!(generics.len(), 1);
2961        assert_eq!(args.len(), 1);
2962
2963        let empty = tail_expr("request.json<CreateBookingRequest>()");
2964        let ExprKind::Call { generics, args, .. } = &empty.kind else {
2965            panic!("expected a call");
2966        };
2967        assert_eq!(generics.len(), 1);
2968        assert!(args.is_empty());
2969
2970        let comparison = tail_expr("a < b");
2971        assert!(matches!(
2972            comparison.kind,
2973            ExprKind::Binary {
2974                op: BinaryOp::Lt,
2975                ..
2976            }
2977        ));
2978
2979        let mixed = tail_expr("a < b && c > d");
2980        assert!(matches!(
2981            mixed.kind,
2982            ExprKind::Binary {
2983                op: BinaryOp::And,
2984                ..
2985            }
2986        ));
2987    }
2988
2989    #[test]
2990    fn parses_the_three_trailing_closure_shapes() {
2991        let bare = tail_expr("tasks.spawn { 1 }");
2992        let ExprKind::Call { args, trailing, .. } = &bare.kind else {
2993            panic!("expected a call");
2994        };
2995        assert!(args.is_empty());
2996        assert!(matches!(
2997            trailing.as_deref().map(|value| &value.kind),
2998            Some(ExprKind::Lambda {
2999                is_async: false,
3000                ..
3001            })
3002        ));
3003
3004        let after_args = tail_expr("clock.timeout(500ms) { 1 }");
3005        let ExprKind::Call { args, trailing, .. } = &after_args.kind else {
3006            panic!("expected a call");
3007        };
3008        assert_eq!(args.len(), 1);
3009        assert!(trailing.is_some());
3010
3011        let then_try = tail_expr("value.recover { ConfigError.InvalidPort(raw) }?");
3012        let ExprKind::Try(inner) = &then_try.kind else {
3013            panic!("expected `?`");
3014        };
3015        assert!(matches!(inner.kind, ExprKind::Call { .. }));
3016    }
3017
3018    #[test]
3019    fn control_flow_headers_do_not_take_trailing_closures() {
3020        let conditional = tail_expr("if ready { 1 } else if other { 2 } else { 3 }");
3021        let ExprKind::If {
3022            condition,
3023            else_branch,
3024            ..
3025        } = &conditional.kind
3026        else {
3027            panic!("expected an if");
3028        };
3029        assert!(matches!(condition.kind, ExprKind::Ident(_)));
3030        assert!(matches!(
3031            else_branch.as_deref().map(|value| &value.kind),
3032            Some(ExprKind::If { .. })
3033        ));
3034
3035        let loop_expr = tail_expr("for item in items.all() { item }");
3036        let ExprKind::For { iterable, .. } = &loop_expr.kind else {
3037            panic!("expected a for loop");
3038        };
3039        assert!(matches!(
3040            iterable.kind,
3041            ExprKind::Call { trailing: None, .. }
3042        ));
3043
3044        let while_expr = tail_expr("while running { step() }");
3045        assert!(matches!(while_expr.kind, ExprKind::While { .. }));
3046
3047        let scrutinee = tail_expr("match value { _ => 1 }");
3048        let ExprKind::Match { scrutinee, .. } = &scrutinee.kind else {
3049            panic!("expected a match");
3050        };
3051        assert!(matches!(scrutinee.kind, ExprKind::Ident(_)));
3052    }
3053
3054    #[test]
3055    fn parses_every_pattern_form() {
3056        let value = tail_expr(
3057            "match value {\n  _ => 1\n  other => 2\n  \"debug\" => 3\n  1 => 4\n  true => 5\n  Ok(inner) => 6\n  LogLevel.Debug => 7\n  ConfigError.InvalidPort(raw) => 8\n}",
3058        );
3059        let ExprKind::Match { arms, .. } = &value.kind else {
3060            panic!("expected a match");
3061        };
3062        assert_eq!(arms.len(), 8);
3063        assert!(matches!(arms[0].pattern.kind, PatternKind::Wildcard));
3064        assert!(matches!(&arms[1].pattern.kind, PatternKind::Binding(name) if name == "other"));
3065        assert!(matches!(arms[2].pattern.kind, PatternKind::Literal(_)));
3066        assert!(matches!(arms[3].pattern.kind, PatternKind::Literal(_)));
3067        assert!(matches!(arms[4].pattern.kind, PatternKind::Literal(_)));
3068        let PatternKind::Variant { path, payload } = &arms[5].pattern.kind else {
3069            panic!("expected a variant");
3070        };
3071        assert_eq!(path[0].node, "Ok");
3072        assert_eq!(payload.len(), 1);
3073        let PatternKind::Variant { path, payload } = &arms[6].pattern.kind else {
3074            panic!("expected a variant");
3075        };
3076        assert_eq!(path.len(), 2);
3077        assert!(payload.is_empty());
3078        assert!(matches!(arms[7].pattern.kind, PatternKind::Variant { .. }));
3079    }
3080
3081    #[test]
3082    fn match_arms_accept_blocks_returns_and_trailing_commas() {
3083        let value = tail_expr("match value {\n  Ok(v) => { v }\n  Err(e) => return Err(e),\n}");
3084        let ExprKind::Match { arms, .. } = &value.kind else {
3085            panic!("expected a match");
3086        };
3087        assert_eq!(arms.len(), 2);
3088        assert!(matches!(arms[0].body.kind, ExprKind::Block(_)));
3089        assert!(matches!(arms[1].body.kind, ExprKind::Return(Some(_))));
3090    }
3091
3092    #[test]
3093    fn await_binds_tighter_than_a_trailing_question_mark() {
3094        let value = tail_expr("await handler(event)?");
3095        let ExprKind::Try(inner) = &value.kind else {
3096            panic!("expected a `?`");
3097        };
3098        let ExprKind::Await(call) = &inner.kind else {
3099            panic!("expected an await");
3100        };
3101        assert!(matches!(call.kind, ExprKind::Call { .. }));
3102    }
3103
3104    #[test]
3105    fn await_alone_has_no_try() {
3106        let value = tail_expr("await handler(event)");
3107        let ExprKind::Await(call) = &value.kind else {
3108            panic!("expected an await");
3109        };
3110        assert!(matches!(call.kind, ExprKind::Call { .. }));
3111    }
3112
3113    #[test]
3114    fn await_binds_tighter_than_binary_operators() {
3115        let sum = tail_expr("await a() + b");
3116        let ExprKind::Binary { op, lhs, .. } = &sum.kind else {
3117            panic!("expected an addition");
3118        };
3119        assert_eq!(*op, BinaryOp::Add);
3120        assert!(matches!(lhs.kind, ExprKind::Await(_)));
3121    }
3122
3123    /// A `?` that is followed by more of the postfix chain stays part of the
3124    /// chain instead of escaping the `Await`: `await f()?.g()` awaits
3125    /// `f()?.g()` as a whole, rather than awaiting `f()` and applying `?` to
3126    /// the result afterwards.
3127    #[test]
3128    fn await_with_a_question_mark_mid_chain_keeps_it_inside_the_chain() {
3129        let value = tail_expr("await f()?.g()");
3130        let ExprKind::Await(inner) = &value.kind else {
3131            panic!("expected an await");
3132        };
3133        let ExprKind::Call { callee, .. } = &inner.kind else {
3134            panic!("expected a call to `g`");
3135        };
3136        let ExprKind::Field { base, name } = &callee.kind else {
3137            panic!("expected a field access");
3138        };
3139        assert_eq!(name.node, "g");
3140        let ExprKind::Try(call) = &base.kind else {
3141            panic!("expected a `?`");
3142        };
3143        assert!(matches!(call.kind, ExprKind::Call { .. }));
3144    }
3145
3146    #[test]
3147    fn await_is_also_an_ordinary_member_name() {
3148        let value = tail_expr("bookings.await()?");
3149        let ExprKind::Try(call) = &value.kind else {
3150            panic!("expected a `?`");
3151        };
3152        let ExprKind::Call { callee, .. } = &call.kind else {
3153            panic!("expected a call");
3154        };
3155        let ExprKind::Field { name, .. } = &callee.kind else {
3156            panic!("expected a field");
3157        };
3158        assert_eq!(name.node, "await");
3159    }
3160
3161    #[test]
3162    fn ranges_are_distinct_from_float_literals() {
3163        let exclusive = tail_expr("0..<attempts");
3164        let ExprKind::Range { inclusive_end, .. } = &exclusive.kind else {
3165            panic!("expected a range");
3166        };
3167        assert!(!inclusive_end);
3168
3169        let inclusive = tail_expr("0..count");
3170        let ExprKind::Range { inclusive_end, .. } = &inclusive.kind else {
3171            panic!("expected a range");
3172        };
3173        assert!(inclusive_end);
3174
3175        assert!(matches!(tail_expr("0.5").kind, ExprKind::Float(_)));
3176        assert!(matches!(tail_expr("500ms").kind, ExprKind::Duration(_)));
3177    }
3178
3179    #[test]
3180    fn precedence_runs_from_assignment_to_postfix() {
3181        let value = tail_expr("total = a + b * c == d && e || f");
3182        let ExprKind::Assign { op, value, .. } = &value.kind else {
3183            panic!("expected an assignment");
3184        };
3185        assert!(op.is_none());
3186        assert!(matches!(
3187            value.kind,
3188            ExprKind::Binary {
3189                op: BinaryOp::Or,
3190                ..
3191            }
3192        ));
3193
3194        let compound = tail_expr("self.requests += 1");
3195        let ExprKind::Assign { op, target, .. } = &compound.kind else {
3196            panic!("expected an assignment");
3197        };
3198        assert_eq!(*op, Some(BinaryOp::Add));
3199        assert!(matches!(target.kind, ExprKind::Field { .. }));
3200
3201        let unary = tail_expr("!ready");
3202        assert!(matches!(
3203            unary.kind,
3204            ExprKind::Unary {
3205                op: UnaryOp::Not,
3206                ..
3207            }
3208        ));
3209    }
3210
3211    #[test]
3212    fn parses_is_at_the_same_precedence_as_comparison() {
3213        let value = tail_expr("a is b && c == d");
3214        let ExprKind::Binary {
3215            op: BinaryOp::And,
3216            lhs,
3217            rhs,
3218        } = &value.kind
3219        else {
3220            panic!("expected `&&` at the top, binding `is` and `==` tighter");
3221        };
3222        assert!(matches!(
3223            lhs.kind,
3224            ExprKind::Binary {
3225                op: BinaryOp::Is,
3226                ..
3227            }
3228        ));
3229        assert!(matches!(
3230            rhs.kind,
3231            ExprKind::Binary {
3232                op: BinaryOp::Eq,
3233                ..
3234            }
3235        ));
3236    }
3237
3238    #[test]
3239    fn parses_primary_expression_forms() {
3240        assert!(matches!(tail_expr("()").kind, ExprKind::Unit));
3241        assert!(matches!(tail_expr("(1 + 2)").kind, ExprKind::Binary { .. }));
3242        assert!(matches!(tail_expr("[1, 2]").kind, ExprKind::ArrayLit(_)));
3243        assert!(matches!(tail_expr("[]").kind, ExprKind::ArrayLit(_)));
3244        assert!(matches!(tail_expr("self").kind, ExprKind::Ident(_)));
3245        assert!(matches!(tail_expr("return").kind, ExprKind::Return(None)));
3246        assert!(matches!(tail_expr("break").kind, ExprKind::Break(None)));
3247        assert!(matches!(
3248            tail_expr("break 1").kind,
3249            ExprKind::Break(Some(_))
3250        ));
3251        assert!(matches!(tail_expr("continue").kind, ExprKind::Continue));
3252        assert!(matches!(tail_expr("{ 1 }").kind, ExprKind::Block(_)));
3253        assert!(matches!(
3254            tail_expr("scope tasks { 1 }").kind,
3255            ExprKind::Scope { .. }
3256        ));
3257    }
3258
3259    #[test]
3260    fn parses_lambda_forms() {
3261        let plain = tail_expr("fn(request) { request }");
3262        let ExprKind::Lambda {
3263            is_async, params, ..
3264        } = &plain.kind
3265        else {
3266            panic!("expected a lambda");
3267        };
3268        assert!(!is_async);
3269        assert_eq!(params.len(), 1);
3270        assert!(params[0].ty.is_none());
3271
3272        let mutating = tail_expr("fn(var metrics) { metrics }");
3273        let ExprKind::Lambda { params, .. } = &mutating.kind else {
3274            panic!("expected a lambda");
3275        };
3276        assert!(params[0].is_var);
3277
3278        let parameterless = tail_expr("async fn { 1 }");
3279        let ExprKind::Lambda {
3280            is_async, params, ..
3281        } = &parameterless.kind
3282        else {
3283            panic!("expected a lambda");
3284        };
3285        assert!(is_async);
3286        assert!(params.is_empty());
3287    }
3288
3289    #[test]
3290    fn blocks_take_their_last_expression_as_a_value() {
3291        let unit = ok("fn f() -> Int {\n  let a = 1\n  a + 1\n}");
3292        let body = &fn_decl(&unit.items[0]).body;
3293        assert_eq!(body.statements.len(), 1);
3294        assert!(matches!(body.statements[0].kind, StmtKind::Let { .. }));
3295        assert!(matches!(
3296            body.tail.as_deref().map(|value| &value.kind),
3297            Some(ExprKind::Binary { .. })
3298        ));
3299
3300        let unit = ok("fn f() {\n  a()\n  b()\n}");
3301        let body = &fn_decl(&unit.items[0]).body;
3302        assert_eq!(body.statements.len(), 1);
3303        assert!(body.tail.is_some());
3304
3305        let unit = ok("fn f() {\n  let a = 1\n}");
3306        let body = &fn_decl(&unit.items[0]).body;
3307        assert_eq!(body.statements.len(), 1);
3308        assert!(body.tail.is_none());
3309    }
3310
3311    #[test]
3312    fn statements_include_bindings_and_nested_items() {
3313        let unit = ok("fn f() {\n  let a: Int = 1\n  var b = 2\n  fn helper() {}\n  helper()\n}");
3314        let body = &fn_decl(&unit.items[0]).body;
3315        assert!(matches!(
3316            &body.statements[0].kind,
3317            StmtKind::Let {
3318                is_var: false,
3319                ty: Some(_),
3320                ..
3321            }
3322        ));
3323        assert!(matches!(
3324            body.statements[1].kind,
3325            StmtKind::Let { is_var: true, .. }
3326        ));
3327        assert!(matches!(body.statements[2].kind, StmtKind::Item(_)));
3328        assert!(body.tail.is_some());
3329    }
3330
3331    #[test]
3332    fn parses_string_interpolation() {
3333        let value = tail_expr("\"Hello, {name}! {a + b}\"");
3334        let ExprKind::Str(parts) = &value.kind else {
3335            panic!("expected a string");
3336        };
3337        assert_eq!(parts.len(), 4);
3338        assert!(matches!(&parts[0], StrPart::Text(text) if text == "Hello, "));
3339        assert!(matches!(
3340            &parts[1],
3341            StrPart::Interpolation(Expr {
3342                kind: ExprKind::Ident(_),
3343                ..
3344            })
3345        ));
3346        assert!(matches!(
3347            &parts[3],
3348            StrPart::Interpolation(Expr {
3349                kind: ExprKind::Binary { .. },
3350                ..
3351            })
3352        ));
3353    }
3354
3355    #[test]
3356    fn interpolation_spans_are_rebased_onto_the_original_file() {
3357        let source = "fn main() {\n  \"count: {name}\"\n}";
3358        let unit = ok(source);
3359        let tail = fn_decl(&unit.items[0]).body.tail.as_deref().unwrap();
3360        let ExprKind::Str(parts) = &tail.kind else {
3361            panic!("expected a string");
3362        };
3363        let StrPart::Interpolation(value) = &parts[1] else {
3364            panic!("expected an interpolation");
3365        };
3366        let start = source.find("name").unwrap() as u32;
3367        assert_eq!(value.span.start, start);
3368        assert_eq!(value.span.end, start + 4);
3369    }
3370
3371    #[test]
3372    fn diagnostics_inside_an_interpolation_point_into_the_original_file() {
3373        let source = "fn main() {\n  \"count: {name ] rest}\"\n}";
3374        let diagnostics = errors(source);
3375        assert_eq!(codes(&diagnostics), ["cove::parse::unexpected_token"]);
3376        let span = diagnostics[0].primary.expect("a primary span");
3377        assert_eq!(span.start as usize, source.find(']').unwrap());
3378        assert_eq!(span.file, FileId(0));
3379    }
3380
3381    #[test]
3382    fn empty_interpolation_is_an_error() {
3383        let diagnostics = errors("fn main() { \"a {  } b\" }");
3384        assert_eq!(codes(&diagnostics), ["cove::parse::empty_interpolation"]);
3385    }
3386
3387    #[test]
3388    fn recovers_from_a_broken_statement_and_keeps_parsing() {
3389        let diagnostics = errors("fn a() { let = 1 }\nfn b() { let = 2 }");
3390        assert_eq!(
3391            codes(&diagnostics),
3392            [
3393                "cove::parse::unexpected_token",
3394                "cove::parse::unexpected_token"
3395            ]
3396        );
3397    }
3398
3399    #[test]
3400    fn recovers_from_a_broken_item_at_the_next_declaration() {
3401        let diagnostics = errors("fn a( {}\nstruct S { x: Int }\nenum E { A }\nfn ! {}");
3402        assert_eq!(diagnostics.len(), 2);
3403        assert!(diagnostics
3404            .iter()
3405            .all(|d| d.code == "cove::parse::unexpected_token"));
3406    }
3407
3408    #[test]
3409    fn reports_a_statement_that_is_not_a_declaration_at_the_top_level() {
3410        let diagnostics = errors("let x = 1\nfn a() {}");
3411        assert_eq!(codes(&diagnostics), ["cove::parse::unexpected_token"]);
3412        assert!(diagnostics[0].message.contains("expected a declaration"));
3413    }
3414
3415    #[test]
3416    fn rejects_assignment_to_a_non_place() {
3417        let diagnostics = errors("fn a() { f() = 1 }");
3418        assert_eq!(
3419            codes(&diagnostics),
3420            ["cove::parse::invalid_assignment_target"]
3421        );
3422    }
3423
3424    #[test]
3425    fn reports_several_independent_errors_in_one_run() {
3426        let diagnostics = errors("fn a() { f(x: 1, 2) }\n/// dangling\n1\nfn b() { let = 1 }");
3427        assert_eq!(
3428            codes(&diagnostics),
3429            [
3430                "cove::parse::positional_after_label",
3431                "cove::parse::dangling_doc_comment",
3432                "cove::parse::unexpected_token"
3433            ]
3434        );
3435    }
3436
3437    #[test]
3438    fn unexpected_token_names_what_was_expected_and_found() {
3439        let diagnostics = errors("fn a(1) {}");
3440        assert_eq!(
3441            diagnostics[0].message,
3442            "expected identifier, found integer literal"
3443        );
3444    }
3445
3446    /// Parses `source` as the body of `fn main`, returning its statements
3447    /// with the tail expression appended, so a test can count the statements
3448    /// a body was split into.
3449    fn body_stmts(source: &str) -> Vec<Stmt> {
3450        let unit = ok(&format!("fn main() {{\n{source}\n}}"));
3451        let body = fn_decl(&unit.items[0]).body.clone();
3452        let mut statements = body.statements;
3453        if let Some(tail) = body.tail {
3454            statements.push(Stmt {
3455                span: tail.span,
3456                kind: StmtKind::Expr(*tail),
3457            });
3458        }
3459        statements
3460    }
3461
3462    fn stmt_expr(stmt: &Stmt) -> &Expr {
3463        match &stmt.kind {
3464            StmtKind::Expr(value) => value,
3465            other => panic!("expected an expression statement, found {other:?}"),
3466        }
3467    }
3468
3469    #[test]
3470    fn a_newline_ends_a_call_statement() {
3471        let statements = body_stmts("println(\"x\")\n()");
3472        assert_eq!(statements.len(), 2);
3473        assert!(matches!(
3474            stmt_expr(&statements[0]).kind,
3475            ExprKind::Call { .. }
3476        ));
3477        assert!(matches!(stmt_expr(&statements[1]).kind, ExprKind::Unit));
3478    }
3479
3480    #[test]
3481    fn a_newline_ends_a_statement_before_a_block() {
3482        let statements = body_stmts("let n = compute()\n{ n }");
3483        assert_eq!(statements.len(), 2);
3484        let StmtKind::Let { value, .. } = &statements[0].kind else {
3485            panic!("expected a binding");
3486        };
3487        assert!(matches!(value.kind, ExprKind::Call { trailing: None, .. }));
3488        assert!(matches!(stmt_expr(&statements[1]).kind, ExprKind::Block(_)));
3489    }
3490
3491    #[test]
3492    fn a_newline_ends_a_match_arm_body() {
3493        let value = tail_expr(
3494            "match x {\n  1 => \"one\"\n  -1 => \"minus one\"\n  2 => \"two\"\n  _ => \"other\"\n}",
3495        );
3496        let ExprKind::Match { arms, .. } = &value.kind else {
3497            panic!("expected a match");
3498        };
3499        assert_eq!(arms.len(), 4);
3500        let PatternKind::Literal(literal) = &arms[1].pattern.kind else {
3501            panic!("expected a literal pattern");
3502        };
3503        assert!(matches!(
3504            literal.kind,
3505            ExprKind::Unary {
3506                op: UnaryOp::Neg,
3507                ..
3508            }
3509        ));
3510        for arm in arms {
3511            assert!(matches!(arm.body.kind, ExprKind::Str(_)));
3512        }
3513    }
3514
3515    /// A `break` alone on its line has no operand, so the statement written
3516    /// under it is a statement of its own rather than something the `break`
3517    /// evaluates and throws away.
3518    #[test]
3519    fn a_newline_ends_a_break_that_has_no_operand() {
3520        let statements = body_stmts("break\nseen = 99");
3521        assert_eq!(statements.len(), 2);
3522        assert!(matches!(
3523            stmt_expr(&statements[0]).kind,
3524            ExprKind::Break(None)
3525        ));
3526        assert!(matches!(
3527            stmt_expr(&statements[1]).kind,
3528            ExprKind::Assign { .. }
3529        ));
3530    }
3531
3532    /// The same for `return`, which differs only in that its swallowed
3533    /// operand sometimes failed to type-check and so was sometimes caught.
3534    #[test]
3535    fn a_newline_ends_a_return_that_has_no_operand() {
3536        let statements = body_stmts("return\nanswer = 99");
3537        assert_eq!(statements.len(), 2);
3538        assert!(matches!(
3539            stmt_expr(&statements[0]).kind,
3540            ExprKind::Return(None)
3541        ));
3542        assert!(matches!(
3543            stmt_expr(&statements[1]).kind,
3544            ExprKind::Assign { .. }
3545        ));
3546    }
3547
3548    /// An operator on the line under a bare `break`, `continue`, or `return`
3549    /// does not continue it either: the keyword is already a whole
3550    /// expression, so the newline ends the statement.
3551    #[test]
3552    fn a_newline_ends_a_bare_keyword_before_an_operator() {
3553        for (source, keyword) in [
3554            ("break\n-1", "break"),
3555            ("continue\n-1", "continue"),
3556            ("return\n-1", "return"),
3557        ] {
3558            let statements = body_stmts(source);
3559            assert_eq!(statements.len(), 2, "`{keyword}` swallowed the next line");
3560            assert!(matches!(
3561                stmt_expr(&statements[1]).kind,
3562                ExprKind::Unary {
3563                    op: UnaryOp::Neg,
3564                    ..
3565                }
3566            ));
3567        }
3568    }
3569
3570    /// The rule constrains only where the operand *starts*. One that opens on
3571    /// the keyword's own line may run over as many further lines as it likes.
3572    #[test]
3573    fn an_operand_that_starts_on_the_keyword_line_may_span_lines() {
3574        let statements = body_stmts("return someCall(\n  a,\n  b,\n)");
3575        assert_eq!(statements.len(), 1);
3576        let ExprKind::Return(Some(value)) = &stmt_expr(&statements[0]).kind else {
3577            panic!("expected a `return` with an operand");
3578        };
3579        let ExprKind::Call { args, .. } = &value.kind else {
3580            panic!("expected a call");
3581        };
3582        assert_eq!(args.len(), 2);
3583
3584        let broken = body_stmts("break someCall(\n  a,\n  b,\n)");
3585        assert_eq!(broken.len(), 1);
3586        let ExprKind::Break(Some(value)) = &stmt_expr(&broken[0]).kind else {
3587            panic!("expected a `break` with an operand");
3588        };
3589        assert!(matches!(value.kind, ExprKind::Call { .. }));
3590    }
3591
3592    /// An operand on the keyword's own line still belongs to it, which is the
3593    /// half of the rule that must not regress.
3594    #[test]
3595    fn an_operand_on_the_same_line_still_belongs_to_the_keyword() {
3596        let broken = body_stmts("break value");
3597        assert_eq!(broken.len(), 1);
3598        assert!(matches!(
3599            stmt_expr(&broken[0]).kind,
3600            ExprKind::Break(Some(_))
3601        ));
3602
3603        let returned = body_stmts("return value");
3604        assert_eq!(returned.len(), 1);
3605        assert!(matches!(
3606            stmt_expr(&returned[0]).kind,
3607            ExprKind::Return(Some(_))
3608        ));
3609    }
3610
3611    /// A group suspends the newline rule for expressions that a further line
3612    /// could finish. A keyword whose operand is optional is already finished,
3613    /// so it ends at the line ending inside `(` as well.
3614    #[test]
3615    fn a_group_does_not_let_a_keyword_reach_the_next_line() {
3616        let statements = body_stmts("let f = fn() {\n  break\n  seen = 99\n}");
3617        assert_eq!(statements.len(), 1);
3618        let StmtKind::Let { value, .. } = &statements[0].kind else {
3619            panic!("expected a binding");
3620        };
3621        let ExprKind::Lambda { body, .. } = &value.kind else {
3622            panic!("expected a lambda");
3623        };
3624        assert_eq!(body.statements.len(), 1);
3625        assert!(matches!(
3626            body.statements[0].kind,
3627            StmtKind::Expr(Expr {
3628                kind: ExprKind::Break(None),
3629                ..
3630            })
3631        ));
3632    }
3633
3634    /// A line that starts with `.` continues the expression before it, so a
3635    /// method chain may be split across lines.
3636    #[test]
3637    fn a_method_chain_may_be_split_across_lines() {
3638        let statements = body_stmts("let result = value\n  .map(f)\n  .unwrapOr(0)");
3639        assert_eq!(statements.len(), 1);
3640        let StmtKind::Let { value, .. } = &statements[0].kind else {
3641            panic!("expected a binding");
3642        };
3643        let ExprKind::Call { callee, .. } = &value.kind else {
3644            panic!("expected a call");
3645        };
3646        let ExprKind::Field { name, .. } = &callee.kind else {
3647            panic!("expected a field");
3648        };
3649        assert_eq!(name.node, "unwrapOr");
3650    }
3651
3652    #[test]
3653    fn newlines_inside_parentheses_and_brackets_do_not_end_a_statement() {
3654        let call = tail_expr("request(\n  url: endpoint,\n  timeout: 5s\n)");
3655        let ExprKind::Call { args, .. } = &call.kind else {
3656            panic!("expected a call");
3657        };
3658        assert_eq!(args.len(), 2);
3659
3660        let array = tail_expr("[\n  1,\n  2,\n  3\n]");
3661        let ExprKind::ArrayLit(elements) = &array.kind else {
3662            panic!("expected an array literal");
3663        };
3664        assert_eq!(elements.len(), 3);
3665
3666        let parenthesised = tail_expr("(\n  1\n  + 2\n)");
3667        assert!(matches!(parenthesised.kind, ExprKind::Binary { .. }));
3668
3669        let generic = tail_expr("api.fetch<\n  Array<Booking>\n>(\n  \"/bookings\"\n)");
3670        let ExprKind::Call { generics, args, .. } = &generic.kind else {
3671            panic!("expected a call");
3672        };
3673        assert_eq!(generics.len(), 1);
3674        assert_eq!(args.len(), 1);
3675    }
3676
3677    #[test]
3678    fn newlines_inside_declaration_headers_and_field_lists_do_not_end_a_statement() {
3679        let unit = ok("fn f<\n  T\n>(\n  a: T,\n  b: Int = 1\n) -> Int {\n  b\n}");
3680        let decl = fn_decl(&unit.items[0]);
3681        assert_eq!(decl.generics.len(), 1);
3682        assert_eq!(decl.params.len(), 2);
3683
3684        let braced = ok("struct S {\n  a: Int\n  b: Map<\n    String,\n    Int\n  >\n}");
3685        let ItemKind::Struct(decl) = &braced.items[0].kind else {
3686            panic!("expected a struct");
3687        };
3688        assert_eq!(decl.fields.len(), 2);
3689
3690        let parens = ok("struct P(\n  a: Int,\n  b: Int\n)");
3691        let ItemKind::Struct(decl) = &parens.items[0].kind else {
3692            panic!("expected a struct");
3693        };
3694        assert_eq!(decl.fields.len(), 2);
3695    }
3696
3697    /// A block inside a group is still a block: its statements end at
3698    /// newlines even though the enclosing `(` suspended the rule.
3699    #[test]
3700    fn a_block_inside_a_group_still_ends_statements_at_newlines() {
3701        let call = tail_expr("spawn(fn() {\n  a()\n  b()\n})");
3702        let ExprKind::Call { args, .. } = &call.kind else {
3703            panic!("expected a call");
3704        };
3705        let ExprKind::Lambda { body, .. } = &args[0].value.kind else {
3706            panic!("expected a lambda");
3707        };
3708        assert_eq!(body.statements.len(), 1);
3709        assert!(body.tail.is_some());
3710    }
3711
3712    #[test]
3713    fn else_attaches_across_a_line_break() {
3714        let plain = tail_expr("if cond {\n}\nelse {\n}");
3715        let ExprKind::If { else_branch, .. } = &plain.kind else {
3716            panic!("expected an if");
3717        };
3718        assert!(matches!(
3719            else_branch.as_deref().map(|value| &value.kind),
3720            Some(ExprKind::Block(_))
3721        ));
3722
3723        let chained = tail_expr("if a {\n}\nelse if b {\n}\nelse {\n}");
3724        let ExprKind::If { else_branch, .. } = &chained.kind else {
3725            panic!("expected an if");
3726        };
3727        assert!(matches!(
3728            else_branch.as_deref().map(|value| &value.kind),
3729            Some(ExprKind::If { .. })
3730        ));
3731    }
3732
3733    #[test]
3734    fn a_match_arm_may_put_its_pattern_body_and_arrow_on_separate_lines() {
3735        let value = tail_expr("match x {\n  Ok(v)\n  =>\n    v\n  Err(e) => 0\n}");
3736        let ExprKind::Match { arms, .. } = &value.kind else {
3737            panic!("expected a match");
3738        };
3739        assert_eq!(arms.len(), 2);
3740        assert!(matches!(arms[0].body.kind, ExprKind::Ident(_)));
3741    }
3742
3743    /// A binary operator continues an expression only from the line it ends:
3744    /// `a +` / `b` is one expression, while `a` / `+ b` is two statements.
3745    /// The operand, not the operator, decides where the line may end.
3746    #[test]
3747    fn a_binary_operator_continues_only_from_the_end_of_a_line() {
3748        let continued = tail_expr("a +\n  b");
3749        assert!(matches!(continued.kind, ExprKind::Binary { .. }));
3750
3751        let split = errors("fn main() {\n  a\n+ b\n}");
3752        assert_eq!(codes(&split), ["cove::parse::newline_ended_statement"]);
3753        assert!(split[0].rule.is_some());
3754        assert!(split[0].help.is_some());
3755
3756        // Even where an expression was not what was expected, the reason the
3757        // operator is stranded is explained.
3758        let header = errors("fn main() {\n  if a\n  && b {\n  }\n}");
3759        assert!(header[0].rule.is_some());
3760        assert!(header[0].help.is_some());
3761
3762        let assignment = body_stmts("total =\n  1");
3763        assert_eq!(assignment.len(), 1);
3764        assert!(matches!(
3765            stmt_expr(&assignment[0]).kind,
3766            ExprKind::Assign { .. }
3767        ));
3768    }
3769
3770    /// `-` and `!` can begin an expression, so a line starting with one is a
3771    /// new statement rather than a continuation.
3772    #[test]
3773    fn a_leading_minus_starts_a_new_statement() {
3774        let statements = body_stmts("a\n- b");
3775        assert_eq!(statements.len(), 2);
3776        assert!(matches!(
3777            stmt_expr(&statements[1]).kind,
3778            ExprKind::Unary {
3779                op: UnaryOp::Neg,
3780                ..
3781            }
3782        ));
3783    }
3784
3785    #[test]
3786    fn a_detached_trailing_closure_explains_the_newline_rule() {
3787        let diagnostics = errors("fn main() {\n  tasks.spawn\n  { work() }\n}");
3788        assert_eq!(
3789            codes(&diagnostics),
3790            ["cove::parse::newline_before_trailing_closure"]
3791        );
3792        assert!(diagnostics[0].rule.is_some());
3793        assert!(diagnostics[0].help.is_some());
3794
3795        // On one line it is still a trailing closure.
3796        let attached = tail_expr("tasks.spawn { work() }");
3797        assert!(matches!(
3798            attached.kind,
3799            ExprKind::Call {
3800                trailing: Some(_),
3801                ..
3802            }
3803        ));
3804    }
3805    /// A block and the expression that is its body each raise the depth, so
3806    /// `fn main() { ... }` costs two levels before the parentheses start.
3807    const OUTER_LEVELS: usize = 2;
3808
3809    #[test]
3810    fn nesting_up_to_the_limit_parses() {
3811        let depth = MAX_NESTING_DEPTH as usize - OUTER_LEVELS;
3812        ok(&format!(
3813            "fn main() {{\n{}1{}\n}}",
3814            "(".repeat(depth),
3815            ")".repeat(depth)
3816        ));
3817    }
3818
3819    /// Every shape that nests, one level past the limit, in a debug build on
3820    /// whatever stack the test harness supplies — which is the case the
3821    /// limit exists for, since an overflow here would abort the test binary
3822    /// rather than fail this test.
3823    #[test]
3824    fn nesting_past_the_limit_is_a_diagnostic() {
3825        let past = MAX_NESTING_DEPTH as usize + 1;
3826        let sources = [
3827            format!(
3828                "fn main() {{\n{}1{}\n}}",
3829                "(".repeat(past),
3830                ")".repeat(past)
3831            ),
3832            format!(
3833                "fn main() {{\n{}1{}\n}}",
3834                "{".repeat(past),
3835                "}".repeat(past)
3836            ),
3837            format!(
3838                "fn main() {{\n{}1{}\n}}",
3839                "[".repeat(past),
3840                "]".repeat(past)
3841            ),
3842            format!("fn main() {{\n{}1\n}}", "-".repeat(past)),
3843            format!("fn main() {{\n  a = {}1\n}}", "a = ".repeat(past)),
3844            format!(
3845                "fn f(a: {}Int{}) {{}}",
3846                "Array<".repeat(past),
3847                ">".repeat(past)
3848            ),
3849            format!(
3850                "fn main() {{\n  match x {{\n    {}y{} => 1\n  }}\n}}",
3851                "Some(".repeat(past),
3852                ")".repeat(past)
3853            ),
3854            // Chains are parsed by a loop rather than by recursion, and are
3855            // counted because the tree they build is as deep as they are long.
3856            format!("fn main() {{\n  1{}\n}}", " + 1".repeat(past)),
3857            format!("fn main() {{\n  a{}\n}}", ".b".repeat(past)),
3858            format!("fn main() {{\n  a{}\n}}", "?".repeat(past)),
3859        ];
3860        for source in sources {
3861            let diagnostics = errors(&source);
3862            let first = &diagnostics[0];
3863            assert_eq!(first.code, "cove::parse::nesting_too_deep");
3864            assert!(first.message.contains("64"), "{}", first.message);
3865            assert!(
3866                first.primary.is_some(),
3867                "the limit reports where it was passed"
3868            );
3869            assert!(
3870                first.rule.is_some(),
3871                "the limit states the rule it enforces"
3872            );
3873            assert!(first.help.is_some(), "the limit says what to do instead");
3874        }
3875    }
3876
3877    /// A file whose nesting is three orders of magnitude past the limit is
3878    /// still one diagnostic and still finishes, because the parser recovers
3879    /// from this error the way it recovers from any other.
3880    #[test]
3881    fn nesting_far_past_the_limit_still_reports_and_returns() {
3882        let past = 100_000;
3883        let source = format!(
3884            "fn main() {{\n{}1{}\n}}",
3885            "(".repeat(past),
3886            ")".repeat(past)
3887        );
3888        let diagnostics = errors(&source);
3889        assert_eq!(codes(&diagnostics), vec!["cove::parse::nesting_too_deep"]);
3890    }
3891
3892    /// The nesting a string literal may contain is scanned before the parser
3893    /// runs, so the lexer must not recurse over it either.
3894    #[test]
3895    fn a_string_of_nothing_but_open_braces_is_a_lexical_error() {
3896        let source = format!("fn main() {{\n  \"{}\"\n}}", "{".repeat(100_000));
3897        let diagnostics = errors(&source);
3898        assert_eq!(
3899            codes(&diagnostics),
3900            vec!["cove::lex::unterminated_interpolation"]
3901        );
3902    }
3903
3904    fn collect_cove_files(dir: &Path, out: &mut Vec<PathBuf>) {
3905        let entries = std::fs::read_dir(dir)
3906            .unwrap_or_else(|error| panic!("cannot read {}: {error}", dir.display()));
3907        for entry in entries {
3908            let path = entry.expect("a directory entry").path();
3909            if path.is_dir() {
3910                collect_cove_files(&path, out);
3911            } else if path.extension().is_some_and(|ext| ext == "cove") {
3912                out.push(path);
3913            }
3914        }
3915    }
3916
3917    #[test]
3918    fn every_example_program_parses() {
3919        let root = Path::new(env!("CARGO_MANIFEST_DIR")).join("../../examples");
3920        let mut files = Vec::new();
3921        collect_cove_files(&root, &mut files);
3922        files.sort();
3923        assert!(
3924            files.len() >= 7,
3925            "expected the example programs to be found"
3926        );
3927
3928        for path in files {
3929            let relative = path
3930                .strip_prefix(&root)
3931                .expect("a path under examples")
3932                .to_string_lossy()
3933                .replace('\\', "/");
3934            let text = std::fs::read_to_string(&path).expect("readable example");
3935            let mut sources = SourceMap::new();
3936            let file = sources.add(path.clone(), text);
3937            let result = crate::parse_file(&sources, file);
3938            if let Err(diagnostics) = result {
3939                let rendered: String = diagnostics
3940                    .iter()
3941                    .map(|diagnostic| cove_diag::render(&sources, diagnostic))
3942                    .collect();
3943                panic!("{relative} failed to parse:\n{rendered}");
3944            }
3945        }
3946    }
3947}