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