1#[derive(Debug, Clone, PartialEq, Eq, Hash)]
8pub enum Type {
9 Int,
11 Float,
13 Bool,
15 String,
17 Quotation(Box<Effect>),
21 Closure {
25 effect: Box<Effect>,
27 captures: Vec<Type>,
30 },
31 Var(String),
34}
35
36#[derive(Debug, Clone, PartialEq, Eq, Hash)]
38pub enum StackType {
39 Empty,
41
42 Cons {
45 rest: Box<StackType>,
47 top: Type,
49 },
50
51 RowVar(String),
54}
55
56#[derive(Debug, Clone, PartialEq, Eq, Hash)]
61pub struct Effect {
62 pub inputs: StackType,
64 pub outputs: StackType,
66}
67
68impl StackType {
69 pub fn empty() -> Self {
71 StackType::Empty
72 }
73
74 pub fn singleton(ty: Type) -> Self {
76 StackType::Cons {
77 rest: Box::new(StackType::Empty),
78 top: ty,
79 }
80 }
81
82 pub fn push(self, ty: Type) -> Self {
84 StackType::Cons {
85 rest: Box::new(self),
86 top: ty,
87 }
88 }
89
90 pub fn from_vec(types: Vec<Type>) -> Self {
92 types
93 .into_iter()
94 .fold(StackType::Empty, |stack, ty| stack.push(ty))
95 }
96
97 pub fn pop(self) -> Option<(StackType, Type)> {
99 match self {
100 StackType::Cons { rest, top } => Some((*rest, top)),
101 _ => None,
102 }
103 }
104}
105
106impl Effect {
107 pub fn new(inputs: StackType, outputs: StackType) -> Self {
109 Effect { inputs, outputs }
110 }
111}
112
113impl std::fmt::Display for Type {
114 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
115 match self {
116 Type::Int => write!(f, "Int"),
117 Type::Float => write!(f, "Float"),
118 Type::Bool => write!(f, "Bool"),
119 Type::String => write!(f, "String"),
120 Type::Quotation(effect) => write!(f, "[{}]", effect),
121 Type::Closure { effect, captures } => {
122 let cap_str: Vec<_> = captures.iter().map(|t| format!("{}", t)).collect();
123 write!(f, "Closure[{}, captures=({})]", effect, cap_str.join(", "))
124 }
125 Type::Var(name) => write!(f, "{}", name),
126 }
127 }
128}
129
130impl std::fmt::Display for StackType {
131 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
132 match self {
133 StackType::Empty => write!(f, "()"),
134 StackType::RowVar(name) => write!(f, "..{}", name),
135 StackType::Cons { rest, top } => {
136 let mut types = vec![format!("{}", top)];
138 let mut current = rest.as_ref();
139 loop {
140 match current {
141 StackType::Empty => break,
142 StackType::RowVar(name) => {
143 types.push(format!("..{}", name));
144 break;
145 }
146 StackType::Cons { rest, top } => {
147 types.push(format!("{}", top));
148 current = rest;
149 }
150 }
151 }
152 types.reverse();
153 write!(f, "({})", types.join(" "))
154 }
155 }
156 }
157}
158
159impl std::fmt::Display for Effect {
160 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
161 write!(f, "{} -- {}", self.inputs, self.outputs)
162 }
163}
164
165#[cfg(test)]
166mod tests {
167 use super::*;
168
169 #[test]
170 fn test_empty_stack() {
171 let stack = StackType::empty();
172 assert_eq!(stack, StackType::Empty);
173 }
174
175 #[test]
176 fn test_singleton_stack() {
177 let stack = StackType::singleton(Type::Int);
178 assert_eq!(
179 stack,
180 StackType::Cons {
181 rest: Box::new(StackType::Empty),
182 top: Type::Int
183 }
184 );
185 }
186
187 #[test]
188 fn test_push_pop() {
189 let stack = StackType::empty().push(Type::Int).push(Type::Bool);
190
191 let (rest, top) = stack.pop().unwrap();
192 assert_eq!(top, Type::Bool);
193
194 let (rest2, top2) = rest.pop().unwrap();
195 assert_eq!(top2, Type::Int);
196 assert_eq!(rest2, StackType::Empty);
197 }
198
199 #[test]
200 fn test_from_vec() {
201 let stack = StackType::from_vec(vec![Type::Int, Type::Bool, Type::String]);
202
203 let (rest, top) = stack.pop().unwrap();
205 assert_eq!(top, Type::String);
206
207 let (rest2, top2) = rest.pop().unwrap();
208 assert_eq!(top2, Type::Bool);
209
210 let (rest3, top3) = rest2.pop().unwrap();
211 assert_eq!(top3, Type::Int);
212 assert_eq!(rest3, StackType::Empty);
213 }
214
215 #[test]
216 fn test_row_variable() {
217 let stack = StackType::Cons {
218 rest: Box::new(StackType::RowVar("a".to_string())),
219 top: Type::Int,
220 };
221
222 let (rest, top) = stack.pop().unwrap();
224 assert_eq!(top, Type::Int);
225 assert_eq!(rest, StackType::RowVar("a".to_string()));
226 }
227
228 #[test]
229 fn test_effect() {
230 let effect = Effect::new(
232 StackType::singleton(Type::Int),
233 StackType::singleton(Type::Bool),
234 );
235
236 assert_eq!(effect.inputs, StackType::singleton(Type::Int));
237 assert_eq!(effect.outputs, StackType::singleton(Type::Bool));
238 }
239
240 #[test]
241 fn test_polymorphic_effect() {
242 let inputs = StackType::Cons {
244 rest: Box::new(StackType::RowVar("a".to_string())),
245 top: Type::Int,
246 };
247
248 let outputs = StackType::Cons {
249 rest: Box::new(StackType::RowVar("a".to_string())),
250 top: Type::Bool,
251 };
252
253 let effect = Effect::new(inputs, outputs);
254
255 assert!(matches!(effect.inputs, StackType::Cons { .. }));
257 assert!(matches!(effect.outputs, StackType::Cons { .. }));
258 }
259}