Skip to main content

prolog2/resolution/
build.rs

1//! Term building: construct new heap terms from clause templates and substitutions.
2
3use crate::{
4    heap::heap::{Cell, Heap, Tag},
5    program::clause::BitFlag64,
6    resolution::unification::Substitution,
7};
8
9/*  If a ref if bound to some complex term which contains args we want
10   to rebuild this term in the query space replacing args with refs or arg reg values
11*/
12pub fn re_build_bound_arg_terms(heap: &mut impl Heap, substitution: &mut Substitution) {
13    for i in 0..substitution.len() {
14        if let (_, bound_addr, true) = substitution[i] {
15            if heap.contains_args(bound_addr) {
16                //Build term if contains args
17                //Update bound_addr to newly built term
18                let new_bound_addr = build(heap, substitution, None, bound_addr);
19                substitution[i].1 = new_bound_addr;
20            }
21        }
22    }
23}
24
25/*  Build a new term from previous term and substitution.
26    Assume that src_addr does not point to bound ref.   ``
27
28*/
29pub fn build(
30    heap: &mut impl Heap,
31    substitution: &mut Substitution,
32    meta_vars: Option<BitFlag64>,
33    src_addr: usize,
34) -> usize {
35    match heap[heap.deref_addr(src_addr)] {
36        (tag @ (Tag::Con | Tag::Flt | Tag::Int | Tag::Stri | Tag::ELis | Tag::Ref), value) => {
37            heap.heap_push((tag, value))
38        }
39        (Tag::Arg, _arg_id) => build_arg(heap, substitution, meta_vars, src_addr),
40        (Tag::Func | Tag::Tup | Tag::Set, _) => build_str(heap, substitution, meta_vars, src_addr),
41        (Tag::Lis, ptr) => {
42            let new_ptr = build_list(heap, substitution, meta_vars, ptr);
43            heap.heap_push((Tag::Lis, new_ptr))
44        }
45        cell => unimplemented!("build: unhandled cell type {cell:?}"),
46    }
47}
48
49fn build_arg(
50    heap: &mut impl Heap,
51    substitution: &mut Substitution,
52    meta_vars: Option<BitFlag64>,
53    src_addr: usize,
54) -> usize {
55    let arg_id = heap[src_addr].1;
56    match meta_vars {
57        Some(bit_flags) if !bit_flags.get(arg_id) => heap.heap_push(heap[src_addr]),
58        _ => match substitution.get_arg(arg_id) {
59            Some(bound_addr) => heap.set_ref(Some(bound_addr)),
60            None => {
61                let ref_addr = heap.set_ref(None);
62                substitution.set_arg(arg_id, ref_addr);
63                ref_addr
64            }
65        },
66    }
67}
68
69fn build_str(
70    heap: &mut impl Heap,
71    substitution: &mut Substitution,
72    meta_vars: Option<BitFlag64>,
73    src_addr: usize,
74) -> usize {
75    let (tag, length) = heap[src_addr];
76    let mut complex_terms: Vec<Option<Cell>> = Vec::with_capacity(length);
77    for i in 1..length + 1 {
78        complex_terms.push(build_complex_term(
79            heap,
80            substitution,
81            meta_vars,
82            src_addr + i,
83        ));
84    }
85    let addr = heap.heap_push((tag, length));
86    let mut i = 1;
87    for complex_term in complex_terms {
88        match complex_term {
89            Some(cell) => heap.heap_push(cell),
90            None => build(heap, substitution, meta_vars, src_addr + i),
91        };
92        i += 1;
93    }
94
95    addr
96}
97
98fn build_list(
99    heap: &mut impl Heap,
100    substitution: &mut Substitution,
101    meta_vars: Option<BitFlag64>,
102    src_addr: usize,
103) -> usize {
104    let head = build_complex_term(heap, substitution, meta_vars, src_addr);
105    let tail = build_complex_term(heap, substitution, meta_vars, src_addr + 1);
106    let ptr = match head {
107        Some(cell) => heap.heap_push(cell),
108        None => build(heap, substitution, meta_vars, src_addr),
109    };
110    match tail {
111        Some(cell) => heap.heap_push(cell),
112        None => build(heap, substitution, meta_vars, src_addr + 1),
113    };
114    ptr
115}
116
117fn build_complex_term(
118    heap: &mut impl Heap,
119    substitution: &mut Substitution,
120    meta_vars: Option<BitFlag64>,
121    src_addr: usize,
122) -> Option<Cell> {
123    match heap[heap.deref_addr(src_addr)] {
124        (Tag::Func | Tag::Tup | Tag::Set, _) => {
125            Some((Tag::Str, build_str(heap, substitution, meta_vars, src_addr)))
126        }
127        (Tag::Str, ptr) => Some((Tag::Str, build_str(heap, substitution, meta_vars, ptr))),
128        (Tag::Lis, ptr) => Some((Tag::Lis, build_list(heap, substitution, meta_vars, ptr))),
129        (Tag::Arg, id) => match meta_vars {
130            Some(bitflags) if !bitflags.get(id) => None,
131            _ => match substitution.get_arg(id) {
132                Some(addr) => build_complex_term(heap, substitution, meta_vars, addr),
133                None => None,
134            },
135        },
136        (Tag::Ref, ref_addr) if ref_addr == src_addr => {
137            if let Some(bound_addr) = substitution.bound(ref_addr) {
138                build_complex_term(heap, substitution, meta_vars, bound_addr)
139            } else {
140                None
141            }
142        }
143        _ => None,
144    }
145}
146
147#[cfg(test)]
148mod tests {
149    use crate::{
150        heap::{
151            heap::{Heap, Tag},
152            symbol_db::SymbolDB,
153        },
154        program::clause::BitFlag64,
155        resolution::{
156            build::{build, re_build_bound_arg_terms},
157            unification::{unify, Substitution},
158        },
159    };
160
161    #[test]
162    fn args() {
163        let p = SymbolDB::set_const("p".into());
164        let f = SymbolDB::set_const("f".into());
165
166        let mut heap = vec![
167            (Tag::Func, 4),
168            (Tag::Con, p),
169            (Tag::Arg, 0),
170            (Tag::Arg, 0),
171            (Tag::Arg, 1),
172        ];
173        let mut substitution = Substitution::default();
174        let addr = build(&mut heap, &mut substitution, None, 0);
175        assert_eq!(
176            heap[addr..(addr + 4)],
177            [
178                (Tag::Func, 4),
179                (Tag::Con, p),
180                (Tag::Ref, addr + 2),
181                (Tag::Ref, addr + 2),
182            ]
183        );
184
185        let mut substitution = Substitution::default();
186        let mut meta_vars = BitFlag64::default();
187        meta_vars.set(0);
188        let addr = build(&mut heap, &mut substitution, Some(meta_vars), 0);
189        heap._print_heap();
190        assert_eq!(
191            heap[addr..(addr + 5)],
192            [
193                (Tag::Func, 4),
194                (Tag::Con, p),
195                (Tag::Ref, addr + 2),
196                (Tag::Ref, addr + 2),
197                (Tag::Arg, 1)
198            ]
199        );
200
201        heap = vec![
202            (Tag::Func, 2),
203            (Tag::Con, f),
204            (Tag::Ref, 2),
205            (Tag::Func, 2),
206            (Tag::Con, p),
207            (Tag::Arg, 0),
208        ];
209        substitution = Substitution::default();
210        substitution.set_arg(0, 0);
211        let addr = build(&mut heap, &mut substitution, None, 3);
212        assert_eq!(
213            heap[addr - 3..(addr + 3)],
214            [
215                (Tag::Func, 2),
216                (Tag::Con, f),
217                (Tag::Ref, 2),
218                (Tag::Func, 2),
219                (Tag::Con, p),
220                (Tag::Str, addr - 3),
221            ]
222        );
223    }
224
225    #[test]
226    fn lists() {
227        let p = SymbolDB::set_const("p".into());
228        let a = SymbolDB::set_const("a".into());
229        let b = SymbolDB::set_const("b".into());
230        let c = SymbolDB::set_const("c".into());
231
232        let mut heap = vec![
233            (Tag::Con, a), //0
234            (Tag::Lis, 2), //1
235            (Tag::Con, b), //2
236            (Tag::Arg, 0), //3
237            (Tag::Func, 2), //4
238            (Tag::Con, p), //5
239            (Tag::Lis, 0), //6
240            (Tag::Con, a), //7
241            (Tag::Lis, 9), //8
242            (Tag::Con, b), //9
243            (Tag::Lis, 11), //10
244            (Tag::Con, c), //11
245            (Tag::ELis, 0), //12
246            (Tag::Func, 2), //13
247            (Tag::Con, p), //14
248            (Tag::Lis, 7), //15
249        ];
250        let mut substitution = Substitution::default();
251        substitution.set_arg(0, 10);
252        let addr = build(&mut heap, &mut substitution, None, 4);
253        assert_eq!(heap.term_string(addr), "p([a,b,c])");
254
255        let mut heap = vec![
256            (Tag::Con, a), //0
257            (Tag::Lis, 2), //1
258            (Tag::Con, b), //2
259            (Tag::Ref, 3), //3
260            (Tag::Func, 2), //4
261            (Tag::Con, p), //5
262            (Tag::Lis, 0), //6
263            (Tag::Con, a), //7
264            (Tag::Lis, 9), //8
265            (Tag::Con, b), //9
266            (Tag::Lis, 11), //10
267            (Tag::Arg, 0), //11
268            (Tag::ELis, 0), //12
269            (Tag::Func, 2), //13
270            (Tag::Con, p), //14
271            (Tag::Lis, 7), //15
272        ];
273        let mut substitution = Substitution::default();
274        substitution = substitution.push((3, 10, true));
275        re_build_bound_arg_terms(&mut heap, &mut substitution);
276        let new_term = build(&mut heap, &mut substitution, None, 13);
277        println!("{}", heap.term_string(new_term));
278    }
279
280    #[test]
281    fn meta_vars() {}
282
283    #[test]
284    fn test1() {
285        let p = SymbolDB::set_const("p".into());
286        let mut heap = vec![
287            (Tag::Ref, 0),  //0
288            (Tag::Lis, 2),  //1
289            (Tag::Ref, 2),  //2
290            (Tag::ELis, 0), //3
291            (Tag::Func, 3), //4
292            (Tag::Con, p),  //5
293            (Tag::Ref, 6),  //6
294            (Tag::Lis, 0),  //7
295            (Tag::Func, 3), //8
296            (Tag::Con, p),  //9
297            (Tag::Arg, 0),  //10
298            (Tag::Arg, 0),  //11
299        ];
300
301        let mut sub = unify(&heap, 8, 4).unwrap();
302        re_build_bound_arg_terms(&mut heap, &mut sub);
303
304        heap._print_heap();
305        println!("{:?}", sub.bound(6))
306    }
307
308    #[test]
309    fn test2() {
310        let p = SymbolDB::set_const("p".into());
311        let mut heap = vec![
312            (Tag::Ref, 0),  //0
313            (Tag::Lis, 2),  //1
314            (Tag::Ref, 2),  //2
315            (Tag::ELis, 0), //3
316            (Tag::Func, 3), //4
317            (Tag::Con, p),  //5
318            (Tag::Ref, 6),  //6
319            (Tag::Lis, 0),  //7
320            (Tag::Func, 3), //8
321            (Tag::Con, p),  //9
322            (Tag::Arg, 0),  //10
323            (Tag::Arg, 0),  //11
324        ];
325
326        let mut sub = unify(&heap, 8, 4).unwrap();
327        re_build_bound_arg_terms(&mut heap, &mut sub);
328
329        heap._print_heap();
330        println!("{:?}", sub.bound(6))
331    }
332}