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