sway_parse/
parse.rs

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}