1use super::item::FunctionFlags;
2use crate::{PResult, Parser};
3use solar_ast::{token::*, *};
4use solar_interface::kw;
5use std::{fmt, ops::RangeInclusive};
6
7impl<'sess, 'ast> Parser<'sess, 'ast> {
8 #[instrument(level = "trace", skip_all)]
10 pub fn parse_type(&mut self) -> PResult<'sess, Type<'ast>> {
11 let mut ty = self
12 .parse_spanned(Self::parse_basic_ty_kind)
13 .map(|(span, kind)| Type { span, kind })?;
14
15 while self.eat(TokenKind::OpenDelim(Delimiter::Bracket)) {
17 let size = if self.check_noexpect(TokenKind::CloseDelim(Delimiter::Bracket)) {
18 None
19 } else {
20 Some(self.parse_expr()?)
21 };
22 self.expect(TokenKind::CloseDelim(Delimiter::Bracket))?;
23 ty = Type {
24 span: ty.span.to(self.prev_token.span),
25 kind: TypeKind::Array(self.alloc(TypeArray { element: ty, size })),
26 };
27 }
28
29 Ok(ty)
30 }
31
32 fn parse_basic_ty_kind(&mut self) -> PResult<'sess, TypeKind<'ast>> {
34 if self.check_elementary_type() {
35 self.parse_elementary_type().map(TypeKind::Elementary)
36 } else if self.eat_keyword(kw::Function) {
37 self.parse_function_header(FunctionFlags::FUNCTION_TY).map(|f| {
38 let FunctionHeader {
39 span: _,
40 name: _,
41 parameters,
42 visibility,
43 state_mutability,
44 modifiers: _,
45 virtual_: _,
46 override_: _,
47 returns,
48 } = f;
49 TypeKind::Function(self.alloc(TypeFunction {
50 parameters,
51 visibility,
52 state_mutability,
53 returns,
54 }))
55 })
56 } else if self.eat_keyword(kw::Mapping) {
57 self.parse_mapping_type().map(|x| TypeKind::Mapping(self.alloc(x)))
58 } else if self.check_path() {
59 self.parse_path().map(TypeKind::Custom)
60 } else {
61 self.unexpected()
62 }
63 }
64
65 pub(super) fn parse_elementary_type(&mut self) -> PResult<'sess, ElementaryType> {
69 let id = self.parse_ident_any()?;
70 debug_assert!(id.is_elementary_type());
71 let mut ty = match id.name {
72 kw::Address => ElementaryType::Address(false),
73 kw::Bool => ElementaryType::Bool,
74 kw::String => ElementaryType::String,
75 kw::Bytes => ElementaryType::Bytes,
76 kw::Fixed => ElementaryType::Fixed(TypeSize::ZERO, TypeFixedSize::ZERO),
77 kw::UFixed => ElementaryType::UFixed(TypeSize::ZERO, TypeFixedSize::ZERO),
78 kw::Int => ElementaryType::Int(TypeSize::ZERO),
79 kw::UInt => ElementaryType::UInt(TypeSize::ZERO),
80 s if s >= kw::UInt8 && s <= kw::UInt256 => {
81 let bytes = s.as_u32() - kw::UInt8.as_u32() + 1;
82 ElementaryType::UInt(TypeSize::new(bytes as u8).unwrap())
83 }
84 s if s >= kw::Int8 && s <= kw::Int256 => {
85 let bytes = s.as_u32() - kw::Int8.as_u32() + 1;
86 ElementaryType::Int(TypeSize::new(bytes as u8).unwrap())
87 }
88 s if s >= kw::Bytes1 && s <= kw::Bytes32 => {
89 let bytes = s.as_u32() - kw::Bytes1.as_u32() + 1;
90 ElementaryType::FixedBytes(TypeSize::new(bytes as u8).unwrap())
91 }
92 s => unreachable!("unexpected elementary type: {s}"),
93 };
94
95 let sm = self.parse_state_mutability();
96 match (&mut ty, sm) {
97 (ElementaryType::Address(p), Some(StateMutability::Payable)) => *p = true,
98 (_, None) => {}
99 (_, Some(_)) => {
100 let msg = if matches!(ty, ElementaryType::Address(_)) {
101 "address types can only be payable or non-payable"
102 } else {
103 "only address types can have state mutability"
104 };
105 self.dcx().err(msg).span(id.span.to(self.prev_token.span)).emit();
106 }
107 }
108
109 Ok(ty)
115 }
116
117 fn parse_mapping_type(&mut self) -> PResult<'sess, TypeMapping<'ast>> {
119 self.expect(TokenKind::OpenDelim(Delimiter::Parenthesis))?;
120
121 let key = self.parse_type()?;
122 if !key.is_elementary() && !key.is_custom() {
124 let msg =
125 "only elementary types or used-defined types can be used as key types in mappings";
126 self.dcx().err(msg).span(key.span).emit();
127 }
128 let key_name = self.parse_ident_opt()?;
129
130 self.expect(TokenKind::FatArrow)?;
131
132 let value = self.parse_type()?;
133 let value_name = self.parse_ident_opt()?;
134
135 self.expect(TokenKind::CloseDelim(Delimiter::Parenthesis))?;
136
137 Ok(TypeMapping { key, key_name, value, value_name })
138 }
139}
140
141#[derive(Debug, PartialEq)]
142enum ParseTySizeError {
143 Parse(std::num::ParseIntError),
144 TryFrom(std::num::TryFromIntError),
145 NotMultipleOf8,
146 OutOfRange(RangeInclusive<u16>),
147 FixedX,
148}
149
150impl fmt::Display for ParseTySizeError {
151 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
152 match self {
153 Self::Parse(e) => e.fmt(f),
154 Self::TryFrom(e) => e.fmt(f),
155 Self::NotMultipleOf8 => f.write_str("number must be a multiple of 8"),
156 Self::OutOfRange(range) => {
157 write!(f, "size is out of range of {}:{} (inclusive)", range.start(), range.end())
158 }
159 Self::FixedX => f.write_str("`fixed` sizes must be separated by exactly one 'x'"),
160 }
161 }
162}
163
164#[allow(dead_code)]
166fn parse_fixed_type(original: &str) -> Result<Option<ElementaryType>, ParseTySizeError> {
167 let s = original;
168 let tmp = s.strip_prefix('u');
169 let unsigned = tmp.is_some();
170 let s = tmp.unwrap_or(s);
171
172 if let Some(s) = s.strip_prefix("fixed") {
173 debug_assert!(!s.is_empty());
174 let (m, n) = parse_fixed_size(s)?;
175 return Ok(Some(if unsigned {
176 ElementaryType::UFixed(m, n)
177 } else {
178 ElementaryType::Fixed(m, n)
179 }));
180 }
181
182 Ok(None)
183}
184
185#[allow(dead_code)]
186fn parse_fb_size(s: &str) -> Result<TypeSize, ParseTySizeError> {
187 parse_ty_size_u8(s, 1..=32, false).map(|x| TypeSize::new(x).unwrap())
188}
189
190#[allow(dead_code)]
191fn parse_int_size(s: &str) -> Result<TypeSize, ParseTySizeError> {
192 parse_ty_size_u8(s, 1..=32, true).map(|x| TypeSize::new(x).unwrap())
193}
194
195#[allow(dead_code)]
196fn parse_fixed_size(s: &str) -> Result<(TypeSize, TypeFixedSize), ParseTySizeError> {
197 let (m, n) = s.split_once('x').ok_or(ParseTySizeError::FixedX)?;
198 let m = parse_int_size(m)?;
199 let n = parse_ty_size_u8(n, 0..=80, false)?;
200 let n = TypeFixedSize::new(n).unwrap();
201 Ok((m, n))
202}
203
204fn parse_ty_size_u8(
212 s: &str,
213 real_range: RangeInclusive<u8>,
214 to_bytes: bool,
215) -> Result<u8, ParseTySizeError> {
216 let mut n = s.parse::<u16>().map_err(ParseTySizeError::Parse)?;
217
218 if to_bytes {
219 if !n.is_multiple_of(8) {
220 return Err(ParseTySizeError::NotMultipleOf8);
221 }
222 n /= 8;
223 }
224
225 let n = u8::try_from(n).map_err(ParseTySizeError::TryFrom)?;
226
227 if !real_range.contains(&n) {
228 let display_range = if to_bytes {
229 *real_range.start() as u16 * 8..=*real_range.end() as u16 * 8
230 } else {
231 *real_range.start() as u16..=*real_range.end() as u16
232 };
233 return Err(ParseTySizeError::OutOfRange(display_range));
234 }
235
236 Ok(n)
237}
238
239#[cfg(test)]
240mod tests {
241 use super::*;
242
243 #[test]
244 fn parse_size() {
245 use ParseTySizeError::*;
246
247 assert_eq!(parse_ty_size_u8("0", 0..=1, false), Ok(0));
248 assert_eq!(parse_ty_size_u8("1", 0..=1, false), Ok(1));
249 assert_eq!(parse_ty_size_u8("0", 0..=1, true), Ok(0));
250 assert_eq!(parse_ty_size_u8("1", 0..=1, true), Err(NotMultipleOf8));
251 assert_eq!(parse_ty_size_u8("8", 0..=1, true), Ok(1));
252
253 assert_eq!(parse_ty_size_u8("0", 1..=32, false), Err(OutOfRange(1..=32)));
254 assert_eq!(parse_ty_size_u8("0", 1..=32, true), Err(OutOfRange(8..=256)));
255 for n in 1..=32 {
256 assert_eq!(parse_ty_size_u8(&n.to_string(), 1..=32, false), Ok(n as u8));
257 for m in 1..=7u16 {
258 assert_eq!(
259 parse_ty_size_u8(&((n - 1) * 8 + m).to_string(), 1..=32, true),
260 Err(NotMultipleOf8)
261 );
262 }
263 assert_eq!(parse_ty_size_u8(&(n * 8).to_string(), 1..=32, true), Ok(n as u8));
264 }
265 }
266}