1use crate::{
2 diagnostics::Diagnostics,
3 fun::{num_to_name, Book, FanKind, Name, Op, Pattern, Term},
4 hvm::{net_trees, tree_children},
5 maybe_grow,
6 net::CtrKind::{self, *},
7};
8use hvm::ast::{Net, Tree};
9use loaned::LoanedMut;
10use std::{
11 collections::{hash_map::Entry, HashMap},
12 ops::{Index, IndexMut},
13};
14
15#[derive(Debug, Clone)]
16pub struct ViciousCycleErr;
17
18pub fn book_to_hvm(book: &Book, diags: &mut Diagnostics) -> Result<(hvm::ast::Book, Labels), Diagnostics> {
19 let mut hvm_book = hvm::ast::Book { defs: Default::default() };
20 let mut labels = Labels::default();
21
22 let main = book.entrypoint.as_ref();
23
24 for def in book.defs.values() {
25 for rule in def.rules.iter() {
26 let net = term_to_hvm(&rule.body, &mut labels);
27
28 let name = if main.is_some_and(|m| &def.name == m) {
29 book.hvm_entrypoint().to_string()
30 } else {
31 def.name.0.to_string()
32 };
33
34 match net {
35 Ok(net) => {
36 hvm_book.defs.insert(name, net);
37 }
38 Err(err) => diags.add_inet_error(err, name),
39 }
40 }
41 }
42
43 for def in book.hvm_defs.values() {
45 hvm_book.defs.insert(def.name.to_string(), def.body.clone());
46 }
47
48 labels.con.finish();
49 labels.dup.finish();
50
51 diags.fatal((hvm_book, labels))
52}
53
54pub fn term_to_hvm(term: &Term, labels: &mut Labels) -> Result<Net, String> {
56 let mut net = Net { root: Tree::Era, rbag: Default::default() };
57
58 let mut state = EncodeTermState {
59 lets: Default::default(),
60 vars: Default::default(),
61 wires: Default::default(),
62 redexes: Default::default(),
63 name_idx: 0,
64 created_nodes: 0,
65 labels,
66 };
67
68 state.encode_term(term, Place::Hole(&mut net.root));
69 LoanedMut::from(std::mem::take(&mut state.redexes)).place(&mut net.rbag);
70
71 let EncodeTermState { created_nodes, .. } = { state };
72
73 let found_nodes = net_trees(&net).map(count_nodes).sum::<usize>();
74 if created_nodes != found_nodes {
75 return Err("Found term that compiles into an inet with a vicious cycle".into());
76 }
77
78 Ok(net)
79}
80
81#[derive(Debug)]
82struct EncodeTermState<'t, 'l> {
83 lets: Vec<(&'t Pattern, &'t Term)>,
84 vars: HashMap<(bool, Name), Place<'t>>,
85 wires: Vec<Option<Place<'t>>>,
86 redexes: Vec<LoanedMut<'t, (bool, Tree, Tree)>>,
87 name_idx: u64,
88 created_nodes: usize,
89 labels: &'l mut Labels,
90}
91
92fn count_nodes(tree: &Tree) -> usize {
93 maybe_grow(|| {
94 usize::from(tree_children(tree).next().is_some()) + tree_children(tree).map(count_nodes).sum::<usize>()
95 })
96}
97
98#[derive(Debug)]
99enum Place<'t> {
100 Tree(LoanedMut<'t, Tree>),
101 Hole(&'t mut Tree),
102 Wire(usize),
103}
104
105impl<'t> EncodeTermState<'t, '_> {
106 fn encode_term(&mut self, term: &'t Term, up: Place<'t>) {
112 maybe_grow(|| {
113 match term {
114 Term::Era => self.link(up, Place::Tree(LoanedMut::new(Tree::Era))),
115 Term::Var { nam } => self.link_var(false, nam, up),
116 Term::Link { nam } => self.link_var(true, nam, up),
117 Term::Ref { nam } => self.link(up, Place::Tree(LoanedMut::new(Tree::Ref { nam: nam.to_string() }))),
118 Term::Num { val } => {
119 let val = hvm::ast::Numb(val.to_bits());
120 self.link(up, Place::Tree(LoanedMut::new(Tree::Num { val })))
121 }
122 Term::Lam { tag, pat, bod } => {
128 let kind = Con(self.labels.con.generate(tag));
129 let node = self.new_ctr(kind);
130 self.link(up, node.0);
131 self.encode_pat(pat, node.1);
132 self.encode_term(bod, node.2);
133 }
134 Term::App { tag, fun, arg } => {
140 let kind = Con(self.labels.con.generate(tag));
141 let node = self.new_ctr(kind);
142 self.encode_term(fun, node.0);
143 self.encode_term(arg, node.1);
144 self.link(up, node.2);
145 }
146 Term::Swt { arg, bnd, with_bnd, with_arg, pred, arms, } => {
148 assert!(bnd.is_none());
150 assert!(with_bnd.is_empty());
151 assert!(with_arg.is_empty());
152 assert!(pred.is_none());
153 assert!(arms.len() == 2);
154
155 self.created_nodes += 2;
156 let loaned = Tree::Swi { fst: Box::new(Tree::Con{fst: Box::new(Tree::Era), snd: Box::new(Tree::Era)}), snd: Box::new(Tree::Era)};
157 let ((zero, succ, out), node) =
158 LoanedMut::loan_with(loaned, |t, l| {
159 let Tree::Swi { fst, snd: out } = t else { unreachable!() };
160 let Tree::Con { fst:zero, snd: succ } = fst.as_mut() else { unreachable!() };
161 (l.loan_mut(zero), l.loan_mut(succ), l.loan_mut(out))
162 });
163
164 self.encode_term(arg, Place::Tree(node));
165 self.encode_term(&arms[0], Place::Hole(zero));
166 self.encode_term(&arms[1], Place::Hole(succ));
167 self.link(up, Place::Hole(out));
168 }
169 Term::Let { pat, val, nxt } => {
170 self.lets.push((pat, val));
173 self.encode_term(nxt, up);
174 }
175 Term::Fan { fan, tag, els } => {
176 let kind = self.fan_kind(fan, tag);
177 self.make_node_list(kind, up, els.iter().map(|el| |slf: &mut Self, up| slf.encode_term(el, up)));
178 }
179 Term::Oper { opr, fst, snd } => {
181 match (fst.as_ref(), snd.as_ref()) {
182 (Term::Num { val }, snd) => {
184 let val = val.to_bits();
185 let val = hvm::ast::Numb((val & !0x1F) | opr.to_native_tag() as u32);
186 let fst = Place::Tree(LoanedMut::new(Tree::Num { val }));
187 let node = self.new_opr();
188 self.link(fst, node.0);
189 self.encode_term(snd, node.1);
190 self.encode_le_ge_opers(opr, up, node.2);
191 }
192 (fst, Term::Num { val }) => {
194 if let Op::POW = opr {
195 let opr_val = hvm::ast::Numb(hvm::hvm::Numb::new_sym(opr.to_native_tag()).0);
197 let oper = Place::Tree(LoanedMut::new(Tree::Num { val: opr_val }));
198 let node1 = self.new_opr();
199 self.encode_term(fst, node1.0);
200 self.link(oper, node1.1);
201 let node2 = self.new_opr();
202 self.link(node1.2, node2.0);
203 self.encode_term(snd, node2.1);
204 self.encode_le_ge_opers(opr, up, node2.2);
205 } else {
206 let val = val.to_bits();
208 let val = hvm::ast::Numb((val & !0x1F) | flip_sym(opr.to_native_tag()) as u32);
209 let snd = Place::Tree(LoanedMut::new(Tree::Num { val }));
210 let node = self.new_opr();
211 self.encode_term(fst, node.0);
212 self.link(snd, node.1);
213 self.encode_le_ge_opers(opr, up, node.2);
214 }
215 }
216 (fst, snd) => {
218 let opr_val = hvm::ast::Numb(hvm::hvm::Numb::new_sym(opr.to_native_tag()).0);
219 let oper = Place::Tree(LoanedMut::new(Tree::Num { val: opr_val }));
220 let node1 = self.new_opr();
221 self.encode_term(fst, node1.0);
222 self.link(oper, node1.1);
223 let node2 = self.new_opr();
224 self.link(node1.2, node2.0);
225 self.encode_term(snd, node2.1);
226 self.encode_le_ge_opers(opr, up, node2.2);
227 }
228 }
229 }
230 Term::Use { .. } | Term::With { .. } | Term::Ask { .. } | Term::Mat { .. } | Term::Bend { .. } | Term::Fold { .. } | Term::Open { .. } | Term::Nat { .. } | Term::Str { .. } | Term::List { .. } | Term::Def { .. } | Term::Err => unreachable!(),
242 }
243 while let Some((pat, val)) = self.lets.pop() {
244 let wire = self.new_wire();
245 self.encode_term(val, Place::Wire(wire));
246 self.encode_pat(pat, Place::Wire(wire));
247 }
248 })
249 }
250
251 fn encode_le_ge_opers(&mut self, opr: &Op, up: Place<'t>, node: Place<'t>) {
252 match opr {
253 Op::LE | Op::GE => {
254 let node_eq = self.new_opr();
255 let eq_val =
256 Place::Tree(LoanedMut::new(Tree::Num { val: hvm::ast::Numb(Op::EQ.to_native_tag() as u32) }));
257 self.link(eq_val, node_eq.0);
258 self.link(node_eq.1, node);
259 self.link(up, node_eq.2);
260 }
261 _ => self.link(up, node),
262 }
263 }
264
265 fn encode_pat(&mut self, pat: &Pattern, up: Place<'t>) {
266 maybe_grow(|| match pat {
267 Pattern::Var(None) => self.link(up, Place::Tree(LoanedMut::new(Tree::Era))),
268 Pattern::Var(Some(name)) => self.link_var(false, name, up),
269 Pattern::Chn(name) => self.link_var(true, name, up),
270 Pattern::Fan(fan, tag, els) => {
271 let kind = self.fan_kind(fan, tag);
272 self.make_node_list(kind, up, els.iter().map(|el| |slf: &mut Self, up| slf.encode_pat(el, up)));
273 }
274 Pattern::Ctr(_, _) | Pattern::Num(_) | Pattern::Lst(_) | Pattern::Str(_) => unreachable!(),
275 })
276 }
277
278 fn link(&mut self, a: Place<'t>, b: Place<'t>) {
279 match (a, b) {
280 (Place::Tree(a), Place::Tree(b)) => {
281 self.redexes.push(LoanedMut::merge((false, Tree::Era, Tree::Era), |r, m| {
282 m.place(b, &mut r.1);
283 m.place(a, &mut r.2);
284 }))
285 }
286 (Place::Tree(t), Place::Hole(h)) | (Place::Hole(h), Place::Tree(t)) => {
287 t.place(h);
288 }
289 (Place::Hole(a), Place::Hole(b)) => {
290 let var = Tree::Var { nam: num_to_name(self.name_idx) };
291 self.name_idx += 1;
292 *a = var.clone();
293 *b = var;
294 }
295 (Place::Wire(v), p) | (p, Place::Wire(v)) => {
296 let v = &mut self.wires[v];
297 match v.take() {
298 Some(q) => self.link(p, q),
299 None => *v = Some(p),
300 }
301 }
302 }
303 }
304
305 fn new_ctr(&mut self, kind: CtrKind) -> (Place<'t>, Place<'t>, Place<'t>) {
306 self.created_nodes += 1;
307 let node = match kind {
308 CtrKind::Con(None) => Tree::Con { fst: Box::new(Tree::Era), snd: Box::new(Tree::Era) },
309 CtrKind::Dup(0) => Tree::Dup { fst: Box::new(Tree::Era), snd: Box::new(Tree::Era) },
310 CtrKind::Tup(None) => Tree::Con { fst: Box::new(Tree::Era), snd: Box::new(Tree::Era) },
311 _ => unreachable!(),
312 };
313 let ((a, b), node) = LoanedMut::loan_with(node, |t, l| match t {
314 Tree::Con { fst, snd } => (l.loan_mut(fst), l.loan_mut(snd)),
315 Tree::Dup { fst, snd } => (l.loan_mut(fst), l.loan_mut(snd)),
316 _ => unreachable!(),
317 });
318 (Place::Tree(node), Place::Hole(a), Place::Hole(b))
319 }
320
321 fn new_opr(&mut self) -> (Place<'t>, Place<'t>, Place<'t>) {
322 self.created_nodes += 1;
323 let ((fst, snd), node) =
324 LoanedMut::loan_with(Tree::Opr { fst: Box::new(Tree::Era), snd: Box::new(Tree::Era) }, |t, l| {
325 let Tree::Opr { fst, snd } = t else { unreachable!() };
326 (l.loan_mut(fst), l.loan_mut(snd))
327 });
328 (Place::Tree(node), Place::Hole(fst), Place::Hole(snd))
329 }
330
331 fn make_node_list(
333 &mut self,
334 kind: CtrKind,
335 mut up: Place<'t>,
336 mut els: impl DoubleEndedIterator<Item = impl FnOnce(&mut Self, Place<'t>)>,
337 ) {
338 let last = els.next_back().unwrap();
339 for item in els {
340 let node = self.new_ctr(kind);
341 self.link(up, node.0);
342 item(self, node.1);
343 up = node.2;
344 }
345 last(self, up);
346 }
347
348 fn new_wire(&mut self) -> usize {
349 let i = self.wires.len();
350 self.wires.push(None);
351 i
352 }
353
354 fn fan_kind(&mut self, fan: &FanKind, tag: &crate::fun::Tag) -> CtrKind {
355 let lab = self.labels[*fan].generate(tag);
356 if *fan == FanKind::Tup {
357 Tup(lab)
358 } else {
359 Dup(lab.unwrap())
360 }
361 }
362
363 fn link_var(&mut self, global: bool, name: &Name, place: Place<'t>) {
364 match self.vars.entry((global, name.clone())) {
365 Entry::Occupied(e) => {
366 let other = e.remove();
367 self.link(place, other);
368 }
369 Entry::Vacant(e) => {
370 e.insert(place);
371 }
372 }
373 }
374}
375
376#[derive(Debug, Default, Clone)]
377pub struct Labels {
378 pub con: LabelGenerator,
379 pub dup: LabelGenerator,
380 pub tup: LabelGenerator,
381}
382
383#[derive(Debug, Default, Clone)]
384pub struct LabelGenerator {
385 pub next: u16,
386 pub name_to_label: HashMap<Name, u16>,
387 pub label_to_name: HashMap<u16, Name>,
388}
389
390impl Index<FanKind> for Labels {
391 type Output = LabelGenerator;
392
393 fn index(&self, fan: FanKind) -> &Self::Output {
394 match fan {
395 FanKind::Tup => &self.tup,
396 FanKind::Dup => &self.dup,
397 }
398 }
399}
400
401impl IndexMut<FanKind> for Labels {
402 fn index_mut(&mut self, fan: FanKind) -> &mut Self::Output {
403 match fan {
404 FanKind::Tup => &mut self.tup,
405 FanKind::Dup => &mut self.dup,
406 }
407 }
408}
409
410impl LabelGenerator {
411 fn generate(&mut self, tag: &crate::fun::Tag) -> Option<u16> {
414 use crate::fun::Tag;
415 match tag {
416 Tag::Named(_name) => {
417 todo!("Named tags not implemented for hvm32");
418 }
427 Tag::Numeric(lab) => Some(*lab),
428 Tag::Auto => Some(0),
429 Tag::Static => None,
430 }
431 }
432
433 pub fn to_tag(&self, label: Option<u16>) -> crate::fun::Tag {
434 use crate::fun::Tag;
435 match label {
436 Some(label) => match self.label_to_name.get(&label) {
437 Some(name) => Tag::Named(name.clone()),
438 None => {
439 if label == 0 {
440 Tag::Auto
441 } else {
442 Tag::Numeric(label)
443 }
444 }
445 },
446 None => Tag::Static,
447 }
448 }
449
450 fn finish(&mut self) {
451 self.next = u16::MAX;
452 self.name_to_label.clear();
453 }
454}
455
456impl Op {
457 fn to_native_tag(self) -> hvm::hvm::Tag {
458 match self {
459 Op::ADD => hvm::hvm::OP_ADD,
460 Op::SUB => hvm::hvm::OP_SUB,
461 Op::MUL => hvm::hvm::OP_MUL,
462 Op::DIV => hvm::hvm::OP_DIV,
463 Op::REM => hvm::hvm::OP_REM,
464 Op::EQ => hvm::hvm::OP_EQ,
465 Op::NEQ => hvm::hvm::OP_NEQ,
466 Op::LT => hvm::hvm::OP_LT,
467 Op::GT => hvm::hvm::OP_GT,
468 Op::AND => hvm::hvm::OP_AND,
469 Op::OR => hvm::hvm::OP_OR,
470 Op::XOR => hvm::hvm::OP_XOR,
471 Op::SHL => hvm::hvm::OP_SHL,
472 Op::SHR => hvm::hvm::OP_SHR,
473
474 Op::POW => hvm::hvm::OP_XOR,
475
476 Op::LE => hvm::hvm::OP_GT,
477 Op::GE => hvm::hvm::OP_LT,
478 }
479 }
480}
481
482fn flip_sym(tag: hvm::hvm::Tag) -> hvm::hvm::Tag {
483 match tag {
484 hvm::hvm::OP_SUB => hvm::hvm::FP_SUB,
485 hvm::hvm::FP_SUB => hvm::hvm::OP_SUB,
486 hvm::hvm::OP_DIV => hvm::hvm::FP_DIV,
487 hvm::hvm::FP_DIV => hvm::hvm::OP_DIV,
488 hvm::hvm::OP_REM => hvm::hvm::FP_REM,
489 hvm::hvm::FP_REM => hvm::hvm::OP_REM,
490 hvm::hvm::OP_LT => hvm::hvm::OP_GT,
491 hvm::hvm::OP_GT => hvm::hvm::OP_LT,
492 hvm::hvm::OP_SHL => hvm::hvm::FP_SHL,
493 hvm::hvm::FP_SHL => hvm::hvm::OP_SHL,
494 hvm::hvm::OP_SHR => hvm::hvm::FP_SHR,
495 hvm::hvm::FP_SHR => hvm::hvm::OP_SHR,
496 _ => tag,
497 }
498}