1use super::level::{LevelId, Levels, LevelsId};
20use super::name::{NameId, Names};
21use super::nat::Nat;
22use rustc_hash::FxHashMap as FxMap;
23use std::rc::Rc;
24
25#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
26pub struct ExprId(pub u32);
27
28pub type Args = smallvec::SmallVec<[ExprId; 8]>;
30
31#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
32pub struct NatId(pub u32);
33
34#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
35pub struct StrId(pub u32);
36
37#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
38pub struct LitId(pub u32);
39
40#[derive(Clone, PartialEq, Eq, Hash, Debug)]
44pub enum Lit {
45 Int(i64),
46 BigInt(logicaffeine_base::BigInt),
47 Float(u64),
48 Duration(i64),
49 Date(i32),
50 Moment(i64),
51}
52
53#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
54pub enum Node {
55 BVar(u32),
56 FVar(u32),
57 Sort(LevelId),
58 Const(NameId, LevelsId),
59 App(ExprId, ExprId),
60 Lam(ExprId, ExprId),
61 Pi(ExprId, ExprId),
62 Let(ExprId, ExprId, ExprId),
63 NatLit(NatId),
64 StrLit(StrId),
65 Proj(NameId, u32, ExprId),
66 Match(ExprId, ExprId, ExprId),
69 Fix(ExprId),
71 MutualFix(ExprId, u32),
74 Seq(ExprId, ExprId),
77 Nil,
78 Lit(LitId),
80}
81
82const HAS_FVAR: u8 = 1;
83const HAS_LPARAM: u8 = 2;
84const WIDE_BVAR: u8 = 4;
87
88impl Node {
89 #[inline]
92 fn hash(&self) -> u64 {
93 let (tag, a, b, c) = match *self {
94 Node::BVar(i) => (1u64, i as u64, 0, 0),
95 Node::FVar(i) => (2, i as u64, 0, 0),
96 Node::Sort(l) => (3, l.0 as u64, 0, 0),
97 Node::Const(n, ls) => (4, n.0 as u64, ls.0 as u64, 0),
98 Node::App(f, a) => (5, f.0 as u64, a.0 as u64, 0),
99 Node::Lam(t, b) => (6, t.0 as u64, b.0 as u64, 0),
100 Node::Pi(t, b) => (7, t.0 as u64, b.0 as u64, 0),
101 Node::Let(t, v, b) => (8, t.0 as u64, v.0 as u64, b.0 as u64),
102 Node::NatLit(n) => (9, n.0 as u64, 0, 0),
103 Node::StrLit(s) => (10, s.0 as u64, 0, 0),
104 Node::Proj(n, i, e) => (11, n.0 as u64, i as u64, e.0 as u64),
105 Node::Match(d, m, c) => (12, d.0 as u64, m.0 as u64, c.0 as u64),
106 Node::Fix(b) => (13, b.0 as u64, 0, 0),
107 Node::MutualFix(ds, i) => (14, ds.0 as u64, i as u64, 0),
108 Node::Seq(h, t) => (15, h.0 as u64, t.0 as u64, 0),
109 Node::Nil => (16, 0, 0, 0),
110 Node::Lit(l) => (17, l.0 as u64, 0, 0),
111 };
112 let mut h = (tag ^ (a << 8)).wrapping_mul(0x9E37_79B9_7F4A_7C15);
113 h = (h ^ b ^ (c << 32)).wrapping_mul(0xBF58_476D_1CE4_E5B9);
114 h ^ (h >> 29)
115 }
116}
117
118#[derive(Clone)]
125struct Table {
126 slots: Vec<u64>,
127 shift: u32,
128 len: usize,
129 generation: u64,
130}
131
132impl Table {
133 fn new(cap: usize) -> Table {
134 let cap = cap.next_power_of_two().max(16);
135 Table {
136 slots: vec![0; cap],
137 shift: 64 - cap.trailing_zeros(),
138 len: 0,
139 generation: 1,
140 }
141 }
142
143 #[inline]
145 fn is_live(&self, s: u64) -> bool {
146 s >> 32 == self.generation
147 }
148
149 #[inline]
151 fn find_or_vacant(&self, entries: &[Entry], node: &Node, h: u64) -> Result<ExprId, usize> {
152 let mask = self.slots.len() - 1;
153 let mut i = (h >> self.shift) as usize;
154 loop {
155 let s = self.slots[i];
156 if !self.is_live(s) {
157 return Err(i);
158 }
159 let id = s as u32 - 1;
160 if entries[id as usize].node == *node {
161 return Ok(ExprId(id));
162 }
163 i = (i + 1) & mask;
164 }
165 }
166
167 #[inline]
169 fn insert_at(&mut self, entries: &[Entry], slot: Option<usize>, id: ExprId, h: u64) {
170 match slot {
171 Some(i) if (self.len + 1) * 2 <= self.slots.len() => {
172 self.slots[i] = (self.generation << 32) | (id.0 as u64 + 1);
173 self.len += 1;
174 }
175 _ => self.insert(entries, id, h),
176 }
177 }
178
179 fn insert(&mut self, entries: &[Entry], id: ExprId, h: u64) {
180 if (self.len + 1) * 2 > self.slots.len() {
181 self.grow(entries);
182 }
183 self.place(id.0, h);
184 self.len += 1;
185 }
186
187 #[inline]
188 fn place(&mut self, id: u32, h: u64) {
189 let mask = self.slots.len() - 1;
190 let mut i = (h >> self.shift) as usize;
191 while self.is_live(self.slots[i]) {
192 i = (i + 1) & mask;
193 }
194 self.slots[i] = (self.generation << 32) | (id as u64 + 1);
195 }
196
197 fn grow(&mut self, entries: &[Entry]) {
198 let cap = (self.slots.len() * 2).max(16);
199 self.shift = 64 - cap.trailing_zeros();
200 let old = std::mem::replace(&mut self.slots, vec![0; cap]);
201 let old_gen = self.generation;
202 self.generation = 1;
203 for s in old {
204 if s >> 32 == old_gen {
205 let id = s as u32 - 1;
206 self.place(id, entries[id as usize].node.hash());
207 }
208 }
209 }
210
211 fn clear(&mut self) {
212 self.len = 0;
213 self.generation += 1;
214 if self.generation >= u32::MAX as u64 {
215 self.slots.iter_mut().for_each(|s| *s = 0);
216 self.generation = 1;
217 }
218 }
219}
220
221#[derive(Clone)]
224struct PermTable {
225 slots: Vec<u32>,
226 shift: u32,
227 len: usize,
228}
229
230impl PermTable {
231 fn new(cap: usize) -> PermTable {
232 let cap = cap.next_power_of_two().max(16);
233 PermTable {
234 slots: vec![0; cap],
235 shift: 64 - cap.trailing_zeros(),
236 len: 0,
237 }
238 }
239
240 fn reserve(&mut self, entries: &[Entry], n: usize) {
241 while (n + 1) * 2 > self.slots.len() {
242 self.grow(entries);
243 }
244 }
245
246 #[inline]
247 fn find_or_vacant(&self, entries: &[Entry], node: &Node, h: u64) -> Result<ExprId, usize> {
248 let mask = self.slots.len() - 1;
249 let mut i = (h >> self.shift) as usize;
250 loop {
251 let s = self.slots[i];
252 if s == 0 {
253 return Err(i);
254 }
255 if entries[(s - 1) as usize].node == *node {
256 return Ok(ExprId(s - 1));
257 }
258 i = (i + 1) & mask;
259 }
260 }
261
262 #[inline]
263 fn insert_at(&mut self, entries: &[Entry], slot: Option<usize>, id: ExprId, h: u64) {
264 match slot {
265 Some(i) if (self.len + 1) * 2 <= self.slots.len() => self.slots[i] = id.0 + 1,
266 _ => {
267 if (self.len + 1) * 2 > self.slots.len() {
268 self.grow(entries);
269 }
270 self.place(id.0, h);
271 }
272 }
273 self.len += 1;
274 }
275
276 #[inline]
277 fn place(&mut self, id: u32, h: u64) {
278 let mask = self.slots.len() - 1;
279 let mut i = (h >> self.shift) as usize;
280 while self.slots[i] != 0 {
281 i = (i + 1) & mask;
282 }
283 self.slots[i] = id + 1;
284 }
285
286 fn grow(&mut self, entries: &[Entry]) {
287 let cap = (self.slots.len() * 2).max(16);
288 self.shift = 64 - cap.trailing_zeros();
289 let old = std::mem::replace(&mut self.slots, vec![0; cap]);
290 for s in old {
291 if s != 0 {
292 self.place(s - 1, entries[(s - 1) as usize].node.hash());
293 }
294 }
295 }
296}
297
298#[derive(Clone)]
303struct Memo {
304 keys: Vec<u64>,
305 vals: Vec<u32>,
306 gens: Vec<u32>,
307 generation: u32,
308 len: usize,
309 shift: u32,
310}
311
312impl Memo {
313 fn new() -> Memo {
314 let cap = 1 << 10;
315 Memo {
316 keys: vec![0; cap],
317 vals: vec![0; cap],
318 gens: vec![0; cap],
319 generation: 1,
320 len: 0,
321 shift: 64 - 10,
322 }
323 }
324
325 #[inline]
326 fn slot(&self, key: u64) -> usize {
327 (key.wrapping_mul(0x9E37_79B9_7F4A_7C15) >> self.shift) as usize
328 }
329
330 #[inline]
332 fn reset(&mut self) {
333 self.len = 0;
334 self.generation = self.generation.wrapping_add(1);
335 if self.generation == 0 {
336 self.gens.iter_mut().for_each(|g| *g = 0);
337 self.generation = 1;
338 }
339 }
340
341 #[inline]
342 fn get(&self, e: ExprId, off: u32) -> Option<ExprId> {
343 let key = ((off as u64) << 32) | e.0 as u64;
344 let mask = self.keys.len() - 1;
345 let mut i = self.slot(key);
346 while self.gens[i] == self.generation {
347 if self.keys[i] == key {
348 return Some(ExprId(self.vals[i]));
349 }
350 i = (i + 1) & mask;
351 }
352 None
353 }
354
355 #[inline]
356 fn insert(&mut self, e: ExprId, off: u32, r: ExprId) {
357 if (self.len + 1) * 2 > self.keys.len() {
358 self.grow();
359 }
360 let key = ((off as u64) << 32) | e.0 as u64;
361 self.place(key, r.0);
362 self.len += 1;
363 }
364
365 #[inline]
366 fn place(&mut self, key: u64, val: u32) {
367 let mask = self.keys.len() - 1;
368 let mut i = self.slot(key);
369 while self.gens[i] == self.generation {
370 i = (i + 1) & mask;
371 }
372 self.keys[i] = key;
373 self.vals[i] = val;
374 self.gens[i] = self.generation;
375 }
376
377 fn grow(&mut self) {
378 let cap = self.keys.len() * 2;
379 let keys = std::mem::replace(&mut self.keys, vec![0; cap]);
380 let vals = std::mem::replace(&mut self.vals, vec![0; cap]);
381 let gens = std::mem::replace(&mut self.gens, vec![0; cap]);
382 self.shift = 64 - cap.trailing_zeros();
383 let g = self.generation;
384 for i in 0..keys.len() {
385 if gens[i] == g {
386 self.place(keys[i], vals[i]);
387 }
388 }
389 }
390}
391
392const SCRATCH: u32 = 1 << 31;
394
395impl ExprId {
396 #[inline]
397 pub fn is_scratch(self) -> bool {
398 self.0 & SCRATCH != 0
399 }
400}
401
402#[inline]
403fn has_scratch_child(node: &Node) -> bool {
404 match *node {
405 Node::App(a, b) | Node::Lam(a, b) | Node::Pi(a, b) | Node::Seq(a, b) => {
406 (a.0 | b.0) & SCRATCH != 0
407 }
408 Node::Let(a, b, c) | Node::Match(a, b, c) => (a.0 | b.0 | c.0) & SCRATCH != 0,
409 Node::Proj(_, _, a) | Node::Fix(a) | Node::MutualFix(a, _) => a.0 & SCRATCH != 0,
410 _ => false,
411 }
412}
413
414#[derive(Copy, Clone)]
416struct Entry {
417 node: Node,
418 mask: u64,
420 lbr: u32,
421 flags: u8,
422 spine: u16,
426}
427
428const SPINE_UNKNOWN: u16 = u16::MAX;
429
430const _: () = assert!(
431 std::mem::size_of::<Entry>() == 32,
432 "an entry stays half a cache line"
433);
434
435#[derive(Clone, Default)]
437struct Region {
438 entries: Vec<Entry>,
439}
440
441impl Region {
442 fn clear(&mut self) {
443 self.entries.clear();
444 }
445
446 fn len(&self) -> usize {
447 self.entries.len()
448 }
449}
450
451#[derive(Clone)]
452pub struct Store {
453 pub names: Names,
454 pub levels: Levels,
455 perm: Region,
456 temp: Region,
457 persistent: PermTable,
458 scratch: Table,
459 in_scratch: bool,
460 force_persistent: bool,
461 tainted: bool,
463 temp_peak: usize,
465 cached_nodes: usize,
468 nats: Vec<Nat>,
469 nat_index: FxMap<Nat, NatId>,
470 strs: Vec<Rc<str>>,
471 str_index: FxMap<Rc<str>, StrId>,
472 lits: Vec<Lit>,
473 lit_index: FxMap<Lit, LitId>,
474 inst_memo: Memo,
475 lift_memo: Memo,
476 abs_memo: Memo,
477 lp_memo: Memo,
478}
479
480impl Default for Store {
481 fn default() -> Self {
482 Self::new()
483 }
484}
485
486impl Store {
487 pub fn new() -> Store {
488 Store {
489 names: Names::new(),
490 levels: Levels::new(),
491 perm: Region::default(),
492 temp: Region::default(),
493 persistent: PermTable::new(1 << 12),
494 scratch: Table::new(1 << 12),
495 in_scratch: false,
496 force_persistent: false,
497 tainted: false,
498 temp_peak: 0,
499 cached_nodes: 0,
500 nats: Vec::new(),
501 nat_index: FxMap::default(),
502 strs: Vec::new(),
503 str_index: FxMap::default(),
504 lits: Vec::new(),
505 lit_index: FxMap::default(),
506 inst_memo: Memo::new(),
507 lift_memo: Memo::new(),
508 abs_memo: Memo::new(),
509 lp_memo: Memo::new(),
510 }
511 }
512
513 pub fn expr_count(&self) -> usize {
514 self.perm.len() + self.temp.len()
515 }
516
517 pub fn persistent_count(&self) -> usize {
518 self.perm.len()
519 }
520
521 pub fn memory_report(&self) -> Vec<(&'static str, usize)> {
523 let region = |r: &Region| r.entries.capacity() * std::mem::size_of::<Entry>();
524 vec![
525 ("persistent nodes (count)", self.perm.len()),
526 (
527 "persistent nodes from cached instantiations (count)",
528 self.cached_nodes,
529 ),
530 (
531 "largest scratch region (nodes)",
532 self.temp_peak.max(self.temp.len()),
533 ),
534 ("persistent region bytes", region(&self.perm)),
535 ("scratch region bytes", region(&self.temp)),
536 (
537 "persistent table bytes",
538 self.persistent.slots.capacity() * 4,
539 ),
540 ("scratch table bytes", self.scratch.slots.capacity() * 8),
541 ("names (count)", self.names.len()),
542 ("levels (count)", self.levels.len()),
543 ("nat literals (count)", self.nats.len()),
544 ("string literals (count)", self.strs.len()),
545 ("LOGOS literals (count)", self.lits.len()),
546 (
547 "memo bytes",
548 [
549 &self.inst_memo,
550 &self.lift_memo,
551 &self.abs_memo,
552 &self.lp_memo,
553 ]
554 .iter()
555 .map(|m| m.keys.capacity() * 16)
556 .sum(),
557 ),
558 ]
559 }
560
561 pub fn reserve_persistent(&mut self, n: usize) {
564 let total = self.perm.len() + n;
565 self.perm.entries.reserve(n);
566 self.persistent.reserve(&self.perm.entries, total);
567 }
568
569 pub fn begin_scratch(&mut self) {
571 debug_assert!(!self.in_scratch);
572 self.in_scratch = true;
573 }
574
575 pub fn end_scratch(&mut self) {
576 if self.in_scratch {
577 self.temp_peak = self.temp_peak.max(self.temp.len());
578 self.in_scratch = false;
579 self.temp.clear();
580 self.scratch.clear();
581 }
582 }
583
584 pub fn in_scratch(&self) -> bool {
585 self.in_scratch
586 }
587
588 pub fn with_persistent<T>(&mut self, f: impl FnOnce(&mut Store) -> T) -> (T, bool) {
597 let saved_force = std::mem::replace(&mut self.force_persistent, true);
598 let saved_taint = std::mem::replace(&mut self.tainted, false);
599 let r = f(self);
600 let persistent = !self.tainted;
601 self.force_persistent = saved_force;
602 self.tainted = saved_taint || self.tainted;
603 (r, persistent)
604 }
605
606 pub fn intern(&mut self, node: Node) -> ExprId {
607 let h = node.hash();
608 let scratch_child = has_scratch_child(&node);
609 let mut perm_slot = None;
610 if !scratch_child {
611 match self.persistent.find_or_vacant(&self.perm.entries, &node, h) {
612 Ok(id) => return id,
613 Err(slot) => perm_slot = Some(slot),
614 }
615 }
616 let mut temp_slot = None;
617 if self.in_scratch {
618 match self.scratch.find_or_vacant(&self.temp.entries, &node, h) {
619 Ok(i) => {
620 self.tainted |= self.force_persistent;
621 return ExprId(i.0 | SCRATCH);
622 }
623 Err(slot) => temp_slot = Some(slot),
624 }
625 }
626 let entry = self.entry_of(node);
627 if self.in_scratch && (!self.force_persistent || scratch_child) {
628 self.tainted |= self.force_persistent;
629 let i = ExprId(self.temp.len() as u32);
630 self.temp.entries.push(entry);
631 self.scratch.insert_at(&self.temp.entries, temp_slot, i, h);
632 ExprId(i.0 | SCRATCH)
633 } else {
634 debug_assert!(!scratch_child);
635 let id = ExprId(self.perm.len() as u32);
636 assert!(id.0 & SCRATCH == 0, "persistent expression store is full");
637 self.cached_nodes += self.force_persistent as usize;
638 self.perm.entries.push(entry);
639 self.persistent
640 .insert_at(&self.perm.entries, perm_slot, id, h);
641 id
642 }
643 }
644
645 #[inline]
646 fn entry(&self, e: ExprId) -> &Entry {
647 if e.0 & SCRATCH != 0 {
648 &self.temp.entries[(e.0 & !SCRATCH) as usize]
649 } else {
650 &self.perm.entries[e.0 as usize]
651 }
652 }
653
654 #[inline]
655 fn lbr_of(&self, e: ExprId) -> u32 {
656 self.entry(e).lbr
657 }
658
659 #[inline]
660 fn flags_of(&self, e: ExprId) -> u8 {
661 self.entry(e).flags
662 }
663
664 #[inline]
665 fn mask_of(&self, e: ExprId) -> u64 {
666 self.entry(e).mask
667 }
668
669 #[inline(always)]
672 fn entry_of(&self, node: Node) -> Entry {
673 let (lbr, mask, flags, spine) = match node {
674 Node::BVar(i) => (
675 i + 1,
676 if i < 64 { 1 << i } else { 0 },
677 if i < 64 { 0 } else { WIDE_BVAR },
678 0,
679 ),
680 Node::FVar(_) => (0, 0, HAS_FVAR, 0),
681 Node::Sort(l) => (
682 0,
683 0,
684 if self.levels.has_param(l) {
685 HAS_LPARAM
686 } else {
687 0
688 },
689 0,
690 ),
691 Node::Const(_, ls) => {
692 let lp = self
693 .levels
694 .get_list(ls)
695 .iter()
696 .any(|l| self.levels.has_param(*l));
697 (0, 0, if lp { HAS_LPARAM } else { 0 }, 0)
698 }
699 Node::App(f, a) => {
700 let (x, y) = (self.entry(f), self.entry(a));
701 (
702 x.lbr.max(y.lbr),
703 x.mask | y.mask,
704 x.flags | y.flags,
705 x.spine.saturating_add(1),
706 )
707 }
708 Node::Lam(t, b) | Node::Pi(t, b) => {
709 let (x, y) = (self.entry(t), self.entry(b));
710 (
711 x.lbr.max(y.lbr.saturating_sub(1)),
712 x.mask | (y.mask >> 1),
713 x.flags | y.flags,
714 0,
715 )
716 }
717 Node::Let(t, v, b) => {
718 let (x, y, z) = (self.entry(t), self.entry(v), self.entry(b));
719 let lbr = x.lbr.max(y.lbr).max(z.lbr.saturating_sub(1));
720 (
721 lbr,
722 x.mask | y.mask | (z.mask >> 1),
723 x.flags | y.flags | z.flags,
724 0,
725 )
726 }
727 Node::NatLit(_) | Node::StrLit(_) | Node::Lit(_) | Node::Nil => (0, 0, 0, 0),
728 Node::Proj(_, _, e) => {
729 let x = self.entry(e);
730 (x.lbr, x.mask, x.flags, 0)
731 }
732 Node::Match(..) | Node::Fix(_) | Node::MutualFix(..) | Node::Seq(..) => {
733 self.logos_entry(node)
734 }
735 };
736 Entry {
737 node,
738 mask,
739 lbr,
740 flags,
741 spine,
742 }
743 }
744
745 #[inline(never)]
748 fn logos_entry(&self, node: Node) -> (u32, u64, u8, u16) {
749 match node {
750 Node::Match(d, m, c) => {
751 let (x, y, z) = (self.entry(d), self.entry(m), self.entry(c));
752 (
753 x.lbr.max(y.lbr).max(z.lbr),
754 x.mask | y.mask | z.mask,
755 x.flags | y.flags | z.flags,
756 0,
757 )
758 }
759 Node::Fix(b) => {
760 let x = self.entry(b);
761 (x.lbr.saturating_sub(1), x.mask >> 1, x.flags, 0)
762 }
763 Node::MutualFix(ds, _) => {
764 let x = self.entry(ds);
766 let n = x.spine as u32;
767 let mask = if n >= 64 { 0 } else { x.mask >> n };
768 let wide = if n >= 64 && x.lbr > n { WIDE_BVAR } else { 0 };
769 (x.lbr.saturating_sub(n), mask, x.flags | wide, 0)
770 }
771 Node::Seq(h, t) => {
772 let (x, y) = (self.entry(h), self.entry(t));
773 (
774 x.lbr.max(y.lbr),
775 x.mask | y.mask,
776 x.flags | y.flags,
777 y.spine.saturating_add(1),
778 )
779 }
780 other => unreachable!("not a LOGOS node: {other:?}"),
781 }
782 }
783
784 #[inline]
785 pub fn node(&self, e: ExprId) -> Node {
786 self.entry(e).node
787 }
788
789 #[inline]
791 pub fn loose_bvar_range(&self, e: ExprId) -> u32 {
792 self.lbr_of(e)
793 }
794
795 #[inline]
797 pub fn loose_bvars(&self, e: ExprId) -> (u32, Option<u64>) {
798 let x = self.entry(e);
799 (
800 x.lbr,
801 if x.flags & WIDE_BVAR != 0 {
802 None
803 } else {
804 Some(x.mask)
805 },
806 )
807 }
808
809 #[inline]
812 pub fn scope_of(&self, e: ExprId) -> (u32, Option<u64>, bool) {
813 let x = self.entry(e);
814 (
815 x.lbr,
816 if x.flags & WIDE_BVAR != 0 {
817 None
818 } else {
819 Some(x.mask)
820 },
821 x.flags & HAS_LPARAM != 0,
822 )
823 }
824
825 #[inline]
829 pub fn loose_bvar_mask(&self, e: ExprId) -> Option<u64> {
830 if self.flags_of(e) & WIDE_BVAR != 0 {
831 None
832 } else {
833 Some(self.mask_of(e))
834 }
835 }
836
837 #[inline]
838 pub fn has_loose_bvars(&self, e: ExprId) -> bool {
839 self.lbr_of(e) > 0
840 }
841
842 #[inline]
843 pub fn has_fvar(&self, e: ExprId) -> bool {
844 self.flags_of(e) & HAS_FVAR != 0
845 }
846
847 #[inline]
848 pub fn has_lparam(&self, e: ExprId) -> bool {
849 self.flags_of(e) & HAS_LPARAM != 0
850 }
851
852 pub fn bvar(&mut self, i: u32) -> ExprId {
855 self.intern(Node::BVar(i))
856 }
857 pub fn fvar(&mut self, i: u32) -> ExprId {
858 self.intern(Node::FVar(i))
859 }
860 pub fn sort(&mut self, l: LevelId) -> ExprId {
861 self.intern(Node::Sort(l))
862 }
863 pub fn prop(&mut self) -> ExprId {
864 self.sort(LevelId::ZERO)
865 }
866 pub fn cnst(&mut self, n: NameId, ls: LevelsId) -> ExprId {
867 self.intern(Node::Const(n, ls))
868 }
869 pub fn cnst_levels(&mut self, n: NameId, ls: &[LevelId]) -> ExprId {
870 let l = self.levels.list(ls);
871 self.cnst(n, l)
872 }
873 pub fn app(&mut self, f: ExprId, a: ExprId) -> ExprId {
874 self.intern(Node::App(f, a))
875 }
876 pub fn lam(&mut self, t: ExprId, b: ExprId) -> ExprId {
877 self.intern(Node::Lam(t, b))
878 }
879 pub fn pi(&mut self, t: ExprId, b: ExprId) -> ExprId {
880 self.intern(Node::Pi(t, b))
881 }
882 pub fn let_(&mut self, t: ExprId, v: ExprId, b: ExprId) -> ExprId {
883 self.intern(Node::Let(t, v, b))
884 }
885 pub fn proj(&mut self, s: NameId, i: u32, e: ExprId) -> ExprId {
886 self.intern(Node::Proj(s, i, e))
887 }
888 pub fn nat_lit(&mut self, n: Nat) -> ExprId {
889 let id = self.nat_id(n);
890 self.intern(Node::NatLit(id))
891 }
892 pub fn nat_id(&mut self, n: Nat) -> NatId {
894 match self.nat_index.get(&n) {
895 Some(id) => *id,
896 None => {
897 let id = NatId(self.nats.len() as u32);
898 self.nats.push(n.clone());
899 self.nat_index.insert(n, id);
900 id
901 }
902 }
903 }
904 pub fn str_lit(&mut self, s: &str) -> ExprId {
905 let id = match self.str_index.get(s) {
906 Some(id) => *id,
907 None => {
908 let rc: Rc<str> = Rc::from(s);
909 let id = StrId(self.strs.len() as u32);
910 self.strs.push(rc.clone());
911 self.str_index.insert(rc, id);
912 id
913 }
914 };
915 self.intern(Node::StrLit(id))
916 }
917 pub fn nat(&self, n: NatId) -> &Nat {
918 &self.nats[n.0 as usize]
919 }
920 pub fn lit(&mut self, l: Lit) -> ExprId {
921 let id = match self.lit_index.get(&l) {
922 Some(id) => *id,
923 None => {
924 let id = LitId(self.lits.len() as u32);
925 self.lits.push(l.clone());
926 self.lit_index.insert(l, id);
927 id
928 }
929 };
930 self.intern(Node::Lit(id))
931 }
932 pub fn lit_value(&self, l: LitId) -> &Lit {
933 &self.lits[l.0 as usize]
934 }
935 pub fn seq(&mut self, items: &[ExprId]) -> ExprId {
936 let nil = self.intern(Node::Nil);
937 items
938 .iter()
939 .rev()
940 .fold(nil, |tail, h| self.intern(Node::Seq(*h, tail)))
941 }
942 pub fn seq_items(&self, mut e: ExprId) -> Args {
944 let mut out = Args::new();
945 while let Node::Seq(h, t) = self.node(e) {
946 out.push(h);
947 e = t;
948 }
949 debug_assert!(matches!(self.node(e), Node::Nil), "a sequence ends in Nil");
950 out
951 }
952 pub fn match_(&mut self, disc: ExprId, motive: ExprId, cases: &[ExprId]) -> ExprId {
953 let cs = self.seq(cases);
954 self.intern(Node::Match(disc, motive, cs))
955 }
956 pub fn fix(&mut self, body: ExprId) -> ExprId {
957 self.intern(Node::Fix(body))
958 }
959 pub fn mutual_fix(&mut self, defs: &[ExprId], index: u32) -> ExprId {
960 let ds = self.seq(defs);
961 self.intern(Node::MutualFix(ds, index))
962 }
963 pub fn string(&self, s: StrId) -> Rc<str> {
964 self.strs[s.0 as usize].clone()
965 }
966
967 pub fn mk_app_n(&mut self, f: ExprId, args: &[ExprId]) -> ExprId {
968 args.iter().fold(f, |acc, a| self.app(acc, *a))
969 }
970
971 pub fn app_fn(&self, mut e: ExprId) -> ExprId {
973 while let Node::App(f, _) = self.node(e) {
974 e = f;
975 }
976 e
977 }
978
979 pub fn app_args(&self, e: ExprId) -> (ExprId, Args) {
982 let n = self.entry(e).spine;
983 if n == SPINE_UNKNOWN {
984 return self.app_args_walk(e);
985 }
986 let mut args: Args = smallvec::smallvec![ExprId(0); n as usize];
987 let mut cur = e;
988 for slot in args.iter_mut().rev() {
989 let Node::App(f, a) = self.node(cur) else {
990 unreachable!("a recorded spine is made of applications")
991 };
992 *slot = a;
993 cur = f;
994 }
995 (cur, args)
996 }
997
998 #[cold]
1000 fn app_args_walk(&self, mut e: ExprId) -> (ExprId, Args) {
1001 let mut args = Args::new();
1002 while let Node::App(f, a) = self.node(e) {
1003 args.push(a);
1004 e = f;
1005 }
1006 args.reverse();
1007 (e, args)
1008 }
1009
1010 pub fn app_num_args(&self, mut e: ExprId) -> usize {
1011 let n = self.entry(e).spine;
1012 if n != SPINE_UNKNOWN {
1013 return n as usize;
1014 }
1015 let mut n = 0;
1016 while let Node::App(f, _) = self.node(e) {
1017 n += 1;
1018 e = f;
1019 }
1020 n
1021 }
1022
1023 pub fn const_head(&self, e: ExprId) -> Option<(NameId, LevelsId)> {
1024 match self.node(self.app_fn(e)) {
1025 Node::Const(n, ls) => Some((n, ls)),
1026 _ => None,
1027 }
1028 }
1029
1030 pub fn instantiate_core(&mut self, e: ExprId, subst: &[ExprId], rev: bool) -> ExprId {
1035 if subst.is_empty() || !self.has_loose_bvars(e) {
1036 return e;
1037 }
1038 self.inst_memo.reset();
1039 self.inst_go(e, 0, subst, rev)
1040 }
1041
1042 pub fn instantiate(&mut self, e: ExprId, subst: &[ExprId]) -> ExprId {
1043 self.instantiate_core(e, subst, false)
1044 }
1045
1046 pub fn instantiate_rev(&mut self, e: ExprId, subst: &[ExprId]) -> ExprId {
1047 self.instantiate_core(e, subst, true)
1048 }
1049
1050 pub fn instantiate1(&mut self, e: ExprId, v: ExprId) -> ExprId {
1051 self.instantiate_core(e, &[v], false)
1052 }
1053
1054 fn inst_go(&mut self, e: ExprId, off: u32, subst: &[ExprId], rev: bool) -> ExprId {
1055 if self.lbr_of(e) <= off {
1056 return e;
1057 }
1058 if let Some(r) = self.inst_memo.get(e, off) {
1059 return r;
1060 }
1061 let n = subst.len() as u32;
1062 let r = match self.node(e) {
1063 Node::BVar(i) => {
1064 if i < off + n {
1065 let k = (i - off) as usize;
1066 let v = if rev {
1067 subst[subst.len() - 1 - k]
1068 } else {
1069 subst[k]
1070 };
1071 self.lift_loose(v, 0, off)
1072 } else {
1073 self.bvar(i - n)
1074 }
1075 }
1076 Node::App(f, a) => {
1077 let (f2, a2) = (
1078 self.inst_go(f, off, subst, rev),
1079 self.inst_go(a, off, subst, rev),
1080 );
1081 self.app(f2, a2)
1082 }
1083 Node::Lam(t, b) => {
1084 let (t2, b2) = (
1085 self.inst_go(t, off, subst, rev),
1086 self.inst_go(b, off + 1, subst, rev),
1087 );
1088 self.lam(t2, b2)
1089 }
1090 Node::Pi(t, b) => {
1091 let (t2, b2) = (
1092 self.inst_go(t, off, subst, rev),
1093 self.inst_go(b, off + 1, subst, rev),
1094 );
1095 self.pi(t2, b2)
1096 }
1097 Node::Let(t, v, b) => {
1098 let t2 = self.inst_go(t, off, subst, rev);
1099 let v2 = self.inst_go(v, off, subst, rev);
1100 let b2 = self.inst_go(b, off + 1, subst, rev);
1101 self.let_(t2, v2, b2)
1102 }
1103 Node::Proj(s, i, x) => {
1104 let x2 = self.inst_go(x, off, subst, rev);
1105 self.proj(s, i, x2)
1106 }
1107 Node::Match(..) | Node::Fix(_) | Node::MutualFix(..) | Node::Seq(..) => {
1108 self.inst_logos(e, off, subst, rev)
1109 }
1110 _ => e,
1111 };
1112 self.inst_memo.insert(e, off, r);
1113 r
1114 }
1115
1116 #[inline(never)]
1120 fn inst_logos(&mut self, e: ExprId, off: u32, subst: &[ExprId], rev: bool) -> ExprId {
1121 self.map_logos(e, &mut |st, c, k| st.inst_go(c, off + k, subst, rev))
1122 }
1123 #[inline(never)]
1124 fn lift_logos(&mut self, e: ExprId, s: u32, d: u32) -> ExprId {
1125 self.map_logos(e, &mut |st, c, k| st.lift_go(c, s + k, d))
1126 }
1127 #[inline(never)]
1128 fn abs_logos(&mut self, e: ExprId, off: u32, fvars: &[u32]) -> ExprId {
1129 self.map_logos(e, &mut |st, c, k| st.abs_go(c, off + k, fvars))
1130 }
1131 #[inline(never)]
1132 fn lp_logos(&mut self, e: ExprId, ps: &[NameId], us: &[LevelId]) -> ExprId {
1133 self.map_logos(e, &mut |st, c, _| st.lp_go(c, ps, us))
1134 }
1135
1136 fn map_logos(
1139 &mut self,
1140 e: ExprId,
1141 f: &mut dyn FnMut(&mut Store, ExprId, u32) -> ExprId,
1142 ) -> ExprId {
1143 match self.node(e) {
1144 Node::Match(d, m, c) => {
1145 let (d2, m2, c2) = (f(self, d, 0), f(self, m, 0), f(self, c, 0));
1146 self.intern(Node::Match(d2, m2, c2))
1147 }
1148 Node::Fix(b) => {
1149 let b2 = f(self, b, 1);
1150 self.intern(Node::Fix(b2))
1151 }
1152 Node::MutualFix(ds, i) => {
1153 let n = self.entry(ds).spine as u32;
1154 let ds2 = f(self, ds, n);
1155 self.intern(Node::MutualFix(ds2, i))
1156 }
1157 Node::Seq(h, t) => {
1158 let (h2, t2) = (f(self, h, 0), f(self, t, 0));
1159 self.intern(Node::Seq(h2, t2))
1160 }
1161 other => unreachable!("not a LOGOS node with children: {other:?}"),
1162 }
1163 }
1164
1165 pub fn lift_loose(&mut self, e: ExprId, s: u32, d: u32) -> ExprId {
1167 if d == 0 || self.lbr_of(e) <= s {
1168 return e;
1169 }
1170 self.lift_memo.reset();
1171 self.lift_go(e, s, d)
1172 }
1173
1174 fn lift_go(&mut self, e: ExprId, s: u32, d: u32) -> ExprId {
1175 if self.lbr_of(e) <= s {
1176 return e;
1177 }
1178 if let Some(r) = self.lift_memo.get(e, s) {
1179 return r;
1180 }
1181 let r = match self.node(e) {
1182 Node::BVar(i) => self.bvar(i + d),
1183 Node::App(f, a) => {
1184 let (f2, a2) = (self.lift_go(f, s, d), self.lift_go(a, s, d));
1185 self.app(f2, a2)
1186 }
1187 Node::Lam(t, b) => {
1188 let (t2, b2) = (self.lift_go(t, s, d), self.lift_go(b, s + 1, d));
1189 self.lam(t2, b2)
1190 }
1191 Node::Pi(t, b) => {
1192 let (t2, b2) = (self.lift_go(t, s, d), self.lift_go(b, s + 1, d));
1193 self.pi(t2, b2)
1194 }
1195 Node::Let(t, v, b) => {
1196 let t2 = self.lift_go(t, s, d);
1197 let v2 = self.lift_go(v, s, d);
1198 let b2 = self.lift_go(b, s + 1, d);
1199 self.let_(t2, v2, b2)
1200 }
1201 Node::Proj(n, i, x) => {
1202 let x2 = self.lift_go(x, s, d);
1203 self.proj(n, i, x2)
1204 }
1205 Node::Match(..) | Node::Fix(_) | Node::MutualFix(..) | Node::Seq(..) => {
1206 self.lift_logos(e, s, d)
1207 }
1208 _ => e,
1209 };
1210 self.lift_memo.insert(e, s, r);
1211 r
1212 }
1213
1214 pub fn abstract_fvars(&mut self, e: ExprId, fvars: &[u32]) -> ExprId {
1217 if fvars.is_empty() || !self.has_fvar(e) {
1218 return e;
1219 }
1220 self.abs_memo.reset();
1221 self.abs_go(e, 0, fvars)
1222 }
1223
1224 fn abs_go(&mut self, e: ExprId, off: u32, fvars: &[u32]) -> ExprId {
1225 if !self.has_fvar(e) {
1226 return e;
1227 }
1228 if let Some(r) = self.abs_memo.get(e, off) {
1229 return r;
1230 }
1231 let r = match self.node(e) {
1232 Node::FVar(x) => match fvars.iter().rposition(|f| *f == x) {
1233 Some(i) => self.bvar(off + (fvars.len() - 1 - i) as u32),
1234 None => e,
1235 },
1236 Node::App(f, a) => {
1237 let (f2, a2) = (self.abs_go(f, off, fvars), self.abs_go(a, off, fvars));
1238 self.app(f2, a2)
1239 }
1240 Node::Lam(t, b) => {
1241 let (t2, b2) = (self.abs_go(t, off, fvars), self.abs_go(b, off + 1, fvars));
1242 self.lam(t2, b2)
1243 }
1244 Node::Pi(t, b) => {
1245 let (t2, b2) = (self.abs_go(t, off, fvars), self.abs_go(b, off + 1, fvars));
1246 self.pi(t2, b2)
1247 }
1248 Node::Let(t, v, b) => {
1249 let t2 = self.abs_go(t, off, fvars);
1250 let v2 = self.abs_go(v, off, fvars);
1251 let b2 = self.abs_go(b, off + 1, fvars);
1252 self.let_(t2, v2, b2)
1253 }
1254 Node::Proj(n, i, x) => {
1255 let x2 = self.abs_go(x, off, fvars);
1256 self.proj(n, i, x2)
1257 }
1258 Node::Match(..) | Node::Fix(_) | Node::MutualFix(..) | Node::Seq(..) => {
1259 self.abs_logos(e, off, fvars)
1260 }
1261 _ => e,
1262 };
1263 self.abs_memo.insert(e, off, r);
1264 r
1265 }
1266
1267 pub fn instantiate_lparams(&mut self, e: ExprId, ps: &[NameId], us: &[LevelId]) -> ExprId {
1269 if ps.is_empty() || !self.has_lparam(e) {
1270 return e;
1271 }
1272 self.lp_memo.reset();
1273 self.lp_go(e, ps, us)
1274 }
1275
1276 fn lp_go(&mut self, e: ExprId, ps: &[NameId], us: &[LevelId]) -> ExprId {
1277 if !self.has_lparam(e) {
1278 return e;
1279 }
1280 if let Some(r) = self.lp_memo.get(e, 0) {
1281 return r;
1282 }
1283 let r = match self.node(e) {
1284 Node::Sort(l) => {
1285 let l2 = self.levels.instantiate(l, ps, us);
1286 self.sort(l2)
1287 }
1288 Node::Const(n, ls) => {
1289 let old: Vec<LevelId> = self.levels.get_list(ls).to_vec();
1290 let new: Vec<LevelId> = old
1291 .iter()
1292 .map(|l| self.levels.instantiate(*l, ps, us))
1293 .collect();
1294 self.cnst_levels(n, &new)
1295 }
1296 Node::App(f, a) => {
1297 let (f2, a2) = (self.lp_go(f, ps, us), self.lp_go(a, ps, us));
1298 self.app(f2, a2)
1299 }
1300 Node::Lam(t, b) => {
1301 let (t2, b2) = (self.lp_go(t, ps, us), self.lp_go(b, ps, us));
1302 self.lam(t2, b2)
1303 }
1304 Node::Pi(t, b) => {
1305 let (t2, b2) = (self.lp_go(t, ps, us), self.lp_go(b, ps, us));
1306 self.pi(t2, b2)
1307 }
1308 Node::Let(t, v, b) => {
1309 let t2 = self.lp_go(t, ps, us);
1310 let v2 = self.lp_go(v, ps, us);
1311 let b2 = self.lp_go(b, ps, us);
1312 self.let_(t2, v2, b2)
1313 }
1314 Node::Proj(n, i, x) => {
1315 let x2 = self.lp_go(x, ps, us);
1316 self.proj(n, i, x2)
1317 }
1318 Node::Match(..) | Node::Fix(_) | Node::MutualFix(..) | Node::Seq(..) => {
1319 self.lp_logos(e, ps, us)
1320 }
1321 _ => e,
1322 };
1323 self.lp_memo.insert(e, 0, r);
1324 r
1325 }
1326
1327 pub fn any_node(&self, e: ExprId, pred: &mut dyn FnMut(&Store, ExprId) -> bool) -> bool {
1329 let mut seen = rustc_hash::FxHashSet::default();
1330 let mut stack = vec![e];
1331 while let Some(x) = stack.pop() {
1332 if !seen.insert(x) {
1333 continue;
1334 }
1335 if pred(self, x) {
1336 return true;
1337 }
1338 match self.node(x) {
1339 Node::App(a, b) | Node::Lam(a, b) | Node::Pi(a, b) | Node::Seq(a, b) => {
1340 stack.push(a);
1341 stack.push(b);
1342 }
1343 Node::Let(a, b, c) | Node::Match(a, b, c) => {
1344 stack.push(a);
1345 stack.push(b);
1346 stack.push(c);
1347 }
1348 Node::Proj(_, _, a) | Node::Fix(a) | Node::MutualFix(a, _) => stack.push(a),
1349 _ => {}
1350 }
1351 }
1352 false
1353 }
1354
1355 pub fn mentions_const(&self, e: ExprId, names: &[NameId]) -> bool {
1357 self.any_node(
1358 e,
1359 &mut |s, x| matches!(s.node(x), Node::Const(c, _) if names.contains(&c)),
1360 )
1361 }
1362}
1363
1364#[cfg(test)]
1365#[path = "../../../logicaffeine_tests/unit/logicaffeine_kernel/dag/expr/tests.rs"]
1366mod tests;