alloy_sol_type_parser/
parameter.rs

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// TODO: Parse visibility and state mutability
10
11/// Represents a function parameter.
12#[derive(Clone, Debug, PartialEq, Eq)]
13pub struct ParameterSpecifier<'a> {
14    /// The full span of the specifier.
15    pub span: &'a str,
16    /// The type of the parameter.
17    pub ty: TypeSpecifier<'a>,
18    /// The storage specifier.
19    pub storage: Option<Storage>,
20    /// Whether the parameter indexed.
21    pub indexed: bool,
22    /// The name of the parameter.
23    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    /// Parse a parameter from a string.
37    #[inline]
38    pub fn parse(input: &'a str) -> Result<Self> {
39        Self::parser.parse(new_input(input)).map_err(Error::parser)
40    }
41
42    /// [`winnow`] parser for this type.
43    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/// Represents a list of function parameters.
81#[derive(Clone, Debug, Default, PartialEq, Eq)]
82pub struct Parameters<'a> {
83    /// The full span of the specifier.
84    pub span: &'a str,
85    /// The parameters.
86    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    /// Parse a parameter list from a string.
100    #[inline]
101    pub fn parse(input: &'a str) -> Result<Self> {
102        Self::parser.parse(new_input(input)).map_err(Error::parser)
103    }
104
105    /// [`winnow`] parser for this type.
106    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/// Storage specifier.
114#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
115pub enum Storage {
116    /// `memory`
117    Memory,
118    /// `storage`
119    Storage,
120    /// `calldata`
121    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    /// Parse a string storage specifier.
142    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    /// Returns a string representation of the storage specifier.
152    #[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}