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#[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 TokenSource::Slice([]) => 0..0,
117 }
118 }
119}
120
121#[derive(Clone)]
124pub struct Parser<'a> {
125 lex: TokenSource<'a>,
126 peeked: Option<Token>,
127 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#[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
189impl<'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 #[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 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 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 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 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 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 Expression::ArrayShorthandLiteral(Box::new(first), Box::new(self.expression()?))
417 } else {
418 let _ = self.peek_and_eat(&TokenKind::Comma)?;
420
421 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 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 self.unit_context
618 .allows_inst(().at(self.file_id(), &start.span()))?;
619
620 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 #[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 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 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 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 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 #[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(), &, &mut_),
1213 "inv",
1214 ));
1215 }
1216
1217 let rest = self.type_expression()?;
1218 Ok(TypeSpec::CopyView(Box::new(rest.clone())).between(self.file_id(), &, &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(), &, &rest),
1224 ))
1225 .between(self.file_id(), &, &rest),
1226 ))
1227 .between(self.file_id(), &, &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 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 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 #[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(|val| val.map(Pattern::Integer)))
1394 },
1395 &|s| {
1396 Ok(s.bool_literal()?
1397 .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 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(), &_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 self.eat_cond(TokenKind::is_identifier, "Identifier")?;
1689 unreachable!();
1690 };
1691
1692 first_arg.0 = first_attrs;
1694 }
1695 if let Some(wire) = first_wire {
1696 let Some(first_arg) = args.first_mut() else {
1697 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 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 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 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 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 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 #[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 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 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 #[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
2768impl<'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 #[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 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 end_marker: &TokenKind,
2840 ) -> CommaSeparatedResult<Vec<T>> {
2841 self.token_separated(inner, &TokenKind::Comma, vec![end_marker.clone()])
2842 }
2843
2844 #[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 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 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 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 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 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 self.eat_unconditional().unwrap();
3004 }
3005
3006 RecoveryResult::Recovered
3007 }
3008 };
3009 let _ = self
3011 .recovering_tokens
3012 .split_off(self.recovering_tokens.len() - new_continuations);
3013 result
3014 }
3015}
3016
3017impl<'a> Parser<'a> {
3019 fn eat(&mut self, expected: &TokenKind) -> Result<Token> {
3020 self.parse_stack
3021 .push(ParseStackEntry::EatingExpected(expected.clone()));
3022 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 let next = self.eat_unconditional()?;
3066
3067 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 fn peek_and_eat(&mut self, kind: &TokenKind) -> Result<Option<Token>> {
3096 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 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 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
3308struct 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 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}