spade_types/
lib.rs

1pub mod meta_types;
2
3use num::BigInt;
4use rustc_hash::FxHashMap as HashMap;
5use serde::{Deserialize, Serialize};
6use spade_common::{
7    name::{Identifier, NameID},
8    num_ext::InfallibleToBigInt,
9};
10
11#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
12pub enum PrimitiveType {
13    Int,
14    Uint,
15    Clock,
16    Bool,
17    Tri,
18    Memory,
19    InOut,
20}
21
22impl std::fmt::Display for PrimitiveType {
23    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
24        let str = match self {
25            PrimitiveType::Int => "int",
26            PrimitiveType::Uint => "uint",
27            PrimitiveType::Clock => "clock",
28            PrimitiveType::Bool => "bool",
29            PrimitiveType::Tri => "tri",
30            PrimitiveType::Memory => "Memory",
31            PrimitiveType::InOut => "inout",
32        };
33        write!(f, "{str}")
34    }
35}
36
37#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
38pub enum ConcreteType {
39    Error,
40    Tuple(Vec<ConcreteType>),
41    Struct {
42        name: NameID,
43        is_port: bool,
44        members: Vec<(Identifier, ConcreteType)>,
45        field_translators: HashMap<Identifier, String>,
46    },
47    Array {
48        inner: Box<ConcreteType>,
49        size: BigInt,
50    },
51    Enum {
52        options: Vec<(NameID, Vec<(Identifier, ConcreteType)>)>,
53    },
54    Single {
55        base: PrimitiveType,
56        params: Vec<ConcreteType>,
57    },
58    Integer(BigInt),
59    Bool(bool),
60    String(String),
61    Backward(Box<ConcreteType>),
62    Wire(Box<ConcreteType>),
63}
64
65impl ConcreteType {
66    pub fn assume_struct(&self) -> (&NameID, &Vec<(Identifier, ConcreteType)>) {
67        match self {
68            ConcreteType::Struct {
69                name,
70                is_port: _,
71                members,
72                field_translators: _,
73            } => (name, members),
74            t => unreachable!("Assumed {} was a struct", t),
75        }
76    }
77
78    pub fn is_error_recursively(&self) -> bool {
79        match self {
80            ConcreteType::Error => true,
81            ConcreteType::Tuple(inner) => inner.iter().any(|ty| ty.is_error_recursively()),
82            ConcreteType::Struct {
83                name: _,
84                is_port: _,
85                members,
86                field_translators: _,
87            } => members.iter().any(|(_, ty)| ty.is_error_recursively()),
88            ConcreteType::Array { inner, size: _ } => inner.is_error_recursively(),
89            ConcreteType::Enum { options } => options.iter().any(|option| {
90                option
91                    .1
92                    .iter()
93                    .any(|(_, member)| member.is_error_recursively())
94            }),
95            ConcreteType::Single { base: _, params } => {
96                params.iter().any(|p| p.is_error_recursively())
97            }
98            ConcreteType::Integer(_) => false,
99            ConcreteType::Bool(_) => false,
100            ConcreteType::String(_) => false,
101            ConcreteType::Backward(inner) => inner.is_error_recursively(),
102            ConcreteType::Wire(inner) => inner.is_error_recursively(),
103        }
104    }
105
106    pub fn is_port(&self) -> bool {
107        match self {
108            ConcreteType::Error => false,
109            ConcreteType::Tuple(inner) => inner.iter().any(Self::is_port),
110            ConcreteType::Struct {
111                name: _,
112                is_port,
113                members: _,
114                field_translators: _,
115            } => *is_port,
116            ConcreteType::Array { inner, size: _ } => inner.is_port(),
117            // Enums cannot be ports
118            ConcreteType::Enum { .. } => false,
119            ConcreteType::Single {
120                base: PrimitiveType::Memory,
121                ..
122            } => true,
123            ConcreteType::Single {
124                base: PrimitiveType::Clock,
125                ..
126            } => true,
127            ConcreteType::Single { .. } => false,
128            ConcreteType::Integer(_) | ConcreteType::Bool(_) | ConcreteType::String(_) => false,
129            ConcreteType::Backward(_) => true,
130            ConcreteType::Wire(_) => true,
131        }
132    }
133}
134
135impl std::fmt::Display for ConcreteType {
136    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
137        let str = match self {
138            ConcreteType::Error => "{error}".to_string(),
139            ConcreteType::Tuple(inner) => {
140                format!(
141                    "({})",
142                    inner
143                        .iter()
144                        .map(|p| format!("{}", p))
145                        .collect::<Vec<_>>()
146                        .join(", ")
147                )
148            }
149            ConcreteType::Struct {
150                name,
151                is_port,
152                members,
153                field_translators: _,
154            } => {
155                let port = if *is_port { "port " } else { "" };
156                format!(
157                    "struct {port}{name} {{{}}}",
158                    members
159                        .iter()
160                        .map(|(name, t)| format!("{}: {}", name, t))
161                        .collect::<Vec<_>>()
162                        .join(", ")
163                )
164            }
165            ConcreteType::Array { inner, size } => {
166                format!("[{}; {}]", inner, size)
167            }
168            ConcreteType::Enum { options } => {
169                let inner = options
170                    .iter()
171                    .map(|o| {
172                        let param_list =
173                            o.1.iter()
174                                .map(|t| format!("{}", t.1))
175                                .collect::<Vec<_>>()
176                                .join(",");
177                        format!("{} ( {} )", o.0 .0, param_list)
178                    })
179                    .collect::<Vec<_>>()
180                    .join(",");
181                format!("enum {{{}}}", inner)
182            }
183            ConcreteType::Single { base, params } => {
184                let params_str = if params.is_empty() {
185                    String::new()
186                } else {
187                    params
188                        .iter()
189                        .map(|p| format!("{}", p))
190                        .collect::<Vec<_>>()
191                        .join(", ")
192                };
193
194                format!("{}{}", base, params_str)
195            }
196            ConcreteType::Integer(size) => {
197                format!("{}", size)
198            }
199            ConcreteType::Bool(val) => {
200                format!("{}", val)
201            }
202            ConcreteType::String(val) => {
203                format!("{:?}", val)
204            }
205            ConcreteType::Backward(inner) => {
206                format!("inv &{}", inner)
207            }
208            ConcreteType::Wire(inner) => {
209                format!("&{}", inner)
210            }
211        };
212
213        write!(f, "{str}")
214    }
215}
216
217#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
218pub enum KnownType {
219    Named(NameID),
220    Integer(BigInt),
221    Bool(bool),
222    String(String),
223    Tuple,
224    Array,
225    Wire,
226    Inverted,
227    // A special type that unifies with anything to produce another error. Doing code generation
228    // on this type will produce invalid code.
229    Error,
230}
231
232impl KnownType {
233    pub fn integer(val: u64) -> Self {
234        Self::Integer(val.to_bigint())
235    }
236}