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