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