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
1480            if !muted.is_empty() || elements.as_ref().is_some_and(Components::is_punctuated) =>
1481        {
1482            let mut value = if elements.as_ref().is_some_and(Components::is_punctuated) {
1483                Sequence::new(
1484                    muted,
1485                    elements
1486                        .map(|elements| contents.packed_content(elements))
1487                        .transpose()?,
1488                )
1489            } else {
1490                let value = elements
1491                    .map(|elements| contents.only_expression(elements))
1492                    .transpose()?;
1493                let mut value = Holder::new(muted, value.map(Box::new));
1494                value.delimiter = typed_delimiter(delimiter_spans, opening_trivia, group_trailing);
1495                return Ok(value.into());
1496            };
1497            value.delimiter = typed_delimiter(delimiter_spans, opening_trivia, group_trailing);
1498            value.into()
1499        }
1500        DelimiterKind::Parenthesis => {
1501            let value = elements
1502                .map(|elements| contents.only_expression(elements))
1503                .transpose()?;
1504            let mut value = Holder::new(Vec::new(), value.map(Box::new));
1505            value.delimiter = typed_delimiter(delimiter_spans, opening_trivia, group_trailing);
1506            value.into()
1507        }
1508    };
1509    Ok(expression)
1510}
1511
1512/// Handles typed delimiter.
1513fn typed_delimiter<D: DelimiterToken>(
1514    spans: crate::DoubleSpan,
1515    opening_trivia: TrailingTrivia,
1516    closing_trivia: TrailingTrivia,
1517) -> D {
1518    let mut delimiter = D::new(spans);
1519    *delimiter.opening_trivia_mut() = opening_trivia;
1520    *delimiter.closing_trivia_mut() = closing_trivia;
1521    delimiter
1522}
1523
1524/// Lowers prefix statement.
1525fn lower_prefix_statement(keyword: SignificantToken, value: Option<Expr>) -> Expr {
1526    if is_token!(&keyword.token, break) {
1527        Expr!(Control::Break {
1528            break_token: typed_token(keyword),
1529            value: value.map(Box::new),
1530        })
1531    } else if is_token!(&keyword.token, continue) {
1532        Expr!(Control::Continue {
1533            continue_token: typed_token(keyword),
1534            value: value.map(Box::new),
1535        })
1536    } else if is_token!(&keyword.token, return) {
1537        Expr!(Control::Return {
1538            return_token: typed_token(keyword),
1539            value: value.map(Box::new),
1540        })
1541    } else {
1542        let value = value.expect("catch, throw, and trap require a value");
1543        if is_token!(&keyword.token, catch) {
1544            Expr!(Catch {
1545                catch_token: typed_token(keyword),
1546                value: Box::new(value),
1547            })
1548        } else if is_token!(&keyword.token, throw) {
1549            Expr!(Throw {
1550                throw_token: typed_token(keyword),
1551                value: Box::new(value),
1552            })
1553        } else if is_token!(&keyword.token, trap) {
1554            Expr!(Trap {
1555                trap_token: typed_token(keyword),
1556                value: Box::new(value),
1557            })
1558        } else {
1559            unreachable!("statement actions are assigned only to statement keywords")
1560        }
1561    }
1562}
1563
1564/// Lowers atom.
1565fn lower_atom(token: SignificantToken) -> Result<Expr, NativeParseError> {
1566    match token.token {
1567        TokenTree::Ident(raw) => Ok(typed_terminal(
1568            Symbol::new(raw.text(), raw.expect_span()),
1569            token.trailing_trivia,
1570        )
1571        .into()),
1572        TokenTree::Literal(raw) => {
1573            let span = raw.expect_span();
1574            Ok(match raw.kind {
1575                LiteralKind::Integer => {
1576                    typed_terminal(IntegerLiteral::new(raw.text(), span), token.trailing_trivia)
1577                        .into()
1578                }
1579                LiteralKind::Float => {
1580                    typed_terminal(FloatLiteral::new(raw.text(), span), token.trailing_trivia)
1581                        .into()
1582                }
1583                LiteralKind::String => {
1584                    lower_string_literal(raw.text(), span, token.trailing_trivia)
1585                }
1586                LiteralKind::RawString => {
1587                    lower_raw_string_literal(raw.text(), span, token.trailing_trivia)
1588                }
1589            })
1590        }
1591        token => Err(unexpected!(token, "an expression")),
1592    }
1593}
1594
1595/// A left operand whose operator-specific structural requirements are valid.
1596enum BinaryLeft {
1597    /// The Expression alternative.
1598    Expression(Box<Expr>),
1599    /// The Assignment alternative.
1600    Assignment {
1601        /// The target.
1602        target: AssignmentTarget,
1603        /// The local.
1604        local: bool,
1605    },
1606    /// The Lambda alternative.
1607    Lambda(LambdaArguments),
1608}
1609
1610/// Internal alternatives for LambdaArguments.
1611pub(crate) enum LambdaArguments {
1612    /// The Variadic alternative.
1613    Variadic(Symbol),
1614    /// The List alternative.
1615    List(Box<Delimited<Option<ArgumentListContent>>>),
1616}
1617
1618impl BinaryLeft {
1619    /// Handles prepare.
1620    fn prepare(left: Expr, operator: &TokenTree) -> Result<Self, NativeParseError> {
1621        let span = operator.expect_span();
1622        Ok(match operator.spelling() {
1623            Some("=") => Self::Assignment {
1624                target: AssignmentTarget::parse(left, false, span)?,
1625                local: false,
1626            },
1627            Some(":=") => Self::Assignment {
1628                target: AssignmentTarget::parse(left, true, span)?,
1629                local: true,
1630            },
1631            Some("->") => Self::Lambda(
1632                lambda_arguments(left).ok_or(NativeParseError::InvalidLambdaArguments { span })?,
1633            ),
1634            _ => Self::Expression(Box::new(left)),
1635        })
1636    }
1637}
1638
1639/// A parsed expression that can occur to the left of an assignment operator.
1640enum AssignmentTarget {
1641    /// The Symbol alternative.
1642    Symbol(Symbol),
1643    /// The Operator alternative.
1644    Operator(ExprOp),
1645    /// The New alternative.
1646    New(ExprNew),
1647    /// The List alternative.
1648    List(Box<AssignmentList>),
1649}
1650
1651impl AssignmentTarget {
1652    /// Handles parse.
1653    fn parse(expression: Expr, local: bool, span: Span) -> Result<Self, NativeParseError> {
1654        match expression {
1655            Expr::Symbol(variable) => Ok(Self::Symbol(variable)),
1656            Expr::Op(expression) => Ok(Self::Operator(expression)),
1657            Expr::New(statement) if local => Ok(Self::New(statement)),
1658            expression => assignment_list(expression)
1659                .map(Box::new)
1660                .map(Self::List)
1661                .ok_or(NativeParseError::InvalidAssignmentTarget { span }),
1662        }
1663    }
1664}
1665
1666/// Lowers binary.
1667fn lower_binary(
1668    left: BinaryLeft,
1669    operator: SignificantToken,
1670    right: Expr,
1671) -> Result<Expr, NativeParseError> {
1672    let span = operator.token.expect_span();
1673    let spelling = operator
1674        .token
1675        .spelling()
1676        .expect("binary actions are assigned only to spelled tokens");
1677    match left {
1678        BinaryLeft::Assignment { target, local } => {
1679            Ok(lower_assignment(target, operator, right, local))
1680        }
1681        BinaryLeft::Lambda(arguments) => Ok(match arguments {
1682            LambdaArguments::Variadic(argument) => Expr!(Lambda::Variadic {
1683                argument,
1684                operator: typed_token(operator),
1685                body: Box::new(right),
1686            }),
1687            LambdaArguments::List(arguments) => Expr!(Lambda::List {
1688                arguments: *arguments,
1689                operator: typed_token(operator),
1690                body: Box::new(right),
1691            }),
1692        }),
1693        BinaryLeft::Expression(left) if spelling == "<-" => Ok(Expr!(Assign::Evaluated {
1694            evaluated_domain: left,
1695            operator: typed_token(operator),
1696            value: Box::new(right),
1697        })),
1698        BinaryLeft::Expression(left) if spelling == "=>" => Ok(Expr!(Option {
1699            key: left,
1700            operator: typed_token(operator),
1701            value: Box::new(right),
1702        })),
1703        BinaryLeft::Expression(left)
1704            if GENERATED_AUGMENTED_OPERATOR_SPELLINGS.contains(&spelling) =>
1705        {
1706            let operator = AugmentedOperator::from_token_tree_with_trivia(
1707                operator.token,
1708                operator.trailing_trivia,
1709            )
1710            .expect("the augmented operator table and category have the same source");
1711            Ok(Expr!(Assign::Augmented {
1712                target: left,
1713                operator,
1714                value: Box::new(right),
1715            }))
1716        }
1717        BinaryLeft::Expression(left) if matches!(spelling, "." | ".?") => Ok(match spelling {
1718            "." => Expr!(Op::Bin::Member::Dot {
1719                receiver: left,
1720                operator: typed_token::<Token![.]>(operator),
1721                member: Box::new(right),
1722            }),
1723            ".?" => Expr!(Op::Bin::Member::Optional {
1724                receiver: left,
1725                operator: typed_token::<Token![.?]>(operator),
1726                member: Box::new(right),
1727            }),
1728            _ => unreachable!(),
1729        }),
1730        BinaryLeft::Expression(left) if spelling == "#" => Ok(Expr!(Op::Bin::Index {
1731            receiver: left,
1732            operator: typed_token(operator),
1733            index: Box::new(right),
1734        })),
1735        BinaryLeft::Expression(left) => {
1736            let spelling = spelling.to_owned();
1737            let operator = BinaryOperator::from_token_tree_with_trivia(
1738                operator.token,
1739                operator.trailing_trivia,
1740            )
1741            .ok_or(NativeParseError::Unsupported {
1742                syntax: spelling,
1743                span,
1744            })?;
1745            Ok(Expr!(Op::Bin::Regular {
1746                left_operand: left,
1747                operator,
1748                right_operand: Box::new(right),
1749            }))
1750        }
1751    }
1752}
1753
1754/// Lowers assignment.
1755fn lower_assignment(
1756    target: AssignmentTarget,
1757    operator: SignificantToken,
1758    right: Expr,
1759    local: bool,
1760) -> Expr {
1761    match (local, target) {
1762        (false, AssignmentTarget::Symbol(variable)) => {
1763            Expr!(Assign::Simple::Global {
1764                variable,
1765                operator: typed_token(operator),
1766                value: Box::new(right),
1767            })
1768        }
1769        (true, AssignmentTarget::Symbol(variable)) => {
1770            Expr!(Assign::Simple::Local {
1771                variable,
1772                operator: typed_token(operator),
1773                value: Box::new(right),
1774            })
1775        }
1776        (false, AssignmentTarget::Operator(argument_expr)) => {
1777            Expr!(Assign::Op {
1778                argument_expr,
1779                operator: typed_token(operator),
1780                value_expr: Box::new(right),
1781            })
1782        }
1783        (true, AssignmentTarget::Operator(ExprOp::Bin(ExprOpBin::Adj(application)))) => {
1784            let (typical_value, function) = installation_value(right);
1785            Expr!(Assign::Install::Method {
1786                method: application.left_operand,
1787                operator: application.operator,
1788                signature: application.right_operand,
1789                assign_op: typed_token(operator),
1790                typical_value,
1791                function: Box::new(function),
1792            })
1793        }
1794        (true, AssignmentTarget::Operator(domain_expr)) => {
1795            let (typical_value, function) = installation_value(right);
1796            Expr!(Assign::Install::Op {
1797                domain_expr,
1798                assign_op: typed_token(operator),
1799                typical_value,
1800                function: Box::new(function),
1801            })
1802        }
1803        (true, AssignmentTarget::New(new_statement)) => {
1804            Expr!(Assign::Install::New {
1805                new_statement,
1806                operator: typed_token(operator),
1807                function: Box::new(right),
1808            })
1809        }
1810        (local, AssignmentTarget::List(argument_list)) => {
1811            if local {
1812                Expr!(Assign::Parallel::Local {
1813                    argument_list,
1814                    operator: typed_token(operator),
1815                    value: Box::new(right),
1816                })
1817            } else {
1818                Expr!(Assign::Parallel::Global {
1819                    argument_list,
1820                    operator: typed_token(operator),
1821                    value: Box::new(right),
1822                })
1823            }
1824        }
1825        (false, AssignmentTarget::New(_)) => {
1826            unreachable!("global assignment preparation rejects new statements")
1827        }
1828    }
1829}
1830
1831/// Handles installation value.
1832pub(crate) fn installation_value(value: Expr) -> (Option<TypeAnnotation>, Expr) {
1833    match value {
1834        Expr::Option(value) => (
1835            Some(TypeAnnotation::new(value.key, value.operator)),
1836            *value.value,
1837        ),
1838        value => (None, value),
1839    }
1840}
1841
1842/// Parses cell stream.
1843fn parse_cell_stream(cells: CellStream) -> Result<SourceFile, NativeParseError> {
1844    let mut elements = Vec::new();
1845    let bof_span = cells.physical_bof();
1846    let eof_span = cells.physical_eof();
1847    // Comments of a comment-only cell lead the next cell that has tokens, or
1848    // close the file when no such cell follows.
1849    let mut detached = Vec::new();
1850    let mut cells = cells.into_iter().peekable();
1851    while let Some(cell) = cells.next() {
1852        if cell.is_empty() {
1853            detached.extend(CommentTrivia::of(&cell.into_parser_token_stream()).into_trivia());
1854            continue;
1855        }
1856        let eoc = cells
1857            .peek()
1858            .and_then(cell_start_span)
1859            .unwrap_or_else(|| end_span(&cell));
1860        if let Some(element) = parse_raw_cell_at(cell, eoc, std::mem::take(&mut detached))? {
1861            elements.push(element);
1862        }
1863    }
1864    let mut source_file = SourceFile::new(BOF::new("", bof_span), elements, EOF::new("", eof_span));
1865    source_file.set_closing_comments(detached);
1866    Ok(source_file)
1867}
1868
1869/// Handles tokenize for native parser.
1870fn tokenize_for_native_parser(tokens: TokenStream) -> Result<CellStream, NativeParseError> {
1871    match tokens.to_cell_stream() {
1872        Ok(cells) => Ok(cells),
1873        Err(tokenize_error) => {
1874            let incomplete = frame_recovering(tokens).incomplete;
1875            if let Some(cell) = incomplete
1876                && let Err(parse_error) = parse_raw_cell(cell)
1877            {
1878                return Err(parse_error);
1879            }
1880            Err(NativeParseError::Tokenize(tokenize_error))
1881        }
1882    }
1883}
1884
1885/// Parses raw cell.
1886pub(crate) fn parse_raw_cell(
1887    tokens: CellTokenStream,
1888) -> Result<Option<crate::nodes::Cell>, NativeParseError> {
1889    let eoc = end_span(&tokens);
1890    parse_raw_cell_at(tokens, eoc, Vec::new())
1891}
1892
1893/// Parses raw cell at.
1894///
1895/// `detached` comments, which precede the cell outside it, lead the comments
1896/// before its first token in the cell's leading trivia.
1897fn parse_raw_cell_at(
1898    tokens: CellTokenStream,
1899    eoc: Span,
1900    mut detached: Vec<Trivia>,
1901) -> Result<Option<crate::nodes::Cell>, NativeParseError> {
1902    let ends_with_semicolon = ends_with_cell_semicolon(&tokens);
1903    let mut tokens = tokens.into_parser_token_stream();
1904    detached.extend(tokens.take_prefix_trivia().into_vec());
1905    let semicolon = ends_with_semicolon
1906        .then(|| tokens.take_final_punctuation(";"))
1907        .flatten()
1908        .map(|(punctuation, trailing_trivia)| {
1909            <Token![;] as Token>::from_token_tree_with_trivia(
1910                TokenTree::Punct(punctuation),
1911                trailing_trivia,
1912            )
1913            .expect("a semicolon punctuation token lowers to Token![;]")
1914        });
1915    let mut cell = Engine::new(tokens).parse_cell(semicolon, eoc)?;
1916    if let Some(cell) = &mut cell {
1917        cell.leading_trivia = LeadingTrivia::new(detached);
1918    }
1919    Ok(cell)
1920}
1921
1922/// Handles cell start span.
1923fn cell_start_span(tokens: &CellTokenStream) -> Option<Span> {
1924    let token = tokens.iter().next()?;
1925    let span = token
1926        .leading_trivia()
1927        .first()
1928        .map_or_else(|| token.span(), Spanned::span);
1929    span.start().map(|start| span.at(start))
1930}
1931
1932impl Parse for Expr {
1933    fn parse(input: &mut ParseStream) -> Result<Self, TokenParseError> {
1934        let tokens = input.by_ref().collect::<TokenStream>();
1935        let mut engine = Engine::new(tokens);
1936        engine.skip_trivia();
1937        let value = engine
1938            .parse_required(PREC_CLOSER)
1939            .map_err(token_parse_error)?;
1940        engine.skip_trivia();
1941        match engine.peek() {
1942            Lookahead::End(_) => Ok(value),
1943            Lookahead::Token(token) => Err(TokenParseError::TrailingToken {
1944                found: token.token.description(),
1945                span: token.token.expect_span(),
1946            }),
1947        }
1948    }
1949}
1950
1951impl Parse for SourceFile {
1952    fn parse(input: &mut ParseStream) -> Result<Self, TokenParseError> {
1953        let tokens = input.by_ref().collect();
1954        tokenize_for_native_parser(tokens)
1955            .and_then(parse_cell_stream)
1956            .map_err(token_parse_error)
1957    }
1958}
1959
1960/// Handles token parse error.
1961fn token_parse_error(error: NativeParseError) -> TokenParseError {
1962    let span = error.expect_span();
1963    TokenParseError::Syntax {
1964        message: error.to_string(),
1965        span,
1966    }
1967}
1968
1969/// Handles parsing spelling.
1970fn parsing_spelling(token: &TokenTree) -> &str {
1971    token.spelling().map_or("", canonical_word_spelling)
1972}
1973
1974/// Handles typed token.
1975fn typed_token<T: Token>(token: SignificantToken) -> T {
1976    let spelling = token.token.description();
1977    T::from_token_tree_with_trivia(token.token, token.trailing_trivia)
1978        .unwrap_or_else(|| panic!("`{spelling}` cannot be lowered to `{}`", T::SPELLING))
1979}
1980
1981/// Handles typed terminal.
1982fn typed_terminal<T: Terminal>(mut terminal: T, trailing_trivia: TrailingTrivia) -> T {
1983    *terminal.trailing_trivia_mut() = trailing_trivia;
1984    terminal
1985}
1986
1987/// Handles empty span at.
1988fn empty_span_at(lookahead: &Span) -> Span {
1989    lookahead.subspan(0, 0)
1990}
1991
1992/// Lowers string literal.
1993fn lower_string_literal(text: &str, span: Span, trailing_trivia: TrailingTrivia) -> Expr {
1994    let body_end = if text.len() > 1 && text.ends_with('"') {
1995        text.len() - 1
1996    } else {
1997        text.len()
1998    };
1999    let body = &text[1..body_end];
2000    let mut elements = Vec::new();
2001    let mut content_start = 0;
2002    let mut cursor = 0;
2003
2004    while cursor < body.len() {
2005        if body.as_bytes()[cursor] != b'\\' {
2006            cursor += 1;
2007            continue;
2008        }
2009        if content_start < cursor {
2010            elements.push(StringElement::Content(StringContent::new(
2011                &body[content_start..cursor],
2012                span.subspan(content_start + 1, cursor + 1),
2013            )));
2014        }
2015        let escape_end = match body.as_bytes()[cursor + 1] {
2016            b'x' => cursor + 4,
2017            b'u' => cursor + 6,
2018            b'0'..=b'7' => {
2019                let mut end = cursor + 2;
2020                while end < body.len()
2021                    && end < cursor + 4
2022                    && body.as_bytes()[end].is_ascii_digit()
2023                    && body.as_bytes()[end] < b'8'
2024                {
2025                    end += 1;
2026                }
2027                end
2028            }
2029            _ => cursor + 2,
2030        };
2031        elements.push(StringElement::Escape(EscapeSequence::new(
2032            &body[cursor..escape_end],
2033            span.subspan(cursor + 1, escape_end + 1),
2034        )));
2035        cursor = escape_end;
2036        content_start = cursor;
2037    }
2038    if content_start < body.len() {
2039        elements.push(StringElement::Content(StringContent::new(
2040            &body[content_start..],
2041            span.subspan(content_start + 1, body_end),
2042        )));
2043    }
2044    typed_terminal(StringLiteral::new(elements, span), trailing_trivia).into()
2045}
2046
2047/// Lowers raw string literal.
2048fn lower_raw_string_literal(text: &str, span: Span, trailing_trivia: TrailingTrivia) -> Expr {
2049    let body_end = if text.len() >= 6 && text.ends_with("///") {
2050        text.len() - 3
2051    } else {
2052        text.len()
2053    };
2054    let body = &text[3..body_end];
2055    let mut elements = Vec::new();
2056    let mut content_start = 0;
2057    let mut cursor = 0;
2058
2059    while cursor + 1 < body.len() {
2060        if &body.as_bytes()[cursor..cursor + 2] != b"//" {
2061            cursor += 1;
2062            continue;
2063        }
2064        if content_start < cursor {
2065            elements.push(RawStringElement::Content(RawStringContent::new(
2066                &body[content_start..cursor],
2067                span.subspan(content_start + 3, cursor + 3),
2068            )));
2069        }
2070        elements.push(RawStringElement::Escape(EscapeSequence::new(
2071            "//",
2072            span.subspan(cursor + 3, cursor + 5),
2073        )));
2074        cursor += 2;
2075        content_start = cursor;
2076    }
2077    if content_start < body.len() {
2078        elements.push(RawStringElement::Content(RawStringContent::new(
2079            &body[content_start..],
2080            span.subspan(content_start + 3, body_end),
2081        )));
2082    }
2083    typed_terminal(RawStringLiteral::new(elements, span), trailing_trivia).into()
2084}
2085
2086/// Handles collection contents.
2087fn collection_contents(expression: Expr) -> Option<(crate::Delimiter, Option<PackedContent>)> {
2088    match expression {
2089        Expr::Collection(ExprCollection::Sequence(value)) if value.statements.is_empty() => {
2090            Some((DelimiterValue::delimiter(&value.delimiter), value.elements))
2091        }
2092        Expr::Collection(ExprCollection::List(value)) if value.statements.is_empty() => {
2093            Some((DelimiterValue::delimiter(&value.delimiter), value.elements))
2094        }
2095        Expr::Collection(ExprCollection::Array(value)) if value.statements.is_empty() => {
2096            Some((DelimiterValue::delimiter(&value.delimiter), value.elements))
2097        }
2098        Expr::Collection(ExprCollection::AngleBar(value)) if value.statements.is_empty() => {
2099            Some((DelimiterValue::delimiter(&value.delimiter), value.elements))
2100        }
2101        Expr::Holder(value) if value.muted.is_empty() => {
2102            let elements = value.value.map(|value| (*value).into());
2103            Some((DelimiterValue::delimiter(&value.delimiter), elements))
2104        }
2105        _ => None,
2106    }
2107}
2108
2109/// Handles assignment list.
2110pub(crate) fn assignment_list(expression: Expr) -> Option<AssignmentList> {
2111    let (delimiter, elements) = collection_contents(expression)?;
2112    let contents = match elements {
2113        Some(elements) => {
2114            let components = packed_components(elements).map(assignment_argument)?;
2115            Some(match components.into_punctuated() {
2116                Ok(arguments) => AssignmentListContent!(Pack { arguments }),
2117                Err(argument) => argument.into(),
2118            })
2119        }
2120        None => None,
2121    };
2122    Some(AssignmentList::new(Delimited::new(delimiter, contents)))
2123}
2124
2125/// Handles assignment argument.
2126fn assignment_argument(component: Component) -> Option<AssignmentArgument> {
2127    match component {
2128        Component::Empty(value) => Some(AssignmentArgument::Empty(value)),
2129        Component::Expr(value) => match *value {
2130            Expr::Symbol(value) => Some(AssignmentArgument::Symbol(value)),
2131            Expr::Op(value) => Some(AssignmentArgument::Op(value)),
2132            Expr::Assign(ExprAssign::Evaluated(value)) => {
2133                Some(AssignmentArgument::Evaluated(value))
2134            }
2135            value => assignment_list(value).map(Into::into),
2136        },
2137    }
2138}
2139
2140/// Handles expr pack symbols.
2141fn expr_pack_symbols(elements: ExprPack) -> Option<Punctuated<Symbol>> {
2142    elements
2143        .pack
2144        .try_map(
2145            |component| match component {
2146                Component::Expr(value) => match *value {
2147                    Expr::Symbol(value) => Ok(value),
2148                    _ => Err(()),
2149                },
2150                Component::Empty(_) => Err(()),
2151            },
2152            Ok,
2153        )
2154        .ok()
2155}
2156
2157/// Handles packed components.
2158fn packed_components(content: PackedContent) -> Components<Component> {
2159    match content {
2160        PackedContent::Expr(expression) => Components {
2161            first: Component::Expr(expression),
2162            rest: Vec::new(),
2163        },
2164        PackedContent::Pack(pack) => Components::from_punctuated(pack.pack),
2165    }
2166}
2167
2168/// Handles lambda arguments.
2169pub(crate) fn lambda_arguments(expression: Expr) -> Option<LambdaArguments> {
2170    match expression {
2171        Expr::Symbol(value) => Some(LambdaArguments::Variadic(value)),
2172        expression => {
2173            let (delimiter, elements) = collection_contents(expression)?;
2174            let arguments = match elements {
2175                Some(PackedContent::Expr(expression)) => match *expression {
2176                    Expr::Symbol(value) => Some(ArgumentListContent::Symbol(value)),
2177                    _ => return None,
2178                },
2179                Some(PackedContent::Pack(pack)) => Some(ArgumentListContent!(Pack {
2180                    arguments: expr_pack_symbols(pack)?,
2181                })),
2182                None => None,
2183            };
2184            Some(LambdaArguments::List(Box::new(Delimited::new(
2185                delimiter, arguments,
2186            ))))
2187        }
2188    }
2189}
2190
2191/// The rule declared for a spelling, found in the generated table.
2192fn token_parse_rule(spelling: &str) -> Option<TokenParseRule> {
2193    TOKEN_PARSE_RULES
2194        .binary_search_by_key(&spelling, |(declared, _)| *declared)
2195        .ok()
2196        .map(|index| TOKEN_PARSE_RULES[index].1)
2197}
2198
2199/// Handles keyword action.
2200fn keyword_action(spelling: &str) -> Option<UnaryAction> {
2201    Some(match spelling {
2202        "break" | "continue" | "return" | "catch" | "throw" | "trap" => UnaryAction::Statement,
2203        "if" | "while" | "try" | "for" | "new" => UnaryAction::Control,
2204        "TEST" | "time" | "timing" | "elapsedTime" | "elapsedTiming" | "breakpoint" | "profile"
2205        | "shield" | "step" | "finish" => UnaryAction::Debug,
2206        "symbol" | "global" | "local" | "threadLocal" | "threadVariable" => UnaryAction::Quote,
2207        _ => return None,
2208    })
2209}
2210
2211/// Parses info.
2212fn parse_info(token: &TokenTree) -> ParseInfo {
2213    if matches!(token, TokenTree::Punct(punctuation) if punctuation.text().is_empty()) {
2214        return ParseInfo::binary(PREC_APPLICATION, PREC_APPLICATION_RIGHT);
2215    }
2216    if let TokenTree::Group(group) = token {
2217        return match group.delim_kind() {
2218            DelimiterKind::Bracket | DelimiterKind::AngleBar => {
2219                ParseInfo::delimiter(PREC_COLLECTION)
2220            }
2221            DelimiterKind::Parenthesis | DelimiterKind::Brace => {
2222                ParseInfo::delimiter(PREC_APPLICATION)
2223            }
2224        };
2225    }
2226
2227    let text = parsing_spelling(token);
2228    if let Some(rule) = token_parse_rule(text) {
2229        let mut info = ParseInfo::from(rule);
2230        if let Some(action) = keyword_action(text) {
2231            info.unary = action;
2232        }
2233        return info;
2234    }
2235
2236    match token {
2237        TokenTree::Ident(_) | TokenTree::Literal(_) => ParseInfo::atom(PREC_APPLICATION),
2238        _ => ParseInfo::stop(PREC_APPLICATION),
2239    }
2240}
2241
2242#[cfg(test)]
2243mod tests {
2244    use super::{NativeCellParser, NativeCellState};
2245    use crate::cell_stream::frame_recovering;
2246    use crate::{Spanned, lex_str};
2247
2248    /// Cell boundaries are decided here, from the flat stream, using the same
2249    /// operator/clause/quote state the grammar needs. Verified against M2
2250    /// v1.26.05 for each case.
2251    #[test]
2252    fn cells_use_operator_clause_and_delimiter_state() {
2253        fn cells(source: &str) -> usize {
2254            let framed = frame_recovering(lex_str(source).unwrap());
2255            framed.cells.len() + usize::from(framed.incomplete.is_some())
2256        }
2257
2258        assert_eq!(cells("1\n2"), 2);
2259        assert_eq!(cells("1 +\n2"), 1);
2260        assert_eq!(cells("not\n1"), 1);
2261        assert_eq!(cells("1!\n2"), 2);
2262        assert_eq!(cells("if condition\nthen value"), 1);
2263        assert_eq!(cells("if condition\nthen value\nnext"), 2);
2264        assert_eq!(cells("symbol if\nnext"), 2);
2265        assert_eq!(cells("symbol +\nnext"), 2);
2266        assert_eq!(cells("1 -* comment\n*- 2"), 2);
2267        assert_eq!(cells("1 + -* comment\n*- 2"), 1);
2268        assert_eq!(cells("1;2"), 2);
2269        // A `;` inside brackets is an ordinary token, so the group stays one
2270        // cell and its contents are untouched by the embedding.
2271        assert_eq!(cells("(1\n2;3)"), 1);
2272        // The quoted `;` is data, not a boundary.
2273        assert_eq!(cells("symbol ;"), 1);
2274    }
2275
2276    #[test]
2277    fn invalid_binary_left_side_wins_over_a_missing_right_operand() {
2278        for (source, state, diagnostic, diagnostic_text) in [
2279            (
2280                "1 + 1 =",
2281                NativeCellState::Incomplete,
2282                "expected an operand after `=`, found end of input",
2283                "=",
2284            ),
2285            (
2286                "2 =",
2287                NativeCellState::Invalid,
2288                "invalid assignment target",
2289                "=",
2290            ),
2291            (
2292                "(x, y) ->",
2293                NativeCellState::Incomplete,
2294                "expected an operand after `->`, found end of input",
2295                "->",
2296            ),
2297            (
2298                "(x + y) ->",
2299                NativeCellState::Invalid,
2300                "invalid lambda argument list",
2301                "->",
2302            ),
2303        ] {
2304            let mut parser = NativeCellParser::new();
2305            assert_eq!(parser.push_line(source), state, "source: `{source}`");
2306            let error = parser
2307                .parse_error()
2308                .unwrap_or_else(|| panic!("expected a diagnostic for `{source}`"));
2309            assert_eq!(error.to_string(), diagnostic, "source: `{source}`");
2310            assert_eq!(error.span().text(), Some(diagnostic_text));
2311        }
2312    }
2313}