alloy_sol_type_parser/
parameter.rs

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