logicaffeine_kernel/
reify.rs1use std::collections::HashMap;
19
20use crate::term::{Literal, Term};
21
22#[derive(Debug, Default)]
27pub struct VarInterner {
28 map: HashMap<String, i64>,
29 next: i64,
30}
31
32impl VarInterner {
33 pub fn new() -> Self {
34 VarInterner {
35 map: HashMap::new(),
36 next: -1_000_000,
37 }
38 }
39
40 pub fn intern(&mut self, name: &str) -> i64 {
42 if let Some(&idx) = self.map.get(name) {
43 return idx;
44 }
45 let idx = self.next;
46 self.next -= 1;
47 self.map.insert(name.to_string(), idx);
48 idx
49 }
50}
51
52pub(crate) fn extract_slit(term: &Term) -> Option<i64> {
54 if let Term::App(ctor, arg) = term {
55 if let Term::Global(name) = ctor.as_ref() {
56 if name == "SLit" {
57 if let Term::Lit(Literal::Int(n)) = arg.as_ref() {
58 return Some(*n);
59 }
60 }
61 }
62 }
63 None
64}
65
66pub(crate) fn extract_svar(term: &Term) -> Option<i64> {
68 if let Term::App(ctor, arg) = term {
69 if let Term::Global(name) = ctor.as_ref() {
70 if name == "SVar" {
71 if let Term::Lit(Literal::Int(i)) = arg.as_ref() {
72 return Some(*i);
73 }
74 }
75 }
76 }
77 None
78}
79
80pub(crate) fn extract_sname(term: &Term) -> Option<String> {
82 if let Term::App(ctor, arg) = term {
83 if let Term::Global(name) = ctor.as_ref() {
84 if name == "SName" {
85 if let Term::Lit(Literal::Text(s)) = arg.as_ref() {
86 return Some(s.clone());
87 }
88 }
89 }
90 }
91 None
92}
93
94pub(crate) fn extract_binary_app(term: &Term) -> Option<(String, Term, Term)> {
96 if let Term::App(outer, b) = term {
97 if let Term::App(sapp_outer, inner) = outer.as_ref() {
98 if let Term::Global(ctor) = sapp_outer.as_ref() {
99 if ctor == "SApp" {
100 if let Term::App(partial, a) = inner.as_ref() {
101 if let Term::App(sapp_inner, op_term) = partial.as_ref() {
102 if let Term::Global(ctor2) = sapp_inner.as_ref() {
103 if ctor2 == "SApp" {
104 if let Some(op) = extract_sname(op_term) {
105 return Some((
106 op,
107 a.as_ref().clone(),
108 b.as_ref().clone(),
109 ));
110 }
111 }
112 }
113 }
114 }
115 }
116 }
117 }
118 }
119 None
120}
121
122#[cfg(test)]
123mod tests {
124 use super::*;
125
126 #[test]
127 fn interner_distinct_names_distinct_indices() {
128 let mut it = VarInterner::new();
129 let a = it.intern("Aa");
130 let b = it.intern("BB");
131 assert_ne!(a, b);
132 }
133
134 #[test]
135 fn interner_same_name_same_index() {
136 let mut it = VarInterner::new();
137 assert_eq!(it.intern("x"), it.intern("x"));
138 }
139
140 #[test]
141 fn interner_indices_negative_below_svar_range() {
142 let mut it = VarInterner::new();
143 assert!(it.intern("x") <= -1_000_000);
144 }
145}