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