Skip to main content

spade_parser/
lib.rs

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