1use crate::keywords::RESERVED_KEYWORDS;
2use crate::{ParseResult, Parser, ParserConsumed, Peeker};
3
4use sway_ast::keywords::{Keyword, PanicToken};
5use sway_ast::Intrinsic;
6use sway_error::parser_error::ParseErrorKind;
7use sway_types::{ast::Delimiter, Ident, Spanned};
8
9pub trait Parse {
10 const FALLBACK_ERROR: ParseErrorKind = ParseErrorKind::InvalidItem;
11
12 fn parse(parser: &mut Parser) -> ParseResult<Self>
13 where
14 Self: Sized;
15
16 fn error(
17 #[allow(clippy::boxed_local)] _spans: Box<[sway_types::Span]>,
18 _error: sway_error::handler::ErrorEmitted,
19 ) -> Option<Self>
20 where
21 Self: Sized,
22 {
23 None
24 }
25}
26
27pub trait Peek {
28 fn peek(peeker: Peeker<'_>) -> Option<Self>
29 where
30 Self: Sized;
31}
32
33pub trait ParseToEnd {
34 fn parse_to_end<'a>(parser: Parser<'a, '_>) -> ParseResult<(Self, ParserConsumed<'a>)>
35 where
36 Self: Sized;
37}
38
39impl<T> Parse for Box<T>
40where
41 T: Parse,
42{
43 fn parse(parser: &mut Parser) -> ParseResult<Box<T>> {
44 let value = parser.parse()?;
45 Ok(Box::new(value))
46 }
47}
48
49macro_rules! impl_tuple (
50 ($($name:ident,)*) => {
51 impl<$($name,)*> Parse for ($($name,)*)
52 where
53 $($name: Parse,)*
54 {
55 #[allow(unused)]
56 fn parse(parser: &mut Parser) -> ParseResult<($($name,)*)> {
57 $(
58 #[allow(non_snake_case)]
59 let $name = parser.parse()?;
60 )*
61 Ok(($($name,)*))
62 }
63 }
64
65 impl<$($name,)*> Peek for ($($name,)*)
66 where
67 $($name: Peek,)*
68 {
69 fn peek(peeker: Peeker<'_>) -> Option<Self> {
70 #![allow(unused_assignments, unused, non_snake_case)]
71
72 let mut tokens = peeker.token_trees;
73 $(
74 let ($name, fewer_tokens) = Peeker::with::<$name>(tokens)?;
75 tokens = fewer_tokens;
76
77 )*
78 Some(($($name,)*))
79 }
80 }
81 };
82);
83
84impl_tuple!();
85impl_tuple!(T0,);
86impl_tuple!(T0, T1,);
87impl_tuple!(T0, T1, T2,);
88impl_tuple!(T0, T1, T2, T3,);
89impl_tuple!(T0, T1, T2, T3, T4,);
90impl_tuple!(T0, T1, T2, T3, T4, T5,);
91impl_tuple!(T0, T1, T2, T3, T4, T5, T6,);
92impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7,);
93impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8,);
94impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9,);
95impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10,);
96impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,);
97
98impl<T> ParseToEnd for Vec<T>
99where
100 T: Parse,
101{
102 fn parse_to_end<'a, 'e>(
103 mut parser: Parser<'a, '_>,
104 ) -> ParseResult<(Vec<T>, ParserConsumed<'a>)> {
105 let mut ret = Vec::new();
106 loop {
107 if let Some(consumed) = parser.check_empty() {
108 return Ok((ret, consumed));
109 }
110
111 match parser.parse_with_recovery() {
112 Ok(value) => ret.push(value),
113 Err(r) => {
114 let (spans, error) =
115 r.recover_at_next_line_with_fallback_error(T::FALLBACK_ERROR);
116 if let Some(error) = T::error(spans, error) {
117 ret.push(error);
118 } else {
119 Err(error)?
120 }
121 }
122 }
123 }
124 }
125}
126
127impl Peek for Ident {
128 fn peek(peeker: Peeker<'_>) -> Option<Ident> {
129 peeker.peek_ident().ok().cloned()
130 }
131}
132
133impl Parse for Ident {
134 fn parse(parser: &mut Parser) -> ParseResult<Ident> {
135 match parser.take::<Ident>() {
136 Some(ident) => {
137 let ident_str = ident.as_str();
138
139 if parser.check_double_underscore
140 && (ident_str.starts_with("__") && Intrinsic::try_from_str(ident_str).is_none())
141 {
142 return Err(parser.emit_error_with_span(
143 ParseErrorKind::InvalidDoubleUnderscore,
144 ident.span(),
145 ));
146 }
147
148 if !ident.is_raw_ident()
149 && (RESERVED_KEYWORDS.contains(ident_str)
150 || (parser.experimental.error_type && ident_str == PanicToken::AS_STR))
151 {
152 return Err(parser.emit_error_with_span(
153 ParseErrorKind::ReservedKeywordIdentifier,
154 ident.span(),
155 ));
156 }
157
158 Ok(ident)
159 }
160 None => Err(parser.emit_error(ParseErrorKind::ExpectedIdent)),
161 }
162 }
163}
164
165impl Peek for Delimiter {
166 fn peek(peeker: Peeker<'_>) -> Option<Delimiter> {
167 peeker.peek_delimiter().ok()
168 }
169}