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