spade_parser/
lib.rs

1pub mod error;
2mod expression;
3pub mod item_type;
4mod items;
5pub mod lexer;
6mod statements;
7
8use std::marker::PhantomData;
9
10use colored::*;
11use itertools::Itertools;
12use local_impl::local_impl;
13use logos::Lexer;
14use spade_diagnostics::diag_list::{DiagList, ResultExt};
15use statements::{AssertParser, BindingParser, DeclParser, LabelParser, RegisterParser, SetParser};
16use tracing::{debug, event, Level};
17
18use spade_ast::{
19    ArgumentList, ArgumentPattern, Attribute, AttributeList, BitLiteral, Block, CallKind,
20    EnumVariant, Expression, Inequality, IntLiteral, Item, ModuleBody, NamedArgument,
21    NamedTurbofish, ParameterList, Pattern, PipelineStageReference, Statement, TraitSpec,
22    TurbofishInner, TypeExpression, TypeParam, TypeSpec, Unit, UnitHead, UnitKind, WhereClause,
23};
24use spade_common::location_info::{lspan, AsLabel, FullSpan, HasCodespan, Loc, WithLocation};
25use spade_common::name::{Identifier, Path, PathSegment, Visibility};
26use spade_common::num_ext::{InfallibleToBigInt, InfallibleToBigUint};
27use spade_diagnostics::{diag_bail, Diagnostic};
28use spade_macros::trace_parser;
29
30use crate::error::{
31    unexpected_token_message, CSErrorTransformations, CommaSeparatedResult, ExpectedArgumentList,
32    Result, SuggestBraceEnumVariant, TokenSeparatedError, UnexpectedToken,
33};
34use crate::item_type::UnitKindLocal;
35use crate::lexer::{LiteralKind, TokenKind};
36
37pub use logos;
38
39/// A token with location info
40#[derive(Clone, Debug, PartialEq)]
41pub struct Token {
42    pub kind: TokenKind,
43    pub span: logos::Span,
44    pub file_id: usize,
45}
46
47impl Token {
48    pub fn new(kind: TokenKind, lexer: &Lexer<TokenKind>, file_id: usize) -> Self {
49        Self {
50            kind,
51            span: lexer.span(),
52            file_id,
53        }
54    }
55
56    pub fn loc(&self) -> Loc<()> {
57        Loc::new((), self.span.codespan(), self.file_id)
58    }
59}
60
61impl HasCodespan for Token {
62    fn codespan(&self) -> spade_codespan::Span {
63        self.span().codespan()
64    }
65}
66
67impl AsLabel for Token {
68    fn file_id(&self) -> usize {
69        self.file_id
70    }
71
72    fn span(&self) -> std::ops::Range<usize> {
73        self.span.clone()
74    }
75}
76
77impl From<Token> for FullSpan {
78    fn from(token: Token) -> FullSpan {
79        (token.codespan(), token.file_id)
80    }
81}
82
83#[derive(Debug, Clone)]
84pub enum Comment {
85    Line(Token),
86    Block(Token, Token),
87}
88
89// Clone for when you want to call a parse function but maybe discard the new parser state
90// depending on some later condition.
91#[derive(Clone)]
92pub struct Parser<'a> {
93    lex: Lexer<'a, TokenKind>,
94    peeked: Option<Token>,
95    // The last token that was eaten. Used in eof diagnostics
96    last_token: Option<Token>,
97    pub parse_stack: Vec<ParseStackEntry>,
98    file_id: usize,
99    unit_context: Option<Loc<UnitKind>>,
100    pub diags: DiagList,
101    recovering_tokens: Vec<fn(&TokenKind) -> bool>,
102    comments: Vec<Comment>,
103}
104
105impl<'a> Parser<'a> {
106    pub fn new(lex: Lexer<'a, TokenKind>, file_id: usize) -> Self {
107        Self {
108            lex,
109            peeked: None,
110            last_token: None,
111            parse_stack: vec![],
112            file_id,
113            unit_context: None,
114            diags: DiagList::new(),
115            recovering_tokens: vec![|tok| tok == &TokenKind::Eof],
116            comments: vec![],
117        }
118    }
119
120    pub fn comments(&self) -> &[Comment] {
121        &self.comments
122    }
123}
124
125/// Peek the next token. If it matches the specified token, get that token
126/// otherwise return Ok(none)
127#[macro_export]
128macro_rules! peek_for {
129    ($self:expr, $token:expr) => {
130        if let Some(t) = $self.peek_and_eat($token)? {
131            t
132        } else {
133            return Ok(None);
134        }
135    };
136}
137
138// Actual parsing functions
139impl<'a> Parser<'a> {
140    #[trace_parser]
141    #[tracing::instrument(level = "trace", skip(self))]
142    pub fn identifier(&mut self) -> Result<Loc<Identifier>> {
143        let token = self.eat_cond(TokenKind::is_identifier, "Identifier")?;
144
145        if let TokenKind::Identifier(name) = token.kind {
146            Ok(name.at(self.file_id, &token.span))
147        } else {
148            unreachable!("eat_cond should have checked this");
149        }
150    }
151
152    #[trace_parser]
153    pub fn path(&mut self) -> Result<Loc<Path>> {
154        let mut result = vec![];
155        loop {
156            result.push(PathSegment::Named(self.identifier()?));
157
158            if self.peek_and_eat(&TokenKind::PathSeparator)?.is_none() {
159                break;
160            }
161        }
162        // NOTE: (safe unwrap) The vec will have at least one element because the first thing
163        // in the loop must push an identifier.
164        let start = result.first().unwrap().loc();
165        let end = result.last().unwrap().loc();
166        Ok(Path(result).between_locs(&start, &end))
167    }
168
169    #[trace_parser]
170    pub fn path_tree_with_as_alias(&mut self) -> Result<Vec<(Loc<Path>, Option<Loc<Identifier>>)>> {
171        let mut prefix = Path(vec![]);
172        let mut alias = None;
173
174        loop {
175            if self.peek_cond(TokenKind::is_identifier, "Identifier")? {
176                let ident = self.identifier()?;
177                prefix = prefix.push_ident(ident);
178            } else if self.peek_and_eat(&TokenKind::OpenBrace)?.is_some() {
179                let result = self
180                    .comma_separated(Self::path_tree_with_as_alias, &TokenKind::CloseBrace)
181                    .no_context()?
182                    .into_iter()
183                    .flatten()
184                    .map(|(p, a)| {
185                        let loc = p.loc();
186                        let path = prefix.join(p.inner);
187                        (path.at_loc(&loc), a)
188                    })
189                    .collect::<Vec<_>>();
190                self.eat(&TokenKind::CloseBrace)?;
191                return Ok(result);
192            } else {
193                let next = self.peek()?;
194                return Err(UnexpectedToken {
195                    got: next,
196                    expected: vec!["identifier", "{", "::"],
197                }
198                .into());
199            }
200
201            if self.peek_and_eat(&TokenKind::As)?.is_some() {
202                alias = Some(self.identifier()?);
203                break;
204            } else if self.peek_and_eat(&TokenKind::PathSeparator)?.is_none() {
205                break;
206            }
207        }
208
209        let start = prefix.0.first().unwrap().loc();
210        let end = prefix.0.last().unwrap().loc();
211        return Ok(vec![(prefix.between_locs(&start, &end), alias)]);
212    }
213
214    pub fn named_turbofish(&mut self) -> Result<Loc<NamedTurbofish>> {
215        // This is a named arg
216        let name = self.identifier()?;
217        if self.peek_and_eat(&TokenKind::Colon)?.is_some() {
218            let value = self.type_expression()?;
219
220            let span = name.span.merge(value.span);
221
222            Ok(NamedTurbofish::Full(name, value).at(self.file_id, &span))
223        } else {
224            Ok(NamedTurbofish::Short(name.clone()).at(self.file_id, &name))
225        }
226    }
227
228    #[trace_parser]
229    pub fn turbofish(&mut self) -> Result<Option<Loc<TurbofishInner>>> {
230        let start = peek_for!(self, &TokenKind::PathSeparator);
231
232        if self.peek_kind(&TokenKind::Lt)? {
233            // safe unwrap, only None for token kind != Lt
234            let params = self.generic_spec_list()?.unwrap();
235
236            Ok(Some(params.map(|p| TurbofishInner::Positional(p))))
237        } else if self.peek_kind(&TokenKind::Dollar)? {
238            self.eat_unconditional()?;
239            let (params, loc) = self.surrounded(
240                &TokenKind::Lt,
241                |s| {
242                    s.comma_separated(Self::named_turbofish, &TokenKind::Gt)
243                        .extra_expected(vec!["identifier", "type spec"])
244                },
245                &TokenKind::Gt,
246            )?;
247
248            Ok(Some(TurbofishInner::Named(params).at_loc(&loc)))
249        } else {
250            let next = self.peek()?;
251            return Err(Diagnostic::error(next, "Expected $ or <")
252                .primary_label("Expected $ or <")
253                .secondary_label(
254                    start,
255                    ":: after an method is used to specify type parameters",
256                ));
257        }
258    }
259
260    #[trace_parser]
261    pub fn path_with_turbofish(
262        &mut self,
263    ) -> Result<Option<(Loc<Path>, Option<Loc<TurbofishInner>>)>> {
264        let mut result = vec![];
265        if !self.peek_cond(TokenKind::is_identifier, "Identifier")? {
266            return Ok(None);
267        }
268
269        loop {
270            result.push(PathSegment::Named(self.identifier()?));
271
272            // NOTE: (safe unwrap) The vec will have at least one element because the first thing
273            // in the loop must push an identifier.
274            let path_start = result.first().unwrap().loc();
275            let path_end = result.last().unwrap().loc();
276
277            if self.peek_and_eat(&TokenKind::PathSeparator)?.is_none() {
278                break Ok(Some((
279                    Path(result).between_locs(&path_start, &path_end),
280                    None,
281                )));
282            } else if self.peek_kind(&TokenKind::Lt)? {
283                // safe unwrap, only None for token kind != Lt
284                let params = self.generic_spec_list()?.unwrap();
285
286                break Ok(Some((
287                    Path(result).between(self.file_id, &path_start, &path_end),
288                    Some(params.map(|p| TurbofishInner::Positional(p))),
289                )));
290            } else if self.peek_kind(&TokenKind::Dollar)? {
291                self.eat_unconditional()?;
292                let (params, loc) = self.surrounded(
293                    &TokenKind::Lt,
294                    |s| {
295                        s.comma_separated(Self::named_turbofish, &TokenKind::Gt)
296                            .extra_expected(vec!["identifier", "type spec"])
297                    },
298                    &TokenKind::Gt,
299                )?;
300
301                break Ok(Some((
302                    Path(result).between(self.file_id, &path_start, &path_end),
303                    Some(TurbofishInner::Named(params).at_loc(&loc)),
304                )));
305            }
306        }
307    }
308
309    #[trace_parser]
310    fn array_label(&mut self) -> Result<Option<Loc<Identifier>>> {
311        if let ref tok @ Token {
312            kind: TokenKind::Label(l),
313            ..
314        } = self.peek()?
315        {
316            self.eat_unconditional()?;
317            Ok(Some(l.at(self.file_id, tok)))
318        } else {
319            Ok(None)
320        }
321    }
322
323    #[trace_parser]
324    fn array_literal(&mut self) -> Result<Option<Loc<Expression>>> {
325        let start = peek_for!(self, &TokenKind::OpenBracket);
326
327        // empty array
328        if let Some(end) = self.peek_and_eat(&TokenKind::CloseBracket)? {
329            return Ok(Some(Expression::ArrayLiteral(vec![]).between(
330                self.file_id,
331                &start,
332                &end,
333            )));
334        }
335
336        // non-empty array => must be an expression
337        let first_label = self.array_label()?;
338        let first = self.expression()?;
339
340        let expr = if self.peek_and_eat(&TokenKind::Semi).unwrap().is_some() {
341            // array shorthand ([<expr>; N])
342            Expression::ArrayShorthandLiteral(Box::new(first), Box::new(self.expression()?))
343        } else {
344            // eat comma, if any
345            let _ = self.peek_and_eat(&TokenKind::Comma)?;
346
347            // now we can continue with the rest of the elements
348            let mut inner = self
349                .comma_separated(
350                    |s| Ok((s.array_label()?, s.expression()?)),
351                    &TokenKind::CloseBracket,
352                )
353                .no_context()?;
354            inner.insert(0, (first_label, first));
355            Expression::ArrayLiteral(inner)
356        };
357
358        let end = self.eat(&TokenKind::CloseBracket)?;
359
360        Ok(Some(expr.between(self.file_id, &start, &end)))
361    }
362
363    fn map_escape_char(c: Loc<char>, string_delimiter: char) -> Result<char> {
364        match c.inner {
365            '0' => Ok('\0'),
366            't' => Ok('\t'),
367            'n' => Ok('\n'),
368            'r' => Ok('\r'),
369            other if other == string_delimiter => Ok(string_delimiter),
370            other => Err(Diagnostic::error(
371                c.loc(),
372                format!("{} is not a valid byte escape character", other),
373            )),
374        }
375    }
376
377    fn ascii_string_literal(&mut self) -> Result<Option<Loc<Expression>>> {
378        let next = self.peek()?;
379        let TokenKind::AsciiStringLiteral(val) = &next.kind else {
380            return Ok(None);
381        };
382
383        self.eat_unconditional()?;
384
385        let mut escape_next = false;
386        let array_elements = val
387            .char_indices()
388            .map(|(i, c)| {
389                // +1 because the token starts with b"
390                let span = (next.span.start + i + 2)..(next.span.start + i + 2 + c.len_utf8());
391                let loc = ().at(self.file_id, &span);
392                if !c.is_ascii() {
393                    return Err(Diagnostic::error(
394                        loc,
395                        "ASCII literals can only contain ASCII value, not unicode",
396                    )
397                    .primary_label("Unicode character in ASCII literal"));
398                }
399
400                let result;
401                (escape_next, result) = match (escape_next, c) {
402                    (false, '\\') => (true, None),
403                    (true, esc) => (false, Some(Self::map_escape_char(esc.at_loc(&loc), '"')?)),
404                    (_, other) => (false, Some(other)),
405                };
406                Ok(result.map(|c| c.at_loc(&loc)))
407            })
408            .collect::<Result<Vec<_>>>()?;
409
410        let elems = array_elements
411            .iter()
412            .filter_map(|maybe_loc_c| {
413                maybe_loc_c.map(|loc_c| {
414                    let mut byte = [0; 1];
415                    loc_c.inner.encode_utf8(&mut byte);
416                    (
417                        None,
418                        Expression::IntLiteral(
419                            IntLiteral::Unsigned {
420                                val: byte[0].to_biguint(),
421                                size: 8u32.to_biguint(),
422                            }
423                            .at_loc(&loc_c),
424                        )
425                        .at_loc(&loc_c),
426                    )
427                })
428            })
429            .collect();
430        Ok(Some(
431            Expression::ArrayLiteral(elems).at(self.file_id, &next),
432        ))
433    }
434
435    #[trace_parser]
436    fn ascii_char_literal(&mut self) -> Result<Option<Loc<IntLiteral>>> {
437        let next = self.peek()?;
438        if let TokenKind::Utf8CharLiteral = &next.kind {
439            return Err(
440                Diagnostic::error(&next.loc(), "Unicode char literals are unsupported.")
441                    .primary_label("Unicode char literal")
442                    .span_suggest_insert_before("Consider making this an ASCII literal", next.loc(), "b")
443                    .help("The `b` prefix is used to denote ASCII literals as opposed to full Unicode"),
444            );
445        }
446        let TokenKind::AsciiCharLiteral(val) = &next.kind else {
447            return Ok(None);
448        };
449        self.eat_unconditional()?;
450
451        if !val.is_ascii() {
452            return Err(Diagnostic::error(
453                next.loc(),
454                "ASCII literals can only be ASCII values, not Unicode",
455            ));
456        }
457
458        let actual_char = if val.len() == 2 && val.starts_with('\\') {
459            Self::map_escape_char(
460                val.chars().skip(1).next().unwrap().at_loc(&next.loc()),
461                '\'',
462            )?
463        } else if val.len() > 1 {
464            return Err(Diagnostic::error(
465                next,
466                "Only a single character is supported in ASCII char literals.",
467            ));
468        } else if val.len() == 1 {
469            val.chars().next().unwrap()
470        } else {
471            return Err(Diagnostic::bug(next.loc(), "Found an empty char literal"));
472        };
473
474        let mut byte = [0; 1];
475        actual_char.encode_utf8(&mut byte);
476        Ok(Some(
477            IntLiteral::Unsigned {
478                val: byte[0].to_biguint(),
479                size: 8u32.to_biguint(),
480            }
481            .at(self.file_id, &next),
482        ))
483    }
484
485    #[trace_parser]
486    fn tuple_literal(&mut self) -> Result<Option<Loc<Expression>>> {
487        let start = peek_for!(self, &TokenKind::OpenParen);
488        if self.peek_kind(&TokenKind::CloseParen)? {
489            return Ok(Some(Expression::TupleLiteral(vec![]).between(
490                self.file_id,
491                &start,
492                &self.eat_unconditional()?,
493            )));
494        }
495        if let Some(_) = self.peek_and_eat(&TokenKind::Comma)? {
496            let closer = self.eat(&TokenKind::CloseParen)?;
497            return Ok(Some(Expression::TupleLiteral(vec![]).between(
498                self.file_id,
499                &start,
500                &closer,
501            )));
502        }
503
504        let first = self.expression()?;
505        let first_sep = self.eat_unconditional()?;
506
507        match &first_sep.kind {
508            TokenKind::CloseParen => {
509                let inner = first.inner.between(self.file_id, &start, &first_sep);
510                Ok(Some(Expression::Parenthesized(Box::new(inner)).between(
511                    self.file_id,
512                    &start,
513                    &first_sep,
514                )))
515            }
516            TokenKind::Comma => {
517                let rest = self
518                    .comma_separated(Self::expression, &TokenKind::CloseParen)
519                    .no_context()?;
520
521                let end = self.eat(&TokenKind::CloseParen)?;
522
523                Ok(Some(
524                    Expression::TupleLiteral(vec![first].into_iter().chain(rest).collect())
525                        .between(self.file_id, &start, &end),
526                ))
527            }
528            _ => Err(UnexpectedToken {
529                got: first_sep,
530                expected: vec!["expression", ",", ")"],
531            }
532            .into()),
533        }
534    }
535
536    #[trace_parser]
537    #[tracing::instrument(skip(self))]
538    fn entity_instance(&mut self) -> Result<Option<Loc<Expression>>> {
539        let start = peek_for!(self, &TokenKind::Instance);
540        let start_loc = ().at(self.file_id, &start);
541
542        // inst is only allowed in entity/pipeline, so check that we are in one of those
543        self.unit_context
544            .allows_inst(().at(self.file_id, &start.span()))?;
545
546        // Check if this is a pipeline or not
547        let pipeline_depth = if self.peek_kind(&TokenKind::OpenParen)? {
548            Some(self.surrounded(
549                &TokenKind::OpenParen,
550                |s| s.type_expression(),
551                &TokenKind::CloseParen,
552            )?)
553        } else {
554            None
555        };
556
557        let peeked = self.peek()?;
558        let (name, turbofish) = self.path_with_turbofish()?.ok_or_else(|| {
559            Diagnostic::from(UnexpectedToken {
560                got: peeked,
561                expected: vec!["identifier", "pipeline depth"],
562            })
563        })?;
564        let next_token = self.peek()?;
565
566        let args = self.argument_list()?.ok_or_else(|| {
567            ExpectedArgumentList {
568                next_token,
569                base_expr: ().between(self.file_id, &start, &name),
570            }
571            .with_suggestions()
572        })?;
573
574        if let Some((depth, end_paren)) = pipeline_depth {
575            Ok(Some(
576                Expression::Call {
577                    kind: CallKind::Pipeline(
578                        ().between(self.file_id, &start_loc, &end_paren),
579                        depth,
580                    ),
581                    callee: name,
582                    args: args.clone(),
583                    turbofish,
584                }
585                .between(self.file_id, &start.span, &args),
586            ))
587        } else {
588            Ok(Some(
589                Expression::Call {
590                    kind: CallKind::Entity(start_loc),
591                    callee: name,
592                    args: args.clone(),
593                    turbofish,
594                }
595                .between(self.file_id, &start.span, &args),
596            ))
597        }
598    }
599
600    // FIXME: Before changing this, merge it with type_level_if
601    #[trace_parser]
602    #[tracing::instrument(skip(self))]
603    pub fn if_expression(&mut self, allow_stages: bool) -> Result<Option<Loc<Expression>>> {
604        let start = peek_for!(self, &TokenKind::If);
605
606        let cond = self.expression()?;
607
608        let on_true = if let Some(block) = self.block(allow_stages)? {
609            block.map(Box::new).map(Expression::Block)
610        } else {
611            let got = self.peek()?;
612            return Err(Diagnostic::error(
613                got.loc(),
614                format!("Unexpected `{}`, expected a block", got.kind.as_str()),
615            )
616            .primary_label("expected a block here"));
617        };
618
619        self.eat(&TokenKind::Else)?;
620        let on_false = if let Some(block) = self.block(allow_stages)? {
621            block.map(Box::new).map(Expression::Block)
622        } else if let Some(expr) = self.if_expression(allow_stages)? {
623            expr
624        } else {
625            let got = self.peek()?;
626            return Err(Diagnostic::error(
627                got.loc(),
628                format!(
629                    "Unexpected `{}`, expected `if` or a block",
630                    got.kind.as_str()
631                ),
632            )
633            .primary_label("expected a block here"));
634        };
635        let end_span = on_false.span;
636
637        Ok(Some(
638            Expression::If(Box::new(cond), Box::new(on_true), Box::new(on_false)).between(
639                self.file_id,
640                &start.span,
641                &end_span,
642            ),
643        ))
644    }
645
646    // FIXME: Before changing this, merge it with if_expression
647    pub fn type_level_if(&mut self) -> Result<Option<Loc<Expression>>> {
648        let start = peek_for!(self, &TokenKind::Gen);
649
650        let Some(inner) = self.if_expression(true)? else {
651            return Err(
652                Diagnostic::error(self.peek()?, "gen must be followed by if")
653                    .primary_label("Expected if")
654                    .secondary_label(start, "Because of this gen"),
655            );
656        };
657        let end_span = inner.loc();
658        let Expression::If(cond, on_true, on_false) = inner.inner else {
659            diag_bail!(inner, "if_expression did not return an if")
660        };
661
662        let on_false = match &on_false.inner {
663            Expression::If(cond, on_true, on_false) => Box::new(
664                Expression::TypeLevelIf(cond.clone(), on_true.clone(), on_false.clone())
665                    .at_loc(&on_false),
666            ),
667            _ => on_false,
668        };
669
670        Ok(Some(
671            Expression::TypeLevelIf(cond, on_true, on_false).between(
672                self.file_id,
673                &start.span,
674                &end_span,
675            ),
676        ))
677    }
678
679    #[trace_parser]
680    pub fn match_expression(&mut self) -> Result<Option<Loc<Expression>>> {
681        let start = peek_for!(self, &TokenKind::Match);
682
683        let expression = self.expression()?;
684
685        let (patterns, body_loc) = self.surrounded(
686            &TokenKind::OpenBrace,
687            |s| {
688                s.comma_separated(
689                    |s| {
690                        let pattern = s.pattern()?;
691                        let if_condition = if s.peek_kind(&TokenKind::If)? {
692                            s.eat_unconditional()?;
693                            Some(s.expression()?)
694                        } else {
695                            None
696                        };
697                        s.eat(&TokenKind::FatArrow)?;
698                        let value = s.expression()?;
699
700                        Ok((pattern, if_condition, value))
701                    },
702                    &TokenKind::CloseBrace,
703                )
704                .no_context()
705            },
706            &TokenKind::CloseBrace,
707        )?;
708        let patterns = patterns.at_loc(&body_loc);
709
710        Ok(Some(
711            Expression::Match(Box::new(expression), patterns).between(
712                self.file_id,
713                &start.span,
714                &body_loc,
715            ),
716        ))
717    }
718
719    #[trace_parser]
720    pub fn unsafe_block(&mut self) -> Result<Option<Loc<Expression>>> {
721        let start = peek_for!(self, &TokenKind::Unsafe);
722
723        let Some(block) = self.block(false)? else {
724            let got = self.peek()?;
725            return Err(Diagnostic::error(
726                got.loc(),
727                format!("Unexpected `{}`, expected a block", got.kind.as_str()),
728            )
729            .primary_label("expected a block here"));
730        };
731
732        let block_loc = block.loc();
733        Ok(Some(Expression::Unsafe(Box::new(block)).between(
734            self.file_id,
735            &start.span,
736            &block_loc,
737        )))
738    }
739
740    #[trace_parser]
741    #[tracing::instrument(skip(self))]
742    pub fn int_literal(&mut self) -> Result<Option<Loc<IntLiteral>>> {
743        let plusminus = match &self.peek()?.kind {
744            TokenKind::Plus | TokenKind::Minus => Some(self.eat_unconditional()?),
745            _ => None,
746        };
747        if self.peek_cond(TokenKind::is_integer, "integer")? {
748            let token = self.eat_unconditional()?;
749            match &token.kind {
750                TokenKind::Integer(val)
751                | TokenKind::HexInteger(val)
752                | TokenKind::BinInteger(val) => {
753                    let (val_int, val_signed) = val;
754
755                    let signed_val = || {
756                        if plusminus.as_ref().map(|tok| &tok.kind) == Some(&TokenKind::Minus) {
757                            -val_int.to_bigint()
758                        } else {
759                            val_int.to_bigint()
760                        }
761                    };
762
763                    let inner = match val_signed {
764                        LiteralKind::Signed(size) => IntLiteral::Signed {
765                            val: signed_val(),
766                            size: size.clone(),
767                        },
768                        LiteralKind::Unsized => IntLiteral::Unsized(signed_val()),
769                        LiteralKind::Unsigned(size) => IntLiteral::Unsigned {
770                            val: val_int.clone(),
771                            size: size.clone(),
772                        },
773                    };
774                    let loc = if let Some(pm) = plusminus {
775                        ().between(self.file_id, &pm, &token)
776                    } else {
777                        token.loc()
778                    };
779                    Ok(Some(inner.at_loc(&loc)))
780                }
781                _ => unreachable!(),
782            }
783        } else if let Some(pm) = plusminus {
784            Err(Diagnostic::error(
785                pm.loc(),
786                format!("expected a number after '{}'", pm.kind.as_str()),
787            ))
788        } else {
789            Ok(None)
790        }
791    }
792
793    #[trace_parser]
794    fn bool_literal(&mut self) -> Result<Option<Loc<bool>>> {
795        if let Some(tok) = self.peek_and_eat(&TokenKind::True)? {
796            Ok(Some(true.at(self.file_id, &tok.span)))
797        } else if let Some(tok) = self.peek_and_eat(&TokenKind::False)? {
798            Ok(Some(false.at(self.file_id, &tok.span)))
799        } else {
800            Ok(None)
801        }
802    }
803
804    #[trace_parser]
805    fn str_literal(&mut self) -> Result<Option<Loc<String>>> {
806        if self.peek_cond(TokenKind::is_string, "string")? {
807            let token = self.eat_unconditional()?;
808            match &token.kind {
809                TokenKind::String(val) => Ok(Some(val.clone().at_loc(&token.loc()))),
810                _ => unreachable!(),
811            }
812        } else {
813            Ok(None)
814        }
815    }
816
817    #[trace_parser]
818    fn tri_literal(&mut self) -> Result<Option<Loc<BitLiteral>>> {
819        if let Some(tok) = self.peek_and_eat(&TokenKind::Low)? {
820            Ok(Some(BitLiteral::Low.at(self.file_id, &tok.span)))
821        } else if let Some(tok) = self.peek_and_eat(&TokenKind::High)? {
822            Ok(Some(BitLiteral::High.at(self.file_id, &tok.span)))
823        } else if let Some(tok) = self.peek_and_eat(&TokenKind::HighImp)? {
824            Ok(Some(BitLiteral::HighImp.at(self.file_id, &tok.span)))
825        } else {
826            Ok(None)
827        }
828    }
829
830    #[trace_parser]
831    #[tracing::instrument(skip(self))]
832    pub fn block(&mut self, is_pipeline: bool) -> Result<Option<Loc<Block>>> {
833        let start = peek_for!(self, &TokenKind::OpenBrace);
834
835        let (statements, result) = self.statements(is_pipeline)?;
836
837        let end = self.eat(&TokenKind::CloseBrace)?;
838
839        Ok(Some(Block { statements, result }.between(
840            self.file_id,
841            &start.span,
842            &end.span,
843        )))
844    }
845
846    pub fn label_access(&mut self) -> Result<Option<Loc<Expression>>> {
847        if let ref tok @ Token {
848            kind: TokenKind::LabelRef(l),
849            ..
850        } = self.peek()?
851        {
852            self.eat_unconditional()?;
853            self.eat(&TokenKind::Dot)?;
854
855            let field = self.identifier()?;
856
857            let loc = ().between(self.file_id, tok, &field);
858            Ok(Some(
859                Expression::LabelAccess {
860                    label: Path::ident(l.at(self.file_id, tok)).at(self.file_id, tok),
861                    field,
862                }
863                .at_loc(&loc),
864            ))
865        } else {
866            Ok(None)
867        }
868    }
869
870    #[trace_parser]
871    pub fn pipeline_reference(&mut self) -> Result<Option<Loc<Expression>>> {
872        let start = peek_for!(self, &TokenKind::Stage);
873        // Peek here because we can't peek in the .ok_or_else below
874        let next = self.peek()?;
875
876        let parsed = self.first_successful(vec![
877            &|s: &mut Self| s.pipeline_stage_reference(&start),
878            &|s: &mut Self| s.pipeline_stage_status(&start),
879        ])?;
880        match parsed {
881            Some(e) => Ok(Some(e)),
882            None => Err(Diagnostic::from(UnexpectedToken {
883                got: next,
884                expected: vec![".", "("],
885            })),
886        }
887    }
888
889    #[trace_parser]
890    pub fn pipeline_stage_reference(
891        &mut self,
892        stage_keyword: &Token,
893    ) -> Result<Option<Loc<Expression>>> {
894        peek_for!(self, &TokenKind::OpenParen);
895
896        self.unit_context.allows_pipeline_ref(stage_keyword.loc())?;
897
898        let next = self.peek()?;
899        let reference = match next.kind {
900            TokenKind::Plus => {
901                let start = self.eat_unconditional()?;
902                let offset = self.expression()?;
903                let result = PipelineStageReference::Relative(
904                    TypeExpression::ConstGeneric(Box::new(offset.clone())).between(
905                        self.file_id,
906                        &start,
907                        &offset,
908                    ),
909                );
910                result
911            }
912            TokenKind::Minus => {
913                let start = self.eat_unconditional()?;
914                let offset = self.expression()?;
915                let texpr = TypeExpression::ConstGeneric(Box::new(
916                    Expression::UnaryOperator(
917                        spade_ast::UnaryOperator::Sub.at(self.file_id, &next.span),
918                        Box::new(offset.clone()),
919                    )
920                    .between(self.file_id, &start, &offset),
921                ))
922                .between(self.file_id, &start, &offset);
923                PipelineStageReference::Relative(texpr)
924            }
925            TokenKind::Identifier(_) => PipelineStageReference::Absolute(self.identifier()?),
926            _ => {
927                return Err(Diagnostic::from(UnexpectedToken {
928                    got: next,
929                    expected: vec!["+", "-", "identifier"],
930                }));
931            }
932        };
933
934        let close_paren = self.eat(&TokenKind::CloseParen)?;
935
936        self.eat(&TokenKind::Dot)?;
937
938        let ident = self.identifier()?;
939
940        Ok(Some(
941            Expression::PipelineReference {
942                stage_kw_and_reference_loc: ().between(
943                    self.file_id,
944                    &stage_keyword.span,
945                    &close_paren.span,
946                ),
947                stage: reference,
948                name: ident.clone(),
949            }
950            .between(self.file_id, &stage_keyword.span, &ident),
951        ))
952    }
953
954    #[trace_parser]
955    pub fn pipeline_stage_status(
956        &mut self,
957        stage_keyword: &Token,
958    ) -> Result<Option<Loc<Expression>>> {
959        peek_for!(self, &TokenKind::Dot);
960
961        let ident = self.identifier()?;
962
963        match ident.inner.as_str() {
964            "valid" => Ok(Some(Expression::StageValid.between(
965                self.file_id,
966                stage_keyword,
967                &ident,
968            ))),
969            "ready" => Ok(Some(Expression::StageReady.between(
970                self.file_id,
971                stage_keyword,
972                &ident,
973            ))),
974            other => Err(Diagnostic::error(
975                &ident,
976                format!("Expected `ready` or `valid`, got `{other}`"),
977            )
978            .primary_label("Expected `ready` or `valid`")),
979        }
980    }
981
982    #[trace_parser]
983    fn argument_list(&mut self) -> Result<Option<Loc<ArgumentList>>> {
984        let is_named = self.peek_and_eat(&TokenKind::Dollar)?.is_some();
985        let opener = peek_for!(self, &TokenKind::OpenParen);
986
987        let argument_list = if is_named {
988            let args = self
989                .comma_separated(Self::named_argument, &TokenKind::CloseParen)
990                .extra_expected(vec![":"])
991                .map_err(|e| {
992                    debug!("check named arguments =");
993                    let Ok(tok) = self.peek() else {
994                        return e;
995                    };
996                    debug!("{:?}", tok);
997                    if tok.kind == TokenKind::Assignment {
998                        e.span_suggest_replace(
999                            "named arguments are specified with `:`",
1000                            // FIXME: expand into whitespace
1001                            // lifeguard: spade#309
1002                            tok.loc(),
1003                            ":",
1004                        )
1005                    } else {
1006                        e
1007                    }
1008                })?
1009                .into_iter()
1010                .map(Loc::strip)
1011                .collect();
1012            ArgumentList::Named(args)
1013        } else {
1014            let args = self
1015                .comma_separated(Self::expression, &TokenKind::CloseParen)
1016                .no_context()?;
1017
1018            ArgumentList::Positional(args)
1019        };
1020        let end = self.eat(&TokenKind::CloseParen)?;
1021        let span = lspan(opener.span).merge(lspan(end.span));
1022        Ok(Some(argument_list.at(self.file_id, &span)))
1023    }
1024    #[trace_parser]
1025    fn named_argument(&mut self) -> Result<Loc<NamedArgument>> {
1026        // This is a named arg
1027        let name = self.identifier()?;
1028        if self.peek_and_eat(&TokenKind::Colon)?.is_some() {
1029            let value = self.expression()?;
1030
1031            let span = name.span.merge(value.span);
1032
1033            Ok(NamedArgument::Full(name, value).at(self.file_id, &span))
1034        } else {
1035            Ok(NamedArgument::Short(name.clone()).at(self.file_id, &name))
1036        }
1037    }
1038
1039    #[trace_parser]
1040    pub fn type_expression(&mut self) -> Result<Loc<TypeExpression>> {
1041        if let Some(val) = self.int_literal()? {
1042            Ok(TypeExpression::Integer(val.inner.clone().as_signed()).at_loc(&val))
1043        } else if let Some(val) = self.str_literal()? {
1044            Ok(TypeExpression::String(val.inner.clone()).at_loc(&val))
1045        } else if self.peek_kind(&TokenKind::OpenBrace)? {
1046            let (expr, span) = self.surrounded(
1047                &TokenKind::OpenBrace,
1048                |s| s.expression(),
1049                &TokenKind::CloseBrace,
1050            )?;
1051            Ok(TypeExpression::ConstGeneric(Box::new(expr)).at(self.file_id, &span))
1052        } else {
1053            let inner = self.type_spec()?;
1054
1055            Ok(TypeExpression::TypeSpec(Box::new(inner.clone())).at_loc(&inner))
1056        }
1057    }
1058
1059    // Types
1060    #[trace_parser]
1061    pub fn type_spec(&mut self) -> Result<Loc<TypeSpec>> {
1062        if let Some(inv) = self.peek_and_eat(&TokenKind::Inv)? {
1063            let rest = self.type_expression()?;
1064            Ok(TypeSpec::Inverted(Box::new(rest.clone())).between(self.file_id, &inv, &rest))
1065        } else if let Some(tilde) = self.peek_and_eat(&TokenKind::Tilde)? {
1066            return Err(Diagnostic::error(
1067                tilde.clone(),
1068                "The syntax for inverted ports has changed from ~ to inv",
1069            )
1070            .primary_label("~ cannot be used in a type")
1071            .span_suggest("Consider using inv", tilde, "inv "));
1072        } else if let Some(wire_sign) = self.peek_and_eat(&TokenKind::Ampersand)? {
1073            if let Some(mut_) = self.peek_and_eat(&TokenKind::Mut)? {
1074                return Err(Diagnostic::error(
1075                    &().at(self.file_id, &mut_),
1076                    "The syntax of &mut has changed to inv &",
1077                )
1078                .primary_label("&mut is now written as inv &")
1079                .span_suggest_replace(
1080                    "Consider using inv &",
1081                    ().between(self.file_id, &wire_sign, &mut_),
1082                    "inv &",
1083                ));
1084            }
1085
1086            let rest = self.type_expression()?;
1087            Ok(TypeSpec::Wire(Box::new(rest.clone())).between(self.file_id, &wire_sign, &rest))
1088        } else if let Some(tuple) = self.tuple_spec()? {
1089            Ok(tuple)
1090        } else if let Some(array) = self.array_spec()? {
1091            Ok(array)
1092        } else {
1093            if !self.peek_cond(TokenKind::is_identifier, "Identifier")? {
1094                return Err(Diagnostic::from(UnexpectedToken {
1095                    got: self.peek()?,
1096                    expected: vec!["type"],
1097                }));
1098            }
1099            // Single type, maybe with generics
1100            let (path, span) = self.path()?.separate();
1101
1102            if path.to_named_strs().as_slice() == [Some("_")] {
1103                return Ok(TypeSpec::Wildcard.at(self.file_id, &span));
1104            }
1105
1106            // Check if this type has generic params
1107            let generics = if self.peek_kind(&TokenKind::Lt)? {
1108                let generic_start = self.eat_unconditional()?;
1109                let type_exprs = self
1110                    .comma_separated(Self::type_expression, &TokenKind::Gt)
1111                    .extra_expected(vec!["type expression"])?;
1112                let generic_end = self.eat(&TokenKind::Gt)?;
1113                Some(type_exprs.between(self.file_id, &generic_start.span, &generic_end.span))
1114            } else {
1115                None
1116            };
1117
1118            let span_end = generics.as_ref().map(|g| g.span).unwrap_or(span);
1119            Ok(TypeSpec::Named(path, generics).between(self.file_id, &span, &span_end))
1120        }
1121    }
1122
1123    #[trace_parser]
1124    pub fn tuple_spec(&mut self) -> Result<Option<Loc<TypeSpec>>> {
1125        let start = peek_for!(self, &TokenKind::OpenParen);
1126        if let Some(_) = self.peek_and_eat(&TokenKind::Comma)? {
1127            let closer = self.eat(&TokenKind::CloseParen)?;
1128            return Ok(Some(TypeSpec::Tuple(vec![]).between(
1129                self.file_id,
1130                &start,
1131                &closer,
1132            )));
1133        }
1134
1135        let inner = self
1136            .comma_separated(Self::type_expression, &TokenKind::CloseParen)
1137            .no_context()?;
1138        let end = self.eat(&TokenKind::CloseParen)?;
1139
1140        let span = lspan(start.span).merge(lspan(end.span));
1141
1142        Ok(Some(TypeSpec::Tuple(inner).at(self.file_id, &span)))
1143    }
1144
1145    #[trace_parser]
1146    pub fn array_spec(&mut self) -> Result<Option<Loc<TypeSpec>>> {
1147        let start = peek_for!(self, &TokenKind::OpenBracket);
1148
1149        let inner = self.type_expression()?;
1150
1151        if let Some(end) = self.peek_and_eat(&TokenKind::CloseBracket)? {
1152            return Err(Diagnostic::error(
1153                ().between_locs(&start.loc(), &end.loc()),
1154                "missing array size",
1155            )
1156            .primary_label("missing size for this array type")
1157            .note("array types need a specified size")
1158            .span_suggest_insert_before("insert a size here", end, "; /* N */"));
1159        }
1160
1161        self.eat(&TokenKind::Semi)?;
1162
1163        let size = self.type_expression()?;
1164
1165        let end = self.eat(&TokenKind::CloseBracket)?;
1166
1167        Ok(Some(
1168            TypeSpec::Array {
1169                inner: Box::new(inner),
1170                size: Box::new(size),
1171            }
1172            .between(self.file_id, &start, &end),
1173        ))
1174    }
1175
1176    /// A name with an associated type, as used in argument definitions as well
1177    /// as struct definitions
1178    ///
1179    /// name: Type
1180    #[trace_parser]
1181    pub fn name_and_type(&mut self) -> Result<(Loc<Identifier>, Loc<TypeSpec>)> {
1182        let name = self.identifier()?;
1183        self.eat(&TokenKind::Colon)?;
1184        let t = self.type_spec()?;
1185        Ok((name, t))
1186    }
1187
1188    #[trace_parser]
1189    pub fn pattern(&mut self) -> Result<Loc<Pattern>> {
1190        let result = self.first_successful(vec![
1191            &|s| {
1192                let start = peek_for!(s, &TokenKind::OpenParen);
1193                let inner = s
1194                    .comma_separated(Self::pattern, &TokenKind::CloseParen)
1195                    .no_context()?;
1196                let end = s.eat(&TokenKind::CloseParen)?;
1197
1198                Ok(Some(Pattern::Tuple(inner).between(
1199                    s.file_id,
1200                    &start.span,
1201                    &end.span,
1202                )))
1203            },
1204            &|s| {
1205                let start = peek_for!(s, &TokenKind::OpenBracket);
1206                let inner = s
1207                    .comma_separated(Self::pattern, &TokenKind::CloseBracket)
1208                    .no_context()?;
1209                let end = s.eat(&TokenKind::CloseBracket)?;
1210                Ok(Some(Pattern::Array(inner).between(
1211                    s.file_id,
1212                    &start.span,
1213                    &end.span,
1214                )))
1215            },
1216            &|s| {
1217                Ok(s.int_literal()?
1218                    // Map option, then map Loc
1219                    .map(|val| val.map(Pattern::Integer)))
1220            },
1221            &|s| {
1222                Ok(s.bool_literal()?
1223                    // Map option, then map Loc
1224                    .map(|val| val.map(Pattern::Bool)))
1225            },
1226            &|s| Ok(s.ascii_char_literal()?.map(|val| val.map(Pattern::Integer))),
1227            &|s| {
1228                let path = s.path()?;
1229                let path_span = path.span;
1230
1231                if let Some(start_paren) = s.peek_and_eat(&TokenKind::OpenParen)? {
1232                    let inner = s
1233                        .comma_separated(Self::pattern, &TokenKind::CloseParen)
1234                        .no_context()?;
1235                    let end_paren = s.eat(&TokenKind::CloseParen)?;
1236
1237                    Ok(Some(
1238                        Pattern::Type(
1239                            path,
1240                            ArgumentPattern::Positional(inner).between(
1241                                s.file_id,
1242                                &start_paren.span,
1243                                &end_paren.span,
1244                            ),
1245                        )
1246                        .between(s.file_id, &path_span, &end_paren.span),
1247                    ))
1248                } else if let Some(start_brace) = s.peek_and_eat(&TokenKind::Dollar)? {
1249                    s.eat(&TokenKind::OpenParen)?;
1250                    let inner_parser = |s: &mut Self| {
1251                        let lhs = s.identifier()?;
1252                        let rhs = if s.peek_and_eat(&TokenKind::Colon)?.is_some() {
1253                            Some(s.pattern()?)
1254                        } else {
1255                            None
1256                        };
1257
1258                        Ok((lhs, rhs))
1259                    };
1260                    let inner = s
1261                        .comma_separated(inner_parser, &TokenKind::CloseParen)
1262                        .extra_expected(vec![":"])?;
1263                    let end_brace = s.eat(&TokenKind::CloseParen)?;
1264
1265                    Ok(Some(
1266                        Pattern::Type(
1267                            path,
1268                            ArgumentPattern::Named(inner).between(
1269                                s.file_id,
1270                                &start_brace.span,
1271                                &end_brace.span,
1272                            ),
1273                        )
1274                        .between(s.file_id, &path_span, &end_brace.span),
1275                    ))
1276                } else {
1277                    Ok(Some(Pattern::Path(path.clone()).at(s.file_id, &path)))
1278                }
1279            },
1280        ])?;
1281
1282        if let Some(result) = result {
1283            Ok(result)
1284        } else {
1285            Err(Diagnostic::from(UnexpectedToken {
1286                got: self.eat_unconditional()?,
1287                expected: vec!["Pattern"],
1288            }))
1289        }
1290    }
1291
1292    #[trace_parser]
1293    pub fn statements(
1294        &mut self,
1295        allow_stages: bool,
1296    ) -> Result<(Vec<Loc<Statement>>, Option<Loc<Expression>>)> {
1297        fn semi_validator(next: Token) -> Result<TokenKind> {
1298            match next.kind {
1299                TokenKind::GreekQuestionMark => Err(Diagnostic::error(
1300                    next.clone(),
1301                    format!("Expected `;`, got a greek question mark (;)"),
1302                )
1303                .help("The greek question mark (;) looks similar to the normal `;` character")),
1304                other => Ok(other),
1305            }
1306        }
1307        let semi_continuation = |inner: Loc<Statement>, parser: &mut Parser| {
1308            let next = parser.peek()?;
1309            let span = next.loc();
1310            match semi_validator(next) {
1311                Ok(TokenKind::Semi) => {
1312                    parser.eat_unconditional()?;
1313                    Ok(inner)
1314                }
1315                Ok(other) => Err(Diagnostic::error(
1316                    span,
1317                    format!("Expected `;`, got `{}`", other.as_str()),
1318                )
1319                .primary_label("Expected `;`")
1320                .span_suggest_insert_after(
1321                    "You probably forgot to end this statement with a `;`",
1322                    inner,
1323                    ";",
1324                )),
1325                Err(err) => Err(err),
1326            }
1327        };
1328
1329        let mut final_expr = None;
1330        let members = self.keyword_peeking_parser_or_else_seq(
1331            vec![
1332                Box::new(BindingParser {}.then(semi_continuation)),
1333                Box::new(RegisterParser {}.then(semi_continuation).then(
1334                    move |statement, _parser| {
1335                        if let Statement::PipelineRegMarker(_, _) = statement.inner {
1336                            if !allow_stages {
1337                                return Err(Diagnostic::error(
1338                                    statement.loc(),
1339                                    "stage outside pipeline",
1340                                )
1341                                .primary_label("stage is not allowed here")
1342                                .note("stages are only allowed in the root block of a pipeline"));
1343                            }
1344                        }
1345                        Ok(statement)
1346                    },
1347                )),
1348                Box::new(DeclParser {}.then(semi_continuation)),
1349                Box::new(LabelParser {}),
1350                Box::new(AssertParser {}.then(semi_continuation)),
1351                Box::new(SetParser {}.then(semi_continuation)),
1352            ],
1353            true,
1354            vec![|tok| tok == &TokenKind::CloseBrace],
1355            |parser| {
1356                if parser.peek_kind(&TokenKind::CloseBrace)? {
1357                    return Ok(None);
1358                }
1359                let (expr, loc) = parser.non_comptime_expression()?.separate_loc();
1360                if matches!(semi_validator(parser.peek()?)?, TokenKind::Semi) {
1361                    parser.eat_unconditional()?;
1362                    Ok(Some(Statement::Expression(expr).at_loc(&loc)))
1363                } else {
1364                    // no semicolon afterwards - set as return value and break out of loop
1365                    final_expr = Some(expr);
1366                    Ok(None)
1367                }
1368            },
1369        )?;
1370
1371        Ok((members, final_expr))
1372    }
1373
1374    #[trace_parser]
1375    pub fn parameter(&mut self) -> Result<(AttributeList, Loc<Identifier>, Loc<TypeSpec>)> {
1376        let attrs = self.attributes()?;
1377        let (name, ty) = self.name_and_type()?;
1378        Ok((attrs, name, ty))
1379    }
1380
1381    #[trace_parser]
1382    pub fn parameter_list(&mut self) -> Result<ParameterList> {
1383        let mut first_attrs = self.attributes()?;
1384
1385        let self_ = if self.peek_cond(
1386            |tok| matches!(tok, TokenKind::Identifier(i) if i.as_str() == "self"),
1387            "Expected argument",
1388        )? {
1389            let self_tok = self.eat_unconditional()?;
1390            self.peek_and_eat(&TokenKind::Comma)?;
1391            let attrs;
1392            (first_attrs, attrs) = (AttributeList::empty(), first_attrs);
1393            Some(attrs.at(self.file_id, &self_tok))
1394        } else {
1395            None
1396        };
1397
1398        let mut args = self
1399            .comma_separated(Self::parameter, &TokenKind::CloseParen)
1400            .no_context()?;
1401
1402        if !first_attrs.is_empty() {
1403            let Some(first_arg) = args.first_mut() else {
1404                // At this point this parser will definitely fail, we run it just for its diagnostic
1405                self.eat_cond(TokenKind::is_identifier, "Identifier")?;
1406                unreachable!();
1407            };
1408
1409            // Patch attributes into the first parameter
1410            first_arg.0 = first_attrs;
1411        }
1412
1413        Ok(ParameterList { self_, args })
1414    }
1415
1416    #[tracing::instrument(skip(self))]
1417    pub fn type_parameter_list(&mut self) -> Result<ParameterList> {
1418        Ok(ParameterList::without_self(
1419            self.comma_separated(Self::parameter, &TokenKind::CloseBrace)
1420                .no_context()?,
1421        ))
1422    }
1423
1424    #[trace_parser]
1425    pub fn type_param(&mut self) -> Result<Loc<TypeParam>> {
1426        // If this is a type level integer
1427        if let Some(_hash) = self.peek_and_eat(&TokenKind::Hash)? {
1428            let meta_type = self.identifier()?;
1429            let name = self.identifier()?;
1430
1431            let loc = ().between_locs(&meta_type, &name);
1432            Ok(TypeParam::TypeWithMeta {
1433                meta: meta_type,
1434                name,
1435            }
1436            .at_loc(&loc))
1437        } else {
1438            let (id, loc) = self.identifier()?.separate();
1439            let traits = if self.peek_and_eat(&TokenKind::Colon)?.is_some() {
1440                self.token_separated(
1441                    Self::trait_spec,
1442                    &TokenKind::Plus,
1443                    vec![TokenKind::Comma, TokenKind::Gt],
1444                )
1445                .no_context()?
1446                .into_iter()
1447                .map(|spec| {
1448                    let loc = ().at_loc(&spec.path);
1449                    spec.at_loc(&loc)
1450                })
1451                .collect()
1452            } else {
1453                vec![]
1454            };
1455            Ok(TypeParam::TypeName { name: id, traits }.at(self.file_id, &loc))
1456        }
1457    }
1458
1459    #[trace_parser]
1460    pub fn generics_list(&mut self) -> Result<Option<Loc<Vec<Loc<TypeParam>>>>> {
1461        if self.peek_kind(&TokenKind::Lt)? {
1462            let (params, loc) = self.surrounded(
1463                &TokenKind::Lt,
1464                |s| {
1465                    s.comma_separated(Self::type_param, &TokenKind::Gt)
1466                        .extra_expected(vec!["type parameter"])
1467                },
1468                &TokenKind::Gt,
1469            )?;
1470            Ok(Some(params.at_loc(&loc)))
1471        } else {
1472            Ok(None)
1473        }
1474    }
1475
1476    #[trace_parser]
1477    pub fn generic_spec_list(&mut self) -> Result<Option<Loc<Vec<Loc<TypeExpression>>>>> {
1478        if self.peek_kind(&TokenKind::Lt)? {
1479            let (params, loc) = self.surrounded(
1480                &TokenKind::Lt,
1481                |s| {
1482                    s.comma_separated(Self::type_expression, &TokenKind::Gt)
1483                        .extra_expected(vec!["type spec"])
1484                },
1485                &TokenKind::Gt,
1486            )?;
1487            Ok(Some(params.at_loc(&loc)))
1488        } else {
1489            Ok(None)
1490        }
1491    }
1492
1493    #[trace_parser]
1494    pub fn trait_spec(&mut self) -> Result<TraitSpec> {
1495        let path = self.path()?;
1496        let mut type_params = self.generic_spec_list()?;
1497        let mut paren_syntax = false;
1498
1499        if self.peek_cond(|tok| tok == &TokenKind::OpenParen, "(")? {
1500            let param_tuple_type = self.tuple_spec()?.unwrap().map(|tuple| {
1501                let TypeSpec::Tuple(contents) = tuple else {
1502                    unreachable!();
1503                };
1504
1505                TypeExpression::TypeSpec(Box::new(Loc::nowhere(TypeSpec::Tuple(contents))))
1506            });
1507
1508            let start = param_tuple_type.loc();
1509            let (return_type, end) = if self.peek_and_eat(&TokenKind::SlimArrow)?.is_some() {
1510                let ty = self.type_expression()?;
1511                let loc = ty.loc();
1512                (ty, loc)
1513            } else {
1514                let dummy = Loc::nowhere(TypeExpression::TypeSpec(Box::new(Loc::nowhere(
1515                    TypeSpec::Tuple(vec![]),
1516                ))));
1517                (dummy, param_tuple_type.loc())
1518            };
1519
1520            let mut new_type_params = type_params.unwrap_or(vec![].nowhere()).inner;
1521            new_type_params.extend_from_slice(&[param_tuple_type, return_type]);
1522            type_params = Some(new_type_params.between_locs(&start, &end));
1523
1524            paren_syntax = true;
1525        };
1526
1527        Ok(TraitSpec {
1528            path,
1529            type_params,
1530            paren_syntax,
1531        })
1532    }
1533
1534    fn disallow_attributes(&self, attributes: &AttributeList, item_start: &Token) -> Result<()> {
1535        if attributes.0.is_empty() {
1536            Ok(())
1537        } else {
1538            let mut diagnostic = Diagnostic::error(
1539                ().between_locs(attributes.0.first().unwrap(), attributes.0.last().unwrap()),
1540                "invalid attribute location",
1541            )
1542            .primary_label("attributes are not allowed here")
1543            .secondary_label(
1544                item_start.loc(),
1545                format!("{} cannot have attributes", item_start.kind.as_str()),
1546            )
1547            .note("attributes are only allowed on structs, enums, their variants, functions and pipelines");
1548            if matches!(item_start.kind, TokenKind::Mod) {
1549                diagnostic.add_help(
1550                    "If you want to document this module, use inside comments (//!) instead.",
1551                );
1552            }
1553            Err(diagnostic)
1554        }
1555    }
1556
1557    fn disallow_visibility(&self, visibility: &Loc<Visibility>, item_start: &Token) -> Result<()> {
1558        if visibility.inner == Visibility::Implicit {
1559            Ok(())
1560        } else {
1561            Err(
1562                Diagnostic::error(visibility, "invalid visibility marker location")
1563                    .primary_label("visibility markers are not allowed here")
1564                    .secondary_label(
1565                        item_start.loc(),
1566                        format!(
1567                            "{} cannot have a visibility marker",
1568                            item_start.kind.as_str()
1569                        ),
1570                    ),
1571            )
1572        }
1573    }
1574
1575    pub fn unit_kind(&mut self, start_token: &Token) -> Result<Option<Loc<UnitKind>>> {
1576        match start_token.kind {
1577            TokenKind::Pipeline => {
1578                self.eat_unconditional()?;
1579                let (depth, depth_span) = self.surrounded(
1580                    &TokenKind::OpenParen,
1581                    |s| match s.type_expression() {
1582                        Ok(t) => Ok(t),
1583                        Err(diag) => Err(diag.secondary_label(
1584                            ().at(s.file_id, start_token),
1585                            "Pipelines require a pipeline depth",
1586                        )),
1587                    },
1588                    &TokenKind::CloseParen,
1589                )?;
1590
1591                Ok(Some(UnitKind::Pipeline(depth).between(
1592                    self.file_id,
1593                    start_token,
1594                    &depth_span,
1595                )))
1596            }
1597            TokenKind::Function => {
1598                self.eat_unconditional()?;
1599                Ok(Some(UnitKind::Function.at(self.file_id, start_token)))
1600            }
1601            TokenKind::Entity => {
1602                self.eat_unconditional()?;
1603                Ok(Some(UnitKind::Entity.at(self.file_id, start_token)))
1604            }
1605            _ => Ok(None),
1606        }
1607    }
1608
1609    #[trace_parser]
1610    #[tracing::instrument(skip(self))]
1611    fn visibility(&mut self) -> Result<Loc<Visibility>> {
1612        if let Some(pub_kw) = self.peek_and_eat(&TokenKind::Pub)? {
1613            if self.peek_and_eat(&TokenKind::OpenParen)?.is_some() {
1614                let next_token = self.peek()?;
1615                let visibility = match next_token.kind {
1616                    TokenKind::Identifier(ref name) => match name.as_str() {
1617                        "lib" => Some(Visibility::AtLib),
1618                        "self" => Some(Visibility::AtSelf),
1619                        "super" => Some(Visibility::AtSuper),
1620                        _ => None,
1621                    },
1622                    _ => None,
1623                };
1624
1625                let Some(visibility) = visibility else {
1626                    return Err(Diagnostic::error(
1627                        next_token,
1628                        "Expected `self`, `super` or `lib`",
1629                    ));
1630                };
1631
1632                self.eat_unconditional()?;
1633
1634                let Some(close_parens) = self.peek_and_eat(&TokenKind::CloseParen)? else {
1635                    let next_token = self.peek()?;
1636                    return Err(Diagnostic::error(next_token, "Expected closing `)`"));
1637                };
1638
1639                Ok(visibility.between_locs(&pub_kw.loc(), &close_parens.loc()))
1640            } else {
1641                Ok(Visibility::Public.at_loc(&pub_kw.loc()))
1642            }
1643        } else {
1644            Ok(Visibility::Implicit.nowhere())
1645        }
1646    }
1647
1648    #[trace_parser]
1649    #[tracing::instrument(skip(self))]
1650    pub fn unit_head(
1651        &mut self,
1652        attributes: &AttributeList,
1653        visibility: &Loc<Visibility>,
1654    ) -> Result<Option<Loc<UnitHead>>> {
1655        let unsafe_token = self.peek_and_eat(&TokenKind::Unsafe)?;
1656        let extern_token = self.peek_and_eat(&TokenKind::Extern)?;
1657        let start_token = self.peek()?;
1658        let Some(unit_kind) = self.unit_kind(&start_token)? else {
1659            if let Some(prev) = unsafe_token.or(extern_token) {
1660                return Err(Diagnostic::error(
1661                    start_token,
1662                    "Expected `fn`, `entity` or `pipeline`",
1663                )
1664                .primary_label("Expected `fn`, `entity` or `pipeline`")
1665                .secondary_label(prev, "Because of this keyword"));
1666            } else {
1667                return Ok(None);
1668            }
1669        };
1670
1671        let name = self.identifier()?;
1672
1673        let type_params = self.generics_list()?;
1674
1675        // Input types
1676        let (inputs, inputs_loc) = self.surrounded(
1677            &TokenKind::OpenParen,
1678            Self::parameter_list,
1679            &TokenKind::CloseParen,
1680        )?;
1681        let inputs = inputs.at_loc(&inputs_loc);
1682
1683        // Return type
1684        let output_type = if let Some(arrow) = self.peek_and_eat(&TokenKind::SlimArrow)? {
1685            Some((arrow.loc(), self.type_spec()?))
1686        } else {
1687            None
1688        };
1689
1690        let where_clauses = self.where_clauses()?;
1691
1692        let end = output_type
1693            .as_ref()
1694            .map(|o| o.1.loc())
1695            .unwrap_or(inputs.loc());
1696
1697        Ok(Some(
1698            UnitHead {
1699                visibility: visibility.clone(),
1700                unsafe_token: unsafe_token.map(|token| token.loc()),
1701                extern_token: extern_token.map(|token| token.loc()),
1702                attributes: attributes.clone(),
1703                unit_kind,
1704                name,
1705                inputs,
1706                output_type,
1707                type_params,
1708                where_clauses,
1709            }
1710            .between(self.file_id, &start_token, &end),
1711        ))
1712    }
1713
1714    fn where_clauses(&mut self) -> Result<Vec<WhereClause>> {
1715        if let Some(where_kw) = self.peek_and_eat(&TokenKind::Where)? {
1716            let clauses = self
1717                .token_separated(
1718                    |s| {
1719                        if s.peek_cond(|t| matches!(t, &TokenKind::Identifier(_)), "identifier")? {
1720                            let name = s.path()?;
1721                            if let Some(_colon) = s.peek_and_eat(&TokenKind::Colon)? {
1722                                // We'll grandfather in the old : {} syntax for now
1723                                if s.peek_cond(
1724                                    |tok| tok == &TokenKind::OpenBrace || tok == &TokenKind::Semi,
1725                                    "{",
1726                                )? {
1727                                    let expression = s
1728                                        .surrounded(
1729                                            &TokenKind::OpenBrace,
1730                                            Self::expression,
1731                                            &TokenKind::CloseBrace,
1732                                        )?
1733                                        .0;
1734
1735                                    Ok(WhereClause::GenericInt {
1736                                        target: name,
1737                                        kind: spade_ast::Inequality::Eq,
1738                                        expression,
1739                                        if_unsatisfied: None,
1740                                    })
1741                                } else {
1742                                    let traits = s
1743                                        .token_separated(
1744                                            Self::trait_spec,
1745                                            &TokenKind::Plus,
1746                                            vec![
1747                                                TokenKind::Comma,
1748                                                TokenKind::OpenBrace,
1749                                                TokenKind::Semi,
1750                                            ],
1751                                        )
1752                                        .extra_expected(vec!["identifier"])?
1753                                        .into_iter()
1754                                        .map(|spec| {
1755                                            let loc = ().at_loc(&spec.path);
1756                                            spec.at_loc(&loc)
1757                                        })
1758                                        .collect();
1759
1760                                    Ok(WhereClause::TraitBounds {
1761                                        target: name,
1762                                        traits,
1763                                    })
1764                                }
1765                            } else {
1766                                let next = s.eat_unconditional()?;
1767                                let inequality = match next.kind {
1768                                    TokenKind::Equals => Inequality::Eq,
1769                                    TokenKind::NotEquals => Inequality::Neq,
1770                                    TokenKind::Gt => Inequality::Gt,
1771                                    TokenKind::Ge => Inequality::Geq,
1772                                    TokenKind::Lt => Inequality::Lt,
1773                                    TokenKind::Le => Inequality::Leq,
1774                                    _ => {
1775                                        return Err(Diagnostic::from(UnexpectedToken {
1776                                            got: next,
1777                                            expected: vec![":", "==", "!=", ">", ">=", "<=", "<"],
1778                                        })
1779                                        .into())
1780                                    }
1781                                };
1782
1783                                let expression = s.expression()?;
1784
1785                                let if_unsatisfied =
1786                                    if let Some(_) = s.peek_and_eat(&TokenKind::Else)? {
1787                                        let message = s.eat_unconditional()?;
1788                                        match message.kind {
1789                                            TokenKind::String(s) => Some(s),
1790                                            _ => {
1791                                                return Err(Diagnostic::from(UnexpectedToken {
1792                                                    got: message,
1793                                                    expected: vec!["\""],
1794                                                }))
1795                                            }
1796                                        }
1797                                    } else {
1798                                        None
1799                                    };
1800
1801                                Ok(WhereClause::GenericInt {
1802                                    target: name,
1803                                    kind: inequality,
1804                                    expression,
1805                                    if_unsatisfied,
1806                                })
1807                            }
1808                        } else {
1809                            Err(Diagnostic::bug(
1810                                ().at(s.file_id, &where_kw),
1811                                "Comma separated should not show this error",
1812                            ))
1813                        }
1814                    },
1815                    &TokenKind::Comma,
1816                    vec![TokenKind::OpenBrace, TokenKind::Semi],
1817                )
1818                .extra_expected(vec!["identifier"])?;
1819
1820            Ok(clauses)
1821        } else {
1822            Ok(vec![])
1823        }
1824    }
1825
1826    #[trace_parser]
1827    pub fn impl_body(&mut self) -> Result<Vec<Loc<Unit>>> {
1828        let result = self.keyword_peeking_parser_seq(
1829            vec![Box::new(items::UnitParser {}.map(|u| Ok(u)))],
1830            true,
1831            vec![|tok| tok == &TokenKind::CloseBrace],
1832        )?;
1833
1834        Ok(result)
1835    }
1836
1837    #[trace_parser]
1838    #[tracing::instrument(level = "debug", skip(self))]
1839    pub fn enum_variant(&mut self) -> Result<EnumVariant> {
1840        let attributes = self.attributes()?;
1841
1842        let name = self.identifier()?;
1843
1844        let args = if let Some(start) = self.peek_and_eat(&TokenKind::OpenBrace)? {
1845            let result = self.type_parameter_list()?;
1846            let end = self.eat(&TokenKind::CloseBrace)?;
1847            Some(result.between(self.file_id, &start, &end))
1848        } else if self.peek_kind(&TokenKind::Comma)? || self.peek_kind(&TokenKind::CloseBrace)? {
1849            None
1850        } else {
1851            let token = self.peek()?;
1852            let message = unexpected_token_message(&token.kind, "`{`, `,` or `}`");
1853            // FIXME: Error::Eof => Diagnostic
1854            let mut err = Diagnostic::error(token, message);
1855            self.maybe_suggest_brace_enum_variant(&mut err)?;
1856            return Err(err);
1857        };
1858
1859        Ok(EnumVariant {
1860            attributes,
1861            name,
1862            args,
1863        })
1864    }
1865
1866    fn maybe_suggest_brace_enum_variant(&mut self, err: &mut Diagnostic) -> Result<bool> {
1867        let open_paren = match self.peek_and_eat(&TokenKind::OpenParen)? {
1868            Some(open_paren) => open_paren.loc(),
1869            _ => return Ok(false),
1870        };
1871        let mut try_parameter_list = self.clone();
1872        if try_parameter_list.parameter_list().is_err() {
1873            return Ok(false);
1874        }
1875        let close_paren = match try_parameter_list.peek_and_eat(&TokenKind::CloseParen)? {
1876            Some(close_paren) => close_paren.loc(),
1877            _ => return Ok(false),
1878        };
1879        err.push_subdiagnostic(
1880            SuggestBraceEnumVariant {
1881                open_paren,
1882                close_paren,
1883            }
1884            .into(),
1885        );
1886        Ok(true)
1887    }
1888
1889    // Parses `<identifier>=<subtree>` if `identifier` matches the specified identifier
1890    #[trace_parser]
1891    #[tracing::instrument(skip(self, value))]
1892    pub fn attribute_key_value<T>(
1893        &mut self,
1894        key: &str,
1895        value: impl Fn(&mut Self) -> Result<T>,
1896    ) -> Result<Option<(Loc<String>, T)>> {
1897        let next = self.peek()?;
1898        if matches!(next.kind, TokenKind::Identifier(k) if k.as_str() == key) {
1899            self.eat_unconditional()?;
1900
1901            self.eat(&TokenKind::Assignment)?;
1902
1903            Ok(Some((
1904                key.to_string().at(self.file_id, &next),
1905                value(self)?,
1906            )))
1907        } else {
1908            Ok(None)
1909        }
1910    }
1911
1912    #[trace_parser]
1913    #[tracing::instrument(skip(self))]
1914    pub fn attribute_inner(&mut self) -> Result<Attribute> {
1915        let start = self.identifier()?;
1916
1917        macro_rules! bool_or_payload {
1918            ($name:ident bool) => {
1919                let mut $name = false;
1920            };
1921            ($name:ident $rest:tt) => {
1922                let mut $name = None;
1923            };
1924        }
1925        macro_rules! rhs_or_present {
1926            ($name:ident, $tok:expr, $s:ident, bool) => {
1927                $name = true
1928            };
1929            ($name:ident, $tok:expr, $s:ident, $subparser:tt) => {{
1930                if let Some(prev) = &$name {
1931                    return Err(Diagnostic::error(
1932                        $tok,
1933                        format!("{} specified more than once", stringify!($name)),
1934                    )
1935                    .primary_label("Specified multiple times")
1936                    .secondary_label(prev, "Previously specified here")
1937                    .into());
1938                }
1939
1940                $s.peek_and_eat(&TokenKind::Assignment)?;
1941                $name = Some($subparser?)
1942            }};
1943        }
1944
1945        macro_rules! check_required {
1946            ($attr_token:expr, $name:ident) => {};
1947            ($attr_token:expr, $name:ident $required:ident) => {
1948                let $name = if let Some(inner) = $name {
1949                    inner
1950                } else {
1951                    return Err(Diagnostic::error(
1952                        $attr_token,
1953                        format!("Missing argument '{}'", stringify!($name)),
1954                    )
1955                    .primary_label(format!("Missing argument '{}'", stringify!($name)))
1956                    .into());
1957                };
1958            };
1959        }
1960
1961        macro_rules! attribute_arg_parser {
1962            ($attr:expr, $self:expr, $s:ident, $result_struct:path{ $($name:ident $([$required:ident])?:  $assignment:tt),* }) => {
1963                {
1964                $( bool_or_payload!($name $assignment) );*;
1965
1966                let params = vec![$(stringify!($name)),*];
1967
1968                $self.surrounded(
1969                    &TokenKind::OpenParen, |$s| {
1970                        loop {
1971                            let next = $s.peek()?;
1972                            match &next.kind {
1973                                $(
1974                                    TokenKind::Identifier(ident) if ident.as_str() == stringify!($name) => {
1975                                        $s.eat_unconditional()?;
1976                                        rhs_or_present!($name, next, $s, $assignment);
1977                                    }
1978                                ),*
1979                                TokenKind::Identifier(_) => {
1980                                    return Err(Diagnostic::error(next, format!("Invalid parameter for {}", $attr))
1981                                        .primary_label("Invalid parameter")
1982                                        .note(if params.is_empty() {
1983                                            format!(
1984                                                "{} does not take any parameters",
1985                                                $attr
1986                                            )
1987                                        } else if params.len() == 1 {
1988                                            format!(
1989                                                "{} only takes the parameter {}",
1990                                                $attr,
1991                                                params[0]
1992                                            )
1993                                        } else {
1994                                            format!(
1995                                                "{} only takes the parameters {} or {}",
1996                                                $attr,
1997                                                params.iter().take(params.len()-1).join(", "),
1998                                                params[params.len() - 1]
1999                                            )
2000                                        })
2001                                        .into()
2002                                    )
2003                                }
2004                                TokenKind::Comma => {
2005                                    $s.eat_unconditional()?;
2006                                }
2007                                TokenKind::CloseParen => {
2008                                    break
2009                                },
2010                                _ => {
2011                                    return Err(Diagnostic::from(UnexpectedToken {
2012                                        got: next,
2013                                        expected: vec!["identifier", ",", ")"],
2014                                    }).into())
2015                                }
2016                            }
2017                        }
2018
2019                        Ok(())
2020                    },
2021                    &TokenKind::CloseParen
2022                )?;
2023
2024                $(check_required!($attr, $name $($required)?);)*
2025
2026                $result_struct {
2027                    $($name),*
2028                }
2029            }
2030            }
2031        }
2032
2033        match start.inner.as_str() {
2034            "spadec_paren_sugar" => Ok(Attribute::SpadecParenSugar),
2035            "verilog_attrs" => {
2036                let (entries, _) = self.surrounded(
2037                    &TokenKind::OpenParen,
2038                    |s| {
2039                        s.comma_separated(|s| s.verilog_attr(), &TokenKind::CloseParen)
2040                            .no_context()
2041                    },
2042                    &TokenKind::CloseParen,
2043                )?;
2044                Ok(Attribute::VerilogAttrs { entries })
2045            }
2046            "no_mangle" => {
2047                if self.peek_kind(&TokenKind::OpenParen)? {
2048                    let (all, _) = self.surrounded(
2049                        &TokenKind::OpenParen,
2050                        Self::identifier,
2051                        &TokenKind::CloseParen,
2052                    )?;
2053                    if all.inner.as_str() != "all" {
2054                        Err(Diagnostic::error(&all, "Invalid attribute syntax")
2055                            .primary_label("Unexpected parameter to `#[no_mangle])")
2056                            .span_suggest_replace("Did you mean `#[no_mangle(all)]`?", all, "all"))
2057                    } else {
2058                        Ok(Attribute::NoMangle { all: true })
2059                    }
2060                } else {
2061                    Ok(Attribute::NoMangle { all: false })
2062                }
2063            }
2064            "fsm" => {
2065                if self.peek_kind(&TokenKind::OpenParen)? {
2066                    let (state, _) = self.surrounded(
2067                        &TokenKind::OpenParen,
2068                        Self::identifier,
2069                        &TokenKind::CloseParen,
2070                    )?;
2071                    Ok(Attribute::Fsm { state: Some(state) })
2072                } else {
2073                    Ok(Attribute::Fsm { state: None })
2074                }
2075            }
2076            "optimize" => {
2077                let (passes, _) = self.surrounded(
2078                    &TokenKind::OpenParen,
2079                    |s| {
2080                        s.comma_separated(|s| s.identifier(), &TokenKind::CloseParen)
2081                            .no_context()
2082                    },
2083                    &TokenKind::CloseParen,
2084                )?;
2085
2086                Ok(Attribute::Optimize {
2087                    passes: passes
2088                        .into_iter()
2089                        .map(|loc| loc.map(|ident| ident.as_str().to_owned()))
2090                        .collect(),
2091                })
2092            }
2093            "surfer_translator" => {
2094                let (result, _) = self.surrounded(
2095                    &TokenKind::OpenParen,
2096                    |s| {
2097                        let tok = s.peek()?;
2098                        if let TokenKind::String(name) = tok.kind {
2099                            s.eat_unconditional()?;
2100                            Ok(Attribute::SurferTranslator(name))
2101                        } else {
2102                            Err(UnexpectedToken {
2103                                got: tok,
2104                                expected: vec!["string"],
2105                            }
2106                            .into())
2107                        }
2108                    },
2109                    &TokenKind::CloseParen,
2110                )?;
2111                Ok(result)
2112            }
2113            "wal_trace" => {
2114                if self.peek_kind(&TokenKind::OpenParen)? {
2115                    Ok(attribute_arg_parser!(
2116                        start,
2117                        self,
2118                        s,
2119                        Attribute::WalTrace {
2120                            clk: { s.expression() },
2121                            rst: { s.expression() }
2122                        }
2123                    ))
2124                } else {
2125                    Ok(Attribute::WalTrace {
2126                        clk: None,
2127                        rst: None,
2128                    })
2129                }
2130            }
2131            "wal_traceable" => Ok(attribute_arg_parser!(
2132                start,
2133                self,
2134                s,
2135                Attribute::WalTraceable {
2136                    suffix: { s.identifier() },
2137                    uses_clk: bool,
2138                    uses_rst: bool
2139                }
2140            )),
2141            "wal_suffix" => Ok(attribute_arg_parser!(start, self, s, Attribute::WalSuffix {
2142                suffix [required]: {s.identifier()}
2143            })),
2144            other => Err(
2145                Diagnostic::error(&start, format!("Unknown attribute '{other}'"))
2146                    .primary_label("Unrecognised attribute"),
2147            ),
2148        }
2149    }
2150
2151    #[trace_parser]
2152    fn verilog_attr(&mut self) -> Result<(Loc<Identifier>, Option<Loc<String>>)> {
2153        let key = self.identifier()?;
2154        let value = if self.peek_and_eat(&TokenKind::Assignment)?.is_some() {
2155            let token = self.eat_cond(TokenKind::is_string, "string")?;
2156            match &token.kind {
2157                TokenKind::String(val) => Some(val.clone().at_loc(&token.loc())),
2158                _ => unreachable!(),
2159            }
2160        } else {
2161            None
2162        };
2163        Ok((key, value))
2164    }
2165
2166    #[trace_parser]
2167    pub fn attributes(&mut self) -> Result<AttributeList> {
2168        // peek_for!(self, &TokenKind::Hash)
2169        let mut result = AttributeList(vec![]);
2170        loop {
2171            if let Some(start) = self.peek_and_eat(&TokenKind::Hash)? {
2172                let (inner, loc) = self.surrounded(
2173                    &TokenKind::OpenBracket,
2174                    Self::attribute_inner,
2175                    &TokenKind::CloseBracket,
2176                )?;
2177
2178                result.0.push(inner.between(self.file_id, &start, &loc));
2179            } else if self.peek_cond(
2180                |tk| matches!(tk, TokenKind::OutsideDocumentation(_)),
2181                "Outside doc-comment",
2182            )? {
2183                let token = self.eat_unconditional()?;
2184                let TokenKind::OutsideDocumentation(doc) = token.kind else {
2185                    unreachable!("eat_cond should have checked this");
2186                };
2187                result
2188                    .0
2189                    .push(Attribute::Documentation { content: doc }.at(token.file_id, &token.span));
2190            } else {
2191                break;
2192            }
2193        }
2194        Ok(result)
2195    }
2196
2197    #[trace_parser]
2198    #[tracing::instrument(skip(self))]
2199    pub fn module_body(&mut self) -> Result<ModuleBody> {
2200        let mut documentation = vec![];
2201        while self.peek_cond(
2202            |tk| matches!(tk, TokenKind::InsideDocumentation(_)),
2203            "Inside doc-comment",
2204        )? {
2205            let token = self.eat_unconditional()?;
2206            let TokenKind::InsideDocumentation(doc) = token.kind else {
2207                unreachable!("eat_cond should have checked this");
2208            };
2209            documentation.push(doc);
2210        }
2211
2212        let members = self.keyword_peeking_parser_seq(
2213            vec![
2214                Box::new(items::UnitParser {}.map(|inner| Ok(Item::Unit(inner)))),
2215                Box::new(items::TraitDefParser {}.map(|inner| Ok(Item::TraitDef(inner)))),
2216                Box::new(items::ImplBlockParser {}.map(|inner| Ok(Item::ImplBlock(inner)))),
2217                Box::new(items::StructParser {}.map(|inner| Ok(Item::Type(inner)))),
2218                Box::new(items::EnumParser {}.map(|inner| Ok(Item::Type(inner)))),
2219                Box::new(items::ModuleParser {}),
2220                Box::new(items::UseParser {}.map(|inner| Ok(Item::Use(inner)))),
2221            ],
2222            true,
2223            vec![],
2224        )?;
2225        Ok(ModuleBody {
2226            members,
2227            documentation,
2228        })
2229    }
2230
2231    /// A module body which is not part of a `mod`. Errors if there is anything
2232    /// but an item found after the last item
2233    #[trace_parser]
2234    #[tracing::instrument(skip(self))]
2235    pub fn top_level_module_body(&mut self) -> Result<Loc<ModuleBody>> {
2236        let start_token = self.peek()?;
2237        let result = (|| {
2238            let result = self.module_body()?;
2239            let end_token = self.peek()?;
2240
2241            Ok(result.between(self.file_id, &start_token, &end_token))
2242        })();
2243
2244        if !self.peek_kind(&TokenKind::Eof)? {
2245            let got = self.peek()?;
2246            Diagnostic::error(
2247                got.loc(),
2248                format!("expected item, got `{}`", got.kind.as_str()),
2249            )
2250            .primary_label("expected item")
2251            .handle_in(&mut self.diags);
2252        }
2253
2254        match result {
2255            Ok(result) => Ok(result),
2256            e @ Err(_) => {
2257                e.handle_in(&mut self.diags);
2258
2259                Ok(ModuleBody {
2260                    members: vec![],
2261                    documentation: vec![],
2262                }
2263                .between(self.file_id, &start_token, &self.peek()?))
2264            }
2265        }
2266    }
2267}
2268
2269// Helper functions for combining parsers
2270impl<'a> Parser<'a> {
2271    #[tracing::instrument(skip_all, fields(parsers = parsers.len()))]
2272    fn first_successful<T>(
2273        &mut self,
2274        parsers: Vec<&dyn Fn(&mut Self) -> Result<Option<T>>>,
2275    ) -> Result<Option<T>> {
2276        for parser in parsers {
2277            match parser(self) {
2278                Ok(Some(val)) => {
2279                    event!(Level::INFO, "Parser matched");
2280                    return Ok(Some(val));
2281                }
2282                Ok(None) => continue,
2283                Err(e) => return Err(e),
2284            }
2285        }
2286        event!(Level::INFO, "No parser matched");
2287        Ok(None)
2288    }
2289
2290    /// Attempts to parse an inner structure surrounded by two tokens, like `( x )`.
2291    ///
2292    /// If the `start` token is not found, an error is produced.
2293    ///
2294    /// If the end token is not found, return a mismatch error
2295    #[tracing::instrument(level = "debug", skip(self, inner))]
2296    fn surrounded<T>(
2297        &mut self,
2298        start: &TokenKind,
2299        mut inner: impl FnMut(&mut Self) -> Result<T>,
2300        end_kind: &TokenKind,
2301    ) -> Result<(T, Loc<()>)> {
2302        let opener = self.eat(start)?;
2303        let result = inner(self)?;
2304        // FIXME: Better error handling here. We are throwing away potential EOFs
2305        let end = if let Some(end) = self.peek_and_eat(end_kind)? {
2306            end
2307        } else {
2308            let got = self.eat_unconditional()?;
2309            return Err(Diagnostic::error(
2310                got.loc(),
2311                format!(
2312                    "expected closing `{}`, got `{}`",
2313                    end_kind.as_str(),
2314                    got.kind.as_str()
2315                ),
2316            )
2317            .primary_label(format!("expected `{}`", end_kind.as_str()))
2318            .secondary_label(
2319                opener.loc(),
2320                format!("...to close this `{}`", start.as_str()),
2321            ));
2322        };
2323
2324        Ok((
2325            result,
2326            Loc::new((), lspan(opener.span).merge(lspan(end.span)), self.file_id),
2327        ))
2328    }
2329
2330    pub fn comma_separated<T>(
2331        &mut self,
2332        inner: impl Fn(&mut Self) -> Result<T>,
2333        // This end marker is used for allowing trailing commas. It should
2334        // be whatever ends the collection that is searched. I.e. (a,b,c,) should have
2335        // `)`, and {} should have `}`
2336        end_marker: &TokenKind,
2337    ) -> CommaSeparatedResult<Vec<T>> {
2338        self.token_separated(inner, &TokenKind::Comma, vec![end_marker.clone()])
2339    }
2340
2341    // NOTE: This cannot currently use #[trace_parser] as it returns an error which is not
2342    // convertible into `Error`. If we end up with more functions like this, that
2343    // macro should probably be made smarter
2344    #[tracing::instrument(level = "debug", skip(self, inner))]
2345    pub fn token_separated<T>(
2346        &mut self,
2347        inner: impl Fn(&mut Self) -> Result<T>,
2348        separator: &TokenKind,
2349        // This end marker is used for allowing trailing commas. It should
2350        // be whatever ends the collection that is searched. I.e. (a,b,c,) should have
2351        // `)`, and {} should have `}`
2352        end_markers: Vec<TokenKind>,
2353    ) -> CommaSeparatedResult<Vec<T>> {
2354        self.parse_stack
2355            .push(ParseStackEntry::Enter("comma_separated".to_string()));
2356        let ret = || -> CommaSeparatedResult<Vec<T>> {
2357            let mut result = vec![];
2358            loop {
2359                // The list might be empty
2360                if end_markers
2361                    .iter()
2362                    .map(|m| self.peek_kind(m))
2363                    .collect::<Result<Vec<_>>>()?
2364                    .into_iter()
2365                    .any(|x| x)
2366                {
2367                    break;
2368                }
2369                result.push(inner(self)?);
2370
2371                // Now we expect to either find a comma, in which case we resume the
2372                // search, or an end marker, in which case we abort
2373                if end_markers
2374                    .iter()
2375                    .map(|m| self.peek_kind(m))
2376                    .collect::<Result<Vec<_>>>()?
2377                    .into_iter()
2378                    .any(|x| x)
2379                {
2380                    break;
2381                } else if self.peek_kind(separator)? {
2382                    self.eat_unconditional()?;
2383                } else {
2384                    return Err(TokenSeparatedError::UnexpectedToken {
2385                        got: self.peek()?,
2386                        separator: separator.clone(),
2387                        end_tokens: end_markers,
2388                    });
2389                }
2390            }
2391            Ok(result)
2392        }();
2393        if let Err(e) = &ret {
2394            self.parse_stack
2395                .push(ParseStackEntry::ExitWithDiagnostic(e.clone().no_context()));
2396        } else {
2397            self.parse_stack.push(ParseStackEntry::Exit);
2398        }
2399
2400        ret
2401    }
2402
2403    fn keyword_peeking_parser_seq<T>(
2404        &mut self,
2405        parsers: Vec<Box<dyn KeywordPeekingParser<T>>>,
2406        support_attributes: bool,
2407        additional_continuations: Vec<fn(&TokenKind) -> bool>,
2408    ) -> Result<Vec<T>> {
2409        let mut result = vec![];
2410        let continuations = parsers
2411            .iter()
2412            .map(|p| p.is_leading_token())
2413            .chain(additional_continuations.iter().cloned())
2414            .collect::<Vec<_>>();
2415        loop {
2416            let inner = self._keyword_peeking_parser_inner(
2417                parsers.as_slice(),
2418                support_attributes,
2419                continuations.as_slice(),
2420            );
2421
2422            match inner {
2423                RecoveryResult::Ok(Some(stmt)) => result.push(stmt),
2424                RecoveryResult::Ok(None) => break,
2425                RecoveryResult::Recovered => continue,
2426            }
2427        }
2428        Ok(result)
2429    }
2430
2431    /// Works like `keyword_peeking_parser_seq` but runs the `other` function if none of the keyword parsers matched.
2432    ///
2433    /// If the `other` function returns a value, it is added to the result and the loop continues.
2434    /// If the `other` function returns `None`, the loop ends.
2435    fn keyword_peeking_parser_or_else_seq<T, F>(
2436        &mut self,
2437        parsers: Vec<Box<dyn KeywordPeekingParser<T>>>,
2438        support_attributes: bool,
2439        additional_continuations: Vec<fn(&TokenKind) -> bool>,
2440        mut other: F,
2441    ) -> Result<Vec<T>>
2442    where
2443        F: FnMut(&mut Self) -> Result<Option<T>>,
2444    {
2445        let mut result = vec![];
2446        let continuations = parsers
2447            .iter()
2448            .map(|p| p.is_leading_token())
2449            .chain(additional_continuations)
2450            .collect::<Vec<_>>();
2451        loop {
2452            let inner = self._keyword_peeking_parser_inner(
2453                parsers.as_slice(),
2454                support_attributes,
2455                continuations.as_slice(),
2456            );
2457
2458            match inner {
2459                RecoveryResult::Ok(Some(stmt)) => result.push(stmt),
2460                RecoveryResult::Ok(None) => {
2461                    if let Some(other_res) = (other)(self)? {
2462                        result.push(other_res);
2463                    } else {
2464                        break;
2465                    }
2466                }
2467                RecoveryResult::Recovered => continue,
2468            }
2469        }
2470        Ok(result)
2471    }
2472
2473    fn _keyword_peeking_parser_inner<T>(
2474        &mut self,
2475        parsers: &[Box<dyn KeywordPeekingParser<T>>],
2476        support_attributes: bool,
2477        continuations: &[fn(&TokenKind) -> bool],
2478    ) -> RecoveryResult<Option<T>> {
2479        self.with_recovery(
2480            |s| {
2481                let attributes = if support_attributes {
2482                    s.attributes()?
2483                } else {
2484                    AttributeList::empty()
2485                };
2486
2487                let visibility = s.visibility()?;
2488
2489                let next = s.peek()?;
2490                let mut result = None;
2491                for parser in parsers {
2492                    if parser.is_leading_token()(&next.kind) {
2493                        result = Some(parser.parse(s, &attributes, &visibility)?)
2494                    }
2495                }
2496                Ok(result)
2497            },
2498            Vec::from(continuations),
2499        )
2500    }
2501
2502    pub fn with_recovery<T>(
2503        &mut self,
2504        inner: impl Fn(&mut Self) -> Result<T>,
2505        continuations: Vec<fn(&TokenKind) -> bool>,
2506    ) -> RecoveryResult<T> {
2507        let new_continuations = continuations.len();
2508        self.recovering_tokens.extend(continuations);
2509        let result = match inner(self) {
2510            Ok(result) => RecoveryResult::Ok(result),
2511            Err(e) => {
2512                self.diags.errors.push(e);
2513
2514                // Once we error, consume tokens until we find a token in the
2515                // current continuation set.
2516                while let Ok(tok) = self.peek() {
2517                    if self
2518                        .recovering_tokens
2519                        .iter()
2520                        .rev()
2521                        .any(|peeker| peeker(&tok.kind))
2522                    {
2523                        break;
2524                    }
2525                    // Safe unwrap, we already peeked
2526                    self.eat_unconditional().unwrap();
2527                }
2528
2529                RecoveryResult::Recovered
2530            }
2531        };
2532        // Pop the newly added continuations
2533        let _ = self
2534            .recovering_tokens
2535            .split_off(self.recovering_tokens.len() - new_continuations);
2536        result
2537    }
2538}
2539
2540// Helper functions for advancing the token stream
2541impl<'a> Parser<'a> {
2542    fn eat(&mut self, expected: &TokenKind) -> Result<Token> {
2543        self.parse_stack
2544            .push(ParseStackEntry::EatingExpected(expected.clone()));
2545        // Calling keep and eat in order to correctly handle >> as > > if desired
2546        let next = self.eat_unconditional()?;
2547        if &next.kind == expected {
2548            Ok(next)
2549        } else if expected == &TokenKind::Gt && next.kind == TokenKind::RightShift {
2550            self.peeked = Some(Token {
2551                kind: TokenKind::Gt,
2552                span: next.span.end..next.span.end,
2553                file_id: next.file_id,
2554            });
2555            Ok(Token {
2556                kind: TokenKind::Gt,
2557                span: next.span.start..next.span.start,
2558                file_id: next.file_id,
2559            })
2560        } else if expected == &TokenKind::Gt && next.kind == TokenKind::ArithmeticRightShift {
2561            self.peeked = Some(Token {
2562                kind: TokenKind::RightShift,
2563                span: next.span.start + 1..next.span.end,
2564                file_id: next.file_id,
2565            });
2566            Ok(Token {
2567                kind: TokenKind::Gt,
2568                span: next.span.start..next.span.start,
2569                file_id: next.file_id,
2570            })
2571        } else {
2572            Err(Diagnostic::from(UnexpectedToken {
2573                got: next,
2574                expected: vec![expected.as_str()],
2575            }))
2576        }
2577    }
2578
2579    fn eat_cond(
2580        &mut self,
2581        condition: impl Fn(&TokenKind) -> bool,
2582        expected_description: &'static str,
2583    ) -> Result<Token> {
2584        // Check if we already have a peeked token
2585        let next = self.eat_unconditional()?;
2586
2587        // Make sure we ate the correct token
2588        if !condition(&next.kind) {
2589            Err(Diagnostic::from(UnexpectedToken {
2590                got: next,
2591                expected: vec![expected_description],
2592            }))
2593        } else {
2594            Ok(next)
2595        }
2596    }
2597
2598    fn eat_unconditional(&mut self) -> Result<Token> {
2599        let food = self
2600            .peeked
2601            .take()
2602            .map(Ok)
2603            .unwrap_or_else(|| self.next_token())?;
2604
2605        self.parse_stack.push(ParseStackEntry::Ate(food.clone()));
2606        self.last_token = Some(food.clone());
2607        Ok(food)
2608    }
2609
2610    /// Peeks the next token. If it is the specified kind, returns that token, otherwise
2611    /// returns None.
2612    ///
2613    /// If kind is > and the peeking is also done for >>, which if found, is split
2614    /// into > which is returned, and > which populates the peek buffer
2615    fn peek_and_eat(&mut self, kind: &TokenKind) -> Result<Option<Token>> {
2616        // peek_cond_no_tracing because peek_kind handles >> -> > > transformation
2617        // which we don't want here
2618        if self.peek_kind(kind)? {
2619            Ok(Some(self.eat(kind)?))
2620        } else {
2621            Ok(None)
2622        }
2623    }
2624
2625    pub fn peek(&mut self) -> Result<Token> {
2626        if let Some(peeked) = self.peeked.clone() {
2627            Ok(peeked)
2628        } else {
2629            let result = match self.next_token() {
2630                Ok(token) => token,
2631                Err(e) => return Err(e),
2632            };
2633            self.peeked = Some(result.clone());
2634
2635            Ok(result)
2636        }
2637    }
2638
2639    fn peek_kind(&mut self, expected: &TokenKind) -> Result<bool> {
2640        let mut result = self.peek_cond_no_tracing(|kind| kind == expected)?;
2641        if expected == &TokenKind::Gt {
2642            result |= self.peek_cond_no_tracing(|kind| kind == &TokenKind::RightShift)?
2643                | self.peek_cond_no_tracing(|kind| kind == &TokenKind::ArithmeticRightShift)?
2644        }
2645        self.parse_stack
2646            .push(ParseStackEntry::PeekingFor(expected.clone(), result));
2647        Ok(result)
2648    }
2649
2650    /// Peek the next token, returning true if the result satisfies the condition.
2651    ///
2652    /// If we reached EOF and the peek returns None, returns false
2653    fn peek_cond(&mut self, cond: impl Fn(&TokenKind) -> bool, msg: &str) -> Result<bool> {
2654        let result = self.peek_cond_no_tracing(cond)?;
2655        self.parse_stack.push(ParseStackEntry::PeekingWithCondition(
2656            msg.to_string(),
2657            result,
2658        ));
2659        Ok(result)
2660    }
2661
2662    fn peek_cond_no_tracing(&mut self, cond: impl Fn(&TokenKind) -> bool) -> Result<bool> {
2663        self.peek().map(|token| cond(&token.kind))
2664    }
2665
2666    fn next_token(&mut self) -> Result<Token> {
2667        self.next_token_helper(0)
2668    }
2669
2670    fn next_token_helper(&mut self, block_comment_depth: usize) -> Result<Token> {
2671        let lex_dot_next = {
2672            let mut break_value: Option<std::result::Result<_, _>> = None;
2673            while let Some(next) = self.lex.next() {
2674                if matches!(next, Ok(TokenKind::Comment)) {
2675                    self.comments.push(Comment::Line(Token {
2676                        kind: TokenKind::Comment,
2677                        span: self.lex.span(),
2678                        file_id: self.file_id,
2679                    }));
2680                } else {
2681                    break_value = Some(next);
2682                    break;
2683                }
2684            }
2685            break_value
2686        };
2687
2688        let out = match lex_dot_next {
2689            Some(Ok(k)) => Ok(Token::new(k, &self.lex, self.file_id)),
2690            Some(Err(_)) => Err(Diagnostic::error(
2691                Loc::new((), lspan(self.lex.span()), self.file_id),
2692                "Lexer error, unexpected symbol",
2693            )),
2694            None => Ok(match &self.last_token {
2695                Some(last) => Token {
2696                    kind: TokenKind::Eof,
2697                    span: last.span.end..last.span.end,
2698                    file_id: last.file_id,
2699                },
2700                None => Token {
2701                    kind: TokenKind::Eof,
2702                    span: logos::Span { start: 0, end: 0 },
2703                    file_id: self.file_id,
2704                },
2705            }),
2706        }?;
2707
2708        match out.kind {
2709            TokenKind::BlockCommentStart => loop {
2710                let next = match self.next_token_helper(block_comment_depth + 1) {
2711                    Ok(next) => next,
2712                    // We don't actually care about lexer errors inside block comments,
2713                    // so let's just continue.
2714                    Err(_) => continue,
2715                };
2716                match next.kind {
2717                    TokenKind::BlockCommentEnd => {
2718                        if block_comment_depth == 0 {
2719                            self.comments.push(Comment::Block(out, next));
2720                        }
2721                        break self.next_token_helper(block_comment_depth);
2722                    }
2723                    TokenKind::Eof => {
2724                        break Err(Diagnostic::error(next, "Unterminated block comment")
2725                            .primary_label("Expected */")
2726                            .secondary_label(out, "to close this block comment"))
2727                    }
2728                    _ => {}
2729                }
2730            },
2731            _ => Ok(out),
2732        }
2733    }
2734}
2735
2736impl<'a> Parser<'a> {
2737    fn set_item_context(&mut self, context: Loc<UnitKind>) -> Result<()> {
2738        if let Some(prev) = &self.unit_context {
2739            Err(Diagnostic::bug(
2740                context.loc(),
2741                "overwriting previously uncleared item context",
2742            )
2743            .primary_label("new context set because of this")
2744            .secondary_label(prev.loc(), "previous context set here"))
2745        } else {
2746            self.unit_context = Some(context);
2747            Ok(())
2748        }
2749    }
2750
2751    fn clear_item_context(&mut self) {
2752        self.unit_context = None
2753    }
2754
2755    #[cfg(test)]
2756    fn set_parsing_entity(&mut self) {
2757        self.set_item_context(UnitKind::Entity.nowhere()).unwrap()
2758    }
2759}
2760
2761trait KeywordPeekingParser<T> {
2762    fn is_leading_token(&self) -> fn(&TokenKind) -> bool;
2763    fn parse(
2764        &self,
2765        parser: &mut Parser,
2766        attributes: &AttributeList,
2767        visibility: &Loc<Visibility>,
2768    ) -> Result<T>;
2769}
2770
2771trait SizedKeywordPeekingParser<T>: Sized + KeywordPeekingParser<T> {
2772    fn map<F, O>(self, mapper: F) -> MappingParser<Self, F, T, O>
2773    where
2774        F: Fn(T) -> Result<O>,
2775    {
2776        MappingParser {
2777            inner: Box::new(self),
2778            mapper: Box::new(mapper),
2779            _phantoms: Default::default(),
2780        }
2781    }
2782
2783    fn then<F>(self, then: F) -> ThenParser<Self, F, T>
2784    where
2785        F: Fn(T, &mut Parser) -> Result<T>,
2786    {
2787        ThenParser {
2788            inner: Box::new(self),
2789            then: Box::new(then),
2790            _phantoms: Default::default(),
2791        }
2792    }
2793}
2794impl<TOuter, TInner> SizedKeywordPeekingParser<TInner> for TOuter where
2795    TOuter: KeywordPeekingParser<TInner> + Sized
2796{
2797}
2798
2799struct MappingParser<Inner, Mapper, I, T>
2800where
2801    Inner: SizedKeywordPeekingParser<I> + ?Sized,
2802    Mapper: Fn(I) -> Result<T>,
2803{
2804    inner: Box<Inner>,
2805    mapper: Box<Mapper>,
2806    _phantoms: (PhantomData<I>, PhantomData<T>),
2807}
2808
2809impl<Inner, Mapper, I, T> KeywordPeekingParser<T> for MappingParser<Inner, Mapper, I, T>
2810where
2811    Inner: SizedKeywordPeekingParser<I> + ?Sized,
2812    Mapper: Fn(I) -> Result<T>,
2813{
2814    fn is_leading_token(&self) -> fn(&TokenKind) -> bool {
2815        self.inner.is_leading_token()
2816    }
2817
2818    fn parse(
2819        &self,
2820        parser: &mut Parser,
2821        attributes: &AttributeList,
2822        visibility: &Loc<Visibility>,
2823    ) -> Result<T> {
2824        (self.mapper)(self.inner.parse(parser, attributes, visibility)?)
2825    }
2826}
2827
2828/// Allows running parsing tasks after successfully running an inner parser. Used
2829/// for example to require `;` after some statements with a helpful error message to
2830/// point out where the `;` is missing.
2831/// This cannot be used to change the type of `T`, which is intentional as that could
2832/// easily change the grammar from LL(1)
2833struct ThenParser<Inner, After, T>
2834where
2835    Inner: SizedKeywordPeekingParser<T> + ?Sized,
2836    After: Fn(T, &mut Parser) -> Result<T>,
2837{
2838    inner: Box<Inner>,
2839    then: Box<After>,
2840    _phantoms: PhantomData<T>,
2841}
2842
2843impl<Inner, After, T> KeywordPeekingParser<T> for ThenParser<Inner, After, T>
2844where
2845    Inner: SizedKeywordPeekingParser<T> + ?Sized,
2846    After: Fn(T, &mut Parser) -> Result<T>,
2847{
2848    fn is_leading_token(&self) -> fn(&TokenKind) -> bool {
2849        self.inner.is_leading_token()
2850    }
2851
2852    fn parse(
2853        &self,
2854        parser: &mut Parser,
2855        attributes: &AttributeList,
2856        visibility: &Loc<Visibility>,
2857    ) -> Result<T> {
2858        let inner = self.inner.parse(parser, attributes, visibility)?;
2859        (self.then)(inner, parser)
2860    }
2861}
2862
2863#[derive(Debug)]
2864pub enum RecoveryResult<T> {
2865    Ok(T),
2866    Recovered,
2867}
2868
2869#[local_impl]
2870impl<T> OptionExt for Option<T> {
2871    fn or_error(
2872        self,
2873        parser: &mut Parser,
2874        err: impl Fn(&mut Parser) -> Result<Diagnostic>,
2875    ) -> Result<T> {
2876        match self {
2877            Some(val) => Ok(val),
2878            None => Err(err(parser)?),
2879        }
2880    }
2881}
2882
2883#[derive(Clone)]
2884pub enum ParseStackEntry {
2885    Enter(String),
2886    Ate(Token),
2887    PeekingWithCondition(String, bool),
2888    PeekingFor(TokenKind, bool),
2889    EatingExpected(TokenKind),
2890    Exit,
2891    ExitWithDiagnostic(Diagnostic),
2892}
2893pub fn format_parse_stack(stack: &[ParseStackEntry]) -> String {
2894    let mut result = String::new();
2895    let mut indent_amount = 0;
2896
2897    for entry in stack {
2898        let mut next_indent_amount = indent_amount;
2899        let message = match entry {
2900            ParseStackEntry::Enter(function) => {
2901                next_indent_amount += 1;
2902                format!("{} `{}`", "trying".white(), function.blue())
2903            }
2904            ParseStackEntry::Ate(token) => format!(
2905                "{} '{}'",
2906                "Eating".bright_yellow(),
2907                token.kind.as_str().bright_purple()
2908            ),
2909            ParseStackEntry::PeekingFor(kind, success) => format!(
2910                "{} {} {}",
2911                "peeking for".white(),
2912                kind.as_str().bright_blue(),
2913                if *success {
2914                    "✓".green()
2915                } else {
2916                    "𐄂".red()
2917                }
2918            ),
2919            ParseStackEntry::PeekingWithCondition(needle, success) => format!(
2920                "{} {} {}",
2921                "peeking conditionally for ".white(),
2922                needle.bright_blue(),
2923                if *success {
2924                    "✓".green()
2925                } else {
2926                    "𐄂".red()
2927                }
2928            ),
2929            ParseStackEntry::EatingExpected(kind) => {
2930                format!(
2931                    "{} {}",
2932                    "eating expected".purple(),
2933                    kind.as_str().bright_purple()
2934                )
2935            }
2936            ParseStackEntry::Exit => {
2937                next_indent_amount -= 1;
2938                String::new()
2939            }
2940            ParseStackEntry::ExitWithDiagnostic(_diag) => {
2941                next_indent_amount -= 1;
2942                "Giving up".bright_red().to_string()
2943            }
2944        };
2945        if let ParseStackEntry::Exit = entry {
2946        } else {
2947            for _ in 0..indent_amount {
2948                result += "| ";
2949            }
2950            result += &message;
2951            result += "\n"
2952        }
2953        indent_amount = next_indent_amount;
2954    }
2955    result
2956}
2957
2958#[cfg(test)]
2959mod tests {
2960    use spade_ast as ast;
2961    use spade_ast::testutil::{ast_ident, ast_path};
2962    use spade_ast::*;
2963    use spade_common::num_ext::InfallibleToBigInt;
2964
2965    use crate::lexer::TokenKind;
2966    use crate::*;
2967
2968    use logos::Logos;
2969
2970    use spade_common::location_info::WithLocation;
2971
2972    #[macro_export]
2973    macro_rules! check_parse {
2974        ($string:expr , $method:ident$(($($arg:expr),*))?, $expected:expr$(, $run_on_parser:expr)?) => {
2975            let mut parser = Parser::new(TokenKind::lexer($string), 0);
2976
2977            $($run_on_parser(&mut parser);)?
2978
2979            let result = parser.$method($($($arg),*)?);
2980            // This is needed because type inference fails for some unexpected reason
2981            let expected: Result<_> = $expected;
2982
2983            if result != expected {
2984                println!("Parser state:\n{}", format_parse_stack(&parser.parse_stack));
2985                panic!(
2986                    "\n\n     {}: {:?}\n{}: {:?}",
2987                    "Got".red(),
2988                    result,
2989                    "Expected".green(),
2990                    expected
2991                );
2992            };
2993        };
2994    }
2995
2996    #[test]
2997    fn parsing_identifier_works() {
2998        check_parse!("abc123_", identifier, Ok(ast_ident("abc123_")));
2999    }
3000
3001    #[test]
3002    fn parsing_paths_works() {
3003        let expected = Path::from_strs(&["path", "to", "thing"]).nowhere();
3004        check_parse!("path::to::thing", path, Ok(expected));
3005    }
3006
3007    #[test]
3008    fn literals_are_expressions() {
3009        check_parse!(
3010            "123",
3011            expression,
3012            Ok(Expression::int_literal_signed(123).nowhere())
3013        );
3014    }
3015
3016    #[test]
3017    fn size_types_work() {
3018        let expected = TypeSpec::Named(
3019            ast_path("uint"),
3020            Some(vec![TypeExpression::Integer(10u32.to_bigint()).nowhere()].nowhere()),
3021        )
3022        .nowhere();
3023        check_parse!("uint<10>", type_spec, Ok(expected));
3024    }
3025
3026    #[test]
3027    fn nested_generics_work() {
3028        let code = "Option<int<5>>";
3029
3030        let expected = TypeSpec::Named(
3031            ast_path("Option"),
3032            Some(
3033                vec![TypeExpression::TypeSpec(Box::new(
3034                    TypeSpec::Named(
3035                        ast_path("int"),
3036                        Some(vec![TypeExpression::Integer(5u32.to_bigint()).nowhere()].nowhere()),
3037                    )
3038                    .nowhere(),
3039                ))
3040                .nowhere()]
3041                .nowhere(),
3042            ),
3043        )
3044        .nowhere();
3045
3046        check_parse!(code, type_spec, Ok(expected));
3047    }
3048
3049    #[test]
3050    fn module_body_parsing_works() {
3051        let code = include_str!("../parser_test_code/multiple_entities.sp");
3052
3053        let e1 = Unit {
3054            head: UnitHead {
3055                visibility: Visibility::Implicit.nowhere(),
3056                unsafe_token: None,
3057                extern_token: None,
3058                attributes: AttributeList::empty(),
3059                unit_kind: UnitKind::Entity.nowhere(),
3060                name: ast_ident("e1"),
3061                inputs: aparams![],
3062                output_type: None,
3063                type_params: None,
3064                where_clauses: vec![],
3065            },
3066            body: Some(
3067                Expression::Block(Box::new(Block {
3068                    statements: vec![],
3069                    result: Some(Expression::int_literal_signed(0).nowhere()),
3070                }))
3071                .nowhere(),
3072            ),
3073        }
3074        .nowhere();
3075
3076        let e2 = Unit {
3077            head: UnitHead {
3078                visibility: Visibility::Implicit.nowhere(),
3079                unsafe_token: None,
3080                extern_token: None,
3081                attributes: AttributeList::empty(),
3082                unit_kind: UnitKind::Entity.nowhere(),
3083                name: ast_ident("e2"),
3084                inputs: aparams![],
3085                output_type: None,
3086                type_params: None,
3087                where_clauses: vec![],
3088            },
3089            body: Some(
3090                Expression::Block(Box::new(Block {
3091                    statements: vec![],
3092                    result: Some(Expression::int_literal_signed(1).nowhere()),
3093                }))
3094                .nowhere(),
3095            ),
3096        }
3097        .nowhere();
3098
3099        let expected = ModuleBody {
3100            members: vec![Item::Unit(e1), Item::Unit(e2)],
3101            documentation: vec![],
3102        };
3103
3104        check_parse!(code, module_body, Ok(expected));
3105    }
3106
3107    #[test]
3108    fn dec_int_literals_work() {
3109        let code = "1";
3110        let expected = IntLiteral::unsized_(1).nowhere();
3111
3112        check_parse!(code, int_literal, Ok(Some(expected)));
3113    }
3114    #[test]
3115    fn dec_negative_int_literals_work() {
3116        let code = "-1";
3117        let expected = IntLiteral::unsized_(-1).nowhere();
3118
3119        check_parse!(code, int_literal, Ok(Some(expected)));
3120    }
3121    #[test]
3122    fn hex_int_literals_work() {
3123        let code = "0xff";
3124        let expected = IntLiteral::unsized_(255).nowhere();
3125
3126        check_parse!(code, int_literal, Ok(Some(expected)));
3127    }
3128    #[test]
3129    fn bin_int_literals_work() {
3130        let code = "0b101";
3131        let expected = IntLiteral::unsized_(5).nowhere();
3132
3133        check_parse!(code, int_literal, Ok(Some(expected)));
3134    }
3135
3136    #[test]
3137    fn type_spec_with_multiple_generics_works() {
3138        let code = "A<X, Y>";
3139
3140        let expected = TypeSpec::Named(
3141            ast_path("A"),
3142            Some(
3143                vec![
3144                    TypeExpression::TypeSpec(Box::new(
3145                        TypeSpec::Named(ast_path("X"), None).nowhere(),
3146                    ))
3147                    .nowhere(),
3148                    TypeExpression::TypeSpec(Box::new(
3149                        TypeSpec::Named(ast_path("Y"), None).nowhere(),
3150                    ))
3151                    .nowhere(),
3152                ]
3153                .nowhere(),
3154            ),
3155        )
3156        .nowhere();
3157
3158        check_parse!(code, type_spec, Ok(expected));
3159    }
3160
3161    #[test]
3162    fn entity_instantiation() {
3163        let code = "inst some_entity(x, y, z)";
3164
3165        let expected = Expression::Call {
3166            kind: CallKind::Entity(().nowhere()),
3167            callee: ast_path("some_entity"),
3168            args: ArgumentList::Positional(vec![
3169                Expression::Identifier(ast_path("x")).nowhere(),
3170                Expression::Identifier(ast_path("y")).nowhere(),
3171                Expression::Identifier(ast_path("z")).nowhere(),
3172            ])
3173            .nowhere(),
3174            turbofish: None,
3175        }
3176        .nowhere();
3177
3178        check_parse!(code, expression, Ok(expected), Parser::set_parsing_entity);
3179    }
3180
3181    #[test]
3182    fn named_args_work() {
3183        let code = "x: a";
3184
3185        let expected = NamedArgument::Full(
3186            ast_ident("x"),
3187            Expression::Identifier(ast_path("a")).nowhere(),
3188        )
3189        .nowhere();
3190
3191        check_parse!(code, named_argument, Ok(expected));
3192    }
3193
3194    #[test]
3195    fn named_capture_shorthand_works() {
3196        let code = "x";
3197
3198        let expected = NamedArgument::Short(ast_ident("x")).nowhere();
3199
3200        check_parse!(code, named_argument, Ok(expected));
3201    }
3202
3203    #[test]
3204    fn tuple_patterns_work() {
3205        let code = "(x, y)";
3206
3207        let expected = Pattern::Tuple(vec![Pattern::name("x"), Pattern::name("y")]).nowhere();
3208
3209        check_parse!(code, pattern, Ok(expected));
3210    }
3211
3212    #[test]
3213    fn integer_patterns_work() {
3214        let code = "1";
3215
3216        let expected = Pattern::integer(1).nowhere();
3217
3218        check_parse!(code, pattern, Ok(expected));
3219    }
3220
3221    #[test]
3222    fn hex_integer_patterns_work() {
3223        let code = "0xff";
3224
3225        let expected = Pattern::integer(255).nowhere();
3226
3227        check_parse!(code, pattern, Ok(expected));
3228    }
3229
3230    #[test]
3231    fn bin_integer_patterns_work() {
3232        let code = "0b101";
3233
3234        let expected = Pattern::integer(5).nowhere();
3235
3236        check_parse!(code, pattern, Ok(expected));
3237    }
3238
3239    #[test]
3240    fn bool_patterns_work() {
3241        let code = "true";
3242
3243        let expected = Pattern::Bool(true).nowhere();
3244
3245        check_parse!(code, pattern, Ok(expected));
3246    }
3247
3248    #[test]
3249    fn positional_type_patterns_work() {
3250        let code = "SomeType(x, y)";
3251
3252        let expected = Pattern::Type(
3253            ast_path("SomeType"),
3254            ArgumentPattern::Positional(vec![Pattern::name("x"), Pattern::name("y")]).nowhere(),
3255        )
3256        .nowhere();
3257
3258        check_parse!(code, pattern, Ok(expected));
3259    }
3260
3261    #[test]
3262    fn named_type_patterns_work() {
3263        let code = "SomeType$(x: a, y)";
3264
3265        let expected = Pattern::Type(
3266            ast_path("SomeType"),
3267            ArgumentPattern::Named(vec![
3268                (ast_ident("x"), Some(Pattern::name("a"))),
3269                (ast_ident("y"), None),
3270            ])
3271            .nowhere(),
3272        )
3273        .nowhere();
3274
3275        check_parse!(code, pattern, Ok(expected));
3276    }
3277
3278    #[test]
3279    fn modules_can_be_empty() {
3280        let code = r#"mod X {}"#;
3281
3282        let expected = ModuleBody {
3283            members: vec![Item::Module(
3284                Module {
3285                    visibility: Visibility::Implicit.nowhere(),
3286                    name: ast_ident("X"),
3287                    body: ModuleBody {
3288                        members: vec![],
3289                        documentation: vec![],
3290                    }
3291                    .nowhere(),
3292                }
3293                .nowhere(),
3294            )],
3295            documentation: vec![],
3296        };
3297
3298        check_parse!(code, module_body, Ok(expected));
3299    }
3300
3301    #[test]
3302    fn modules_containing_items_work() {
3303        let code = r#"mod X {mod Y {}}"#;
3304
3305        let expected = ModuleBody {
3306            members: vec![Item::Module(
3307                Module {
3308                    visibility: Visibility::Implicit.nowhere(),
3309                    name: ast_ident("X"),
3310                    body: ModuleBody {
3311                        members: vec![Item::Module(
3312                            Module {
3313                                visibility: Visibility::Implicit.nowhere(),
3314                                name: ast_ident("Y"),
3315                                body: ModuleBody {
3316                                    members: vec![],
3317                                    documentation: vec![],
3318                                }
3319                                .nowhere(),
3320                            }
3321                            .nowhere(),
3322                        )],
3323                        documentation: vec![],
3324                    }
3325                    .nowhere(),
3326                }
3327                .nowhere(),
3328            )],
3329            documentation: vec![],
3330        };
3331
3332        check_parse!(code, module_body, Ok(expected));
3333    }
3334}