cainome_parser/tokens/
mod.rs

1//! Cairo ABI tokens.
2//!
3//! TODO.
4
5mod array;
6mod basic;
7mod composite;
8mod constants;
9mod function;
10mod genericity;
11mod non_zero;
12mod option;
13mod result;
14mod tuple;
15
16use std::collections::HashMap;
17
18pub use array::Array;
19pub use basic::CoreBasic;
20pub use composite::{Composite, CompositeInner, CompositeInnerKind, CompositeType};
21pub use function::{Function, FunctionOutputKind, StateMutability};
22pub use non_zero::NonZero;
23pub use option::Option;
24pub use result::Result;
25pub use tuple::Tuple;
26
27use crate::{CainomeResult, Error};
28
29#[derive(Debug, Clone, PartialEq)]
30pub enum Token {
31    CoreBasic(CoreBasic),
32    Array(Array),
33    Tuple(Tuple),
34    Composite(Composite),
35    Function(Function),
36    Option(Option),
37    Result(Result),
38    NonZero(NonZero),
39}
40
41impl Token {
42    pub fn parse(type_path: &str) -> CainomeResult<Self> {
43        if let Ok(b) = CoreBasic::parse(type_path) {
44            return Ok(Token::CoreBasic(b));
45        }
46
47        if let Ok(a) = Array::parse(type_path) {
48            return Ok(Token::Array(a));
49        }
50
51        if let Ok(t) = Tuple::parse(type_path) {
52            return Ok(Token::Tuple(t));
53        }
54
55        if let Ok(o) = Option::parse(type_path) {
56            return Ok(Token::Option(o));
57        }
58
59        if let Ok(r) = Result::parse(type_path) {
60            return Ok(Token::Result(r));
61        }
62
63        if let Ok(n) = NonZero::parse(type_path) {
64            return Ok(Token::NonZero(n));
65        }
66
67        if let Ok(c) = Composite::parse(type_path) {
68            return Ok(Token::Composite(c));
69        }
70
71        Err(Error::TokenInitFailed(format!(
72            "Couldn't initialize a Token from type path `{}`",
73            type_path,
74        )))
75    }
76
77    pub fn type_name(&self) -> String {
78        match self {
79            Token::CoreBasic(t) => t.type_name(),
80            Token::Array(_) => "array".to_string(),
81            Token::Tuple(_) => "tuple".to_string(),
82            Token::Composite(t) => t.type_name(),
83            Token::Function(_) => "function".to_string(),
84            Token::Option(_) => "option".to_string(),
85            Token::Result(_) => "result".to_string(),
86            Token::NonZero(_) => "non_zero".to_string(),
87        }
88    }
89
90    pub fn type_path(&self) -> String {
91        match self {
92            Token::CoreBasic(t) => t.type_path.to_string(),
93            Token::Array(t) => t.type_path.to_string(),
94            Token::Tuple(t) => t.type_path.to_string(),
95            Token::Composite(t) => t.type_path_no_generic(),
96            Token::Function(t) => t.name.clone(),
97            Token::Option(t) => t.type_path.to_string(),
98            Token::Result(t) => t.type_path.to_string(),
99            Token::NonZero(t) => t.type_path.to_string(),
100        }
101    }
102
103    // TODO: we may remove these two functions...! And change types somewhere..
104    pub fn to_composite(&self) -> CainomeResult<&Composite> {
105        match self {
106            Token::Composite(t) => Ok(t),
107            _ => Err(Error::ConversionFailed(format!(
108                "Can't convert token into composite, got {:?}",
109                self
110            ))),
111        }
112    }
113
114    pub fn to_function(&self) -> CainomeResult<&Function> {
115        match self {
116            Token::Function(t) => Ok(t),
117            _ => Err(Error::ConversionFailed(format!(
118                "Can't convert token into function, got {:?}",
119                self
120            ))),
121        }
122    }
123
124    pub fn apply_alias(&mut self, type_path: &str, alias: &str) {
125        match self {
126            Token::Array(t) => t.apply_alias(type_path, alias),
127            Token::Tuple(t) => t.apply_alias(type_path, alias),
128            Token::Composite(t) => t.apply_alias(type_path, alias),
129            Token::Function(t) => t.apply_alias(type_path, alias),
130            Token::Option(t) => t.apply_alias(type_path, alias),
131            Token::Result(t) => t.apply_alias(type_path, alias),
132            _ => (),
133        }
134    }
135
136    /// Recursively hydrates nested tokens
137    ///
138    /// Once abi is parsed, a flat list of tokens defined in cairo code is generated from parsed
139    /// json abi string.
140    /// Then token list are filtered to only keep single copy of each token.
141    /// Some tokens can have nested tokens that may not have inners defined inside thus leading to
142    /// confusion while using tokens. i.e Enums does not have inner variants defined.
143    ///
144    /// # Arguments
145    ///
146    /// * `token` - The token to hydrate.
147    /// * `filtered` - A map of type path to token that have already been hydrated.
148    /// * `recursion_max_depth` - Max depth recursion for token to hydrate.
149    /// * `iteration_count` - Current iteration count.
150    ///
151    pub fn hydrate(
152        token: Self,
153        filtered: &HashMap<String, Token>,
154        recursion_max_depth: usize,
155        iteration_count: usize,
156    ) -> Self {
157        if recursion_max_depth < iteration_count {
158            return token;
159        }
160        match token {
161            Token::CoreBasic(_) => token,
162            Token::Array(arr) => Token::Array(Array {
163                inner: Box::new(Self::hydrate(
164                    *arr.inner,
165                    filtered,
166                    recursion_max_depth,
167                    iteration_count + 1,
168                )),
169                type_path: arr.type_path,
170                is_legacy: arr.is_legacy,
171            }),
172            Token::Tuple(tup) => Token::Tuple(Tuple {
173                inners: tup
174                    .inners
175                    .into_iter()
176                    .map(|inner| {
177                        Self::hydrate(inner, filtered, recursion_max_depth, iteration_count + 1)
178                    })
179                    .collect(),
180                type_path: tup.type_path,
181            }),
182            Token::Option(opt) => Token::Option(Option {
183                type_path: opt.type_path,
184                inner: Box::new(Self::hydrate(
185                    *opt.inner,
186                    filtered,
187                    recursion_max_depth,
188                    iteration_count + 1,
189                )),
190            }),
191            Token::NonZero(non_zero) => Token::NonZero(NonZero {
192                type_path: non_zero.type_path,
193                inner: Box::new(Self::hydrate(
194                    *non_zero.inner,
195                    filtered,
196                    recursion_max_depth,
197                    iteration_count + 1,
198                )),
199            }),
200            Token::Result(res) => Token::Result(Result {
201                type_path: res.type_path,
202                inner: Box::new(Self::hydrate(
203                    *res.inner,
204                    filtered,
205                    recursion_max_depth,
206                    iteration_count + 1,
207                )),
208                error: Box::new(Self::hydrate(
209                    *res.error,
210                    filtered,
211                    recursion_max_depth,
212                    iteration_count + 1,
213                )),
214            }),
215            Token::Composite(comp) => {
216                let type_path = comp.type_path_no_generic();
217
218                if comp.r#type == CompositeType::Unknown && !comp.is_builtin() {
219                    if let Some(hydrated) = filtered.get(&type_path) {
220                        return Token::hydrate(
221                            hydrated.clone(),
222                            filtered,
223                            recursion_max_depth,
224                            iteration_count + 1,
225                        );
226                    } else {
227                        panic!("Composite {} not found in filtered tokens", type_path);
228                    }
229                }
230                Token::Composite(Composite {
231                    type_path,
232                    inners: comp
233                        .inners
234                        .into_iter()
235                        .map(|i| CompositeInner {
236                            index: i.index,
237                            name: i.name,
238                            kind: i.kind,
239                            token: Self::hydrate(
240                                i.token,
241                                filtered,
242                                recursion_max_depth,
243                                iteration_count + 1,
244                            ),
245                        })
246                        .collect(),
247                    generic_args: comp
248                        .generic_args
249                        .into_iter()
250                        .map(|(name, token)| {
251                            (
252                                name,
253                                Self::hydrate(
254                                    token,
255                                    filtered,
256                                    recursion_max_depth,
257                                    iteration_count + 1,
258                                ),
259                            )
260                        })
261                        .collect(),
262                    r#type: comp.r#type,
263                    is_event: comp.is_event,
264                    alias: comp.alias,
265                })
266            }
267            Token::Function(func) => Token::Function(Function {
268                name: func.name,
269                inputs: func
270                    .inputs
271                    .into_iter()
272                    .map(|(name, token)| {
273                        (
274                            name,
275                            Self::hydrate(
276                                token,
277                                filtered,
278                                recursion_max_depth,
279                                iteration_count + 1,
280                            ),
281                        )
282                    })
283                    .collect(),
284                outputs: func
285                    .outputs
286                    .into_iter()
287                    .map(|token| {
288                        Self::hydrate(token, filtered, recursion_max_depth, iteration_count + 1)
289                    })
290                    .collect(),
291                named_outputs: func
292                    .named_outputs
293                    .into_iter()
294                    .map(|(name, token)| {
295                        (
296                            name,
297                            Self::hydrate(
298                                token,
299                                filtered,
300                                recursion_max_depth,
301                                iteration_count + 1,
302                            ),
303                        )
304                    })
305                    .collect(),
306                state_mutability: func.state_mutability,
307            }),
308        }
309    }
310}