1pub mod physical;
42
43use std::collections::HashMap;
44use std::hash::Hash;
45use std::num::NonZeroU32;
46
47#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
49pub struct InstId(pub NonZeroU32);
50
51impl InstId {
52 pub fn new(index: usize) -> Self {
53 InstId(NonZeroU32::new((index + 1) as u32).expect("index overflow"))
57 }
58
59 pub fn index(&self) -> usize {
60 (self.0.get() - 1) as usize
61 }
62}
63
64pub trait InternKey: Copy + Eq + Hash {
65 fn new(index: usize) -> Self;
66 fn index(&self) -> usize;
67}
68
69#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
71pub struct NameId(pub NonZeroU32);
72
73impl InternKey for NameId {
74 fn new(index: usize) -> Self {
75 NameId(NonZeroU32::new((index + 1) as u32).expect("index overflow"))
76 }
77
78 fn index(&self) -> usize {
79 (self.0.get() - 1) as usize
80 }
81}
82
83#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
85pub struct StringId(pub NonZeroU32);
86
87impl InternKey for StringId {
88 fn new(index: usize) -> Self {
89 StringId(NonZeroU32::new((index + 1) as u32).expect("index overflow"))
90 }
91
92 fn index(&self) -> usize {
93 (self.0.get() - 1) as usize
94 }
95}
96
97#[derive(Debug)]
99pub struct Store<K: InternKey> {
100 map: HashMap<String, K>,
101 vec: Vec<String>,
102}
103
104impl<K: InternKey> Default for Store<K> {
105 fn default() -> Self {
106 Self {
107 map: HashMap::default(),
108 vec: Vec::new(),
109 }
110 }
111}
112
113impl<K: InternKey> Store<K> {
114 pub fn new() -> Self {
115 Self::default()
116 }
117
118 pub fn intern(&mut self, name: String) -> K {
119 if let Some(&id) = self.map.get(&name) {
120 return id;
121 }
122 let id = K::new(self.vec.len());
123 self.vec.push(name.clone());
124 self.map.insert(name, id);
125 id
126 }
127
128 pub fn get(&self, id: K) -> &str {
129 &self.vec[id.index()]
130 }
131
132 pub fn lookup(&self, name: &str) -> Option<K> {
133 self.map.get(name).copied()
134 }
135}
136
137#[derive(Default, Debug)]
139pub struct Ir {
140 pub insts: Vec<Inst>,
141 pub name_store: Store<NameId>,
142 pub string_store: Store<StringId>,
143}
144
145impl Ir {
146 pub fn new() -> Self {
147 Self::default()
148 }
149
150 pub fn add_inst(&mut self, inst: Inst) -> InstId {
151 let id = InstId::new(self.insts.len());
152 self.insts.push(inst);
153 id
154 }
155
156 pub fn get(&self, id: InstId) -> &Inst {
157 &self.insts[id.index()]
158 }
159
160 pub fn intern_name(&mut self, name: impl Into<String>) -> NameId {
161 self.name_store.intern(name.into())
162 }
163
164 pub fn resolve_name(&self, id: NameId) -> &str {
165 self.name_store.get(id)
166 }
167
168 pub fn intern_string(&mut self, s: impl Into<String>) -> StringId {
169 self.string_store.intern(s.into())
170 }
171
172 pub fn resolve_string(&self, id: StringId) -> &str {
173 self.string_store.get(id)
174 }
175}
176
177#[derive(Clone, Debug, PartialEq)]
179pub enum Inst {
180 Bool(bool),
182 Number(i64),
183 Float(f64),
184 String(StringId),
186 Bytes(Vec<u8>),
187 Name(NameId),
189
190 List(Vec<InstId>),
192 Map {
194 keys: Vec<InstId>,
195 values: Vec<InstId>,
196 },
197 Struct {
199 fields: Vec<NameId>,
200 values: Vec<InstId>,
201 },
202
203 Var(NameId),
206
207 ApplyFn {
210 function: NameId,
211 args: Vec<InstId>,
212 },
213
214 Atom {
217 predicate: NameId,
218 args: Vec<InstId>,
219 },
220 NegAtom(InstId),
222 Eq(InstId, InstId),
224 Ineq(InstId, InstId),
226
227 Transform {
230 var: Option<NameId>,
231 app: InstId,
232 },
233
234 Rule {
237 head: InstId, premises: Vec<InstId>, transform: Vec<InstId>, },
241
242 Decl {
244 atom: InstId,
245 descr: Vec<InstId>, bounds: Vec<InstId>, constraints: Option<InstId>, },
249
250 BoundDecl {
252 base_terms: Vec<InstId>,
253 },
254
255 Constraints {
257 consequences: Vec<InstId>, alternatives: Vec<Vec<InstId>>, },
260}
261
262#[cfg(test)]
263mod compat_test;
264
265#[cfg(test)]
266mod tests {
267 use super::*;
268
269 #[test]
270 fn basic_ir_construction() {
271 let mut ir = Ir::new();
272
273 let x_name = ir.intern_name("X");
276 let var_x = ir.add_inst(Inst::Var(x_name));
277
278 let p_name = ir.intern_name("p");
279 let atom_head = ir.add_inst(Inst::Atom {
280 predicate: p_name,
281 args: vec![var_x],
282 });
283
284 let q_name = ir.intern_name("q");
285 let atom_body = ir.add_inst(Inst::Atom {
286 predicate: q_name,
287 args: vec![var_x],
288 });
289
290 let rule = ir.add_inst(Inst::Rule {
291 head: atom_head,
292 premises: vec![atom_body],
293 transform: vec![],
294 });
295
296 assert_eq!(ir.insts.len(), 4);
297
298 if let Inst::Rule { head, .. } = ir.get(rule) {
299 assert_eq!(*head, atom_head);
300 } else {
301 panic!("Expected Rule");
302 }
303 }
304
305 #[test]
306 fn complex_types() {
307 let mut ir = Ir::new();
308
309 let n_string = ir.intern_name("/string");
314 let s_string = ir.add_inst(Inst::Name(n_string));
315
316 let n_a = ir.intern_name("/a");
317 let s_a = ir.add_inst(Inst::Name(n_a));
318
319 let fn_opt_name = ir.intern_name("fn:opt");
324 let fn_opt = ir.add_inst(Inst::ApplyFn {
325 function: fn_opt_name,
326 args: vec![s_a, s_string],
327 });
328
329 let fn_struct_name = ir.intern_name("fn:Struct");
334 let fn_struct = ir.add_inst(Inst::ApplyFn {
335 function: fn_struct_name,
336 args: vec![fn_opt],
337 });
338
339 let fn_pair_name = ir.intern_name("fn:Pair");
342 let fn_pair = ir.add_inst(Inst::ApplyFn {
343 function: fn_pair_name,
344 args: vec![s_string, fn_struct],
345 });
346
347 if let Inst::ApplyFn { function, args } = ir.get(fn_pair) {
350 assert_eq!(ir.resolve_name(*function), "fn:Pair");
351
352 assert_eq!(args.len(), 2);
353
354 assert_eq!(args[0], s_string);
355
356 assert_eq!(args[1], fn_struct);
357 } else {
358 panic!("Expected ApplyFn");
359 }
360 }
361}