Skip to main content

m2_syn/
native.rs

1//! Direct construction of the typed graph from [`CellStream`](crate::CellStream).
2//!
3//! The native precedence engine owns parsing decisions only. Token storage,
4//! cursor position, trivia skipping, and newline detection belong to
5//! [`ParseStream`](crate::ParseStream), shared with generated [`Parse`](crate::Parse)
6//! implementations.
7
8use std::error::Error;
9use std::fmt::{Display, Formatter};
10use std::option::Option;
11
12use crate::lexer::canonical_keyword_spelling;
13use crate::parse::{Lookahead, SignificantToken};
14use crate::{
15    AngleBarList, AnyCell, Array, Assignment, AssignmentExpr, BinaryAssignment, BinaryExpression,
16    BinaryInstallation, BinaryOperator, BindingPack, BreakStatement, CatchStatement, CellStream,
17    Collection, Component, ContinueStatement, DebugClause, DebugKeyword, DelimiterKind, ElseClause,
18    EmptyComponent, EvaluatedAssignment, ExceptClause, Expr, ExpressionCell, FloatLiteral, ForLoop,
19    IfStatement, IntegerLiteral, IterationRange, LambdaExpression, LambdaParameters, LexError,
20    List, LiteralKind, LocalAssignment, LocalStructuredBinding, LoopBody, MutedCell, MutedGroup,
21    NakedSequence, NewStatement, OperatorExpr, OptionExpression, PREC_APPLICATION,
22    PREC_APPLICATION_RIGHT, PREC_CLOSER, PREC_COLLECTION, PREC_COMMA, PREC_CONTROL,
23    PREC_LOOP_CLAUSE, PREC_QUOTE, PREC_SEMICOLON, ParenthesizedExpression, Parse, ParseStream,
24    Parser, PostfixAssignment, PostfixExpression, PostfixInstallation, PostfixOperator,
25    PrefixAssignment, PrefixExpression, PrefixInstallation, PrefixOperator, Punctuated,
26    QuoteExpression, QuoteSpecifier, RawStringContent, RawStringElement, RawStringLiteral,
27    ReturnStatement, Sequence, SequenceCell, SourceFile, SourceId, Span, Spanned, StringContent,
28    StringElement, StringLiteral, StructuredBinding, Symbol, ThenClause, ThrowStatement,
29    TokenParseError, TokenStream, TokenTree, TrapStatement, TryFallback, TryStatement, WhileLoop,
30    lex_str,
31};
32
33macro_rules! is_token {
34    ($token:expr, $($pattern:tt)*) => {
35        <Token![$($pattern)*] as crate::Token>::matches_token_tree($token)
36    };
37}
38
39/// The built-in parser implemented directly from Macaulay2's `P/B/U` table.
40#[derive(Debug, Default)]
41pub struct NativeParser;
42
43impl NativeParser {
44    pub fn new() -> Self {
45        Self
46    }
47}
48
49impl Parser for NativeParser {
50    type Error = NativeParseError;
51
52    fn parse_cells(&mut self, tokens: CellStream) -> Result<SourceFile, Self::Error> {
53        parse_cells(tokens)
54    }
55}
56
57pub fn parse_native(source: &str, source_id: SourceId) -> Result<SourceFile, NativeParseError> {
58    let tokens = lex_str(source, source_id).map_err(NativeParseError::Lex)?;
59    NativeParser.parse_cells(tokens)
60}
61
62#[derive(Debug, Spanned)]
63pub enum NativeParseError {
64    Lex(LexError),
65    Unexpected {
66        found: String,
67        expected: &'static str,
68        span: Span,
69    },
70    MissingOperand {
71        operator: String,
72        span: Span,
73    },
74    NewlineInApplication {
75        span: Span,
76    },
77    InvalidAssignmentTarget {
78        span: Span,
79    },
80    InvalidLambdaParameters {
81        span: Span,
82    },
83    Unsupported {
84        syntax: String,
85        span: Span,
86    },
87}
88
89impl Display for NativeParseError {
90    fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
91        match self {
92            Self::Lex(error) => error.fmt(formatter),
93            Self::Unexpected {
94                found, expected, ..
95            } => write!(formatter, "expected {expected}, found `{found}`"),
96            Self::MissingOperand { operator, .. } => {
97                write!(formatter, "operator `{operator}` requires an operand")
98            }
99            Self::NewlineInApplication { .. } => {
100                formatter.write_str("implicit application cannot cross a line break")
101            }
102            Self::InvalidAssignmentTarget { .. } => {
103                formatter.write_str("invalid assignment target")
104            }
105            Self::InvalidLambdaParameters { .. } => {
106                formatter.write_str("invalid lambda parameter list")
107            }
108            Self::Unsupported { syntax, .. } => {
109                write!(
110                    formatter,
111                    "native parsing of `{syntax}` is not implemented yet"
112                )
113            }
114        }
115    }
116}
117
118impl Error for NativeParseError {
119    fn source(&self) -> Option<&(dyn Error + 'static)> {
120        match self {
121            Self::Lex(error) => Some(error),
122            _ => None,
123        }
124    }
125}
126
127#[derive(Debug, Clone, Copy)]
128/// Parser-local instruction for interpreting a token in unary position.
129///
130/// This is not a syntax category and is never stored in the token stream or
131/// typed CST. [`parse_info`] derives it temporarily from the current raw token
132/// so the precedence engine can select the corresponding parsing routine.
133enum UnaryAction {
134    Atom,
135    Prefix,
136    Statement,
137    Control,
138    Debug,
139    Delimiter,
140    Quote,
141    Error,
142}
143
144#[derive(Debug, Clone, Copy)]
145struct ParseInfo {
146    precedence: u8,
147    binary_strength: Option<u8>,
148    unary_strength: Option<u8>,
149    unary: UnaryAction,
150    postfix: bool,
151}
152
153impl ParseInfo {
154    const fn atom(precedence: u8) -> Self {
155        Self {
156            precedence,
157            binary_strength: None,
158            unary_strength: None,
159            unary: UnaryAction::Atom,
160            postfix: false,
161        }
162    }
163
164    const fn binary(precedence: u8, strength: u8) -> Self {
165        Self {
166            precedence,
167            binary_strength: Some(strength),
168            unary_strength: None,
169            unary: UnaryAction::Error,
170            postfix: false,
171        }
172    }
173
174    const fn prefix_binary(precedence: u8, binary_strength: u8, unary_strength: u8) -> Self {
175        Self {
176            precedence,
177            binary_strength: Some(binary_strength),
178            unary_strength: Some(unary_strength),
179            unary: UnaryAction::Prefix,
180            postfix: false,
181        }
182    }
183
184    const fn prefix(precedence: u8, unary_strength: u8) -> Self {
185        Self {
186            precedence,
187            binary_strength: None,
188            unary_strength: Some(unary_strength),
189            unary: UnaryAction::Prefix,
190            postfix: false,
191        }
192    }
193
194    const fn statement() -> Self {
195        Self {
196            precedence: PREC_APPLICATION,
197            binary_strength: None,
198            unary_strength: Some(PREC_CONTROL),
199            unary: UnaryAction::Statement,
200            postfix: false,
201        }
202    }
203
204    const fn control(unary_strength: u8) -> Self {
205        Self {
206            precedence: PREC_APPLICATION,
207            binary_strength: None,
208            unary_strength: Some(unary_strength),
209            unary: UnaryAction::Control,
210            postfix: false,
211        }
212    }
213
214    const fn debug() -> Self {
215        Self {
216            precedence: PREC_APPLICATION,
217            binary_strength: None,
218            unary_strength: Some(PREC_CONTROL),
219            unary: UnaryAction::Debug,
220            postfix: false,
221        }
222    }
223
224    const fn postfix(precedence: u8) -> Self {
225        Self {
226            precedence,
227            binary_strength: None,
228            unary_strength: None,
229            unary: UnaryAction::Error,
230            postfix: true,
231        }
232    }
233
234    const fn delimiter(precedence: u8) -> Self {
235        Self {
236            precedence,
237            binary_strength: None,
238            unary_strength: Some(PREC_CLOSER),
239            unary: UnaryAction::Delimiter,
240            postfix: false,
241        }
242    }
243
244    const fn stop(precedence: u8) -> Self {
245        Self {
246            precedence,
247            binary_strength: None,
248            unary_strength: None,
249            unary: UnaryAction::Error,
250            postfix: false,
251        }
252    }
253
254    const fn quote(precedence: u8, unary_strength: u8) -> Self {
255        Self {
256            precedence,
257            binary_strength: None,
258            unary_strength: Some(unary_strength),
259            unary: UnaryAction::Quote,
260            postfix: false,
261        }
262    }
263}
264
265struct Engine {
266    input: ParseStream,
267}
268
269impl Engine {
270    fn new(tokens: TokenStream) -> Self {
271        Self {
272            input: ParseStream::new(tokens),
273        }
274    }
275
276    fn parse_cell(
277        mut self,
278        delimiter: crate::Delimiter,
279    ) -> Result<Option<AnyCell>, NativeParseError> {
280        self.skip_trivia();
281        if matches!(self.peek(), Lookahead::End(_)) {
282            return match delimiter.kind {
283                DelimiterKind::Empty => Ok(None),
284                DelimiterKind::Semicolon => Err(NativeParseError::Unexpected {
285                    found: ";".into(),
286                    expected: "a statement before `;`",
287                    span: delimiter.closing_span(),
288                }),
289                _ => Err(NativeParseError::Unexpected {
290                    found: delimiter.kind.to_string(),
291                    expected: "an empty or semicolon cell delimiter",
292                    span: delimiter.span(),
293                }),
294            };
295        }
296
297        let (components, comma) = self.parse_components()?;
298
299        if let Lookahead::Token(token) = self.peek() {
300            return Err(self.unexpected(token.token, "the end of the cell"));
301        }
302
303        let cell = match delimiter.kind {
304            DelimiterKind::Semicolon => AnyCell::MutedCell(MutedCell::new(
305                components,
306                Token![;](delimiter.closing_span()),
307            )),
308            DelimiterKind::Empty if comma => {
309                AnyCell::SequenceCell(SequenceCell::new(NakedSequence::new(components)))
310            }
311            DelimiterKind::Empty => {
312                let value = self.only_expression(components)?;
313                AnyCell::ExpressionCell(ExpressionCell::new(value))
314            }
315            _ => {
316                return Err(NativeParseError::Unexpected {
317                    found: delimiter.kind.to_string(),
318                    expected: "an empty or semicolon cell delimiter",
319                    span: delimiter.span(),
320                });
321            }
322        };
323        Ok(Some(cell))
324    }
325
326    fn parse_components(&mut self) -> Result<(Punctuated<Component>, bool), NativeParseError> {
327        if self.at_end() || self.at_punctuation(";") {
328            return Ok((Punctuated::new(), false));
329        }
330
331        let first = if self.at_punctuation(",") {
332            Component::EmptyComponent(EmptyComponent::new("", self.peek().span()))
333        } else {
334            Component::Expr(self.parse_required(PREC_COMMA)?)
335        };
336        let mut elements = Punctuated::from_value(first);
337        let mut has_comma = false;
338
339        while let Some(comma) = self.take_punctuation(",") {
340            has_comma = true;
341            let next = if self.at_end() || self.at_punctuation(";") || self.at_punctuation(",") {
342                Component::EmptyComponent(EmptyComponent::new("", self.peek().span()))
343            } else {
344                Component::Expr(self.parse_required(PREC_COMMA)?)
345            };
346            elements.push(typed_token(comma), next);
347        }
348
349        Ok((elements, has_comma))
350    }
351
352    fn parse_required(&mut self, level: u8) -> Result<Expr, NativeParseError> {
353        let token = match self.consume() {
354            Lookahead::Token(token) => token,
355            Lookahead::End(span) => {
356                return Err(NativeParseError::MissingOperand {
357                    operator: "end of input".into(),
358                    span,
359                });
360            }
361        };
362        self.parse_consumed(token, level)
363    }
364
365    fn parse_nullable(&mut self, level: u8) -> Result<Option<Expr>, NativeParseError> {
366        let lookahead = self.peek();
367        let Lookahead::Token(token) = lookahead else {
368            return Ok(None);
369        };
370        if parse_info(&token.token).precedence <= level {
371            return Ok(None);
372        }
373        let Lookahead::Token(token) = self.consume() else {
374            unreachable!("the token just peeked is consumable")
375        };
376        self.parse_consumed(token, level).map(Some)
377    }
378
379    fn parse_consumed(
380        &mut self,
381        token: SignificantToken,
382        level: u8,
383    ) -> Result<Expr, NativeParseError> {
384        let info = parse_info(&token.token);
385        let result = match info.unary {
386            UnaryAction::Atom => self.lower_atom(token.token)?,
387            UnaryAction::Prefix => {
388                let strength = info.unary_strength.expect("prefix operators have U");
389                let operand = self.parse_required(level.max(strength))?;
390                let span = token.token.span();
391                let spelling = token_description(&token.token);
392                let operator = PrefixOperator::from_token_tree(token.token).ok_or({
393                    NativeParseError::Unsupported {
394                        syntax: spelling,
395                        span,
396                    }
397                })?;
398                PrefixExpression::new(operator, operand).into()
399            }
400            UnaryAction::Statement => {
401                let strength = info
402                    .unary_strength
403                    .expect("prefix statements have a unary binding strength");
404                let operand = if is_token!(&token.token, break)
405                    || is_token!(&token.token, continue)
406                    || is_token!(&token.token, return)
407                {
408                    self.parse_nullable(level.max(strength))?
409                } else {
410                    self.parse_required(level.max(strength))
411                        .map_err(|error| {
412                            if matches!(error, NativeParseError::MissingOperand { .. }) {
413                                NativeParseError::MissingOperand {
414                                    operator: token_description(&token.token),
415                                    span: token.token.span(),
416                                }
417                            } else {
418                                error
419                            }
420                        })?
421                        .into()
422                };
423                self.lower_prefix_statement(token.token, operand)
424            }
425            UnaryAction::Control => {
426                if is_token!(&token.token, if) {
427                    self.parse_if_statement(token.token)?
428                } else if is_token!(&token.token, for) {
429                    self.parse_for_loop(token.token)?
430                } else if is_token!(&token.token, while) {
431                    self.parse_while_loop(token.token)?
432                } else if is_token!(&token.token, try) {
433                    self.parse_try_statement(token.token)?
434                } else if is_token!(&token.token, new) {
435                    self.parse_new_statement(token.token)?
436                } else {
437                    unreachable!("control actions are assigned only to control keywords")
438                }
439            }
440            UnaryAction::Debug => self.parse_debug_clause(token.token)?,
441            UnaryAction::Delimiter => self.parse_delimited(token.token)?,
442            UnaryAction::Quote => {
443                let operator = token_description(&token.token);
444                let quoted = match self.consume() {
445                    Lookahead::Token(quoted) => quoted.token,
446                    Lookahead::End(span) => {
447                        return Err(NativeParseError::MissingOperand { operator, span });
448                    }
449                };
450                let specifier = if is_token!(&token.token, symbol) {
451                    QuoteSpecifier::Symbol(typed_token(token.token))
452                } else if is_token!(&token.token, local) {
453                    QuoteSpecifier::Local(typed_token(token.token))
454                } else if is_token!(&token.token, global) {
455                    QuoteSpecifier::Global(typed_token(token.token))
456                } else if is_token!(&token.token, threadVariable) {
457                    QuoteSpecifier::ThreadVariable(typed_token(token.token))
458                } else if is_token!(&token.token, threadLocal) {
459                    QuoteSpecifier::ThreadLocal(typed_token(token.token))
460                } else {
461                    unreachable!("quote actions are assigned only to quote specifiers")
462                };
463                let quoted_span = quoted.span();
464                let Some(quoted_text) = token_spelling(&quoted).map(str::to_owned) else {
465                    return Err(self.unexpected(quoted, "a quoted token"));
466                };
467                let quoted = Symbol::new(quoted_text, quoted_span);
468                QuoteExpression::new(specifier, quoted).into()
469            }
470            UnaryAction::Error => return Err(self.unexpected(token.token, "an expression")),
471        };
472        self.accumulate(result, level)
473    }
474
475    fn lower_prefix_statement(&self, keyword: TokenTree, value: Option<Expr>) -> Expr {
476        if is_token!(&keyword, break) {
477            BreakStatement::new(typed_token(keyword), value).into()
478        } else if is_token!(&keyword, continue) {
479            ContinueStatement::new(typed_token(keyword), value).into()
480        } else if is_token!(&keyword, return) {
481            ReturnStatement::new(typed_token(keyword), value).into()
482        } else if is_token!(&keyword, catch) {
483            CatchStatement::new(
484                typed_token(keyword),
485                value.expect("catch statements require a value"),
486            )
487            .into()
488        } else if is_token!(&keyword, throw) {
489            ThrowStatement::new(
490                typed_token(keyword),
491                value.expect("throw statements require a value"),
492            )
493            .into()
494        } else if is_token!(&keyword, trap) {
495            TrapStatement::new(
496                typed_token(keyword),
497                value.expect("trap statements require a value"),
498            )
499            .into()
500        } else {
501            unreachable!("statement actions are assigned only to statement keywords")
502        }
503    }
504
505    fn parse_if_statement(&mut self, keyword: TokenTree) -> Result<Expr, NativeParseError> {
506        let condition = self.required_clause_expression(PREC_CONTROL, &keyword)?;
507        let then_keyword = self.consume_exact("then")?;
508        let then_value = self.required_clause_expression(PREC_CONTROL, &then_keyword)?;
509        let then_clause = ThenClause::new(typed_token(then_keyword), then_value);
510        let else_clause = self
511            .take_exact("else")
512            .map(|else_keyword| {
513                let value = self.required_clause_expression(PREC_CONTROL, &else_keyword)?;
514                Ok::<_, NativeParseError>(ElseClause::new(typed_token(else_keyword), value))
515            })
516            .transpose()?;
517        Ok(IfStatement::new(typed_token(keyword), condition, then_clause, else_clause).into())
518    }
519
520    fn parse_for_loop(&mut self, keyword: TokenTree) -> Result<Expr, NativeParseError> {
521        let variable = self.consume_symbol("a loop variable")?;
522
523        let mut in_keyword = None;
524        let mut iterated_collection = None;
525        let mut from_keyword = None;
526        let mut range_start = None;
527        let mut to_keyword = None;
528        let mut range_end = None;
529
530        if let Some(token) = self.take_exact("in") {
531            iterated_collection = Some(self.required_clause_expression(PREC_LOOP_CLAUSE, &token)?);
532            in_keyword = Some(typed_token(token));
533        } else {
534            if let Some(token) = self.take_exact("from") {
535                range_start = Some(self.required_clause_expression(PREC_LOOP_CLAUSE, &token)?);
536                from_keyword = Some(typed_token(token));
537            }
538            if let Some(token) = self.take_exact("to") {
539                range_end = Some(self.required_clause_expression(PREC_LOOP_CLAUSE, &token)?);
540                to_keyword = Some(typed_token(token));
541            }
542        }
543
544        let range =
545            (in_keyword.is_some() || from_keyword.is_some() || to_keyword.is_some()).then(|| {
546                IterationRange::new(
547                    in_keyword,
548                    iterated_collection,
549                    from_keyword,
550                    range_start,
551                    to_keyword,
552                    range_end,
553                )
554            });
555
556        let (when_keyword, filter) = if let Some(token) = self.take_exact("when") {
557            let filter = self.required_clause_expression(PREC_LOOP_CLAUSE, &token)?;
558            (Some(typed_token(token)), Some(filter))
559        } else {
560            (None, None)
561        };
562        let body = self.parse_loop_body()?;
563
564        Ok(ForLoop::new(
565            typed_token(keyword),
566            variable,
567            range,
568            when_keyword,
569            filter,
570            body,
571        )
572        .into())
573    }
574
575    fn parse_while_loop(&mut self, keyword: TokenTree) -> Result<Expr, NativeParseError> {
576        let condition = self.required_clause_expression(PREC_CONTROL, &keyword)?;
577        let body = self.parse_loop_body()?;
578        Ok(WhileLoop::new(typed_token(keyword), condition, body).into())
579    }
580
581    fn parse_loop_body(&mut self) -> Result<LoopBody, NativeParseError> {
582        let mut list_keyword = None;
583        let mut listed_value = None;
584        let mut do_keyword = None;
585        let mut ignored_value = None;
586
587        if let Some(token) = self.take_exact("list") {
588            listed_value = Some(self.required_clause_expression(PREC_CONTROL, &token)?);
589            list_keyword = Some(typed_token(token));
590            if let Some(token) = self.take_exact("do") {
591                ignored_value = Some(self.required_clause_expression(PREC_CONTROL, &token)?);
592                do_keyword = Some(typed_token(token));
593            }
594        } else if let Some(token) = self.take_exact("do") {
595            ignored_value = Some(self.required_clause_expression(PREC_CONTROL, &token)?);
596            do_keyword = Some(typed_token(token));
597        } else {
598            return Err(self.expected_at_lookahead("`list` or `do`"));
599        }
600
601        Ok(LoopBody::new(
602            list_keyword,
603            listed_value,
604            do_keyword,
605            ignored_value,
606        ))
607    }
608
609    fn parse_try_statement(&mut self, keyword: TokenTree) -> Result<Expr, NativeParseError> {
610        let value = self.required_clause_expression(PREC_CONTROL, &keyword)?;
611        let then_clause = self
612            .take_exact("then")
613            .map(|then_keyword| {
614                let value = self.required_clause_expression(PREC_CONTROL, &then_keyword)?;
615                Ok::<_, NativeParseError>(ThenClause::new(typed_token(then_keyword), value))
616            })
617            .transpose()?;
618
619        let fallback = if let Some(else_keyword) = self.take_exact("else") {
620            let value = self.required_clause_expression(PREC_CONTROL, &else_keyword)?;
621            Some(TryFallback::ElseClause(ElseClause::new(
622                typed_token(else_keyword),
623                value,
624            )))
625        } else if let Some(except_keyword) = self.take_exact("except") {
626            let exception = self.consume_symbol("an exception symbol")?;
627            let do_keyword = self.consume_exact("do")?;
628            let value = self.required_clause_expression(PREC_CONTROL, &do_keyword)?;
629            Some(TryFallback::ExceptClause(ExceptClause::new(
630                typed_token(except_keyword),
631                exception,
632                typed_token(do_keyword),
633                value,
634            )))
635        } else {
636            None
637        };
638
639        Ok(TryStatement::new(typed_token(keyword), value, then_clause, fallback).into())
640    }
641
642    fn parse_new_statement(&mut self, keyword: TokenTree) -> Result<Expr, NativeParseError> {
643        let class = self.required_clause_expression(PREC_LOOP_CLAUSE, &keyword)?;
644        let (of_keyword, parent) = if let Some(token) = self.take_exact("of") {
645            let parent = self.required_clause_expression(PREC_LOOP_CLAUSE, &token)?;
646            (Some(typed_token(token)), Some(parent))
647        } else {
648            (None, None)
649        };
650        let (from_keyword, instance) = if let Some(token) = self.take_exact("from") {
651            let instance = self.required_clause_expression(PREC_LOOP_CLAUSE, &token)?;
652            (Some(typed_token(token)), Some(instance))
653        } else {
654            (None, None)
655        };
656
657        Ok(NewStatement::new(
658            typed_token(keyword),
659            class,
660            of_keyword,
661            parent,
662            from_keyword,
663            instance,
664        )
665        .into())
666    }
667
668    fn parse_debug_clause(&mut self, keyword: TokenTree) -> Result<Expr, NativeParseError> {
669        let span = keyword.span();
670        let spelling = parsing_spelling(&keyword).to_owned();
671        let value_is_optional = matches!(spelling.as_str(), "step" | "finish");
672        let value = if value_is_optional {
673            self.parse_nullable(PREC_CONTROL)?
674        } else {
675            Some(self.parse_required(PREC_CONTROL).map_err(|error| {
676                if matches!(error, NativeParseError::MissingOperand { .. }) {
677                    NativeParseError::MissingOperand {
678                        operator: token_description(&keyword),
679                        span,
680                    }
681                } else {
682                    error
683                }
684            })?)
685        };
686        let keyword = match spelling.as_str() {
687            "step" => DebugKeyword::Step(typed_token(keyword)),
688            "finish" => DebugKeyword::Finish(typed_token(keyword)),
689            "shield" => DebugKeyword::Shield(typed_token(keyword)),
690            "TEST" => DebugKeyword::Test(typed_token(keyword)),
691            "time" => DebugKeyword::Time(typed_token(keyword)),
692            "timing" => DebugKeyword::Timing(typed_token(keyword)),
693            "breakpoint" => DebugKeyword::Breakpoint(typed_token(keyword)),
694            "elapsedTime" => DebugKeyword::ElapsedTime(typed_token(keyword)),
695            "elapsedTiming" => DebugKeyword::ElapsedTiming(typed_token(keyword)),
696            "profile" => DebugKeyword::Profile(typed_token(keyword)),
697            _ => unreachable!("debug actions are assigned only to debug keywords"),
698        };
699        Ok(DebugClause::new(keyword, value).into())
700    }
701
702    fn required_clause_expression(
703        &mut self,
704        level: u8,
705        keyword: &TokenTree,
706    ) -> Result<Expr, NativeParseError> {
707        match self.parse_nullable(level)? {
708            None => Err(NativeParseError::MissingOperand {
709                operator: token_description(keyword),
710                span: keyword.span(),
711            }),
712            Some(expression) => Ok(expression),
713        }
714    }
715
716    fn consume_symbol(&mut self, expected: &'static str) -> Result<Symbol, NativeParseError> {
717        match self.consume() {
718            Lookahead::Token(token)
719                if matches!(token.token, TokenTree::Ident(_))
720                    && matches!(parse_info(&token.token).unary, UnaryAction::Atom) =>
721            {
722                let span = token.token.span();
723                let text = token_description(&token.token);
724                Ok(Symbol::new(text, span))
725            }
726            Lookahead::Token(token) => Err(self.unexpected(token.token, expected)),
727            Lookahead::End(span) => Err(NativeParseError::Unexpected {
728                found: "end of input".into(),
729                expected,
730                span,
731            }),
732        }
733    }
734
735    fn consume_exact(&mut self, spelling: &'static str) -> Result<TokenTree, NativeParseError> {
736        match self.consume() {
737            Lookahead::Token(token) if parsing_spelling(&token.token) == spelling => {
738                Ok(token.token)
739            }
740            Lookahead::Token(token) => Err(self.unexpected(token.token, spelling)),
741            Lookahead::End(span) => Err(NativeParseError::Unexpected {
742                found: "end of input".into(),
743                expected: spelling,
744                span,
745            }),
746        }
747    }
748
749    fn take_exact(&mut self, spelling: &'static str) -> Option<TokenTree> {
750        if matches!(
751            self.peek(),
752            Lookahead::Token(token)
753                if parsing_spelling(&token.token) == spelling
754        ) {
755            let Lookahead::Token(token) = self.consume() else {
756                unreachable!("the token just peeked is consumable")
757            };
758            Some(token.token)
759        } else {
760            None
761        }
762    }
763
764    fn expected_at_lookahead(&self, expected: &'static str) -> NativeParseError {
765        match self.peek() {
766            Lookahead::Token(token) => self.unexpected(token.token, expected),
767            Lookahead::End(span) => NativeParseError::Unexpected {
768                found: "end of input".into(),
769                expected,
770                span,
771            },
772        }
773    }
774
775    fn accumulate(&mut self, mut left: Expr, level: u8) -> Result<Expr, NativeParseError> {
776        loop {
777            let Lookahead::Token(next) = self.peek() else {
778                return Ok(left);
779            };
780            let info = parse_info(&next.token);
781            if info.precedence <= level {
782                return Ok(left);
783            }
784            let Lookahead::Token(operator) = self.consume() else {
785                unreachable!("the token just peeked is consumable")
786            };
787            left = if let Some(strength) = info.binary_strength {
788                let right = self.parse_required(strength).map_err(|error| {
789                    if matches!(error, NativeParseError::MissingOperand { .. }) {
790                        NativeParseError::MissingOperand {
791                            operator: token_description(&operator.token),
792                            span: operator.token.span(),
793                        }
794                    } else {
795                        error
796                    }
797                })?;
798                self.lower_binary(left, operator.token, right)?
799            } else if info.postfix {
800                let span = operator.token.span();
801                let spelling = token_description(&operator.token);
802                let operator = PostfixOperator::from_token_tree(operator.token).ok_or(
803                    NativeParseError::Unsupported {
804                        syntax: spelling,
805                        span,
806                    },
807                )?;
808                PostfixExpression::new(left, operator).into()
809            } else if !matches!(info.unary, UnaryAction::Error) {
810                if operator.crossed_newline {
811                    return Err(NativeParseError::NewlineInApplication {
812                        span: operator.token.span(),
813                    });
814                }
815                let adjacency_span = operator.leading_span;
816                let right = self.parse_consumed(operator, PREC_APPLICATION_RIGHT)?;
817                BinaryExpression::new(
818                    left,
819                    BinaryOperator::from(Token![SPACE](adjacency_span)),
820                    right,
821                )
822                .into()
823            } else {
824                return Err(self.unexpected(operator.token, "an operator"));
825            };
826        }
827    }
828
829    fn parse_delimited(&mut self, token: TokenTree) -> Result<Expr, NativeParseError> {
830        let TokenTree::Group(group) = token else {
831            return Err(self.unexpected(token, "a delimited group"));
832        };
833        let kind = group.delim_kind();
834        let delimiter_span = group.span();
835        let mut contents = Self::new(group.into_stream());
836        let mut muted = Vec::new();
837        let (elements, comma) = loop {
838            let (elements, comma) = contents.parse_components()?;
839            let Some(separator) = contents.take_punctuation(";") else {
840                break (elements, comma);
841            };
842            if elements.is_empty() {
843                return Err(contents.unexpected(separator, "a statement before `;`"));
844            }
845            muted.push(MutedGroup::new(elements, typed_token(separator)));
846        };
847        if let Lookahead::Token(token) = contents.peek() {
848            return Err(contents.unexpected(token.token, "the end of the group"));
849        }
850
851        let expression: Expr = match kind {
852            DelimiterKind::Empty | DelimiterKind::Semicolon => {
853                return Err(NativeParseError::Unsupported {
854                    syntax: format!("{} cell delimiter in expression position", kind),
855                    span: delimiter_span.span(),
856                });
857            }
858            DelimiterKind::Bracket => {
859                let mut value = Array::new(muted, elements);
860                value.delimiter = <Delimiter![[]] as crate::DelimiterToken>::new(delimiter_span);
861                value.into()
862            }
863            DelimiterKind::Brace => {
864                let mut value = List::new(muted, elements);
865                value.delimiter = <Delimiter![{}] as crate::DelimiterToken>::new(delimiter_span);
866                value.into()
867            }
868            DelimiterKind::AngleBar => {
869                let mut value = AngleBarList::new(muted, elements);
870                value.delimiter =
871                    <Delimiter![< | | >] as crate::DelimiterToken>::new(delimiter_span);
872                value.into()
873            }
874            DelimiterKind::Parenthesis if !muted.is_empty() || comma => {
875                let mut value = Sequence::new(muted, elements);
876                value.delimiter = <Delimiter![()] as crate::DelimiterToken>::new(delimiter_span);
877                value.into()
878            }
879            DelimiterKind::Parenthesis => {
880                let value = match elements.len() {
881                    0 => None,
882                    1 => Some(contents.only_expression(elements)?),
883                    _ => unreachable!("multiple components imply a comma"),
884                };
885                let mut value = ParenthesizedExpression::new(Vec::new(), value);
886                value.delimiter = <Delimiter![()] as crate::DelimiterToken>::new(delimiter_span);
887                value.into()
888            }
889        };
890        Ok(expression)
891    }
892
893    fn lower_atom(&mut self, token: TokenTree) -> Result<Expr, NativeParseError> {
894        match token {
895            TokenTree::Ident(token) => {
896                let span = token.span();
897                Ok(Symbol::new(token.text(), span).into())
898            }
899            TokenTree::Literal(token) => {
900                let span = token.span();
901                let text = token.text().to_owned();
902                Ok(match token.kind {
903                    LiteralKind::Integer => IntegerLiteral::new(text, span).into(),
904                    LiteralKind::Float => FloatLiteral::new(text, span).into(),
905                    LiteralKind::String => lower_string_literal(text, span),
906                    LiteralKind::RawString => lower_raw_string_literal(text, span),
907                })
908            }
909            token => Err(self.unexpected(token, "an expression")),
910        }
911    }
912
913    fn lower_binary(
914        &mut self,
915        left: Expr,
916        operator: TokenTree,
917        right: Expr,
918    ) -> Result<Expr, NativeParseError> {
919        let span = operator.span();
920        let spelling = token_spelling(&operator)
921            .expect("binary actions are assigned only to spelled tokens")
922            .to_owned();
923        match spelling.as_str() {
924            "=" => self.lower_assignment(left, operator, right, false),
925            ":=" => self.lower_assignment(left, operator, right, true),
926            "<-" => Ok(EvaluatedAssignment::new(left, typed_token(operator), right).into()),
927            "=>" => Ok(OptionExpression::new(left, typed_token(operator), right).into()),
928            "->" => {
929                let parameters = lambda_parameters(left)
930                    .ok_or(NativeParseError::InvalidLambdaParameters { span })?;
931                Ok(LambdaExpression::new(parameters, typed_token(operator), right).into())
932            }
933            _ => {
934                let operator = BinaryOperator::from_token_tree(operator).ok_or({
935                    NativeParseError::Unsupported {
936                        syntax: spelling,
937                        span,
938                    }
939                })?;
940                Ok(BinaryExpression::new(left, operator, right).into())
941            }
942        }
943    }
944
945    fn lower_assignment(
946        &mut self,
947        left: Expr,
948        operator: TokenTree,
949        right: Expr,
950        local: bool,
951    ) -> Result<Expr, NativeParseError> {
952        let span = operator.span();
953        let result =
954            match (local, left) {
955                (false, Expr::Symbol(left)) => {
956                    AssignmentExpr::Assignment(Assignment::new(left, typed_token(operator), right))
957                }
958                (true, Expr::Symbol(left)) => AssignmentExpr::LocalAssignment(
959                    LocalAssignment::new(left, typed_token(operator), right),
960                ),
961                (false, Expr::Collection(left)) => AssignmentExpr::StructuredBinding(
962                    StructuredBinding::new(binding_pack(left), typed_token(operator), right),
963                ),
964                (true, Expr::Collection(left)) => AssignmentExpr::LocalStructuredBinding(
965                    LocalStructuredBinding::new(binding_pack(left), typed_token(operator), right),
966                ),
967                (false, Expr::OperatorExpr(OperatorExpr::BinaryExpression(left))) => {
968                    AssignmentExpr::BinaryAssignment(BinaryAssignment::new(
969                        left,
970                        typed_token(operator),
971                        right,
972                    ))
973                }
974                (true, Expr::OperatorExpr(OperatorExpr::BinaryExpression(left))) => {
975                    AssignmentExpr::BinaryInstallation(BinaryInstallation::new(
976                        left,
977                        typed_token(operator),
978                        right,
979                    ))
980                }
981                (false, Expr::OperatorExpr(OperatorExpr::PrefixExpression(left))) => {
982                    AssignmentExpr::PrefixAssignment(PrefixAssignment::new(
983                        left,
984                        typed_token(operator),
985                        right,
986                    ))
987                }
988                (true, Expr::OperatorExpr(OperatorExpr::PrefixExpression(left))) => {
989                    AssignmentExpr::PrefixInstallation(PrefixInstallation::new(
990                        left,
991                        typed_token(operator),
992                        right,
993                    ))
994                }
995                (false, Expr::OperatorExpr(OperatorExpr::PostfixExpression(left))) => {
996                    AssignmentExpr::PostfixAssignment(PostfixAssignment::new(
997                        left,
998                        typed_token(operator),
999                        right,
1000                    ))
1001                }
1002                (true, Expr::OperatorExpr(OperatorExpr::PostfixExpression(left))) => {
1003                    AssignmentExpr::PostfixInstallation(PostfixInstallation::new(
1004                        left,
1005                        typed_token(operator),
1006                        right,
1007                    ))
1008                }
1009                _ => return Err(NativeParseError::InvalidAssignmentTarget { span }),
1010            };
1011        Ok(Expr::AssignmentExpr(result))
1012    }
1013
1014    fn only_expression(&self, components: Punctuated<Component>) -> Result<Expr, NativeParseError> {
1015        let mut components = components.into_iter();
1016        match (components.next(), components.next()) {
1017            (Some(Component::Expr(value)), None) => Ok(value),
1018            (Some(value), _) => Err(NativeParseError::Unexpected {
1019                found: "a sequence".into(),
1020                expected: "one expression",
1021                span: value.span(),
1022            }),
1023            (None, _) => Err(NativeParseError::MissingOperand {
1024                operator: "empty expression".into(),
1025                span: self.input.eof_span(),
1026            }),
1027        }
1028    }
1029
1030    fn peek(&self) -> Lookahead {
1031        self.input.lookahead()
1032    }
1033
1034    fn consume(&mut self) -> Lookahead {
1035        self.input.consume_lookahead()
1036    }
1037
1038    fn skip_trivia(&mut self) {
1039        self.input.skip_trivia();
1040    }
1041
1042    fn at_end(&self) -> bool {
1043        matches!(self.peek(), Lookahead::End(_))
1044    }
1045
1046    fn at_punctuation(&self, spelling: &str) -> bool {
1047        matches!(
1048            self.peek(),
1049            Lookahead::Token(token)
1050                if token.token.spelling() == Some(spelling)
1051        )
1052    }
1053
1054    fn take_punctuation(&mut self, spelling: &str) -> Option<TokenTree> {
1055        if !self.at_punctuation(spelling) {
1056            return None;
1057        }
1058        let Lookahead::Token(token) = self.consume() else {
1059            unreachable!("the punctuation just peeked is consumable")
1060        };
1061        Some(token.token)
1062    }
1063
1064    fn unexpected(&self, token: TokenTree, expected: &'static str) -> NativeParseError {
1065        let span = token.span();
1066        NativeParseError::Unexpected {
1067            found: token_description(&token),
1068            expected,
1069            span,
1070        }
1071    }
1072}
1073
1074fn parse_cells(cells: CellStream) -> Result<SourceFile, NativeParseError> {
1075    let mut elements = Vec::new();
1076    for cell in cells {
1077        let delimiter = *cell.delimiter();
1078        if let Some(element) = Engine::new(cell.into_stream()).parse_cell(delimiter)? {
1079            elements.push(element);
1080        }
1081    }
1082    Ok(SourceFile::new(elements))
1083}
1084
1085impl Parse for Expr {
1086    fn parse(input: &mut ParseStream) -> Result<Self, TokenParseError> {
1087        let tokens = input.by_ref().collect::<TokenStream>();
1088        let mut engine = Engine::new(tokens);
1089        engine.skip_trivia();
1090        let value = engine
1091            .parse_required(PREC_CLOSER)
1092            .map_err(token_parse_error)?;
1093        engine.skip_trivia();
1094        match engine.peek() {
1095            Lookahead::End(_) => Ok(value),
1096            Lookahead::Token(token) => Err(TokenParseError::TrailingToken {
1097                found: token_description(&token.token),
1098                span: token.token.span(),
1099            }),
1100        }
1101    }
1102}
1103
1104impl Parse for SourceFile {
1105    fn parse(input: &mut ParseStream) -> Result<Self, TokenParseError> {
1106        let source_id = input
1107            .peek()
1108            .and_then(|token| token.span().source().ok())
1109            .unwrap_or_else(SourceId::fresh);
1110        let source = input.by_ref().collect::<TokenStream>().to_string();
1111        parse_native(&source, source_id).map_err(token_parse_error)
1112    }
1113}
1114
1115fn token_parse_error(error: NativeParseError) -> TokenParseError {
1116    let span = error.span();
1117    TokenParseError::Syntax {
1118        message: error.to_string(),
1119        span,
1120    }
1121}
1122
1123fn token_spelling(token: &TokenTree) -> Option<&str> {
1124    token.spelling()
1125}
1126
1127fn parsing_spelling(token: &TokenTree) -> &str {
1128    token_spelling(token)
1129        .map(canonical_keyword_spelling)
1130        .unwrap_or("")
1131}
1132
1133fn token_description(token: &TokenTree) -> String {
1134    match token {
1135        TokenTree::Group(group) => group.delim_kind().to_string(),
1136        TokenTree::Trivia(token) => token.text().to_owned(),
1137        _ => token_spelling(token).unwrap_or("").to_owned(),
1138    }
1139}
1140
1141fn typed_token<T: crate::cst::Token>(token: TokenTree) -> T {
1142    let spelling = token_description(&token);
1143    T::from_token_tree(token)
1144        .unwrap_or_else(|| panic!("`{spelling}` cannot be lowered to `{}`", T::SPELLING))
1145}
1146
1147fn lower_string_literal(text: String, span: Span) -> Expr {
1148    let body = &text[1..text.len() - 1];
1149    let elements = (!body.is_empty())
1150        .then(|| StringElement::StringContent(StringContent::new(body, span)))
1151        .into_iter()
1152        .collect();
1153    StringLiteral::new(elements).into()
1154}
1155
1156fn lower_raw_string_literal(text: String, span: Span) -> Expr {
1157    let body = &text[3..text.len() - 3];
1158    let elements = (!body.is_empty())
1159        .then(|| RawStringElement::RawStringContent(RawStringContent::new(body, span)))
1160        .into_iter()
1161        .collect();
1162    RawStringLiteral::new(elements).into()
1163}
1164
1165fn binding_pack(collection: Collection) -> BindingPack {
1166    match collection {
1167        Collection::ParenthesizedExpression(value) => BindingPack::ParenthesizedExpression(value),
1168        Collection::Sequence(value) => BindingPack::Sequence(value),
1169        Collection::List(value) => BindingPack::List(value),
1170        Collection::Array(value) => BindingPack::Array(value),
1171        Collection::AngleBarList(value) => BindingPack::AngleBarList(value),
1172    }
1173}
1174
1175fn lambda_parameters(expression: Expr) -> Option<LambdaParameters> {
1176    match expression {
1177        Expr::Symbol(value) => Some(LambdaParameters::Symbol(value)),
1178        Expr::Collection(Collection::ParenthesizedExpression(value)) => {
1179            Some(LambdaParameters::ParenthesizedExpression(value))
1180        }
1181        Expr::Collection(Collection::Sequence(value)) => Some(LambdaParameters::Sequence(value)),
1182        Expr::Collection(Collection::List(value)) => Some(LambdaParameters::List(value)),
1183        Expr::Collection(Collection::Array(value)) => Some(LambdaParameters::Array(value)),
1184        Expr::Collection(Collection::AngleBarList(value)) => {
1185            Some(LambdaParameters::AngleBarList(value))
1186        }
1187        _ => None,
1188    }
1189}
1190
1191fn parse_info(token: &TokenTree) -> ParseInfo {
1192    if let TokenTree::Group(group) = token {
1193        return match group.delim_kind() {
1194            DelimiterKind::Empty | DelimiterKind::Semicolon => ParseInfo::stop(PREC_CLOSER),
1195            DelimiterKind::Bracket | DelimiterKind::AngleBar => {
1196                ParseInfo::delimiter(PREC_COLLECTION)
1197            }
1198            DelimiterKind::Parenthesis | DelimiterKind::Brace => {
1199                ParseInfo::delimiter(PREC_APPLICATION)
1200            }
1201        };
1202    }
1203
1204    let text = parsing_spelling(token);
1205    if let Some(info) = __m2_syn_parse_info!(text, ParseInfo) {
1206        return info;
1207    }
1208
1209    if is_token!(token, ;) {
1210        return ParseInfo::stop(PREC_SEMICOLON);
1211    }
1212    if is_token!(token, ,) {
1213        return ParseInfo::stop(PREC_COMMA);
1214    }
1215    if is_token!(token, else)
1216        || is_token!(token, then)
1217        || is_token!(token, do)
1218        || is_token!(token, list)
1219        || is_token!(token, except)
1220    {
1221        return ParseInfo::stop(PREC_CONTROL);
1222    }
1223    if is_token!(token, when)
1224        || is_token!(token, of)
1225        || is_token!(token, in)
1226        || is_token!(token, from)
1227        || is_token!(token, to)
1228    {
1229        return ParseInfo::stop(PREC_LOOP_CLAUSE);
1230    }
1231
1232    if is_token!(token, break)
1233        || is_token!(token, continue)
1234        || is_token!(token, return)
1235        || is_token!(token, catch)
1236        || is_token!(token, throw)
1237        || is_token!(token, trap)
1238    {
1239        return ParseInfo::statement();
1240    }
1241
1242    let control_strength = if is_token!(token, for) || is_token!(token, new) {
1243        Some(PREC_LOOP_CLAUSE)
1244    } else if is_token!(token, if) || is_token!(token, while) || is_token!(token, try) {
1245        Some(PREC_CONTROL)
1246    } else {
1247        None
1248    };
1249    if let Some(strength) = control_strength {
1250        return ParseInfo::control(strength);
1251    }
1252
1253    if is_token!(token, TEST)
1254        || is_token!(token, time)
1255        || is_token!(token, timing)
1256        || is_token!(token, elapsedTime)
1257        || is_token!(token, elapsedTiming)
1258        || is_token!(token, breakpoint)
1259        || is_token!(token, profile)
1260        || is_token!(token, shield)
1261        || is_token!(token, step)
1262        || is_token!(token, finish)
1263    {
1264        return ParseInfo::debug();
1265    }
1266
1267    if is_token!(token, symbol)
1268        || is_token!(token, global)
1269        || is_token!(token, threadVariable)
1270        || is_token!(token, threadLocal)
1271        || is_token!(token, local)
1272    {
1273        return ParseInfo::quote(PREC_APPLICATION, PREC_QUOTE);
1274    }
1275
1276    match token {
1277        TokenTree::Ident(_) | TokenTree::Literal(_) => ParseInfo::atom(PREC_APPLICATION),
1278        _ => ParseInfo::stop(PREC_APPLICATION),
1279    }
1280}