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, LeadingTrivia, LexError, LexErrorKind, LiteralKind, Parse,
18    ParseStream, Parser, Punctuated, Recovered, Span, Spanned, Terminal, Token, TokenParseError,
19    TokenStream, TokenTree, Tokenize, TrailingTrivia, Trivia, 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)]
539/// Binding powers and unary behavior for one parser token.
540struct ParseInfo {
541    /// The precedence.
542    precedence: u8,
543    /// The binary strength.
544    binary_strength: Option<u8>,
545    /// The unary strength.
546    unary_strength: Option<u8>,
547    /// The unary.
548    unary: UnaryAction,
549    /// The postfix.
550    postfix: bool,
551}
552
553impl From<TokenParseRule> for ParseInfo {
554    fn from(rule: TokenParseRule) -> Self {
555        match rule {
556            TokenParseRule::Precedence(precedence) => Self::stop(precedence),
557            TokenParseRule::Postfix(precedence) => Self::postfix(precedence),
558            TokenParseRule::Binary(precedence, strength) => Self::binary(precedence, strength),
559            TokenParseRule::Prefix(precedence, strength) => {
560                Self::unary(precedence, UnaryAction::Prefix, strength)
561            }
562            TokenParseRule::PrefixBinary(precedence, binary, unary) => {
563                Self::prefix_binary(precedence, binary, unary)
564            }
565            TokenParseRule::Unary(precedence, strength) => {
566                Self::unary(precedence, UnaryAction::Error, strength)
567            }
568        }
569    }
570}
571
572impl ParseInfo {
573    /// Handles atom.
574    const fn atom(precedence: u8) -> Self {
575        Self {
576            precedence,
577            binary_strength: None,
578            unary_strength: None,
579            unary: UnaryAction::Atom,
580            postfix: false,
581        }
582    }
583
584    /// Handles binary.
585    const fn binary(precedence: u8, strength: u8) -> Self {
586        Self {
587            precedence,
588            binary_strength: Some(strength),
589            unary_strength: None,
590            unary: UnaryAction::Error,
591            postfix: false,
592        }
593    }
594
595    /// Handles prefix binary.
596    const fn prefix_binary(precedence: u8, binary_strength: u8, unary_strength: u8) -> Self {
597        Self {
598            precedence,
599            binary_strength: Some(binary_strength),
600            unary_strength: Some(unary_strength),
601            unary: UnaryAction::Prefix,
602            postfix: false,
603        }
604    }
605
606    /// A token whose action in unary position is to introduce something that
607    /// binds at `strength`: a statement, a control form, a timing form, or a
608    /// quoted name.
609    const fn unary(precedence: u8, unary: UnaryAction, strength: u8) -> Self {
610        Self {
611            precedence,
612            binary_strength: None,
613            unary_strength: Some(strength),
614            unary,
615            postfix: false,
616        }
617    }
618
619    /// Handles postfix.
620    const fn postfix(precedence: u8) -> Self {
621        Self {
622            precedence,
623            binary_strength: None,
624            unary_strength: None,
625            unary: UnaryAction::Error,
626            postfix: true,
627        }
628    }
629
630    /// Handles delimiter.
631    const fn delimiter(precedence: u8) -> Self {
632        Self {
633            precedence,
634            binary_strength: None,
635            unary_strength: Some(PREC_CLOSER),
636            unary: UnaryAction::Delimiter,
637            postfix: false,
638        }
639    }
640
641    /// Handles stop.
642    const fn stop(precedence: u8) -> Self {
643        Self {
644            precedence,
645            binary_strength: None,
646            unary_strength: None,
647            unary: UnaryAction::Error,
648            postfix: false,
649        }
650    }
651}
652
653/// Internal state for Engine.
654struct Engine {
655    /// The input.
656    input: ParseStream,
657}
658
659/// Internal state for Components.
660struct Components<T> {
661    /// The first.
662    first: T,
663    /// The rest.
664    rest: Vec<(Token![,], T)>,
665}
666
667impl<T> Components<T> {
668    /// Creates the value from punctuated.
669    fn from_punctuated(values: Punctuated<T>) -> Self {
670        let (pair, rest) = values.into_parts();
671        let (first, punctuation, second) = pair.into_parts();
672        let mut pairs = Vec::with_capacity(rest.len() + 1);
673        pairs.push((punctuation, second));
674        pairs.extend(rest);
675        Self { first, rest: pairs }
676    }
677
678    /// Returns whether the value is punctuated.
679    fn is_punctuated(&self) -> bool {
680        !self.rest.is_empty()
681    }
682
683    /// Converts the value into punctuated.
684    fn into_punctuated(self) -> Result<Punctuated<T>, T> {
685        let mut rest = self.rest.into_iter();
686        let Some((punctuation, second)) = rest.next() else {
687            return Err(self.first);
688        };
689        let mut values = Punctuated::new(self.first, punctuation, second);
690        for (punctuation, value) in rest {
691            values.push(punctuation, value);
692        }
693        Ok(values)
694    }
695
696    /// Handles map.
697    fn map<U>(self, mut map: impl FnMut(T) -> Option<U>) -> Option<Components<U>> {
698        Some(Components {
699            first: map(self.first)?,
700            rest: self
701                .rest
702                .into_iter()
703                .map(|(punctuation, value)| Some((punctuation, map(value)?)))
704                .collect::<Option<Vec<_>>>()?,
705        })
706    }
707}
708
709impl Engine {
710    /// Creates a new value.
711    fn new(tokens: TokenStream) -> Self {
712        Self {
713            input: ParseStream::new(tokens),
714        }
715    }
716
717    /// Parses cell.
718    fn parse_cell(
719        mut self,
720        semicolon: Option<Token![;]>,
721        eoc_span: Span,
722    ) -> Result<Option<crate::nodes::Cell>, NativeParseError> {
723        self.skip_trivia();
724        if matches!(self.peek(), Lookahead::End(_)) {
725            return match semicolon {
726                None => Ok(None),
727                Some(semicolon) => Err(NativeParseError::Unexpected {
728                    found: ";".into(),
729                    expected: "a statement before `;`",
730                    span: semicolon.expect_span(),
731                }),
732            };
733        }
734
735        let components = self.parse_components()?;
736
737        if let Lookahead::Token(token) = self.peek() {
738            return Err(unexpected!(token.token, "the end of the cell"));
739        }
740
741        let eoc = EOC::new("", eoc_span);
742        Ok(Some(crate::nodes::Cell::new(
743            self.packed_content(components)?,
744            semicolon,
745            eoc,
746        )))
747    }
748
749    /// Parses components.
750    fn parse_components(&mut self) -> Result<Components<Component>, NativeParseError> {
751        let first = if self.at_punctuation(",") {
752            Component::Empty(Empty::new("", empty_span_at(&self.peek().expect_span())))
753        } else {
754            self.parse_required(PREC_COMMA)?.into()
755        };
756        let mut rest = Vec::new();
757
758        while let Some(comma) = self.take_punctuation(",") {
759            let next = if self.at_end() || self.at_punctuation(";") || self.at_punctuation(",") {
760                Component::Empty(Empty::new("", empty_span_at(&self.peek().expect_span())))
761            } else {
762                self.parse_required(PREC_COMMA)?.into()
763            };
764            rest.push((typed_token(comma), next));
765        }
766
767        Ok(Components { first, rest })
768    }
769
770    /// Parses optional components.
771    fn parse_optional_components(
772        &mut self,
773    ) -> Result<Option<Components<Component>>, NativeParseError> {
774        if self.at_end() || self.at_punctuation(";") {
775            Ok(None)
776        } else {
777            self.parse_components().map(Some)
778        }
779    }
780
781    /// Parses required.
782    fn parse_required(&mut self, level: u8) -> Result<Expr, NativeParseError> {
783        let token = match self.consume() {
784            Lookahead::Token(token) => token,
785            Lookahead::End(span) => {
786                return Err(NativeParseError::MissingOperand {
787                    operator: "end of input".into(),
788                    span,
789                });
790            }
791        };
792        self.parse_consumed(token, level)
793    }
794
795    /// Parses nullable.
796    fn parse_nullable(&mut self, level: u8) -> Result<Option<Expr>, NativeParseError> {
797        let lookahead = self.peek();
798        let Lookahead::Token(token) = lookahead else {
799            return Ok(None);
800        };
801        if parse_info(&token.token).precedence <= level {
802            return Ok(None);
803        }
804        let Lookahead::Token(token) = self.consume() else {
805            unreachable!("the token just peeked is consumable")
806        };
807        self.parse_consumed(token, level).map(Some)
808    }
809
810    /// Parses consumed.
811    fn parse_consumed(
812        &mut self,
813        token: SignificantToken,
814        level: u8,
815    ) -> Result<Expr, NativeParseError> {
816        let info = parse_info(&token.token);
817        let result = match info.unary {
818            UnaryAction::Atom => lower_atom(token)?,
819            UnaryAction::Prefix => {
820                let strength = info.unary_strength.expect("prefix operators have U");
821                let operand = self.parse_required(level.max(strength))?;
822                let span = token.token.expect_span();
823                let spelling = token.token.description();
824                let operator =
825                    PrefixOperator::from_token_tree_with_trivia(token.token, token.trailing_trivia)
826                        .ok_or({
827                            NativeParseError::Unsupported {
828                                syntax: spelling,
829                                span,
830                            }
831                        })?;
832                Expr!(Op::Prefix {
833                    operator,
834                    operand: Box::new(operand),
835                })
836            }
837            UnaryAction::Statement => {
838                let strength = info
839                    .unary_strength
840                    .expect("prefix statements have a unary binding strength");
841                let operand = if is_token!(&token.token, break)
842                    || is_token!(&token.token, continue)
843                    || is_token!(&token.token, return)
844                {
845                    self.parse_nullable(level.max(strength))?
846                } else {
847                    self.parse_required(level.max(strength))
848                        .map_err(|error| error.missing_operand_for(&token.token))?
849                        .into()
850                };
851                lower_prefix_statement(token, operand)
852            }
853            UnaryAction::Control => {
854                if is_token!(&token.token, if) {
855                    self.parse_if_statement(token)?
856                } else if is_token!(&token.token, for) {
857                    self.parse_for_loop(token)?
858                } else if is_token!(&token.token, while) {
859                    self.parse_while_loop(token)?
860                } else if is_token!(&token.token, try) {
861                    self.parse_try_statement(token)?
862                } else if is_token!(&token.token, new) {
863                    self.parse_new_statement(token)?
864                } else {
865                    unreachable!("control actions are assigned only to control keywords")
866                }
867            }
868            UnaryAction::Debug => self.parse_debug_clause(token)?,
869            UnaryAction::Delimiter => parse_delimited(token)?,
870            UnaryAction::Quote => {
871                let operator = token.token.description();
872                let quoted = match self.consume() {
873                    Lookahead::Token(quoted) => quoted,
874                    Lookahead::End(span) => {
875                        return Err(NativeParseError::MissingOperand { operator, span });
876                    }
877                };
878                let quoted_span = quoted.token.expect_span();
879                let Some(quoted_text) = quoted.token.spelling().map(str::to_owned) else {
880                    return Err(unexpected!(quoted.token, "a quoted token"));
881                };
882                let quoted = typed_terminal(
883                    Symbol::new(quoted_text, quoted_span),
884                    quoted.trailing_trivia,
885                );
886                if is_token!(&token.token, symbol) {
887                    Expr!(Quote::Symbol {
888                        specifier: typed_token(token),
889                        symbol: quoted,
890                    })
891                } else if is_token!(&token.token, local) {
892                    Expr!(Quote::Local {
893                        specifier: typed_token(token),
894                        symbol: quoted,
895                    })
896                } else if is_token!(&token.token, global) {
897                    Expr!(Quote::Global {
898                        specifier: typed_token(token),
899                        symbol: quoted,
900                    })
901                } else if is_token!(&token.token, threadVariable) {
902                    Expr!(Quote::ThreadVariable {
903                        specifier: typed_token(token),
904                        symbol: quoted,
905                    })
906                } else if is_token!(&token.token, threadLocal) {
907                    Expr!(Quote::ThreadLocal {
908                        specifier: typed_token(token),
909                        symbol: quoted,
910                    })
911                } else {
912                    unreachable!("quote actions are assigned only to quote specifiers")
913                }
914            }
915            UnaryAction::Error => {
916                return Err(unexpected!(token.token, "an expression"));
917            }
918        };
919        self.accumulate(result, level)
920    }
921
922    /// Parses if statement.
923    fn parse_if_statement(&mut self, keyword: SignificantToken) -> Result<Expr, NativeParseError> {
924        let condition = self.required_clause_expression(PREC_CONTROL, &keyword.token)?;
925        let then_keyword = self.consume_exact("then")?;
926        let then_value = self.required_clause_expression(PREC_CONTROL, &then_keyword.token)?;
927        let then_clause = ThenClause::new(typed_token(then_keyword), Box::new(then_value));
928        let else_clause = self
929            .take_exact("else")
930            .map(|else_keyword| {
931                let value = self.required_clause_expression(PREC_CONTROL, &else_keyword.token)?;
932                Ok::<_, NativeParseError>(ElseClause::new(
933                    typed_token(else_keyword),
934                    Box::new(value),
935                ))
936            })
937            .transpose()?;
938        Ok(Expr!(If {
939            if_token: typed_token(keyword),
940            condition: Box::new(condition),
941            then_clause,
942            else_clause,
943        }))
944    }
945
946    /// Parses for loop.
947    fn parse_for_loop(&mut self, keyword: SignificantToken) -> Result<Expr, NativeParseError> {
948        let variable = self.consume_symbol("a loop variable")?;
949
950        enum Domain {
951            /// The Bare alternative.
952            Bare,
953            /// The Range alternative.
954            Range(Option<RangeBoundFrom>, Option<RangeBoundTo>),
955            /// The In alternative.
956            In(SignificantToken, Box<Expr>),
957        }
958        let domain = if let Some(token) = self.take_exact("in") {
959            let collection = self.required_clause_expression(PREC_LOOP_CLAUSE, &token.token)?;
960            Domain::In(token, Box::new(collection))
961        } else {
962            let lower_bound = self
963                .take_exact("from")
964                .map(|token| {
965                    let value = self.required_clause_expression(PREC_LOOP_CLAUSE, &token.token)?;
966                    Ok::<_, NativeParseError>(RangeBoundFrom::new(
967                        typed_token(token),
968                        Box::new(value),
969                    ))
970                })
971                .transpose()?;
972            let upper_bound = self
973                .take_exact("to")
974                .map(|token| {
975                    let value = self.required_clause_expression(PREC_LOOP_CLAUSE, &token.token)?;
976                    Ok::<_, NativeParseError>(RangeBoundTo::new(
977                        typed_token(token),
978                        Box::new(value),
979                    ))
980                })
981                .transpose()?;
982            if lower_bound.is_some() || upper_bound.is_some() {
983                Domain::Range(lower_bound, upper_bound)
984            } else {
985                Domain::Bare
986            }
987        };
988
989        let when_condition = if let Some(token) = self.take_exact("when") {
990            let condition = self.required_clause_expression(PREC_LOOP_CLAUSE, &token.token)?;
991            Some(WhenCondition::new(typed_token(token), Box::new(condition)))
992        } else {
993            None
994        };
995        let body = self.parse_loop_body()?;
996
997        Ok(match domain {
998            Domain::Bare => Expr!(For::Bare {
999                for_token: typed_token(keyword),
1000                variable,
1001                condition: when_condition,
1002                body,
1003            }),
1004            Domain::Range(lower_bound, upper_bound) => Expr!(For::Range {
1005                for_token: typed_token(keyword),
1006                variable,
1007                lower_bound,
1008                upper_bound,
1009                condition: when_condition,
1010                body,
1011            }),
1012            Domain::In(token, collection) => Expr!(For::In {
1013                for_token: typed_token(keyword),
1014                variable,
1015                in_token: typed_token(token),
1016                collection,
1017                condition: when_condition,
1018                body,
1019            }),
1020        })
1021    }
1022
1023    /// Parses while loop.
1024    fn parse_while_loop(&mut self, keyword: SignificantToken) -> Result<Expr, NativeParseError> {
1025        let condition = self.required_clause_expression(PREC_CONTROL, &keyword.token)?;
1026        let body = self.parse_loop_body()?;
1027        Ok(Expr!(While {
1028            while_token: typed_token(keyword),
1029            condition: Box::new(condition),
1030            body,
1031        }))
1032    }
1033
1034    /// Parses loop body.
1035    fn parse_loop_body(&mut self) -> Result<LoopBody, NativeParseError> {
1036        let (list_step, do_step) = if let Some(token) = self.take_exact("list") {
1037            let listed_value = self.required_clause_expression(PREC_CONTROL, &token.token)?;
1038            let list_step = Some(ListStep::new(typed_token(token), Box::new(listed_value)));
1039            if let Some(token) = self.take_exact("do") {
1040                let ignored_value = self.required_clause_expression(PREC_CONTROL, &token.token)?;
1041                (
1042                    list_step,
1043                    Some(DoStep::new(typed_token(token), Box::new(ignored_value))),
1044                )
1045            } else {
1046                (list_step, None)
1047            }
1048        } else if let Some(token) = self.take_exact("do") {
1049            let ignored_value = self.required_clause_expression(PREC_CONTROL, &token.token)?;
1050            (
1051                None,
1052                Some(DoStep::new(typed_token(token), Box::new(ignored_value))),
1053            )
1054        } else {
1055            return Err(self.expected_at_lookahead("`list` or `do`"));
1056        };
1057
1058        Ok(LoopBody::new(list_step, do_step))
1059    }
1060
1061    /// Parses try statement.
1062    fn parse_try_statement(&mut self, keyword: SignificantToken) -> Result<Expr, NativeParseError> {
1063        let value = self.required_clause_expression(PREC_CONTROL, &keyword.token)?;
1064        let then_clause = self
1065            .take_exact("then")
1066            .map(|then_keyword| {
1067                let value = self.required_clause_expression(PREC_CONTROL, &then_keyword.token)?;
1068                Ok::<_, NativeParseError>(ThenClause::new(
1069                    typed_token(then_keyword),
1070                    Box::new(value),
1071                ))
1072            })
1073            .transpose()?;
1074
1075        let fallback = if let Some(else_keyword) = self.take_exact("else") {
1076            let value = self.required_clause_expression(PREC_CONTROL, &else_keyword.token)?;
1077            Some(TryFallback::Else(ElseClause::new(
1078                typed_token(else_keyword),
1079                Box::new(value),
1080            )))
1081        } else if let Some(except_keyword) = self.take_exact("except") {
1082            let exception = self.consume_symbol("an exception symbol")?;
1083            let do_keyword = self.consume_exact("do")?;
1084            let value = self.required_clause_expression(PREC_CONTROL, &do_keyword.token)?;
1085            Some(TryFallback!(Except {
1086                except_token: typed_token(except_keyword),
1087                exception,
1088                do_token: typed_token(do_keyword),
1089                value: Box::new(value),
1090            }))
1091        } else {
1092            None
1093        };
1094
1095        Ok(Expr!(Try {
1096            try_token: typed_token(keyword),
1097            value: Box::new(value),
1098            on_success: then_clause,
1099            fallback,
1100        }))
1101    }
1102
1103    /// Parses new statement.
1104    fn parse_new_statement(&mut self, keyword: SignificantToken) -> Result<Expr, NativeParseError> {
1105        let class = self.required_clause_expression(PREC_LOOP_CLAUSE, &keyword.token)?;
1106        let parent_class = if let Some(token) = self.take_exact("of") {
1107            let parent = self.required_clause_expression(PREC_LOOP_CLAUSE, &token.token)?;
1108            Some(OfClass::new(typed_token(token), Box::new(parent)))
1109        } else {
1110            None
1111        };
1112        let instance = if let Some(token) = self.take_exact("from") {
1113            let instance = self.required_clause_expression(PREC_LOOP_CLAUSE, &token.token)?;
1114            Some(FromInstance::new(typed_token(token), Box::new(instance)))
1115        } else {
1116            None
1117        };
1118
1119        Ok(Expr!(New {
1120            new_token: typed_token(keyword),
1121            class: Box::new(class),
1122            parent_class,
1123            instance,
1124        }))
1125    }
1126
1127    /// Parses debug clause.
1128    fn parse_debug_clause(&mut self, keyword: SignificantToken) -> Result<Expr, NativeParseError> {
1129        let spelling = parsing_spelling(&keyword.token).to_owned();
1130        if matches!(
1131            spelling.as_str(),
1132            "time" | "timing" | "elapsedTime" | "elapsedTiming" | "profile"
1133        ) {
1134            let value = self
1135                .parse_required(PREC_CONTROL)
1136                .map_err(|error| error.missing_operand_for(&keyword.token))?;
1137            return Ok(match spelling.as_str() {
1138                "time" => Expr!(Profile::Time {
1139                    modifier: typed_token(keyword),
1140                    value: Box::new(value),
1141                }),
1142                "timing" => Expr!(Profile::Timing {
1143                    modifier: typed_token(keyword),
1144                    value: Box::new(value),
1145                }),
1146                "elapsedTime" => Expr!(Profile::ElapsedTime {
1147                    modifier: typed_token(keyword),
1148                    value: Box::new(value),
1149                }),
1150                "elapsedTiming" => Expr!(Profile::ElapsedTiming {
1151                    modifier: typed_token(keyword),
1152                    value: Box::new(value),
1153                }),
1154                "profile" => Expr!(Profile::Profile {
1155                    modifier: typed_token(keyword),
1156                    value: Box::new(value),
1157                }),
1158                _ => unreachable!(),
1159            });
1160        }
1161        let value_is_optional = matches!(spelling.as_str(), "step" | "finish");
1162        let value = if value_is_optional {
1163            self.parse_nullable(PREC_CONTROL)?
1164        } else {
1165            Some(
1166                self.parse_required(PREC_CONTROL)
1167                    .map_err(|error| error.missing_operand_for(&keyword.token))?,
1168            )
1169        };
1170        let value = value.map(Box::new);
1171        Ok(match spelling.as_str() {
1172            "step" => Expr!(Debug::Step {
1173                keyword: typed_token(keyword),
1174                value,
1175            }),
1176            "finish" => Expr!(Debug::Finish {
1177                keyword: typed_token(keyword),
1178                value,
1179            }),
1180            "shield" => Expr!(Debug::Shield {
1181                keyword: typed_token(keyword),
1182                value,
1183            }),
1184            "TEST" => Expr!(Debug::Test {
1185                keyword: typed_token(keyword),
1186                value,
1187            }),
1188            "breakpoint" => Expr!(Debug::Breakpoint {
1189                keyword: typed_token(keyword),
1190                value,
1191            }),
1192            _ => unreachable!("debug actions are assigned only to debug keywords"),
1193        })
1194    }
1195
1196    /// Handles required clause expression.
1197    fn required_clause_expression(
1198        &mut self,
1199        level: u8,
1200        keyword: &TokenTree,
1201    ) -> Result<Expr, NativeParseError> {
1202        match self.parse_nullable(level)? {
1203            None => Err(NativeParseError::MissingOperand {
1204                operator: keyword.description(),
1205                span: keyword.expect_span(),
1206            }),
1207            Some(expression) => Ok(expression),
1208        }
1209    }
1210
1211    /// Consumes symbol.
1212    fn consume_symbol(&mut self, expected: &'static str) -> Result<Symbol, NativeParseError> {
1213        match self.consume() {
1214            Lookahead::Token(token)
1215                if matches!(token.token, TokenTree::Ident(_))
1216                    && matches!(parse_info(&token.token).unary, UnaryAction::Atom) =>
1217            {
1218                let span = token.token.expect_span();
1219                let text = token.token.description();
1220                Ok(typed_terminal(
1221                    Symbol::new(text, span),
1222                    token.trailing_trivia,
1223                ))
1224            }
1225            Lookahead::Token(token) => Err(unexpected!(token.token, expected)),
1226            Lookahead::End(span) => Err(NativeParseError::unexpected_end(expected, span)),
1227        }
1228    }
1229
1230    /// Consumes exact.
1231    fn consume_exact(
1232        &mut self,
1233        spelling: &'static str,
1234    ) -> Result<SignificantToken, NativeParseError> {
1235        match self.consume() {
1236            Lookahead::Token(token) if parsing_spelling(&token.token) == spelling => Ok(token),
1237            Lookahead::Token(token) => Err(unexpected!(token.token, spelling)),
1238            Lookahead::End(span) => Err(NativeParseError::unexpected_end(spelling, span)),
1239        }
1240    }
1241
1242    /// Takes exact.
1243    fn take_exact(&mut self, spelling: &'static str) -> Option<SignificantToken> {
1244        if matches!(
1245            self.peek(),
1246            Lookahead::Token(token)
1247                if parsing_spelling(&token.token) == spelling
1248        ) {
1249            let Lookahead::Token(token) = self.consume() else {
1250                unreachable!("the token just peeked is consumable")
1251            };
1252            Some(token)
1253        } else {
1254            None
1255        }
1256    }
1257
1258    /// Handles expected at lookahead.
1259    fn expected_at_lookahead(&self, expected: &'static str) -> NativeParseError {
1260        match self.peek() {
1261            Lookahead::Token(token) => unexpected!(token.token, expected),
1262            Lookahead::End(span) => NativeParseError::unexpected_end(expected, span),
1263        }
1264    }
1265
1266    /// Handles accumulate.
1267    fn accumulate(&mut self, mut left: Expr, level: u8) -> Result<Expr, NativeParseError> {
1268        loop {
1269            let Lookahead::Token(next) = self.peek() else {
1270                return Ok(left);
1271            };
1272            let info = if matches!(&next.token, TokenTree::Punct(punct) if punct.text().is_empty())
1273            {
1274                self.adjacency_info()
1275            } else {
1276                parse_info(&next.token)
1277            };
1278            if info.precedence <= level {
1279                return Ok(left);
1280            }
1281            let Lookahead::Token(operator) = self.consume() else {
1282                unreachable!("the token just peeked is consumable")
1283            };
1284            left = if matches!(&operator.token, TokenTree::Punct(punct) if punct.text().is_empty())
1285            {
1286                let right = self
1287                    .parse_required(PREC_APPLICATION_RIGHT)
1288                    .map_err(|error| error.missing_operand_for(&operator.token))?;
1289                let adjacency = typed_terminal(
1290                    Adj::new("", operator.token.expect_span()),
1291                    operator.trailing_trivia,
1292                );
1293                Expr!(Op::Bin::Adj {
1294                    left_operand: Box::new(left),
1295                    operator: adjacency,
1296                    right_operand: Box::new(right),
1297                })
1298            } else if let Some(strength) = info.binary_strength {
1299                let left = BinaryLeft::prepare(left, &operator.token)?;
1300                let right = self
1301                    .parse_required(strength)
1302                    .map_err(|error| error.missing_operand_for(&operator.token))?;
1303                lower_binary(left, operator, right)?
1304            } else if info.postfix {
1305                let span = operator.token.expect_span();
1306                let spelling = operator.token.description();
1307                let operator = PostfixOperator::from_token_tree_with_trivia(
1308                    operator.token,
1309                    operator.trailing_trivia,
1310                )
1311                .ok_or(NativeParseError::Unsupported {
1312                    syntax: spelling,
1313                    span,
1314                })?;
1315                Expr!(Op::Postfix {
1316                    operand: Box::new(left),
1317                    operator,
1318                })
1319            } else if !matches!(info.unary, UnaryAction::Error) {
1320                if operator.crossed_newline {
1321                    return Err(NativeParseError::NewlineInApplication {
1322                        span: operator.token.expect_span(),
1323                    });
1324                }
1325                let adjacency_span = operator.token.expect_span().subspan(0, 0);
1326                let right = self.parse_consumed(operator, PREC_APPLICATION_RIGHT)?;
1327                Expr!(Op::Bin::Adj {
1328                    left_operand: Box::new(left),
1329                    operator: Adj::new("", adjacency_span),
1330                    right_operand: Box::new(right),
1331                })
1332            } else {
1333                return Err(unexpected!(operator.token, "an operator"));
1334            };
1335        }
1336    }
1337
1338    /// Handles adjacency info.
1339    fn adjacency_info(&self) -> ParseInfo {
1340        let mut input = self.input.fork();
1341        let _ = input.next_significant();
1342        input.next_significant().map_or_else(
1343            || ParseInfo::stop(PREC_APPLICATION),
1344            |right| ParseInfo::binary(parse_info(&right.token).precedence, PREC_APPLICATION_RIGHT),
1345        )
1346    }
1347
1348    /// Handles only expression.
1349    fn only_expression(&self, components: Components<Component>) -> Result<Expr, NativeParseError> {
1350        if components.is_punctuated() {
1351            return Err(NativeParseError::Unexpected {
1352                found: "a sequence".into(),
1353                expected: "one expression",
1354                span: components.first.expect_span(),
1355            });
1356        }
1357        match components.first {
1358            Component::Expr(value) => Ok(*value),
1359            value => Err(NativeParseError::Unexpected {
1360                found: "an empty component".into(),
1361                expected: "one expression",
1362                span: value.expect_span(),
1363            }),
1364        }
1365    }
1366
1367    /// Handles packed content.
1368    fn packed_content(
1369        &self,
1370        components: Components<Component>,
1371    ) -> Result<PackedContent, NativeParseError> {
1372        match components.into_punctuated() {
1373            Ok(components) => Ok(ExprPack::new(components).into()),
1374            Err(Component::Expr(expression)) => Ok((*expression).into()),
1375            Err(value) => Err(NativeParseError::Unexpected {
1376                found: "an empty component".into(),
1377                expected: "one expression",
1378                span: value.expect_span(),
1379            }),
1380        }
1381    }
1382
1383    /// Handles peek.
1384    fn peek(&self) -> Lookahead {
1385        self.input.lookahead()
1386    }
1387
1388    /// Handles consume.
1389    fn consume(&mut self) -> Lookahead {
1390        self.input.consume_lookahead()
1391    }
1392
1393    /// Skips trivia.
1394    fn skip_trivia(&mut self) {
1395        self.input.skip_trivia();
1396    }
1397
1398    /// Handles at end.
1399    fn at_end(&self) -> bool {
1400        matches!(self.peek(), Lookahead::End(_))
1401    }
1402
1403    /// Handles at punctuation.
1404    fn at_punctuation(&self, spelling: &str) -> bool {
1405        matches!(
1406            self.peek(),
1407            Lookahead::Token(token)
1408                if token.token.spelling() == Some(spelling)
1409        )
1410    }
1411
1412    /// Takes punctuation.
1413    fn take_punctuation(&mut self, spelling: &str) -> Option<SignificantToken> {
1414        if !self.at_punctuation(spelling) {
1415            return None;
1416        }
1417        let Lookahead::Token(token) = self.consume() else {
1418            unreachable!("the punctuation just peeked is consumable")
1419        };
1420        Some(token)
1421    }
1422}
1423
1424/// Parses delimited.
1425fn parse_delimited(token: SignificantToken) -> Result<Expr, NativeParseError> {
1426    let group_trailing = token.trailing_trivia;
1427    let group = match token.token {
1428        TokenTree::Group(group) => group,
1429        token => return Err(unexpected!(token, "a delimited group")),
1430    };
1431    let kind = group.delim_kind();
1432    let delimiter_spans = group.delimiter().spans.clone();
1433    let mut group_contents = group.into_stream();
1434    let opening_trivia = group_contents.take_leading_trivia();
1435    let mut contents = Engine::new(group_contents);
1436    let mut muted = Vec::new();
1437    let elements = loop {
1438        let elements = contents.parse_optional_components()?;
1439        let Some(separator) = contents.take_punctuation(";") else {
1440            break elements;
1441        };
1442        let Some(elements) = elements else {
1443            return Err(unexpected!(separator.token, "a statement before `;`"));
1444        };
1445        muted.push(Statement::new(
1446            contents.packed_content(elements)?,
1447            typed_token(separator),
1448        ));
1449    };
1450    if let Lookahead::Token(token) = contents.peek() {
1451        return Err(unexpected!(token.token, "the end of the group"));
1452    }
1453
1454    let expression: Expr = match kind {
1455        DelimiterKind::Bracket => {
1456            let elements = elements
1457                .map(|elements| contents.packed_content(elements))
1458                .transpose()?;
1459            let mut value = Array::new(muted, elements);
1460            value.delimiter = typed_delimiter(delimiter_spans, opening_trivia, group_trailing);
1461            value.into()
1462        }
1463        DelimiterKind::Brace => {
1464            let elements = elements
1465                .map(|elements| contents.packed_content(elements))
1466                .transpose()?;
1467            let mut value = List::new(muted, elements);
1468            value.delimiter = typed_delimiter(delimiter_spans, opening_trivia, group_trailing);
1469            value.into()
1470        }
1471        DelimiterKind::AngleBar => {
1472            let elements = elements
1473                .map(|elements| contents.packed_content(elements))
1474                .transpose()?;
1475            let mut value = AngleBarList::new(muted, elements);
1476            value.delimiter = typed_delimiter(delimiter_spans, opening_trivia, group_trailing);
1477            value.into()
1478        }
1479        DelimiterKind::Parenthesis if muted.is_empty() && elements.is_none() => {
1480            let mut value = Sequence::new(Vec::new(), None);
1481            value.delimiter = typed_delimiter(delimiter_spans, opening_trivia, group_trailing);
1482            value.into()
1483        }
1484        DelimiterKind::Parenthesis
1485            if !muted.is_empty() || elements.as_ref().is_some_and(Components::is_punctuated) =>
1486        {
1487            let mut value = if elements.as_ref().is_some_and(Components::is_punctuated) {
1488                Sequence::new(
1489                    muted,
1490                    elements
1491                        .map(|elements| contents.packed_content(elements))
1492                        .transpose()?,
1493                )
1494            } else {
1495                let value = elements
1496                    .map(|elements| contents.only_expression(elements))
1497                    .transpose()?;
1498                let mut value = Holder::new(muted, value.map(Box::new));
1499                value.delimiter = typed_delimiter(delimiter_spans, opening_trivia, group_trailing);
1500                return Ok(value.into());
1501            };
1502            value.delimiter = typed_delimiter(delimiter_spans, opening_trivia, group_trailing);
1503            value.into()
1504        }
1505        DelimiterKind::Parenthesis => {
1506            let value = elements
1507                .map(|elements| contents.only_expression(elements))
1508                .transpose()?;
1509            let mut value = Holder::new(Vec::new(), value.map(Box::new));
1510            value.delimiter = typed_delimiter(delimiter_spans, opening_trivia, group_trailing);
1511            value.into()
1512        }
1513    };
1514    Ok(expression)
1515}
1516
1517/// Handles typed delimiter.
1518fn typed_delimiter<D: DelimiterToken>(
1519    spans: crate::DoubleSpan,
1520    opening_trivia: TrailingTrivia,
1521    closing_trivia: TrailingTrivia,
1522) -> D {
1523    let mut delimiter = D::new(spans);
1524    *delimiter.opening_trivia_mut() = opening_trivia;
1525    *delimiter.closing_trivia_mut() = closing_trivia;
1526    delimiter
1527}
1528
1529/// Lowers prefix statement.
1530fn lower_prefix_statement(keyword: SignificantToken, value: Option<Expr>) -> Expr {
1531    if is_token!(&keyword.token, break) {
1532        Expr!(Control::Break {
1533            break_token: typed_token(keyword),
1534            value: value.map(Box::new),
1535        })
1536    } else if is_token!(&keyword.token, continue) {
1537        Expr!(Control::Continue {
1538            continue_token: typed_token(keyword),
1539            value: value.map(Box::new),
1540        })
1541    } else if is_token!(&keyword.token, return) {
1542        Expr!(Control::Return {
1543            return_token: typed_token(keyword),
1544            value: value.map(Box::new),
1545        })
1546    } else {
1547        let value = value.expect("catch, throw, and trap require a value");
1548        if is_token!(&keyword.token, catch) {
1549            Expr!(Catch {
1550                catch_token: typed_token(keyword),
1551                value: Box::new(value),
1552            })
1553        } else if is_token!(&keyword.token, throw) {
1554            Expr!(Throw {
1555                throw_token: typed_token(keyword),
1556                value: Box::new(value),
1557            })
1558        } else if is_token!(&keyword.token, trap) {
1559            Expr!(Trap {
1560                trap_token: typed_token(keyword),
1561                value: Box::new(value),
1562            })
1563        } else {
1564            unreachable!("statement actions are assigned only to statement keywords")
1565        }
1566    }
1567}
1568
1569/// Lowers atom.
1570fn lower_atom(token: SignificantToken) -> Result<Expr, NativeParseError> {
1571    match token.token {
1572        TokenTree::Ident(raw) => Ok(typed_terminal(
1573            Symbol::new(raw.text(), raw.expect_span()),
1574            token.trailing_trivia,
1575        )
1576        .into()),
1577        TokenTree::Literal(raw) => {
1578            let span = raw.expect_span();
1579            Ok(match raw.kind {
1580                LiteralKind::Integer => {
1581                    typed_terminal(IntegerLiteral::new(raw.text(), span), token.trailing_trivia)
1582                        .into()
1583                }
1584                LiteralKind::Float => {
1585                    typed_terminal(FloatLiteral::new(raw.text(), span), token.trailing_trivia)
1586                        .into()
1587                }
1588                LiteralKind::String => {
1589                    lower_string_literal(raw.text(), span, token.trailing_trivia)
1590                }
1591                LiteralKind::RawString => {
1592                    lower_raw_string_literal(raw.text(), span, token.trailing_trivia)
1593                }
1594            })
1595        }
1596        token => Err(unexpected!(token, "an expression")),
1597    }
1598}
1599
1600/// A left operand whose operator-specific structural requirements are valid.
1601enum BinaryLeft {
1602    /// The Expression alternative.
1603    Expression(Box<Expr>),
1604    /// The Assignment alternative.
1605    Assignment {
1606        /// The target.
1607        target: AssignmentTarget,
1608        /// The local.
1609        local: bool,
1610    },
1611    /// The Lambda alternative.
1612    Lambda(LambdaArguments),
1613}
1614
1615/// Internal alternatives for LambdaArguments.
1616pub(crate) enum LambdaArguments {
1617    /// The Variadic alternative.
1618    Variadic(Symbol),
1619    /// The List alternative.
1620    List(Box<Delimited<Option<ArgumentListContent>>>),
1621}
1622
1623impl BinaryLeft {
1624    /// Handles prepare.
1625    fn prepare(left: Expr, operator: &TokenTree) -> Result<Self, NativeParseError> {
1626        let span = operator.expect_span();
1627        Ok(match operator.spelling() {
1628            Some("=") => Self::Assignment {
1629                target: AssignmentTarget::parse(left, false, span)?,
1630                local: false,
1631            },
1632            Some(":=") => Self::Assignment {
1633                target: AssignmentTarget::parse(left, true, span)?,
1634                local: true,
1635            },
1636            Some("->") => Self::Lambda(
1637                lambda_arguments(left).ok_or(NativeParseError::InvalidLambdaArguments { span })?,
1638            ),
1639            _ => Self::Expression(Box::new(left)),
1640        })
1641    }
1642}
1643
1644/// A parsed expression that can occur to the left of an assignment operator.
1645enum AssignmentTarget {
1646    /// The Symbol alternative.
1647    Symbol(Symbol),
1648    /// The Operator alternative.
1649    Operator(ExprOp),
1650    /// The New alternative.
1651    New(ExprNew),
1652    /// The List alternative.
1653    List(Box<AssignmentList>),
1654}
1655
1656impl AssignmentTarget {
1657    /// Handles parse.
1658    fn parse(expression: Expr, local: bool, span: Span) -> Result<Self, NativeParseError> {
1659        match expression {
1660            Expr::Symbol(variable) => Ok(Self::Symbol(variable)),
1661            Expr::Op(expression) => Ok(Self::Operator(expression)),
1662            Expr::New(statement) if local => Ok(Self::New(statement)),
1663            expression => assignment_list(expression)
1664                .map(Box::new)
1665                .map(Self::List)
1666                .ok_or(NativeParseError::InvalidAssignmentTarget { span }),
1667        }
1668    }
1669}
1670
1671/// Lowers binary.
1672fn lower_binary(
1673    left: BinaryLeft,
1674    operator: SignificantToken,
1675    right: Expr,
1676) -> Result<Expr, NativeParseError> {
1677    let span = operator.token.expect_span();
1678    let spelling = operator
1679        .token
1680        .spelling()
1681        .expect("binary actions are assigned only to spelled tokens");
1682    match left {
1683        BinaryLeft::Assignment { target, local } => {
1684            Ok(lower_assignment(target, operator, right, local))
1685        }
1686        BinaryLeft::Lambda(arguments) => Ok(match arguments {
1687            LambdaArguments::Variadic(argument) => Expr!(Lambda::Variadic {
1688                argument,
1689                operator: typed_token(operator),
1690                body: Box::new(right),
1691            }),
1692            LambdaArguments::List(arguments) => Expr!(Lambda::List {
1693                arguments: *arguments,
1694                operator: typed_token(operator),
1695                body: Box::new(right),
1696            }),
1697        }),
1698        BinaryLeft::Expression(left) if spelling == "<-" => Ok(Expr!(Assign::Evaluated {
1699            evaluated_domain: left,
1700            operator: typed_token(operator),
1701            value: Box::new(right),
1702        })),
1703        BinaryLeft::Expression(left) if spelling == "=>" => Ok(Expr!(Option {
1704            key: left,
1705            operator: typed_token(operator),
1706            value: Box::new(right),
1707        })),
1708        BinaryLeft::Expression(left)
1709            if GENERATED_AUGMENTED_OPERATOR_SPELLINGS.contains(&spelling) =>
1710        {
1711            let operator = AugmentedOperator::from_token_tree_with_trivia(
1712                operator.token,
1713                operator.trailing_trivia,
1714            )
1715            .expect("the augmented operator table and category have the same source");
1716            Ok(Expr!(Assign::Augmented {
1717                target: left,
1718                operator,
1719                value: Box::new(right),
1720            }))
1721        }
1722        BinaryLeft::Expression(left) if matches!(spelling, "." | ".?") => Ok(match spelling {
1723            "." => Expr!(Op::Bin::Member::Dot {
1724                receiver: left,
1725                operator: typed_token::<Token![.]>(operator),
1726                member: Box::new(right),
1727            }),
1728            ".?" => Expr!(Op::Bin::Member::Optional {
1729                receiver: left,
1730                operator: typed_token::<Token![.?]>(operator),
1731                member: Box::new(right),
1732            }),
1733            _ => unreachable!(),
1734        }),
1735        BinaryLeft::Expression(left) if spelling == "#" => Ok(Expr!(Op::Bin::Index {
1736            receiver: left,
1737            operator: typed_token(operator),
1738            index: Box::new(right),
1739        })),
1740        BinaryLeft::Expression(left) => {
1741            let spelling = spelling.to_owned();
1742            let operator = BinaryOperator::from_token_tree_with_trivia(
1743                operator.token,
1744                operator.trailing_trivia,
1745            )
1746            .ok_or(NativeParseError::Unsupported {
1747                syntax: spelling,
1748                span,
1749            })?;
1750            Ok(Expr!(Op::Bin::Regular {
1751                left_operand: left,
1752                operator,
1753                right_operand: Box::new(right),
1754            }))
1755        }
1756    }
1757}
1758
1759/// Lowers assignment.
1760fn lower_assignment(
1761    target: AssignmentTarget,
1762    operator: SignificantToken,
1763    right: Expr,
1764    local: bool,
1765) -> Expr {
1766    match (local, target) {
1767        (false, AssignmentTarget::Symbol(variable)) => {
1768            Expr!(Assign::Simple::Global {
1769                variable,
1770                operator: typed_token(operator),
1771                value: Box::new(right),
1772            })
1773        }
1774        (true, AssignmentTarget::Symbol(variable)) => {
1775            Expr!(Assign::Simple::Local {
1776                variable,
1777                operator: typed_token(operator),
1778                value: Box::new(right),
1779            })
1780        }
1781        (false, AssignmentTarget::Operator(argument_expr)) => {
1782            Expr!(Assign::Op {
1783                argument_expr,
1784                operator: typed_token(operator),
1785                value_expr: Box::new(right),
1786            })
1787        }
1788        (true, AssignmentTarget::Operator(ExprOp::Bin(ExprOpBin::Adj(application)))) => {
1789            let (typical_value, function) = installation_value(right);
1790            Expr!(Assign::Install::Method {
1791                method: application.left_operand,
1792                operator: application.operator,
1793                signature: application.right_operand,
1794                assign_op: typed_token(operator),
1795                typical_value,
1796                function: Box::new(function),
1797            })
1798        }
1799        (true, AssignmentTarget::Operator(domain_expr)) => {
1800            let (typical_value, function) = installation_value(right);
1801            Expr!(Assign::Install::Op {
1802                domain_expr,
1803                assign_op: typed_token(operator),
1804                typical_value,
1805                function: Box::new(function),
1806            })
1807        }
1808        (true, AssignmentTarget::New(new_statement)) => {
1809            Expr!(Assign::Install::New {
1810                new_statement,
1811                operator: typed_token(operator),
1812                function: Box::new(right),
1813            })
1814        }
1815        (local, AssignmentTarget::List(argument_list)) => {
1816            if local {
1817                Expr!(Assign::Parallel::Local {
1818                    argument_list,
1819                    operator: typed_token(operator),
1820                    value: Box::new(right),
1821                })
1822            } else {
1823                Expr!(Assign::Parallel::Global {
1824                    argument_list,
1825                    operator: typed_token(operator),
1826                    value: Box::new(right),
1827                })
1828            }
1829        }
1830        (false, AssignmentTarget::New(_)) => {
1831            unreachable!("global assignment preparation rejects new statements")
1832        }
1833    }
1834}
1835
1836/// Handles installation value.
1837pub(crate) fn installation_value(value: Expr) -> (Option<TypeAnnotation>, Expr) {
1838    match value {
1839        Expr::Option(value) => (
1840            Some(TypeAnnotation::new(value.key, value.operator)),
1841            *value.value,
1842        ),
1843        value => (None, value),
1844    }
1845}
1846
1847/// Parses cell stream.
1848fn parse_cell_stream(cells: CellStream) -> Result<SourceFile, NativeParseError> {
1849    let mut elements = Vec::new();
1850    let bof_span = cells.physical_bof();
1851    let eof_span = cells.physical_eof();
1852    // Comments of a comment-only cell lead the next cell that has tokens, or
1853    // close the file when no such cell follows.
1854    let mut detached = Vec::new();
1855    let mut cells = cells.into_iter().peekable();
1856    while let Some(cell) = cells.next() {
1857        if cell.is_empty() {
1858            detached.extend(CommentTrivia::of(&cell.into_parser_token_stream()).into_trivia());
1859            continue;
1860        }
1861        let eoc = cells
1862            .peek()
1863            .and_then(cell_start_span)
1864            .unwrap_or_else(|| end_span(&cell));
1865        if let Some(element) = parse_raw_cell_at(cell, eoc, std::mem::take(&mut detached))? {
1866            elements.push(element);
1867        }
1868    }
1869    let mut source_file = SourceFile::new(BOF::new("", bof_span), elements, EOF::new("", eof_span));
1870    source_file.set_closing_comments(detached);
1871    Ok(source_file)
1872}
1873
1874/// Handles tokenize for native parser.
1875fn tokenize_for_native_parser(tokens: TokenStream) -> Result<CellStream, NativeParseError> {
1876    match tokens.to_cell_stream() {
1877        Ok(cells) => Ok(cells),
1878        Err(tokenize_error) => {
1879            let incomplete = frame_recovering(tokens).incomplete;
1880            if let Some(cell) = incomplete
1881                && let Err(parse_error) = parse_raw_cell(cell)
1882            {
1883                return Err(parse_error);
1884            }
1885            Err(NativeParseError::Tokenize(tokenize_error))
1886        }
1887    }
1888}
1889
1890/// Parses raw cell.
1891pub(crate) fn parse_raw_cell(
1892    tokens: CellTokenStream,
1893) -> Result<Option<crate::nodes::Cell>, NativeParseError> {
1894    let eoc = end_span(&tokens);
1895    parse_raw_cell_at(tokens, eoc, Vec::new())
1896}
1897
1898/// Parses raw cell at.
1899///
1900/// `detached` comments, which precede the cell outside it, lead the comments
1901/// before its first token in the cell's leading trivia.
1902fn parse_raw_cell_at(
1903    tokens: CellTokenStream,
1904    eoc: Span,
1905    mut detached: Vec<Trivia>,
1906) -> Result<Option<crate::nodes::Cell>, NativeParseError> {
1907    let ends_with_semicolon = ends_with_cell_semicolon(&tokens);
1908    let mut tokens = tokens.into_parser_token_stream();
1909    detached.extend(tokens.take_prefix_trivia().into_vec());
1910    let semicolon = ends_with_semicolon
1911        .then(|| tokens.take_final_punctuation(";"))
1912        .flatten()
1913        .map(|(punctuation, trailing_trivia)| {
1914            <Token![;] as Token>::from_token_tree_with_trivia(
1915                TokenTree::Punct(punctuation),
1916                trailing_trivia,
1917            )
1918            .expect("a semicolon punctuation token lowers to Token![;]")
1919        });
1920    let mut cell = Engine::new(tokens).parse_cell(semicolon, eoc)?;
1921    if let Some(cell) = &mut cell {
1922        cell.leading_trivia = LeadingTrivia::new(detached);
1923    }
1924    Ok(cell)
1925}
1926
1927/// Handles cell start span.
1928fn cell_start_span(tokens: &CellTokenStream) -> Option<Span> {
1929    let token = tokens.iter().next()?;
1930    let span = token
1931        .leading_trivia()
1932        .first()
1933        .map_or_else(|| token.span(), Spanned::span);
1934    span.start().map(|start| span.at(start))
1935}
1936
1937impl Parse for Expr {
1938    fn parse(input: &mut ParseStream) -> Result<Self, TokenParseError> {
1939        let tokens = input.by_ref().collect::<TokenStream>();
1940        let mut engine = Engine::new(tokens);
1941        engine.skip_trivia();
1942        let value = engine
1943            .parse_required(PREC_CLOSER)
1944            .map_err(token_parse_error)?;
1945        engine.skip_trivia();
1946        match engine.peek() {
1947            Lookahead::End(_) => Ok(value),
1948            Lookahead::Token(token) => Err(TokenParseError::TrailingToken {
1949                found: token.token.description(),
1950                span: token.token.expect_span(),
1951            }),
1952        }
1953    }
1954}
1955
1956impl Parse for SourceFile {
1957    fn parse(input: &mut ParseStream) -> Result<Self, TokenParseError> {
1958        let tokens = input.by_ref().collect();
1959        tokenize_for_native_parser(tokens)
1960            .and_then(parse_cell_stream)
1961            .map_err(token_parse_error)
1962    }
1963}
1964
1965/// Handles token parse error.
1966fn token_parse_error(error: NativeParseError) -> TokenParseError {
1967    let span = error.expect_span();
1968    TokenParseError::Syntax {
1969        message: error.to_string(),
1970        span,
1971    }
1972}
1973
1974/// Handles parsing spelling.
1975fn parsing_spelling(token: &TokenTree) -> &str {
1976    token.spelling().map_or("", canonical_word_spelling)
1977}
1978
1979/// Handles typed token.
1980fn typed_token<T: Token>(token: SignificantToken) -> T {
1981    let spelling = token.token.description();
1982    T::from_token_tree_with_trivia(token.token, token.trailing_trivia)
1983        .unwrap_or_else(|| panic!("`{spelling}` cannot be lowered to `{}`", T::SPELLING))
1984}
1985
1986/// Handles typed terminal.
1987fn typed_terminal<T: Terminal>(mut terminal: T, trailing_trivia: TrailingTrivia) -> T {
1988    *terminal.trailing_trivia_mut() = trailing_trivia;
1989    terminal
1990}
1991
1992/// Handles empty span at.
1993fn empty_span_at(lookahead: &Span) -> Span {
1994    lookahead.subspan(0, 0)
1995}
1996
1997/// Lowers string literal.
1998fn lower_string_literal(text: &str, span: Span, trailing_trivia: TrailingTrivia) -> Expr {
1999    let body_end = if text.len() > 1 && text.ends_with('"') {
2000        text.len() - 1
2001    } else {
2002        text.len()
2003    };
2004    let body = &text[1..body_end];
2005    let mut elements = Vec::new();
2006    let mut content_start = 0;
2007    let mut cursor = 0;
2008
2009    while cursor < body.len() {
2010        if body.as_bytes()[cursor] != b'\\' {
2011            cursor += 1;
2012            continue;
2013        }
2014        if content_start < cursor {
2015            elements.push(StringElement::Content(StringContent::new(
2016                &body[content_start..cursor],
2017                span.subspan(content_start + 1, cursor + 1),
2018            )));
2019        }
2020        let escape_end = match body.as_bytes()[cursor + 1] {
2021            b'x' => cursor + 4,
2022            b'u' => cursor + 6,
2023            b'0'..=b'7' => {
2024                let mut end = cursor + 2;
2025                while end < body.len()
2026                    && end < cursor + 4
2027                    && body.as_bytes()[end].is_ascii_digit()
2028                    && body.as_bytes()[end] < b'8'
2029                {
2030                    end += 1;
2031                }
2032                end
2033            }
2034            _ => cursor + 2,
2035        };
2036        elements.push(StringElement::Escape(EscapeSequence::new(
2037            &body[cursor..escape_end],
2038            span.subspan(cursor + 1, escape_end + 1),
2039        )));
2040        cursor = escape_end;
2041        content_start = cursor;
2042    }
2043    if content_start < body.len() {
2044        elements.push(StringElement::Content(StringContent::new(
2045            &body[content_start..],
2046            span.subspan(content_start + 1, body_end),
2047        )));
2048    }
2049    typed_terminal(StringLiteral::new(elements, span), trailing_trivia).into()
2050}
2051
2052/// Lowers raw string literal.
2053fn lower_raw_string_literal(text: &str, span: Span, trailing_trivia: TrailingTrivia) -> Expr {
2054    let body_end = if text.len() >= 6 && text.ends_with("///") {
2055        text.len() - 3
2056    } else {
2057        text.len()
2058    };
2059    let body = &text[3..body_end];
2060    let mut elements = Vec::new();
2061    let mut content_start = 0;
2062    let mut cursor = 0;
2063
2064    while cursor + 1 < body.len() {
2065        if &body.as_bytes()[cursor..cursor + 2] != b"//" {
2066            cursor += 1;
2067            continue;
2068        }
2069        if content_start < cursor {
2070            elements.push(RawStringElement::Content(RawStringContent::new(
2071                &body[content_start..cursor],
2072                span.subspan(content_start + 3, cursor + 3),
2073            )));
2074        }
2075        elements.push(RawStringElement::Escape(EscapeSequence::new(
2076            "//",
2077            span.subspan(cursor + 3, cursor + 5),
2078        )));
2079        cursor += 2;
2080        content_start = cursor;
2081    }
2082    if content_start < body.len() {
2083        elements.push(RawStringElement::Content(RawStringContent::new(
2084            &body[content_start..],
2085            span.subspan(content_start + 3, body_end),
2086        )));
2087    }
2088    typed_terminal(RawStringLiteral::new(elements, span), trailing_trivia).into()
2089}
2090
2091/// Handles collection contents.
2092fn collection_contents(expression: Expr) -> Option<(crate::Delimiter, Option<PackedContent>)> {
2093    match expression {
2094        Expr::Collection(ExprCollection::Sequence(value)) if value.statements.is_empty() => {
2095            Some((DelimiterValue::delimiter(&value.delimiter), value.elements))
2096        }
2097        Expr::Collection(ExprCollection::List(value)) if value.statements.is_empty() => {
2098            Some((DelimiterValue::delimiter(&value.delimiter), value.elements))
2099        }
2100        Expr::Collection(ExprCollection::Array(value)) if value.statements.is_empty() => {
2101            Some((DelimiterValue::delimiter(&value.delimiter), value.elements))
2102        }
2103        Expr::Collection(ExprCollection::AngleBar(value)) if value.statements.is_empty() => {
2104            Some((DelimiterValue::delimiter(&value.delimiter), value.elements))
2105        }
2106        Expr::Holder(value) if value.muted.is_empty() => {
2107            let elements = value.value.map(|value| (*value).into());
2108            Some((DelimiterValue::delimiter(&value.delimiter), elements))
2109        }
2110        _ => None,
2111    }
2112}
2113
2114/// Handles assignment list.
2115pub(crate) fn assignment_list(expression: Expr) -> Option<AssignmentList> {
2116    let (delimiter, elements) = collection_contents(expression)?;
2117    let contents = match elements {
2118        Some(elements) => {
2119            let components = packed_components(elements).map(assignment_argument)?;
2120            Some(match components.into_punctuated() {
2121                Ok(arguments) => AssignmentListContent!(Pack { arguments }),
2122                Err(argument) => argument.into(),
2123            })
2124        }
2125        None => None,
2126    };
2127    Some(AssignmentList::new(Delimited::new(delimiter, contents)))
2128}
2129
2130/// Handles assignment argument.
2131fn assignment_argument(component: Component) -> Option<AssignmentArgument> {
2132    match component {
2133        Component::Empty(value) => Some(AssignmentArgument::Empty(value)),
2134        Component::Expr(value) => match *value {
2135            Expr::Symbol(value) => Some(AssignmentArgument::Symbol(value)),
2136            Expr::Op(value) => Some(AssignmentArgument::Op(value)),
2137            Expr::Assign(ExprAssign::Evaluated(value)) => {
2138                Some(AssignmentArgument::Evaluated(value))
2139            }
2140            value => assignment_list(value).map(Into::into),
2141        },
2142    }
2143}
2144
2145/// Handles expr pack symbols.
2146fn expr_pack_symbols(elements: ExprPack) -> Option<Punctuated<Symbol>> {
2147    elements
2148        .pack
2149        .try_map(
2150            |component| match component {
2151                Component::Expr(value) => match *value {
2152                    Expr::Symbol(value) => Ok(value),
2153                    _ => Err(()),
2154                },
2155                Component::Empty(_) => Err(()),
2156            },
2157            Ok,
2158        )
2159        .ok()
2160}
2161
2162/// Handles packed components.
2163fn packed_components(content: PackedContent) -> Components<Component> {
2164    match content {
2165        PackedContent::Expr(expression) => Components {
2166            first: Component::Expr(expression),
2167            rest: Vec::new(),
2168        },
2169        PackedContent::Pack(pack) => Components::from_punctuated(pack.pack),
2170    }
2171}
2172
2173/// Handles lambda arguments.
2174pub(crate) fn lambda_arguments(expression: Expr) -> Option<LambdaArguments> {
2175    match expression {
2176        Expr::Symbol(value) => Some(LambdaArguments::Variadic(value)),
2177        expression => {
2178            let (delimiter, elements) = collection_contents(expression)?;
2179            let arguments = match elements {
2180                Some(PackedContent::Expr(expression)) => match *expression {
2181                    Expr::Symbol(value) => Some(ArgumentListContent::Symbol(value)),
2182                    _ => return None,
2183                },
2184                Some(PackedContent::Pack(pack)) => Some(ArgumentListContent!(Pack {
2185                    arguments: expr_pack_symbols(pack)?,
2186                })),
2187                None => None,
2188            };
2189            Some(LambdaArguments::List(Box::new(Delimited::new(
2190                delimiter, arguments,
2191            ))))
2192        }
2193    }
2194}
2195
2196/// The rule declared for a spelling, found in the generated table.
2197fn token_parse_rule(spelling: &str) -> Option<TokenParseRule> {
2198    TOKEN_PARSE_RULES
2199        .binary_search_by_key(&spelling, |(declared, _)| *declared)
2200        .ok()
2201        .map(|index| TOKEN_PARSE_RULES[index].1)
2202}
2203
2204/// Handles keyword action.
2205fn keyword_action(spelling: &str) -> Option<UnaryAction> {
2206    Some(match spelling {
2207        "break" | "continue" | "return" | "catch" | "throw" | "trap" => UnaryAction::Statement,
2208        "if" | "while" | "try" | "for" | "new" => UnaryAction::Control,
2209        "TEST" | "time" | "timing" | "elapsedTime" | "elapsedTiming" | "breakpoint" | "profile"
2210        | "shield" | "step" | "finish" => UnaryAction::Debug,
2211        "symbol" | "global" | "local" | "threadLocal" | "threadVariable" => UnaryAction::Quote,
2212        _ => return None,
2213    })
2214}
2215
2216/// Parses info.
2217fn parse_info(token: &TokenTree) -> ParseInfo {
2218    if matches!(token, TokenTree::Punct(punctuation) if punctuation.text().is_empty()) {
2219        return ParseInfo::binary(PREC_APPLICATION, PREC_APPLICATION_RIGHT);
2220    }
2221    if let TokenTree::Group(group) = token {
2222        return match group.delim_kind() {
2223            DelimiterKind::Bracket | DelimiterKind::AngleBar => {
2224                ParseInfo::delimiter(PREC_COLLECTION)
2225            }
2226            DelimiterKind::Parenthesis | DelimiterKind::Brace => {
2227                ParseInfo::delimiter(PREC_APPLICATION)
2228            }
2229        };
2230    }
2231
2232    let text = parsing_spelling(token);
2233    if let Some(rule) = token_parse_rule(text) {
2234        let mut info = ParseInfo::from(rule);
2235        if let Some(action) = keyword_action(text) {
2236            info.unary = action;
2237        }
2238        return info;
2239    }
2240
2241    match token {
2242        TokenTree::Ident(_) | TokenTree::Literal(_) => ParseInfo::atom(PREC_APPLICATION),
2243        _ => ParseInfo::stop(PREC_APPLICATION),
2244    }
2245}
2246
2247#[cfg(test)]
2248mod tests {
2249    use super::{NativeCellParser, NativeCellState};
2250    use crate::cell_stream::frame_recovering;
2251    use crate::{Spanned, lex_str};
2252
2253    /// Cell boundaries are decided here, from the flat stream, using the same
2254    /// operator/clause/quote state the grammar needs. Verified against M2
2255    /// v1.26.05 for each case.
2256    #[test]
2257    fn cells_use_operator_clause_and_delimiter_state() {
2258        fn cells(source: &str) -> usize {
2259            let framed = frame_recovering(lex_str(source).unwrap());
2260            framed.cells.len() + usize::from(framed.incomplete.is_some())
2261        }
2262
2263        assert_eq!(cells("1\n2"), 2);
2264        assert_eq!(cells("1 +\n2"), 1);
2265        assert_eq!(cells("not\n1"), 1);
2266        assert_eq!(cells("1!\n2"), 2);
2267        assert_eq!(cells("if condition\nthen value"), 1);
2268        assert_eq!(cells("if condition\nthen value\nnext"), 2);
2269        assert_eq!(cells("symbol if\nnext"), 2);
2270        assert_eq!(cells("symbol +\nnext"), 2);
2271        assert_eq!(cells("1 -* comment\n*- 2"), 2);
2272        assert_eq!(cells("1 + -* comment\n*- 2"), 1);
2273        assert_eq!(cells("1;2"), 2);
2274        // A `;` inside brackets is an ordinary token, so the group stays one
2275        // cell and its contents are untouched by the embedding.
2276        assert_eq!(cells("(1\n2;3)"), 1);
2277        // The quoted `;` is data, not a boundary.
2278        assert_eq!(cells("symbol ;"), 1);
2279    }
2280
2281    #[test]
2282    fn invalid_binary_left_side_wins_over_a_missing_right_operand() {
2283        for (source, state, diagnostic, diagnostic_text) in [
2284            (
2285                "1 + 1 =",
2286                NativeCellState::Incomplete,
2287                "expected an operand after `=`, found end of input",
2288                "=",
2289            ),
2290            (
2291                "2 =",
2292                NativeCellState::Invalid,
2293                "invalid assignment target",
2294                "=",
2295            ),
2296            (
2297                "(x, y) ->",
2298                NativeCellState::Incomplete,
2299                "expected an operand after `->`, found end of input",
2300                "->",
2301            ),
2302            (
2303                "(x + y) ->",
2304                NativeCellState::Invalid,
2305                "invalid lambda argument list",
2306                "->",
2307            ),
2308        ] {
2309            let mut parser = NativeCellParser::new();
2310            assert_eq!(parser.push_line(source), state, "source: `{source}`");
2311            let error = parser
2312                .parse_error()
2313                .unwrap_or_else(|| panic!("expected a diagnostic for `{source}`"));
2314            assert_eq!(error.to_string(), diagnostic, "source: `{source}`");
2315            assert_eq!(error.span().text(), Some(diagnostic_text));
2316        }
2317    }
2318}