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