1use crate::{Lexer, PErr, PResult};
2use smallvec::SmallVec;
3use solar_ast::{
4 self as ast, AstPath, Box, DocComment, DocComments, PathSlice,
5 token::{Delimiter, Token, TokenKind},
6};
7use solar_data_structures::{BumpExt, fmt::or_list};
8use solar_interface::{
9 Ident, Result, Session, Span, Symbol,
10 diagnostics::DiagCtxt,
11 source_map::{FileName, SourceFile},
12};
13use std::{fmt, path::Path};
14
15mod expr;
16mod item;
17mod lit;
18mod stmt;
19mod ty;
20mod yul;
21
22#[doc = include_str!("../../doc-examples/parser.rs")]
30pub struct Parser<'sess, 'ast> {
32 pub sess: &'sess Session,
34 pub arena: &'ast ast::Arena,
36
37 pub token: Token,
39 pub prev_token: Token,
41 expected_tokens: Vec<ExpectedToken>,
43 last_unexpected_token_span: Option<Span>,
45 docs: Vec<DocComment>,
47
48 tokens: std::vec::IntoIter<Token>,
50
51 in_yul: bool,
55 in_contract: bool,
57}
58
59#[derive(Clone, Debug, PartialEq, Eq)]
60enum ExpectedToken {
61 Token(TokenKind),
62 Keyword(Symbol),
63 Lit,
64 StrLit,
65 Ident,
66 Path,
67 ElementaryType,
68}
69
70impl fmt::Display for ExpectedToken {
71 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72 f.write_str(match self {
73 Self::Token(t) => return write!(f, "`{t}`"),
74 Self::Keyword(kw) => return write!(f, "`{kw}`"),
75 Self::StrLit => "string literal",
76 Self::Lit => "literal",
77 Self::Ident => "identifier",
78 Self::Path => "path",
79 Self::ElementaryType => "elementary type name",
80 })
81 }
82}
83
84impl ExpectedToken {
85 fn to_string_many(tokens: &[Self]) -> String {
86 or_list(tokens).to_string()
87 }
88
89 fn eq_kind(&self, other: TokenKind) -> bool {
90 match *self {
91 Self::Token(kind) => kind == other,
92 _ => false,
93 }
94 }
95}
96
97#[derive(Debug)]
99struct SeqSep {
100 sep: Option<TokenKind>,
102 trailing_sep_allowed: bool,
104 trailing_sep_required: bool,
106}
107
108impl SeqSep {
109 fn trailing_enforced(t: TokenKind) -> Self {
110 Self { sep: Some(t), trailing_sep_required: true, trailing_sep_allowed: true }
111 }
112
113 #[allow(dead_code)]
114 fn trailing_allowed(t: TokenKind) -> Self {
115 Self { sep: Some(t), trailing_sep_required: false, trailing_sep_allowed: true }
116 }
117
118 fn trailing_disallowed(t: TokenKind) -> Self {
119 Self { sep: Some(t), trailing_sep_required: false, trailing_sep_allowed: false }
120 }
121
122 fn none() -> Self {
123 Self { sep: None, trailing_sep_required: false, trailing_sep_allowed: false }
124 }
125}
126
127impl<'sess, 'ast> Parser<'sess, 'ast> {
128 pub fn new(sess: &'sess Session, arena: &'ast ast::Arena, tokens: Vec<Token>) -> Self {
130 let mut parser = Self {
131 sess,
132 arena,
133 token: Token::DUMMY,
134 prev_token: Token::DUMMY,
135 expected_tokens: Vec::with_capacity(8),
136 last_unexpected_token_span: None,
137 docs: Vec::with_capacity(4),
138 tokens: tokens.into_iter(),
139 in_yul: false,
140 in_contract: false,
141 };
142 parser.bump();
143 parser
144 }
145
146 pub fn from_source_code(
148 sess: &'sess Session,
149 arena: &'ast ast::Arena,
150 filename: FileName,
151 src: impl Into<String>,
152 ) -> Result<Self> {
153 Self::from_lazy_source_code(sess, arena, filename, || Ok(src.into()))
154 }
155
156 pub fn from_file(sess: &'sess Session, arena: &'ast ast::Arena, path: &Path) -> Result<Self> {
160 Self::from_lazy_source_code(sess, arena, FileName::Real(path.to_path_buf()), || {
161 sess.source_map().file_loader().load_file(path)
162 })
163 }
164
165 pub fn from_lazy_source_code(
169 sess: &'sess Session,
170 arena: &'ast ast::Arena,
171 filename: FileName,
172 get_src: impl FnOnce() -> std::io::Result<String>,
173 ) -> Result<Self> {
174 let file = sess
175 .source_map()
176 .new_source_file_with(filename, get_src)
177 .map_err(|e| sess.dcx.err(e.to_string()).emit())?;
178 Ok(Self::from_source_file(sess, arena, &file))
179 }
180
181 pub fn from_source_file(
187 sess: &'sess Session,
188 arena: &'ast ast::Arena,
189 file: &SourceFile,
190 ) -> Self {
191 Self::from_lexer(arena, Lexer::from_source_file(sess, file))
192 }
193
194 pub fn from_lexer(arena: &'ast ast::Arena, lexer: Lexer<'sess, '_>) -> Self {
196 Self::new(lexer.sess, arena, lexer.into_tokens())
197 }
198
199 #[inline]
201 pub fn dcx(&self) -> &'sess DiagCtxt {
202 &self.sess.dcx
203 }
204
205 pub fn alloc<T>(&self, value: T) -> Box<'ast, T> {
207 self.arena.alloc(value)
208 }
209
210 pub fn alloc_path(&self, values: &[Ident]) -> AstPath<'ast> {
216 PathSlice::from_mut_slice(self.arena.alloc_slice_copy(values))
217 }
218
219 pub fn alloc_vec<T>(&self, values: Vec<T>) -> Box<'ast, [T]> {
221 self.arena.alloc_vec(values)
222 }
223
224 pub fn alloc_smallvec<A: smallvec::Array>(&self, values: SmallVec<A>) -> Box<'ast, [A::Item]> {
226 self.arena.alloc_smallvec(values)
227 }
228
229 #[inline]
231 #[track_caller]
232 pub fn unexpected<T>(&mut self) -> PResult<'sess, T> {
233 Err(self.unexpected_error())
234 }
235
236 #[inline]
238 #[track_caller]
239 pub fn unexpected_error(&mut self) -> PErr<'sess> {
240 #[cold]
241 #[inline(never)]
242 #[track_caller]
243 fn unexpected_ok(b: bool) -> ! {
244 unreachable!("`unexpected()` returned Ok({b})")
245 }
246 match self.expect_one_of(&[], &[]) {
247 Ok(b) => unexpected_ok(b),
248 Err(e) => e,
249 }
250 }
251
252 #[track_caller]
254 pub fn expect(&mut self, tok: TokenKind) -> PResult<'sess, bool > {
255 if self.expected_tokens.is_empty() {
256 if self.check_noexpect(tok) {
257 self.bump();
258 Ok(false)
259 } else {
260 Err(self.unexpected_error_with(tok))
261 }
262 } else {
263 self.expect_one_of(&[tok], &[])
264 }
265 }
266
267 #[track_caller]
269 fn unexpected_error_with(&mut self, t: TokenKind) -> PErr<'sess> {
270 let prev_span = if self.prev_token.span.is_dummy() {
271 self.token.span
274 } else if self.token.is_eof() {
275 self.prev_token.span
277 } else {
278 self.prev_token.span.shrink_to_hi()
279 };
280 let span = self.token.span;
281
282 let this_token_str = self.token.full_description();
283 let label_exp = format!("expected `{t}`");
284 let msg = format!("{label_exp}, found {this_token_str}");
285 let mut err = self.dcx().err(msg).span(span);
286 if !self.sess.source_map().is_multiline(prev_span.until(span)) {
287 err = err.span_label(span, label_exp);
290 } else {
291 err = err.span_label(prev_span, label_exp);
292 err = err.span_label(span, "unexpected token");
293 }
294 err
295 }
296
297 #[track_caller]
301 pub fn expect_one_of(
302 &mut self,
303 edible: &[TokenKind],
304 inedible: &[TokenKind],
305 ) -> PResult<'sess, bool > {
306 if edible.contains(&self.token.kind) {
307 self.bump();
308 Ok(false)
309 } else if inedible.contains(&self.token.kind) {
310 Ok(false)
312 } else if self.token.kind != TokenKind::Eof
313 && self.last_unexpected_token_span == Some(self.token.span)
314 {
315 panic!("called unexpected twice on the same token");
316 } else {
317 self.expected_one_of_not_found(edible, inedible)
318 }
319 }
320
321 #[track_caller]
322 fn expected_one_of_not_found(
323 &mut self,
324 edible: &[TokenKind],
325 inedible: &[TokenKind],
326 ) -> PResult<'sess, bool> {
327 let mut expected = edible
328 .iter()
329 .chain(inedible)
330 .cloned()
331 .map(ExpectedToken::Token)
332 .chain(self.expected_tokens.iter().cloned())
333 .filter(|token| {
334 fn is_ident_eq_keyword(found: TokenKind, expected: &ExpectedToken) -> bool {
337 if let TokenKind::Ident(current_sym) = found
338 && let ExpectedToken::Keyword(suggested_sym) = expected
339 {
340 return current_sym == *suggested_sym;
341 }
342 false
343 }
344
345 if !token.eq_kind(self.token.kind) {
346 let eq = is_ident_eq_keyword(self.token.kind, token);
347 if !eq {
354 if let ExpectedToken::Token(kind) = token
355 && *kind == self.token.kind
356 {
357 return false;
358 }
359 return true;
360 }
361 }
362 false
363 })
364 .collect::<Vec<_>>();
365 expected.sort_by_cached_key(ToString::to_string);
366 expected.dedup();
367
368 let expect = ExpectedToken::to_string_many(&expected);
369 let actual = self.token.full_description();
370 let (msg_exp, (mut label_span, label_exp)) = match expected.len() {
371 0 => (
372 format!("unexpected token: {actual}"),
373 (self.prev_token.span, "unexpected token after this".to_string()),
374 ),
375 1 => (
376 format!("expected {expect}, found {actual}"),
377 (self.prev_token.span.shrink_to_hi(), format!("expected {expect}")),
378 ),
379 len => {
380 let fmt = format!("expected one of {expect}, found {actual}");
381 let short_expect = if len > 6 { format!("{len} possible tokens") } else { expect };
382 let s = self.prev_token.span.shrink_to_hi();
383 (fmt, (s, format!("expected one of {short_expect}")))
384 }
385 };
386 if self.token.is_eof() {
387 label_span = self.prev_token.span;
389 };
390
391 self.last_unexpected_token_span = Some(self.token.span);
392 let mut err = self.dcx().err(msg_exp).span(self.token.span);
393
394 if self.prev_token.span.is_dummy()
395 || !self
396 .sess
397 .source_map()
398 .is_multiline(self.token.span.shrink_to_hi().until(label_span.shrink_to_lo()))
399 {
400 err = err.span_label(self.token.span, label_exp);
403 } else {
404 err = err.span_label(label_span, label_exp);
405 err = err.span_label(self.token.span, "unexpected token");
406 }
407
408 Err(err)
409 }
410
411 #[track_caller]
413 fn expect_semi(&mut self) -> PResult<'sess, ()> {
414 self.expect(TokenKind::Semi).map(drop)
415 }
416
417 #[inline]
422 #[must_use]
423 fn check(&mut self, tok: TokenKind) -> bool {
424 let is_present = self.check_noexpect(tok);
425 if !is_present {
426 self.expected_tokens.push(ExpectedToken::Token(tok));
427 }
428 is_present
429 }
430
431 #[inline]
432 #[must_use]
433 fn check_noexpect(&self, tok: TokenKind) -> bool {
434 self.token.kind == tok
435 }
436
437 #[must_use]
442 pub fn eat_noexpect(&mut self, tok: TokenKind) -> bool {
443 let is_present = self.check_noexpect(tok);
444 if is_present {
445 self.bump()
446 }
447 is_present
448 }
449
450 #[must_use]
452 pub fn eat(&mut self, tok: TokenKind) -> bool {
453 let is_present = self.check(tok);
454 if is_present {
455 self.bump()
456 }
457 is_present
458 }
459
460 #[must_use]
463 fn check_keyword(&mut self, kw: Symbol) -> bool {
464 self.expected_tokens.push(ExpectedToken::Keyword(kw));
465 self.token.is_keyword(kw)
466 }
467
468 #[must_use]
471 pub fn eat_keyword(&mut self, kw: Symbol) -> bool {
472 if self.check_keyword(kw) {
473 self.bump();
474 true
475 } else {
476 false
477 }
478 }
479
480 #[track_caller]
484 fn expect_keyword(&mut self, kw: Symbol) -> PResult<'sess, ()> {
485 if !self.eat_keyword(kw) { self.unexpected() } else { Ok(()) }
486 }
487
488 #[must_use]
489 fn check_ident(&mut self) -> bool {
490 self.check_or_expected(self.token.is_ident(), ExpectedToken::Ident)
491 }
492
493 #[must_use]
494 fn check_nr_ident(&mut self) -> bool {
495 self.check_or_expected(self.token.is_non_reserved_ident(self.in_yul), ExpectedToken::Ident)
496 }
497
498 #[must_use]
499 fn check_path(&mut self) -> bool {
500 self.check_or_expected(self.token.is_ident(), ExpectedToken::Path)
501 }
502
503 #[must_use]
504 fn check_lit(&mut self) -> bool {
505 self.check_or_expected(self.token.is_lit(), ExpectedToken::Lit)
506 }
507
508 #[must_use]
509 fn check_str_lit(&mut self) -> bool {
510 self.check_or_expected(self.token.is_str_lit(), ExpectedToken::StrLit)
511 }
512
513 #[must_use]
514 fn check_elementary_type(&mut self) -> bool {
515 self.check_or_expected(self.token.is_elementary_type(), ExpectedToken::ElementaryType)
516 }
517
518 #[must_use]
519 fn check_or_expected(&mut self, ok: bool, t: ExpectedToken) -> bool {
520 if !ok {
521 self.expected_tokens.push(t);
522 }
523 ok
524 }
525
526 #[track_caller]
530 #[inline]
531 fn parse_paren_comma_seq<T>(
532 &mut self,
533 allow_empty: bool,
534 f: impl FnMut(&mut Self) -> PResult<'sess, T>,
535 ) -> PResult<'sess, Box<'ast, [T]>> {
536 self.parse_delim_comma_seq(Delimiter::Parenthesis, allow_empty, f)
537 }
538
539 #[track_caller]
543 #[inline]
544 fn parse_delim_comma_seq<T>(
545 &mut self,
546 delim: Delimiter,
547 allow_empty: bool,
548 f: impl FnMut(&mut Self) -> PResult<'sess, T>,
549 ) -> PResult<'sess, Box<'ast, [T]>> {
550 self.parse_delim_seq(delim, SeqSep::trailing_disallowed(TokenKind::Comma), allow_empty, f)
551 }
552
553 #[track_caller]
556 #[inline]
557 fn parse_nodelim_comma_seq<T>(
558 &mut self,
559 stop: TokenKind,
560 allow_empty: bool,
561 f: impl FnMut(&mut Self) -> PResult<'sess, T>,
562 ) -> PResult<'sess, Box<'ast, [T]>> {
563 self.parse_seq_to_before_end(
564 stop,
565 SeqSep::trailing_disallowed(TokenKind::Comma),
566 allow_empty,
567 f,
568 )
569 .map(|(v, _recovered)| v)
570 }
571
572 #[track_caller]
576 #[inline]
577 fn parse_delim_seq<T>(
578 &mut self,
579 delim: Delimiter,
580 sep: SeqSep,
581 allow_empty: bool,
582 f: impl FnMut(&mut Self) -> PResult<'sess, T>,
583 ) -> PResult<'sess, Box<'ast, [T]>> {
584 self.parse_unspanned_seq(
585 TokenKind::OpenDelim(delim),
586 TokenKind::CloseDelim(delim),
587 sep,
588 allow_empty,
589 f,
590 )
591 }
592
593 #[track_caller]
597 #[inline]
598 fn parse_unspanned_seq<T>(
599 &mut self,
600 bra: TokenKind,
601 ket: TokenKind,
602 sep: SeqSep,
603 allow_empty: bool,
604 f: impl FnMut(&mut Self) -> PResult<'sess, T>,
605 ) -> PResult<'sess, Box<'ast, [T]>> {
606 self.expect(bra)?;
607 self.parse_seq_to_end(ket, sep, allow_empty, f)
608 }
609
610 #[track_caller]
614 #[inline]
615 fn parse_seq_to_end<T>(
616 &mut self,
617 ket: TokenKind,
618 sep: SeqSep,
619 allow_empty: bool,
620 f: impl FnMut(&mut Self) -> PResult<'sess, T>,
621 ) -> PResult<'sess, Box<'ast, [T]>> {
622 let (val, recovered) = self.parse_seq_to_before_end(ket, sep, allow_empty, f)?;
623 if !recovered {
624 self.expect(ket)?;
625 }
626 Ok(val)
627 }
628
629 #[track_caller]
633 #[inline]
634 fn parse_seq_to_before_end<T>(
635 &mut self,
636 ket: TokenKind,
637 sep: SeqSep,
638 allow_empty: bool,
639 f: impl FnMut(&mut Self) -> PResult<'sess, T>,
640 ) -> PResult<'sess, (Box<'ast, [T]>, bool )> {
641 self.parse_seq_to_before_tokens(&[ket], sep, allow_empty, f)
642 }
643
644 fn check_any(&mut self, kets: &[TokenKind]) -> bool {
646 kets.iter().any(|&k| self.check(k))
647 }
648
649 #[track_caller]
653 fn parse_seq_to_before_tokens<T>(
654 &mut self,
655 kets: &[TokenKind],
656 sep: SeqSep,
657 allow_empty: bool,
658 mut f: impl FnMut(&mut Self) -> PResult<'sess, T>,
659 ) -> PResult<'sess, (Box<'ast, [T]>, bool )> {
660 let mut first = true;
661 let mut recovered = false;
662 let mut trailing = false;
663 let mut v = SmallVec::<[T; 8]>::new();
664
665 if !allow_empty {
666 v.push(f(self)?);
667 first = false;
668 }
669
670 while !self.check_any(kets) {
671 if let TokenKind::CloseDelim(..) | TokenKind::Eof = self.token.kind {
672 break;
673 }
674
675 if let Some(sep_kind) = sep.sep {
676 if first {
677 first = false;
679 } else {
680 match self.expect(sep_kind) {
682 Ok(recovered_) => {
683 if recovered_ {
684 recovered = true;
685 break;
686 }
687 }
688 Err(e) => return Err(e),
689 }
690
691 if self.check_any(kets) {
692 trailing = true;
693 break;
694 }
695 }
696 }
697
698 v.push(f(self)?);
699 }
700
701 if let Some(sep_kind) = sep.sep {
702 let open_close_delim = first && allow_empty;
703 if !open_close_delim
704 && sep.trailing_sep_required
705 && !trailing
706 && let Err(e) = self.expect(sep_kind)
707 {
708 e.emit();
709 }
710 if !sep.trailing_sep_allowed && trailing {
711 let msg = format!("trailing `{sep_kind}` separator is not allowed");
712 self.dcx().err(msg).span(self.prev_token.span).emit();
713 }
714 }
715
716 Ok((self.alloc_smallvec(v), recovered))
717 }
718
719 pub fn bump(&mut self) {
721 let next = self.next_token();
722 if next.is_comment_or_doc() {
723 return self.bump_trivia(next);
724 }
725 self.inlined_bump_with(next);
726 }
727
728 pub fn bump_with(&mut self, next: Token) {
734 self.inlined_bump_with(next);
735 }
736
737 #[inline(always)]
739 fn inlined_bump_with(&mut self, next: Token) {
740 #[cfg(debug_assertions)]
741 if next.is_comment_or_doc() {
742 self.dcx().bug("`bump_with` should not be used with comments").span(next.span).emit();
743 }
744 self.prev_token = std::mem::replace(&mut self.token, next);
745 self.expected_tokens.clear();
746 self.docs.clear();
747 }
748
749 #[cold]
753 fn bump_trivia(&mut self, next: Token) {
754 self.docs.clear();
755
756 debug_assert!(next.is_comment_or_doc());
757 self.prev_token = std::mem::replace(&mut self.token, next);
758 while let Some((is_doc, doc)) = self.token.comment() {
759 if is_doc {
760 self.docs.push(doc);
761 }
762 self.token = self.next_token();
764 }
765
766 self.expected_tokens.clear();
767 }
768
769 #[inline(always)]
773 fn next_token(&mut self) -> Token {
774 self.tokens.next().unwrap_or(Token { kind: TokenKind::Eof, span: self.token.span })
775 }
776
777 #[inline]
782 pub fn look_ahead(&self, dist: usize) -> Token {
783 match dist {
785 0 => self.token,
786 1 => self.look_ahead_full(1),
787 2 => self.look_ahead_full(2),
788 dist => self.look_ahead_full(dist),
789 }
790 }
791
792 fn look_ahead_full(&self, dist: usize) -> Token {
793 self.tokens
794 .as_slice()
795 .iter()
796 .copied()
797 .filter(|t| !t.is_comment_or_doc())
798 .nth(dist - 1)
799 .unwrap_or(Token::EOF)
800 }
801
802 #[inline]
806 pub fn look_ahead_with<R>(&self, dist: usize, f: impl FnOnce(Token) -> R) -> R {
807 f(self.look_ahead(dist))
808 }
809
810 #[inline]
812 fn in_contract<R>(&mut self, f: impl FnOnce(&mut Self) -> R) -> R {
813 let old = std::mem::replace(&mut self.in_contract, true);
814 let res = f(self);
815 self.in_contract = old;
816 res
817 }
818
819 #[inline]
821 fn in_yul<R>(&mut self, f: impl FnOnce(&mut Self) -> R) -> R {
822 let old = std::mem::replace(&mut self.in_yul, true);
823 let res = f(self);
824 self.in_yul = old;
825 res
826 }
827}
828
829impl<'sess, 'ast> Parser<'sess, 'ast> {
831 #[track_caller]
833 pub fn parse_spanned<T>(
834 &mut self,
835 f: impl FnOnce(&mut Self) -> PResult<'sess, T>,
836 ) -> PResult<'sess, (Span, T)> {
837 let lo = self.token.span;
838 let res = f(self);
839 let span = lo.to(self.prev_token.span);
840 match res {
841 Ok(t) => Ok((span, t)),
842 Err(e) if e.span.is_dummy() => Err(e.span(span)),
843 Err(e) => Err(e),
844 }
845 }
846
847 #[inline]
849 pub fn parse_doc_comments(&mut self) -> DocComments<'ast> {
850 if !self.docs.is_empty() { self.parse_doc_comments_inner() } else { Default::default() }
851 }
852
853 #[cold]
854 fn parse_doc_comments_inner(&mut self) -> DocComments<'ast> {
855 let docs = self.arena.alloc_slice_copy(&self.docs);
856 self.docs.clear();
857 docs.into()
858 }
859
860 #[track_caller]
862 pub fn parse_path(&mut self) -> PResult<'sess, AstPath<'ast>> {
863 let first = self.parse_ident()?;
864 self.parse_path_with(first)
865 }
866
867 #[track_caller]
869 pub fn parse_path_with(&mut self, first: Ident) -> PResult<'sess, AstPath<'ast>> {
870 if self.in_yul {
871 self.parse_path_with_f(first, Self::parse_yul_path_ident)
872 } else {
873 self.parse_path_with_f(first, Self::parse_ident)
874 }
875 }
876
877 fn parse_yul_path_ident(&mut self) -> PResult<'sess, Ident> {
879 let ident = self.ident_or_err(true)?;
880 if !ident.is_yul_evm_builtin() && ident.is_reserved(true) {
881 self.expected_ident_found_err().emit();
882 }
883 self.bump();
884 Ok(ident)
885 }
886
887 #[track_caller]
889 pub fn parse_path_any(&mut self) -> PResult<'sess, AstPath<'ast>> {
890 let first = self.parse_ident_any()?;
891 self.parse_path_with_f(first, Self::parse_ident_any)
892 }
893
894 #[track_caller]
896 fn parse_path_with_f(
897 &mut self,
898 first: Ident,
899 mut f: impl FnMut(&mut Self) -> PResult<'sess, Ident>,
900 ) -> PResult<'sess, AstPath<'ast>> {
901 if !self.check_noexpect(TokenKind::Dot) {
902 return Ok(self.alloc_path(&[first]));
903 }
904
905 let mut path = SmallVec::<[_; 4]>::new();
906 path.push(first);
907 while self.eat(TokenKind::Dot) {
908 path.push(f(self)?);
909 }
910 Ok(self.alloc_path(&path))
911 }
912
913 #[track_caller]
915 pub fn parse_ident(&mut self) -> PResult<'sess, Ident> {
916 self.parse_ident_common(true)
917 }
918
919 #[track_caller]
921 pub fn parse_ident_any(&mut self) -> PResult<'sess, Ident> {
922 let ident = self.ident_or_err(true)?;
923 self.bump();
924 Ok(ident)
925 }
926
927 #[track_caller]
929 pub fn parse_ident_opt(&mut self) -> PResult<'sess, Option<Ident>> {
930 if self.check_ident() { self.parse_ident().map(Some) } else { Ok(None) }
931 }
932
933 #[track_caller]
934 fn parse_ident_common(&mut self, recover: bool) -> PResult<'sess, Ident> {
935 let ident = self.ident_or_err(recover)?;
936 if ident.is_reserved(self.in_yul) {
937 let err = self.expected_ident_found_err();
938 if recover {
939 err.emit();
940 } else {
941 return Err(err);
942 }
943 }
944 self.bump();
945 Ok(ident)
946 }
947
948 #[track_caller]
950 fn ident_or_err(&mut self, recover: bool) -> PResult<'sess, Ident> {
951 match self.token.ident() {
952 Some(ident) => Ok(ident),
953 None => self.expected_ident_found(recover),
954 }
955 }
956
957 #[track_caller]
958 fn expected_ident_found(&mut self, recover: bool) -> PResult<'sess, Ident> {
959 self.expected_ident_found_other(self.token, recover)
960 }
961
962 #[track_caller]
963 fn expected_ident_found_other(&mut self, token: Token, recover: bool) -> PResult<'sess, Ident> {
964 let msg = format!("expected identifier, found {}", token.full_description());
965 let span = token.span;
966 let mut err = self.dcx().err(msg).span(span);
967
968 let mut recovered_ident = None;
969
970 let suggest_remove_comma = token.kind == TokenKind::Comma && self.look_ahead(1).is_ident();
971 if suggest_remove_comma {
972 if recover {
973 self.bump();
974 recovered_ident = self.ident_or_err(false).ok();
975 }
976 err = err.span_help(span, "remove this comma");
977 }
978
979 if recover && let Some(ident) = recovered_ident {
980 err.emit();
981 return Ok(ident);
982 }
983 Err(err)
984 }
985
986 #[track_caller]
987 fn expected_ident_found_err(&mut self) -> PErr<'sess> {
988 self.expected_ident_found(false).unwrap_err()
989 }
990}