Skip to main content

m2_syn/parser/
native.rs

1//! Direct construction of the typed graph from a flat token stream.
2//!
3//! The native precedence engine owns parsing decisions only. Token storage,
4//! cursor position, trivia skipping, and newline detection belong to
5//! [`ParseStream`], shared with generated [`Parse`]
6//! implementations.
7
8use std::error::Error;
9use std::fmt::{Display, Formatter};
10
11use crate::cell_stream::{end_span, ends_with_cell_semicolon, frame_recovering};
12use crate::lexer::canonical_word_spelling;
13use crate::nodes::*;
14use crate::parse::{Lookahead, SignificantToken};
15use crate::{
16    CellStream, CellStreamError, CellTokenStream, CommentTrivia, Delimited, DelimiterKind,
17    DelimiterToken, DelimiterValue, LexError, LexErrorKind, LiteralKind, Parse, ParseStream,
18    Parser, Punctuated, Recovered, Span, Spanned, Terminal, Token, TokenParseError, TokenStream,
19    TokenTree, Tokenize, TrailingTrivia, lex_str, lex_str_recovering,
20};
21
22/// Tests a raw token against one typed-token spelling.
23macro_rules! is_token {
24    ($token:expr, $($pattern:tt)*) => {
25        <Token![$($pattern)*] as Token>::matches_token_tree($token)
26    };
27}
28
29/// Constructs the native parser's unexpected-token diagnostic.
30macro_rules! unexpected {
31    ($token:expr, $expected:expr) => {{
32        let token = $token;
33        NativeParseError::Unexpected {
34            span: token.expect_span(),
35            found: token.description(),
36            expected: $expected,
37        }
38    }};
39}
40
41/// The PREC CLOSER constant.
42const PREC_CLOSER: u8 = 6;
43/// The PREC COMMA constant.
44const PREC_COMMA: u8 = 10;
45/// The PREC CONTROL constant.
46const PREC_CONTROL: u8 = 12;
47/// The PREC LOOP CLAUSE constant.
48const PREC_LOOP_CLAUSE: u8 = 16;
49/// The PREC COLLECTION constant.
50const PREC_COLLECTION: u8 = 56;
51/// The PREC APPLICATION RIGHT constant.
52const PREC_APPLICATION_RIGHT: u8 = 61;
53/// The PREC APPLICATION constant.
54const PREC_APPLICATION: u8 = 62;
55
56/// The built-in parser implemented directly from Macaulay2's `P/B/U` table.
57#[derive(Debug)]
58pub struct NativeParser;
59
60impl Parser for NativeParser {
61    type Error = NativeParseError;
62
63    fn parse_cells(&mut self, cells: CellStream) -> Result<SourceFile, Self::Error> {
64        parse_cell_stream(cells)
65    }
66}
67
68/// Parses a complete source file with the native precedence engine.
69///
70/// # Errors
71///
72/// Returns [`NativeParseError`] when lexing fails or the token sequence is not
73/// valid complete Macaulay2 syntax.
74pub fn parse_native(source: &str) -> Result<SourceFile, NativeParseError> {
75    let tokens = lex_str(source).map_err(NativeParseError::Lex)?;
76    let cells = tokenize_for_native_parser(tokens)?;
77    NativeParser.parse_cells(cells)
78}
79
80/// Parses source while retaining valid syntax inside unclosed delimiters.
81///
82/// Missing closing delimiters become zero-width closing spans at end of input
83/// and are returned as non-fatal lexical diagnostics. Other lexical or
84/// grammatical failures remain fatal.
85///
86/// # Errors
87///
88/// Returns [`NativeParseError`] when source cannot be recovered into a complete
89/// typed file.
90pub fn parse_native_recovering(
91    source: &str,
92) -> Result<Recovered<SourceFile, LexError>, NativeParseError> {
93    let recovered = lex_str_recovering(source).map_err(NativeParseError::Lex)?;
94    let (tokens, diagnostics) = recovered.into_parts();
95    let source = tokens.source();
96    let framed = frame_recovering(tokens);
97    let cells = CellStream::from_cells_with_source(
98        framed.cells.into_iter().chain(framed.incomplete),
99        source,
100    );
101    let syntax = NativeParser.parse_cells(cells)?;
102    Ok(Recovered::new(syntax, diagnostics))
103}
104
105/// The current state of an append-oriented native cell parser.
106#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
107pub enum NativeCellState {
108    /// No submitted syntax is waiting and no completed cell is queued.
109    Empty,
110    /// The current syntax is complete or a completed shell cell is queued.
111    Complete,
112    /// The active source is a prefix that more input may complete.
113    Incomplete,
114    /// The active source contains an error that appended input cannot repair.
115    Invalid,
116}
117
118/// One completed native cell together with its exact submitted source.
119#[derive(Debug)]
120pub struct CompletedNativeCell {
121    /// The source.
122    source: Span,
123    /// The syntax.
124    syntax: crate::nodes::Cell,
125}
126
127impl CompletedNativeCell {
128    /// Returns the exact source submitted for this evaluation unit.
129    ///
130    /// # Panics
131    ///
132    /// Panics if the internally retained source span cannot resolve its text.
133    pub fn source(&self) -> &str {
134        self.source
135            .text()
136            .expect("completed cell source spans must resolve to text")
137    }
138
139    /// Returns the parsed typed cell.
140    pub fn syntax(&self) -> &crate::nodes::Cell {
141        &self.syntax
142    }
143
144    /// Separates the exact source span from the typed cell.
145    pub fn into_parts(self) -> (Span, crate::nodes::Cell) {
146        (self.source, self.syntax)
147    }
148}
149
150/// A retained native parser for line-oriented shell input.
151///
152/// Each call to [`Self::push_line`] appends one submitted physical line. Cells
153/// completed by a top-level newline or semicolon are removed from the active
154/// buffer and never parsed again. Only the unfinished tail is lexed and parsed
155/// on later submissions.
156///
157/// Missing delimiter closers and parser requirements at end of input are
158/// classified as [`NativeCellState::Incomplete`]. A recoverable typed cell is
159/// available through [`Self::active_syntax`] when synthetic delimiter closers
160/// were enough to parse its contents.
161///
162/// ```
163/// use m2_syn::{Lex, NativeCellParser, NativeCellState};
164///
165/// let mut parser = NativeCellParser::new();
166/// assert_eq!(parser.push_line("f = x -> ("), NativeCellState::Incomplete);
167/// assert!(parser.active_syntax().is_some());
168/// assert_eq!(parser.push_line("x + 1"), NativeCellState::Incomplete);
169/// assert_eq!(parser.push_line(")"), NativeCellState::Complete);
170///
171/// let cells = parser.take_completed();
172/// assert_eq!(cells[0].syntax().to_m2(), "f = x -> (\nx + 1\n)");
173/// ```
174#[derive(Debug)]
175pub struct NativeCellParser {
176    /// The active source.
177    active_source: String,
178    /// The active tokens.
179    active_tokens: TokenStream,
180    /// The active syntax.
181    active_syntax: Option<crate::nodes::Cell>,
182    /// The completed.
183    completed: Vec<CompletedNativeCell>,
184    /// The lexer diagnostics.
185    lexer_diagnostics: Vec<LexError>,
186    /// The parse error.
187    parse_error: Option<NativeParseError>,
188    /// The state.
189    state: NativeCellState,
190}
191
192impl Default for NativeCellParser {
193    fn default() -> Self {
194        Self::new()
195    }
196}
197
198impl NativeCellParser {
199    /// Creates an empty native shell parser.
200    pub fn new() -> Self {
201        Self {
202            active_source: String::new(),
203            active_tokens: TokenStream::new(),
204            active_syntax: None,
205            completed: Vec::new(),
206            lexer_diagnostics: Vec::new(),
207            parse_error: None,
208            state: NativeCellState::Empty,
209        }
210    }
211
212    /// Appends one submitted physical line and refreshes the active cell.
213    ///
214    /// A line feed is appended when `line` does not already end in one. This is
215    /// the submission boundary: a syntactically complete final expression may
216    /// become a completed cell, while an operator, required clause, or open
217    /// delimiter keeps the cell active.
218    pub fn push_line(&mut self, line: &str) -> NativeCellState {
219        self.active_source.push_str(line);
220        if !line.ends_with('\n') {
221            self.active_source.push('\n');
222        }
223        self.refresh()
224    }
225
226    /// Returns the current completion classification.
227    pub fn state(&self) -> NativeCellState {
228        self.state
229    }
230
231    /// Returns the exact source still belonging to the unfinished cell.
232    pub fn active_source(&self) -> &str {
233        &self.active_source
234    }
235
236    /// Returns recovered tokens for the unfinished cell.
237    pub fn active_tokens(&self) -> &TokenStream {
238        &self.active_tokens
239    }
240
241    /// Returns recovered typed syntax for the unfinished cell when available.
242    pub fn active_syntax(&self) -> Option<&crate::nodes::Cell> {
243        self.active_syntax.as_ref()
244    }
245
246    /// Returns lexer diagnostics for the active cell.
247    pub fn lexer_diagnostics(&self) -> &[LexError] {
248        &self.lexer_diagnostics
249    }
250
251    /// Returns the parser failure for an incomplete or invalid active cell.
252    pub fn parse_error(&self) -> Option<&NativeParseError> {
253        self.parse_error.as_ref()
254    }
255
256    /// Returns completed evaluation units that have not yet been taken.
257    pub fn completed(&self) -> &[CompletedNativeCell] {
258        &self.completed
259    }
260
261    /// Takes every completed evaluation unit without disturbing an active cell.
262    pub fn take_completed(&mut self) -> Vec<CompletedNativeCell> {
263        let completed = std::mem::take(&mut self.completed);
264        if self.state == NativeCellState::Complete {
265            self.state = NativeCellState::Empty;
266        }
267        completed
268    }
269
270    /// Discards the unfinished cell and its diagnostics.
271    pub fn reset_active(&mut self) {
272        self.active_source.clear();
273        self.active_tokens = TokenStream::new();
274        self.active_syntax = None;
275        self.lexer_diagnostics.clear();
276        self.parse_error = None;
277        self.state = if self.completed.is_empty() {
278            NativeCellState::Empty
279        } else {
280            NativeCellState::Complete
281        };
282    }
283
284    /// Handles refresh.
285    fn refresh(&mut self) -> NativeCellState {
286        self.active_tokens = TokenStream::new();
287        self.active_syntax = None;
288        self.lexer_diagnostics.clear();
289        self.parse_error = None;
290
291        loop {
292            let recovered = match lex_str_recovering(&self.active_source) {
293                Ok(recovered) => recovered,
294                Err(error) => {
295                    self.state = if incomplete_lex_error(error.kind()) {
296                        NativeCellState::Incomplete
297                    } else {
298                        NativeCellState::Invalid
299                    };
300                    self.lexer_diagnostics.push(error);
301                    return self.state;
302                }
303            };
304            let (tokens, diagnostics) = recovered.into_parts();
305            let framed = frame_recovering(tokens.clone());
306            let has_incomplete = framed.incomplete.is_some();
307            let mut cells = framed.cells.into_iter().map(|cell| (cell, true));
308            let first = cells
309                .next()
310                .or_else(|| framed.incomplete.map(|cell| (cell, false)));
311            let Some((cell, cell_complete)) = first else {
312                self.active_tokens = tokens;
313                self.lexer_diagnostics = diagnostics;
314                self.state = if self.completed.is_empty() {
315                    NativeCellState::Empty
316                } else {
317                    NativeCellState::Complete
318                };
319                return self.state;
320            };
321
322            let has_following_cell = cells.next().is_some() || has_incomplete;
323            let ended_by_semicolon = ends_with_cell_semicolon(&cell);
324            let boundary = end_span(&cell);
325            let end = boundary.end().unwrap_or(self.active_source.len());
326            let source = Span::ranged(std::sync::Arc::clone(boundary.source()), 0..end);
327
328            match parse_raw_cell(cell) {
329                Ok(Some(syntax)) if cell_complete && has_following_cell => {
330                    self.completed.push(CompletedNativeCell { source, syntax });
331                    self.active_source.replace_range(..end, "");
332                }
333                Ok(Some(syntax)) if cell_complete && diagnostics.is_empty() => {
334                    self.completed.push(CompletedNativeCell { source, syntax });
335                    self.active_source.clear();
336                    self.active_tokens = TokenStream::new();
337                    self.state = NativeCellState::Complete;
338                    return self.state;
339                }
340                Ok(Some(syntax)) => {
341                    self.active_tokens = tokens;
342                    self.active_syntax = Some(syntax);
343                    self.lexer_diagnostics = diagnostics;
344                    self.state = NativeCellState::Incomplete;
345                    return self.state;
346                }
347                Ok(None) => {
348                    self.active_tokens = tokens;
349                    self.lexer_diagnostics = diagnostics;
350                    self.state = if self.completed.is_empty() {
351                        NativeCellState::Empty
352                    } else {
353                        NativeCellState::Complete
354                    };
355                    return self.state;
356                }
357                Err(error) => {
358                    let can_append_to_cell =
359                        !cell_complete || (!has_following_cell && !ended_by_semicolon);
360                    self.state = if can_append_to_cell && incomplete_parse_error(&error) {
361                        NativeCellState::Incomplete
362                    } else {
363                        NativeCellState::Invalid
364                    };
365                    self.active_tokens = tokens;
366                    self.lexer_diagnostics = diagnostics;
367                    self.parse_error = Some(error);
368                    return self.state;
369                }
370            }
371        }
372    }
373}
374
375/// Handles incomplete lex error.
376pub(crate) fn incomplete_lex_error(kind: LexErrorKind) -> bool {
377    matches!(
378        kind,
379        LexErrorKind::UnterminatedGroup
380            | LexErrorKind::UnterminatedString
381            | LexErrorKind::UnterminatedRawString
382            | LexErrorKind::UnterminatedBlockComment
383    )
384}
385
386/// Handles incomplete parse error.
387pub(crate) fn incomplete_parse_error(error: &NativeParseError) -> bool {
388    match error {
389        NativeParseError::MissingOperand { .. } => true,
390        NativeParseError::Unexpected { found, .. } => found == "end of input",
391        NativeParseError::Lex(error) => incomplete_lex_error(error.kind()),
392        NativeParseError::Tokenize(_) => true,
393        NativeParseError::NewlineInApplication { .. }
394        | NativeParseError::InvalidAssignmentTarget { .. }
395        | NativeParseError::InvalidLambdaArguments { .. }
396        | NativeParseError::Unsupported { .. } => false,
397    }
398}
399
400#[derive(Debug, Spanned)]
401/// An error produced by the native lexer or precedence parser.
402pub enum NativeParseError {
403    /// Tokenization failed before parsing began.
404    Lex(LexError),
405    /// The raw token stream could not be partitioned into complete cells.
406    Tokenize(CellStreamError),
407    /// The parser encountered a token that cannot occur in this position.
408    Unexpected {
409        /// A readable description of the received token.
410        found: String,
411        /// A readable description of the required syntax.
412        expected: &'static str,
413        /// The received token or end-of-input position.
414        span: Span,
415    },
416    /// A prefix or binary operator has no operand.
417    MissingOperand {
418        /// The operator spelling.
419        operator: String,
420        /// The operator or end-of-input position.
421        span: Span,
422    },
423    /// Implicit function application crossed a top-level line break.
424    NewlineInApplication {
425        /// The token following the line break.
426        span: Span,
427    },
428    /// The left side of an assignment is not assignable.
429    InvalidAssignmentTarget {
430        /// The assignment operator span.
431        span: Span,
432    },
433    /// The left side of a lambda arrow is not an argument form.
434    InvalidLambdaArguments {
435        /// The lambda arrow span.
436        span: Span,
437    },
438    /// The grammar recognizes syntax that this native backend cannot lower yet.
439    Unsupported {
440        /// The unsupported syntax spelling.
441        syntax: String,
442        /// The unsupported token span.
443        span: Span,
444    },
445}
446
447impl NativeParseError {
448    /// Handles unexpected end.
449    fn unexpected_end(expected: &'static str, span: Span) -> Self {
450        Self::Unexpected {
451            found: "end of input".into(),
452            expected,
453            span,
454        }
455    }
456
457    /// Handles missing operand for.
458    fn missing_operand_for(self, operator: &TokenTree) -> Self {
459        if matches!(self, Self::MissingOperand { .. }) {
460            Self::MissingOperand {
461                operator: operator.description(),
462                span: operator.expect_span(),
463            }
464        } else {
465            self
466        }
467    }
468}
469
470impl Display for NativeParseError {
471    fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
472        match self {
473            Self::Lex(error) => error.fmt(formatter),
474            Self::Tokenize(error) => error.fmt(formatter),
475            Self::Unexpected {
476                found, expected, ..
477            } => write!(formatter, "expected {expected}, found `{found}`"),
478            Self::MissingOperand { operator, .. } => {
479                write!(
480                    formatter,
481                    "expected an operand after `{operator}`, found end of input"
482                )
483            }
484            Self::NewlineInApplication { .. } => {
485                formatter.write_str("implicit application cannot cross a line break")
486            }
487            Self::InvalidAssignmentTarget { .. } => {
488                formatter.write_str("invalid assignment target")
489            }
490            Self::InvalidLambdaArguments { .. } => {
491                formatter.write_str("invalid lambda argument list")
492            }
493            Self::Unsupported { syntax, .. } => {
494                write!(
495                    formatter,
496                    "native parsing of `{syntax}` is not implemented yet"
497                )
498            }
499        }
500    }
501}
502
503impl Error for NativeParseError {
504    fn source(&self) -> Option<&(dyn Error + 'static)> {
505        match self {
506            Self::Lex(error) => Some(error),
507            Self::Tokenize(error) => Some(error),
508            _ => None,
509        }
510    }
511}
512
513#[derive(Debug, Clone, Copy)]
514/// Parser-local instruction for interpreting a token in unary position.
515///
516/// This is not a syntax category and is never stored in the token stream or
517/// typed CST. [`parse_info`] derives it temporarily from the current raw token
518/// so the precedence engine can select the corresponding parsing routine.
519enum UnaryAction {
520    /// The Atom alternative.
521    Atom,
522    /// The Prefix alternative.
523    Prefix,
524    /// The Statement alternative.
525    Statement,
526    /// The Control alternative.
527    Control,
528    /// The Debug alternative.
529    Debug,
530    /// The Delimiter alternative.
531    Delimiter,
532    /// The Quote alternative.
533    Quote,
534    /// The Error alternative.
535    Error,
536}
537
538#[derive(Debug, Clone, Copy)]
539struct ParseInfo {
540    /// The precedence.
541    precedence: u8,
542    /// The binary strength.
543    binary_strength: Option<u8>,
544    /// The unary strength.
545    unary_strength: Option<u8>,
546    /// The unary.
547    unary: UnaryAction,
548    /// The postfix.
549    postfix: bool,
550}
551
552impl From<TokenParseRule> for ParseInfo {
553    fn from(rule: TokenParseRule) -> Self {
554        match rule {
555            TokenParseRule::Precedence(precedence) => Self::stop(precedence),
556            TokenParseRule::Postfix(precedence) => Self::postfix(precedence),
557            TokenParseRule::Binary(precedence, strength) => Self::binary(precedence, strength),
558            TokenParseRule::Prefix(precedence, strength) => {
559                Self::unary(precedence, UnaryAction::Prefix, strength)
560            }
561            TokenParseRule::PrefixBinary(precedence, binary, unary) => {
562                Self::prefix_binary(precedence, binary, unary)
563            }
564            TokenParseRule::Unary(precedence, strength) => {
565                Self::unary(precedence, UnaryAction::Error, strength)
566            }
567        }
568    }
569}
570
571impl ParseInfo {
572    /// Handles atom.
573    const fn atom(precedence: u8) -> Self {
574        Self {
575            precedence,
576            binary_strength: None,
577            unary_strength: None,
578            unary: UnaryAction::Atom,
579            postfix: false,
580        }
581    }
582
583    /// Handles binary.
584    const fn binary(precedence: u8, strength: u8) -> Self {
585        Self {
586            precedence,
587            binary_strength: Some(strength),
588            unary_strength: None,
589            unary: UnaryAction::Error,
590            postfix: false,
591        }
592    }
593
594    /// Handles prefix binary.
595    const fn prefix_binary(precedence: u8, binary_strength: u8, unary_strength: u8) -> Self {
596        Self {
597            precedence,
598            binary_strength: Some(binary_strength),
599            unary_strength: Some(unary_strength),
600            unary: UnaryAction::Prefix,
601            postfix: false,
602        }
603    }
604
605    /// A token whose action in unary position is to introduce something that
606    /// binds at `strength`: a statement, a control form, a timing form, or a
607    /// quoted name.
608    const fn unary(precedence: u8, unary: UnaryAction, strength: u8) -> Self {
609        Self {
610            precedence,
611            binary_strength: None,
612            unary_strength: Some(strength),
613            unary,
614            postfix: false,
615        }
616    }
617
618    /// Handles postfix.
619    const fn postfix(precedence: u8) -> Self {
620        Self {
621            precedence,
622            binary_strength: None,
623            unary_strength: None,
624            unary: UnaryAction::Error,
625            postfix: true,
626        }
627    }
628
629    /// Handles delimiter.
630    const fn delimiter(precedence: u8) -> Self {
631        Self {
632            precedence,
633            binary_strength: None,
634            unary_strength: Some(PREC_CLOSER),
635            unary: UnaryAction::Delimiter,
636            postfix: false,
637        }
638    }
639
640    /// Handles stop.
641    const fn stop(precedence: u8) -> Self {
642        Self {
643            precedence,
644            binary_strength: None,
645            unary_strength: None,
646            unary: UnaryAction::Error,
647            postfix: false,
648        }
649    }
650}
651
652/// Internal state for Engine.
653struct Engine {
654    /// The input.
655    input: ParseStream,
656}
657
658/// Internal state for Components.
659struct Components<T> {
660    /// The first.
661    first: T,
662    /// The rest.
663    rest: Vec<(Token![,], T)>,
664}
665
666impl<T> Components<T> {
667    /// Creates the value from punctuated.
668    fn from_punctuated(values: Punctuated<T>) -> Self {
669        let (pair, rest) = values.into_parts();
670        let (first, punctuation, second) = pair.into_parts();
671        let mut pairs = Vec::with_capacity(rest.len() + 1);
672        pairs.push((punctuation, second));
673        pairs.extend(rest);
674        Self { first, rest: pairs }
675    }
676
677    /// Returns whether the value is punctuated.
678    fn is_punctuated(&self) -> bool {
679        !self.rest.is_empty()
680    }
681
682    /// Converts the value into punctuated.
683    fn into_punctuated(self) -> Result<Punctuated<T>, T> {
684        let mut rest = self.rest.into_iter();
685        let Some((punctuation, second)) = rest.next() else {
686            return Err(self.first);
687        };
688        let mut values = Punctuated::new(self.first, punctuation, second);
689        for (punctuation, value) in rest {
690            values.push(punctuation, value);
691        }
692        Ok(values)
693    }
694
695    /// Handles map.
696    fn map<U>(self, mut map: impl FnMut(T) -> Option<U>) -> Option<Components<U>> {
697        Some(Components {
698            first: map(self.first)?,
699            rest: self
700                .rest
701                .into_iter()
702                .map(|(punctuation, value)| Some((punctuation, map(value)?)))
703                .collect::<Option<Vec<_>>>()?,
704        })
705    }
706}
707
708impl Engine {
709    /// Creates a new value.
710    fn new(tokens: TokenStream) -> Self {
711        Self {
712            input: ParseStream::new(tokens),
713        }
714    }
715
716    /// Parses cell.
717    fn parse_cell(
718        mut self,
719        semicolon: Option<Token![;]>,
720        eoc_span: Span,
721    ) -> Result<Option<crate::nodes::Cell>, NativeParseError> {
722        self.skip_trivia();
723        if matches!(self.peek(), Lookahead::End(_)) {
724            return match semicolon {
725                None => Ok(None),
726                Some(semicolon) => Err(NativeParseError::Unexpected {
727                    found: ";".into(),
728                    expected: "a statement before `;`",
729                    span: semicolon.expect_span(),
730                }),
731            };
732        }
733
734        let components = self.parse_components()?;
735
736        if let Lookahead::Token(token) = self.peek() {
737            return Err(unexpected!(token.token, "the end of the cell"));
738        }
739
740        let eoc = EOC::new("", eoc_span);
741        Ok(Some(crate::nodes::Cell::new(
742            self.packed_content(components)?,
743            semicolon,
744            eoc,
745        )))
746    }
747
748    /// Parses components.
749    fn parse_components(&mut self) -> Result<Components<Component>, NativeParseError> {
750        let first = if self.at_punctuation(",") {
751            Component::Empty(Empty::new("", empty_span_at(&self.peek().expect_span())))
752        } else {
753            self.parse_required(PREC_COMMA)?.into()
754        };
755        let mut rest = Vec::new();
756
757        while let Some(comma) = self.take_punctuation(",") {
758            let next = if self.at_end() || self.at_punctuation(";") || self.at_punctuation(",") {
759                Component::Empty(Empty::new("", empty_span_at(&self.peek().expect_span())))
760            } else {
761                self.parse_required(PREC_COMMA)?.into()
762            };
763            rest.push((typed_token(comma), next));
764        }
765
766        Ok(Components { first, rest })
767    }
768
769    /// Parses optional components.
770    fn parse_optional_components(
771        &mut self,
772    ) -> Result<Option<Components<Component>>, NativeParseError> {
773        if self.at_end() || self.at_punctuation(";") {
774            Ok(None)
775        } else {
776            self.parse_components().map(Some)
777        }
778    }
779
780    /// Parses required.
781    fn parse_required(&mut self, level: u8) -> Result<Expr, NativeParseError> {
782        let token = match self.consume() {
783            Lookahead::Token(token) => token,
784            Lookahead::End(span) => {
785                return Err(NativeParseError::MissingOperand {
786                    operator: "end of input".into(),
787                    span,
788                });
789            }
790        };
791        self.parse_consumed(token, level)
792    }
793
794    /// Parses nullable.
795    fn parse_nullable(&mut self, level: u8) -> Result<Option<Expr>, NativeParseError> {
796        let lookahead = self.peek();
797        let Lookahead::Token(token) = lookahead else {
798            return Ok(None);
799        };
800        if parse_info(&token.token).precedence <= level {
801            return Ok(None);
802        }
803        let Lookahead::Token(token) = self.consume() else {
804            unreachable!("the token just peeked is consumable")
805        };
806        self.parse_consumed(token, level).map(Some)
807    }
808
809    /// Parses consumed.
810    fn parse_consumed(
811        &mut self,
812        token: SignificantToken,
813        level: u8,
814    ) -> Result<Expr, NativeParseError> {
815        let info = parse_info(&token.token);
816        let result = match info.unary {
817            UnaryAction::Atom => lower_atom(token)?,
818            UnaryAction::Prefix => {
819                let strength = info.unary_strength.expect("prefix operators have U");
820                let operand = self.parse_required(level.max(strength))?;
821                let span = token.token.expect_span();
822                let spelling = token.token.description();
823                let operator =
824                    PrefixOperator::from_token_tree_with_trivia(token.token, token.trailing_trivia)
825                        .ok_or({
826                            NativeParseError::Unsupported {
827                                syntax: spelling,
828                                span,
829                            }
830                        })?;
831                Expr!(Op::Prefix {
832                    operator,
833                    operand: Box::new(operand),
834                })
835            }
836            UnaryAction::Statement => {
837                let strength = info
838                    .unary_strength
839                    .expect("prefix statements have a unary binding strength");
840                let operand = if is_token!(&token.token, break)
841                    || is_token!(&token.token, continue)
842                    || is_token!(&token.token, return)
843                {
844                    self.parse_nullable(level.max(strength))?
845                } else {
846                    self.parse_required(level.max(strength))
847                        .map_err(|error| error.missing_operand_for(&token.token))?
848                        .into()
849                };
850                lower_prefix_statement(token, operand)
851            }
852            UnaryAction::Control => {
853                if is_token!(&token.token, if) {
854                    self.parse_if_statement(token)?
855                } else if is_token!(&token.token, for) {
856                    self.parse_for_loop(token)?
857                } else if is_token!(&token.token, while) {
858                    self.parse_while_loop(token)?
859                } else if is_token!(&token.token, try) {
860                    self.parse_try_statement(token)?
861                } else if is_token!(&token.token, new) {
862                    self.parse_new_statement(token)?
863                } else {
864                    unreachable!("control actions are assigned only to control keywords")
865                }
866            }
867            UnaryAction::Debug => self.parse_debug_clause(token)?,
868            UnaryAction::Delimiter => parse_delimited(token)?,
869            UnaryAction::Quote => {
870                let operator = token.token.description();
871                let quoted = match self.consume() {
872                    Lookahead::Token(quoted) => quoted,
873                    Lookahead::End(span) => {
874                        return Err(NativeParseError::MissingOperand { operator, span });
875                    }
876                };
877                let quoted_span = quoted.token.expect_span();
878                let Some(quoted_text) = quoted.token.spelling().map(str::to_owned) else {
879                    return Err(unexpected!(quoted.token, "a quoted token"));
880                };
881                let quoted = typed_terminal(
882                    Symbol::new(quoted_text, quoted_span),
883                    quoted.trailing_trivia,
884                );
885                if is_token!(&token.token, symbol) {
886                    Expr!(Quote::Symbol {
887                        specifier: typed_token(token),
888                        symbol: quoted,
889                    })
890                } else if is_token!(&token.token, local) {
891                    Expr!(Quote::Local {
892                        specifier: typed_token(token),
893                        symbol: quoted,
894                    })
895                } else if is_token!(&token.token, global) {
896                    Expr!(Quote::Global {
897                        specifier: typed_token(token),
898                        symbol: quoted,
899                    })
900                } else if is_token!(&token.token, threadVariable) {
901                    Expr!(Quote::ThreadVariable {
902                        specifier: typed_token(token),
903                        symbol: quoted,
904                    })
905                } else if is_token!(&token.token, threadLocal) {
906                    Expr!(Quote::ThreadLocal {
907                        specifier: typed_token(token),
908                        symbol: quoted,
909                    })
910                } else {
911                    unreachable!("quote actions are assigned only to quote specifiers")
912                }
913            }
914            UnaryAction::Error => {
915                return Err(unexpected!(token.token, "an expression"));
916            }
917        };
918        self.accumulate(result, level)
919    }
920
921    /// Parses if statement.
922    fn parse_if_statement(&mut self, keyword: SignificantToken) -> Result<Expr, NativeParseError> {
923        let condition = self.required_clause_expression(PREC_CONTROL, &keyword.token)?;
924        let then_keyword = self.consume_exact("then")?;
925        let then_value = self.required_clause_expression(PREC_CONTROL, &then_keyword.token)?;
926        let then_clause = ThenClause::new(typed_token(then_keyword), Box::new(then_value));
927        let else_clause = self
928            .take_exact("else")
929            .map(|else_keyword| {
930                let value = self.required_clause_expression(PREC_CONTROL, &else_keyword.token)?;
931                Ok::<_, NativeParseError>(ElseClause::new(
932                    typed_token(else_keyword),
933                    Box::new(value),
934                ))
935            })
936            .transpose()?;
937        Ok(Expr!(If {
938            if_token: typed_token(keyword),
939            condition: Box::new(condition),
940            then_clause,
941            else_clause,
942        }))
943    }
944
945    /// Parses for loop.
946    fn parse_for_loop(&mut self, keyword: SignificantToken) -> Result<Expr, NativeParseError> {
947        let variable = self.consume_symbol("a loop variable")?;
948
949        enum Domain {
950            /// The Bare alternative.
951            Bare,
952            /// The Range alternative.
953            Range(Option<RangeBoundFrom>, Option<RangeBoundTo>),
954            /// The In alternative.
955            In(SignificantToken, Box<Expr>),
956        }
957        let domain = if let Some(token) = self.take_exact("in") {
958            let collection = self.required_clause_expression(PREC_LOOP_CLAUSE, &token.token)?;
959            Domain::In(token, Box::new(collection))
960        } else {
961            let lower_bound = self
962                .take_exact("from")
963                .map(|token| {
964                    let value = self.required_clause_expression(PREC_LOOP_CLAUSE, &token.token)?;
965                    Ok::<_, NativeParseError>(RangeBoundFrom::new(
966                        typed_token(token),
967                        Box::new(value),
968                    ))
969                })
970                .transpose()?;
971            let upper_bound = self
972                .take_exact("to")
973                .map(|token| {
974                    let value = self.required_clause_expression(PREC_LOOP_CLAUSE, &token.token)?;
975                    Ok::<_, NativeParseError>(RangeBoundTo::new(
976                        typed_token(token),
977                        Box::new(value),
978                    ))
979                })
980                .transpose()?;
981            if lower_bound.is_some() || upper_bound.is_some() {
982                Domain::Range(lower_bound, upper_bound)
983            } else {
984                Domain::Bare
985            }
986        };
987
988        let when_condition = if let Some(token) = self.take_exact("when") {
989            let condition = self.required_clause_expression(PREC_LOOP_CLAUSE, &token.token)?;
990            Some(WhenCondition::new(typed_token(token), Box::new(condition)))
991        } else {
992            None
993        };
994        let body = self.parse_loop_body()?;
995
996        Ok(match domain {
997            Domain::Bare => Expr!(For::Bare {
998                for_token: typed_token(keyword),
999                variable,
1000                condition: when_condition,
1001                body,
1002            }),
1003            Domain::Range(lower_bound, upper_bound) => Expr!(For::Range {
1004                for_token: typed_token(keyword),
1005                variable,
1006                lower_bound,
1007                upper_bound,
1008                condition: when_condition,
1009                body,
1010            }),
1011            Domain::In(token, collection) => Expr!(For::In {
1012                for_token: typed_token(keyword),
1013                variable,
1014                in_token: typed_token(token),
1015                collection,
1016                condition: when_condition,
1017                body,
1018            }),
1019        })
1020    }
1021
1022    /// Parses while loop.
1023    fn parse_while_loop(&mut self, keyword: SignificantToken) -> Result<Expr, NativeParseError> {
1024        let condition = self.required_clause_expression(PREC_CONTROL, &keyword.token)?;
1025        let body = self.parse_loop_body()?;
1026        Ok(Expr!(While {
1027            while_token: typed_token(keyword),
1028            condition: Box::new(condition),
1029            body,
1030        }))
1031    }
1032
1033    /// Parses loop body.
1034    fn parse_loop_body(&mut self) -> Result<LoopBody, NativeParseError> {
1035        let (list_step, do_step) = if let Some(token) = self.take_exact("list") {
1036            let listed_value = self.required_clause_expression(PREC_CONTROL, &token.token)?;
1037            let list_step = Some(ListStep::new(typed_token(token), Box::new(listed_value)));
1038            if let Some(token) = self.take_exact("do") {
1039                let ignored_value = self.required_clause_expression(PREC_CONTROL, &token.token)?;
1040                (
1041                    list_step,
1042                    Some(DoStep::new(typed_token(token), Box::new(ignored_value))),
1043                )
1044            } else {
1045                (list_step, None)
1046            }
1047        } else if let Some(token) = self.take_exact("do") {
1048            let ignored_value = self.required_clause_expression(PREC_CONTROL, &token.token)?;
1049            (
1050                None,
1051                Some(DoStep::new(typed_token(token), Box::new(ignored_value))),
1052            )
1053        } else {
1054            return Err(self.expected_at_lookahead("`list` or `do`"));
1055        };
1056
1057        Ok(LoopBody::new(list_step, do_step))
1058    }
1059
1060    /// Parses try statement.
1061    fn parse_try_statement(&mut self, keyword: SignificantToken) -> Result<Expr, NativeParseError> {
1062        let value = self.required_clause_expression(PREC_CONTROL, &keyword.token)?;
1063        let then_clause = self
1064            .take_exact("then")
1065            .map(|then_keyword| {
1066                let value = self.required_clause_expression(PREC_CONTROL, &then_keyword.token)?;
1067                Ok::<_, NativeParseError>(ThenClause::new(
1068                    typed_token(then_keyword),
1069                    Box::new(value),
1070                ))
1071            })
1072            .transpose()?;
1073
1074        let fallback = if let Some(else_keyword) = self.take_exact("else") {
1075            let value = self.required_clause_expression(PREC_CONTROL, &else_keyword.token)?;
1076            Some(TryFallback::Else(ElseClause::new(
1077                typed_token(else_keyword),
1078                Box::new(value),
1079            )))
1080        } else if let Some(except_keyword) = self.take_exact("except") {
1081            let exception = self.consume_symbol("an exception symbol")?;
1082            let do_keyword = self.consume_exact("do")?;
1083            let value = self.required_clause_expression(PREC_CONTROL, &do_keyword.token)?;
1084            Some(TryFallback!(Except {
1085                except_token: typed_token(except_keyword),
1086                exception,
1087                do_token: typed_token(do_keyword),
1088                value: Box::new(value),
1089            }))
1090        } else {
1091            None
1092        };
1093
1094        Ok(Expr!(Try {
1095            try_token: typed_token(keyword),
1096            value: Box::new(value),
1097            on_success: then_clause,
1098            fallback,
1099        }))
1100    }
1101
1102    /// Parses new statement.
1103    fn parse_new_statement(&mut self, keyword: SignificantToken) -> Result<Expr, NativeParseError> {
1104        let class = self.required_clause_expression(PREC_LOOP_CLAUSE, &keyword.token)?;
1105        let parent_class = if let Some(token) = self.take_exact("of") {
1106            let parent = self.required_clause_expression(PREC_LOOP_CLAUSE, &token.token)?;
1107            Some(OfClass::new(typed_token(token), Box::new(parent)))
1108        } else {
1109            None
1110        };
1111        let instance = if let Some(token) = self.take_exact("from") {
1112            let instance = self.required_clause_expression(PREC_LOOP_CLAUSE, &token.token)?;
1113            Some(FromInstance::new(typed_token(token), Box::new(instance)))
1114        } else {
1115            None
1116        };
1117
1118        Ok(Expr!(New {
1119            new_token: typed_token(keyword),
1120            class: Box::new(class),
1121            parent_class,
1122            instance,
1123        }))
1124    }
1125
1126    /// Parses debug clause.
1127    fn parse_debug_clause(&mut self, keyword: SignificantToken) -> Result<Expr, NativeParseError> {
1128        let spelling = parsing_spelling(&keyword.token).to_owned();
1129        if matches!(
1130            spelling.as_str(),
1131            "time" | "timing" | "elapsedTime" | "elapsedTiming" | "profile"
1132        ) {
1133            let value = self
1134                .parse_required(PREC_CONTROL)
1135                .map_err(|error| error.missing_operand_for(&keyword.token))?;
1136            return Ok(match spelling.as_str() {
1137                "time" => Expr!(Profile::Time {
1138                    modifier: typed_token(keyword),
1139                    value: Box::new(value),
1140                }),
1141                "timing" => Expr!(Profile::Timing {
1142                    modifier: typed_token(keyword),
1143                    value: Box::new(value),
1144                }),
1145                "elapsedTime" => Expr!(Profile::ElapsedTime {
1146                    modifier: typed_token(keyword),
1147                    value: Box::new(value),
1148                }),
1149                "elapsedTiming" => Expr!(Profile::ElapsedTiming {
1150                    modifier: typed_token(keyword),
1151                    value: Box::new(value),
1152                }),
1153                "profile" => Expr!(Profile::Profile {
1154                    modifier: typed_token(keyword),
1155                    value: Box::new(value),
1156                }),
1157                _ => unreachable!(),
1158            });
1159        }
1160        let value_is_optional = matches!(spelling.as_str(), "step" | "finish");
1161        let value = if value_is_optional {
1162            self.parse_nullable(PREC_CONTROL)?
1163        } else {
1164            Some(
1165                self.parse_required(PREC_CONTROL)
1166                    .map_err(|error| error.missing_operand_for(&keyword.token))?,
1167            )
1168        };
1169        let value = value.map(Box::new);
1170        Ok(match spelling.as_str() {
1171            "step" => Expr!(Debug::Step {
1172                keyword: typed_token(keyword),
1173                value,
1174            }),
1175            "finish" => Expr!(Debug::Finish {
1176                keyword: typed_token(keyword),
1177                value,
1178            }),
1179            "shield" => Expr!(Debug::Shield {
1180                keyword: typed_token(keyword),
1181                value,
1182            }),
1183            "TEST" => Expr!(Debug::Test {
1184                keyword: typed_token(keyword),
1185                value,
1186            }),
1187            "breakpoint" => Expr!(Debug::Breakpoint {
1188                keyword: typed_token(keyword),
1189                value,
1190            }),
1191            _ => unreachable!("debug actions are assigned only to debug keywords"),
1192        })
1193    }
1194
1195    /// Handles required clause expression.
1196    fn required_clause_expression(
1197        &mut self,
1198        level: u8,
1199        keyword: &TokenTree,
1200    ) -> Result<Expr, NativeParseError> {
1201        match self.parse_nullable(level)? {
1202            None => Err(NativeParseError::MissingOperand {
1203                operator: keyword.description(),
1204                span: keyword.expect_span(),
1205            }),
1206            Some(expression) => Ok(expression),
1207        }
1208    }
1209
1210    /// Consumes symbol.
1211    fn consume_symbol(&mut self, expected: &'static str) -> Result<Symbol, NativeParseError> {
1212        match self.consume() {
1213            Lookahead::Token(token)
1214                if matches!(token.token, TokenTree::Ident(_))
1215                    && matches!(parse_info(&token.token).unary, UnaryAction::Atom) =>
1216            {
1217                let span = token.token.expect_span();
1218                let text = token.token.description();
1219                Ok(typed_terminal(
1220                    Symbol::new(text, span),
1221                    token.trailing_trivia,
1222                ))
1223            }
1224            Lookahead::Token(token) => Err(unexpected!(token.token, expected)),
1225            Lookahead::End(span) => Err(NativeParseError::unexpected_end(expected, span)),
1226        }
1227    }
1228
1229    /// Consumes exact.
1230    fn consume_exact(
1231        &mut self,
1232        spelling: &'static str,
1233    ) -> Result<SignificantToken, NativeParseError> {
1234        match self.consume() {
1235            Lookahead::Token(token) if parsing_spelling(&token.token) == spelling => Ok(token),
1236            Lookahead::Token(token) => Err(unexpected!(token.token, spelling)),
1237            Lookahead::End(span) => Err(NativeParseError::unexpected_end(spelling, span)),
1238        }
1239    }
1240
1241    /// Takes exact.
1242    fn take_exact(&mut self, spelling: &'static str) -> Option<SignificantToken> {
1243        if matches!(
1244            self.peek(),
1245            Lookahead::Token(token)
1246                if parsing_spelling(&token.token) == spelling
1247        ) {
1248            let Lookahead::Token(token) = self.consume() else {
1249                unreachable!("the token just peeked is consumable")
1250            };
1251            Some(token)
1252        } else {
1253            None
1254        }
1255    }
1256
1257    /// Handles expected at lookahead.
1258    fn expected_at_lookahead(&self, expected: &'static str) -> NativeParseError {
1259        match self.peek() {
1260            Lookahead::Token(token) => unexpected!(token.token, expected),
1261            Lookahead::End(span) => NativeParseError::unexpected_end(expected, span),
1262        }
1263    }
1264
1265    /// Handles accumulate.
1266    fn accumulate(&mut self, mut left: Expr, level: u8) -> Result<Expr, NativeParseError> {
1267        loop {
1268            let Lookahead::Token(next) = self.peek() else {
1269                return Ok(left);
1270            };
1271            let info = if matches!(&next.token, TokenTree::Punct(punct) if punct.text().is_empty())
1272            {
1273                self.adjacency_info()
1274            } else {
1275                parse_info(&next.token)
1276            };
1277            if info.precedence <= level {
1278                return Ok(left);
1279            }
1280            let Lookahead::Token(operator) = self.consume() else {
1281                unreachable!("the token just peeked is consumable")
1282            };
1283            left = if matches!(&operator.token, TokenTree::Punct(punct) if punct.text().is_empty())
1284            {
1285                let right = self
1286                    .parse_required(PREC_APPLICATION_RIGHT)
1287                    .map_err(|error| error.missing_operand_for(&operator.token))?;
1288                let adjacency = typed_terminal(
1289                    Adj::new("", operator.token.expect_span()),
1290                    operator.trailing_trivia,
1291                );
1292                Expr!(Op::Bin::Adj {
1293                    left_operand: Box::new(left),
1294                    operator: adjacency,
1295                    right_operand: Box::new(right),
1296                })
1297            } else if let Some(strength) = info.binary_strength {
1298                let left = BinaryLeft::prepare(left, &operator.token)?;
1299                let right = self
1300                    .parse_required(strength)
1301                    .map_err(|error| error.missing_operand_for(&operator.token))?;
1302                lower_binary(left, operator, right)?
1303            } else if info.postfix {
1304                let span = operator.token.expect_span();
1305                let spelling = operator.token.description();
1306                let operator = PostfixOperator::from_token_tree_with_trivia(
1307                    operator.token,
1308                    operator.trailing_trivia,
1309                )
1310                .ok_or(NativeParseError::Unsupported {
1311                    syntax: spelling,
1312                    span,
1313                })?;
1314                Expr!(Op::Postfix {
1315                    operand: Box::new(left),
1316                    operator,
1317                })
1318            } else if !matches!(info.unary, UnaryAction::Error) {
1319                if operator.crossed_newline {
1320                    return Err(NativeParseError::NewlineInApplication {
1321                        span: operator.token.expect_span(),
1322                    });
1323                }
1324                let adjacency_span = operator.token.expect_span().subspan(0, 0);
1325                let right = self.parse_consumed(operator, PREC_APPLICATION_RIGHT)?;
1326                Expr!(Op::Bin::Adj {
1327                    left_operand: Box::new(left),
1328                    operator: Adj::new("", adjacency_span),
1329                    right_operand: Box::new(right),
1330                })
1331            } else {
1332                return Err(unexpected!(operator.token, "an operator"));
1333            };
1334        }
1335    }
1336
1337    /// Handles adjacency info.
1338    fn adjacency_info(&self) -> ParseInfo {
1339        let mut input = self.input.fork();
1340        let _ = input.next_significant();
1341        input.next_significant().map_or_else(
1342            || ParseInfo::stop(PREC_APPLICATION),
1343            |right| ParseInfo::binary(parse_info(&right.token).precedence, PREC_APPLICATION_RIGHT),
1344        )
1345    }
1346
1347    /// Handles only expression.
1348    fn only_expression(&self, components: Components<Component>) -> Result<Expr, NativeParseError> {
1349        if components.is_punctuated() {
1350            return Err(NativeParseError::Unexpected {
1351                found: "a sequence".into(),
1352                expected: "one expression",
1353                span: components.first.expect_span(),
1354            });
1355        }
1356        match components.first {
1357            Component::Expr(value) => Ok(*value),
1358            value => Err(NativeParseError::Unexpected {
1359                found: "an empty component".into(),
1360                expected: "one expression",
1361                span: value.expect_span(),
1362            }),
1363        }
1364    }
1365
1366    /// Handles packed content.
1367    fn packed_content(
1368        &self,
1369        components: Components<Component>,
1370    ) -> Result<PackedContent, NativeParseError> {
1371        match components.into_punctuated() {
1372            Ok(components) => Ok(ExprPack::new(components).into()),
1373            Err(Component::Expr(expression)) => Ok((*expression).into()),
1374            Err(value) => Err(NativeParseError::Unexpected {
1375                found: "an empty component".into(),
1376                expected: "one expression",
1377                span: value.expect_span(),
1378            }),
1379        }
1380    }
1381
1382    /// Handles peek.
1383    fn peek(&self) -> Lookahead {
1384        self.input.lookahead()
1385    }
1386
1387    /// Handles consume.
1388    fn consume(&mut self) -> Lookahead {
1389        self.input.consume_lookahead()
1390    }
1391
1392    /// Skips trivia.
1393    fn skip_trivia(&mut self) {
1394        self.input.skip_trivia();
1395    }
1396
1397    /// Handles at end.
1398    fn at_end(&self) -> bool {
1399        matches!(self.peek(), Lookahead::End(_))
1400    }
1401
1402    /// Handles at punctuation.
1403    fn at_punctuation(&self, spelling: &str) -> bool {
1404        matches!(
1405            self.peek(),
1406            Lookahead::Token(token)
1407                if token.token.spelling() == Some(spelling)
1408        )
1409    }
1410
1411    /// Takes punctuation.
1412    fn take_punctuation(&mut self, spelling: &str) -> Option<SignificantToken> {
1413        if !self.at_punctuation(spelling) {
1414            return None;
1415        }
1416        let Lookahead::Token(token) = self.consume() else {
1417            unreachable!("the punctuation just peeked is consumable")
1418        };
1419        Some(token)
1420    }
1421}
1422
1423/// Parses delimited.
1424fn parse_delimited(token: SignificantToken) -> Result<Expr, NativeParseError> {
1425    let group_trailing = token.trailing_trivia;
1426    let group = match token.token {
1427        TokenTree::Group(group) => group,
1428        token => return Err(unexpected!(token, "a delimited group")),
1429    };
1430    let kind = group.delim_kind();
1431    let delimiter_spans = group.delimiter().spans.clone();
1432    let mut group_contents = group.into_stream();
1433    let opening_trivia = group_contents.take_leading_trivia();
1434    let mut contents = Engine::new(group_contents);
1435    let mut muted = Vec::new();
1436    let elements = loop {
1437        let elements = contents.parse_optional_components()?;
1438        let Some(separator) = contents.take_punctuation(";") else {
1439            break elements;
1440        };
1441        let Some(elements) = elements else {
1442            return Err(unexpected!(separator.token, "a statement before `;`"));
1443        };
1444        muted.push(Statement::new(
1445            contents.packed_content(elements)?,
1446            typed_token(separator),
1447        ));
1448    };
1449    if let Lookahead::Token(token) = contents.peek() {
1450        return Err(unexpected!(token.token, "the end of the group"));
1451    }
1452
1453    let expression: Expr = match kind {
1454        DelimiterKind::Bracket => {
1455            let elements = elements
1456                .map(|elements| contents.packed_content(elements))
1457                .transpose()?;
1458            let mut value = Array::new(muted, elements);
1459            value.delimiter = typed_delimiter(delimiter_spans, opening_trivia, group_trailing);
1460            value.into()
1461        }
1462        DelimiterKind::Brace => {
1463            let elements = elements
1464                .map(|elements| contents.packed_content(elements))
1465                .transpose()?;
1466            let mut value = List::new(muted, elements);
1467            value.delimiter = typed_delimiter(delimiter_spans, opening_trivia, group_trailing);
1468            value.into()
1469        }
1470        DelimiterKind::AngleBar => {
1471            let elements = elements
1472                .map(|elements| contents.packed_content(elements))
1473                .transpose()?;
1474            let mut value = AngleBarList::new(muted, elements);
1475            value.delimiter = typed_delimiter(delimiter_spans, opening_trivia, group_trailing);
1476            value.into()
1477        }
1478        DelimiterKind::Parenthesis
1479            if !muted.is_empty() || elements.as_ref().is_some_and(Components::is_punctuated) =>
1480        {
1481            let mut value = if elements.as_ref().is_some_and(Components::is_punctuated) {
1482                Sequence::new(
1483                    muted,
1484                    elements
1485                        .map(|elements| contents.packed_content(elements))
1486                        .transpose()?,
1487                )
1488            } else {
1489                let value = elements
1490                    .map(|elements| contents.only_expression(elements))
1491                    .transpose()?;
1492                let mut value = Holder::new(muted, value.map(Box::new));
1493                value.delimiter = typed_delimiter(delimiter_spans, opening_trivia, group_trailing);
1494                return Ok(value.into());
1495            };
1496            value.delimiter = typed_delimiter(delimiter_spans, opening_trivia, group_trailing);
1497            value.into()
1498        }
1499        DelimiterKind::Parenthesis => {
1500            let value = elements
1501                .map(|elements| contents.only_expression(elements))
1502                .transpose()?;
1503            let mut value = Holder::new(Vec::new(), value.map(Box::new));
1504            value.delimiter = typed_delimiter(delimiter_spans, opening_trivia, group_trailing);
1505            value.into()
1506        }
1507    };
1508    Ok(expression)
1509}
1510
1511/// Handles typed delimiter.
1512fn typed_delimiter<D: DelimiterToken>(
1513    spans: crate::DoubleSpan,
1514    opening_trivia: TrailingTrivia,
1515    closing_trivia: TrailingTrivia,
1516) -> D {
1517    let mut delimiter = D::new(spans);
1518    *delimiter.opening_trivia_mut() = opening_trivia;
1519    *delimiter.closing_trivia_mut() = closing_trivia;
1520    delimiter
1521}
1522
1523/// Lowers prefix statement.
1524fn lower_prefix_statement(keyword: SignificantToken, value: Option<Expr>) -> Expr {
1525    if is_token!(&keyword.token, break) {
1526        Expr!(Control::Break {
1527            break_token: typed_token(keyword),
1528            value: value.map(Box::new),
1529        })
1530    } else if is_token!(&keyword.token, continue) {
1531        Expr!(Control::Continue {
1532            continue_token: typed_token(keyword),
1533            value: value.map(Box::new),
1534        })
1535    } else if is_token!(&keyword.token, return) {
1536        Expr!(Control::Return {
1537            return_token: typed_token(keyword),
1538            value: value.map(Box::new),
1539        })
1540    } else {
1541        let value = value.expect("catch, throw, and trap require a value");
1542        if is_token!(&keyword.token, catch) {
1543            Expr!(Catch {
1544                catch_token: typed_token(keyword),
1545                value: Box::new(value),
1546            })
1547        } else if is_token!(&keyword.token, throw) {
1548            Expr!(Throw {
1549                throw_token: typed_token(keyword),
1550                value: Box::new(value),
1551            })
1552        } else if is_token!(&keyword.token, trap) {
1553            Expr!(Trap {
1554                trap_token: typed_token(keyword),
1555                value: Box::new(value),
1556            })
1557        } else {
1558            unreachable!("statement actions are assigned only to statement keywords")
1559        }
1560    }
1561}
1562
1563/// Lowers atom.
1564fn lower_atom(token: SignificantToken) -> Result<Expr, NativeParseError> {
1565    match token.token {
1566        TokenTree::Ident(raw) => Ok(typed_terminal(
1567            Symbol::new(raw.text(), raw.expect_span()),
1568            token.trailing_trivia,
1569        )
1570        .into()),
1571        TokenTree::Literal(raw) => {
1572            let span = raw.expect_span();
1573            Ok(match raw.kind {
1574                LiteralKind::Integer => {
1575                    typed_terminal(IntegerLiteral::new(raw.text(), span), token.trailing_trivia)
1576                        .into()
1577                }
1578                LiteralKind::Float => {
1579                    typed_terminal(FloatLiteral::new(raw.text(), span), token.trailing_trivia)
1580                        .into()
1581                }
1582                LiteralKind::String => {
1583                    lower_string_literal(raw.text(), span, token.trailing_trivia)
1584                }
1585                LiteralKind::RawString => {
1586                    lower_raw_string_literal(raw.text(), span, token.trailing_trivia)
1587                }
1588            })
1589        }
1590        token => Err(unexpected!(token, "an expression")),
1591    }
1592}
1593
1594/// A left operand whose operator-specific structural requirements are valid.
1595enum BinaryLeft {
1596    /// The Expression alternative.
1597    Expression(Box<Expr>),
1598    /// The Assignment alternative.
1599    Assignment {
1600        /// The target.
1601        target: AssignmentTarget,
1602        /// The local.
1603        local: bool,
1604    },
1605    /// The Lambda alternative.
1606    Lambda(LambdaArguments),
1607}
1608
1609/// Internal alternatives for LambdaArguments.
1610pub(crate) enum LambdaArguments {
1611    /// The Variadic alternative.
1612    Variadic(Symbol),
1613    /// The List alternative.
1614    List(Box<Delimited<Option<ArgumentListContent>>>),
1615}
1616
1617impl BinaryLeft {
1618    /// Handles prepare.
1619    fn prepare(left: Expr, operator: &TokenTree) -> Result<Self, NativeParseError> {
1620        let span = operator.expect_span();
1621        Ok(match operator.spelling() {
1622            Some("=") => Self::Assignment {
1623                target: AssignmentTarget::parse(left, false, span)?,
1624                local: false,
1625            },
1626            Some(":=") => Self::Assignment {
1627                target: AssignmentTarget::parse(left, true, span)?,
1628                local: true,
1629            },
1630            Some("->") => Self::Lambda(
1631                lambda_arguments(left).ok_or(NativeParseError::InvalidLambdaArguments { span })?,
1632            ),
1633            _ => Self::Expression(Box::new(left)),
1634        })
1635    }
1636}
1637
1638/// A parsed expression that can occur to the left of an assignment operator.
1639enum AssignmentTarget {
1640    /// The Symbol alternative.
1641    Symbol(Symbol),
1642    /// The Operator alternative.
1643    Operator(ExprOp),
1644    /// The New alternative.
1645    New(ExprNew),
1646    /// The List alternative.
1647    List(Box<AssignmentList>),
1648}
1649
1650impl AssignmentTarget {
1651    /// Handles parse.
1652    fn parse(expression: Expr, local: bool, span: Span) -> Result<Self, NativeParseError> {
1653        match expression {
1654            Expr::Symbol(variable) => Ok(Self::Symbol(variable)),
1655            Expr::Op(expression) => Ok(Self::Operator(expression)),
1656            Expr::New(statement) if local => Ok(Self::New(statement)),
1657            expression => assignment_list(expression)
1658                .map(Box::new)
1659                .map(Self::List)
1660                .ok_or(NativeParseError::InvalidAssignmentTarget { span }),
1661        }
1662    }
1663}
1664
1665/// Lowers binary.
1666fn lower_binary(
1667    left: BinaryLeft,
1668    operator: SignificantToken,
1669    right: Expr,
1670) -> Result<Expr, NativeParseError> {
1671    let span = operator.token.expect_span();
1672    let spelling = operator
1673        .token
1674        .spelling()
1675        .expect("binary actions are assigned only to spelled tokens");
1676    match left {
1677        BinaryLeft::Assignment { target, local } => {
1678            Ok(lower_assignment(target, operator, right, local))
1679        }
1680        BinaryLeft::Lambda(arguments) => Ok(match arguments {
1681            LambdaArguments::Variadic(argument) => Expr!(Lambda::Variadic {
1682                argument,
1683                operator: typed_token(operator),
1684                body: Box::new(right),
1685            }),
1686            LambdaArguments::List(arguments) => Expr!(Lambda::List {
1687                arguments: *arguments,
1688                operator: typed_token(operator),
1689                body: Box::new(right),
1690            }),
1691        }),
1692        BinaryLeft::Expression(left) if spelling == "<-" => Ok(Expr!(Assign::Evaluated {
1693            evaluated_domain: left,
1694            operator: typed_token(operator),
1695            value: Box::new(right),
1696        })),
1697        BinaryLeft::Expression(left) if spelling == "=>" => Ok(Expr!(Option {
1698            key: left,
1699            operator: typed_token(operator),
1700            value: Box::new(right),
1701        })),
1702        BinaryLeft::Expression(left)
1703            if GENERATED_AUGMENTED_OPERATOR_SPELLINGS.contains(&spelling) =>
1704        {
1705            let operator = AugmentedOperator::from_token_tree_with_trivia(
1706                operator.token,
1707                operator.trailing_trivia,
1708            )
1709            .expect("the augmented operator table and category have the same source");
1710            Ok(Expr!(Assign::Augmented {
1711                target: left,
1712                operator,
1713                value: Box::new(right),
1714            }))
1715        }
1716        BinaryLeft::Expression(left) if matches!(spelling, "." | ".?") => Ok(match spelling {
1717            "." => Expr!(Op::Bin::Member::Dot {
1718                receiver: left,
1719                operator: typed_token::<Token![.]>(operator),
1720                member: Box::new(right),
1721            }),
1722            ".?" => Expr!(Op::Bin::Member::Optional {
1723                receiver: left,
1724                operator: typed_token::<Token![.?]>(operator),
1725                member: Box::new(right),
1726            }),
1727            _ => unreachable!(),
1728        }),
1729        BinaryLeft::Expression(left) if spelling == "#" => Ok(Expr!(Op::Bin::Index {
1730            receiver: left,
1731            operator: typed_token(operator),
1732            index: Box::new(right),
1733        })),
1734        BinaryLeft::Expression(left) => {
1735            let spelling = spelling.to_owned();
1736            let operator = BinaryOperator::from_token_tree_with_trivia(
1737                operator.token,
1738                operator.trailing_trivia,
1739            )
1740            .ok_or(NativeParseError::Unsupported {
1741                syntax: spelling,
1742                span,
1743            })?;
1744            Ok(Expr!(Op::Bin::Regular {
1745                left_operand: left,
1746                operator,
1747                right_operand: Box::new(right),
1748            }))
1749        }
1750    }
1751}
1752
1753/// Lowers assignment.
1754fn lower_assignment(
1755    target: AssignmentTarget,
1756    operator: SignificantToken,
1757    right: Expr,
1758    local: bool,
1759) -> Expr {
1760    match (local, target) {
1761        (false, AssignmentTarget::Symbol(variable)) => {
1762            Expr!(Assign::Simple::Global {
1763                variable,
1764                operator: typed_token(operator),
1765                value: Box::new(right),
1766            })
1767        }
1768        (true, AssignmentTarget::Symbol(variable)) => {
1769            Expr!(Assign::Simple::Local {
1770                variable,
1771                operator: typed_token(operator),
1772                value: Box::new(right),
1773            })
1774        }
1775        (false, AssignmentTarget::Operator(argument_expr)) => {
1776            Expr!(Assign::Op {
1777                argument_expr,
1778                operator: typed_token(operator),
1779                value_expr: Box::new(right),
1780            })
1781        }
1782        (true, AssignmentTarget::Operator(ExprOp::Bin(ExprOpBin::Adj(application)))) => {
1783            let (typical_value, function) = installation_value(right);
1784            Expr!(Assign::Install::Method {
1785                method: application.left_operand,
1786                operator: application.operator,
1787                signature: application.right_operand,
1788                assign_op: typed_token(operator),
1789                typical_value,
1790                function: Box::new(function),
1791            })
1792        }
1793        (true, AssignmentTarget::Operator(domain_expr)) => {
1794            let (typical_value, function) = installation_value(right);
1795            Expr!(Assign::Install::Op {
1796                domain_expr,
1797                assign_op: typed_token(operator),
1798                typical_value,
1799                function: Box::new(function),
1800            })
1801        }
1802        (true, AssignmentTarget::New(new_statement)) => {
1803            Expr!(Assign::Install::New {
1804                new_statement,
1805                operator: typed_token(operator),
1806                function: Box::new(right),
1807            })
1808        }
1809        (local, AssignmentTarget::List(argument_list)) => {
1810            if local {
1811                Expr!(Assign::Parallel::Local {
1812                    argument_list,
1813                    operator: typed_token(operator),
1814                    value: Box::new(right),
1815                })
1816            } else {
1817                Expr!(Assign::Parallel::Global {
1818                    argument_list,
1819                    operator: typed_token(operator),
1820                    value: Box::new(right),
1821                })
1822            }
1823        }
1824        (false, AssignmentTarget::New(_)) => {
1825            unreachable!("global assignment preparation rejects new statements")
1826        }
1827    }
1828}
1829
1830/// Handles installation value.
1831pub(crate) fn installation_value(value: Expr) -> (Option<TypeAnnotation>, Expr) {
1832    match value {
1833        Expr::Option(value) => (
1834            Some(TypeAnnotation::new(value.key, value.operator)),
1835            *value.value,
1836        ),
1837        value => (None, value),
1838    }
1839}
1840
1841/// Parses cell stream.
1842fn parse_cell_stream(cells: CellStream) -> Result<SourceFile, NativeParseError> {
1843    let mut elements = Vec::new();
1844    let eof_span = cells.physical_eof();
1845    let mut comments = CommentTrivia::default();
1846    let mut cells = cells.into_iter().peekable();
1847    while let Some(cell) = cells.next() {
1848        if cell.is_empty() {
1849            comments.append(CommentTrivia::take_inner(
1850                &mut cell.into_parser_token_stream(),
1851            ));
1852            continue;
1853        }
1854        let eoc = cells
1855            .peek()
1856            .and_then(cell_start_span)
1857            .unwrap_or_else(|| end_span(&cell));
1858        if let Some(element) = parse_raw_cell_at(cell, eoc)? {
1859            elements.push(element);
1860        }
1861    }
1862    let mut source_file = SourceFile::new(elements, EOF::new("", eof_span));
1863    source_file.comments = comments;
1864    Ok(source_file)
1865}
1866
1867/// Handles tokenize for native parser.
1868fn tokenize_for_native_parser(tokens: TokenStream) -> Result<CellStream, NativeParseError> {
1869    match tokens.to_cell_stream() {
1870        Ok(cells) => Ok(cells),
1871        Err(tokenize_error) => {
1872            let incomplete = frame_recovering(tokens).incomplete;
1873            if let Some(cell) = incomplete
1874                && let Err(parse_error) = parse_raw_cell(cell)
1875            {
1876                return Err(parse_error);
1877            }
1878            Err(NativeParseError::Tokenize(tokenize_error))
1879        }
1880    }
1881}
1882
1883/// Parses raw cell.
1884pub(crate) fn parse_raw_cell(
1885    tokens: CellTokenStream,
1886) -> Result<Option<crate::nodes::Cell>, NativeParseError> {
1887    let eoc = end_span(&tokens);
1888    parse_raw_cell_at(tokens, eoc)
1889}
1890
1891/// Parses raw cell at.
1892fn parse_raw_cell_at(
1893    tokens: CellTokenStream,
1894    eoc: Span,
1895) -> Result<Option<crate::nodes::Cell>, NativeParseError> {
1896    let ends_with_semicolon = ends_with_cell_semicolon(&tokens);
1897    let mut tokens = tokens.into_parser_token_stream();
1898    let comments = CommentTrivia::take_from_cell(&mut tokens);
1899    let semicolon = ends_with_semicolon
1900        .then(|| tokens.take_final_punctuation(";"))
1901        .flatten()
1902        .map(|(punctuation, trailing_trivia)| {
1903            <Token![;] as Token>::from_token_tree_with_trivia(
1904                TokenTree::Punct(punctuation),
1905                trailing_trivia,
1906            )
1907            .expect("a semicolon punctuation token lowers to Token![;]")
1908        });
1909    let mut cell = Engine::new(tokens).parse_cell(semicolon, eoc)?;
1910    if let Some(cell) = &mut cell {
1911        cell.comments = comments;
1912    }
1913    Ok(cell)
1914}
1915
1916/// Handles cell start span.
1917fn cell_start_span(tokens: &CellTokenStream) -> Option<Span> {
1918    let token = tokens.iter().next()?;
1919    let span = token
1920        .leading_trivia()
1921        .first()
1922        .map_or_else(|| token.span(), Spanned::span);
1923    span.start().map(|start| span.at(start))
1924}
1925
1926impl Parse for Expr {
1927    fn parse(input: &mut ParseStream) -> Result<Self, TokenParseError> {
1928        let tokens = input.by_ref().collect::<TokenStream>();
1929        let mut engine = Engine::new(tokens);
1930        engine.skip_trivia();
1931        let value = engine
1932            .parse_required(PREC_CLOSER)
1933            .map_err(token_parse_error)?;
1934        engine.skip_trivia();
1935        match engine.peek() {
1936            Lookahead::End(_) => Ok(value),
1937            Lookahead::Token(token) => Err(TokenParseError::TrailingToken {
1938                found: token.token.description(),
1939                span: token.token.expect_span(),
1940            }),
1941        }
1942    }
1943}
1944
1945impl Parse for SourceFile {
1946    fn parse(input: &mut ParseStream) -> Result<Self, TokenParseError> {
1947        let tokens = input.by_ref().collect();
1948        tokenize_for_native_parser(tokens)
1949            .and_then(parse_cell_stream)
1950            .map_err(token_parse_error)
1951    }
1952}
1953
1954/// Handles token parse error.
1955fn token_parse_error(error: NativeParseError) -> TokenParseError {
1956    let span = error.expect_span();
1957    TokenParseError::Syntax {
1958        message: error.to_string(),
1959        span,
1960    }
1961}
1962
1963/// Handles parsing spelling.
1964fn parsing_spelling(token: &TokenTree) -> &str {
1965    token.spelling().map_or("", canonical_word_spelling)
1966}
1967
1968/// Handles typed token.
1969fn typed_token<T: Token>(token: SignificantToken) -> T {
1970    let spelling = token.token.description();
1971    T::from_token_tree_with_trivia(token.token, token.trailing_trivia)
1972        .unwrap_or_else(|| panic!("`{spelling}` cannot be lowered to `{}`", T::SPELLING))
1973}
1974
1975/// Handles typed terminal.
1976fn typed_terminal<T: Terminal>(mut terminal: T, trailing_trivia: TrailingTrivia) -> T {
1977    *terminal.trailing_trivia_mut() = trailing_trivia;
1978    terminal
1979}
1980
1981/// Handles empty span at.
1982fn empty_span_at(lookahead: &Span) -> Span {
1983    lookahead.subspan(0, 0)
1984}
1985
1986/// Lowers string literal.
1987fn lower_string_literal(text: &str, span: Span, trailing_trivia: TrailingTrivia) -> Expr {
1988    let body = &text[1..text.len() - 1];
1989    let mut elements = Vec::new();
1990    let mut content_start = 0;
1991    let mut cursor = 0;
1992
1993    while cursor < body.len() {
1994        if body.as_bytes()[cursor] != b'\\' {
1995            cursor += 1;
1996            continue;
1997        }
1998        if content_start < cursor {
1999            elements.push(StringElement::Content(StringContent::new(
2000                &body[content_start..cursor],
2001                span.subspan(content_start + 1, cursor + 1),
2002            )));
2003        }
2004        let escape_end = match body.as_bytes()[cursor + 1] {
2005            b'x' => cursor + 4,
2006            b'u' => cursor + 6,
2007            b'0'..=b'7' => {
2008                let mut end = cursor + 2;
2009                while end < body.len()
2010                    && end < cursor + 4
2011                    && body.as_bytes()[end].is_ascii_digit()
2012                    && body.as_bytes()[end] < b'8'
2013                {
2014                    end += 1;
2015                }
2016                end
2017            }
2018            _ => cursor + 2,
2019        };
2020        elements.push(StringElement::Escape(EscapeSequence::new(
2021            &body[cursor..escape_end],
2022            span.subspan(cursor + 1, escape_end + 1),
2023        )));
2024        cursor = escape_end;
2025        content_start = cursor;
2026    }
2027    if content_start < body.len() {
2028        elements.push(StringElement::Content(StringContent::new(
2029            &body[content_start..],
2030            span.subspan(content_start + 1, text.len() - 1),
2031        )));
2032    }
2033    typed_terminal(StringLiteral::new(elements, span), trailing_trivia).into()
2034}
2035
2036/// Lowers raw string literal.
2037fn lower_raw_string_literal(text: &str, span: Span, trailing_trivia: TrailingTrivia) -> Expr {
2038    let body = &text[3..text.len() - 3];
2039    let mut elements = Vec::new();
2040    let mut content_start = 0;
2041    let mut cursor = 0;
2042
2043    while cursor + 1 < body.len() {
2044        if &body.as_bytes()[cursor..cursor + 2] != b"//" {
2045            cursor += 1;
2046            continue;
2047        }
2048        if content_start < cursor {
2049            elements.push(RawStringElement::Content(RawStringContent::new(
2050                &body[content_start..cursor],
2051                span.subspan(content_start + 3, cursor + 3),
2052            )));
2053        }
2054        elements.push(RawStringElement::Escape(EscapeSequence::new(
2055            "//",
2056            span.subspan(cursor + 3, cursor + 5),
2057        )));
2058        cursor += 2;
2059        content_start = cursor;
2060    }
2061    if content_start < body.len() {
2062        elements.push(RawStringElement::Content(RawStringContent::new(
2063            &body[content_start..],
2064            span.subspan(content_start + 3, text.len() - 3),
2065        )));
2066    }
2067    typed_terminal(RawStringLiteral::new(elements, span), trailing_trivia).into()
2068}
2069
2070/// Handles collection contents.
2071fn collection_contents(expression: Expr) -> Option<(crate::Delimiter, Option<PackedContent>)> {
2072    match expression {
2073        Expr::Collection(ExprCollection::Sequence(value)) if value.statements.is_empty() => {
2074            Some((DelimiterValue::delimiter(&value.delimiter), value.elements))
2075        }
2076        Expr::Collection(ExprCollection::List(value)) if value.statements.is_empty() => {
2077            Some((DelimiterValue::delimiter(&value.delimiter), value.elements))
2078        }
2079        Expr::Collection(ExprCollection::Array(value)) if value.statements.is_empty() => {
2080            Some((DelimiterValue::delimiter(&value.delimiter), value.elements))
2081        }
2082        Expr::Collection(ExprCollection::AngleBar(value)) if value.statements.is_empty() => {
2083            Some((DelimiterValue::delimiter(&value.delimiter), value.elements))
2084        }
2085        Expr::Holder(value) if value.muted.is_empty() => {
2086            let elements = value.value.map(|value| (*value).into());
2087            Some((DelimiterValue::delimiter(&value.delimiter), elements))
2088        }
2089        _ => None,
2090    }
2091}
2092
2093/// Handles assignment list.
2094pub(crate) fn assignment_list(expression: Expr) -> Option<AssignmentList> {
2095    let (delimiter, elements) = collection_contents(expression)?;
2096    let contents = match elements {
2097        Some(elements) => {
2098            let components = packed_components(elements).map(assignment_argument)?;
2099            Some(match components.into_punctuated() {
2100                Ok(arguments) => AssignmentListContent!(Pack { arguments }),
2101                Err(argument) => argument.into(),
2102            })
2103        }
2104        None => None,
2105    };
2106    Some(AssignmentList::new(Delimited::new(delimiter, contents)))
2107}
2108
2109/// Handles assignment argument.
2110fn assignment_argument(component: Component) -> Option<AssignmentArgument> {
2111    match component {
2112        Component::Empty(value) => Some(AssignmentArgument::Empty(value)),
2113        Component::Expr(value) => match *value {
2114            Expr::Symbol(value) => Some(AssignmentArgument::Symbol(value)),
2115            Expr::Op(value) => Some(AssignmentArgument::Op(value)),
2116            value => assignment_list(value).map(Into::into),
2117        },
2118    }
2119}
2120
2121/// Handles expr pack symbols.
2122fn expr_pack_symbols(elements: ExprPack) -> Option<Punctuated<Symbol>> {
2123    elements
2124        .pack
2125        .try_map(
2126            |component| match component {
2127                Component::Expr(value) => match *value {
2128                    Expr::Symbol(value) => Ok(value),
2129                    _ => Err(()),
2130                },
2131                Component::Empty(_) => Err(()),
2132            },
2133            Ok,
2134        )
2135        .ok()
2136}
2137
2138/// Handles packed components.
2139fn packed_components(content: PackedContent) -> Components<Component> {
2140    match content {
2141        PackedContent::Expr(expression) => Components {
2142            first: Component::Expr(expression),
2143            rest: Vec::new(),
2144        },
2145        PackedContent::Pack(pack) => Components::from_punctuated(pack.pack),
2146    }
2147}
2148
2149/// Handles lambda arguments.
2150pub(crate) fn lambda_arguments(expression: Expr) -> Option<LambdaArguments> {
2151    match expression {
2152        Expr::Symbol(value) => Some(LambdaArguments::Variadic(value)),
2153        expression => {
2154            let (delimiter, elements) = collection_contents(expression)?;
2155            let arguments = match elements {
2156                Some(PackedContent::Expr(expression)) => match *expression {
2157                    Expr::Symbol(value) => Some(ArgumentListContent::Symbol(value)),
2158                    _ => return None,
2159                },
2160                Some(PackedContent::Pack(pack)) => Some(ArgumentListContent!(Pack {
2161                    arguments: expr_pack_symbols(pack)?,
2162                })),
2163                None => None,
2164            };
2165            Some(LambdaArguments::List(Box::new(Delimited::new(
2166                delimiter, arguments,
2167            ))))
2168        }
2169    }
2170}
2171
2172/// The rule declared for a spelling, found in the generated table.
2173fn token_parse_rule(spelling: &str) -> Option<TokenParseRule> {
2174    TOKEN_PARSE_RULES
2175        .binary_search_by_key(&spelling, |(declared, _)| *declared)
2176        .ok()
2177        .map(|index| TOKEN_PARSE_RULES[index].1)
2178}
2179
2180/// Handles keyword action.
2181fn keyword_action(spelling: &str) -> Option<UnaryAction> {
2182    Some(match spelling {
2183        "break" | "continue" | "return" | "catch" | "throw" | "trap" => UnaryAction::Statement,
2184        "if" | "while" | "try" | "for" | "new" => UnaryAction::Control,
2185        "TEST" | "time" | "timing" | "elapsedTime" | "elapsedTiming" | "breakpoint" | "profile"
2186        | "shield" | "step" | "finish" => UnaryAction::Debug,
2187        "symbol" | "global" | "local" | "threadLocal" | "threadVariable" => UnaryAction::Quote,
2188        _ => return None,
2189    })
2190}
2191
2192/// Parses info.
2193fn parse_info(token: &TokenTree) -> ParseInfo {
2194    if matches!(token, TokenTree::Punct(punctuation) if punctuation.text().is_empty()) {
2195        return ParseInfo::binary(PREC_APPLICATION, PREC_APPLICATION_RIGHT);
2196    }
2197    if let TokenTree::Group(group) = token {
2198        return match group.delim_kind() {
2199            DelimiterKind::Bracket | DelimiterKind::AngleBar => {
2200                ParseInfo::delimiter(PREC_COLLECTION)
2201            }
2202            DelimiterKind::Parenthesis | DelimiterKind::Brace => {
2203                ParseInfo::delimiter(PREC_APPLICATION)
2204            }
2205        };
2206    }
2207
2208    let text = parsing_spelling(token);
2209    if let Some(rule) = token_parse_rule(text) {
2210        let mut info = ParseInfo::from(rule);
2211        if let Some(action) = keyword_action(text) {
2212            info.unary = action;
2213        }
2214        return info;
2215    }
2216
2217    match token {
2218        TokenTree::Ident(_) | TokenTree::Literal(_) => ParseInfo::atom(PREC_APPLICATION),
2219        _ => ParseInfo::stop(PREC_APPLICATION),
2220    }
2221}
2222
2223#[cfg(test)]
2224mod tests {
2225    use super::{NativeCellParser, NativeCellState};
2226    use crate::cell_stream::frame_recovering;
2227    use crate::{Spanned, lex_str};
2228
2229    /// Cell boundaries are decided here, from the flat stream, using the same
2230    /// operator/clause/quote state the grammar needs. Verified against M2
2231    /// v1.26.05 for each case.
2232    #[test]
2233    fn cells_use_operator_clause_and_delimiter_state() {
2234        fn cells(source: &str) -> usize {
2235            let framed = frame_recovering(lex_str(source).unwrap());
2236            framed.cells.len() + usize::from(framed.incomplete.is_some())
2237        }
2238
2239        assert_eq!(cells("1\n2"), 2);
2240        assert_eq!(cells("1 +\n2"), 1);
2241        assert_eq!(cells("not\n1"), 1);
2242        assert_eq!(cells("1!\n2"), 2);
2243        assert_eq!(cells("if condition\nthen value"), 1);
2244        assert_eq!(cells("if condition\nthen value\nnext"), 2);
2245        assert_eq!(cells("symbol if\nnext"), 2);
2246        assert_eq!(cells("symbol +\nnext"), 2);
2247        assert_eq!(cells("1 -* comment\n*- 2"), 2);
2248        assert_eq!(cells("1 + -* comment\n*- 2"), 1);
2249        assert_eq!(cells("1;2"), 2);
2250        // A `;` inside brackets is an ordinary token, so the group stays one
2251        // cell and its contents are untouched by the embedding.
2252        assert_eq!(cells("(1\n2;3)"), 1);
2253        // The quoted `;` is data, not a boundary.
2254        assert_eq!(cells("symbol ;"), 1);
2255    }
2256
2257    #[test]
2258    fn invalid_binary_left_side_wins_over_a_missing_right_operand() {
2259        for (source, state, diagnostic, diagnostic_text) in [
2260            (
2261                "1 + 1 =",
2262                NativeCellState::Incomplete,
2263                "expected an operand after `=`, found end of input",
2264                "=",
2265            ),
2266            (
2267                "2 =",
2268                NativeCellState::Invalid,
2269                "invalid assignment target",
2270                "=",
2271            ),
2272            (
2273                "(x, y) ->",
2274                NativeCellState::Incomplete,
2275                "expected an operand after `->`, found end of input",
2276                "->",
2277            ),
2278            (
2279                "(x + y) ->",
2280                NativeCellState::Invalid,
2281                "invalid lambda argument list",
2282                "->",
2283            ),
2284        ] {
2285            let mut parser = NativeCellParser::new();
2286            assert_eq!(parser.push_line(source), state, "source: `{source}`");
2287            let error = parser
2288                .parse_error()
2289                .unwrap_or_else(|| panic!("expected a diagnostic for `{source}`"));
2290            assert_eq!(error.to_string(), diagnostic, "source: `{source}`");
2291            assert_eq!(error.span().text(), Some(diagnostic_text));
2292        }
2293    }
2294}