1use crate::{Parse, ParseBracket, ParseResult, ParseToEnd, Parser, ParserConsumed};
2use sway_ast::brackets::{Parens, SquareBrackets};
3use sway_ast::keywords::{DoubleColonToken, OpenAngleBracketToken, PtrToken, SliceToken, StrToken};
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::<StrToken>() {
55 let length = SquareBrackets::try_parse_all_inner(parser, |mut parser| {
56 parser.emit_error(ParseErrorKind::UnexpectedTokenAfterStrLength)
57 })?;
58 let t = match length {
59 Some(length) => Ty::StringArray { str_token, length },
60 None => Ty::StringSlice(str_token),
61 };
62 return Ok(t);
63 }
64
65 if let Some(underscore_token) = parser.take() {
66 return Ok(Ty::Infer { underscore_token });
67 }
68
69 if let Some(ptr_token) = parser.take::<PtrToken>() {
70 let ty = SquareBrackets::parse_all_inner(parser, |mut parser| {
71 parser.emit_error(ParseErrorKind::UnexpectedTokenAfterPtrType)
72 })?;
73 return Ok(Ty::Ptr { ptr_token, ty });
74 }
75
76 if let Some(slice_token) = parser.take::<SliceToken>() {
79 let ty = SquareBrackets::<Box<Ty>>::parse_all_inner(parser, |mut parser| {
80 parser.emit_error(ParseErrorKind::UnexpectedTokenAfterSliceType)
81 })?;
82 return Ok(Ty::Slice {
83 slice_token: Some(slice_token),
84 ty,
85 });
86 }
87
88 if let Some(ampersand_token) = parser.take() {
89 let mut_token = parser.take();
90 let ty = Box::new(parser.parse()?);
91 return Ok(Ty::Ref {
92 ampersand_token,
93 mut_token,
94 ty,
95 });
96 }
97
98 if let Some(bang_token) = parser.take() {
99 return Ok(Ty::Never { bang_token });
100 }
101
102 if parser.peek::<OpenAngleBracketToken>().is_some()
103 || parser.peek::<DoubleColonToken>().is_some()
104 || parser.peek::<Ident>().is_some()
105 {
106 let path_type = parser.parse()?;
107 return Ok(Ty::Path(path_type));
108 }
109
110 if let Ok(literal) = parser.parse::<Literal>() {
111 return Ok(Ty::Expr(Box::new(Expr::Literal(literal))));
112 }
113
114 Err(parser.emit_error(ParseErrorKind::ExpectedType))
115 }
116}
117
118impl ParseToEnd for TyArrayDescriptor {
119 fn parse_to_end<'a, 'e>(
120 mut parser: Parser<'a, '_>,
121 ) -> ParseResult<(TyArrayDescriptor, ParserConsumed<'a>)> {
122 let ty = parser.parse()?;
123 let semicolon_token = parser.parse()?;
124 let length = parser.parse()?;
125 let consumed = match parser.check_empty() {
126 Some(consumed) => consumed,
127 None => {
128 return Err(parser.emit_error(ParseErrorKind::UnexpectedTokenAfterArrayTypeLength))
129 }
130 };
131 let descriptor = TyArrayDescriptor {
132 ty,
133 semicolon_token,
134 length,
135 };
136 Ok((descriptor, consumed))
137 }
138}
139
140#[cfg(test)]
141mod tests {
142 use super::*;
143 use crate::test_utils::parse;
144 use assert_matches::*;
145
146 #[test]
147 fn parse_ptr() {
148 let item = parse::<Ty>(
149 r#"
150 __ptr[T]
151 "#,
152 );
153 assert_matches!(item, Ty::Ptr { .. });
154 }
155
156 #[test]
157 fn parse_array() {
158 let item = parse::<Ty>("[T; 1]");
159 assert_matches!(item, Ty::Array { .. });
160 }
161
162 #[test]
163 fn parse_slice() {
164 let item = parse::<Ty>("__slice[T]");
166 assert_matches!(item, Ty::Slice { .. });
167
168 let item = parse::<Ty>("[T]");
170 assert_matches!(item, Ty::Slice { .. });
171
172 let item = parse::<Ty>("&[T]");
173 assert_matches!(item, Ty::Ref { ty, .. } if matches!(&*ty, Ty::Slice { .. }));
174 }
175
176 #[test]
177 fn parse_ref() {
178 let item = parse::<Ty>(
179 r#"
180 &T
181 "#,
182 );
183 assert_matches!(
184 item,
185 Ty::Ref {
186 mut_token: None,
187 ..
188 }
189 );
190 }
191
192 #[test]
193 fn parse_mut_ref() {
194 let item = parse::<Ty>(
195 r#"
196 &mut T
197 "#,
198 );
199 assert_matches!(
200 item,
201 Ty::Ref {
202 mut_token: Some(_),
203 ..
204 }
205 );
206 }
207}