spade_parser/
lib.rs

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