scilla_parser/
type.rs

1use std::fmt::Display;
2
3use crate::{simplified_representation::primitives::SrType, FieldList};
4
5/// Represents all different scilla types.
6#[derive(Debug, PartialEq, Clone)]
7pub enum Type {
8    Int32,
9    Int64,
10    Int128,
11    Int256,
12
13    Uint32,
14    Uint64,
15    Uint128,
16    Uint256,
17
18    String,
19
20    BNum,
21    Map(Box<Type>, Box<Type>),
22
23    ByStr,
24    ByStrX(usize),
25    ByStr20,
26    /// See https://scilla.readthedocs.io/en/latest/scilla-in-depth.html#addresses-1
27    ByStr20With {
28        type_name: String, // contract, library, ...
29        fields: FieldList,
30    },
31
32    // ADT
33    Bool,
34    Option(Box<Type>),
35    Pair(Box<Type>, Box<Type>),
36    List(Box<Type>),
37
38    Other(String),
39}
40
41impl Display for Type {
42    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
43        match self {
44            Type::Int32 => write!(f, "Int32"),
45            Type::Int64 => write!(f, "Int64"),
46            Type::Int128 => write!(f, "Int128"),
47            Type::Int256 => write!(f, "Int256"),
48            Type::Uint32 => write!(f, "Uint32"),
49            Type::Uint64 => write!(f, "Uint64"),
50            Type::Uint128 => write!(f, "Uint128"),
51            Type::Uint256 => write!(f, "Uint256"),
52            Type::String => write!(f, "String"),
53            Type::BNum => write!(f, "BNum"),
54            Type::Bool => write!(f, "Bool"),
55            Type::Map(ref k, ref v) => write!(f, "(Map {}, {})", k, v),
56            Type::Option(ref k) => write!(f, "(Option {})", k),
57            Type::List(ref k) => write!(f, "(List {})", k),
58            Type::Pair(ref k, ref v) => write!(f, "(Pair {} {})", k, v),
59            Type::ByStr => write!(f, "ByStr"),
60            Type::ByStrX(n) => write!(f, "ByStr{}", n),
61            Type::ByStr20 => write!(f, "ByStr20"),
62            Type::ByStr20With { type_name, fields } => {
63                let fields = fields
64                    .iter()
65                    .map(|field| format!("field {}: {}", field.name, field.r#type))
66                    .collect::<Vec<String>>()
67                    .join(", ");
68                write!(f, "ByStr20 with {type_name}{fields} end")
69            }
70            Type::Other(ref s) => write!(f, "{}", s),
71        }
72    }
73}
74
75impl From<SrType> for Type {
76    fn from(mut type_definition: SrType) -> Self {
77        match type_definition.main_type.as_str() {
78            "Int32" => Type::Int32,
79            "Int64" => Type::Int64,
80            "Int128" => Type::Int128,
81            "Int256" => Type::Int256,
82            "Uint32" => Type::Uint32,
83            "Uint64" => Type::Uint64,
84            "Uint128" => Type::Uint128,
85            "Uint256" => Type::Uint256,
86            "String" => Type::String,
87            "ByStr" => Type::ByStr,
88            "ByStrX" => todo!(),
89            "BNum" => Type::BNum,
90            "Bool" => Type::Bool,
91            // TODO: Remove unwrap
92            "Option" => Type::Option(Box::new(type_definition.sub_types.pop().unwrap().into())),
93            "List" => Type::List(Box::new(type_definition.sub_types.pop().unwrap().into())),
94            "Pair" => {
95                let t2 = type_definition.sub_types.pop().unwrap();
96                let t1 = type_definition.sub_types.pop().unwrap();
97                Type::Pair(Box::new(t1.into()), Box::new(t2.into()))
98            }
99            "Map" => {
100                let value = type_definition.sub_types.pop().unwrap();
101                let key = type_definition.sub_types.pop().unwrap();
102                Type::Map(Box::new(key.into()), Box::new(value.into()))
103            }
104            "ByStr20" => type_definition
105                .address_type
106                .map_or(Type::ByStr20, |address_type| Type::ByStr20With {
107                    type_name: address_type.type_name,
108                    fields: address_type.fields,
109                }),
110            t if t.starts_with("ByStr") => {
111                if let Some(number) = t
112                    .strip_prefix("ByStr")
113                    .and_then(|s| s.parse::<usize>().ok())
114                {
115                    Type::ByStrX(number)
116                } else {
117                    Type::Other(type_definition.main_type)
118                }
119            }
120            _ => Type::Other(type_definition.main_type),
121        }
122    }
123}
124
125#[cfg(test)]
126mod tests {
127    use super::*;
128
129    #[test]
130    fn test_type_to_string() {
131        //(List (Pair ByStr20 (List (Pair ByStr20 Uint32))))
132        let list_type = Type::List(Box::new(Type::Pair(
133            Box::new(Type::ByStrX(20)),
134            Box::new(Type::List(Box::new(Type::Pair(
135                Box::new(Type::ByStrX(20)),
136                Box::new(Type::Uint32),
137            )))),
138        )));
139
140        assert_eq!(
141            "(List (Pair ByStr20 (List (Pair ByStr20 Uint32))))",
142            list_type.to_string()
143        );
144
145        // (List (Pair ByStr20 (List (Pair ByStr20 (List (Pair Uint32 Uint128))))))
146        let list_type = Type::List(Box::new(Type::Pair(
147            Box::new(Type::ByStrX(20)),
148            Box::new(Type::List(Box::new(Type::Pair(
149                Box::new(Type::ByStrX(20)),
150                Box::new(Type::List(Box::new(Type::Pair(
151                    Box::new(Type::Uint32),
152                    Box::new(Type::Uint128),
153                )))),
154            )))),
155        )));
156
157        assert_eq!(
158            "(List (Pair ByStr20 (List (Pair ByStr20 (List (Pair Uint32 Uint128))))))",
159            list_type.to_string()
160        );
161    }
162}