spade_types/
lib.rs

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