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