1use crate::{Parse, ParseBracket, ParseResult, ParseToEnd, Parser, ParserConsumed};
2use sway_ast::brackets::{Parens, SquareBrackets};
3use sway_ast::keywords::{DoubleColonToken, OpenAngleBracketToken, PtrToken, SliceToken};
4use sway_ast::ty::{Ty, TyArrayDescriptor, TyTupleDescriptor};
5use sway_error::parser_error::ParseErrorKind;
6use sway_types::{ast::Delimiter, Ident};
7
8impl Parse for Ty {
9 fn parse(parser: &mut Parser) -> ParseResult<Ty> {
10 if let Some((mut parser, span)) = parser.enter_delimited(Delimiter::Parenthesis) {
13 if let Some(_consumed) = parser.check_empty() {
14 return Ok(Ty::Tuple(Parens::new(TyTupleDescriptor::Nil, span)));
15 }
16 let head = parser.parse()?;
17 if let Some(comma_token) = parser.take() {
18 let (tail, _consumed) = parser.parse_to_end()?;
19 let tuple = TyTupleDescriptor::Cons {
20 head,
21 comma_token,
22 tail,
23 };
24 return Ok(Ty::Tuple(Parens::new(tuple, span)));
25 }
26 if parser.check_empty().is_some() {
27 return Ok(*head);
28 }
29 return Err(parser
30 .emit_error(ParseErrorKind::ExpectedCommaOrCloseParenInTupleOrParenExpression));
31 }
32
33 if let Some((mut inner_parser, span)) = parser.enter_delimited(Delimiter::Bracket) {
34 if let Ok((array, _)) = inner_parser.try_parse_to_end::<TyArrayDescriptor>(false) {
36 return Ok(Ty::Array(SquareBrackets { inner: array, span }));
37 }
38
39 if let Ok(Some((ty, _))) = inner_parser.try_parse_and_check_empty::<Ty>(false) {
41 return Ok(Ty::Slice {
42 slice_token: None,
43 ty: SquareBrackets {
44 inner: Box::new(ty),
45 span,
46 },
47 });
48 }
49 }
50
51 if let Some(str_token) = parser.take() {
52 let length = SquareBrackets::try_parse_all_inner(parser, |mut parser| {
53 parser.emit_error(ParseErrorKind::UnexpectedTokenAfterStrLength)
54 })?;
55 let t = match length {
56 Some(length) => Ty::StringArray { str_token, length },
57 None => Ty::StringSlice(str_token),
58 };
59 return Ok(t);
60 }
61
62 if let Some(underscore_token) = parser.take() {
63 return Ok(Ty::Infer { underscore_token });
64 }
65
66 if let Some(ptr_token) = parser.take::<PtrToken>() {
67 let ty = SquareBrackets::parse_all_inner(parser, |mut parser| {
68 parser.emit_error(ParseErrorKind::UnexpectedTokenAfterPtrType)
69 })?;
70 return Ok(Ty::Ptr { ptr_token, ty });
71 }
72
73 if let Some(slice_token) = parser.take::<SliceToken>() {
76 let ty = SquareBrackets::<Box<Ty>>::parse_all_inner(parser, |mut parser| {
77 parser.emit_error(ParseErrorKind::UnexpectedTokenAfterSliceType)
78 })?;
79 return Ok(Ty::Slice {
80 slice_token: Some(slice_token),
81 ty,
82 });
83 }
84
85 if let Some(ampersand_token) = parser.take() {
86 let mut_token = parser.take();
87 let ty = Box::new(parser.parse()?);
88 return Ok(Ty::Ref {
89 ampersand_token,
90 mut_token,
91 ty,
92 });
93 }
94
95 if let Some(bang_token) = parser.take() {
96 return Ok(Ty::Never { bang_token });
97 }
98
99 if parser.peek::<OpenAngleBracketToken>().is_some()
100 || parser.peek::<DoubleColonToken>().is_some()
101 || parser.peek::<Ident>().is_some()
102 {
103 let path_type = parser.parse()?;
104 return Ok(Ty::Path(path_type));
105 }
106
107 Err(parser.emit_error(ParseErrorKind::ExpectedType))
108 }
109}
110
111impl ParseToEnd for TyArrayDescriptor {
112 fn parse_to_end<'a, 'e>(
113 mut parser: Parser<'a, '_>,
114 ) -> ParseResult<(TyArrayDescriptor, ParserConsumed<'a>)> {
115 let ty = parser.parse()?;
116 let semicolon_token = parser.parse()?;
117 let length = parser.parse()?;
118 let consumed = match parser.check_empty() {
119 Some(consumed) => consumed,
120 None => {
121 return Err(parser.emit_error(ParseErrorKind::UnexpectedTokenAfterArrayTypeLength))
122 }
123 };
124 let descriptor = TyArrayDescriptor {
125 ty,
126 semicolon_token,
127 length,
128 };
129 Ok((descriptor, consumed))
130 }
131}
132
133#[cfg(test)]
134mod tests {
135 use super::*;
136 use crate::test_utils::parse;
137 use assert_matches::*;
138
139 #[test]
140 fn parse_ptr() {
141 let item = parse::<Ty>(
142 r#"
143 __ptr[T]
144 "#,
145 );
146 assert_matches!(item, Ty::Ptr { .. });
147 }
148
149 #[test]
150 fn parse_array() {
151 let item = parse::<Ty>("[T; 1]");
152 assert_matches!(item, Ty::Array { .. });
153 }
154
155 #[test]
156 fn parse_slice() {
157 let item = parse::<Ty>("__slice[T]");
159 assert_matches!(item, Ty::Slice { .. });
160
161 let item = parse::<Ty>("[T]");
163 assert_matches!(item, Ty::Slice { .. });
164
165 let item = parse::<Ty>("&[T]");
166 assert_matches!(item, Ty::Ref { ty, .. } if matches!(&*ty, Ty::Slice { .. }));
167 }
168
169 #[test]
170 fn parse_ref() {
171 let item = parse::<Ty>(
172 r#"
173 &T
174 "#,
175 );
176 assert_matches!(
177 item,
178 Ty::Ref {
179 mut_token: None,
180 ..
181 }
182 );
183 }
184
185 #[test]
186 fn parse_mut_ref() {
187 let item = parse::<Ty>(
188 r#"
189 &mut T
190 "#,
191 );
192 assert_matches!(
193 item,
194 Ty::Ref {
195 mut_token: Some(_),
196 ..
197 }
198 );
199 }
200}