praxis_parser/parse.rs
1//! The Praxis parser.
2//!
3//! Recursive descent over statements and structure, with a Pratt (precedence
4//! climbing) loop for arithmetic and the other binary operators (ADR-004). It
5//! consumes the lexer's [`Token`] stream and emits a rowan green tree
6//! (ADR-003) via [`GreenNodeBuilder`], retaining trivia so the tree is lossless
7//! (§13.1). On an unexpected token it emits a `P0xx` diagnostic, wraps the stray
8//! token in a [`SyntaxKind::PARSE_ERROR`] node, advances to a synchronization
9//! point, and keeps going — that is the LSP-grade recovery required by §15.2.
10//!
11//! The grammar is §19: `fn`/`struct`/`enum` items, `var` bindings and
12//! assignment, blocks, `if`/`while`/`for`/`loop`/`match`, and expressions —
13//! literals, calls, closures, ranges, record and collection literals, patterns,
14//! and `read`'s parser expressions (§7.1).
15
16use praxis_source::diagnostic::sort_by_position;
17use praxis_source::{BytePos, Span};
18use praxis_source::{DiagCode, Diagnostic, FileId, FileSpan, Severity};
19use praxis_syntax::{PraxisLanguage, SyntaxKind, SyntaxNode, Token};
20use rowan::{GreenNodeBuilder, Language};
21
22use crate::lex::{LexOutput, lex};
23
24/// The result of parsing one source file: the lossless tree, the lexed tokens,
25/// and any diagnostics (lex + parse merged).
26#[derive(Debug)]
27pub struct ParseOutput {
28 /// The lossless syntax tree (trivia retained). Always produced, even when
29 /// the input is malformed — error nodes ([`SyntaxKind::PARSE_ERROR`]) carry
30 /// the tokens the parser could not place.
31 pub tree: SyntaxNode,
32 /// The token stream from the lex pass, kept for later LSP use (semantic
33 /// tokens) and diagnostics.
34 pub tokens: Vec<Token>,
35 /// Lex (`T0xx`) and parse (`P0xx`) diagnostics, in source order.
36 pub diagnostics: Vec<Diagnostic>,
37}
38
39/// Lex then parse `text` belonging to `file`.
40///
41/// This is the front-end entry point the CLI threads in after reading a file.
42/// It never panics on malformed input; it always returns a tree and as many
43/// diagnostics as it could gather.
44pub fn parse(file: FileId, text: &str) -> ParseOutput {
45 let LexOutput {
46 tokens,
47 mut diagnostics,
48 } = lex(file, text);
49 let mut parser = Parser::new(file, text, &tokens);
50 parser.parse_source_file();
51 let (green, parse_diags) = parser.finish();
52 diagnostics.extend(parse_diags);
53 sort_by_position(&mut diagnostics);
54 let tree = SyntaxNode::new_root(green);
55 ParseOutput {
56 tree,
57 tokens,
58 diagnostics,
59 }
60}
61
62// ---------------------------------------------------------------------------
63// Precedence table (Pratt climbing).
64// ---------------------------------------------------------------------------
65
66/// Binary operator binding power. Higher binds tighter. Left-associative
67/// operators parse by calling `expr(min_bp + 1)` on the right; right-associative
68/// ones would call `expr(min_bp)` (none exist, but the table is shaped to allow
69/// it).
70#[derive(Clone, Copy)]
71struct BindingPower {
72 left: u8,
73 right: u8,
74}
75
76/// The binding power of `op`, or `None` if it is not a binary operator.
77fn infix_binding_power(op: SyntaxKind) -> Option<BindingPower> {
78 Some(match op {
79 // Logical or (lowest of all).
80 SyntaxKind::PIPE2 => bp(1, 2),
81 // Range (§4.11, ADR-059): below comparison, above nothing but `||`. So
82 // `0..n - 1` is `0..(n - 1)` — the bound is an arithmetic expression,
83 // which is how every range in the corpus is written.
84 SyntaxKind::DOT2 | SyntaxKind::DOT2EQ => bp(3, 4),
85 // Logical and: **below comparison and above `..`**. The two rules that
86 // matter are that `&&` binds tighter than `||` (`a || b && c` is
87 // `a || (b && c)`) and looser than comparison (`a == b && c == d` is
88 // `(a == b) && (c == d)`), which is §3.3's own shape. Where `&&` sits
89 // relative to `..` is arbitrary — a range of `Bool`s and a range bound
90 // that is a `&&` are both nonsense.
91 SyntaxKind::AMP2 => bp(5, 6),
92 // Comparison (non-associative in spirit; we parse left-assoc).
93 SyntaxKind::EQ2
94 | SyntaxKind::NEQ
95 | SyntaxKind::LT
96 | SyntaxKind::GT
97 | SyntaxKind::LTEQ
98 | SyntaxKind::GTEQ => bp(7, 8),
99 // Additive.
100 SyntaxKind::PLUS | SyntaxKind::MINUS => bp(9, 10),
101 // Multiplicative.
102 SyntaxKind::STAR | SyntaxKind::SLASH | SyntaxKind::PERCENT => bp(11, 12),
103 _ => return None,
104 })
105}
106
107/// The node kind an infix operator builds. Every operator but `..`/`..=` builds
108/// a [`SyntaxKind::BIN_EXPR`]; a range is its own node because it is not an
109/// operator applied to two numbers but a collection built from two bounds.
110fn infix_node_kind(op: SyntaxKind) -> SyntaxKind {
111 match op {
112 SyntaxKind::DOT2 | SyntaxKind::DOT2EQ => SyntaxKind::RANGE_EXPR,
113 _ => SyntaxKind::BIN_EXPR,
114 }
115}
116
117/// Prefix (unary) operator binding power.
118fn prefix_binding_power(op: SyntaxKind) -> Option<u8> {
119 match op {
120 // Above every infix operator, so `!a && b` is `(!a) && b` — §3.3's own
121 // `!diagonals && dx != 0` — and `-a * b` is `(-a) * b`.
122 SyntaxKind::MINUS | SyntaxKind::BANG => Some(13),
123 // `read` is a prefix expression (§7.1): `read parser_expression`. Its
124 // body is a parser-expression, not an ordinary expression, so it gets
125 // the highest binding power (binds tighter than arithmetic).
126 SyntaxKind::KW_READ => Some(15),
127 _ => None,
128 }
129}
130
131/// The compiler-owned type constructors, the only names that take an explicit
132/// type-argument list in expression position (§3.3's `Counter[(Int, Int)]()`).
133///
134/// The parser has to know these **by name**, because nothing else can tell
135/// `Counter[(Int, Int)]()` from `m[key]`: the brackets are the same and the
136/// contents are ambiguous too — `Int` is a legal expression, and `(Int, Int)` a
137/// legal tuple of two. `parse`'s own special case (§7.1) is the precedent for a
138/// name-driven decision here.
139///
140/// The list is the §6.1 collection set plus `Option`, and `praxis-hir`'s
141/// `is_type_ctor_name` is the other copy of it —
142/// `the_parsers_type_constructors_are_the_compilers` asserts the two agree, so a
143/// name in only one cannot go unnoticed.
144pub const TYPE_CONSTRUCTOR_NAMES: &[&str] = &[
145 "Vec", "Deque", "Map", "Set", "Counter", "MinHeap", "MaxHeap", "BitSet", "Grid", "Range",
146 "Option",
147];
148
149/// Whether `op` is an assignment operator (statement-level reassignment, §4.2).
150/// These are not infix expression operators; they are parsed as statements.
151fn is_assignment_op(op: SyntaxKind) -> bool {
152 matches!(
153 op,
154 SyntaxKind::EQ
155 | SyntaxKind::PLUS_EQ
156 | SyntaxKind::MINUS_EQ
157 | SyntaxKind::STAR_EQ
158 | SyntaxKind::SLASH_EQ
159 | SyntaxKind::PERCENT_EQ
160 )
161}
162
163/// Whether `kind` can start a match pattern (§4.6). Used to decide whether
164/// to continue parsing arms after a newline (arms are comma-OR-newline separated).
165///
166/// This set must stay the set [`Parser::parse_pattern`] consumes: a pattern this
167/// admits is one that parses, and one it rejects silently ends the arm list.
168fn is_pattern_start(kind: SyntaxKind) -> bool {
169 // The literal half is `SyntaxKind::is_pattern_literal` — the same set
170 // `parse_pattern` consumes and `praxis_ast::Pattern` reads back.
171 kind.is_pattern_literal()
172 || matches!(
173 kind,
174 SyntaxKind::UNDERSCORE
175 | SyntaxKind::Ident
176 // A tuple pattern.
177 | SyntaxKind::L_PAREN
178 // A headless record pattern (ADR-091).
179 | SyntaxKind::L_BRACE
180 )
181}
182
183const fn bp(left: u8, right: u8) -> BindingPower {
184 BindingPower { left, right }
185}
186
187// ---------------------------------------------------------------------------
188// Statement separation (D8, ADR-049).
189// ---------------------------------------------------------------------------
190
191/// Whether a bare `Name { … }` in expression position is a record literal.
192///
193/// `if p { … }` is genuinely ambiguous: `p { … }` could be a record literal, or
194/// `p` could be the condition and `{ … }` the then-block. The four keyword heads
195/// — `if`, `while`, `for`'s iterator, `match`'s scrutinee — resolve it by
196/// suppressing the literal, and the suppression follows the operands of the
197/// expression they own.
198///
199/// It stops at the first bracket. Inside `(…)`, `[…]`, an argument list or a
200/// block, the `{` cannot be the body the keyword is looking for, so there is
201/// nothing left to disambiguate — which is why suppression is a parameter
202/// threaded through the expression grammar rather than parser-wide state. State
203/// would leak into every parenthesized subexpression and every match-arm body,
204/// making valid record literals unwritable there.
205#[derive(Clone, Copy, PartialEq, Eq, Debug)]
206enum StructLit {
207 Allowed,
208 Suppressed,
209}
210
211/// What ended a statement.
212///
213/// Returning this rather than a `bool` is the point: a statement loop cannot
214/// advance without either producing a separator value or emitting a diagnostic,
215/// so "two statements adjacent with no separator" has no accepted
216/// representation (D8, ADR-049).
217#[derive(Clone, Copy, PartialEq, Eq, Debug)]
218enum StmtSeparator {
219 /// An explicit `;`, consumed.
220 Semicolon,
221 /// A line break before the next token. The newline itself is trivia and
222 /// stays trivia — the fact that it existed rides on the token after it.
223 Newline,
224 /// `}` or end of file: there is no next statement to separate from.
225 EndOfBlock,
226}
227
228/// What `(1,)` and `(Int,)` are told, in one place because they are one rule
229/// (§4.4). The expression and the type position both reach it through
230/// [`Parser::parse_parenthesized`]; a second copy of the sentence is a second
231/// thing to forget to change.
232const ONE_ELEMENT_TUPLE_MSG: &str = "a tuple has two elements or more, so this comma names nothing";
233
234// ---------------------------------------------------------------------------
235// Parser state.
236// ---------------------------------------------------------------------------
237
238struct Parser<'t> {
239 file: FileId,
240 /// Full source text; needed to extract each token's spelling for the green
241 /// tree (the lexer only stored spans, not text).
242 text: &'t str,
243 tokens: &'t [Token],
244 /// Index into `tokens`; advances monotonically.
245 cursor: usize,
246 builder: GreenNodeBuilder<'static>,
247 diagnostics: Vec<Diagnostic>,
248}
249
250impl<'t> Parser<'t> {
251 fn new(file: FileId, text: &'t str, tokens: &'t [Token]) -> Parser<'t> {
252 Parser {
253 file,
254 text,
255 tokens,
256 cursor: 0,
257 builder: GreenNodeBuilder::new(),
258 diagnostics: Vec::new(),
259 }
260 }
261
262 // --- entry point ---
263
264 fn parse_source_file(&mut self) {
265 self.start_root_node(SyntaxKind::SOURCE_FILE);
266 while !self.at_end() {
267 // Emit any trivia leading each statement into the root node.
268 self.eat_trivia();
269 if self.at_end() {
270 break;
271 }
272 let before = self.meaningful_index();
273 if self.parse_stmt() {
274 // A statement is separated from the next by `;`, a newline, or
275 // the end of the file — and by nothing else.
276 self.expect_stmt_separator();
277 } else {
278 // Recovery: skip to the next statement boundary.
279 self.recover_to_stmt_boundary();
280 }
281 // Guarantee termination on any input (defense against infinite loops).
282 self.ensure_progress(before);
283 }
284 // Trailing trivia belongs to the root.
285 self.eat_trivia();
286 self.finish_node();
287 }
288
289 // --- token cursor (over the meaningful stream; trivia emitted on sight) ---
290
291 /// The kind of the current meaningful token (trivia skipped for the
292 /// decision, but not consumed — it is emitted when bumped).
293 fn peek(&mut self) -> SyntaxKind {
294 self.nth_kind(0)
295 }
296
297 /// Kind of the meaningful token `n` positions ahead (0 = current).
298 fn nth_kind(&mut self, n: usize) -> SyntaxKind {
299 let mut idx = self.cursor;
300 let mut want = n;
301 while idx < self.tokens.len() {
302 let kind = self.tokens[idx].kind;
303 if kind.is_trivia() {
304 idx += 1;
305 continue;
306 }
307 if want == 0 {
308 return kind;
309 }
310 want -= 1;
311 idx += 1;
312 }
313 SyntaxKind::EOF
314 }
315
316 /// Whether the cursor is past the last meaningful token.
317 fn at_end(&mut self) -> bool {
318 self.peek() == SyntaxKind::EOF
319 }
320
321 /// True iff a line break sits between the previous meaningful token and the
322 /// current one (D8, ADR-049).
323 ///
324 /// The flag lives on the token *after* the break, so this answer does not
325 /// depend on whether the intervening trivia has already been emitted into
326 /// the tree.
327 fn newline_before(&self) -> bool {
328 self.newline_before_nth(0)
329 }
330
331 /// [`Parser::newline_before`] about the meaningful token `n` positions ahead
332 /// (0 = current). The field-vs-method decision looks one token past the name,
333 /// and `p.x\n(a, b)` must not be a method call for the same reason
334 /// `10\n(a, b)` must not be one.
335 fn newline_before_nth(&self, n: usize) -> bool {
336 self.tokens[self.cursor..]
337 .iter()
338 .filter(|token| !token.kind.is_trivia())
339 .nth(n)
340 .is_some_and(|token| token.preceded_by_newline)
341 }
342
343 /// True iff the `(` here opens an **argument list** for the expression that
344 /// precedes it, rather than beginning something new.
345 ///
346 /// A `(` begins three things: a parenthesized expression, a tuple, and a
347 /// **tuple pattern**, in a match arm and in a `for` binding. So a line-leading
348 /// `(` is ambiguous in exactly the way ADR-049's rule is written to settle:
349 ///
350 /// ```text
351 /// match p {
352 /// (0, 0) => 10
353 /// (a, b) => a + b // a second arm, not `10(a, b)`
354 /// }
355 /// ```
356 ///
357 /// A match arm has no workaround for the ambiguity — a tuple pattern *is* how
358 /// the arm is written — so the tie is broken by D8's own rule: a newline ends
359 /// a statement. It is not consulted anywhere in the Pratt operator loop, so
360 /// `1 +\n2` and a `.method()` chain across lines are unaffected, and a `(`
361 /// that opens an expression is unaffected — only a `(` asked to *continue* one
362 /// is.
363 ///
364 /// The cost is stated rather than hidden: a call whose callee ends a line and
365 /// whose argument list begins the next (`f\n(1)`) is two expressions, and the
366 /// fix is to move the `(` up.
367 fn at_argument_list(&mut self) -> bool {
368 self.at(SyntaxKind::L_PAREN) && !self.newline_before()
369 }
370
371 /// True iff the `[` here opens a **subscript** on the expression that
372 /// precedes it, rather than beginning a list literal.
373 ///
374 /// [`at_argument_list`](Self::at_argument_list)'s rule at the second bracket.
375 /// A `[` both begins a list literal and continues the expression before it,
376 /// and the two spellings are the same two characters:
377 ///
378 /// ```text
379 /// var n = total
380 /// [1, 2, 3] // a list literal, not `total[1, 2, 3]`
381 /// ```
382 ///
383 /// So the tie is broken by position, exactly as it is for `(`: a `[` on the
384 /// same line as what precedes it subscripts that expression, and a
385 /// line-leading `[` starts a new one. `m[k]`, `grid[x, y]` and `m[k][j]` are
386 /// unaffected — every one of them is written on one line — and the cost is
387 /// the mirror of the argument-list rule's: a subscript whose receiver ends a
388 /// line and whose bracket begins the next is two expressions, and the fix is
389 /// to move the `[` up.
390 fn at_subscript(&mut self) -> bool {
391 self.at(SyntaxKind::L_BRACK) && !self.newline_before()
392 }
393
394 /// True iff a value follows `break`/`return` on the same line.
395 ///
396 /// Two questions, both of which must say yes: the next token has to be able
397 /// to begin an expression at all (a `;`, `}`, `)`, `,`, `else` or `in`
398 /// cannot), and it has to be on *this* line — `return\n1` is a value-less
399 /// return followed by a separate statement, which is the second half of
400 /// D8's rule.
401 fn starts_expr(&mut self) -> bool {
402 if self.newline_before() {
403 return false;
404 }
405 // Consume trivia so the cursor lands on the meaningful token, then check
406 // whether that token can begin an expression.
407 self.eat_trivia();
408 let k = self
409 .tokens
410 .get(self.cursor)
411 .map(|t| t.kind)
412 .unwrap_or(SyntaxKind::EOF);
413 use SyntaxKind::*;
414 !matches!(
415 k,
416 EOF | SEMICOLON | R_BRACE | R_PAREN | COMMA | KW_ELSE | KW_IN
417 )
418 }
419
420 /// Demand the separator that must follow a statement, and report which one
421 /// it was — `;`, a line break, or the end of the enclosing block/file.
422 ///
423 /// `None` means there was none: two statements ran together on one line, and
424 /// a `P002` has been emitted at the second one. The caller keeps parsing
425 /// (one diagnostic per run-on, not a cascade), because the statement itself
426 /// was well-formed and the next one usually is too.
427 fn expect_stmt_separator(&mut self) -> Option<StmtSeparator> {
428 if self.eat(SyntaxKind::SEMICOLON) {
429 return Some(StmtSeparator::Semicolon);
430 }
431 if self.at_end() || self.at(SyntaxKind::R_BRACE) {
432 return Some(StmtSeparator::EndOfBlock);
433 }
434 if self.newline_before() {
435 return Some(StmtSeparator::Newline);
436 }
437 let span = self.current_span();
438 self.error_with(
439 DiagCode::ExpectedStatementSeparator,
440 span,
441 "expected `;` or a line break between statements",
442 );
443 None
444 }
445
446 /// The source text of the current meaningful token (trivia skipped). Used to
447 /// special-case keywords-that-look-like-idents such as `parse` and parser
448 /// constructor names (`lines`, `csv`, …).
449 fn peek_text(&mut self) -> Option<&'t str> {
450 let mut idx = self.cursor;
451 while idx < self.tokens.len() {
452 let kind = self.tokens[idx].kind;
453 if kind.is_trivia() {
454 idx += 1;
455 continue;
456 }
457 let span = self.tokens[idx].span;
458 return Some(&self.text[span.start().to_usize()..span.end().to_usize()]);
459 }
460 None
461 }
462
463 /// `true` if an updating store's operator starts here: an `Ident` spelling
464 /// `min` or `max`, **immediately** followed by `=` (§6.2).
465 ///
466 /// Adjacency is the rule, exactly as it is for `+=`: `min=` is one operator
467 /// spelled in two tokens because `min` is an identifier, and `min = x` with a
468 /// space is two tokens that mean what they say. Checking the raw token stream
469 /// rather than [`Parser::nth_kind`] is what makes that askable — `nth_kind`
470 /// skips trivia, which is precisely the difference.
471 ///
472 /// `==` cannot be mistaken for it: the lexer's max-munch makes that one
473 /// `EQ2` token.
474 fn at_update_op(&mut self) -> bool {
475 if !self.at(SyntaxKind::Ident) {
476 return false;
477 }
478 if !matches!(self.peek_text(), Some("min" | "max")) {
479 return false;
480 }
481 let ident = self.meaningful_index();
482 self.tokens
483 .get(ident + 1)
484 .is_some_and(|t| t.kind == SyntaxKind::EQ)
485 }
486
487 /// `true` if a statement's `:bp` breakpoint marker starts here: a `:`
488 /// **immediately** followed by an `Ident` spelling `bp` (§9.8).
489 ///
490 /// [`Parser::at_update_op`]'s shape, and adjacency is the rule for its
491 /// reason: `bp` is an identifier, so `:bp` is one marker spelled in two
492 /// tokens, and `: bp` with a space is a `:` followed by a name. The raw
493 /// token stream is what makes that askable — [`Parser::nth_kind`] skips
494 /// trivia, which is exactly the difference between the two spellings.
495 ///
496 /// A type annotation cannot be mistaken for it, because this is only ever
497 /// asked at the *end* of a statement: `var x: Int = 1` has consumed its `:`
498 /// inside [`Parser::parse_var`] long before this runs, and a `:` that
499 /// survives to a statement's end begins nothing else in the grammar.
500 fn at_breakpoint_marker(&mut self) -> bool {
501 self.is_breakpoint_marker_at(self.meaningful_index())
502 }
503
504 /// Whether the raw token at `colon` is a `:` that begins a `:bp` marker.
505 ///
506 /// The marker's rule lives here and nowhere else. A `{`'s lookahead has to
507 /// ask the same question one token further along — `{ x:bp }` is a block
508 /// holding a marked statement, `{ x: bp }` is a record literal whose field
509 /// is the binding `bp` — and asking it by re-spelling the adjacency test
510 /// would put the rule in two places for the two positions to drift apart.
511 fn is_breakpoint_marker_at(&self, colon: usize) -> bool {
512 if self.tokens.get(colon).map(|t| t.kind) != Some(SyntaxKind::COLON) {
513 return false;
514 }
515 self.tokens.get(colon + 1).is_some_and(|t| {
516 t.kind == SyntaxKind::Ident
517 && &self.text[t.span.start().to_usize()..t.span.end().to_usize()] == "bp"
518 })
519 }
520
521 /// Consume a trailing `:bp` marker into a [`SyntaxKind::BREAKPOINT`] node,
522 /// if one is here. Answers whether it consumed anything.
523 ///
524 /// Called from each statement parser just before it closes its own node, so
525 /// the marker is a *child of the statement it marks* rather than a sibling
526 /// of it. That is what lets HIR lowering ask a statement node whether it
527 /// carries one without re-deriving the association from source positions.
528 fn eat_breakpoint_marker(&mut self) -> bool {
529 if !self.at_breakpoint_marker() {
530 return false;
531 }
532 // `start_node` sweeps the leading trivia into the *enclosing* node, so
533 // the whitespace before `:bp` stays outside the marker. The two tokens
534 // are adjacent by `at_breakpoint_marker`'s check, so neither bump needs
535 // a sweep of its own.
536 self.start_node(SyntaxKind::BREAKPOINT);
537 self.bump_meaningful(); // `:`
538 self.bump_meaningful(); // `bp`
539 self.finish_node();
540 true
541 }
542
543 /// `true` if the current meaningful token is `kind`.
544 fn at(&mut self, kind: SyntaxKind) -> bool {
545 self.peek() == kind
546 }
547
548 /// Consume the current meaningful token if it is `kind`, returning `true`.
549 /// Emits any trivia encountered first.
550 fn eat(&mut self, kind: SyntaxKind) -> bool {
551 if self.at(kind) {
552 self.bump();
553 true
554 } else {
555 false
556 }
557 }
558
559 /// Consume the current meaningful token and append it (plus any leading
560 /// trivia) to the tree. Panics only if called at EOF — the grammar always
561 /// checks `at`/`at_end` first, so this is unreachable in well-formed calls.
562 fn bump(&mut self) {
563 // Emit any trivia sitting before the token we are about to take.
564 self.eat_trivia();
565 self.bump_meaningful();
566 }
567
568 /// Consume the current token assuming trivia has already been emitted (no
569 /// trivia sweep). Used after an explicit `eat_trivia` to keep trivia out of
570 /// a node that is about to be opened.
571 fn bump_meaningful(&mut self) {
572 debug_assert!(self.cursor < self.tokens.len(), "bump past EOF");
573 let token = self.tokens[self.cursor];
574 if token.kind == SyntaxKind::EOF {
575 // Do not advance past EOF; callers should not bump it.
576 return;
577 }
578 self.emit_token(token);
579 self.cursor += 1;
580 }
581
582 /// The index of the current *meaningful* token (skipping trivia). Used to
583 /// detect whether a sub-parse made progress; an infinite loop anywhere in
584 /// the grammar would show up as `meaningful_index()` not advancing.
585 fn meaningful_index(&self) -> usize {
586 self.nth_index(0).unwrap_or(self.tokens.len())
587 }
588
589 /// The **raw** token index of the meaningful token `n` positions ahead
590 /// (0 = current), or `None` past the last one.
591 ///
592 /// [`Parser::nth_kind`]'s answer with the position kept, which is what an
593 /// adjacency question needs: `nth_kind` skips trivia, so it cannot tell
594 /// `:bp` from `: bp`, and every two-token operator in this grammar
595 /// (`min=`, `:bp`) is decided by whether the second token *touches* the
596 /// first. `meaningful_index` answers that for the token under the cursor;
597 /// this answers it for one further ahead, which is where a `{`'s contents
598 /// are read from.
599 fn nth_index(&self, n: usize) -> Option<usize> {
600 let mut idx = self.cursor;
601 let mut want = n;
602 while idx < self.tokens.len() {
603 if self.tokens[idx].kind.is_trivia() {
604 idx += 1;
605 continue;
606 }
607 if want == 0 {
608 return Some(idx);
609 }
610 want -= 1;
611 idx += 1;
612 }
613 None
614 }
615
616 /// Defense against catastrophic infinite loops: if the cursor did not
617 /// advance past `before`, consume one token (in a PARSE_ERROR node) so the
618 /// parser always makes progress. Every loop over statements/expressions
619 /// calls this after each body iteration.
620 ///
621 /// This is a safety net, not the primary recovery mechanism — the grammar
622 /// is written to always consume — but it guarantees termination on any
623 /// input, which is a hard requirement (§19: "no panic on fuzzed input",
624 /// and an OOM-kill from an unbounded loop is a panic in disguise).
625 fn ensure_progress(&mut self, before: usize) {
626 let now = self.meaningful_index();
627 if now <= before && !self.at_end() {
628 self.start_node(SyntaxKind::PARSE_ERROR);
629 let span = self.current_span();
630 self.error(span, "stuck: skipping token to make progress");
631 self.bump();
632 self.finish_node();
633 }
634 }
635
636 /// Emit trivia (whitespace/comments) into the tree up to, but not
637 /// including, the next meaningful token. Trivia is part of the lossless
638 /// tree, so it must be appended even though it is ignored for decisions.
639 fn eat_trivia(&mut self) {
640 while self.cursor < self.tokens.len() {
641 let kind = self.tokens[self.cursor].kind;
642 if !kind.is_trivia() {
643 break;
644 }
645 self.emit_token(self.tokens[self.cursor]);
646 self.cursor += 1;
647 }
648 }
649
650 /// Append a single token's text to the green tree.
651 fn emit_token(&mut self, token: Token) {
652 // Compute the byte range first so the immutable borrow of `self.text`
653 // ends before the mutable borrow of `self.builder` begins.
654 let start = token.span.start().to_u32() as usize;
655 let end = token.span.end().to_u32() as usize;
656 let text = &self.text[start..end];
657 self.builder
658 .token(PraxisLanguage::kind_to_raw(token.kind), text);
659 }
660
661 // --- green-tree helpers ---
662
663 /// Open a node **on its first meaningful token** — the trivia in front of it
664 /// is emitted first, so it lands in the enclosing node instead.
665 ///
666 /// This is the whole of the rule "a node never begins with trivia", and it
667 /// belongs here rather than at every call site. It is what makes a node's
668 /// span the node's own text: the `PATH_EXPR` for `a` in `var c = a + b`
669 /// spans `"a"` and not `" a"`, so the caret in a diagnostic that underlines
670 /// an expression starts at the expression.
671 ///
672 /// The root is the one node this cannot open ([`start_root_node`](Self::start_root_node)):
673 /// there is nothing to emit trivia into before it exists.
674 fn start_node(&mut self, kind: SyntaxKind) {
675 self.eat_trivia();
676 self.builder.start_node(PraxisLanguage::kind_to_raw(kind));
677 }
678
679 /// Open the root node. The only node opened *before* its leading trivia,
680 /// because a token cannot be emitted with no node open — the root is where
681 /// a file's leading trivia goes.
682 fn start_root_node(&mut self, kind: SyntaxKind) {
683 self.builder.start_node(PraxisLanguage::kind_to_raw(kind));
684 }
685
686 fn finish_node(&mut self) {
687 self.builder.finish_node();
688 }
689
690 fn start_node_at(&mut self, cp: rowan::Checkpoint, kind: SyntaxKind) {
691 self.builder
692 .start_node_at(cp, PraxisLanguage::kind_to_raw(kind));
693 }
694
695 // --- diagnostics ---
696
697 fn error(&mut self, span: Span, message: impl Into<String>) {
698 self.error_with(DiagCode::UnexpectedToken, span, message);
699 }
700
701 fn error_with(&mut self, code: DiagCode, span: Span, message: impl Into<String>) {
702 self.diagnostics.push(Diagnostic::new(
703 Severity::Error,
704 code,
705 message,
706 FileSpan::new(self.file, span),
707 ));
708 }
709
710 /// Consume `self` to produce the green node and the parse diagnostics.
711 fn finish(self) -> (rowan::GreenNode, Vec<Diagnostic>) {
712 let green = self.builder.finish();
713 (green, self.diagnostics)
714 }
715
716 // -----------------------------------------------------------------------
717 // Grammar.
718 // -----------------------------------------------------------------------
719
720 /// Parse one statement. Returns `false` if recovery was needed.
721 fn parse_stmt(&mut self) -> bool {
722 match self.peek() {
723 SyntaxKind::KW_VAR => self.parse_var(),
724 SyntaxKind::KW_FN => self.parse_fn_item(),
725 SyntaxKind::KW_STRUCT => self.parse_struct_item(),
726 SyntaxKind::KW_ENUM => self.parse_enum_item(),
727 // `name = expr` / `name += expr` reassignment (§4.2).
728 SyntaxKind::Ident if is_assignment_op(self.nth_kind(1)) => self.parse_assign_stmt(),
729 _ => self.parse_expr_stmt(),
730 }
731 }
732
733 /// `var name [: Type] = expr` — the language's one binding form (§4.2).
734 fn parse_var(&mut self) -> bool {
735 self.start_node(SyntaxKind::VAR_STMT);
736 self.bump(); // `var`
737 self.expect_binder("binding name");
738 // Optional type annotation `: Type`.
739 if self.eat(SyntaxKind::COLON) {
740 self.parse_type();
741 }
742 self.expect(SyntaxKind::EQ, "`=`");
743 self.parse_expr();
744 self.eat_breakpoint_marker();
745 self.finish_node();
746 true
747 }
748
749 /// `name = expr` or `name += expr` (etc.) — reassignment to an existing
750 /// binding (§4.2). The lhs is a bare name; a field or subscript target
751 /// builds a `PLACE_ASSIGN_STMT` in
752 /// [`parse_expr_stmt`](Self::parse_expr_stmt) instead.
753 fn parse_assign_stmt(&mut self) -> bool {
754 self.start_node(SyntaxKind::ASSIGN_STMT);
755 self.bump(); // name
756 self.bump(); // assignment operator (=, +=, ...)
757 self.parse_expr();
758 self.eat_breakpoint_marker();
759 self.finish_node();
760 true
761 }
762
763 /// `fn name(params) -> Ret { body }` (params and return type optional).
764 fn parse_fn_item(&mut self) -> bool {
765 self.start_node(SyntaxKind::FN_ITEM);
766 self.bump(); // `fn`
767 self.expect(SyntaxKind::Ident, "function name");
768 if self.eat(SyntaxKind::L_PAREN) {
769 self.start_node(SyntaxKind::PARAM_LIST);
770 // Zero or more `name: Type` params separated by commas.
771 if !self.at(SyntaxKind::R_PAREN) {
772 loop {
773 let before = self.meaningful_index();
774 self.start_node(SyntaxKind::PARAM);
775 self.expect_binder("parameter name");
776 // The `: Type` annotation is OPTIONAL (§4.9, criterion 1):
777 // `fn manhattan(a, b) { … }` infers param types from use.
778 if self.eat(SyntaxKind::COLON) {
779 self.parse_type();
780 }
781 self.finish_node();
782 if !self.eat(SyntaxKind::COMMA) {
783 break;
784 }
785 // A trailing comma closes the list.
786 if self.at(SyntaxKind::R_PAREN) {
787 break;
788 }
789 // Guarantee termination on any input.
790 self.ensure_progress(before);
791 }
792 }
793 self.expect(SyntaxKind::R_PAREN, "`)`");
794 self.finish_node();
795 }
796 // Optional `-> Type` return annotation.
797 if self.eat(SyntaxKind::THIN_ARROW) {
798 self.parse_type();
799 }
800 // Body.
801 if self.at(SyntaxKind::L_BRACE) {
802 self.parse_block();
803 } else {
804 let span = self.current_span();
805 self.error(span, "expected `{` to begin function body");
806 }
807 self.finish_node();
808 true
809 }
810
811 /// `struct Name { field: Type, … }` (§4.5). The field list is a
812 /// `FIELD_LIST` of `FIELD` children, each `name: Type`.
813 fn parse_struct_item(&mut self) -> bool {
814 self.start_node(SyntaxKind::STRUCT_ITEM);
815 self.bump(); // `struct`
816 self.expect(SyntaxKind::Ident, "struct name");
817 self.expect(SyntaxKind::L_BRACE, "`{` to begin struct fields");
818 self.start_node(SyntaxKind::FIELD_LIST);
819 if !self.at(SyntaxKind::R_BRACE) {
820 loop {
821 let before = self.meaningful_index();
822 self.start_node(SyntaxKind::FIELD);
823 self.expect(SyntaxKind::Ident, "field name");
824 self.expect(SyntaxKind::COLON, "`:` before field type");
825 self.parse_type();
826 self.finish_node();
827 // A comma **or** a line break separates fields — §4.5's own
828 // `struct Point { x: Int\n y: Int }` writes the second, and a
829 // trailing comma closes the list either way.
830 if !self.member_separator("struct fields") {
831 break;
832 }
833 self.ensure_progress(before);
834 }
835 }
836 self.expect(SyntaxKind::R_BRACE, "`}` to end struct fields");
837 self.finish_node(); // FIELD_LIST
838 self.finish_node(); // STRUCT_ITEM
839 true
840 }
841
842 /// Whether another member of a brace-delimited declaration follows, having
843 /// consumed the separator between them.
844 ///
845 /// A member is followed by a comma **or** a line break, which is the rule
846 /// match arms use (D8, ADR-049) and the one §4.5's and §4.6's own
847 /// declarations are written with:
848 ///
849 /// ```praxis
850 /// struct Point {
851 /// x: Int
852 /// y: Int
853 /// }
854 /// ```
855 ///
856 /// The two separators are interchangeable and a trailing comma still closes
857 /// the list, so the answer is `false` at the closing brace whichever one
858 /// preceded it. A member that follows with *neither* is reported at the
859 /// same code a run-together statement is — and then parsed anyway, because
860 /// the mistake is the separator and not the member.
861 fn member_separator(&mut self, what: &str) -> bool {
862 let comma = self.eat(SyntaxKind::COMMA);
863 // A closing brace ends the list, and an `Ident` is the only token that
864 // can begin either kind of member — anything else is a mistake the
865 // member's own parser will report.
866 if self.at(SyntaxKind::R_BRACE) || !self.at(SyntaxKind::Ident) {
867 return false;
868 }
869 if !comma && !self.newline_before() {
870 let span = self.current_span();
871 self.error_with(
872 DiagCode::ExpectedStatementSeparator,
873 span,
874 format!("expected `,` or a line break between {what}"),
875 );
876 }
877 true
878 }
879
880 /// `enum Name { Variant, Variant(Type, …), … }` (§4.6). Each variant is
881 /// an `ENUM_VARIANT` node: a name optionally followed by `( type_list )`.
882 fn parse_enum_item(&mut self) -> bool {
883 self.start_node(SyntaxKind::ENUM_ITEM);
884 self.bump(); // `enum`
885 self.expect(SyntaxKind::Ident, "enum name");
886 self.expect(SyntaxKind::L_BRACE, "`{` to begin enum variants");
887 if !self.at(SyntaxKind::R_BRACE) {
888 loop {
889 let before = self.meaningful_index();
890 self.start_node(SyntaxKind::ENUM_VARIANT);
891 self.expect(SyntaxKind::Ident, "variant name");
892 // Optional payload: `( Type, Type, … )`.
893 if self.eat(SyntaxKind::L_PAREN) {
894 if !self.at(SyntaxKind::R_PAREN) {
895 loop {
896 let pbefore = self.meaningful_index();
897 self.parse_type();
898 if !self.eat(SyntaxKind::COMMA) {
899 break;
900 }
901 // A trailing comma closes the list.
902 if self.at(SyntaxKind::R_PAREN) {
903 break;
904 }
905 self.ensure_progress(pbefore);
906 }
907 }
908 self.expect(SyntaxKind::R_PAREN, "`)` to close variant payload");
909 }
910 self.finish_node(); // ENUM_VARIANT
911 // A comma **or** a line break, as §4.6's
912 // own `enum Tile { Empty\n Wall\n … }`
913 // writes it.
914 if !self.member_separator("enum variants") {
915 break;
916 }
917 self.ensure_progress(before);
918 }
919 }
920 self.expect(SyntaxKind::R_BRACE, "`}` to end enum variants");
921 self.finish_node(); // ENUM_ITEM
922 true
923 }
924
925 /// A bare expression used as a statement.
926 fn parse_expr_stmt(&mut self) -> bool {
927 if self.at(SyntaxKind::L_BRACE) {
928 // A block as a statement is parsed as an expression.
929 self.start_node(SyntaxKind::EXPR_STMT);
930 self.parse_expr();
931 self.eat_breakpoint_marker();
932 self.finish_node();
933 return true;
934 }
935 // The expression is parsed before the statement node is opened, because
936 // what it turns out to be decides the kind: an assignment operator after
937 // it makes the whole thing a `PLACE_ASSIGN_STMT` whose first child is the
938 // target (`counts[point] += 1`), and anything else an `EXPR_STMT`.
939 //
940 // A bare `name` target never reaches here — `parse_stmt` sends
941 // `name = …` to `parse_assign_stmt` on the token after the name — so the
942 // targets this sees are the compound ones. Which of them is a place is
943 // inference's answer rather than the parser's: `p.x = 1` is a field store
944 // (§4.5) and `f() = 1` is a well-formed *shape* whose mistake is that it
945 // names no storage (`Y021`), and a parse error there says only "expected
946 // a statement separator" about either.
947 self.eat_trivia();
948 let cp = self.checkpoint_lhs();
949 self.parse_expr();
950 if is_assignment_op(self.peek()) {
951 self.start_node_at(cp, SyntaxKind::PLACE_ASSIGN_STMT);
952 self.bump(); // assignment operator
953 self.parse_expr();
954 self.eat_breakpoint_marker();
955 self.finish_node(); // PLACE_ASSIGN_STMT
956 return true;
957 }
958 // `distance[key] min= candidate` (§6.2). The operator is two tokens, so
959 // the parser decides it here rather than the lexer: `min` is an
960 // identifier everywhere else, and a lexer rule would take it away from
961 // every program that names the prelude helper.
962 if self.at_update_op() {
963 self.start_node_at(cp, SyntaxKind::PLACE_ASSIGN_STMT);
964 self.start_node(SyntaxKind::UPDATE_OP);
965 self.bump(); // `min` / `max`
966 self.bump(); // `=`
967 self.finish_node(); // UPDATE_OP
968 self.parse_expr();
969 self.eat_breakpoint_marker();
970 self.finish_node(); // PLACE_ASSIGN_STMT
971 return true;
972 }
973 self.start_node_at(cp, SyntaxKind::EXPR_STMT);
974 self.eat_breakpoint_marker();
975 self.finish_node();
976 true
977 }
978
979 /// `{ stmt; stmt; expr }` — a block. The last expression is the block's
980 /// value (§4.11). Every item is either a statement or a trailing expression.
981 fn parse_block(&mut self) {
982 self.start_node(SyntaxKind::BLOCK_EXPR);
983 self.bump(); // `{`
984 while !self.at(SyntaxKind::R_BRACE) && !self.at_end() {
985 self.eat_trivia();
986 if self.at(SyntaxKind::R_BRACE) || self.at_end() {
987 break;
988 }
989 let before = self.meaningful_index();
990 // Every item is a statement (var/fn/assignment) or a bare
991 // expression statement (which may be the trailing expression). The
992 // dispatch in parse_stmt covers all of these.
993 self.parse_stmt();
994 // A `;` is optional only because a newline separates just as well;
995 // one of the two (or the closing `}`) has to be there.
996 self.expect_stmt_separator();
997 // Guarantee termination on any input.
998 self.ensure_progress(before);
999 }
1000 self.expect(SyntaxKind::R_BRACE, "`}` to close block");
1001 self.finish_node();
1002 }
1003
1004 // --- expressions (Pratt climbing) ---
1005
1006 /// Entry into expression parsing at the lowest binding power.
1007 ///
1008 /// This is the *bracketed* entry: a record literal is legal here. Every
1009 /// caller that is inside `(…)`, an argument list, a block or a record body
1010 /// uses it. The four keyword heads use [`Parser::parse_expr_no_struct_lit`].
1011 fn parse_expr(&mut self) {
1012 self.parse_expr_bp(0, StructLit::Allowed);
1013 }
1014
1015 /// Entry into an expression that a `{` will terminate: an `if`/`while`
1016 /// condition, a `for` iterator, a `match` scrutinee.
1017 fn parse_expr_no_struct_lit(&mut self) {
1018 self.parse_expr_bp(0, StructLit::Suppressed);
1019 }
1020
1021 fn parse_expr_bp(&mut self, min_bp: u8, lit: StructLit) {
1022 // Capture the builder position *before* the left operand is emitted, so
1023 // a later infix operator can wrap (lhs op rhs) into a BIN_EXPR via
1024 // start_node_at. This is the standard rowan Pratt idiom.
1025 let cp = self.checkpoint_lhs();
1026 // Parse the left-hand side (prefix / atom).
1027 self.parse_prefix(lit);
1028
1029 // Fold infix operators while their binding power is high enough.
1030 loop {
1031 let op = self.peek();
1032 if op == SyntaxKind::EOF {
1033 break;
1034 }
1035 let Some(bp) = infix_binding_power(op) else {
1036 break;
1037 };
1038 if bp.left < min_bp {
1039 break;
1040 }
1041 // Wrap the already-emitted lhs + operator + rhs in a BIN_EXPR (or a
1042 // RANGE_EXPR), retroactively opening the node at the checkpoint taken
1043 // before lhs.
1044 self.start_node_at(cp, infix_node_kind(op));
1045 self.bump(); // operator
1046 // The operands of a suppressed expression are suppressed too:
1047 // `if a == p { … }` has the same ambiguity `if p { … }` has.
1048 self.parse_expr_bp(bp.right, lit);
1049 self.finish_node();
1050 }
1051 }
1052
1053 /// Prefix expression: unary operators, `read`, then an atom or a
1054 /// parenthesized expression. Followed by any postfix `expr(args)` calls
1055 /// (§4.10) — calling a closure retrieved from a collection
1056 /// (`fs.get(0)(100)`), the result of another call (`f(1)(2)`), a paren
1057 /// (`(|x| x*3)(14)`), etc.
1058 fn parse_prefix(&mut self, lit: StructLit) {
1059 // Capture the builder position before the primary is emitted, so a
1060 // postfix `expr(args)` can wrap the whole primary as the call's callee
1061 // via start_node_at (same idiom as the method-call loop).
1062 let cp = self.checkpoint_lhs();
1063 let op = self.peek();
1064 // `read parser_expression` (§7.1): a prefix expression whose body is a
1065 // parser-expression grammar, not an ordinary expression.
1066 if op == SyntaxKind::KW_READ {
1067 self.start_node(SyntaxKind::READ_EXPR);
1068 self.bump(); // `read`
1069 self.parse_parser_expr();
1070 self.finish_node();
1071 } else if op == SyntaxKind::PIPE || op == SyntaxKind::PIPE2 {
1072 // `|params| expr` closure (§4.10) — and `|| expr`, the
1073 // zero-parameter one (§4.2).
1074 //
1075 // The lexer's max-munch makes `||` one token (`PIPE2`), so the empty
1076 // parameter list and logical-or are spelled identically. The tie is
1077 // broken by **position**, the same rule `min=` and `[` use: this
1078 // function is only ever called where an expression must *begin*, and
1079 // a binary operator has no left operand there. So a `||` here is the
1080 // empty parameter list and nothing else, and a `||` between two
1081 // operands is still logical-or — the infix loop reads it, and it
1082 // never comes through here.
1083 self.parse_closure(lit);
1084 } else if let Some(bp) = prefix_binding_power(op) {
1085 self.start_node(SyntaxKind::UNARY_EXPR);
1086 self.bump(); // unary operator
1087 self.parse_expr_bp(bp, lit);
1088 self.finish_node();
1089 } else {
1090 self.parse_atom(lit);
1091 }
1092 self.parse_postfix(cp);
1093 }
1094
1095 /// The postfix chain on the expression preceding the current position:
1096 /// `expr(args)`, `expr.method(args)` and `expr.field`, in **any order and
1097 /// any number of times**, left-associatively.
1098 ///
1099 /// One loop over all three forms rather than a call loop followed by a
1100 /// field/method loop: two sequential loops cannot express `(fs).get(0)(100)`
1101 /// (a call on the result of a method call), because control never returns
1102 /// from the second loop to the first.
1103 ///
1104 /// `cp` is the checkpoint taken *before* the primary was emitted, so
1105 /// `start_node_at(cp, …)` retroactively wraps it as the new node's first
1106 /// child. It is NOT updated between iterations: each link in `a.b().c()`
1107 /// must wrap the entire preceding expression, which starts at the original
1108 /// `cp`.
1109 fn parse_postfix(&mut self, cp: rowan::Checkpoint) {
1110 loop {
1111 match self.peek() {
1112 // An argument list, and **only on the same line**. See
1113 // [`Parser::at_argument_list`] for why.
1114 SyntaxKind::L_PAREN if self.at_argument_list() => {
1115 self.start_node_at(cp, SyntaxKind::CALL_EXPR);
1116 self.bump(); // `(`
1117 self.parse_arg_list();
1118 self.finish_node(); // CALL_EXPR
1119 }
1120 // `m[key]`, `grid[x, y]` — a subscript. A postfix form like the
1121 // other two, so `grid[x, y].len()` and `m[k][j]` chain without a
1122 // second loop.
1123 //
1124 // And **only on the same line**, for the reason the `(` above is:
1125 // a `[` also begins a list literal. See [`Parser::at_subscript`].
1126 SyntaxKind::L_BRACK if self.at_subscript() => {
1127 self.start_node_at(cp, SyntaxKind::INDEX_EXPR);
1128 self.bump(); // `[`
1129 // A subscript selects *something*, so unlike a call's
1130 // argument list an empty one is a syntax error rather than an
1131 // arity the catalog happens not to have a row for.
1132 if self.at(SyntaxKind::R_BRACK) {
1133 let span = self.current_span();
1134 self.error(span, "expected an index expression");
1135 }
1136 self.parse_arg_list_until(SyntaxKind::R_BRACK, "`]`");
1137 self.finish_node(); // INDEX_EXPR
1138 }
1139 SyntaxKind::DOT => {
1140 self.bump(); // `.`
1141 // `p.0` — a tuple element, selected by position.
1142 // The lexer guarantees the literal is an integer here: a
1143 // digit run immediately after a `.` takes no fraction, so
1144 // `t.0.1` is two indices and not an index and a float.
1145 if self.at(SyntaxKind::IntLit) {
1146 self.start_node_at(cp, SyntaxKind::TUPLE_INDEX_EXPR);
1147 self.bump(); // the index
1148 self.finish_node(); // TUPLE_INDEX_EXPR
1149 continue;
1150 }
1151 if !self.at(SyntaxKind::Ident) {
1152 let span = self.current_span();
1153 self.error(span, "expected a name or a tuple index after `.`");
1154 break;
1155 }
1156 // Disambiguate field access (`p.x`) from method call
1157 // (`p.x()`): an IDENT followed by `(` **on the same line** is
1158 // a method call. The line break matters here for the same
1159 // reason it does at the top of this loop — `p.x\n(a, b)` is a
1160 // match arm body followed by a tuple pattern, not
1161 // `p.x(a, b)`.
1162 if self.nth_kind(1) == SyntaxKind::L_PAREN && !self.newline_before_nth(1) {
1163 self.bump(); // method name
1164 self.start_node_at(cp, SyntaxKind::METHOD_CALL_EXPR);
1165 self.bump(); // `(`
1166 self.parse_arg_list();
1167 self.finish_node(); // METHOD_CALL_EXPR
1168 } else {
1169 self.start_node_at(cp, SyntaxKind::FIELD_EXPR);
1170 self.bump(); // field name
1171 self.finish_node(); // FIELD_EXPR
1172 }
1173 }
1174 _ => break,
1175 }
1176 }
1177 }
1178
1179 /// The `arg, arg, …)` of a call, with the opening `(` already consumed.
1180 /// Emits the `ARG_LIST` node and consumes the closing `)`.
1181 fn parse_arg_list(&mut self) {
1182 self.parse_arg_list_until(SyntaxKind::R_PAREN, "`)`");
1183 }
1184
1185 /// The `arg, arg, …<closer>` of a call or a subscript, with the opener
1186 /// already consumed. Emits the `ARG_LIST` node and consumes `closer`.
1187 ///
1188 /// One function for both brackets: `grid[x, y]` (§6.4) is a comma-separated
1189 /// expression list with the same trailing-comma rule a call's has, and a
1190 /// second copy of a list loop is a second place for that rule to be missing.
1191 fn parse_arg_list_until(&mut self, closer: SyntaxKind, closer_msg: &str) {
1192 self.start_node(SyntaxKind::ARG_LIST);
1193 if !self.at(closer) {
1194 loop {
1195 let before = self.meaningful_index();
1196 self.parse_expr();
1197 if !self.eat(SyntaxKind::COMMA) {
1198 break;
1199 }
1200 // A trailing comma closes the list rather than opening another
1201 // argument — §3.3's own `max(\n abs(dx),\n abs(dy),\n)` writes
1202 // one, and counting it would make the call's arity one too high.
1203 if self.at(closer) {
1204 break;
1205 }
1206 // Guarantee termination on any input.
1207 self.ensure_progress(before);
1208 }
1209 }
1210 self.expect(closer, closer_msg);
1211 self.finish_node(); // ARG_LIST
1212 }
1213
1214 /// The `[Type, …]` type-argument list of a constructor call, with the name
1215 /// already emitted and the `[` still current.
1216 ///
1217 /// A type-argument list exists only on a constructor *call*, so the `(` after
1218 /// it is required: `Counter[Int]` alone names a type in value position, which
1219 /// no expression grammar accepts.
1220 fn parse_type_arg_list(&mut self) {
1221 self.start_node(SyntaxKind::TYPE_ARG_LIST);
1222 self.bump(); // `[`
1223 if self.at(SyntaxKind::R_BRACK) {
1224 let span = self.current_span();
1225 self.error(span, "expected a type argument");
1226 } else {
1227 loop {
1228 let before = self.meaningful_index();
1229 self.parse_type();
1230 if !self.eat(SyntaxKind::COMMA) {
1231 break;
1232 }
1233 // A trailing comma closes the list.
1234 if self.at(SyntaxKind::R_BRACK) {
1235 break;
1236 }
1237 // Guarantee termination on any input.
1238 self.ensure_progress(before);
1239 }
1240 }
1241 self.expect(SyntaxKind::R_BRACK, "`]`");
1242 self.finish_node(); // TYPE_ARG_LIST
1243 // The `(` is required and it is on **this** line,
1244 // so the report and what `parse_name_or_call` goes
1245 // on to build cannot disagree.
1246 if !self.at_argument_list() {
1247 let span = self.current_span();
1248 self.error(
1249 span,
1250 "`(` — a type argument list belongs to a constructor call",
1251 );
1252 }
1253 }
1254
1255 /// `|params| expr` — a closure expression (§4.10). Each parameter is a
1256 /// **pattern**, optionally annotated `: Type`, separated by commas, between two
1257 /// `|`. The body is a single expression (which may be a `{ block }`). Closures
1258 /// capture outer variables automatically (§4.10); the capture analysis is in
1259 /// HIR.
1260 ///
1261 /// A parameter is a pattern for the reason a `for` binding is one:
1262 /// destructuring in binding position **is** a pattern, so `|(a, b)| a + b`
1263 /// needs no grammar of its own.
1264 ///
1265 /// Nothing here can be confused with the body: a parameter is followed by `,`,
1266 /// `:` or `|`, never by an expression, so a record pattern's brace has nothing
1267 /// else waiting for it.
1268 ///
1269 /// The body inherits the ambient suppression rather than resetting it: `|`
1270 /// is not a bracket the grammar can close over, so a closure written
1271 /// directly as an `if` condition has the same ambiguity a name does.
1272 fn parse_closure(&mut self, lit: StructLit) {
1273 self.start_node(SyntaxKind::CLOSURE_EXPR);
1274 // `|| expr` — the zero-parameter closure. One `PIPE2` token is *both*
1275 // pipes: there is no parameter list between them to parse and no closing
1276 // `|` to demand. The token stays whole rather than being split into two,
1277 // because the tree's job is to round-trip the source and `||` is what
1278 // the source says; the node kind is what carries the meaning.
1279 if self.eat(SyntaxKind::PIPE2) {
1280 self.parse_expr_bp(0, lit);
1281 self.finish_node();
1282 return;
1283 }
1284 self.bump(); // `|`
1285 // Zero or more `pattern` or `pattern: Type` params separated by commas.
1286 if !self.at(SyntaxKind::PIPE) {
1287 loop {
1288 let before = self.meaningful_index();
1289 self.start_node(SyntaxKind::PARAM);
1290 self.parse_pattern();
1291 if self.eat(SyntaxKind::COLON) {
1292 self.parse_type();
1293 }
1294 self.finish_node();
1295 if !self.eat(SyntaxKind::COMMA) {
1296 break;
1297 }
1298 // A trailing comma closes the list.
1299 if self.at(SyntaxKind::PIPE) {
1300 break;
1301 }
1302 self.ensure_progress(before);
1303 }
1304 }
1305 self.expect(SyntaxKind::PIPE, "`|` to close closure parameters");
1306 // Body: a single expression (which may be a `{ block }`).
1307 self.parse_expr_bp(0, lit);
1308 self.finish_node();
1309 }
1310
1311 /// Smallest expression: literals (including interpolated ones), names,
1312 /// calls, parenthesized expressions, list literals, blocks, and the
1313 /// keyword-headed expressions (`if`, `while`, `for`, `loop`, `match`,
1314 /// `break`, `continue`, `return`).
1315 fn parse_atom(&mut self, lit: StructLit) {
1316 let kind = self.peek();
1317 match kind {
1318 // The `LITERAL` set is `SyntaxKind::is_literal_token`: this is the
1319 // site that *builds* the node and `praxis_ast::Literal::token` is the
1320 // one that reads it back, so both must ask the same predicate.
1321 // `true`/`false` are literals too — one arm covers every literal.
1322 k if k.is_literal_token() => {
1323 self.start_node(SyntaxKind::LITERAL);
1324 self.bump();
1325 self.finish_node();
1326 }
1327 SyntaxKind::InterpOpen => self.parse_interp(),
1328 SyntaxKind::L_PAREN => self.parse_paren(),
1329 SyntaxKind::L_BRACK => self.parse_list(),
1330 // An anonymous record literal `{ x: 1, y }` (§5.6) and a block are
1331 // both a `{` here; [`Parser::at_anonymous_record_lit`] is the whole
1332 // of the tie-break.
1333 SyntaxKind::L_BRACE if self.at_anonymous_record_lit() => {
1334 let cp = self.checkpoint_lhs();
1335 self.parse_record_lit_body(cp);
1336 }
1337 SyntaxKind::L_BRACE => self.parse_block(),
1338 SyntaxKind::KW_IF => self.parse_if(),
1339 SyntaxKind::KW_WHILE => self.parse_while(),
1340 SyntaxKind::KW_FOR => self.parse_for(),
1341 SyntaxKind::KW_LOOP => self.parse_loop(),
1342 SyntaxKind::KW_BREAK => self.parse_break(),
1343 SyntaxKind::KW_CONTINUE => self.parse_continue(),
1344 SyntaxKind::KW_RETURN => self.parse_return(),
1345 SyntaxKind::KW_MATCH => self.parse_match(),
1346 SyntaxKind::Ident => self.parse_name_or_call(lit),
1347 _ => {
1348 // Nothing recognizable. CRITICAL: we must make forward progress
1349 // here — emitting a diagnostic without advancing the cursor
1350 // would let every caller loop spin forever (and balloon memory).
1351 // So consume the offending token (wrapped in a PARSE_ERROR) even
1352 // at EOF, where bump() is a no-op, we bail without consuming.
1353 if self.at_end() {
1354 let span = self.current_span();
1355 self.error(span, "expected an expression");
1356 } else {
1357 self.start_node(SyntaxKind::PARSE_ERROR);
1358 let span = self.current_span();
1359 self.error(span, "expected an expression");
1360 self.bump(); // guaranteed progress
1361 self.finish_node();
1362 }
1363 }
1364 }
1365 }
1366
1367 /// An interpolated text literal: `"a{x}b{y}"` (§8.1, ADR-147).
1368 ///
1369 /// The lexer has already decided the shape — it emits an `InterpOpen`, then
1370 /// the hole's ordinary tokens, then an `InterpMiddle` for each further hole,
1371 /// then exactly one `InterpClose` — so this is a straight walk of that run
1372 /// rather than a scan of any kind. **Nothing here re-reads the source text**,
1373 /// which is the point: the hole's expression is parsed by
1374 /// [`parse_expr`](Self::parse_expr), so it is an ordinary subtree whose names
1375 /// are tokens at their own ranges, and closure capture analysis sees them
1376 /// (ADR-147 decision 1).
1377 ///
1378 /// The loop is bounded by the token stream, not by a count, and the
1379 /// `InterpClose` is `expect`ed rather than assumed: a token stream missing
1380 /// one cannot be produced by the lexer, but a parser that assumed it would
1381 /// spin at EOF instead of reporting.
1382 fn parse_interp(&mut self) {
1383 self.start_node(SyntaxKind::INTERP_EXPR);
1384 self.bump(); // `"…{`
1385 loop {
1386 self.refuse_doubled_brace();
1387 self.parse_expr(); // the hole
1388 if self.at(SyntaxKind::InterpMiddle) {
1389 self.bump(); // `}…{`
1390 continue;
1391 }
1392 break;
1393 }
1394 self.expect(SyntaxKind::InterpClose, "`}` to close the interpolation");
1395 self.finish_node();
1396 }
1397
1398 /// A hole whose expression *opens with a brace* is `{{`, and `{{` is not an
1399 /// escape in this language — ADR-147 decision 4 chose `\{` instead, so that
1400 /// `"…"` and `'…'` keep one shared escape table.
1401 ///
1402 /// Without this the doubling rule other languages use does not fail, it
1403 /// **means something else**: `{` opens the hole, `{}` is an empty block, `}`
1404 /// closes the hole, so `"a{{}}b"` is a well-typed program printing `aUnitb`,
1405 /// and `"a{{x}}b"` reports `N001` about a name the author thought they had
1406 /// escaped. A reader arriving from Rust, C# or Python writes `{{` first and
1407 /// gets no sign they were wrong, so the mistaken escape is refused where it
1408 /// is written and the message names the spelling that works.
1409 ///
1410 /// It costs a block as a hole's whole expression, which nothing wants: a
1411 /// hole is a rendering site, and `"{ var t = f(); t }"` is a sentence no one
1412 /// writes inside a string. A record literal is unaffected — that opens with
1413 /// its type's name, not with a brace.
1414 fn refuse_doubled_brace(&mut self) {
1415 if !self.at(SyntaxKind::L_BRACE) {
1416 return;
1417 }
1418 let span = self.current_span();
1419 self.error(
1420 span,
1421 "`{{` is not an escape for a literal brace: write `\\{` for a `{`, \
1422 or a value to render between single braces",
1423 );
1424 }
1425
1426 fn parse_paren(&mut self) {
1427 // Either `( expr )` (PAREN_EXPR) or `( e1, e2, … )` (TUPLE_EXPR) — the
1428 // decision, and everything that follows from it, is
1429 // `parse_parenthesized`'s.
1430 let cp = self.checkpoint_lhs();
1431 self.bump(); // `(`
1432 self.parse_parenthesized(
1433 cp,
1434 SyntaxKind::TUPLE_EXPR,
1435 SyntaxKind::PAREN_EXPR,
1436 Self::parse_expr,
1437 );
1438 }
1439
1440 /// A parenthesized list, in either position: `( x )` / `( T )` groups,
1441 /// `( a, b, … )` / `( T, U, … )` is a tuple. The caller has taken `cp`
1442 /// *before* the `(` and consumed the `(`; `element` parses one element —
1443 /// `parse_expr` in expression position, `parse_type` in type position.
1444 ///
1445 /// Which node this is cannot be known until a comma turns up after the first
1446 /// element, so the shared prefix is emitted first and the right kind is then
1447 /// opened *retroactively* at `cp`. Both `(` and `)` end up inside the single
1448 /// resulting node (no double nesting).
1449 ///
1450 /// One function for both positions so the §4.4 arity rule below is written
1451 /// once.
1452 fn parse_parenthesized(
1453 &mut self,
1454 cp: rowan::Checkpoint,
1455 tuple_kind: SyntaxKind,
1456 single_kind: SyntaxKind,
1457 mut element: impl FnMut(&mut Self),
1458 ) {
1459 if self.at(SyntaxKind::R_PAREN) {
1460 // Empty `()`, `single_kind` in both positions but for two reasons.
1461 // As an expression it is a degenerate paren expr, and it is `Unit` —
1462 // the same type `()` names in an annotation, and the value `out(())`
1463 // prints. As a type it is recorded as a plain `TYPE_REF` and left
1464 // for type resolution to reject.
1465 self.expect(SyntaxKind::R_PAREN, "`)`");
1466 self.start_node_at(cp, single_kind);
1467 self.finish_node();
1468 return;
1469 }
1470 element(self); // first element
1471 let is_tuple = self.at(SyntaxKind::COMMA);
1472 let mut elements = 1usize;
1473 let mut trailing_comma = None;
1474 if is_tuple {
1475 // Collect the remaining elements.
1476 loop {
1477 let before = self.meaningful_index();
1478 let comma = self.current_span();
1479 if !self.eat(SyntaxKind::COMMA) {
1480 break;
1481 }
1482 if self.at(SyntaxKind::R_PAREN) {
1483 // Trailing comma: `(a, b, )` — stop without another element.
1484 trailing_comma = Some(comma);
1485 break;
1486 }
1487 element(self);
1488 elements += 1;
1489 // Guarantee termination on any input.
1490 self.ensure_progress(before);
1491 }
1492 }
1493 // **A tuple has two elements or more** (§4.4). `(1,)` is the one spelling
1494 // that reaches here with fewer, and the language has nothing for it to
1495 // mean: `TupleElems` refuses to represent a one-element tuple, so typing
1496 // and lowering would have to disagree about what the node is. `(Int,)` is
1497 // the type-position spelling of the same mistake — an annotation naming a
1498 // type the language does not have.
1499 //
1500 // So the comma is refused here, and the node recovers as the grouping
1501 // the author most likely meant. `(1, 2,)` is untouched — a trailing
1502 // comma is punctuation at every arity the type exists at.
1503 let one_element_tuple = is_tuple && elements < 2;
1504 if one_element_tuple {
1505 let at = trailing_comma.unwrap_or_else(|| self.current_span());
1506 self.error(at, ONE_ELEMENT_TUPLE_MSG);
1507 }
1508 let kind = if is_tuple && !one_element_tuple {
1509 tuple_kind
1510 } else {
1511 single_kind
1512 };
1513 self.expect(SyntaxKind::R_PAREN, "`)`");
1514 self.start_node_at(cp, kind);
1515 self.finish_node();
1516 }
1517
1518 /// `[ e1, e2, … ]` — a `Vec` literal (§6.1). The opening `[` is current.
1519 ///
1520 /// One node kind for every arity, including the empty `[]`: a list is a
1521 /// collection built from its elements, so nothing about it changes at two
1522 /// the way a paren becomes a tuple at two. The element list is an `ARG_LIST`
1523 /// for the reason a subscript's is — the comma rules, the trailing comma and
1524 /// the recovery are one loop, and a second copy is a second place for a rule
1525 /// to be missing.
1526 fn parse_list(&mut self) {
1527 self.start_node(SyntaxKind::LIST_EXPR);
1528 self.bump(); // `[`
1529 // Unlike a subscript, an empty one is legal: `[]` is the empty
1530 // `Vec`, whose element type inference takes from its use.
1531 self.parse_arg_list_until(SyntaxKind::R_BRACK, "`]` to close list literal");
1532 self.finish_node(); // LIST_EXPR
1533 }
1534
1535 fn parse_if(&mut self) {
1536 self.start_node(SyntaxKind::IF_EXPR);
1537 self.bump(); // `if`
1538 // The condition is a parenthesized or bare expression; accept either.
1539 // Suppress record-literal parsing so `if x { … }` doesn't read
1540 // the then-block as `x { … }`.
1541 self.parse_expr_no_struct_lit();
1542 self.parse_block(); // then-branch
1543 if self.eat(SyntaxKind::KW_ELSE) {
1544 self.start_node(SyntaxKind::ELSE_BRANCH);
1545 if self.at(SyntaxKind::KW_IF) {
1546 self.parse_if();
1547 } else {
1548 self.parse_block();
1549 }
1550 self.finish_node();
1551 }
1552 self.finish_node();
1553 }
1554
1555 fn parse_while(&mut self) {
1556 self.start_node(SyntaxKind::WHILE_EXPR);
1557 self.bump(); // `while`
1558 self.parse_expr_no_struct_lit();
1559 self.parse_block();
1560 self.finish_node();
1561 }
1562
1563 /// `for pattern in iter { body }` (§4.11). The binding and the `in` keyword
1564 /// separate the iterator expression from the loop body.
1565 fn parse_for(&mut self) {
1566 self.start_node(SyntaxKind::FOR_EXPR);
1567 self.bump(); // `for`
1568 // The binding is a **pattern**: `for (k, v) in m` takes the
1569 // pair apart, and a bare name is the pattern that binds the
1570 // whole item. Nothing here can be confused with the loop
1571 // body — the pattern is followed by `in`, never by `{`.
1572 self.parse_pattern();
1573 self.expect(SyntaxKind::KW_IN, "`in` after the for-loop binding");
1574 self.parse_expr_no_struct_lit(); // iterator
1575 self.parse_block();
1576 self.finish_node();
1577 }
1578
1579 /// `loop { body }` (§4.11) — an explicit infinite loop, terminated by
1580 /// `break` (optionally with a value).
1581 fn parse_loop(&mut self) {
1582 self.start_node(SyntaxKind::LOOP_EXPR);
1583 self.bump(); // `loop`
1584 self.parse_block();
1585 self.finish_node();
1586 }
1587
1588 /// `break [expr]` (§4.11). The optional value is an expression; absent
1589 /// means the loop yields Unit.
1590 fn parse_break(&mut self) {
1591 self.start_node(SyntaxKind::BREAK_EXPR);
1592 self.bump(); // `break`
1593 // A value follows iff the next token starts an expression (not `;`/`}`/EOF).
1594 if self.starts_expr() {
1595 self.parse_expr();
1596 }
1597 self.finish_node();
1598 }
1599
1600 /// `continue` (§4.11).
1601 fn parse_continue(&mut self) {
1602 self.start_node(SyntaxKind::CONTINUE_EXPR);
1603 self.bump(); // `continue`
1604 self.finish_node();
1605 }
1606
1607 /// `return [expr]` (§4.11).
1608 fn parse_return(&mut self) {
1609 self.start_node(SyntaxKind::RETURN_EXPR);
1610 self.bump(); // `return`
1611 if self.starts_expr() {
1612 self.parse_expr();
1613 }
1614 self.finish_node();
1615 }
1616
1617 /// `match scrutinee { pattern => expr, … }` (§4.6, §4.11).
1618 fn parse_match(&mut self) {
1619 self.start_node(SyntaxKind::MATCH_EXPR);
1620 self.bump(); // `match`
1621 // The scrutinee is an expression; suppress record literals so the `{`
1622 // opening the arm list isn't consumed as a record body.
1623 self.parse_expr_no_struct_lit();
1624 self.expect(SyntaxKind::L_BRACE, "`{` to begin match arms");
1625 if !self.at(SyntaxKind::R_BRACE) {
1626 loop {
1627 let before = self.meaningful_index();
1628 self.start_node(SyntaxKind::MATCH_ARM);
1629 self.parse_pattern();
1630 self.expect(SyntaxKind::FAT_ARROW, "`=>` in match arm");
1631 // Arm body: a record literal is legal here. The `{` that could be
1632 // confused with a block belongs to the *match*, and it was
1633 // consumed above — inside the arm list there is nothing left for
1634 // a `Name { … }` to be mistaken for.
1635 self.parse_expr();
1636 self.finish_node(); // MATCH_ARM
1637 // Arms are comma-OR-newline separated (§4.6).
1638 let comma = self.eat(SyntaxKind::COMMA);
1639 // Stop if we hit `}` or something that can't start a pattern.
1640 if self.at(SyntaxKind::R_BRACE) || !is_pattern_start(self.peek()) {
1641 break;
1642 }
1643 if !comma && !self.newline_before() {
1644 let span = self.current_span();
1645 self.error_with(
1646 DiagCode::ExpectedStatementSeparator,
1647 span,
1648 "expected `,` or a line break between match arms",
1649 );
1650 }
1651 self.ensure_progress(before);
1652 }
1653 }
1654 self.expect(SyntaxKind::R_BRACE, "`}` to end match arms");
1655 self.finish_node(); // MATCH_EXPR
1656 }
1657
1658 /// Parse a pattern (§4.6). Grammar:
1659 ///
1660 /// ```text
1661 /// pattern := "_" // wildcard
1662 /// | literal // `SyntaxKind::is_pattern_literal`
1663 /// | Ident // variable bind or payload-less variant
1664 /// | Ident "(" [pattern ("," pattern)*] ")" // enum variant
1665 /// | Ident "{" [pattern_field ("," pattern_field)*] "}" // record (§4.5)
1666 /// | "{" pattern_field ("," pattern_field)* "}" // headless record (ADR-091)
1667 /// | "(" pattern ("," pattern)* ")" // tuple (§4.4)
1668 /// pattern_field := Ident [":" pattern]
1669 /// ```
1670 ///
1671 /// A record pattern's `{` is unambiguous where a record *literal*'s is not:
1672 /// a pattern is followed by `=>` or `in`, never by a block, so nothing else
1673 /// can be waiting for that brace. That is also what makes the **head
1674 /// optional** (ADR-091 Decision 2): a leading `{` in pattern position can
1675 /// only ever open fields, so a headless record pattern needs no new token to
1676 /// tell it apart, and it pins its record from the scrutinee exactly as a
1677 /// tuple pattern does. It is the form a `choice(...)` payload record wants,
1678 /// because an anonymous record has no name a head could write.
1679 ///
1680 /// Parentheses in pattern position are **always** a tuple — there is no
1681 /// grouping form, because a pattern has no precedence to override. `(p)` is
1682 /// therefore a one-element tuple pattern, which `Y123` reports against every
1683 /// type: `TypeData::Tuple` carries two elements or more.
1684 ///
1685 /// A headless `{}` is rejected for `()`'s reason (ADR-091 Decision 3): it
1686 /// binds nothing and tests nothing against a record it cannot even name, so
1687 /// it is an irrefutable arm written by accident. The pattern that matches
1688 /// anything is spelled `_`. A *headed* `P {}` is kept — it names the record
1689 /// it tests for, so it is refutable, and it is `Some` beside `Some(_)`.
1690 fn parse_pattern(&mut self) {
1691 self.start_node(SyntaxKind::PATTERN);
1692 match self.peek() {
1693 SyntaxKind::UNDERSCORE => {
1694 self.bump(); // `_`
1695 }
1696 k if k.is_pattern_literal() => {
1697 self.bump(); // literal
1698 }
1699 // An interpolated literal is not a constant, so it is not a pattern
1700 // (§8.1, ADR-147). It is refused *here*, with the whole run consumed
1701 // into a `PARSE_ERROR`, rather than falling through to the arm below:
1702 // `match s { "{x}" => … }` would otherwise leave a `PATTERN` whose
1703 // only direct `Ident` is the hole's `x`, and `Pattern::kind` would
1704 // read that as a **variable bind** — an irrefutable arm that swallows
1705 // every value.
1706 SyntaxKind::InterpOpen => {
1707 let span = self.current_span();
1708 self.error(
1709 span,
1710 "an interpolated text literal is not a pattern; a pattern tests a constant",
1711 );
1712 self.start_node(SyntaxKind::PARSE_ERROR);
1713 self.parse_interp();
1714 self.finish_node();
1715 }
1716 SyntaxKind::Ident => {
1717 self.bump(); // variant name, record name, or variable bind
1718 if self.at(SyntaxKind::L_BRACE) {
1719 // Record pattern: `Name { field, field: pat, … }`.
1720 self.parse_record_pattern_fields();
1721 } else if self.eat(SyntaxKind::L_PAREN) {
1722 // Enum variant with payload: `Name(pat, pat, …)`.
1723 self.parse_pattern_list(SyntaxKind::R_PAREN);
1724 self.expect(SyntaxKind::R_PAREN, "`)` to close variant pattern");
1725 }
1726 }
1727 SyntaxKind::L_BRACE => {
1728 // Headless record pattern `{ a, b: p }` (ADR-091). The fields
1729 // are the headed form's, unchanged — one production, so `for
1730 // {x, y} in points` and `|{x, y}| x + y` arrive with it.
1731 if self.nth_kind(1) == SyntaxKind::R_BRACE {
1732 // `{}` binds nothing and names no record: an arm nobody can
1733 // read as refutable. Reported where `()` is, and for the
1734 // same reason.
1735 let span = self.current_span();
1736 self.error(span, "expected a pattern");
1737 }
1738 self.parse_record_pattern_fields();
1739 }
1740 SyntaxKind::L_PAREN => {
1741 // Tuple pattern `(a, b)` — or a grouping `(p)`, which the list
1742 // leaves as the one child it parsed.
1743 self.bump(); // `(`
1744 if self.at(SyntaxKind::R_PAREN) {
1745 // `()` has no type to match: `Unit` is not a tuple.
1746 let span = self.current_span();
1747 self.error(span, "expected a pattern");
1748 } else {
1749 self.parse_pattern_list(SyntaxKind::R_PAREN);
1750 }
1751 self.expect(SyntaxKind::R_PAREN, "`)` to close tuple pattern");
1752 }
1753 _ => {
1754 let span = self.current_span();
1755 self.error(span, "expected a pattern");
1756 if !self.at_end() {
1757 self.bump();
1758 }
1759 }
1760 }
1761 self.finish_node(); // PATTERN
1762 }
1763
1764 /// A comma-separated list of patterns, up to but not including `closer`.
1765 /// A trailing comma closes the list rather than opening an element.
1766 fn parse_pattern_list(&mut self, closer: SyntaxKind) {
1767 loop {
1768 let before = self.meaningful_index();
1769 self.parse_pattern();
1770 if !self.eat(SyntaxKind::COMMA) {
1771 break;
1772 }
1773 if self.at(closer) {
1774 break;
1775 }
1776 self.ensure_progress(before);
1777 }
1778 }
1779
1780 /// The `{ field, field: pat, … }` body of a record pattern (§4.5).
1781 /// A punned field binds the field's own name; an explicit one matches the
1782 /// sub-pattern against that field.
1783 fn parse_record_pattern_fields(&mut self) {
1784 self.bump(); // `{`
1785 if !self.at(SyntaxKind::R_BRACE) {
1786 loop {
1787 let before = self.meaningful_index();
1788 self.start_node(SyntaxKind::PATTERN_FIELD);
1789 self.expect(SyntaxKind::Ident, "field name");
1790 if self.eat(SyntaxKind::COLON) {
1791 self.parse_pattern();
1792 }
1793 self.finish_node(); // PATTERN_FIELD
1794 if !self.eat(SyntaxKind::COMMA) {
1795 break;
1796 }
1797 // A trailing comma closes the list.
1798 if self.at(SyntaxKind::R_BRACE) {
1799 break;
1800 }
1801 self.ensure_progress(before);
1802 }
1803 }
1804 self.expect(SyntaxKind::R_BRACE, "`}` to close record pattern");
1805 }
1806
1807 // --- types --------------------------------------------------------------
1808
1809 /// Parse a type annotation. Grammar:
1810 ///
1811 /// ```text
1812 /// type := atom_type ("->" type)? // function types, right-assoc
1813 /// atom_type := Ident // scalar: Int, Text, Bool, ...
1814 /// | "(" [type ("," type)*] ")" // tuple (≥2) or grouped type
1815 /// ```
1816 ///
1817 /// A scalar or grouped type becomes a [`TYPE_REF`](SyntaxKind::TYPE_REF); a
1818 /// parenthesized two-or-more-element list becomes a
1819 /// [`TUPLE_TYPE`](SyntaxKind::TUPLE_TYPE); anything followed by `->` wraps in
1820 /// an [`FN_TYPE`](SyntaxKind::FN_TYPE). Unknown identifiers (e.g. a typo or a
1821 /// reserved-but-unused scalar like `Float`) parse as `TYPE_REF` and are
1822 /// rejected by name resolution (`N002`), not by the parser.
1823 fn parse_type(&mut self) {
1824 let cp = self.checkpoint_lhs();
1825 self.parse_atom_type();
1826 // Function types bind right-associatively: `A -> B -> C` = `A -> (B -> C)`.
1827 if self.eat(SyntaxKind::THIN_ARROW) {
1828 self.parse_type(); // rhs (recurses, so right-assoc)
1829 // Wrap lhs + arrow + rhs retroactively. `parse_atom_type` already
1830 // emitted exactly one node; reopening at `cp` captures it.
1831 self.start_node_at(cp, SyntaxKind::FN_TYPE);
1832 self.finish_node();
1833 }
1834 // A scalar atom is already a TYPE_REF; a tuple/group is TUPLE_TYPE; an
1835 // arrow-wrapped one is FN_TYPE. The node is on the builder.
1836 }
1837
1838 /// Parse one atomic type (no `->`). Emits exactly one node onto the builder:
1839 /// [`TYPE_REF`] for a scalar or grouped type, [`TUPLE_TYPE`] for two or more
1840 /// comma-separated elements. A scalar name followed by `[T]` or `[K, V]` is
1841 /// a collection type (§4.4) — also emitted as `TYPE_REF` with the bracketed
1842 /// args as children.
1843 fn parse_atom_type(&mut self) {
1844 if self.at(SyntaxKind::Ident) {
1845 let cp = self.checkpoint_lhs();
1846 self.eat_trivia();
1847 self.start_node(SyntaxKind::TYPE_REF);
1848 self.bump_meaningful(); // the scalar name
1849 self.finish_node();
1850 // Collection type args: `Vec[Int]`, `Map[Text, Int]`, …
1851 if self.at(SyntaxKind::L_BRACK) {
1852 self.bump(); // `[`
1853 self.start_node_at(cp, SyntaxKind::TYPE_REF);
1854 // The first type arg.
1855 self.parse_type();
1856 while self.eat(SyntaxKind::COMMA) {
1857 // A trailing comma closes the list.
1858 if self.at(SyntaxKind::R_BRACK) {
1859 break;
1860 }
1861 self.parse_type();
1862 }
1863 self.expect(SyntaxKind::R_BRACK, "`]`");
1864 self.finish_node(); // wraps name + args into one TYPE_REF
1865 }
1866 return;
1867 }
1868 if self.at(SyntaxKind::L_PAREN) {
1869 // `( T )` (grouped) or `( T, U, … )` (tuple) — the same list, the
1870 // same arity rule and the same retroactive node as `parse_paren`'s,
1871 // over `parse_type` instead of `parse_expr`.
1872 let cp = self.checkpoint_lhs();
1873 self.bump(); // `(`
1874 self.parse_parenthesized(
1875 cp,
1876 SyntaxKind::TUPLE_TYPE,
1877 SyntaxKind::TYPE_REF,
1878 Self::parse_type,
1879 );
1880 return;
1881 }
1882 // Nothing recognizable: emit a diagnostic + a PARSE_ERROR node, but make
1883 // progress (OOM rule) by consuming the stray token if any.
1884 if self.at_end() {
1885 let span = self.current_span();
1886 self.error(span, "expected a type");
1887 } else {
1888 self.start_node(SyntaxKind::PARSE_ERROR);
1889 let span = self.current_span();
1890 self.error(span, "expected a type");
1891 self.bump();
1892 self.finish_node();
1893 }
1894 }
1895
1896 /// An identifier, possibly followed by a call `(args)` and/or `.method(args)`
1897 /// postfixes. Method calls chain left-associatively: `v.push(1).len()`.
1898 fn parse_name_or_call(&mut self, lit: StructLit) {
1899 let cp = self.checkpoint_lhs();
1900 // Peek the identifier text to special-case `parse(text, parser_expr)`
1901 // (§7.1) before committing to an ordinary call.
1902 let name_text = self.peek_text();
1903 // `parse(text, parser_expression)` (§7.1) is *syntax*, not a call of a
1904 // binding named `parse` — so the keyword must not become a `PATH_EXPR`.
1905 // Name resolution would report `` `parse` is not defined `` on every
1906 // use, and `ParseExpr::text_expr` — "the first `Expr` child" — would
1907 // answer with the keyword's own path instead of the text argument.
1908 // Decided before the node is opened, which needs one token of lookahead.
1909 if name_text == Some("parse") && self.nth_kind(1) == SyntaxKind::L_PAREN {
1910 self.start_node_at(cp, SyntaxKind::PARSE_EXPR);
1911 self.bump(); // `parse`
1912 self.bump(); // `(`
1913 self.parse_expr(); // first arg: the Text
1914 if self.eat(SyntaxKind::COMMA) {
1915 self.parse_parser_expr();
1916 }
1917 self.expect(SyntaxKind::R_PAREN, "`)` to close parse()");
1918 self.finish_node(); // PARSE_EXPR
1919 return;
1920 }
1921 // `Counter[(Int, Int)]()` — explicit type arguments on a constructor call
1922 // (§3.3). Decided from the *name* before the brackets are reached,
1923 // because the brackets themselves are a subscript's and their contents
1924 // cannot break the tie: `Int` parses as an expression too.
1925 //
1926 // Consequence, stated rather than hidden: a binding that shadows a type
1927 // constructor's name cannot be subscripted — `Counter[0]` reads as a type
1928 // argument list and then wants a `(`. That is the whole cost of the rule,
1929 // and it buys `m[k](7)` staying a call on an indexed closure.
1930 let takes_type_args = name_text.is_some_and(|t| TYPE_CONSTRUCTOR_NAMES.contains(&t))
1931 && self.nth_kind(1) == SyntaxKind::L_BRACK;
1932 self.start_node(SyntaxKind::PATH_EXPR);
1933 self.bump(); // name
1934 self.finish_node();
1935 if takes_type_args {
1936 self.parse_type_arg_list();
1937 }
1938 if self.at_argument_list() {
1939 self.bump(); // `(`
1940 self.start_node_at(cp, SyntaxKind::CALL_EXPR);
1941 // Re-open the path as the callee: rowan's checkpoint wraps the
1942 // already-emitted PATH_EXPR, so the call's first child is the path.
1943 self.parse_arg_list();
1944 self.finish_node(); // CALL_EXPR
1945 } else if self.at(SyntaxKind::L_BRACE) && lit == StructLit::Allowed {
1946 // Record literal: `Name { field: expr, … }` or `Name { x, y }` (§4.5
1947 // punning). In expression position, a bare name followed by `{` is a
1948 // record construction; the keyword heads suppress that reading (see
1949 // [`StructLit`]) so their block is not taken as a record body.
1950 self.parse_record_lit_body(cp);
1951 }
1952 // The rest of the postfix chain — `.method(args)`, `.field` and further
1953 // `(args)` calls in any order.
1954 self.parse_postfix(cp);
1955 }
1956
1957 /// Whether the `{` under the cursor opens an **anonymous record literal**
1958 /// (§5.6) rather than a block.
1959 ///
1960 /// Both are a `{` where an expression must begin, so one of the two readings
1961 /// has to be chosen from what follows. The rule is that a record literal is
1962 /// what a **block cannot be**, decided from two tokens:
1963 ///
1964 /// - `{ x: …` — a block's first statement cannot be a name followed by a
1965 /// `:`. The one thing that looks like it is a marked statement, `{ x:bp }`,
1966 /// and the `:bp` adjacency rule ([`Parser::is_breakpoint_marker_at`]) is
1967 /// what separates the two. `{ x: bp }` with a space is the record literal
1968 /// whose field is the binding `bp`, which is the same answer `min=` gives.
1969 /// - `{ x, …` — a block's first statement cannot be a name followed by a
1970 /// `,`. This is what admits an all-punned literal, `{ x, y }`.
1971 ///
1972 /// **`{ x }` stays a block**, and that is the one case the rule cannot have
1973 /// both ways: it is a well-formed block whose value is `x` *and* a
1974 /// well-formed one-field punned literal, and blocks-as-values had the
1975 /// spelling first. Write `{ x: x }` for the record. A `{}` is likewise the
1976 /// empty block it already was — a record with no fields has no field set to
1977 /// be identified by, so nothing is lost.
1978 ///
1979 /// The [`StructLit`] suppression the four keyword heads set is deliberately
1980 /// **not** consulted. What that flag protects is `p { … }` — a *name*
1981 /// followed by the brace that could be the keyword's block (ADR-050). A `{`
1982 /// where an operand is still required is not that: `if { x: 1 } == p { … }`
1983 /// has the literal at the head of the condition, so the block the `if` is
1984 /// waiting for cannot be it.
1985 fn at_anonymous_record_lit(&mut self) -> bool {
1986 if !self.at(SyntaxKind::L_BRACE) || self.nth_kind(1) != SyntaxKind::Ident {
1987 return false;
1988 }
1989 match self.nth_kind(2) {
1990 SyntaxKind::COLON => !self
1991 .nth_index(2)
1992 .is_some_and(|colon| self.is_breakpoint_marker_at(colon)),
1993 SyntaxKind::COMMA => true,
1994 _ => false,
1995 }
1996 }
1997
1998 /// The `{ field: expr, … }` body of a record literal, opened as a
1999 /// [`RECORD_LIT_EXPR`](SyntaxKind::RECORD_LIT_EXPR) at `cp`.
2000 ///
2001 /// One production for both spellings. `cp` is what decides which: taken
2002 /// before a head name was emitted it wraps that name as the literal's
2003 /// `PATH_EXPR` child, and taken at the `{` there is no child before the
2004 /// field list — which is exactly how [`praxis_ast::RecordLitExpr::name`]
2005 /// reports an anonymous literal, and the shape a headless record *pattern*
2006 /// already has (ADR-091).
2007 fn parse_record_lit_body(&mut self, cp: rowan::Checkpoint) {
2008 self.start_node_at(cp, SyntaxKind::RECORD_LIT_EXPR);
2009 self.bump(); // `{`
2010 self.start_node(SyntaxKind::FIELD_LIST);
2011 if !self.at(SyntaxKind::R_BRACE) {
2012 loop {
2013 let before = self.meaningful_index();
2014 self.start_node(SyntaxKind::FIELD);
2015 self.expect(SyntaxKind::Ident, "field name");
2016 // Field punning (`{ x, y }`) or explicit (`{ x: expr }`).
2017 if self.eat(SyntaxKind::COLON) {
2018 self.parse_expr();
2019 }
2020 self.finish_node();
2021 if !self.eat(SyntaxKind::COMMA) {
2022 break;
2023 }
2024 // A trailing comma closes the list.
2025 if self.at(SyntaxKind::R_BRACE) {
2026 break;
2027 }
2028 self.ensure_progress(before);
2029 }
2030 }
2031 self.expect(SyntaxKind::R_BRACE, "`}` to close record literal");
2032 self.finish_node(); // FIELD_LIST
2033 self.finish_node(); // RECORD_LIT_EXPR
2034 }
2035
2036 // -----------------------------------------------------------------------
2037 // Input-parser expression grammar (§7).
2038 //
2039 // `parser_expr := atom | template | call`
2040 // Whitespace and indentation outside backticks are insignificant (§7.1).
2041 // -----------------------------------------------------------------------
2042
2043 /// Parse a parser expression (§7 EBNF). Emits a `PARSER_EXPR` wrapper node
2044 /// around exactly one of: an atomic name, a backtick template, or a
2045 /// constructor call `name(args)`.
2046 fn parse_parser_expr(&mut self) {
2047 self.eat_trivia(); // whitespace outside backticks is insignificant (§7.1)
2048 let kind = self.peek();
2049 match kind {
2050 // An unterminated run is still *shaped* like a template, and the
2051 // lexer has already reported it (T002, ADR-094). Taking it here
2052 // rather than falling through to "expected a parser expression"
2053 // is what keeps one typo to one error: the alternative is a P001
2054 // and then an I000 about an interior nobody wrote.
2055 SyntaxKind::BacktickTemplate | SyntaxKind::UnterminatedBacktickTemplate => {
2056 self.parse_parser_template()
2057 }
2058 SyntaxKind::Ident => {
2059 // An identifier is either an atomic parser (`int`, `char`, …)
2060 // or a constructor call (`lines(P)`, `sep(s, P)`). Decide by the
2061 // presence of `(`.
2062 if self.nth_kind(1) == SyntaxKind::L_PAREN {
2063 self.parse_parser_call();
2064 } else {
2065 self.parse_parser_atom();
2066 }
2067 }
2068 _ => {
2069 // Nothing recognizable as a parser expression.
2070 let span = self.current_span();
2071 self.error(span, "expected a parser expression");
2072 self.start_node(SyntaxKind::PARSER_EXPR);
2073 self.start_node(SyntaxKind::PARSE_ERROR);
2074 if !self.at_end() {
2075 self.bump(); // guaranteed progress
2076 }
2077 self.finish_node(); // PARSE_ERROR
2078 self.finish_node(); // PARSER_EXPR
2079 }
2080 }
2081 }
2082
2083 /// Parse an atomic parser name: `int`, `char`, `word`, `text`, `rest`,
2084 /// `digit` (§7.4). The identifier is wrapped in `PARSER_EXPR > PARSER_ATOM`.
2085 fn parse_parser_atom(&mut self) {
2086 self.start_node(SyntaxKind::PARSER_EXPR);
2087 self.start_node(SyntaxKind::PARSER_ATOM);
2088 self.bump(); // the atomic name
2089 self.finish_node(); // PARSER_ATOM
2090 self.finish_node(); // PARSER_EXPR
2091 }
2092
2093 /// Parse a backtick template as a parser expression (§7.2). The whole
2094 /// `BacktickTemplate` token is emitted as a `PARSER_TEMPLATE` child; its
2095 /// interior is re-scanned by `praxis-input-parser` later (in HIR). The
2096 /// template node is wrapped in `PARSER_EXPR`.
2097 fn parse_parser_template(&mut self) {
2098 self.start_node(SyntaxKind::PARSER_EXPR);
2099 self.start_node(SyntaxKind::PARSER_TEMPLATE);
2100 self.bump(); // the BacktickTemplate token (interior re-scanned in HIR)
2101 self.finish_node(); // PARSER_TEMPLATE
2102 self.finish_node(); // PARSER_EXPR
2103 }
2104
2105 /// Parse a constructor call `name(args)` (§7.5). Emits
2106 /// `PARSER_EXPR > PARSER_CALL > PATH_EXPR + PARSER_ARG_LIST`. Each argument
2107 /// is one of:
2108 /// - a positional parser expression (`lines(int)` → child `int`);
2109 /// - a positional literal, emitted as a `LITERAL` node: a string (the
2110 /// separator for `sep`, the set for `one_of`) or a whole number (the
2111 /// count of `repeated(P, N)`, §7.5). **Which constructors accept which
2112 /// literal is not the grammar's question** — it is
2113 /// `Constructor::arg_shape`'s, exactly as `Constructor::keyword_arg`
2114 /// owns the keyword question. A count written where no count belongs
2115 /// earns an argument diagnostic naming the constructor, which says more
2116 /// than "expected a parser expression" does;
2117 /// - a named argument `name: parser_expr` (§7.5), emitted as a
2118 /// `PARSER_NAMED_ARG` node — used by heterogeneous `sections`
2119 /// (`rules: lines(...)`), `chars`/`grid` keyword args (`skip: whitespace`,
2120 /// `fill: value`), and the `repeated(...)` tail marker of `sections`.
2121 fn parse_parser_call(&mut self) {
2122 self.start_node(SyntaxKind::PARSER_EXPR);
2123 self.start_node(SyntaxKind::PARSER_CALL);
2124 // The constructor name as a path.
2125 self.start_node(SyntaxKind::PATH_EXPR);
2126 self.bump(); // constructor name
2127 self.finish_node();
2128 // Argument list.
2129 self.expect(SyntaxKind::L_PAREN, "`(` to open parser call arguments");
2130 self.start_node(SyntaxKind::PARSER_ARG_LIST);
2131 if !self.at(SyntaxKind::R_PAREN) {
2132 loop {
2133 self.eat_trivia();
2134 if self.at(SyntaxKind::TextLit) || self.at(SyntaxKind::IntLit) {
2135 // A positional literal: `sep`'s separator, or the count of
2136 // `repeated(P, N)`.
2137 self.start_node(SyntaxKind::LITERAL);
2138 self.bump();
2139 self.finish_node();
2140 } else if self.at(SyntaxKind::MINUS) && self.nth_kind(1) == SyntaxKind::IntLit {
2141 // A negative count is still a *count*, and it belongs in one
2142 // `LITERAL` node so the shape check can say what is wrong
2143 // with it. Left to `parse_parser_expr`, `repeated(P, -1)`
2144 // would report "expected a parser expression" at the `-` —
2145 // a complaint about the wrong thing entirely.
2146 self.start_node(SyntaxKind::LITERAL);
2147 self.bump(); // `-`
2148 self.bump(); // the digits
2149 self.finish_node();
2150 } else if self.at(SyntaxKind::Ident) && self.nth_kind(1) == SyntaxKind::COLON {
2151 // A named argument `name: parser_expr`. The name is a bare
2152 // ident followed by `:`. This does not conflict with a
2153 // constructor call (`lines(...)`) because that has `(` at
2154 // position 1, not `:`.
2155 self.start_node(SyntaxKind::PARSER_NAMED_ARG);
2156 self.bump(); // the name ident
2157 self.eat_trivia();
2158 self.expect(SyntaxKind::COLON, "`:` after a named argument");
2159 self.eat_trivia();
2160 self.parse_parser_named_arg_value();
2161 self.finish_node(); // PARSER_NAMED_ARG
2162 } else {
2163 self.parse_parser_expr();
2164 }
2165 self.eat_trivia();
2166 if !self.eat(SyntaxKind::COMMA) {
2167 break;
2168 }
2169 // Allow a trailing comma: if the next token is `)`, stop.
2170 self.eat_trivia();
2171 if self.at(SyntaxKind::R_PAREN) {
2172 break;
2173 }
2174 }
2175 }
2176 self.expect(SyntaxKind::R_PAREN, "`)` to close parser call arguments");
2177 self.finish_node(); // PARSER_ARG_LIST
2178 self.finish_node(); // PARSER_CALL
2179 self.finish_node(); // PARSER_EXPR
2180 }
2181
2182 /// Parse the value after `name:` in a parser call's argument list.
2183 ///
2184 /// Two shapes live here, and only the grammar can tell them apart by
2185 /// looking:
2186 /// - a **literal** (`fill: 0`, `fill: "-"`) — the value of a keyword
2187 /// argument, which is not a parser expression at all. It becomes a
2188 /// `PARSER_KEYWORD_VALUE` node holding the raw token, and whether the
2189 /// constructor actually has a keyword argument of that name is decided
2190 /// later, by `Constructor::keyword_arg`, where that rule already lives.
2191 /// - anything else (`rules: lines(int)`, `skip: whitespace`) — a parser
2192 /// expression.
2193 fn parse_parser_named_arg_value(&mut self) {
2194 if matches!(
2195 self.peek(),
2196 SyntaxKind::IntLit | SyntaxKind::FloatLit | SyntaxKind::TextLit
2197 ) {
2198 self.start_node(SyntaxKind::PARSER_KEYWORD_VALUE);
2199 self.bump(); // the literal token
2200 self.finish_node();
2201 } else {
2202 self.parse_parser_expr();
2203 }
2204 }
2205
2206 // -----------------------------------------------------------------------
2207 // Error recovery.
2208 // -----------------------------------------------------------------------
2209
2210 /// Expect a **binding position**: a name, or `_` for one the program is
2211 /// deliberately not naming (D7, ADR-049). Reports at the current token if
2212 /// neither is there.
2213 ///
2214 /// `var _ = f()`, `fn g(_)` and `|_| 0` are legal and introduce nothing —
2215 /// the AST's name accessors look for an `Ident`, so a wildcard binder is an
2216 /// absent name all the way down rather than a symbol called `_`.
2217 fn expect_binder(&mut self, what: &str) -> bool {
2218 if self.at(SyntaxKind::UNDERSCORE) {
2219 self.bump();
2220 return true;
2221 }
2222 self.expect(SyntaxKind::Ident, what)
2223 }
2224
2225 fn expect(&mut self, kind: SyntaxKind, what: &str) -> bool {
2226 if self.at(kind) {
2227 self.bump();
2228 true
2229 } else {
2230 let span = self.current_span();
2231 let spelling = self.current_spelling();
2232 self.error(span, format!("expected {what}, found {spelling}"));
2233 false
2234 }
2235 }
2236
2237 /// The span of the current meaningful token (or a zero-width span at EOF).
2238 fn current_span(&mut self) -> Span {
2239 self.eat_trivia();
2240 if self.cursor < self.tokens.len() {
2241 self.tokens[self.cursor].span
2242 } else {
2243 Span::at(BytePos::ZERO)
2244 }
2245 }
2246
2247 /// A human-readable spelling of the current token, for diagnostics.
2248 fn current_spelling(&mut self) -> &'static str {
2249 match self.peek() {
2250 SyntaxKind::EOF => "end of file",
2251 _ => "unexpected token",
2252 }
2253 }
2254
2255 /// Skip tokens until a plausible statement boundary (a brace, a statement
2256 /// keyword, or EOF), wrapping skipped tokens in a `PARSE_ERROR` node.
2257 fn recover_to_stmt_boundary(&mut self) {
2258 self.start_node(SyntaxKind::PARSE_ERROR);
2259 let span = self.current_span();
2260 self.error(span, "unexpected token, skipping to recover");
2261 while !self.at_end()
2262 && !self.at(SyntaxKind::R_BRACE)
2263 && !matches!(
2264 self.peek(),
2265 SyntaxKind::KW_VAR
2266 | SyntaxKind::KW_FN
2267 | SyntaxKind::KW_IF
2268 | SyntaxKind::KW_WHILE
2269 | SyntaxKind::KW_RETURN
2270 )
2271 {
2272 self.bump();
2273 }
2274 self.finish_node();
2275 }
2276
2277 /// The builder checkpoint *before* the current operand was emitted.
2278 ///
2279 /// In a single-pass builder the checkpoint must be captured before the
2280 /// children are emitted, so we stash one at the start of each prefix/atom.
2281 ///
2282 /// The trivia in front of the operand is emitted **first**, for
2283 /// [`start_node`](Self::start_node)'s reason and by the same rule: a node
2284 /// retroactively opened here — a `BIN_EXPR`, a `RANGE_EXPR`, a `CALL_EXPR`,
2285 /// a parenthesized expression — would otherwise begin at a checkpoint taken
2286 /// before the whitespace and swallow it.
2287 fn checkpoint_lhs(&mut self) -> rowan::Checkpoint {
2288 self.eat_trivia();
2289 self.builder.checkpoint()
2290 }
2291}
2292
2293#[cfg(test)]
2294mod tests {
2295 use super::*;
2296 use praxis_source::{DiagnosticCategory, SourceMap};
2297
2298 fn parse_text(text: &str) -> ParseOutput {
2299 let map = SourceMap::new();
2300 let id = map.intern("test.px", text);
2301 parse(id, text)
2302 }
2303
2304 fn dump(text: &str) -> String {
2305 praxis_test_support::format_syntax_tree(&parse_text(text).tree)
2306 }
2307
2308 #[test]
2309 fn parses_var_binding() {
2310 let out = parse_text("var x = 1");
2311 assert!(out.diagnostics.is_empty(), "{:?}", out.diagnostics);
2312 insta::assert_snapshot!(dump("var x = 1"), @r#"
2313 SOURCE_FILE@0..9
2314 VAR_STMT@0..9
2315 KW_VAR "var"@0..3
2316 Whitespace " "@3..4
2317 Ident "x"@4..5
2318 Whitespace " "@5..6
2319 EQ "="@6..7
2320 Whitespace " "@7..8
2321 LITERAL@8..9
2322 IntLit "1"@8..9
2323 "#);
2324 }
2325
2326 #[test]
2327 fn parses_var_binding_and_reassignment() {
2328 let out = parse_text("var score = 0");
2329 assert!(out.diagnostics.is_empty(), "{:?}", out.diagnostics);
2330 let kinds = construct_names(&out.tree);
2331 assert!(kinds.contains(&SyntaxKind::VAR_STMT));
2332 }
2333
2334 #[test]
2335 fn parses_function_definition() {
2336 let src = "fn add(a: Int, b: Int) -> Int { a + b }";
2337 let out = parse_text(src);
2338 assert!(out.diagnostics.is_empty(), "{:?}", out.diagnostics);
2339 let kinds = construct_names(&out.tree);
2340 assert!(kinds.contains(&SyntaxKind::FN_ITEM));
2341 assert!(kinds.contains(&SyntaxKind::PARAM_LIST));
2342 assert!(kinds.contains(&SyntaxKind::PARAM));
2343 assert!(kinds.contains(&SyntaxKind::BLOCK_EXPR));
2344 assert!(kinds.contains(&SyntaxKind::BIN_EXPR));
2345 }
2346
2347 #[test]
2348 fn parses_out_call() {
2349 let out = parse_text("out(42)");
2350 assert!(out.diagnostics.is_empty(), "{:?}", out.diagnostics);
2351 let kinds = construct_names(&out.tree);
2352 assert!(kinds.contains(&SyntaxKind::CALL_EXPR));
2353 assert!(kinds.contains(&SyntaxKind::ARG_LIST));
2354 }
2355
2356 #[test]
2357 fn parses_if_else() {
2358 let src = "if x { out(1) } else { out(2) }";
2359 let out = parse_text(src);
2360 assert!(out.diagnostics.is_empty(), "{:?}", out.diagnostics);
2361 let kinds = construct_names(&out.tree);
2362 assert!(kinds.contains(&SyntaxKind::IF_EXPR));
2363 assert!(kinds.contains(&SyntaxKind::ELSE_BRANCH));
2364 }
2365
2366 #[test]
2367 fn parses_while_loop() {
2368 let out = parse_text("while x < 10 { x = x + 1 }");
2369 assert!(out.diagnostics.is_empty(), "{:?}", out.diagnostics);
2370 let kinds = construct_names(&out.tree);
2371 assert!(kinds.contains(&SyntaxKind::WHILE_EXPR));
2372 }
2373
2374 #[test]
2375 fn parses_block_expression() {
2376 let out = parse_text("{ var a = 1\n a }");
2377 assert!(out.diagnostics.is_empty(), "{:?}", out.diagnostics);
2378 let kinds = construct_names(&out.tree);
2379 assert!(kinds.contains(&SyntaxKind::BLOCK_EXPR));
2380 assert!(kinds.contains(&SyntaxKind::VAR_STMT));
2381 assert!(kinds.contains(&SyntaxKind::EXPR_STMT));
2382 }
2383
2384 #[test]
2385 fn parses_text_literal() {
2386 let out = parse_text(r#"out("hello")"#);
2387 assert!(out.diagnostics.is_empty(), "{:?}", out.diagnostics);
2388 let kinds = construct_names(&out.tree);
2389 assert!(kinds.contains(&SyntaxKind::TextLit));
2390 }
2391
2392 /// A `'#'` in expression position is a `LITERAL` holding one `CharLit`, and
2393 /// the node spans exactly the literal — no leading trivia.
2394 #[test]
2395 fn parses_char_literal() {
2396 let src = "var c = '#'";
2397 let out = parse_text(src);
2398 assert!(out.diagnostics.is_empty(), "{:?}", out.diagnostics);
2399 let lit = out
2400 .tree
2401 .descendants()
2402 .find(|n| n.kind() == SyntaxKind::LITERAL)
2403 .expect("a LITERAL node");
2404 assert_eq!(lit.text().to_string(), "'#'");
2405 assert!(construct_names(&out.tree).contains(&SyntaxKind::CharLit));
2406 }
2407
2408 // --- string interpolation (§8.1, ADR-147) -------------------------------
2409
2410 /// An interpolated literal is an `INTERP_EXPR`, and the hole's expression is
2411 /// an ordinary subtree under it — a `PATH_EXPR` here, a `BIN_EXPR` below.
2412 /// That is what everything else in the compiler reads it through.
2413 #[test]
2414 fn parses_an_interpolated_literal() {
2415 let out = parse_text(r#"out("Part 2: {part2}")"#);
2416 assert!(out.diagnostics.is_empty(), "{:?}", out.diagnostics);
2417 let kinds = construct_names(&out.tree);
2418 assert!(kinds.contains(&SyntaxKind::INTERP_EXPR));
2419 assert!(kinds.contains(&SyntaxKind::PATH_EXPR));
2420 assert!(kinds.contains(&SyntaxKind::InterpOpen));
2421 assert!(kinds.contains(&SyntaxKind::InterpClose));
2422 // And it is *not* a LITERAL: a LITERAL is a leaf whose value comes off a
2423 // token, which an interpolated literal's does not.
2424 assert!(!kinds.contains(&SyntaxKind::TextLit));
2425 }
2426
2427 /// A hole holds a full expression (ADR-147 decision 1), so the shapes below
2428 /// each land as the node they would be anywhere else.
2429 #[test]
2430 fn a_hole_holds_a_full_expression() {
2431 for (src, expected) in [
2432 (r#"out("{a + b}")"#, SyntaxKind::BIN_EXPR),
2433 (r#"out("{p.0}")"#, SyntaxKind::TUPLE_INDEX_EXPR),
2434 (r#"out("{xs.len()}")"#, SyntaxKind::METHOD_CALL_EXPR),
2435 (r#"out("{m["k"]}")"#, SyntaxKind::INDEX_EXPR),
2436 (r#"out("{if c { 1 } else { 2 }}")"#, SyntaxKind::IF_EXPR),
2437 ] {
2438 let out = parse_text(src);
2439 assert!(out.diagnostics.is_empty(), "{src}: {:?}", out.diagnostics);
2440 assert!(construct_names(&out.tree).contains(&expected), "{src}");
2441 }
2442 }
2443
2444 /// Several holes are one node with one `InterpClose`, and the fragments
2445 /// alternate with the holes.
2446 #[test]
2447 fn several_holes_are_one_node() {
2448 let out = parse_text(r#"out("{a} and {b} and {c}")"#);
2449 assert!(out.diagnostics.is_empty(), "{:?}", out.diagnostics);
2450 let kinds = construct_names(&out.tree);
2451 assert_eq!(
2452 kinds
2453 .iter()
2454 .filter(|k| **k == SyntaxKind::INTERP_EXPR)
2455 .count(),
2456 1
2457 );
2458 assert_eq!(
2459 kinds
2460 .iter()
2461 .filter(|k| **k == SyntaxKind::InterpMiddle)
2462 .count(),
2463 2
2464 );
2465 }
2466
2467 /// Postfix operators apply to the whole literal, not to the last hole: an
2468 /// `INTERP_EXPR` is an atom like any other.
2469 #[test]
2470 fn an_interpolated_literal_takes_postfix_operators() {
2471 let out = parse_text(r#"var n = "{a}b".len()"#);
2472 assert!(out.diagnostics.is_empty(), "{:?}", out.diagnostics);
2473 assert!(construct_names(&out.tree).contains(&SyntaxKind::METHOD_CALL_EXPR));
2474 }
2475
2476 /// **An interpolated literal is not a pattern**, and refusing it is not
2477 /// pedantry: without the arm that reports it, `match s { "{x}" => … }`
2478 /// leaves a `PATTERN` whose only direct `Ident` is the hole's `x`, which
2479 /// `Pattern::kind` reads as a variable bind — an irrefutable arm that
2480 /// swallows every value with no diagnostic at all. That is why this asserts
2481 /// the diagnostic rather than the tree shape.
2482 #[test]
2483 fn an_interpolated_literal_is_not_a_pattern() {
2484 let out = parse_text("var r = match s {\n \"{x}\" => 1\n _ => 2\n}");
2485 assert!(
2486 !out.diagnostics.is_empty(),
2487 "an interpolated literal in pattern position must be reported"
2488 );
2489 assert!(
2490 out.diagnostics
2491 .iter()
2492 .any(|d| d.message().contains("not a pattern")),
2493 "{:?}",
2494 out.diagnostics
2495 );
2496 }
2497
2498 /// `{{` is the escape in Rust, C# and Python, so it is the first thing a
2499 /// reader tries — and here it would otherwise *parse*: `{` opens the hole,
2500 /// `{}` is an empty block, `}` closes it, and `"a{{}}b"` prints `aUnitb`
2501 /// with no diagnostic. The refusal is what keeps that from being silent.
2502 #[test]
2503 fn a_doubled_brace_is_refused_rather_than_meaning_a_block() {
2504 for src in [
2505 "out(\"a{{}}b\")",
2506 "out(\"a{{x}}b\")",
2507 "out(\"{{}}\")",
2508 "out(\"ok {n} then a{{}}b\")",
2509 ] {
2510 let out = parse_text(src);
2511 assert!(
2512 out.diagnostics
2513 .iter()
2514 .any(|d| d.message().contains("is not an escape for a literal brace")),
2515 "`{src}` must be refused, got {:?}",
2516 out.diagnostics
2517 );
2518 }
2519 // The spelling that works, and an ordinary hole, are both untouched.
2520 for src in ["out(\"a\\{\\}b\")", "out(\"a{n}b\")", "out(\"{a + b}\")"] {
2521 let out = parse_text(src);
2522 assert!(
2523 out.diagnostics.is_empty(),
2524 "`{src}` must parse cleanly, got {:?}",
2525 out.diagnostics
2526 );
2527 }
2528 }
2529
2530 /// **`is_pattern_start`'s half of ADR-141.** Leave `CharLit` out of it and
2531 /// the arm list stops after `'#' => …`: the second and third arms leave the
2532 /// tree with no diagnostic at all, and the literal still looks like it
2533 /// works.
2534 #[test]
2535 fn a_char_arm_does_not_truncate_the_arm_list() {
2536 let src = "var r = match c {\n '#' => 1\n '.' => 2\n _ => 3\n}";
2537 let out = parse_text(src);
2538 assert!(out.diagnostics.is_empty(), "{:?}", out.diagnostics);
2539 let arms = construct_names(&out.tree)
2540 .into_iter()
2541 .filter(|k| *k == SyntaxKind::MATCH_ARM)
2542 .count();
2543 assert_eq!(arms, 3);
2544 }
2545
2546 // --- statement separation and postfix chains ---------------------------
2547
2548 #[test]
2549 fn regression_same_line_statements_require_a_semicolon() {
2550 let out = parse_text("var a = 1 var b = 2");
2551 assert!(
2552 !out.diagnostics.is_empty(),
2553 "two statements on one line must not parse as if a separator existed"
2554 );
2555 }
2556
2557 #[test]
2558 fn regression_semicolons_separate_top_level_statements() {
2559 let out = parse_text("var a = 1; var b = 2");
2560 assert!(out.diagnostics.is_empty(), "{:?}", out.diagnostics);
2561 assert_eq!(
2562 construct_names(&out.tree)
2563 .iter()
2564 .filter(|kind| **kind == SyntaxKind::VAR_STMT)
2565 .count(),
2566 2
2567 );
2568 }
2569
2570 #[test]
2571 fn regression_newline_terminates_a_bare_return() {
2572 let out = parse_text("fn f() { return\n1 }");
2573 assert!(out.diagnostics.is_empty(), "{:?}", out.diagnostics);
2574 let return_expr = out
2575 .tree
2576 .descendants()
2577 .find(|node| node.kind() == SyntaxKind::RETURN_EXPR)
2578 .expect("return expression");
2579 assert_eq!(
2580 return_expr.children().count(),
2581 0,
2582 "the next line must be a separate expression, not return's value"
2583 );
2584 }
2585
2586 #[test]
2587 fn regression_postfix_forms_may_be_interleaved() {
2588 let out = parse_text("(fs).get(0)(100)");
2589 assert!(out.diagnostics.is_empty(), "{:?}", out.diagnostics);
2590 let kinds = construct_names(&out.tree);
2591 assert_eq!(
2592 kinds
2593 .iter()
2594 .filter(|kind| **kind == SyntaxKind::CALL_EXPR)
2595 .count(),
2596 1,
2597 "the final `(100)` must call the result of `.get(0)`"
2598 );
2599 assert_eq!(
2600 out.tree.children().count(),
2601 1,
2602 "the postfix call must remain part of the same expression statement"
2603 );
2604 }
2605
2606 // --- where a newline ends a statement, and where it does not -----------
2607
2608 /// D8's second half, stated for the operator it is most likely to break.
2609 /// A newline is consulted between statements and at `break`/`return`'s
2610 /// optional-value decision — never inside the Pratt loop.
2611 #[test]
2612 fn an_operator_continues_across_a_line_break() {
2613 let out = parse_text("var a = 1 +\n2");
2614 assert!(out.diagnostics.is_empty(), "{:?}", out.diagnostics);
2615 let kinds = construct_names(&out.tree);
2616 assert_eq!(
2617 kinds
2618 .iter()
2619 .filter(|kind| **kind == SyntaxKind::VAR_STMT)
2620 .count(),
2621 1,
2622 "`1 +` and `2` are one addition, not two statements"
2623 );
2624 assert!(kinds.contains(&SyntaxKind::BIN_EXPR));
2625 }
2626
2627 /// **A node never begins with trivia**, so an expression's `text_range` is
2628 /// the expression and a caret under it underlines only that.
2629 ///
2630 /// Asserted as an invariant over whole trees rather than as another
2631 /// snapshot: `start_node` has dozens of call sites and a snapshot pins the
2632 /// handful a fixture happens to reach. The exception is the **root**, which
2633 /// is where a file's leading trivia has to go — there is no node before it.
2634 #[test]
2635 fn a_node_never_begins_with_trivia() {
2636 for src in [
2637 "var c = a + b",
2638 " var c = ( a ) + 1 ",
2639 "// a leading comment\nvar t = true && false",
2640 "fn f(x) -> Int {\n var y = -x\n y * 2\n}",
2641 "var v = read lines( `{a:int},{b:int}` )",
2642 "var m = match t {\n A => 1\n _ => 2\n}",
2643 "for i in 0..n {\n out( i )\n}",
2644 "var p = Point { x: 1, y: 2 }",
2645 "var f = |a, b| a + b\nvar g = f ( 1 , 2 )",
2646 "var s = 0\ns += grid [ 1 , 2 ]",
2647 // Recovery paths open nodes too, and `PARSE_ERROR` is a node.
2648 "var @ = 1\nvar ok = 2",
2649 "var x = (",
2650 ] {
2651 let tree = parse_text(src).tree;
2652 for node in tree.descendants() {
2653 if node.kind() == SyntaxKind::SOURCE_FILE {
2654 continue;
2655 }
2656 let Some(first) = node.first_token() else {
2657 continue;
2658 };
2659 assert!(
2660 !first.kind().is_trivia(),
2661 "{:?}@{:?} begins with {:?} in {src:?}\n{}",
2662 node.kind(),
2663 node.text_range(),
2664 first.kind(),
2665 praxis_test_support::format_syntax_tree(&tree),
2666 );
2667 }
2668 }
2669 }
2670
2671 /// The same rule stated directly: an operand's range is the operand, so
2672 /// `lhs.syntax().text_range()` is what a diagnostic can point at.
2673 #[test]
2674 fn an_operands_range_is_the_operand_and_not_the_space_before_it() {
2675 // `var c = a + b` — `a` at 8..9, `b` at 12..13.
2676 let tree = parse_text("var c = a + b").tree;
2677 let bin = tree
2678 .descendants()
2679 .find(|n| n.kind() == SyntaxKind::BIN_EXPR)
2680 .expect("a BIN_EXPR");
2681 assert_eq!(
2682 bin.text_range(),
2683 rowan::TextRange::new(8.into(), 13.into()),
2684 "the binary expression is `a + b`, not `= a + b`"
2685 );
2686 let operands: Vec<_> = bin
2687 .children()
2688 .filter(|n| n.kind() == SyntaxKind::PATH_EXPR)
2689 .map(|n| n.text_range())
2690 .collect();
2691 assert_eq!(
2692 operands,
2693 vec![
2694 rowan::TextRange::new(8.into(), 9.into()),
2695 rowan::TextRange::new(12.into(), 13.into()),
2696 ],
2697 "each operand's range is one character wide"
2698 );
2699 }
2700
2701 /// `..`/`..=` is an infix operator that builds a `RANGE_EXPR` (ADR-059), and
2702 /// it binds **looser than arithmetic and comparison**: every range in the
2703 /// corpus writes an arithmetic bound, so `0..n - 1` has to be `0..(n - 1)`.
2704 #[test]
2705 fn a_range_binds_looser_than_the_arithmetic_in_its_bounds() {
2706 // The bound is the whole subtraction, so the RANGE_EXPR contains a
2707 // BIN_EXPR rather than the other way round.
2708 insta::assert_snapshot!(dump("var r = 0..n - 1"), @r#"
2709 SOURCE_FILE@0..16
2710 VAR_STMT@0..16
2711 KW_VAR "var"@0..3
2712 Whitespace " "@3..4
2713 Ident "r"@4..5
2714 Whitespace " "@5..6
2715 EQ "="@6..7
2716 Whitespace " "@7..8
2717 RANGE_EXPR@8..16
2718 LITERAL@8..9
2719 IntLit "0"@8..9
2720 DOT2 ".."@9..11
2721 BIN_EXPR@11..16
2722 PATH_EXPR@11..12
2723 Ident "n"@11..12
2724 Whitespace " "@12..13
2725 MINUS "-"@13..14
2726 Whitespace " "@14..15
2727 LITERAL@15..16
2728 IntLit "1"@15..16
2729 "#);
2730 // …and looser than comparison too, so `a..b == c..d` compares two ranges.
2731 let out = parse_text("var b = 1..2 == 3..4");
2732 assert!(out.diagnostics.is_empty(), "{:?}", out.diagnostics);
2733 let kinds = construct_names(&out.tree);
2734 assert_eq!(
2735 kinds
2736 .iter()
2737 .filter(|k| **k == SyntaxKind::RANGE_EXPR)
2738 .count(),
2739 2,
2740 "two ranges, one comparison — not a range over a Bool"
2741 );
2742 assert_eq!(
2743 kinds.iter().filter(|k| **k == SyntaxKind::BIN_EXPR).count(),
2744 1
2745 );
2746 }
2747
2748 /// `..=` is its own token in the same position, and the *node* is the same
2749 /// kind — the difference is the operator token, which is where
2750 /// `RangeExpr::is_inclusive` reads it from.
2751 #[test]
2752 fn an_inclusive_range_is_the_same_node_with_a_different_operator() {
2753 let out = parse_text("var r = 0..=9");
2754 assert!(out.diagnostics.is_empty(), "{:?}", out.diagnostics);
2755 let kinds = construct_names(&out.tree);
2756 assert!(kinds.contains(&SyntaxKind::RANGE_EXPR));
2757 assert!(kinds.contains(&SyntaxKind::DOT2EQ));
2758 assert!(!kinds.contains(&SyntaxKind::DOT2));
2759 }
2760
2761 /// A range is an ordinary expression, so it appears wherever one may: a
2762 /// `for` header (where the `{` must not be read as a record literal), a
2763 /// call argument, and a parenthesized bound.
2764 #[test]
2765 fn a_range_is_legal_wherever_an_expression_is() {
2766 for src in [
2767 "for i in 0..n { out(i) }",
2768 "for i in 0..=n { out(i) }",
2769 "var r = (0 - 1)..(n + 1)",
2770 "out(0..3)",
2771 // The bound may itself be a call or a method call.
2772 "var r = 0..v.len()",
2773 "var r = abs(0 - 3)..max(1, 2)",
2774 ] {
2775 let out = parse_text(src);
2776 assert!(out.diagnostics.is_empty(), "{src:?}: {:?}", out.diagnostics);
2777 assert!(
2778 construct_names(&out.tree).contains(&SyntaxKind::RANGE_EXPR),
2779 "{src:?} produced no RANGE_EXPR"
2780 );
2781 }
2782 // `Range` in *type* position is a type name, not a range expression —
2783 // the annotation form D6 makes a first-class value worth having.
2784 let out = parse_text("fn f(r: Range) -> Range { r }");
2785 assert!(out.diagnostics.is_empty(), "{:?}", out.diagnostics);
2786 assert!(!construct_names(&out.tree).contains(&SyntaxKind::RANGE_EXPR));
2787 }
2788
2789 /// D8's rule, applied to `..`: a newline after it continues the expression,
2790 /// exactly as one after `+` does. The Pratt loop never consults
2791 /// `newline_before`, and this is the test that says a range is not the
2792 /// exception.
2793 #[test]
2794 fn a_range_continues_across_a_line_break() {
2795 let out = parse_text("var r = 1 ..\n5");
2796 assert!(out.diagnostics.is_empty(), "{:?}", out.diagnostics);
2797 let kinds = construct_names(&out.tree);
2798 assert_eq!(
2799 kinds
2800 .iter()
2801 .filter(|kind| **kind == SyntaxKind::VAR_STMT)
2802 .count(),
2803 1,
2804 "`1 ..` and `5` are one range, not two statements"
2805 );
2806 assert!(kinds.contains(&SyntaxKind::RANGE_EXPR));
2807 }
2808
2809 /// …and so does a postfix chain: the line break before `.len()` is inside an
2810 /// expression, so it terminates nothing.
2811 #[test]
2812 fn a_method_chain_continues_across_a_line_break() {
2813 let out = parse_text("var n = v\n .len()");
2814 assert!(out.diagnostics.is_empty(), "{:?}", out.diagnostics);
2815 assert!(construct_names(&out.tree).contains(&SyntaxKind::METHOD_CALL_EXPR));
2816 }
2817
2818 /// `break`'s half of the optional-value rule;
2819 /// `regression_newline_terminates_a_bare_return` covers `return`.
2820 #[test]
2821 fn a_newline_terminates_a_bare_break() {
2822 let out = parse_text("loop { break\n1 }");
2823 assert!(out.diagnostics.is_empty(), "{:?}", out.diagnostics);
2824 let break_expr = out
2825 .tree
2826 .descendants()
2827 .find(|node| node.kind() == SyntaxKind::BREAK_EXPR)
2828 .expect("break expression");
2829 assert_eq!(break_expr.children().count(), 0);
2830 }
2831
2832 /// A `;` separates statements *inside* a block — it is one of the two things
2833 /// that can, the other being a line break.
2834 #[test]
2835 fn a_semicolon_separates_two_statements_on_one_line_in_a_block() {
2836 let out = parse_text("fn f() { var a = 1; var b = 2 }");
2837 assert!(out.diagnostics.is_empty(), "{:?}", out.diagnostics);
2838 assert_eq!(
2839 construct_names(&out.tree)
2840 .iter()
2841 .filter(|kind| **kind == SyntaxKind::VAR_STMT)
2842 .count(),
2843 2
2844 );
2845 }
2846
2847 /// A run-on is reported where it happens and parsing continues: three
2848 /// statements, two missing separators, three `VAR_STMT`s and no cascade.
2849 #[test]
2850 fn each_missing_separator_is_reported_once_and_parsing_continues() {
2851 let out = parse_text("var a = 1 var b = 2 var c = 3");
2852 let separator_errors = out
2853 .diagnostics
2854 .iter()
2855 .filter(|d| d.kind() == DiagCode::ExpectedStatementSeparator)
2856 .count();
2857 assert_eq!(separator_errors, 2, "{:?}", out.diagnostics);
2858 assert_eq!(
2859 construct_names(&out.tree)
2860 .iter()
2861 .filter(|kind| **kind == SyntaxKind::VAR_STMT)
2862 .count(),
2863 3
2864 );
2865 }
2866
2867 /// The block loop demands one too, and the closing `}` is a separator in its
2868 /// own right — a trailing expression needs nothing after it.
2869 #[test]
2870 fn a_block_demands_a_separator_but_its_closing_brace_is_one() {
2871 let clean = parse_text("fn f() { var a = 1\n a }");
2872 assert!(clean.diagnostics.is_empty(), "{:?}", clean.diagnostics);
2873
2874 let run_on = parse_text("fn f() { var a = 1 a }");
2875 assert!(
2876 run_on
2877 .diagnostics
2878 .iter()
2879 .any(|d| d.kind() == DiagCode::ExpectedStatementSeparator),
2880 "{:?}",
2881 run_on.diagnostics
2882 );
2883 }
2884
2885 /// Match arms are comma-OR-newline separated, and a run-on is reported.
2886 #[test]
2887 fn match_arms_on_one_line_need_a_comma() {
2888 let commas = parse_text("fn f() { match x { A => 1, B => 2 } }");
2889 assert!(commas.diagnostics.is_empty(), "{:?}", commas.diagnostics);
2890
2891 let newlines = parse_text("fn f() { match x {\n A => 1\n B => 2\n } }");
2892 assert!(
2893 newlines.diagnostics.is_empty(),
2894 "{:?}",
2895 newlines.diagnostics
2896 );
2897
2898 let run_on = parse_text("fn f() { match x { A => 1 B => 2 } }");
2899 assert!(
2900 run_on
2901 .diagnostics
2902 .iter()
2903 .any(|d| d.kind() == DiagCode::ExpectedStatementSeparator),
2904 "{:?}",
2905 run_on.diagnostics
2906 );
2907 }
2908
2909 #[test]
2910 fn regression_parenthesized_record_literal_is_valid_in_a_condition() {
2911 let out = parse_text("if (Point { x: 1 } == p) { 0 }");
2912 assert!(out.diagnostics.is_empty(), "{:?}", out.diagnostics);
2913 assert!(
2914 construct_names(&out.tree).contains(&SyntaxKind::RECORD_LIT_EXPR),
2915 "the parenthesized condition must retain its record literal"
2916 );
2917 }
2918
2919 #[test]
2920 fn regression_match_arm_may_return_a_record_literal() {
2921 let out = parse_text("match x { A => Point { x: 1 } }");
2922 assert!(out.diagnostics.is_empty(), "{:?}", out.diagnostics);
2923 assert!(
2924 construct_names(&out.tree).contains(&SyntaxKind::RECORD_LIT_EXPR),
2925 "the arm body must contain a record literal"
2926 );
2927 }
2928
2929 // --- which brackets reset record-literal suppression --------------------
2930
2931 /// Every bracketed context resets it, not only parentheses: an argument
2932 /// list, a tuple, and a block are all places where the `{` cannot be the
2933 /// body a keyword is waiting for.
2934 #[test]
2935 fn every_bracket_restores_record_literals_inside_a_condition() {
2936 for src in [
2937 "if f(Point { x: 1 }) { 0 }",
2938 "if (Point { x: 1 }, 2) == t { 0 }",
2939 "if { var p = Point { x: 1 }\n p.ok } { 0 }",
2940 "while v.has(Point { x: 1 }) { 0 }",
2941 "for q in near(Origin { x: 0 }) { 0 }",
2942 "match f(Point { x: 1 }) { A => 1 }",
2943 ] {
2944 let out = parse_text(src);
2945 assert!(out.diagnostics.is_empty(), "{src}: {:?}", out.diagnostics);
2946 assert!(
2947 construct_names(&out.tree).contains(&SyntaxKind::RECORD_LIT_EXPR),
2948 "{src}: the bracketed record literal was suppressed"
2949 );
2950 }
2951 }
2952
2953 /// A match arm body resets it at every depth, not just at the top: the arm's
2954 /// own blocks and closures allow record literals too.
2955 #[test]
2956 fn a_match_arm_allows_a_record_literal_at_any_depth() {
2957 for src in [
2958 "match x { A => { Point { x: 1 } } }",
2959 "match x { A => |q| Point { x: 1 } }",
2960 "match x { A => if c { Point { x: 1 } } else { q } }",
2961 ] {
2962 let out = parse_text(src);
2963 assert!(out.diagnostics.is_empty(), "{src}: {:?}", out.diagnostics);
2964 assert!(
2965 construct_names(&out.tree).contains(&SyntaxKind::RECORD_LIT_EXPR),
2966 "{src}: the arm body suppressed its record literal"
2967 );
2968 }
2969 }
2970
2971 /// …and the suppression still does the job it exists for, in all four heads
2972 /// and through the operands of the expression they own.
2973 #[test]
2974 fn a_keyword_head_still_claims_its_brace_as_a_block() {
2975 for (src, body) in [
2976 ("if p { 0 }", SyntaxKind::IF_EXPR),
2977 ("if a == p { 0 }", SyntaxKind::IF_EXPR),
2978 ("if !p { 0 }", SyntaxKind::IF_EXPR),
2979 ("while p { 0 }", SyntaxKind::WHILE_EXPR),
2980 ("for q in ps { 0 }", SyntaxKind::FOR_EXPR),
2981 ("match p { A => 1 }", SyntaxKind::MATCH_EXPR),
2982 ] {
2983 let out = parse_text(src);
2984 assert!(out.diagnostics.is_empty(), "{src}: {:?}", out.diagnostics);
2985 let kinds = construct_names(&out.tree);
2986 assert!(kinds.contains(&body), "{src}: expected a {body:?}");
2987 assert!(
2988 !kinds.contains(&SyntaxKind::RECORD_LIT_EXPR),
2989 "{src}: the head's brace was eaten as a record body"
2990 );
2991 }
2992 }
2993
2994 // --- the headless record literal `{ x: 1 }` (§5.6, ADR-152) -------------
2995
2996 /// A `{` where an expression must begin is a record literal when a block
2997 /// could not be what follows: a name and a `:`, or a name and a `,`.
2998 #[test]
2999 fn a_brace_a_block_cannot_explain_is_a_record_literal() {
3000 for src in [
3001 "var p = { x: 1 }",
3002 "var p = { x: 1, y: 2 }",
3003 "var p = { x: 1, }",
3004 "var p = { x, y }",
3005 "var p = { x, y: 2 }",
3006 "var p = { x: 1, y }",
3007 "var p = { pos: { x: 1 }, n: 2 }",
3008 "f({ x: 1 })",
3009 "var vs = [{ x: 1 }, { x: 2 }]",
3010 "var f = |q| { x: q }",
3011 "out({ x: 1 }.x)",
3012 ] {
3013 let out = parse_text(src);
3014 assert!(out.diagnostics.is_empty(), "{src}: {:?}", out.diagnostics);
3015 assert!(
3016 construct_names(&out.tree).contains(&SyntaxKind::RECORD_LIT_EXPR),
3017 "{src}: read as a block"
3018 );
3019 }
3020 }
3021
3022 /// …and everything else at that position is still the block it was.
3023 ///
3024 /// `{ x }` is the case the rule cannot have both ways — a block whose value
3025 /// is `x`, and a one-field punned literal, are the same six characters — and
3026 /// the block had the spelling first. `{ x:bp }` is the other: `:bp` is a
3027 /// marker on the statement `x`, told from the field `x: bp` by the same
3028 /// adjacency that tells `min=` from `min =`.
3029 #[test]
3030 fn a_brace_a_block_can_explain_is_still_a_block() {
3031 for src in [
3032 "var p = { x }",
3033 "var p = { }",
3034 "var p = { x\n y }",
3035 "var p = { f(1) }",
3036 "var p = { x:bp }",
3037 "var p = { var t = 1\n t }",
3038 ] {
3039 let out = parse_text(src);
3040 assert!(out.diagnostics.is_empty(), "{src}: {:?}", out.diagnostics);
3041 let kinds = construct_names(&out.tree);
3042 assert!(kinds.contains(&SyntaxKind::BLOCK_EXPR), "{src}: no block");
3043 assert!(
3044 !kinds.contains(&SyntaxKind::RECORD_LIT_EXPR),
3045 "{src}: the block was eaten as a record literal"
3046 );
3047 }
3048 }
3049
3050 /// The marker rule is adjacency and only adjacency, so the spacing decides
3051 /// — and both spellings are things somebody means.
3052 #[test]
3053 fn a_space_after_the_colon_is_a_field_and_not_a_marker() {
3054 let marker = parse_text("var p = { x:bp }");
3055 assert!(marker.diagnostics.is_empty(), "{:?}", marker.diagnostics);
3056 assert!(construct_names(&marker.tree).contains(&SyntaxKind::BREAKPOINT));
3057
3058 let field = parse_text("var p = { x: bp }");
3059 assert!(field.diagnostics.is_empty(), "{:?}", field.diagnostics);
3060 let kinds = construct_names(&field.tree);
3061 assert!(kinds.contains(&SyntaxKind::RECORD_LIT_EXPR));
3062 assert!(
3063 !kinds.contains(&SyntaxKind::BREAKPOINT),
3064 "`: bp` with a space is a field whose value is the binding `bp`"
3065 );
3066 }
3067
3068 /// **A keyword head does not suppress it**, and does not need to.
3069 ///
3070 /// What [`StructLit`] suppression protects is `p { … }` — a *name* followed
3071 /// by the brace that could be the keyword's block (ADR-050). A `{` where an
3072 /// operand is still required cannot be that block: the block comes after a
3073 /// complete head, so a brace at the head's start has nothing to be confused
3074 /// with.
3075 #[test]
3076 fn a_keyword_head_may_open_with_a_record_literal() {
3077 for src in [
3078 "if { hit: true }.hit { 0 }",
3079 "while { n: 1 }.n == 1 { 0 }",
3080 "for q in { xs: ps }.xs { 0 }",
3081 "match { tag: t }.tag { A => 1 }",
3082 ] {
3083 let out = parse_text(src);
3084 assert!(out.diagnostics.is_empty(), "{src}: {:?}", out.diagnostics);
3085 assert!(
3086 construct_names(&out.tree).contains(&SyntaxKind::RECORD_LIT_EXPR),
3087 "{src}: the head's own literal was read as a block"
3088 );
3089 }
3090 }
3091
3092 /// An anonymous literal is the same node as a headed one, with the head
3093 /// absent — which is what `RecordLitExpr::name()` answers `None` from.
3094 #[test]
3095 fn an_anonymous_literal_has_no_path_child() {
3096 let anon = dump("var p = { x: 1 }");
3097 let headed = dump("var p = Point { x: 1 }");
3098 assert!(anon.contains("RECORD_LIT_EXPR"), "{anon}");
3099 assert!(anon.contains("FIELD_LIST"), "{anon}");
3100 assert!(
3101 !anon.contains("PATH_EXPR"),
3102 "an anonymous literal names nothing: {anon}"
3103 );
3104 assert!(headed.contains("PATH_EXPR"), "{headed}");
3105 }
3106
3107 // --- Pratt precedence ---
3108
3109 #[test]
3110 fn arithmetic_is_left_associative() {
3111 // 1 + 2 + 3 should nest left: ((1 + 2) + 3).
3112 let out = parse_text("1 + 2 + 3");
3113 assert!(out.diagnostics.is_empty(), "{:?}", out.diagnostics);
3114 let tree = dump("1 + 2 + 3");
3115 insta::assert_snapshot!(tree, @r#"
3116 SOURCE_FILE@0..9
3117 EXPR_STMT@0..9
3118 BIN_EXPR@0..9
3119 BIN_EXPR@0..5
3120 LITERAL@0..1
3121 IntLit "1"@0..1
3122 Whitespace " "@1..2
3123 PLUS "+"@2..3
3124 Whitespace " "@3..4
3125 LITERAL@4..5
3126 IntLit "2"@4..5
3127 Whitespace " "@5..6
3128 PLUS "+"@6..7
3129 Whitespace " "@7..8
3130 LITERAL@8..9
3131 IntLit "3"@8..9
3132 "#);
3133 }
3134
3135 #[test]
3136 fn multiplication_binds_tighter_than_addition() {
3137 // 1 + 2 * 3 -> 1 + (2 * 3)
3138 let out = parse_text("1 + 2 * 3");
3139 assert!(out.diagnostics.is_empty(), "{:?}", out.diagnostics);
3140 let kinds = construct_names(&out.tree);
3141 assert!(kinds.contains(&SyntaxKind::BIN_EXPR));
3142 }
3143
3144 #[test]
3145 fn parentheses_override_precedence() {
3146 // (1 + 2) * 3 -> the addition is the lhs of the multiply.
3147 let out = parse_text("(1 + 2) * 3");
3148 assert!(out.diagnostics.is_empty(), "{:?}", out.diagnostics);
3149 let kinds = construct_names(&out.tree);
3150 assert!(kinds.contains(&SyntaxKind::PAREN_EXPR));
3151 }
3152
3153 #[test]
3154 fn parses_unary_minus() {
3155 let out = parse_text("-x");
3156 assert!(out.diagnostics.is_empty(), "{:?}", out.diagnostics);
3157 let kinds = construct_names(&out.tree);
3158 assert!(kinds.contains(&SyntaxKind::UNARY_EXPR));
3159 }
3160
3161 // --- Error recovery (§15.2, acceptance: multiple diagnostics, never panic) ---
3162
3163 #[test]
3164 fn malformed_input_produces_multiple_diagnostics_and_never_panics() {
3165 // A file with several distinct problems: missing `=` in a let, a stray
3166 // `)`, and a second broken statement. Recovery must keep going and emit
3167 // at least two P0xx diagnostics.
3168 let src = "var x 1\n )\nvar = \n";
3169 let out = parse_text(src);
3170 let parse_diags: Vec<_> = out
3171 .diagnostics
3172 .iter()
3173 .filter(|d| d.code().category() == DiagnosticCategory::Parse)
3174 .collect();
3175 assert!(
3176 parse_diags.len() >= 2,
3177 "expected >=2 parse diagnostics, got {}: {:?}",
3178 parse_diags.len(),
3179 parse_diags
3180 );
3181 // The tree is always produced.
3182 assert_eq!(out.tree.kind(), SyntaxKind::SOURCE_FILE);
3183 }
3184
3185 #[test]
3186 fn empty_input_parses_to_empty_source_file() {
3187 let out = parse_text("");
3188 assert!(out.diagnostics.is_empty());
3189 assert_eq!(out.tree.kind(), SyntaxKind::SOURCE_FILE);
3190 // No children except possibly trailing trivia (none here).
3191 assert_eq!(out.tree.children_with_tokens().count(), 0);
3192 }
3193
3194 #[test]
3195 fn whitespace_only_input_is_clean() {
3196 let out = parse_text(" \n // just a comment\n ");
3197 assert!(out.diagnostics.is_empty());
3198 }
3199
3200 // --- type annotations + tuples ------------------------------------------
3201
3202 #[test]
3203 fn parses_let_with_tuple_type_annotation() {
3204 let src = "var p: (Int, Int) = (1, 2)";
3205 let out = parse_text(src);
3206 assert!(out.diagnostics.is_empty(), "{:?}", out.diagnostics);
3207 let kinds = construct_names(&out.tree);
3208 assert!(kinds.contains(&SyntaxKind::TUPLE_TYPE));
3209 assert!(kinds.contains(&SyntaxKind::TUPLE_EXPR));
3210 assert!(kinds.contains(&SyntaxKind::TYPE_REF));
3211 }
3212
3213 #[test]
3214 fn parses_fn_with_full_annotations() {
3215 // Full parameter + return annotations, including a tuple return type.
3216 let src = "fn f(a: Int, b: Int) -> (Int, Int) { (a, b) }";
3217 let out = parse_text(src);
3218 assert!(out.diagnostics.is_empty(), "{:?}", out.diagnostics);
3219 let kinds = construct_names(&out.tree);
3220 assert!(kinds.contains(&SyntaxKind::TYPE_REF));
3221 assert!(kinds.contains(&SyntaxKind::TUPLE_TYPE));
3222 }
3223
3224 #[test]
3225 fn parses_higher_order_function_type() {
3226 // `(Int) -> Int` as a parameter type.
3227 let src = "fn apply(f: (Int) -> Int, x: Int) -> Int { f(x) }";
3228 let out = parse_text(src);
3229 assert!(out.diagnostics.is_empty(), "{:?}", out.diagnostics);
3230 let kinds = construct_names(&out.tree);
3231 assert!(kinds.contains(&SyntaxKind::FN_TYPE));
3232 }
3233
3234 #[test]
3235 fn parses_scalar_type_annotation() {
3236 let src = "var x: Int = 1";
3237 let out = parse_text(src);
3238 assert!(out.diagnostics.is_empty(), "{:?}", out.diagnostics);
3239 let kinds = construct_names(&out.tree);
3240 assert!(kinds.contains(&SyntaxKind::TYPE_REF));
3241 }
3242
3243 #[test]
3244 fn tuple_expression_distinguishes_from_paren() {
3245 // Single-element paren stays PAREN_EXPR; two-element is TUPLE_EXPR.
3246 let single = construct_names(&parse_text("(1)").tree);
3247 assert!(single.contains(&SyntaxKind::PAREN_EXPR));
3248 assert!(!single.contains(&SyntaxKind::TUPLE_EXPR));
3249
3250 let pair = construct_names(&parse_text("(1, 2)").tree);
3251 assert!(pair.contains(&SyntaxKind::TUPLE_EXPR));
3252 assert!(!pair.contains(&SyntaxKind::PAREN_EXPR));
3253 }
3254
3255 /// **A tuple has two elements or more** (§4.4), so `(1,)` is refused *here*,
3256 /// at the comma — a one-element `TUPLE_EXPR` is a shape `TupleElems` cannot
3257 /// represent, so typing and lowering would disagree about the node.
3258 ///
3259 /// The node recovers as `PAREN_EXPR`, the grouping the author most likely
3260 /// meant, so nothing downstream sees the shape that does not exist.
3261 #[test]
3262 fn a_one_element_tuple_is_refused_at_the_comma() {
3263 let parsed = parse_text("var t = (1,)\n");
3264 assert_eq!(
3265 parsed.diagnostics.len(),
3266 1,
3267 "one report, at the comma: {:?}",
3268 parsed.diagnostics
3269 );
3270 assert!(
3271 parsed.diagnostics[0].message().contains("two elements"),
3272 "{}",
3273 parsed.diagnostics[0].message()
3274 );
3275 let kinds = construct_names(&parsed.tree);
3276 assert!(kinds.contains(&SyntaxKind::PAREN_EXPR));
3277 assert!(!kinds.contains(&SyntaxKind::TUPLE_EXPR));
3278
3279 // A trailing comma at an arity the type *has* is punctuation, untouched.
3280 let trailing = parse_text("var t = (1, 2,)\n");
3281 assert!(
3282 trailing.diagnostics.is_empty(),
3283 "{:?}",
3284 trailing.diagnostics
3285 );
3286 assert!(construct_names(&trailing.tree).contains(&SyntaxKind::TUPLE_EXPR));
3287
3288 // The same rule in type position.
3289 let annotated = parse_text("var t: (Int,) = 1\n");
3290 assert_eq!(
3291 annotated.diagnostics.len(),
3292 1,
3293 "{:?}",
3294 annotated.diagnostics
3295 );
3296 assert!(!construct_names(&annotated.tree).contains(&SyntaxKind::TUPLE_TYPE));
3297 assert!(
3298 parse_text("var t: (Int, Text,) = (1, \"a\")\n")
3299 .diagnostics
3300 .is_empty()
3301 );
3302 }
3303
3304 #[test]
3305 fn tuple_expression_snapshot() {
3306 insta::assert_snapshot!(dump("(1, 2)"), @r#"
3307 SOURCE_FILE@0..6
3308 EXPR_STMT@0..6
3309 TUPLE_EXPR@0..6
3310 L_PAREN "("@0..1
3311 LITERAL@1..2
3312 IntLit "1"@1..2
3313 COMMA ","@2..3
3314 Whitespace " "@3..4
3315 LITERAL@4..5
3316 IntLit "2"@4..5
3317 R_PAREN ")"@5..6
3318 "#);
3319 }
3320
3321 #[test]
3322 fn function_type_right_associative() {
3323 // `A -> B -> C` parses as `A -> (B -> C)`: the outer FN_TYPE's result is
3324 // itself an FN_TYPE.
3325 let src = "var f: Int -> Text -> Bool = panic";
3326 let out = parse_text(src);
3327 assert!(out.diagnostics.is_empty(), "{:?}", out.diagnostics);
3328 let kinds = construct_names(&out.tree);
3329 // Two FN_TYPE nodes for the nested arrow.
3330 let fn_type_count = kinds.iter().filter(|k| **k == SyntaxKind::FN_TYPE).count();
3331 assert_eq!(fn_type_count, 2);
3332 }
3333
3334 // --- input-parser expression syntax (§7) ---
3335
3336 #[test]
3337 fn parses_read_atomic() {
3338 let out = parse_text("var v = read int");
3339 assert!(out.diagnostics.is_empty(), "{:?}", out.diagnostics);
3340 let kinds = construct_names(&out.tree);
3341 assert!(kinds.contains(&SyntaxKind::READ_EXPR));
3342 assert!(kinds.contains(&SyntaxKind::PARSER_EXPR));
3343 assert!(kinds.contains(&SyntaxKind::PARSER_ATOM));
3344 }
3345
3346 #[test]
3347 fn parses_read_lines_of_int() {
3348 let out = parse_text("var v = read lines(int)");
3349 assert!(out.diagnostics.is_empty(), "{:?}", out.diagnostics);
3350 let kinds = construct_names(&out.tree);
3351 assert!(kinds.contains(&SyntaxKind::READ_EXPR));
3352 assert!(kinds.contains(&SyntaxKind::PARSER_CALL));
3353 // Nested atom inside the call's arg list.
3354 assert!(kinds.contains(&SyntaxKind::PARSER_ATOM));
3355 assert!(kinds.contains(&SyntaxKind::PARSER_ARG_LIST));
3356 }
3357
3358 #[test]
3359 fn parses_read_nested_constructors() {
3360 // sections(lines(csv(int))) — whitespace outside backticks is
3361 // insignificant (§7.1 acceptance criterion 5).
3362 let out = parse_text("var v = read sections( lines( csv( int ) ) )");
3363 assert!(out.diagnostics.is_empty(), "{:?}", out.diagnostics);
3364 let kinds = construct_names(&out.tree);
3365 // Three nested PARSER_CALL nodes (sections, lines, csv).
3366 let call_count = kinds
3367 .iter()
3368 .filter(|k| **k == SyntaxKind::PARSER_CALL)
3369 .count();
3370 assert_eq!(call_count, 3);
3371 }
3372
3373 #[test]
3374 fn parses_read_template() {
3375 let out = parse_text("var v = read lines(`{x:int},{y:int}`)");
3376 assert!(out.diagnostics.is_empty(), "{:?}", out.diagnostics);
3377 let kinds = construct_names(&out.tree);
3378 assert!(kinds.contains(&SyntaxKind::READ_EXPR));
3379 assert!(kinds.contains(&SyntaxKind::PARSER_CALL));
3380 assert!(kinds.contains(&SyntaxKind::PARSER_TEMPLATE));
3381 assert!(kinds.contains(&SyntaxKind::BacktickTemplate));
3382 }
3383
3384 #[test]
3385 fn parses_read_grid() {
3386 let out = parse_text("solve(read grid(char))");
3387 assert!(out.diagnostics.is_empty(), "{:?}", out.diagnostics);
3388 let kinds = construct_names(&out.tree);
3389 assert!(kinds.contains(&SyntaxKind::READ_EXPR));
3390 assert!(kinds.contains(&SyntaxKind::PARSER_CALL));
3391 }
3392
3393 #[test]
3394 fn parses_read_sep_with_string_literal() {
3395 let out = parse_text(r#"var v = read sep(" -> ", word)"#);
3396 assert!(out.diagnostics.is_empty(), "{:?}", out.diagnostics);
3397 let kinds = construct_names(&out.tree);
3398 assert!(kinds.contains(&SyntaxKind::READ_EXPR));
3399 assert!(kinds.contains(&SyntaxKind::PARSER_CALL));
3400 // The string-literal separator is inside the arg list.
3401 assert!(kinds.contains(&SyntaxKind::TextLit));
3402 }
3403
3404 // --- named arguments in parser constructor calls (§7.5) ------------------
3405
3406 #[test]
3407 fn parses_named_args_in_sections() {
3408 // heterogeneous `sections(rules: ..., updates: ...)` — two named args.
3409 let out = parse_text("var v = read sections(rules: lines(int), updates: lines(int))");
3410 assert!(out.diagnostics.is_empty(), "{:?}", out.diagnostics);
3411 let kinds = construct_names(&out.tree);
3412 assert!(kinds.contains(&SyntaxKind::PARSER_NAMED_ARG));
3413 // Two named args.
3414 let named_count = kinds
3415 .iter()
3416 .filter(|k| **k == SyntaxKind::PARSER_NAMED_ARG)
3417 .count();
3418 assert_eq!(named_count, 2);
3419 }
3420
3421 #[test]
3422 fn parses_repeated_tail_in_sections() {
3423 // The `repeated(...)` tail marker of named sections.
3424 let out =
3425 parse_text("var v = read sections(draws: csv(int), boards: repeated(matrix(int)))");
3426 assert!(out.diagnostics.is_empty(), "{:?}", out.diagnostics);
3427 let kinds = construct_names(&out.tree);
3428 assert!(kinds.contains(&SyntaxKind::PARSER_NAMED_ARG));
3429 }
3430
3431 /// **A count is a positional literal, and the grammar has a shape for it.**
3432 /// The `N` of `repeated(P, N)` is an integer in positional position; the
3433 /// keyword-value path that also accepts one (`fill: 0`) is reachable only
3434 /// after a `name:`, so the positional case needs its own arm.
3435 #[test]
3436 fn a_parser_call_takes_a_positional_count_literal() {
3437 let out = parse_text("var v = read sections(a: repeated(lines(int), 2), b: lines(int))");
3438 assert!(out.diagnostics.is_empty(), "{:?}", out.diagnostics);
3439 let kinds = construct_names(&out.tree);
3440 assert!(
3441 !kinds.contains(&SyntaxKind::PARSE_ERROR),
3442 "a count argument must not be an error node"
3443 );
3444 assert!(
3445 kinds.contains(&SyntaxKind::LITERAL),
3446 "the count is a LITERAL child of the argument list"
3447 );
3448 }
3449
3450 /// A negative count is one `LITERAL`, not a `-` the parser complains about
3451 /// separately: the diagnostic a reader needs is about the *count*, and only
3452 /// a node that holds the whole thing can carry it there.
3453 #[test]
3454 fn a_negative_count_is_one_literal_not_a_parse_error() {
3455 let out = parse_text("var v = read sections(a: repeated(int, -1))");
3456 assert!(out.diagnostics.is_empty(), "{:?}", out.diagnostics);
3457 let kinds = construct_names(&out.tree);
3458 assert!(!kinds.contains(&SyntaxKind::PARSE_ERROR));
3459 assert_eq!(
3460 kinds.iter().filter(|k| **k == SyntaxKind::LITERAL).count(),
3461 1,
3462 "`-1` is one literal node, not two"
3463 );
3464 }
3465
3466 #[test]
3467 fn parses_keyword_arg_in_chars() {
3468 // `chars(one_of(...), skip: whitespace)` — a positional arg followed by
3469 // a named keyword arg.
3470 let out = parse_text("var v = read chars(one_of(\"LR\"), skip: whitespace)");
3471 assert!(out.diagnostics.is_empty(), "{:?}", out.diagnostics);
3472 let kinds = construct_names(&out.tree);
3473 assert!(kinds.contains(&SyntaxKind::PARSER_NAMED_ARG));
3474 }
3475
3476 #[test]
3477 fn named_arg_does_not_shadow_constructor_call() {
3478 // A constructor call argument (`lines(int)`) has `(` at position 1, so
3479 // it is NOT mistaken for a named arg. Only `ident:` is.
3480 let out = parse_text("var v = read sections(lines(int))");
3481 assert!(out.diagnostics.is_empty(), "{:?}", out.diagnostics);
3482 let kinds = construct_names(&out.tree);
3483 assert!(
3484 !kinds.contains(&SyntaxKind::PARSER_NAMED_ARG),
3485 "positional constructor-call arg must not parse as a named arg"
3486 );
3487 }
3488
3489 #[test]
3490 fn parses_parse_call() {
3491 let out = parse_text("var v = parse(sample, lines(int))");
3492 assert!(out.diagnostics.is_empty(), "{:?}", out.diagnostics);
3493 let kinds = construct_names(&out.tree);
3494 assert!(kinds.contains(&SyntaxKind::PARSE_EXPR));
3495 assert!(kinds.contains(&SyntaxKind::PARSER_CALL));
3496 }
3497
3498 #[test]
3499 fn parser_expression_whitespace_is_insignificant() {
3500 // The same parser expression laid out differently must produce the same
3501 // tree shape (modulo trivia). §7.1 acceptance criterion 5.
3502 let a = construct_names(&parse_text("read lines(int)").tree);
3503 let b = construct_names(&parse_text("read\n lines(\n int\n )").tree);
3504 // Filter out trivia (whitespace) for the comparison.
3505 let filt = |ks: &[SyntaxKind]| -> Vec<SyntaxKind> {
3506 ks.iter().filter(|k| !k.is_trivia()).copied().collect()
3507 };
3508 assert_eq!(filt(&a), filt(&b));
3509 }
3510 /// `&&` is one token and one infix operator, and its precedence is the two
3511 /// facts that matter: tighter than `||`, looser than comparison.
3512 ///
3513 /// The whole precedence table is asserted below rather than just `&&`'s row,
3514 /// because a binding power is only meaningful relative to the others.
3515 #[test]
3516 fn logical_and_binds_tighter_than_or_and_looser_than_comparison() {
3517 // One token, not two `AMP`s — max-munch, as for `||`.
3518 let out = parse_text("var b = x && y");
3519 assert!(out.diagnostics.is_empty(), "{:?}", out.diagnostics);
3520 let kinds = construct_names(&out.tree);
3521 assert!(kinds.contains(&SyntaxKind::AMP2));
3522 assert!(!kinds.contains(&SyntaxKind::AMP), "`&&` is never two `&`s");
3523
3524 // `a || b && c` is `a || (b && c)`: the outer BIN_EXPR is the `||`.
3525 assert_eq!(
3526 shape("var r = a || b && c"),
3527 shape("var r = a || (b && c)"),
3528 "&& binds tighter than ||"
3529 );
3530 assert_ne!(shape("var r = a || b && c"), shape("var r = (a || b) && c"));
3531
3532 // `a == b && c == d` is `(a == b) && (c == d)` — §3.3's own shape, and
3533 // the reason `&&` must be looser than comparison.
3534 assert_eq!(
3535 shape("var r = a == b && c == d"),
3536 shape("var r = (a == b) && (c == d)")
3537 );
3538
3539 // `!x && y` is `(!x) && y`: prefix stays above every infix operator.
3540 // §3.3 writes `!diagonals && …`.
3541 assert_eq!(shape("var r = !x && y"), shape("var r = (!x) && y"));
3542 assert_ne!(shape("var r = !x && y"), shape("var r = !(x && y)"));
3543
3544 // The rest of the table: arithmetic binds tighter than comparison, `*`
3545 // than `+`, and unary minus than `*`.
3546 assert_eq!(shape("var r = a + b < c"), shape("var r = (a + b) < c"));
3547 assert_eq!(shape("var r = a + b * c"), shape("var r = a + (b * c)"));
3548 assert_eq!(shape("var r = -a * b"), shape("var r = (-a) * b"));
3549 // …and `..` binds looser than the arithmetic in its bounds (ADR-059).
3550 assert_eq!(shape("var r = 0..n - 1"), shape("var r = 0..(n - 1)"));
3551 assert_ne!(shape("var r = 0..n - 1"), shape("var r = (0..n) - 1"));
3552 }
3553
3554 /// **A trailing comma closes a list; it does not open another element.**
3555 ///
3556 /// Asserted over every comma-separated list in the grammar rather than over
3557 /// the argument list alone: accepting a trailing comma is a property of the
3558 /// grammar, and each list loop is a separate place for it to be missing.
3559 #[test]
3560 fn a_trailing_comma_closes_a_list_rather_than_opening_an_element() {
3561 // The list, and the same list without the trailing comma: identical trees
3562 // once the comma token is out of the way, which is what "closes it" means.
3563 for (with, without) in [
3564 // Call arguments, in §3.3's own layout.
3565 (
3566 "var d = max(\n abs(a),\n abs(b),\n)",
3567 "var d = max(abs(a), abs(b))",
3568 ),
3569 ("var x = f(1,)", "var x = f(1)"),
3570 // Tuple literal, collection type arguments.
3571 ("var t = (1, 2,)", "var t = (1, 2)"),
3572 ("var v: Vec[Int,] = Vec()", "var v: Vec[Int] = Vec()"),
3573 (
3574 "var m: Map[Text, Int,] = Map()",
3575 "var m: Map[Text, Int] = Map()",
3576 ),
3577 // Declarations: struct fields, enum variants, an enum payload.
3578 (
3579 "struct P { x: Int, y: Int, }",
3580 "struct P { x: Int, y: Int }",
3581 ),
3582 ("enum E { A, B, }", "enum E { A, B }"),
3583 ("enum E { B(Int, Int,), }", "enum E { B(Int, Int) }"),
3584 // Function and closure parameters.
3585 (
3586 "fn add(a: Int, b: Int,) -> Int { a + b }",
3587 "fn add(a: Int, b: Int) -> Int { a + b }",
3588 ),
3589 ("var f = |a, b,| a + b", "var f = |a, b| a + b"),
3590 // Record literal fields, and match arms.
3591 (
3592 "struct P { x: Int }\nvar p = P { x: 1, }",
3593 "struct P { x: Int }\nvar p = P { x: 1 }",
3594 ),
3595 (
3596 "var r = match n { 1 => 1, _ => 0, }",
3597 "var r = match n { 1 => 1, _ => 0 }",
3598 ),
3599 // Subscript indices.
3600 ("var c = grid[x, y,]", "var c = grid[x, y]"),
3601 ] {
3602 let out = parse_text(with);
3603 assert!(out.diagnostics.is_empty(), "{with}: {:?}", out.diagnostics);
3604 let filt = |t: &str| -> Vec<SyntaxKind> {
3605 construct_names(&parse_text(t).tree)
3606 .into_iter()
3607 .filter(|k| !k.is_trivia() && *k != SyntaxKind::COMMA)
3608 .collect()
3609 };
3610 assert_eq!(filt(with), filt(without), "{with}");
3611 }
3612
3613 // …and a *leading* or doubled comma is still a mistake: the rule is that
3614 // a comma may precede the closer, not that commas are optional.
3615 for bad in ["var x = f(1,,2)", "var x = f(,1)", "var t = (1,,2)"] {
3616 let out = parse_text(bad);
3617 assert!(!out.diagnostics.is_empty(), "{bad} must still report");
3618 }
3619 }
3620
3621 /// **A subscript is a postfix form like a call**, so it chains with the
3622 /// other two in any order — and a statement whose target is one is an
3623 /// assignment.
3624 #[test]
3625 fn a_subscript_is_a_postfix_form_and_can_be_an_assignment_target() {
3626 // Reads, at both arities, and chained with the other postfix forms in
3627 // every order — which is what one loop over all three buys.
3628 for src in [
3629 "var v = m[key]",
3630 "var c = grid[x, y]",
3631 "var n = m[a][b]",
3632 "var n = f(x)[0]",
3633 "var n = grid[x, y].len()",
3634 "var n = v[0].0",
3635 "var n = rows[i].len() + 1",
3636 "var n = m[k](7)",
3637 ] {
3638 let out = parse_text(src);
3639 assert!(out.diagnostics.is_empty(), "{src}: {:?}", out.diagnostics);
3640 }
3641
3642 // A subscript wraps the *whole* preceding expression, so `f(x)[0]` is one
3643 // statement and not two.
3644 let out = parse_text("var n = f(x)[0]");
3645 assert_eq!(
3646 construct_names(&out.tree)
3647 .iter()
3648 .filter(|k| **k == SyntaxKind::INDEX_EXPR)
3649 .count(),
3650 1
3651 );
3652
3653 // Assignment through a subscript, in every operator the grammar has.
3654 for src in [
3655 "m[key] = 1",
3656 "counts[key] += 1",
3657 "m[key] -= 1",
3658 "m[key] *= 2",
3659 "m[key] /= 2",
3660 "m[key] %= 2",
3661 "grid[x, y] = 7",
3662 "m[a][b] += 1",
3663 ] {
3664 let out = parse_text(src);
3665 assert!(out.diagnostics.is_empty(), "{src}: {:?}", out.diagnostics);
3666 assert_eq!(
3667 construct_names(&out.tree)
3668 .iter()
3669 .filter(|k| **k == SyntaxKind::PLACE_ASSIGN_STMT)
3670 .count(),
3671 1,
3672 "{src} is one assignment statement"
3673 );
3674 }
3675
3676 // A bare name target is an `ASSIGN_STMT` — a different node, with a
3677 // *token* target — so the two paths stay distinct.
3678 let out = parse_text("x += 1");
3679 let kinds = construct_names(&out.tree);
3680 assert!(kinds.contains(&SyntaxKind::ASSIGN_STMT), "{kinds:?}");
3681 assert!(!kinds.contains(&SyntaxKind::PLACE_ASSIGN_STMT), "{kinds:?}");
3682
3683 // Whether a target is a place is inference's answer and not the
3684 // parser's, so both kinds parse the same way: `p.x = 3` is a field store
3685 // (§4.5) and `f() = 3` names no storage at all (`Y021`), and the parser
3686 // wraps each of them without asking. This is the assertion that would
3687 // fail if the wrap were made conditional on the target's shape.
3688 for src in ["f() = 3", "p.x = 3", "v.len() += 1"] {
3689 let out = parse_text(src);
3690 assert!(out.diagnostics.is_empty(), "{src}: {:?}", out.diagnostics);
3691 assert_eq!(
3692 construct_names(&out.tree)
3693 .iter()
3694 .filter(|k| **k == SyntaxKind::PLACE_ASSIGN_STMT)
3695 .count(),
3696 1,
3697 "{src}"
3698 );
3699 }
3700
3701 // A `[` after a line break does not continue the expression before it:
3702 // a list literal begins with one, so the tie is broken by position the
3703 // way it is for `(`.
3704 let out = parse_text(
3705 "var n = m
3706[key]",
3707 );
3708 assert!(out.diagnostics.is_empty(), "{:?}", out.diagnostics);
3709 assert_eq!(
3710 out.tree.children().count(),
3711 2,
3712 "a line-leading `[` starts a list rather than subscripting"
3713 );
3714 // …and a `[` on the same line still subscripts, which is every subscript
3715 // any program writes.
3716 let out = parse_text("var n = m[key]");
3717 assert!(out.diagnostics.is_empty(), "{:?}", out.diagnostics);
3718 assert_eq!(out.tree.children().count(), 1);
3719
3720 // An unclosed subscript is reported rather than swallowing the rest.
3721 for bad in ["var v = m[key", "var v = m[]", "m[key] ="] {
3722 let out = parse_text(bad);
3723 assert!(!out.diagnostics.is_empty(), "{bad} must report");
3724 }
3725 }
3726
3727 /// **A type constructor's name followed by `[` opens a type-argument list;
3728 /// every other name followed by `[` is a subscript.**
3729 ///
3730 /// The two forms are the same two characters, and their contents cannot
3731 /// break the tie either (`Int` is a legal expression, `(Int, Int)` a legal
3732 /// tuple), so the name in front is the whole rule and this is where it is
3733 /// pinned.
3734 #[test]
3735 fn a_type_constructors_brackets_are_type_arguments_and_every_other_names_are_a_subscript() {
3736 let count = |text: &str, kind: SyntaxKind| -> usize {
3737 let out = parse_text(text);
3738 assert!(out.diagnostics.is_empty(), "{text}: {:?}", out.diagnostics);
3739 construct_names(&out.tree)
3740 .into_iter()
3741 .filter(|k| *k == kind)
3742 .count()
3743 };
3744
3745 // §3.3's own spelling, and the shapes around it.
3746 for src in [
3747 "var c = Counter[(Int, Int)]()",
3748 "var v = Vec[Int]()",
3749 "var m = Map[Text, Int]()",
3750 "var g = Grid[Vec[Int]]()",
3751 // A trailing comma closes this list too.
3752 "var m = Map[Text, Int,]()",
3753 ] {
3754 assert_eq!(count(src, SyntaxKind::TYPE_ARG_LIST), 1, "{src}");
3755 assert_eq!(count(src, SyntaxKind::INDEX_EXPR), 0, "{src}");
3756 assert_eq!(count(src, SyntaxKind::CALL_EXPR), 1, "{src}");
3757 }
3758
3759 // …and every other name's brackets are still a subscript, including a
3760 // subscript **followed by a call**, which is what a "brackets before `(`
3761 // are type arguments" rule would have broken.
3762 for src in [
3763 "var v = m[key]",
3764 "var v = m[key](7)",
3765 "var v = counter[key]",
3766 "var v = grid[x, y]",
3767 ] {
3768 assert_eq!(count(src, SyntaxKind::INDEX_EXPR), 1, "{src}");
3769 assert_eq!(count(src, SyntaxKind::TYPE_ARG_LIST), 0, "{src}");
3770 }
3771
3772 // A type-argument list belongs to a *call*, so a bare one reports rather
3773 // than parsing as a type in value position. An empty one reports too: a
3774 // constructor with no arguments is spelled `Counter()`.
3775 for bad in [
3776 "var c = Counter[Int]",
3777 "var c = Counter[]()",
3778 "var c = Counter[Int",
3779 "var c = Vec[Int] + 1",
3780 ] {
3781 let out = parse_text(bad);
3782 assert!(!out.diagnostics.is_empty(), "{bad} must report");
3783 }
3784 }
3785
3786 /// A `[` that **begins** an expression opens a list literal; a `[` that
3787 /// continues one is still a subscript.
3788 ///
3789 /// The two spellings are the same two characters, and — as with a
3790 /// type-argument list and a `(` — their contents cannot break the tie: `[k]`
3791 /// is a legal list and a legal subscript. Position is the whole rule, and
3792 /// this is where it is pinned.
3793 #[test]
3794 fn a_bracket_that_begins_an_expression_is_a_list_and_one_that_continues_it_is_a_subscript() {
3795 let count = |src: &str, kind: SyntaxKind| -> usize {
3796 let out = parse_text(src);
3797 assert!(out.diagnostics.is_empty(), "{src}: {:?}", out.diagnostics);
3798 construct_names(&out.tree)
3799 .into_iter()
3800 .filter(|k| *k == kind)
3801 .count()
3802 };
3803
3804 // Every position an expression can begin in: a binding, an argument, a
3805 // `for` iterable, a return value, an element of another list.
3806 for src in [
3807 "var v = [1, 2, 3]",
3808 "var v = []",
3809 "var v = [1]",
3810 // A trailing comma closes this list too.
3811 "var v = [1, 2,]",
3812 "out([1, 2])",
3813 "for x in [1, 2] { out(x) }",
3814 "fn f() { return [1] }",
3815 ] {
3816 assert!(count(src, SyntaxKind::LIST_EXPR) >= 1, "{src}");
3817 assert_eq!(count(src, SyntaxKind::INDEX_EXPR), 0, "{src}");
3818 }
3819
3820 // One node kind at every arity, including zero: nothing about a list
3821 // changes at two the way a paren becomes a tuple there.
3822 for (src, want) in [
3823 ("var v = []", 1),
3824 ("var v = [1]", 1),
3825 ("var v = [1, 2]", 1),
3826 ("var v = [[1], [2, 3]]", 3),
3827 ] {
3828 assert_eq!(count(src, SyntaxKind::LIST_EXPR), want, "{src}");
3829 }
3830
3831 // …and a `[` that continues an expression is a subscript, including one
3832 // that indexes a list literal.
3833 for (src, want) in [
3834 ("var v = m[key]", 1),
3835 ("var v = grid[x, y]", 1),
3836 // Chained: each link continues the whole expression before it.
3837 ("var v = m[k][j]", 2),
3838 // A list literal is itself something a subscript can continue.
3839 ("var v = [1, 2][0]", 1),
3840 ("var v = f()[0]", 1),
3841 ] {
3842 assert_eq!(count(src, SyntaxKind::INDEX_EXPR), want, "{src}");
3843 }
3844 assert_eq!(count("var v = [1, 2][0]", SyntaxKind::LIST_EXPR), 1);
3845
3846 // An empty subscript is an error: a subscript selects *something*, where
3847 // a list may hold nothing.
3848 for bad in ["var v = m[]", "var v = [1, 2", "var v = [1 2]"] {
3849 let out = parse_text(bad);
3850 assert!(!out.diagnostics.is_empty(), "{bad} must report");
3851 }
3852 }
3853
3854 /// **A `for` binding is a pattern**, so `for (k, v) in m` takes the pair
3855 /// apart where `for kv in m` could only name it. Destructuring in binding
3856 /// position *is* a pattern, so the header reuses the pattern grammar rather
3857 /// than having one of its own (ADR-066 decision 3).
3858 #[test]
3859 fn a_for_binding_is_a_pattern() {
3860 let count = |src: &str, kind: SyntaxKind| -> usize {
3861 let out = parse_text(src);
3862 assert!(out.diagnostics.is_empty(), "{src}: {:?}", out.diagnostics);
3863 construct_names(&out.tree)
3864 .into_iter()
3865 .filter(|k| *k == kind)
3866 .count()
3867 };
3868
3869 // The shapes, and the count of patterns each holds: the header's own,
3870 // plus one per element or field.
3871 for (src, patterns) in [
3872 ("for x in v { }", 1),
3873 ("for (k, v) in m { }", 3),
3874 ("for (a, (b, c)) in v { }", 5),
3875 ("for P { x, y } in ps { }", 1),
3876 ("for P { at: (x, y) } in ps { }", 4),
3877 ("for _ in v { }", 1),
3878 ] {
3879 assert_eq!(count(src, SyntaxKind::PATTERN), patterns, "{src}");
3880 assert_eq!(count(src, SyntaxKind::FOR_EXPR), 1, "{src}");
3881 }
3882
3883 // The pattern is followed by `in`, never by `{`, so a record pattern's
3884 // brace cannot be read as the loop body — and the iterator keeps its own
3885 // record-literal suppression.
3886 let out = parse_text("for P { x } in near(Origin { x: 0 }) { 0 }");
3887 assert!(out.diagnostics.is_empty(), "{:?}", out.diagnostics);
3888
3889 // A missing `in`, and a missing pattern, both still report.
3890 for bad in ["for x v { }", "for in v { }", "for (x, in v { }"] {
3891 let out = parse_text(bad);
3892 assert!(!out.diagnostics.is_empty(), "{bad} must report");
3893 }
3894 }
3895
3896 /// **`min=` and `max=` are operators exactly where an identifier cannot be
3897 /// one**, and `min` is a name everywhere else.
3898 ///
3899 /// §6.2 writes `distance[key] min= candidate` and `best[key] max= score`.
3900 /// `min` is an `Ident`, so `min=` is two tokens the parser joins by context:
3901 /// a lexer rule that claimed `min=` would take `min` away from every program
3902 /// that calls the prelude helper (ADR-058), which §3.3's own program does.
3903 #[test]
3904 fn an_updating_store_is_an_operator_only_where_a_name_cannot_be() {
3905 let count = |src: &str, kind: SyntaxKind| -> usize {
3906 let out = parse_text(src);
3907 assert!(out.diagnostics.is_empty(), "{src}: {:?}", out.diagnostics);
3908 construct_names(&out.tree)
3909 .into_iter()
3910 .filter(|k| *k == kind)
3911 .count()
3912 };
3913
3914 // §6.2's own two lines, and the shapes around them: a computed index, a
3915 // computed value, and the operator inside a block.
3916 for src in [
3917 "distance[key] min= candidate",
3918 "best[key] max= score",
3919 "d[a + b] min= f(x)",
3920 "fn go() {\n d[k] max= n\n}",
3921 "grid[x, y] min= 3",
3922 ] {
3923 assert_eq!(count(src, SyntaxKind::UPDATE_OP), 1, "{src}");
3924 assert_eq!(count(src, SyntaxKind::PLACE_ASSIGN_STMT), 1, "{src}");
3925 }
3926
3927 // The operator is **adjacent**, as `+=` is: with a space it is an
3928 // identifier followed by `=`, which is two statements run together and
3929 // reports as one.
3930 for spaced in ["d[k] min = 3", "d[k] max = 3"] {
3931 let out = parse_text(spaced);
3932 assert!(!out.diagnostics.is_empty(), "{spaced} must report");
3933 }
3934
3935 // `min` and `max` are ordinary names everywhere else — the whole reason
3936 // the rule is contextual.
3937 for src in [
3938 "var d = min(3, 4)",
3939 "var d = max(abs(a), abs(b))",
3940 "var m = min",
3941 "out(min(1, 2) + max(3, 4))",
3942 // …including as the receiver of a subscript, where the identifier is
3943 // followed by `[` and not by `=`.
3944 "var v = min[0]",
3945 ] {
3946 let out = parse_text(src);
3947 assert!(out.diagnostics.is_empty(), "{src}: {:?}", out.diagnostics);
3948 assert_eq!(count(src, SyntaxKind::UPDATE_OP), 0, "{src}");
3949 }
3950
3951 // `==` is one token by max-munch, so a comparison can never be read as an
3952 // update, and no other identifier gets the rule.
3953 for src in ["var r = d[k] == v", "var r = m[k] == 3"] {
3954 assert_eq!(count(src, SyntaxKind::UPDATE_OP), 0, "{src}");
3955 }
3956 let out = parse_text("d[k] mid= 3");
3957 assert!(
3958 !out.diagnostics.is_empty(),
3959 "only `min` and `max` are operators"
3960 );
3961
3962 // A target that is not a place still *parses*, exactly as `f() = 1`
3963 // does: naming no storage is inference's report and not the parser's.
3964 for src in ["x min= 1", "f() max= 1"] {
3965 let out = parse_text(src);
3966 assert!(out.diagnostics.is_empty(), "{src}: {:?}", out.diagnostics);
3967 assert_eq!(count(src, SyntaxKind::UPDATE_OP), 1, "{src}");
3968 }
3969
3970 // …and a missing value is a mistake, not an empty store.
3971 let out = parse_text("d[k] min=");
3972 assert!(!out.diagnostics.is_empty(), "a value is required");
3973 }
3974
3975 /// §9.8's `:bp` marker rides the same rule an updating store does, at the
3976 /// one other position where an identifier can decide an operator: the end of
3977 /// a statement, where a `:` begins nothing else.
3978 #[test]
3979 fn a_breakpoint_marker_is_a_marker_only_where_a_type_cannot_be() {
3980 let count = |src: &str, kind: SyntaxKind| -> usize {
3981 let out = parse_text(src);
3982 assert!(out.diagnostics.is_empty(), "{src}: {:?}", out.diagnostics);
3983 construct_names(&out.tree)
3984 .into_iter()
3985 .filter(|k| *k == kind)
3986 .count()
3987 };
3988
3989 // Every statement form takes one, and it lands inside that statement's
3990 // own node rather than beside it.
3991 for (src, stmt) in [
3992 ("var a = 1 :bp", SyntaxKind::VAR_STMT),
3993 ("var a: Int = 1 :bp", SyntaxKind::VAR_STMT),
3994 (
3995 "fn f() {\n var a = 1\n a = 2 :bp\n}",
3996 SyntaxKind::ASSIGN_STMT,
3997 ),
3998 ("var m = [1]\nm[0] = 2 :bp", SyntaxKind::PLACE_ASSIGN_STMT),
3999 (
4000 "var m = [1]\nm[0] min= 2 :bp",
4001 SyntaxKind::PLACE_ASSIGN_STMT,
4002 ),
4003 ("out(1) :bp", SyntaxKind::EXPR_STMT),
4004 ("{ }\n:bp", SyntaxKind::EXPR_STMT),
4005 ] {
4006 assert_eq!(count(src, SyntaxKind::BREAKPOINT), 1, "{src}");
4007 assert_eq!(count(src, stmt), 1, "{src}");
4008 }
4009
4010 // The marker is a *child of the statement*, which is what lets lowering
4011 // ask a statement node whether it carries one.
4012 let out = parse_text("var a = 1 :bp");
4013 let var_stmt = out
4014 .tree
4015 .descendants()
4016 .find(|n| n.kind() == SyntaxKind::VAR_STMT)
4017 .expect("a var statement");
4018 assert!(
4019 var_stmt
4020 .children()
4021 .any(|c| c.kind() == SyntaxKind::BREAKPOINT),
4022 "the marker is the statement's child"
4023 );
4024
4025 // Adjacent, exactly as `min=` is: with a space it is a `:` that begins
4026 // nothing, and the statement runs on.
4027 for spaced in ["var a = 1 : bp", "out(1) : bp"] {
4028 let out = parse_text(spaced);
4029 assert!(!out.diagnostics.is_empty(), "{spaced} must report");
4030 }
4031
4032 // `bp` is an ordinary name everywhere else — the whole reason the rule
4033 // is contextual — including as a binding, a call and a type annotation's
4034 // *value* position.
4035 for src in [
4036 "var bp = 1",
4037 "var a = bp",
4038 "fn bp() {\n out(1)\n}",
4039 "var a: Int = 1\nvar bp = a",
4040 // The other `:`s in the grammar are inside declarations, where a
4041 // statement has not ended and this rule is never asked.
4042 "struct P { bp: Int }",
4043 "fn f(bp: Int) -> Int {\n bp\n}",
4044 ] {
4045 let out = parse_text(src);
4046 assert!(out.diagnostics.is_empty(), "{src}: {:?}", out.diagnostics);
4047 assert_eq!(count(src, SyntaxKind::BREAKPOINT), 0, "{src}");
4048 }
4049
4050 // A marker on a nested statement belongs to *that* statement, not to the
4051 // block that contains it: the outer `EXPR_STMT` has no marker child.
4052 let out = parse_text("{\n out(1) :bp\n}");
4053 assert!(out.diagnostics.is_empty(), "{:?}", out.diagnostics);
4054 let outer = out
4055 .tree
4056 .children()
4057 .find(|n| n.kind() == SyntaxKind::EXPR_STMT)
4058 .expect("the block statement");
4059 assert!(
4060 !outer.children().any(|c| c.kind() == SyntaxKind::BREAKPOINT),
4061 "the inner statement's marker is not the outer statement's"
4062 );
4063 }
4064
4065 /// **A declaration's members are separated by a comma or a line break** —
4066 /// which is how §4.5 and §4.6 write their own. Match arms take either
4067 /// separator (D8, ADR-049); struct fields and enum variants are the same
4068 /// rule at the same kind of brace.
4069 #[test]
4070 fn a_declarations_members_take_a_comma_or_a_line_break() {
4071 // The design doc's own text, verbatim, and the comma form beside it: the
4072 // same tree once the comma token is out of the way, which is what "either
4073 // separator" means.
4074 for (breaks, commas) in [
4075 (
4076 "struct Point {\n x: Int\n y: Int\n}",
4077 "struct Point { x: Int, y: Int }",
4078 ),
4079 (
4080 "enum Tile {\n Empty\n Wall\n Number(Int)\n Portal(Text)\n}",
4081 "enum Tile { Empty, Wall, Number(Int), Portal(Text) }",
4082 ),
4083 // Mixed, in both orders — the two separators are interchangeable and
4084 // not two dialects.
4085 (
4086 "struct P {\n x: Int, y: Int\n z: Int\n}",
4087 "struct P { x: Int, y: Int, z: Int }",
4088 ),
4089 ("enum E {\n A, B\n C\n}", "enum E { A, B, C }"),
4090 // …and a trailing comma still closes the list, whichever preceded it.
4091 (
4092 "struct P {\n x: Int\n y: Int,\n}",
4093 "struct P { x: Int, y: Int }",
4094 ),
4095 ("enum E {\n A\n B,\n}", "enum E { A, B }"),
4096 ] {
4097 let out = parse_text(breaks);
4098 assert!(
4099 out.diagnostics.is_empty(),
4100 "{breaks}: {:?}",
4101 out.diagnostics
4102 );
4103 let filt = |t: &str| -> Vec<SyntaxKind> {
4104 construct_names(&parse_text(t).tree)
4105 .into_iter()
4106 .filter(|k| !k.is_trivia() && *k != SyntaxKind::COMMA)
4107 .collect()
4108 };
4109 assert_eq!(filt(breaks), filt(commas), "{breaks}");
4110 }
4111
4112 // The rule is a separator, not "separators are optional": two members on
4113 // one line with neither is still a mistake.
4114 for bad in [
4115 "struct P { x: Int y: Int }",
4116 "enum E { A B }",
4117 "enum E { A(Int) B }",
4118 ] {
4119 let out = parse_text(bad);
4120 assert!(!out.diagnostics.is_empty(), "{bad} must report");
4121 }
4122
4123 // The shapes with no separator to give: an empty declaration and a
4124 // one-member one, on one line and across lines.
4125 for src in [
4126 "struct P { }",
4127 "enum E { }",
4128 "struct P { x: Int }",
4129 "struct P {\n x: Int\n}",
4130 "enum E {\n A\n}",
4131 ] {
4132 let out = parse_text(src);
4133 assert!(out.diagnostics.is_empty(), "{src}: {:?}", out.diagnostics);
4134 }
4135 }
4136
4137 /// **A record pattern and a tuple pattern are patterns wherever a pattern is
4138 /// legal**, and each carries its sub-patterns in a shape the rest of the
4139 /// compiler can read.
4140 ///
4141 /// The list of shapes matters more than any one of them. A record pattern's
4142 /// fields are `PATTERN_FIELD`s and a tuple's elements are bare `PATTERN`s, so
4143 /// `P { x }` never looks like `P(x)`, and `P { x: p }` and `P { x }` are one
4144 /// node shape with an optional child rather than two identifier-counting
4145 /// rules.
4146 #[test]
4147 fn a_record_pattern_names_fields_and_a_tuple_pattern_names_positions() {
4148 let count = |src: &str, kind: SyntaxKind| -> usize {
4149 let out = parse_text(src);
4150 assert!(out.diagnostics.is_empty(), "{src}: {:?}", out.diagnostics);
4151 construct_names(&out.tree)
4152 .into_iter()
4153 .filter(|k| *k == kind)
4154 .count()
4155 };
4156
4157 // A record pattern's fields, punned and explicit and mixed. The `{` is
4158 // unambiguous here where a record *literal*'s is not: a pattern is
4159 // followed by `=>`, never by a block.
4160 for (src, fields) in [
4161 ("var a = match p { P { x } => x }", 1),
4162 ("var a = match p { P { x, y } => x }", 2),
4163 ("var a = match p { P { x: 1, y } => y }", 2),
4164 ("var a = match p { P { x: q, y: r } => q }", 2),
4165 // A trailing comma closes this list too.
4166 ("var a = match p { P { x, y, } => x }", 2),
4167 ] {
4168 assert_eq!(count(src, SyntaxKind::PATTERN_FIELD), fields, "{src}");
4169 }
4170
4171 // A tuple pattern's elements are sub-patterns, at every arity and nested.
4172 // The counts include the arm's own outer pattern.
4173 for (src, patterns) in [
4174 ("var a = match t { (x, y) => x }", 3),
4175 ("var a = match t { (x, y, z) => x }", 4),
4176 ("var a = match t { (x, (y, z)) => x }", 5),
4177 ("var a = match t { (1, _) => 0, _ => 1 }", 4),
4178 // …and a trailing comma.
4179 ("var a = match t { (x, y,) => x }", 3),
4180 ] {
4181 assert_eq!(count(src, SyntaxKind::PATTERN), patterns, "{src}");
4182 }
4183
4184 // The two compose: a record field holding a tuple, a tuple element
4185 // holding a record, and a variant payload holding either.
4186 for src in [
4187 "var a = match p { P { at: (x, y) } => x }",
4188 "var a = match t { (P { x }, n) => x }",
4189 "var a = match o { Some(P { x, y }) => x, None => 0 }",
4190 "var a = match o { Some((x, y)) => x, None => 0 }",
4191 ] {
4192 let out = parse_text(src);
4193 assert!(out.diagnostics.is_empty(), "{src}: {:?}", out.diagnostics);
4194 }
4195
4196 // A tuple pattern must be able to *start* an arm, or the arm list stops
4197 // at it and every arm after it silently leaves the tree — which is what
4198 // `is_pattern_start` decides.
4199 let out = parse_text("var a = match t { (x, y) => x\n _ => 0 }");
4200 assert!(out.diagnostics.is_empty(), "{:?}", out.diagnostics);
4201 assert_eq!(
4202 count(
4203 "var a = match t { (x, y) => x\n _ => 0 }",
4204 SyntaxKind::MATCH_ARM
4205 ),
4206 2,
4207 "both arms are in the tree"
4208 );
4209
4210 // The shapes that are not patterns. `()` has no type to match — `Unit` is
4211 // not a tuple — and a field with a `:` and nothing after it is a pattern
4212 // the program did not finish writing.
4213 for bad in [
4214 "var a = match u { () => 0 }",
4215 "var a = match p { P { x: } => 0 }",
4216 "var a = match p { P { , x } => 0 }",
4217 "var a = match p { P { x => 0 }",
4218 "var a = match t { (x, => 0 }",
4219 ] {
4220 let out = parse_text(bad);
4221 assert!(!out.diagnostics.is_empty(), "{bad} must report");
4222 }
4223 }
4224
4225 /// **A record pattern's head is optional** (ADR-091). It is the headed
4226 /// production with the head made optional, so it costs one arm in
4227 /// `parse_pattern`, one entry in `is_pattern_start`, and no new token.
4228 #[test]
4229 fn a_record_pattern_needs_no_head() {
4230 let count = |src: &str, kind: SyntaxKind| -> usize {
4231 let out = parse_text(src);
4232 assert!(out.diagnostics.is_empty(), "{src}: {:?}", out.diagnostics);
4233 construct_names(&out.tree)
4234 .into_iter()
4235 .filter(|k| *k == kind)
4236 .count()
4237 };
4238
4239 // The fields are the headed form's, unchanged — punned, explicit, mixed,
4240 // and with a trailing comma.
4241 for (src, fields) in [
4242 ("var a = match p { {x} => x }", 1),
4243 ("var a = match p { {x, y} => x }", 2),
4244 ("var a = match p { {x: 1, y} => y }", 2),
4245 ("var a = match p { {x: q, y: r} => q }", 2),
4246 ("var a = match p { {x, y,} => x }", 2),
4247 ] {
4248 assert_eq!(count(src, SyntaxKind::PATTERN_FIELD), fields, "{src}");
4249 }
4250
4251 // One production, so it composes in every position a pattern appears:
4252 // nested in a variant's payload (the shape a `choice(...)` payload record
4253 // needs), in a tuple, in a `for` header, and as a closure parameter.
4254 for src in [
4255 "var a = match m { Mul({x, y}) => x, Do(_) => 0 }",
4256 "var a = match t { ({x}, n) => x }",
4257 "var a = match p { {at: (x, y)} => x }",
4258 "for {x, y} in ps { out(x) }",
4259 "var f = |{x, y}| x + y",
4260 ] {
4261 let out = parse_text(src);
4262 assert!(out.diagnostics.is_empty(), "{src}: {:?}", out.diagnostics);
4263 }
4264
4265 // A headless pattern must be able to *start* an arm, or the arm list
4266 // stops before it and it — with every arm after it — silently leaves the
4267 // tree. The headless arm is written **second** on purpose: the first
4268 // arm's pattern is parsed unconditionally, so only a later one exercises
4269 // `is_pattern_start`.
4270 assert_eq!(
4271 count(
4272 "var a = match p { _ => 0\n {x, y} => x }",
4273 SyntaxKind::MATCH_ARM
4274 ),
4275 2,
4276 "both arms are in the tree"
4277 );
4278
4279 // `{}` is rejected where `()` is, and for the same reason (ADR-091
4280 // Decision 3): it binds nothing and names no record, so it is an
4281 // irrefutable arm written by accident. The pattern that matches
4282 // everything is spelled `_`.
4283 let out = parse_text("var a = match p { {} => 0 }");
4284 assert!(
4285 out.diagnostics
4286 .iter()
4287 .any(|d| d.message().contains("expected a pattern")),
4288 "an empty headless record pattern must report: {:?}",
4289 out.diagnostics
4290 );
4291
4292 // …but a *headed* `P {}` is kept: it names the record it tests for, so it
4293 // is refutable — `Some` beside `Some(_)`.
4294 let out = parse_text("var a = match p { P {} => 0 }");
4295 assert!(out.diagnostics.is_empty(), "{:?}", out.diagnostics);
4296 }
4297
4298 /// **A `(` that begins a line begins something new**; a `(` on the same line
4299 /// as the expression before it is that expression's argument list.
4300 ///
4301 /// `peek()` skips trivia and a newline **is** trivia, so without the rule the
4302 /// postfix loop and `parse_name_or_call` would open a `CALL_EXPR` on a
4303 /// line-leading `(`. In a `match` that is silent data loss: the arm body
4304 /// swallows the next arm's tuple pattern as an argument list, the arm loop
4305 /// finds no pattern start, and every arm after the first leaves the tree.
4306 #[test]
4307 fn a_line_leading_paren_begins_a_new_thing_and_a_same_line_one_is_a_call() {
4308 let count = |src: &str, kind: SyntaxKind| -> usize {
4309 let out = parse_text(src);
4310 assert!(out.diagnostics.is_empty(), "{src}: {:?}", out.diagnostics);
4311 construct_names(&out.tree)
4312 .into_iter()
4313 .filter(|k| *k == kind)
4314 .count()
4315 };
4316
4317 // Three arms, and all three are in the tree. A `10(a, b)` call would
4318 // leave one arm and one `CALL_EXPR`.
4319 let arms = "var r = match p {\n (0, 0) => 10\n (a, b) => a + b\n _ => 0\n}";
4320 assert_eq!(count(arms, SyntaxKind::MATCH_ARM), 3);
4321 assert_eq!(count(arms, SyntaxKind::CALL_EXPR), 0);
4322
4323 // The same shape after every kind of arm body a `(` could attach itself
4324 // to — a name, a call, a subscript, a field read, a block.
4325 for body in ["n", "f(1)", "m[k]", "p.x", "{ 0 }"] {
4326 let src = format!("var r = match p {{\n _ => {body}\n (a, b) => 1\n}}");
4327 assert_eq!(count(&src, SyntaxKind::MATCH_ARM), 2, "{src}");
4328 }
4329
4330 // The other direction, which is the rule's whole content: on one line a
4331 // `(` still opens an argument list, through every callee shape — a name,
4332 // a call's result, a subscript's, a paren, a closure.
4333 for src in [
4334 "var a = f(1)",
4335 "var a = f(1)(2)",
4336 "var a = m[k](7)",
4337 "var a = (g)(3)",
4338 "var a = (|x| x * 3)(14)",
4339 "var a = fs.get(0)(100)",
4340 ] {
4341 assert!(count(src, SyntaxKind::CALL_EXPR) >= 1, "{src}");
4342 }
4343
4344 // A `[` is subject to the same rule, because a list literal begins with
4345 // one: `m\n[k]` is a binding and a list, not a subscript.
4346 let sub = "var a = m\n[k]";
4347 assert_eq!(count(sub, SyntaxKind::INDEX_EXPR), 0);
4348 assert_eq!(count(sub, SyntaxKind::LIST_EXPR), 1);
4349 assert_eq!(count(sub, SyntaxKind::VAR_STMT), 1);
4350 // On one line it is a subscript.
4351 assert_eq!(count("var a = m[k]", SyntaxKind::INDEX_EXPR), 1);
4352 assert_eq!(count("var a = m[k]", SyntaxKind::LIST_EXPR), 0);
4353
4354 // Nor is the Pratt loop (ADR-049 D8): an operator that ends a line still
4355 // continues across it, and so does a `.method()` chain.
4356 assert_eq!(count("var a = 1 +\n2", SyntaxKind::BIN_EXPR), 1);
4357 assert_eq!(
4358 count("var a = v\n .len()", SyntaxKind::METHOD_CALL_EXPR),
4359 1
4360 );
4361 assert_eq!(
4362 count(
4363 "var a = v\n .map(f)\n .sum()",
4364 SyntaxKind::METHOD_CALL_EXPR
4365 ),
4366 2
4367 );
4368
4369 // A `(` that *opens* an expression is untouched wherever it appears —
4370 // only a `(` asked to continue one is.
4371 assert_eq!(count("var a = 1\n(b, c)", SyntaxKind::TUPLE_EXPR), 1);
4372 assert_eq!(count("var a = 1\n(b, c)", SyntaxKind::VAR_STMT), 1);
4373 assert_eq!(count("var a = 1\n(b + c) * 2", SyntaxKind::PAREN_EXPR), 1);
4374
4375 // …and a `for` binding is the second place a tuple pattern makes a
4376 // line-leading `(` reachable.
4377 assert_eq!(
4378 count("var a = 1\nfor (k, v) in m { }", SyntaxKind::FOR_EXPR),
4379 1
4380 );
4381
4382 // The cost, stated as a test rather than left to be discovered: a callee
4383 // that ends a line and an argument list that begins the next are two
4384 // expressions, so this is two statements and not one call.
4385 let split = "var a = f\n(1)";
4386 assert_eq!(count(split, SyntaxKind::CALL_EXPR), 0);
4387 assert_eq!(count(split, SyntaxKind::PAREN_EXPR), 1);
4388 }
4389
4390 /// **`||` is an empty parameter list where an expression must begin, and
4391 /// logical-or everywhere else.** The lexer's max-munch makes it one token,
4392 /// so position is the only thing that can tell the two apart — §4.2's
4393 /// shadowing example is `var show_old = || out(a)`.
4394 #[test]
4395 fn a_double_pipe_is_a_closure_where_an_expression_begins_and_an_operator_between_two() {
4396 let count = |src: &str, kind: SyntaxKind| -> usize {
4397 let out = parse_text(src);
4398 assert!(out.diagnostics.is_empty(), "{src}: {:?}", out.diagnostics);
4399 construct_names(&out.tree)
4400 .into_iter()
4401 .filter(|k| *k == kind)
4402 .count()
4403 };
4404
4405 // §4.2's own line, and the zero-parameter closure in every position an
4406 // expression begins: a binding, an argument, a block tail, a `return`, an
4407 // operand of the very operator it is spelled like, and its own body.
4408 for src in [
4409 "var show_old = || out(a)",
4410 "var f = || 5",
4411 "out(|| 5)",
4412 "fn g() { || 5 }",
4413 "fn g() { return || 5 }",
4414 "var f = a || || 5",
4415 "var f = || || 7",
4416 "var f = if p { || 1 } else { || 2 }",
4417 ] {
4418 assert!(count(src, SyntaxKind::CLOSURE_EXPR) >= 1, "{src}");
4419 assert_eq!(count(src, SyntaxKind::PARAM), 0, "{src}");
4420 }
4421
4422 // `| |` with a space is the same closure — the two spellings differ only
4423 // in how the lexer munched them.
4424 assert_eq!(count("var f = | | 5", SyntaxKind::CLOSURE_EXPR), 1);
4425
4426 // The other direction: between two operands `||` is logical-or, whose
4427 // precedence is the lowest of all — below `..` and `&&`.
4428 assert_eq!(count("var a = p || q", SyntaxKind::BIN_EXPR), 1);
4429 assert_eq!(count("var a = p || q", SyntaxKind::CLOSURE_EXPR), 0);
4430 assert_eq!(
4431 shape("var a = p || q && r"),
4432 shape("var a = p || (q && r)"),
4433 "`&&` still binds tighter than `||`"
4434 );
4435 assert_eq!(
4436 shape("var a = p == q || r == s"),
4437 shape("var a = (p == q) || (r == s)"),
4438 "comparison still binds tighter than `||`"
4439 );
4440 assert_eq!(
4441 shape("var a = p || q || r"),
4442 shape("var a = (p || q) || r"),
4443 "`||` is still left-associative"
4444 );
4445
4446 // A one-parameter closure is untouched, which is what says the
4447 // zero-parameter arm only fires on the two-pipe token.
4448 assert_eq!(count("var f = |x| x", SyntaxKind::PARAM), 1);
4449 }
4450
4451 /// **A closure parameter is a pattern, not a bare name** — Appendix D writes
4452 /// `|(a, b)| abs(a - b)`. It is the same grammar the `for` binding uses, at
4453 /// the third and last binding position.
4454 #[test]
4455 fn a_closure_parameter_is_a_pattern() {
4456 let count = |src: &str, kind: SyntaxKind| -> usize {
4457 let out = parse_text(src);
4458 assert!(out.diagnostics.is_empty(), "{src}: {:?}", out.diagnostics);
4459 construct_names(&out.tree)
4460 .into_iter()
4461 .filter(|k| *k == kind)
4462 .count()
4463 };
4464
4465 // Appendix D's own line.
4466 assert_eq!(
4467 count(
4468 "var d = left.zip(right).map(|(a, b)| abs(a - b)).sum()",
4469 SyntaxKind::CLOSURE_EXPR
4470 ),
4471 1
4472 );
4473
4474 // The shapes, and the pattern count each holds: the parameter's own, plus
4475 // one per element or nested field.
4476 for (src, params, patterns) in [
4477 ("var f = |x| x", 1, 1),
4478 ("var f = |_| 0", 1, 1),
4479 ("var f = |(a, b)| a", 1, 3),
4480 ("var f = |(a, (b, c))| a", 1, 5),
4481 ("var f = |P { x, y }| x", 1, 1),
4482 ("var f = |P { at: (x, y) }| x", 1, 4),
4483 ("var f = |(a, b), c| a", 2, 4),
4484 ("var f = |a, (b, c)| a", 2, 4),
4485 ("var f = | | 0", 0, 0),
4486 ] {
4487 assert_eq!(count(src, SyntaxKind::PARAM), params, "{src}");
4488 assert_eq!(count(src, SyntaxKind::PATTERN), patterns, "{src}");
4489 assert_eq!(count(src, SyntaxKind::CLOSURE_EXPR), 1, "{src}");
4490 }
4491
4492 // A pattern parameter still takes an annotation, and the annotation is the
4493 // whole argument's — the `:` is what ends the pattern.
4494 assert_eq!(
4495 count("var f = |(a, b): (Int, Int)| a", SyntaxKind::TUPLE_TYPE),
4496 1
4497 );
4498 assert_eq!(count("var f = |x: Int| x", SyntaxKind::TYPE_REF), 1);
4499
4500 // A trailing comma still closes the list, and a record pattern's brace
4501 // is not read as anything else: a parameter is followed by `,`, `:` or
4502 // `|`, never by an expression.
4503 for src in ["var f = |(a, b),| a", "var f = |P { x }| P { x: x }"] {
4504 assert_eq!(count(src, SyntaxKind::CLOSURE_EXPR), 1, "{src}");
4505 }
4506
4507 // The malformed shapes still report.
4508 for bad in [
4509 "var f = |(a, | a",
4510 "var f = |(| a",
4511 "var f = |+| a",
4512 "var f = |a, | ",
4513 ] {
4514 let out = parse_text(bad);
4515 assert!(!out.diagnostics.is_empty(), "{bad} must report");
4516 }
4517 }
4518
4519 /// The construct shape of `text` with parentheses erased, so two spellings
4520 /// that differ only by explicit grouping compare equal exactly when they
4521 /// parse to the same tree. Comparing the raw kind lists could not: the
4522 /// parenthesized form has `PAREN_EXPR`, `L_PAREN` and `R_PAREN` in it.
4523 fn shape(text: &str) -> Vec<SyntaxKind> {
4524 let out = parse_text(text);
4525 assert!(out.diagnostics.is_empty(), "{text}: {:?}", out.diagnostics);
4526 construct_names(&out.tree)
4527 .into_iter()
4528 .filter(|k| {
4529 !k.is_trivia()
4530 && !matches!(
4531 k,
4532 SyntaxKind::PAREN_EXPR | SyntaxKind::L_PAREN | SyntaxKind::R_PAREN
4533 )
4534 })
4535 .collect()
4536 }
4537
4538 fn construct_names(node: &SyntaxNode) -> Vec<SyntaxKind> {
4539 let mut out = Vec::new();
4540 collect(node, &mut out);
4541 return out;
4542 fn collect(node: &SyntaxNode, out: &mut Vec<SyntaxKind>) {
4543 out.push(node.kind());
4544 for child in node.children_with_tokens() {
4545 match child {
4546 rowan::NodeOrToken::Node(n) => collect(&n, out),
4547 rowan::NodeOrToken::Token(t) => out.push(t.kind()),
4548 }
4549 }
4550 }
4551 }
4552}