1use crate::{
2 Error, Input, Result, TypeSpecifier, new_input,
3 utils::{opt_ws_ident, spanned, tuple_parser},
4};
5use alloc::vec::Vec;
6use core::fmt;
7use winnow::{ModalResult, Parser, combinator::trace};
8
9#[derive(Clone, Debug, PartialEq, Eq)]
13pub struct ParameterSpecifier<'a> {
14 pub span: &'a str,
16 pub ty: TypeSpecifier<'a>,
18 pub storage: Option<Storage>,
20 pub indexed: bool,
22 pub name: Option<&'a str>,
24}
25
26impl<'a> TryFrom<&'a str> for ParameterSpecifier<'a> {
27 type Error = Error;
28
29 #[inline]
30 fn try_from(value: &'a str) -> Result<Self> {
31 Self::parse(value)
32 }
33}
34
35impl<'a> ParameterSpecifier<'a> {
36 #[inline]
38 pub fn parse(input: &'a str) -> Result<Self> {
39 Self::parser.parse(new_input(input)).map_err(Error::parser)
40 }
41
42 pub(crate) fn parser(input: &mut Input<'a>) -> ModalResult<Self> {
44 trace(
45 "ParameterSpecifier",
46 spanned(|input: &mut Input<'a>| {
47 let ty = TypeSpecifier::parser(input)?;
48 let mut name = opt_ws_ident(input)?;
49
50 let mut storage = None;
51 if let Some(kw @ ("storage" | "memory" | "calldata")) = name {
52 storage = match kw {
53 "storage" => Some(Storage::Storage),
54 "memory" => Some(Storage::Memory),
55 "calldata" => Some(Storage::Calldata),
56 _ => unreachable!(),
57 };
58 name = opt_ws_ident(input)?;
59 }
60
61 let mut indexed = false;
62 if let Some("indexed") = name {
63 indexed = true;
64 name = opt_ws_ident(input)?;
65 }
66 Ok((ty, storage, indexed, name))
67 }),
68 )
69 .parse_next(input)
70 .map(|(span, (ty, storage, indexed, name))| Self {
71 span,
72 ty,
73 storage,
74 indexed,
75 name,
76 })
77 }
78}
79
80#[derive(Clone, Debug, Default, PartialEq, Eq)]
82pub struct Parameters<'a> {
83 pub span: &'a str,
85 pub params: Vec<ParameterSpecifier<'a>>,
87}
88
89impl<'a> TryFrom<&'a str> for Parameters<'a> {
90 type Error = Error;
91
92 #[inline]
93 fn try_from(value: &'a str) -> Result<Self> {
94 Self::parse(value)
95 }
96}
97
98impl<'a> Parameters<'a> {
99 #[inline]
101 pub fn parse(input: &'a str) -> Result<Self> {
102 Self::parser.parse(new_input(input)).map_err(Error::parser)
103 }
104
105 pub(crate) fn parser(input: &mut Input<'a>) -> ModalResult<Self> {
107 trace("Parameters", spanned(tuple_parser(ParameterSpecifier::parser)))
108 .parse_next(input)
109 .map(|(span, params)| Self { span, params })
110 }
111}
112
113#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
115pub enum Storage {
116 Memory,
118 Storage,
120 Calldata,
122}
123
124impl core::str::FromStr for Storage {
125 type Err = Error;
126
127 #[inline]
128 fn from_str(s: &str) -> Result<Self> {
129 Self::parse(s)
130 }
131}
132
133impl fmt::Display for Storage {
134 #[inline]
135 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
136 f.write_str(self.as_str())
137 }
138}
139
140impl Storage {
141 pub fn parse(s: &str) -> Result<Self> {
143 match s {
144 "memory" => Ok(Self::Memory),
145 "storage" => Ok(Self::Storage),
146 "calldata" => Ok(Self::Calldata),
147 s => Err(Error::_new("invalid storage specifier: ", &s)),
148 }
149 }
150
151 #[inline]
153 pub const fn as_str(self) -> &'static str {
154 match self {
155 Self::Memory => "memory",
156 Self::Storage => "storage",
157 Self::Calldata => "calldata",
158 }
159 }
160}
161
162#[cfg(test)]
163mod tests {
164 use super::*;
165
166 #[test]
167 fn parse_param() {
168 assert_eq!(
169 ParameterSpecifier::parse("bool name"),
170 Ok(ParameterSpecifier {
171 span: "bool name",
172 ty: TypeSpecifier::parse("bool").unwrap(),
173 storage: None,
174 indexed: false,
175 name: Some("name"),
176 })
177 );
178
179 assert_eq!(
180 ParameterSpecifier::parse("bool indexed name"),
181 Ok(ParameterSpecifier {
182 span: "bool indexed name",
183 ty: TypeSpecifier::parse("bool").unwrap(),
184 storage: None,
185 indexed: true,
186 name: Some("name"),
187 })
188 );
189
190 assert_eq!(
191 ParameterSpecifier::parse("bool2 indexed \t name"),
192 Ok(ParameterSpecifier {
193 span: "bool2 indexed \t name",
194 ty: TypeSpecifier::parse("bool2").unwrap(),
195 storage: None,
196 indexed: true,
197 name: Some("name"),
198 })
199 );
200
201 ParameterSpecifier::parse("a b ").unwrap_err();
202 ParameterSpecifier::parse(" a b ").unwrap_err();
203 ParameterSpecifier::parse(" a b").unwrap_err();
204 }
205
206 #[test]
207 fn parse_params() {
208 assert_eq!(Parameters::parse("()"), Ok(Parameters { span: "()", params: vec![] }));
209 assert_eq!(Parameters::parse("( )"), Ok(Parameters { span: "( )", params: vec![] }));
210 assert_eq!(Parameters::parse("( )"), Ok(Parameters { span: "( )", params: vec![] }));
211 assert_eq!(Parameters::parse("( )"), Ok(Parameters { span: "( )", params: vec![] }));
212
213 assert_eq!(
214 Parameters::parse("(\tuint256 , \t)"),
215 Ok(Parameters {
216 span: "(\tuint256 , \t)",
217 params: vec![ParameterSpecifier {
218 span: "uint256 ",
219 ty: TypeSpecifier::parse("uint256").unwrap(),
220 storage: None,
221 indexed: false,
222 name: None,
223 }]
224 })
225 );
226 assert_eq!(
227 Parameters::parse("( \t uint256 \ta,\t bool b, \t)"),
228 Ok(Parameters {
229 span: "( \t uint256 \ta,\t bool b, \t)",
230 params: vec![
231 ParameterSpecifier {
232 span: "uint256 \ta",
233 ty: TypeSpecifier::parse("uint256").unwrap(),
234 storage: None,
235 indexed: false,
236 name: Some("a"),
237 },
238 ParameterSpecifier {
239 span: "bool b",
240 ty: TypeSpecifier::parse("bool").unwrap(),
241 storage: None,
242 indexed: false,
243 name: Some("b"),
244 }
245 ]
246 })
247 );
248 }
249
250 #[test]
251 fn parse_storage() {
252 assert_eq!(
253 ParameterSpecifier::parse("foo storag"),
254 Ok(ParameterSpecifier {
255 span: "foo storag",
256 ty: TypeSpecifier::parse("foo").unwrap(),
257 storage: None,
258 indexed: false,
259 name: Some("storag")
260 })
261 );
262 assert_eq!(
263 ParameterSpecifier::parse("foo storage"),
264 Ok(ParameterSpecifier {
265 span: "foo storage",
266 ty: TypeSpecifier::parse("foo").unwrap(),
267 storage: Some(Storage::Storage),
268 indexed: false,
269 name: None
270 })
271 );
272 assert_eq!(
273 ParameterSpecifier::parse("foo storage bar"),
274 Ok(ParameterSpecifier {
275 span: "foo storage bar",
276 ty: TypeSpecifier::parse("foo").unwrap(),
277 storage: Some(Storage::Storage),
278 indexed: false,
279 name: "bar".into()
280 })
281 );
282 assert_eq!(
283 ParameterSpecifier::parse("foo memory bar"),
284 Ok(ParameterSpecifier {
285 span: "foo memory bar",
286 ty: TypeSpecifier::parse("foo").unwrap(),
287 storage: Some(Storage::Memory),
288 indexed: false,
289 name: "bar".into()
290 })
291 );
292 assert_eq!(
293 ParameterSpecifier::parse("foo calldata bar"),
294 Ok(ParameterSpecifier {
295 span: "foo calldata bar",
296 ty: TypeSpecifier::parse("foo").unwrap(),
297 storage: Some(Storage::Calldata),
298 indexed: false,
299 name: "bar".into()
300 })
301 );
302 ParameterSpecifier::parse("foo storag bar").unwrap_err();
303 }
304}