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