1use crate::types::*;
4use indexmap::IndexMap;
5
6#[derive(Debug, Clone)]
7pub struct TypeDef {
8 pub params: Vec<String>,
9 pub kind: TypeDefKind,
10}
11
12#[derive(Debug, Clone)]
13pub enum TypeDefKind {
14 Union(IndexMap<String, Option<Ty>>),
16 Alias(Ty),
18 Opaque,
20}
21
22#[derive(Debug, Clone, Default)]
23pub struct TypeEnv {
24 pub types: IndexMap<String, TypeDef>,
26 pub ctor_to_type: IndexMap<String, String>,
28}
29
30impl TypeEnv {
31 pub fn new_with_builtins() -> Self {
32 let mut e = TypeEnv::default();
33 let mut r_variants = IndexMap::new();
35 r_variants.insert("Ok".into(), Some(Ty::Var(0))); r_variants.insert("Err".into(), Some(Ty::Var(1))); e.types.insert("Result".into(), TypeDef {
38 params: vec!["T".into(), "E".into()],
39 kind: TypeDefKind::Union(r_variants),
40 });
41 e.ctor_to_type.insert("Ok".into(), "Result".into());
42 e.ctor_to_type.insert("Err".into(), "Result".into());
43
44 let mut o_variants = IndexMap::new();
46 o_variants.insert("Some".into(), Some(Ty::Var(0))); o_variants.insert("None".into(), None);
48 e.types.insert("Option".into(), TypeDef {
49 params: vec!["T".into()],
50 kind: TypeDefKind::Union(o_variants),
51 });
52 e.ctor_to_type.insert("Some".into(), "Option".into());
53 e.ctor_to_type.insert("None".into(), "Option".into());
54
55 e.types.insert("Nil".into(), TypeDef {
57 params: vec![],
58 kind: TypeDefKind::Alias(Ty::Unit),
59 });
60
61 e.types.insert("Map".into(), TypeDef { params: vec!["K".into(), "V".into()], kind: TypeDefKind::Opaque });
63 e.types.insert("Set".into(), TypeDef { params: vec!["T".into()], kind: TypeDefKind::Opaque });
64
65 e.types.insert("Stream".into(), TypeDef { params: vec!["T".into()], kind: TypeDefKind::Opaque });
72
73 let mut tz_variants = IndexMap::new();
79 tz_variants.insert("Utc".into(), None);
80 tz_variants.insert("Local".into(), None);
81 tz_variants.insert("Offset".into(), Some(Ty::int()));
82 tz_variants.insert("Iana".into(), Some(Ty::str()));
83 e.types.insert("Tz".into(), TypeDef {
84 params: vec![],
85 kind: TypeDefKind::Union(tz_variants),
86 });
87 for ctor in &["Utc", "Local", "Offset", "Iana"] {
88 e.ctor_to_type.insert((*ctor).into(), "Tz".into());
89 }
90
91 let mut http_err_variants = IndexMap::new();
97 http_err_variants.insert("NetworkError".into(), Some(Ty::str()));
98 http_err_variants.insert("TimeoutError".into(), None);
99 http_err_variants.insert("TlsError".into(), Some(Ty::str()));
100 http_err_variants.insert("DecodeError".into(), Some(Ty::str()));
101 e.types.insert("HttpError".into(), TypeDef {
102 params: vec![],
103 kind: TypeDefKind::Union(http_err_variants),
104 });
105 for ctor in &["NetworkError", "TimeoutError", "TlsError", "DecodeError"] {
106 e.ctor_to_type.insert((*ctor).into(), "HttpError".into());
107 }
108
109 let mut req_fields = IndexMap::new();
118 req_fields.insert("method".into(), Ty::str());
119 req_fields.insert("url".into(), Ty::str());
120 req_fields.insert("headers".into(), Ty::Con("Map".into(), vec![Ty::str(), Ty::str()]));
121 req_fields.insert("body".into(), Ty::Con("Option".into(), vec![Ty::bytes()]));
122 req_fields.insert("timeout_ms".into(), Ty::Con("Option".into(), vec![Ty::int()]));
123 e.types.insert("HttpRequest".into(), TypeDef {
124 params: vec![],
125 kind: TypeDefKind::Alias(Ty::Record(req_fields)),
126 });
127
128 let mut resp_fields = IndexMap::new();
132 resp_fields.insert("status".into(), Ty::int());
133 resp_fields.insert("headers".into(), Ty::Con("Map".into(), vec![Ty::str(), Ty::str()]));
134 resp_fields.insert("body".into(), Ty::bytes());
135 e.types.insert("HttpResponse".into(), TypeDef {
136 params: vec![],
137 kind: TypeDefKind::Alias(Ty::Record(resp_fields)),
138 });
139
140 let mut mat_fields = IndexMap::new();
147 mat_fields.insert("rows".into(), Ty::int());
148 mat_fields.insert("cols".into(), Ty::int());
149 mat_fields.insert("data".into(), Ty::List(Box::new(Ty::float())));
150 e.types.insert("Matrix".into(), TypeDef {
151 params: vec![],
152 kind: TypeDefKind::Alias(Ty::Record(mat_fields)),
153 });
154
155 e
156 }
157
158 pub fn add_user_type(&mut self, name: &str, decl: lex_ast::TypeDecl) -> Result<(), String> {
159 match &decl.definition {
160 lex_ast::TypeExpr::Union { variants } => {
161 let mut vmap = IndexMap::new();
162 for v in variants {
163 let payload = v.payload.as_ref().map(|p| ty_from_canon(p, &decl.params));
164 vmap.insert(v.name.clone(), payload);
165 self.ctor_to_type.insert(v.name.clone(), name.to_string());
166 }
167 self.types.insert(name.to_string(), TypeDef {
168 params: decl.params.clone(),
169 kind: TypeDefKind::Union(vmap),
170 });
171 }
172 other => {
173 let ty = ty_from_canon(other, &decl.params);
174 self.types.insert(name.to_string(), TypeDef {
175 params: decl.params.clone(),
176 kind: TypeDefKind::Alias(ty),
177 });
178 }
179 }
180 Ok(())
181 }
182}
183
184pub fn ty_from_canon(t: &lex_ast::TypeExpr, params: &[String]) -> Ty {
188 match t {
189 lex_ast::TypeExpr::Named { name, args } => {
190 if let Some(idx) = params.iter().position(|p| p == name) {
192 if !args.is_empty() {
193 return Ty::Con(name.clone(), args.iter().map(|a| ty_from_canon(a, params)).collect());
195 }
196 return Ty::Var(idx as u32);
197 }
198 match name.as_str() {
200 "Int" => return Ty::int(),
201 "Float" => return Ty::float(),
202 "Bool" => return Ty::bool(),
203 "Str" => return Ty::str(),
204 "Bytes" => return Ty::bytes(),
205 "Unit" | "Nil" => return Ty::Unit,
206 "Never" => return Ty::Never,
207 "List" if args.len() == 1 => return Ty::List(Box::new(ty_from_canon(&args[0], params))),
208 "Tuple" => return Ty::Tuple(args.iter().map(|a| ty_from_canon(a, params)).collect()),
213 _ => {}
214 }
215 Ty::Con(name.clone(), args.iter().map(|a| ty_from_canon(a, params)).collect())
216 }
217 lex_ast::TypeExpr::Record { fields } => {
218 let mut m = IndexMap::new();
219 for f in fields { m.insert(f.name.clone(), ty_from_canon(&f.ty, params)); }
220 Ty::Record(m)
221 }
222 lex_ast::TypeExpr::Tuple { items } => Ty::Tuple(items.iter().map(|t| ty_from_canon(t, params)).collect()),
223 lex_ast::TypeExpr::Function { params: ps, effects, ret } => {
224 let effs = EffectSet {
226 concrete: {
227 let mut s = std::collections::BTreeSet::new();
228 for e in effects {
229 let arg = e.arg.as_ref().map(|a| match a {
230 lex_ast::EffectArg::Str { value } => crate::types::EffectArg::Str(value.clone()),
231 lex_ast::EffectArg::Int { value } => crate::types::EffectArg::Int(*value),
232 lex_ast::EffectArg::Ident { value } => crate::types::EffectArg::Ident(value.clone()),
233 });
234 s.insert(crate::types::EffectKind { name: e.name.clone(), arg });
235 }
236 s
237 },
238 var: None,
239 };
240 Ty::Function {
241 params: ps.iter().map(|t| ty_from_canon(t, params)).collect(),
242 effects: effs,
243 ret: Box::new(ty_from_canon(ret, params)),
244 }
245 }
246 lex_ast::TypeExpr::Union { .. } => {
247 Ty::Unit
249 }
250 lex_ast::TypeExpr::Refined { base, .. } => {
251 ty_from_canon(base, params)
261 }
262 }
263}