Skip to main content

espy_ears/
lib.rs

1#![doc = include_str!("../README.md")]
2
3use dst_factory::make_dst_factory;
4use espy_eyes::{Lexer, Lexigram, Token};
5use std::iter::Peekable;
6
7#[cfg(test)]
8mod tests;
9
10#[derive(Debug, Eq, PartialEq)]
11pub enum Error<'source> {
12    /// An invalid token was encountered.
13    ///
14    /// The ast interprets an erroneous token as `None`,
15    /// which may lead to further error diagnostics.
16    ///
17    /// See: [`espy_eyes::Error`]
18    Lexer(espy_eyes::Error<'source>),
19    MissingToken {
20        /// Must contain at least one element.
21        expected: &'static [Lexigram],
22        /// A `None` token may have been caused by a Lexer error.
23        actual: Option<Token<'source>>,
24    },
25    /// Occurs when an expression is required,
26    /// but a token that ends expression context was immediately encountered.
27    ExpectedExpression(Option<Token<'source>>),
28    /// Occurs when a "root" [`Block`] encounters something which is not a statement or expression.
29    ExpectedStatementOrExpression(Token<'source>),
30    /// Occurs when parenthesis in an expression are unbalanced.
31    ///
32    /// [`Error::IncompleteExpression`] serves as the opening-parenthesis equivalent.
33    UnexpectedCloseParen(Token<'source>),
34    /// This error should only ever occur on [`Expression`]s,
35    /// so positioning can be derived from surrounding context.
36    IncompleteExpression,
37}
38
39/// Contains a list of the errors encountered by an ast node.
40#[derive(Debug, Default, Eq, PartialEq)]
41pub struct Diagnostics<'source> {
42    pub errors: Vec<Error<'source>>,
43}
44
45impl<'source> Diagnostics<'source> {
46    fn expect(
47        &mut self,
48        t: Option<espy_eyes::Result<'source>>,
49        expected: &'static [Lexigram],
50    ) -> Option<Token<'source>> {
51        let actual = self.wrap(t);
52        if actual.is_some_and(|actual| expected.contains(&actual.lexigram)) {
53            actual
54        } else {
55            self.errors.push(Error::MissingToken { expected, actual });
56            None
57        }
58    }
59
60    fn expect_expression(
61        &mut self,
62        lexer: &mut Peekable<Lexer<'source>>,
63    ) -> Option<Box<Expression<'source>>> {
64        let expression = Expression::new(lexer);
65        if expression.is_none() {
66            self.errors.push(Error::ExpectedExpression(
67                lexer.peek().copied().transpose().ok().flatten(),
68            ));
69        }
70        expression
71    }
72
73    fn next_if(
74        &mut self,
75        lexer: &mut Peekable<Lexer<'source>>,
76        expected: &'static [Lexigram],
77    ) -> Option<Token<'source>> {
78        self.expect(lexer.peek().copied(), expected).inspect(|_| {
79            lexer.next();
80        })
81    }
82
83    fn wrap(&mut self, t: Option<espy_eyes::Result<'source>>) -> Option<Token<'source>> {
84        match t? {
85            Ok(t) => Some(t),
86            Err(e) => {
87                let t = if let espy_eyes::Error {
88                    origin,
89                    kind: espy_eyes::ErrorKind::ReservedSymbol,
90                } = e
91                {
92                    Some(Token {
93                        origin,
94                        lexigram: Lexigram::Ident,
95                    })
96                } else {
97                    None
98                };
99                self.errors.push(Error::Lexer(e));
100                t
101            }
102        }
103    }
104}
105
106/// Components of an expression.
107///
108/// Expression evalutation is stack-based rather than using a syntax tree.
109#[derive(Debug, Eq, PartialEq)]
110pub enum Node<'source> {
111    Unit(Token<'source>, Token<'source>),
112    Bool(bool, Token<'source>),
113    Number(Token<'source>),
114    String(Token<'source>),
115    Variable(Token<'source>),
116    PointFreeParameter(Token<'source>),
117    Block(Box<Block<'source>>),
118    PointFreeFunction {
119        brace_pipe: Token<'source>,
120        body: Box<Block<'source>>,
121    },
122    If(Box<If<'source>>),
123    Match(Box<Match<'source>>),
124    Enum(Box<Enum<'source>>),
125
126    Pipe(Token<'source>),
127    Call(Token<'source>),
128    Bind(Token<'source>),
129    Positive(Token<'source>),
130    Negative(Token<'source>),
131    Annotation(Box<Annotation<'source>>),
132    Not(Token<'source>),
133    Deref(Token<'source>),
134    Mul(Token<'source>),
135    Div(Token<'source>),
136    Add(Token<'source>),
137    Sub(Token<'source>),
138    EqualTo(Token<'source>),
139    NotEqualTo(Token<'source>),
140    Greater(Token<'source>),
141    GreaterEqual(Token<'source>),
142    Lesser(Token<'source>),
143    LesserEqual(Token<'source>),
144    LogicalAnd(Token<'source>),
145    LogicalOr(Token<'source>),
146    Name {
147        name: Token<'source>,
148        colon_token: Token<'source>,
149    },
150    Field {
151        dot_token: Token<'source>,
152        index: Token<'source>,
153    },
154    OptionalField {
155        dot_question_token: Token<'source>,
156        index: Token<'source>,
157    },
158    Join(Token<'source>),
159    List {
160        length: u32,
161    },
162}
163
164#[derive(Debug, Eq, PartialEq)]
165enum Operation<'source> {
166    Call(Token<'source>),
167    Pipe(Token<'source>),
168    Bind(Token<'source>),
169    Positive(Token<'source>),
170    Negative(Token<'source>),
171    Annotation(Box<Annotation<'source>>),
172    Not(Token<'source>),
173    Deref(Token<'source>),
174    Mul(Token<'source>),
175    Div(Token<'source>),
176    Add(Token<'source>),
177    Sub(Token<'source>),
178    EqualTo(Token<'source>),
179    NotEqualTo(Token<'source>),
180    Greater(Token<'source>),
181    GreaterEqual(Token<'source>),
182    Lesser(Token<'source>),
183    LesserEqual(Token<'source>),
184    LogicalAnd(Token<'source>),
185    LogicalOr(Token<'source>),
186    Name {
187        name: Token<'source>,
188        colon_token: Token<'source>,
189    },
190    Field {
191        dot_token: Token<'source>,
192        index: Token<'source>,
193    },
194    OptionalField {
195        dot_question_token: Token<'source>,
196        index: Token<'source>,
197    },
198    Join(Token<'source>),
199}
200
201impl Operation<'_> {
202    // NOTE: please keep espybook/precedence.md up to date with this!
203    fn precedence(&self) -> usize {
204        match self {
205            Operation::Field { .. } | Operation::OptionalField { .. } | Operation::Deref(_) => 10,
206            Operation::Positive(_)
207            | Operation::Negative(_)
208            | Operation::Annotation(_)
209            | Operation::Not(_) => 9,
210            Operation::Mul(_) | Operation::Div(_) => 8,
211            Operation::Add(_) | Operation::Sub(_) => 7,
212            Operation::EqualTo(_)
213            | Operation::NotEqualTo(_)
214            | Operation::Greater(_)
215            | Operation::GreaterEqual(_)
216            | Operation::Lesser(_)
217            | Operation::LesserEqual(_) => 6,
218            Operation::LogicalAnd(_) => 5,
219            Operation::LogicalOr(_) => 4,
220            Operation::Name { .. } => 3,
221            Operation::Join(_) => 2,
222            Operation::Pipe(_) | Operation::Call(_) | Operation::Bind(_) => 1,
223        }
224    }
225
226    // NOTE: please keep espybook/precedence.md up to date with this!
227    fn left_associative(&self) -> bool {
228        match self {
229            Operation::Field { .. }
230            | Operation::OptionalField { .. }
231            | Operation::Deref(_)
232            | Operation::Mul(_)
233            | Operation::Div(_)
234            | Operation::Add(_)
235            | Operation::Sub(_)
236            | Operation::EqualTo(_)
237            | Operation::NotEqualTo(_)
238            | Operation::Greater(_)
239            | Operation::GreaterEqual(_)
240            | Operation::Lesser(_)
241            | Operation::LesserEqual(_)
242            | Operation::LogicalAnd(_)
243            | Operation::LogicalOr(_)
244            | Operation::Join(_)
245            | Operation::Call(_)
246            | Operation::Bind(_)
247            | Operation::Pipe(_) => true,
248            // Unary operators have to be here to avoid miscompilation
249            Operation::Positive(_)
250            | Operation::Negative(_)
251            | Operation::Annotation(_)
252            | Operation::Not(_)
253            | Operation::Name { .. } => false,
254        }
255    }
256}
257
258impl<'source> From<Operation<'source>> for Node<'source> {
259    fn from(op: Operation<'source>) -> Self {
260        match op {
261            Operation::Field { dot_token, index } => Node::Field { dot_token, index },
262            Operation::OptionalField {
263                dot_question_token,
264                index,
265            } => Node::OptionalField {
266                dot_question_token,
267                index,
268            },
269            Operation::Pipe(t) => Node::Pipe(t),
270            Operation::Bind(t) => Node::Bind(t),
271            Operation::Call(t) => Node::Call(t),
272            Operation::Positive(t) => Node::Positive(t),
273            Operation::Negative(t) => Node::Negative(t),
274            Operation::Annotation(t) => Node::Annotation(t),
275            Operation::Not(t) => Node::Not(t),
276            Operation::Deref(t) => Node::Deref(t),
277            Operation::Mul(t) => Node::Mul(t),
278            Operation::Div(t) => Node::Div(t),
279            Operation::Add(t) => Node::Add(t),
280            Operation::Sub(t) => Node::Sub(t),
281            Operation::EqualTo(t) => Node::EqualTo(t),
282            Operation::NotEqualTo(t) => Node::NotEqualTo(t),
283            Operation::Greater(t) => Node::Greater(t),
284            Operation::GreaterEqual(t) => Node::GreaterEqual(t),
285            Operation::Lesser(t) => Node::Lesser(t),
286            Operation::LesserEqual(t) => Node::LesserEqual(t),
287            Operation::LogicalAnd(t) => Node::LogicalAnd(t),
288            Operation::LogicalOr(t) => Node::LogicalOr(t),
289            Operation::Name { name, colon_token } => Node::Name { name, colon_token },
290            Operation::Join(t) => Node::Join(t),
291        }
292    }
293}
294
295/// This type should not contain an incomplete expression so long as there are no error diagnostics.
296#[derive(Debug, Eq, PartialEq)]
297#[make_dst_factory(pub)]
298pub struct Expression<'source> {
299    pub first_token: Option<Token<'source>>,
300    pub last_token: Option<Token<'source>>,
301    pub diagnostics: Diagnostics<'source>,
302    pub contents: [Node<'source>],
303}
304
305impl<'source> Expression<'source> {
306    /// Parse an expression until an unexpected token is upcoming (via peek).
307    pub fn new(lexer: &mut Peekable<Lexer<'source>>) -> Option<Box<Self>> {
308        Self::new_internal(lexer, None, None, false)
309    }
310
311    /// Parse an expression until an unexpected token is upcoming (via peek).
312    pub fn list(lexer: &mut Peekable<Lexer<'source>>) -> Option<Box<Self>> {
313        Self::new_internal(lexer, None, None, true)
314    }
315
316    pub fn new_point_free(
317        brace_pipe: Token<'source>,
318        lexer: &mut Peekable<Lexer<'source>>,
319    ) -> Option<Box<Self>> {
320        Self::new_internal(
321            lexer,
322            Some(Node::PointFreeParameter(brace_pipe)),
323            Some(brace_pipe),
324            false,
325        )
326    }
327
328    /// Parse an expression until an unexpected token is upcoming (via peek).
329    fn new_internal(
330        lexer: &mut Peekable<Lexer<'source>>,
331        first_node: Option<Node<'source>>,
332        mut last_token: Option<Token<'source>>,
333        list_mode: bool,
334    ) -> Option<Box<Self>> {
335        fn flush_by_precedence<'source>(
336            output: &mut Vec<Node<'source>>,
337            stack: &mut Vec<Operation<'source>>,
338            operator: &Operation<'source>,
339        ) {
340            while let Some(op) = stack.pop_if(|x| {
341                if operator.left_associative() {
342                    x.precedence() >= operator.precedence()
343                } else {
344                    x.precedence() > operator.precedence()
345                }
346            }) {
347                output.push(op.into());
348            }
349        }
350        fn push_with_precedence<'source>(
351            output: &mut Vec<Node<'source>>,
352            stack: &mut Vec<Operation<'source>>,
353            operator: Operation<'source>,
354        ) {
355            flush_by_precedence(output, stack, &operator);
356            stack.push(operator);
357        }
358        // List of tokens that imply the unary position.
359        // This is probably not the best way to do this.
360        const UNARY_POSITION: &[Lexigram] = &[
361            Lexigram::Plus,
362            Lexigram::Minus,
363            Lexigram::Star,
364            Lexigram::Slash,
365            Lexigram::Not,
366            Lexigram::Caret,
367            Lexigram::Pipe,
368            Lexigram::DoubleEqual,
369            Lexigram::BangEqual,
370            Lexigram::Greater,
371            Lexigram::GreaterEqual,
372            Lexigram::Lesser,
373            Lexigram::LesserEqual,
374            Lexigram::And,
375            Lexigram::Or,
376            Lexigram::Comma,
377            Lexigram::Colon,
378            // This one is used to lie entirely about what the last token is
379            // because @anno[tation] and [ list of things ] both use CloseSquare.
380            // I should REALLY stop using these for unary position.
381            Lexigram::At,
382        ];
383        // List of tokens which are well-known to end a (sub-)expression.
384        // Technically any token not recognized by the match block later in this
385        // function are capable of ending an expression, but only the following
386        // list will be considered "end of expression" for the purposes of
387        // trailing comma detection.
388        const EXPRESSION_TERMINATORS: &[Lexigram] = &[
389            Lexigram::CloseParen,
390            Lexigram::CloseSquare,
391            Lexigram::CloseBrace,
392            Lexigram::Then,
393            Lexigram::End,
394            Lexigram::SingleEqual,
395            Lexigram::Semicolon,
396        ];
397        let first_token = last_token.or_else(|| lexer.peek().copied().transpose().ok().flatten());
398        let mut diagnostics = Diagnostics::default();
399        let mut contents = Vec::from_iter(first_node);
400        let mut stack = Vec::new();
401        // It's fine to start this at one because empty expressions always yield unit.
402        let mut list_length = list_mode.then_some(1);
403        loop {
404            let unary_position = last_token.is_none_or(|t| UNARY_POSITION.contains(&t.lexigram));
405            let t = diagnostics.wrap(lexer.peek().copied());
406            macro_rules! lexi {
407                ($($name:ident)? @ $lexi:ident) => {
408                    Some($($name @)? Token {
409                        lexigram: Lexigram::$lexi,
410                        ..
411                    })
412                };
413            }
414            macro_rules! op {
415                ($op:ident($inner:expr)) => {
416                    push_with_precedence(&mut contents, &mut stack, Operation::$op($inner))
417                };
418            }
419            macro_rules! imp_op {
420                ($inner:expr) => {
421                    if let Some(list_length) = &mut list_length {
422                        // This resolves precedence as if a function call were occuring,
423                        // even though no instruction will be generated for the list until the end of this function.
424                        flush_by_precedence(&mut contents, &mut stack, &Operation::Call($inner));
425                        *list_length += 1;
426                    } else {
427                        push_with_precedence(&mut contents, &mut stack, Operation::Call($inner))
428                    }
429                };
430            }
431            match t {
432                // Terminals
433                //
434                // A terminal value outside of unary position implies a function call,
435                // so flush the operator stack in this case.
436                lexi!(number @ Number) => {
437                    if !unary_position {
438                        imp_op!(number);
439                    }
440                    contents.push(Node::Number(number));
441                }
442                lexi!(string @ String) => {
443                    if !unary_position {
444                        imp_op!(string);
445                    }
446                    contents.push(Node::String(string));
447                }
448                lexi!(ident @ Ident) => {
449                    if !unary_position {
450                        imp_op!(ident);
451                    }
452                    last_token = lexer.next().transpose().ok().flatten();
453                    if let Some(Ok(
454                        colon_token @ Token {
455                            lexigram: Lexigram::Colon,
456                            ..
457                        },
458                    )) = lexer.peek().copied()
459                    {
460                        last_token = lexer.next().transpose().ok().flatten();
461                        push_with_precedence(
462                            &mut contents,
463                            &mut stack,
464                            Operation::Name {
465                                name: ident,
466                                colon_token,
467                            },
468                        );
469                    } else {
470                        contents.push(Node::Variable(ident));
471                    }
472                    continue;
473                }
474                lexi!(t @ True) => {
475                    if !unary_position {
476                        imp_op!(t);
477                    }
478                    contents.push(Node::Bool(true, t));
479                }
480                lexi!(t @ False) => {
481                    if !unary_position {
482                        imp_op!(t);
483                    }
484                    contents.push(Node::Bool(false, t));
485                }
486                lexi!(t @ OpenParen) => {
487                    if !unary_position {
488                        imp_op!(t);
489                    }
490                    lexer.next();
491                    if let Some(close) = lexer.peek().copied().transpose().ok().flatten()
492                        && close.lexigram == Lexigram::CloseParen
493                    {
494                        contents.push(Node::Unit(t, close));
495                    } else {
496                        contents.push(Node::Block(Block::build(
497                            BlockResult::Expression(Expression::new(lexer)),
498                            Diagnostics::default(),
499                            [],
500                        )));
501                        diagnostics.expect(lexer.peek().copied(), &[Lexigram::CloseParen]);
502                    }
503                }
504                lexi!(t @ OpenSquare) => {
505                    if !unary_position {
506                        imp_op!(t);
507                    }
508                    lexer.next();
509                    contents.push(Node::Block(Block::build(
510                        BlockResult::Expression(Expression::list(lexer)),
511                        Diagnostics::default(),
512                        [],
513                    )));
514                    diagnostics.expect(lexer.peek().copied(), &[Lexigram::CloseSquare]);
515                }
516                lexi!(t @ OpenBrace) => {
517                    if !unary_position {
518                        imp_op!(t);
519                    }
520                    lexer.next();
521                    contents.push(Node::Block(Block::child(&mut *lexer)));
522                    diagnostics.expect(lexer.peek().copied(), &[Lexigram::CloseBrace]);
523                }
524                lexi!(t @ OpenBracePipe) => {
525                    if !unary_position {
526                        imp_op!(t);
527                    }
528                    lexer.next();
529                    let expression = Expression::new_point_free(t, lexer);
530                    if expression.is_none() {
531                        diagnostics.errors.push(Error::ExpectedExpression(
532                            lexer.peek().copied().transpose().ok().flatten(),
533                        ));
534                    }
535                    // Don't attempt to parse the semicolon if the expression already failed.
536                    let body = if expression.is_some()
537                        && let Some(Ok(semicolon_token)) = lexer.next_if(|x| {
538                            matches!(
539                                x,
540                                Ok(Token {
541                                    lexigram: Lexigram::Semicolon,
542                                    ..
543                                })
544                            )
545                        }) {
546                        Block::parse_after(
547                            Vec::from_iter([Statement::Sequence(Sequence {
548                                expression,
549                                semicolon_token,
550                            })]),
551                            &mut *lexer,
552                            false,
553                        )
554                    } else {
555                        Block::build(
556                            BlockResult::Expression(expression),
557                            Diagnostics::default(),
558                            [],
559                        )
560                    };
561                    contents.push(Node::PointFreeFunction {
562                        brace_pipe: t,
563                        body,
564                    });
565                    diagnostics.expect(lexer.peek().copied(), &[Lexigram::CloseBrace]);
566                }
567
568                // prefix operators
569                lexi!(t @ Plus) if unary_position => op!(Positive(t)),
570                lexi!(t @ Minus) if unary_position => op!(Negative(t)),
571                lexi!(t @ Not) if unary_position => op!(Not(t)),
572                lexi!(t @ At) if unary_position => {
573                    lexer.next();
574                    let annotation = Annotation::new(t, lexer);
575                    last_token = Some(t);
576                    op!(Annotation(Box::new(annotation)));
577                    continue;
578                }
579                // postfix
580                lexi!(dot_token @ Dot) if !unary_position => {
581                    last_token = lexer.next().transpose().ok().flatten();
582                    if let Some(index) =
583                        diagnostics.next_if(lexer, &[Lexigram::Ident, Lexigram::Number])
584                    {
585                        last_token = Some(index);
586                        push_with_precedence(
587                            &mut contents,
588                            &mut stack,
589                            Operation::Field { dot_token, index },
590                        );
591                    }
592                    continue;
593                }
594                lexi!(dot_question_token @ DotQuestion) if !unary_position => {
595                    last_token = lexer.next().transpose().ok().flatten();
596                    if let Some(index) =
597                        diagnostics.next_if(lexer, &[Lexigram::Ident, Lexigram::Number])
598                    {
599                        last_token = Some(index);
600                        push_with_precedence(
601                            &mut contents,
602                            &mut stack,
603                            Operation::OptionalField {
604                                dot_question_token,
605                                index,
606                            },
607                        );
608                    }
609                    continue;
610                }
611                lexi!(t @ DotStar) if !unary_position => op!(Deref(t)),
612                lexi!(t @ Bang) if !unary_position => op!(Bind(t)),
613                // infix operators
614                lexi!(t @ Plus) if !unary_position => op!(Add(t)),
615                lexi!(t @ Minus) if !unary_position => op!(Sub(t)),
616                lexi!(t @ Star) if !unary_position => op!(Mul(t)),
617                lexi!(t @ Slash) if !unary_position => op!(Div(t)),
618                lexi!(t @ Pipe) if !unary_position => op!(Pipe(t)),
619                lexi!(t @ DoubleEqual) if !unary_position => op!(EqualTo(t)),
620                lexi!(t @ BangEqual) if !unary_position => op!(NotEqualTo(t)),
621                lexi!(t @ Greater) if !unary_position => op!(Greater(t)),
622                lexi!(t @ GreaterEqual) if !unary_position => op!(GreaterEqual(t)),
623                lexi!(t @ Lesser) if !unary_position => op!(Lesser(t)),
624                lexi!(t @ LesserEqual) if !unary_position => op!(LesserEqual(t)),
625                lexi!(t @ And) if !unary_position => op!(LogicalAnd(t)),
626                lexi!(t @ Or) if !unary_position => op!(LogicalOr(t)),
627                lexi!(t @ Comma) if !unary_position => {
628                    // this will be ignored if the comma is trailing
629                    let potential_last_token = lexer.next().transpose().ok().flatten();
630                    if !lexer
631                        .peek()
632                        .copied()
633                        .transpose()
634                        .ok()
635                        .flatten()
636                        .is_none_or(|t| EXPRESSION_TERMINATORS.contains(&t.lexigram))
637                    {
638                        op!(Join(t));
639                        last_token = potential_last_token;
640                    }
641                    continue;
642                }
643                lexi!(  @ If) => contents.push(If::from(&mut *lexer).into()),
644                lexi!(  @ Match) => contents.push(Match::new(&mut *lexer).into()),
645                lexi!(  @ Enum) => contents.push(Enum::from(&mut *lexer).into()),
646                _ => {
647                    if unary_position {
648                        if !contents.is_empty() || !stack.is_empty() {
649                            diagnostics.errors.push(Error::IncompleteExpression);
650                        }
651                    } else {
652                        while let Some(op) = stack.pop() {
653                            contents.push(op.into());
654                        }
655                    }
656                    if contents.is_empty() && diagnostics.errors.is_empty() {
657                        return None;
658                    }
659                    if let Some(length) = list_length {
660                        contents.push(Node::List { length });
661                    }
662                    return Some(Expression::build(
663                        first_token,
664                        last_token,
665                        diagnostics,
666                        contents,
667                    ));
668                }
669            }
670            // This is sometimes skipped with a continue!
671            last_token = lexer.next().transpose().unwrap_or(None);
672        }
673    }
674}
675
676#[derive(Debug, Eq, PartialEq)]
677pub struct Annotation<'source> {
678    pub at_sign: Token<'source>,
679    pub name: Option<Token<'source>>,
680    pub open_square: Option<Token<'source>>,
681    pub tokens: Box<[Token<'source>]>,
682    pub close_square: Option<Token<'source>>,
683    pub diagnostics: Diagnostics<'source>,
684}
685
686impl<'source> Annotation<'source> {
687    fn new(at_sign: Token<'source>, lexer: &mut Peekable<Lexer<'source>>) -> Self {
688        let mut diagnostics = Diagnostics::default();
689        let name = diagnostics.next_if(lexer, &[Lexigram::Ident]);
690        let open_square = diagnostics.next_if(lexer, &[Lexigram::OpenSquare]);
691        let mut tokens = Vec::new();
692        let mut square_level = 0;
693        loop {
694            let token = match diagnostics.wrap(lexer.peek().copied()) {
695                Some(
696                    token @ Token {
697                        lexigram: Lexigram::OpenSquare,
698                        ..
699                    },
700                ) => {
701                    square_level += 1;
702                    token
703                }
704                Some(
705                    token @ Token {
706                        lexigram: Lexigram::CloseSquare,
707                        ..
708                    },
709                ) => {
710                    if square_level > 0 {
711                        square_level -= 1;
712                        token
713                    } else {
714                        break;
715                    }
716                }
717                Some(token) => token,
718                None => break,
719            };
720            lexer.next();
721            tokens.push(token);
722        }
723        let close_square = diagnostics.next_if(lexer, &[Lexigram::CloseSquare]);
724        Self {
725            at_sign,
726            name,
727            open_square,
728            tokens: tokens.into_boxed_slice(),
729            close_square,
730            diagnostics,
731        }
732    }
733}
734
735#[derive(Debug, Eq, PartialEq)]
736pub struct If<'source> {
737    pub if_token: Token<'source>,
738    pub condition: Option<Box<Expression<'source>>>,
739    pub then_token: Option<Token<'source>>,
740    pub first: Box<Block<'source>>,
741    pub else_token: Option<Token<'source>>,
742    pub else_kind: Option<Token<'source>>,
743    pub second: Box<Block<'source>>,
744    pub end_token: Option<Token<'source>>,
745    pub diagnostics: Diagnostics<'source>,
746}
747
748impl<'source> From<If<'source>> for Node<'source> {
749    fn from(if_block: If<'source>) -> Self {
750        Self::If(Box::new(if_block))
751    }
752}
753
754impl<'source> From<&mut Peekable<Lexer<'source>>> for If<'source> {
755    fn from(lexer: &mut Peekable<Lexer<'source>>) -> Self {
756        let if_token = lexer
757            .next()
758            .transpose()
759            .ok()
760            .flatten()
761            .expect("caller must have peeked a token");
762        let mut diagnostics = Diagnostics::default();
763        let condition = diagnostics.expect_expression(lexer);
764        let then_token = diagnostics.next_if(lexer, &[Lexigram::Then]);
765        let first = Block::child(&mut *lexer);
766        let (second, else_token, else_kind) = if let else_token @ Some(Token {
767            lexigram: Lexigram::Else,
768            ..
769        }) = diagnostics.wrap(lexer.peek().copied())
770        {
771            lexer.next();
772            let (second, else_kind) = match diagnostics.wrap(lexer.peek().copied()) {
773                else_kind @ Some(Token {
774                    lexigram: Lexigram::Then,
775                    ..
776                }) => {
777                    lexer.next();
778                    (Block::child(&mut *lexer), else_kind)
779                }
780                else_kind @ Some(Token {
781                    lexigram: Lexigram::If,
782                    ..
783                }) => (
784                    Block::build(
785                        Expression::build(
786                            None,
787                            None,
788                            Diagnostics::default(),
789                            [Self::from(&mut *lexer).into()],
790                        )
791                        .into(),
792                        Diagnostics::default(),
793                        [],
794                    ),
795                    else_kind,
796                ),
797                _ => {
798                    diagnostics.expect(lexer.peek().copied(), &[Lexigram::Then, Lexigram::If]);
799                    (Box::default(), None)
800                }
801            };
802            (second, else_token, else_kind)
803        } else {
804            (Box::default(), None, None)
805        };
806        let end_token = diagnostics.expect(lexer.peek().copied(), &[Lexigram::End]);
807        Self {
808            if_token,
809            condition,
810            then_token,
811            first,
812            else_token,
813            else_kind,
814            second,
815            end_token,
816            diagnostics,
817        }
818    }
819}
820
821#[derive(Debug, Eq, PartialEq)]
822pub struct MatchCase<'source> {
823    pub let_token: Option<Token<'source>>,
824    pub binding: Option<Binding<'source>>,
825    pub equals_token: Option<Token<'source>>,
826    pub case: Option<Box<Expression<'source>>>,
827    pub arrow_token: Option<Token<'source>>,
828    pub expression: Option<Box<Expression<'source>>>,
829    pub semicolon_token: Option<Token<'source>>,
830}
831
832#[derive(Debug, Eq, PartialEq)]
833#[make_dst_factory(pub)]
834pub struct Match<'source> {
835    pub match_token: Token<'source>,
836    pub expression: Option<Box<Expression<'source>>>,
837    pub then_token: Option<Token<'source>>,
838    pub end_token: Option<Token<'source>>,
839    pub diagnostics: Diagnostics<'source>,
840    pub cases: [MatchCase<'source>],
841}
842
843impl<'source> From<Box<Match<'source>>> for Node<'source> {
844    fn from(struct_block: Box<Match<'source>>) -> Self {
845        Self::Match(struct_block)
846    }
847}
848
849impl<'source> Match<'source> {
850    /// # Panics
851    ///
852    /// Panics if the lexer returns `None`.
853    ///
854    /// This function should only be called after successfully peeking a [`Lexigram::Match`].
855    pub fn new(lexer: &mut Peekable<Lexer<'source>>) -> Box<Self> {
856        let match_token = lexer
857            .next()
858            .transpose()
859            .ok()
860            .flatten()
861            .expect("caller must have peeked a token");
862        let mut diagnostics = Diagnostics::default();
863
864        let expression = diagnostics.expect_expression(lexer);
865        let then_token = diagnostics.next_if(lexer, &[Lexigram::Then]);
866        let mut cases = Vec::new();
867
868        // ew
869        loop {
870            let (let_token, binding, equals_token, case) = if let let_token @ Some(Token {
871                lexigram: Lexigram::Let,
872                ..
873            }) =
874                diagnostics.wrap(lexer.peek().copied())
875            {
876                lexer.next();
877                let binding = Binding::new(lexer)
878                    .map_err(|e| diagnostics.errors.push(e))
879                    .ok();
880                let (equal_token, case) = if let equal_token @ Some(Token {
881                    lexigram: Lexigram::SingleEqual,
882                    ..
883                }) = diagnostics.wrap(lexer.peek().copied())
884                {
885                    lexer.next();
886                    let case = diagnostics.expect_expression(lexer);
887                    (equal_token, case)
888                } else {
889                    (None, None)
890                };
891                (let_token, binding, equal_token, case)
892            } else {
893                let case = diagnostics.expect_expression(lexer);
894                (None, None, None, case)
895            };
896            let arrow_token = diagnostics.next_if(lexer, &[Lexigram::DoubleArrow]);
897            let expression = diagnostics.expect_expression(lexer);
898            let semicolon_token = diagnostics.next_if(lexer, &[Lexigram::Semicolon]);
899            cases.push(MatchCase {
900                let_token,
901                binding,
902                equals_token,
903                case,
904                arrow_token,
905                expression,
906                semicolon_token,
907            });
908            if semicolon_token.is_none()
909                || diagnostics
910                    .wrap(lexer.peek().copied())
911                    .is_some_and(|t| t.lexigram == Lexigram::End)
912            {
913                break;
914            }
915        }
916        let end_token = diagnostics.expect(lexer.peek().copied(), &[Lexigram::End]);
917        Match::build(
918            match_token,
919            expression,
920            then_token,
921            end_token,
922            diagnostics,
923            cases,
924        )
925    }
926}
927
928#[derive(Debug, Eq, PartialEq)]
929pub struct Enum<'source> {
930    pub enum_token: Token<'source>,
931    pub variants: Option<Box<Expression<'source>>>,
932    pub end_token: Option<Token<'source>>,
933    pub diagnostics: Diagnostics<'source>,
934}
935
936impl<'source> From<Enum<'source>> for Node<'source> {
937    fn from(struct_block: Enum<'source>) -> Self {
938        Self::Enum(Box::new(struct_block))
939    }
940}
941
942impl<'source> From<&mut Peekable<Lexer<'source>>> for Enum<'source> {
943    fn from(lexer: &mut Peekable<Lexer<'source>>) -> Self {
944        let enum_token = lexer
945            .next()
946            .transpose()
947            .ok()
948            .flatten()
949            .expect("caller must have peeked a token");
950        let mut diagnostics = Diagnostics::default();
951        let variants = diagnostics.expect_expression(lexer);
952        let end_token = diagnostics.expect(lexer.peek().copied(), &[Lexigram::End]);
953        Self {
954            enum_token,
955            variants,
956            end_token,
957            diagnostics,
958        }
959    }
960}
961
962#[derive(Debug, Eq, PartialEq)]
963pub enum Statement<'source> {
964    Sequence(Sequence<'source>),
965    Let(Let<'source>),
966    WhereIs(WhereIs<'source>),
967    Set(Set<'source>),
968}
969
970#[derive(Debug, Eq, PartialEq)]
971pub struct Let<'source> {
972    pub let_token: Token<'source>,
973    pub binding: Option<Binding<'source>>,
974    pub equals_token: Option<Token<'source>>,
975    pub expression: Option<Box<Expression<'source>>>,
976    pub semicolon_token: Option<Token<'source>>,
977    pub diagnostics: Diagnostics<'source>,
978}
979
980impl<'source> Let<'source> {
981    pub fn new(let_token: Token<'source>, lexer: &mut Peekable<Lexer<'source>>) -> Self {
982        let mut diagnostics = Diagnostics::default();
983        let binding = Binding::new(lexer)
984            .map_err(|e| diagnostics.errors.push(e))
985            .ok();
986        let equals_token = diagnostics.next_if(lexer, &[Lexigram::SingleEqual]);
987        let expression = diagnostics.expect_expression(lexer);
988        let semicolon_token = diagnostics.next_if(lexer, &[Lexigram::Semicolon]);
989
990        Let {
991            let_token,
992            binding,
993            equals_token,
994            expression,
995            semicolon_token,
996            diagnostics,
997        }
998    }
999}
1000
1001#[derive(Debug, Eq, PartialEq)]
1002pub struct WhereIs<'source> {
1003    pub where_token: Token<'source>,
1004    pub expression: Option<Box<Expression<'source>>>,
1005    pub is_token: Option<Token<'source>>,
1006    pub binding: Option<Binding<'source>>,
1007    pub semicolon_token: Option<Token<'source>>,
1008    pub diagnostics: Diagnostics<'source>,
1009}
1010
1011impl<'source> WhereIs<'source> {
1012    pub fn new(where_token: Token<'source>, lexer: &mut Peekable<Lexer<'source>>) -> Self {
1013        let mut diagnostics = Diagnostics::default();
1014        let expression = diagnostics.expect_expression(lexer);
1015        let is_token = diagnostics.next_if(lexer, &[Lexigram::Is]);
1016        let binding = Binding::new(lexer)
1017            .map_err(|e| diagnostics.errors.push(e))
1018            .ok();
1019        let semicolon_token = diagnostics.next_if(lexer, &[Lexigram::Semicolon]);
1020
1021        WhereIs {
1022            where_token,
1023            expression,
1024            is_token,
1025            binding,
1026            semicolon_token,
1027            diagnostics,
1028        }
1029    }
1030}
1031
1032#[derive(Debug, Eq, PartialEq)]
1033pub struct Sequence<'source> {
1034    pub expression: Option<Box<Expression<'source>>>,
1035    pub semicolon_token: Token<'source>,
1036}
1037
1038impl<'source> Sequence<'source> {
1039    /// # Errors
1040    ///
1041    /// Returns a lone [`Expression`] if no semicolon token was encountered.
1042    pub fn try_sequence(
1043        lexer: &mut Peekable<Lexer<'source>>,
1044    ) -> Result<Self, Option<Box<Expression<'source>>>> {
1045        let expression = Expression::new(&mut *lexer);
1046        if let Some(Ok(
1047            semicolon_token @ Token {
1048                lexigram: Lexigram::Semicolon,
1049                ..
1050            },
1051        )) = lexer.peek().copied()
1052        {
1053            lexer.next();
1054            Ok(Sequence {
1055                expression,
1056                semicolon_token,
1057            })
1058        } else {
1059            Err(expression)
1060        }
1061    }
1062}
1063
1064#[derive(Debug, Eq, PartialEq)]
1065pub struct Set<'source> {
1066    pub set_token: Token<'source>,
1067    pub target: Option<Box<Expression<'source>>>,
1068    pub equals_token: Option<Token<'source>>,
1069    pub expression: Option<Box<Expression<'source>>>,
1070    pub semicolon_token: Option<Token<'source>>,
1071    pub diagnostics: Diagnostics<'source>,
1072}
1073
1074impl<'source> Set<'source> {
1075    /// # Panics
1076    ///
1077    /// Panics if the lexer returns `None`.
1078    ///
1079    /// This function should only be called after successfully peeking a [`Lexigram::Set`].
1080    pub fn new(lexer: &mut Peekable<Lexer<'source>>) -> Self {
1081        let mut diagnostics = Diagnostics::default();
1082        let set_token = lexer
1083            .next()
1084            .transpose()
1085            .ok()
1086            .flatten()
1087            .expect("caller must have peeked a token");
1088        let target = diagnostics.expect_expression(lexer);
1089        let equals_token = diagnostics.next_if(lexer, &[Lexigram::SingleEqual]);
1090        let expression = diagnostics.expect_expression(lexer);
1091        let semicolon_token = diagnostics.next_if(lexer, &[Lexigram::Semicolon]);
1092
1093        Set {
1094            set_token,
1095            target,
1096            equals_token,
1097            expression,
1098            semicolon_token,
1099            diagnostics,
1100        }
1101    }
1102}
1103
1104#[derive(Debug, Eq, PartialEq)]
1105pub struct Use<'source> {
1106    pub use_token: Token<'source>,
1107    pub expression: Option<Box<Expression<'source>>>,
1108    pub semicolon_token: Option<Token<'source>>,
1109    pub body: Box<Block<'source>>,
1110    pub diagnostics: Diagnostics<'source>,
1111}
1112
1113impl<'source> Use<'source> {
1114    /// # Panics
1115    ///
1116    /// Panics if the lexer returns `None`.
1117    ///
1118    /// This function should only be called after successfully peeking a [`Lexigram::Use`].
1119    pub fn new(lexer: &mut Peekable<Lexer<'source>>) -> Self {
1120        let mut diagnostics = Diagnostics::default();
1121        let use_token = lexer
1122            .next()
1123            .transpose()
1124            .ok()
1125            .flatten()
1126            .expect("caller must have peeked a token");
1127        let expression = diagnostics.expect_expression(lexer);
1128        let semicolon_token = diagnostics.next_if(lexer, &[Lexigram::Semicolon]);
1129        let body = Block::child(lexer);
1130
1131        Self {
1132            use_token,
1133            expression,
1134            semicolon_token,
1135            body,
1136            diagnostics,
1137        }
1138    }
1139}
1140
1141#[derive(Debug, Eq, PartialEq)]
1142pub struct NumericBinding<'source> {
1143    pub binding: Binding<'source>,
1144    pub comma_token: Option<Token<'source>>,
1145}
1146
1147#[derive(Debug, Eq, PartialEq)]
1148pub struct NamedBinding<'source> {
1149    pub field: Token<'source>,
1150    pub action: Option<NamedBindingAction<'source>>,
1151    pub comma_token: Option<Token<'source>>,
1152}
1153
1154#[derive(Debug, Eq, PartialEq)]
1155pub enum NamedBindingAction<'source> {
1156    Optional(Token<'source>),
1157    Binding(NamedSubBinding<'source>),
1158}
1159
1160#[derive(Debug, Eq, PartialEq)]
1161pub struct NamedSubBinding<'source> {
1162    pub colon_token: Token<'source>,
1163    pub binding: Binding<'source>,
1164}
1165
1166#[derive(Debug, Eq, PartialEq)]
1167pub enum BindingMethod<'source> {
1168    Single(Token<'source>),
1169    Numeric {
1170        open_paren: Token<'source>,
1171        bindings: Box<[NumericBinding<'source>]>,
1172        close_paren: Option<Token<'source>>,
1173    },
1174    Named {
1175        open_brace: Token<'source>,
1176        bindings: Box<[NamedBinding<'source>]>,
1177        close_brace: Option<Token<'source>>,
1178    },
1179}
1180
1181#[derive(Debug, Eq, PartialEq)]
1182pub struct Binding<'source> {
1183    pub method: BindingMethod<'source>,
1184    pub diagnostics: Diagnostics<'source>,
1185}
1186
1187impl<'source> Binding<'source> {
1188    /// # Errors
1189    ///
1190    /// Returns an error if no valid binding token was encountered.
1191    pub fn new(lexer: &mut Peekable<Lexer<'source>>) -> Result<Self, Error<'source>> {
1192        match lexer.peek().copied().transpose().map_err(Error::Lexer)? {
1193            Some(
1194                t @ Token {
1195                    lexigram: Lexigram::Ident | Lexigram::Discard,
1196                    ..
1197                },
1198            ) => {
1199                lexer.next();
1200                Ok(Binding {
1201                    method: BindingMethod::Single(t),
1202                    diagnostics: Diagnostics::default(),
1203                })
1204            }
1205            Some(
1206                open_paren @ Token {
1207                    lexigram: Lexigram::OpenParen,
1208                    ..
1209                },
1210            ) => {
1211                let mut diagnostics = Diagnostics::default();
1212                let mut bindings = Vec::new();
1213                lexer.next();
1214                loop {
1215                    let t = diagnostics.wrap(lexer.peek().copied());
1216                    if let Some(Token {
1217                        lexigram: Lexigram::CloseParen,
1218                        ..
1219                    }) = t
1220                    {
1221                        break;
1222                    }
1223                    if let Ok(binding) = Binding::new(lexer) {
1224                        let comma_token = diagnostics
1225                            .wrap(lexer.peek().copied())
1226                            .filter(|t| t.lexigram == Lexigram::Comma);
1227                        bindings.push(NumericBinding {
1228                            binding,
1229                            comma_token,
1230                        });
1231                        if comma_token.is_some() {
1232                            lexer.next();
1233                        } else {
1234                            break;
1235                        }
1236                    } else {
1237                        diagnostics.errors.push(Error::MissingToken {
1238                            expected: &[
1239                                Lexigram::Ident,
1240                                Lexigram::Discard,
1241                                Lexigram::OpenParen,
1242                                Lexigram::OpenBrace,
1243                                Lexigram::CloseParen,
1244                            ],
1245                            actual: t,
1246                        });
1247                        break;
1248                    }
1249                }
1250                let close_paren = diagnostics.next_if(lexer, &[Lexigram::CloseParen]);
1251                Ok(Binding {
1252                    method: BindingMethod::Numeric {
1253                        open_paren,
1254                        bindings: bindings.into_boxed_slice(),
1255                        close_paren,
1256                    },
1257                    diagnostics,
1258                })
1259            }
1260            Some(
1261                open_brace @ Token {
1262                    lexigram: Lexigram::OpenBrace,
1263                    ..
1264                },
1265            ) => {
1266                let mut diagnostics = Diagnostics::default();
1267                let mut bindings = Vec::new();
1268                lexer.next();
1269                loop {
1270                    match diagnostics.wrap(lexer.peek().copied()) {
1271                        Some(Token {
1272                            lexigram: Lexigram::CloseBrace,
1273                            ..
1274                        }) => break,
1275                        Some(
1276                            field @ Token {
1277                                lexigram: Lexigram::Ident,
1278                                ..
1279                            },
1280                        ) => {
1281                            lexer.next();
1282                            match diagnostics.wrap(lexer.peek().copied()) {
1283                                Some(
1284                                    question_token @ Token {
1285                                        lexigram: Lexigram::Question,
1286                                        ..
1287                                    },
1288                                ) => {
1289                                    lexer.next();
1290                                    let comma_token = diagnostics
1291                                        .wrap(lexer.peek().copied())
1292                                        .filter(|t| t.lexigram == Lexigram::Comma);
1293                                    bindings.push(NamedBinding {
1294                                        field,
1295                                        action: Some(NamedBindingAction::Optional(question_token)),
1296                                        comma_token,
1297                                    });
1298                                    if comma_token.is_some() {
1299                                        lexer.next();
1300                                    } else {
1301                                        break;
1302                                    }
1303                                }
1304                                Some(
1305                                    colon_token @ Token {
1306                                        lexigram: Lexigram::Colon,
1307                                        ..
1308                                    },
1309                                ) => {
1310                                    lexer.next();
1311                                    match Binding::new(lexer) {
1312                                        Ok(binding) => {
1313                                            let comma_token = diagnostics
1314                                                .wrap(lexer.peek().copied())
1315                                                .filter(|t| t.lexigram == Lexigram::Comma);
1316                                            bindings.push(NamedBinding {
1317                                                field,
1318                                                action: Some(NamedBindingAction::Binding(
1319                                                    NamedSubBinding {
1320                                                        colon_token,
1321                                                        binding,
1322                                                    },
1323                                                )),
1324                                                comma_token,
1325                                            });
1326                                            if comma_token.is_some() {
1327                                                lexer.next();
1328                                            } else {
1329                                                break;
1330                                            }
1331                                        }
1332                                        Err(e) => {
1333                                            diagnostics.errors.push(e);
1334                                            break;
1335                                        }
1336                                    }
1337                                }
1338                                comma_token @ Some(Token {
1339                                    lexigram: Lexigram::Comma,
1340                                    ..
1341                                }) => {
1342                                    lexer.next();
1343                                    bindings.push(NamedBinding {
1344                                        field,
1345                                        action: None,
1346                                        comma_token,
1347                                    });
1348                                }
1349                                _ => {
1350                                    bindings.push(NamedBinding {
1351                                        field,
1352                                        action: None,
1353                                        comma_token: None,
1354                                    });
1355                                    break;
1356                                }
1357                            }
1358                        }
1359                        actual => {
1360                            diagnostics.errors.push(Error::MissingToken {
1361                                expected: &[Lexigram::Ident, Lexigram::CloseBrace],
1362                                actual,
1363                            });
1364                            break;
1365                        }
1366                    }
1367                }
1368                let close_brace = diagnostics.next_if(lexer, &[Lexigram::CloseBrace]);
1369                Ok(Binding {
1370                    method: BindingMethod::Named {
1371                        open_brace,
1372                        bindings: bindings.into_boxed_slice(),
1373                        close_brace,
1374                    },
1375                    diagnostics,
1376                })
1377            }
1378            actual => Err(Error::MissingToken {
1379                expected: &[
1380                    Lexigram::Ident,
1381                    Lexigram::Discard,
1382                    Lexigram::OpenParen,
1383                    Lexigram::OpenBrace,
1384                ],
1385                actual,
1386            }),
1387        }
1388    }
1389}
1390
1391#[derive(Debug, Eq, PartialEq)]
1392pub struct Function<'source> {
1393    pub with_token: Token<'source>,
1394    pub argument: Option<Binding<'source>>,
1395    pub semicolon_token: Option<Token<'source>>,
1396    pub body: Box<Block<'source>>,
1397    pub diagnostics: Diagnostics<'source>,
1398}
1399
1400#[derive(Debug, Eq, PartialEq)]
1401#[allow(
1402    clippy::large_enum_variant,
1403    reason = "this is already inside of a (very large) boxed block"
1404)]
1405pub enum BlockResult<'source> {
1406    Expression(Option<Box<Expression<'source>>>),
1407    Function(Function<'source>),
1408    Use(Use<'source>),
1409}
1410
1411impl BlockResult<'_> {
1412    #[must_use]
1413    pub fn is_empty(&self) -> bool {
1414        match self {
1415            BlockResult::Expression(expression) => expression.is_none(),
1416            _ => false,
1417        }
1418    }
1419}
1420
1421impl Default for BlockResult<'_> {
1422    fn default() -> Self {
1423        Self::Expression(None)
1424    }
1425}
1426
1427impl<'source> From<Box<Expression<'source>>> for BlockResult<'source> {
1428    fn from(expression: Box<Expression<'source>>) -> Self {
1429        Self::Expression(Some(expression))
1430    }
1431}
1432
1433impl<'source> From<Function<'source>> for BlockResult<'source> {
1434    fn from(function: Function<'source>) -> Self {
1435        Self::Function(function)
1436    }
1437}
1438
1439#[derive(Debug, Eq, PartialEq)]
1440#[make_dst_factory(pub)]
1441pub struct Block<'source> {
1442    pub result: BlockResult<'source>,
1443    pub diagnostics: Diagnostics<'source>,
1444    pub statements: [Statement<'source>],
1445}
1446
1447impl Default for Box<Block<'_>> {
1448    fn default() -> Self {
1449        Block::build(BlockResult::Expression(None), Diagnostics::default(), [])
1450    }
1451}
1452
1453impl<'source> Block<'source> {
1454    pub fn new(lexer: &mut Peekable<Lexer<'source>>) -> Box<Self> {
1455        Self::parse(lexer, true)
1456    }
1457
1458    fn child(lexer: &mut Peekable<Lexer<'source>>) -> Box<Self> {
1459        Self::parse(lexer, false)
1460    }
1461
1462    fn parse(lexer: &mut Peekable<Lexer<'source>>, root: bool) -> Box<Self> {
1463        Self::parse_after(Vec::new(), lexer, root)
1464    }
1465
1466    fn parse_after(
1467        mut statements: Vec<Statement<'source>>,
1468        lexer: &mut Peekable<Lexer<'source>>,
1469        root: bool,
1470    ) -> Box<Self> {
1471        let mut diagnostics = Diagnostics::default();
1472        let result = loop {
1473            let statement = match diagnostics.wrap(lexer.peek().copied()) {
1474                Some(
1475                    let_token @ Token {
1476                        lexigram: Lexigram::Let,
1477                        ..
1478                    },
1479                ) => {
1480                    lexer.next();
1481                    Statement::Let(Let::new(let_token, lexer))
1482                }
1483                Some(
1484                    where_token @ Token {
1485                        lexigram: Lexigram::Where,
1486                        ..
1487                    },
1488                ) => {
1489                    lexer.next();
1490                    Statement::WhereIs(WhereIs::new(where_token, lexer))
1491                }
1492                Some(Token {
1493                    lexigram: Lexigram::Set,
1494                    ..
1495                }) => Statement::Set(Set::new(lexer)),
1496                Some(Token {
1497                    lexigram: Lexigram::Use,
1498                    ..
1499                }) => break BlockResult::Use(Use::new(lexer)),
1500                Some(
1501                    with_token @ Token {
1502                        lexigram: Lexigram::With,
1503                        ..
1504                    },
1505                ) => {
1506                    lexer.next();
1507                    let mut st_diagnostics = Diagnostics::default();
1508                    let argument = Binding::new(lexer)
1509                        .map_err(|e| st_diagnostics.errors.push(e))
1510                        .ok();
1511                    let semicolon_token = diagnostics.next_if(lexer, &[Lexigram::Semicolon]);
1512                    let body = Block::parse(&mut *lexer, root);
1513
1514                    break Function {
1515                        with_token,
1516                        argument,
1517                        semicolon_token,
1518                        body,
1519                        diagnostics: st_diagnostics,
1520                    }
1521                    .into();
1522                }
1523                _ => match Sequence::try_sequence(&mut *lexer) {
1524                    Ok(sequence) => Statement::Sequence(sequence),
1525                    Err(expression) => {
1526                        break BlockResult::Expression(expression);
1527                    }
1528                },
1529            };
1530            statements.push(statement);
1531        };
1532        if root && let Some(t) = lexer.peek().copied().transpose().ok().flatten() {
1533            diagnostics
1534                .errors
1535                .push(Error::ExpectedStatementOrExpression(t));
1536        }
1537        Self::build(result, diagnostics, statements)
1538    }
1539}