sway_parse/
path.rs

1use crate::{Parse, ParseResult, Parser};
2
3use sway_ast::keywords::{DoubleColonToken, OpenAngleBracketToken, SelfToken, StorageToken};
4use sway_ast::{
5    AngleBrackets, PathExpr, PathExprSegment, PathType, PathTypeSegment, QualifiedPathRoot,
6};
7use sway_types::{Ident, Spanned};
8
9impl Parse for PathExpr {
10    fn parse(parser: &mut Parser) -> ParseResult<PathExpr> {
11        let root_opt = match parser.take() {
12            Some(open_angle_bracket_token) => {
13                let qualified_path_root = parser.parse()?;
14                let close_angle_bracket_token = parser.parse()?;
15                let angle_brackets = AngleBrackets {
16                    open_angle_bracket_token,
17                    inner: qualified_path_root,
18                    close_angle_bracket_token,
19                };
20                let double_colon_token = parser.parse()?;
21                Some((Some(angle_brackets), double_colon_token))
22            }
23            None => parser
24                .take()
25                .map(|double_colon_token| (None, double_colon_token)),
26        };
27        let prefix = parser.parse()?;
28        let mut suffix: Vec<(DoubleColonToken, PathExprSegment)> = Vec::new();
29        let mut incomplete_suffix = false;
30        while let Some(double_colon_token) = parser.take() {
31            if let Ok(segment) = parser.parse() {
32                suffix.push((double_colon_token, segment));
33            } else {
34                incomplete_suffix = true;
35                // this is to make the span be `foo::` instead of just `foo`
36                let dummy_path_expr_segment = PathExprSegment {
37                    name: Ident::new(double_colon_token.span()),
38                    generics_opt: None,
39                };
40                suffix.push((double_colon_token, dummy_path_expr_segment));
41                break;
42            }
43        }
44        Ok(PathExpr {
45            root_opt,
46            prefix,
47            suffix,
48            incomplete_suffix,
49        })
50    }
51}
52
53fn parse_ident(parser: &mut Parser) -> ParseResult<Ident> {
54    if let Some(token) = parser.take::<StorageToken>() {
55        Ok(Ident::from(token))
56    } else if let Some(token) = parser.take::<SelfToken>() {
57        Ok(Ident::from(token))
58    } else {
59        parser.parse::<Ident>()
60    }
61}
62
63impl Parse for PathExprSegment {
64    fn parse(parser: &mut Parser) -> ParseResult<PathExprSegment> {
65        Ok(PathExprSegment {
66            name: parse_ident(parser)?,
67            generics_opt: parser.guarded_parse::<(DoubleColonToken, OpenAngleBracketToken), _>()?,
68        })
69    }
70}
71
72impl Parse for PathType {
73    fn parse(parser: &mut Parser) -> ParseResult<PathType> {
74        let root_opt = match parser.take() {
75            Some(open_angle_bracket_token) => {
76                let qualified_path_root = parser.parse()?;
77                let close_angle_bracket_token = parser.parse()?;
78                let angle_brackets = AngleBrackets {
79                    open_angle_bracket_token,
80                    inner: qualified_path_root,
81                    close_angle_bracket_token,
82                };
83                let double_colon_token = parser.parse()?;
84                Some((Some(angle_brackets), double_colon_token))
85            }
86            None => parser
87                .take()
88                .map(|double_colon_token| (None, double_colon_token)),
89        };
90        let prefix = parser.parse()?;
91        let mut suffix = Vec::new();
92        while let Some(double_colon_token) = parser.take() {
93            let segment = parser.parse()?;
94            suffix.push((double_colon_token, segment));
95        }
96        Ok(PathType {
97            root_opt,
98            prefix,
99            suffix,
100        })
101    }
102}
103
104impl Parse for PathTypeSegment {
105    fn parse(parser: &mut Parser) -> ParseResult<PathTypeSegment> {
106        let name = parse_ident(parser)?;
107        let generics_opt =
108            if let Some(generics) = parser.guarded_parse::<OpenAngleBracketToken, _>()? {
109                Some((None, generics))
110            } else if let Some((double_colon_token, generics)) =
111                parser.guarded_parse::<(DoubleColonToken, OpenAngleBracketToken), _>()?
112            {
113                Some((Some(double_colon_token), generics))
114            } else {
115                None
116            };
117        Ok(PathTypeSegment { name, generics_opt })
118    }
119}
120
121impl Parse for QualifiedPathRoot {
122    fn parse(parser: &mut Parser) -> ParseResult<QualifiedPathRoot> {
123        let ty = parser.parse()?;
124        let as_trait = (parser.parse()?, parser.parse()?);
125        Ok(QualifiedPathRoot { ty, as_trait })
126    }
127}
128
129#[cfg(test)]
130mod tests {
131    use super::*;
132    use crate::test_utils::parse;
133    use insta::*;
134
135    #[test]
136    fn parse_nested_path() {
137        assert_ron_snapshot!(parse::<PathExpr>(r#"
138            std::vec::Vec
139        "#,), @r#"
140        PathExpr(
141          root_opt: None,
142          prefix: PathExprSegment(
143            name: BaseIdent(
144              name_override_opt: None,
145              span: Span(
146                src: "\n            std::vec::Vec\n        ",
147                start: 13,
148                end: 16,
149                source_id: None,
150              ),
151              is_raw_ident: false,
152            ),
153            generics_opt: None,
154          ),
155          suffix: [
156            (DoubleColonToken(
157              span: Span(
158                src: "\n            std::vec::Vec\n        ",
159                start: 16,
160                end: 18,
161                source_id: None,
162              ),
163            ), PathExprSegment(
164              name: BaseIdent(
165                name_override_opt: None,
166                span: Span(
167                  src: "\n            std::vec::Vec\n        ",
168                  start: 18,
169                  end: 21,
170                  source_id: None,
171                ),
172                is_raw_ident: false,
173              ),
174              generics_opt: None,
175            )),
176            (DoubleColonToken(
177              span: Span(
178                src: "\n            std::vec::Vec\n        ",
179                start: 21,
180                end: 23,
181                source_id: None,
182              ),
183            ), PathExprSegment(
184              name: BaseIdent(
185                name_override_opt: None,
186                span: Span(
187                  src: "\n            std::vec::Vec\n        ",
188                  start: 23,
189                  end: 26,
190                  source_id: None,
191                ),
192                is_raw_ident: false,
193              ),
194              generics_opt: None,
195            )),
196          ],
197        )
198        "#);
199    }
200}