1use std::collections::HashMap;
4
5use super::{
6 build_tree::TreeClause,
7 term::{Term, Unit},
8};
9use crate::{
10 heap::heap::Heap,
11 program::{clause::Clause, predicate_table::PredicateTable},
12};
13
14pub fn build_clause(
15 literals: Vec<Term>,
16 meta_vars: Option<Vec<String>>,
17 constrained_vars: Option<Vec<String>>,
18 heap: &mut impl Heap,
19 query: bool,
20) -> Clause {
21 let mut var_values = HashMap::new();
22
23 let literals: Vec<usize> = literals
24 .into_iter()
25 .map(|term| term.encode(heap, &mut var_values, query))
26 .collect();
27
28 let meta_vars = meta_vars.map(|vars| {
29 vars.into_iter()
30 .map(|var| *var_values.get(&var).unwrap())
31 .collect::<Vec<usize>>()
32 });
33
34 let constrained_vars = constrained_vars.map(|vars| {
35 vars.into_iter()
36 .map(|var| *var_values.get(&var).unwrap())
37 .collect::<Vec<usize>>()
38 });
39
40 Clause::new(literals, meta_vars, constrained_vars)
41}
42
43fn extract_var_names_from_set(term: Term) -> Vec<String> {
45 if let Term::Set(set_terms) = term {
46 set_terms
47 .into_iter()
48 .map(|t| {
49 if let Term::Unit(Unit::Variable(symbol)) = t {
50 symbol
51 } else {
52 panic!("meta variable set should only contain variables")
53 }
54 })
55 .collect()
56 } else {
57 panic!("Expected a Set term")
58 }
59}
60
61fn extract_var_names_from_list(term: Term) -> Vec<String> {
63 if let Term::List(list_terms, tail) = term {
64 assert!(
65 matches!(*tail, Term::EmptyList),
66 "Unconstrained variable list must not have a tail"
67 );
68 list_terms
69 .into_iter()
70 .map(|t| {
71 if let Term::Unit(Unit::Variable(symbol)) = t {
72 symbol
73 } else {
74 panic!("unconstrained variable list should only contain variables")
75 }
76 })
77 .collect()
78 } else {
79 panic!("Expected a List term")
80 }
81}
82
83fn extract_meta_rule_vars(terms: &mut Vec<Term>) -> (Vec<String>, Option<Vec<String>>) {
90 let last = terms.pop().unwrap();
91 match last {
92 Term::Set(_) => {
94 let meta_vars = extract_var_names_from_set(last);
95 (meta_vars, None)
96 }
97 Term::List(_, _) => {
99 let unconstrained = extract_var_names_from_list(last);
100 let constrained = if matches!(terms.last(), Some(Term::Set(_))) {
102 extract_var_names_from_set(terms.pop().unwrap())
103 } else {
104 Vec::new()
106 };
107 let mut meta_vars = constrained.clone();
108 meta_vars.extend(unconstrained);
109 (meta_vars, Some(constrained))
110 }
111 _ => panic!("Last literal in meta_rule wasn't a set or list"),
112 }
113}
114
115pub(crate) fn execute_tree(
116 syntax_tree: Vec<TreeClause>,
117 heap: &mut impl Heap,
118 pred_table: &mut PredicateTable,
119) {
120 for clause in syntax_tree {
121 match clause {
122 TreeClause::Fact(term) => {
123 let clause = build_clause(vec![term], None, None, heap, false);
124 let symbol_arity = heap.str_symbol_arity(clause[0]);
125 pred_table
126 .add_clause_to_predicate(clause, symbol_arity)
127 .unwrap();
128 }
129 TreeClause::Rule(terms) => {
130 let clause = build_clause(terms, None, None, heap, false);
131 let symbol_arity = heap.str_symbol_arity(clause[0]);
132 pred_table
133 .add_clause_to_predicate(clause, symbol_arity)
134 .unwrap();
135 }
136 TreeClause::MetaRule(mut terms) => {
137 let (meta_vars, constrained_vars) = extract_meta_rule_vars(&mut terms);
138 let clause = build_clause(terms, Some(meta_vars), constrained_vars, heap, false);
139 let symbol_arity = heap.str_symbol_arity(clause[0]);
140 pred_table
141 .add_clause_to_predicate(clause, symbol_arity)
142 .unwrap();
143 }
144 TreeClause::MetaFact(head, meta_data) => {
145 let meta_vars = extract_var_names_from_set(meta_data);
146 let clause = build_clause(vec![head], Some(meta_vars), None, heap, false);
147 let symbol_arity = heap.str_symbol_arity(clause[0]);
148 pred_table
149 .add_clause_to_predicate(clause, symbol_arity)
150 .unwrap();
151 }
152 TreeClause::Directive(_terms) => {
153 unimplemented!("directive execution not yet supported")
154 }
155 }
156 }
157}
158
159#[cfg(test)]
160mod tests {
161 use crate::{
162 heap::{
163 heap::{Cell, Tag},
164 symbol_db::SymbolDB,
165 },
166 parser::execute_tree::execute_tree,
167 program::predicate_table::{Predicate, PredicateTable},
168 };
169
170 use super::super::{build_tree::TokenStream, tokeniser::tokenise};
171
172 #[test]
173 fn facts() {
174 let mut heap = Vec::<Cell>::new();
175 let mut pred_table = PredicateTable::new();
176 let facts = TokenStream::new(tokenise("p(a,b).q(c).".into()).unwrap())
177 .parse_all()
178 .unwrap();
179
180 let [p, q, a, b, c] = ["p", "q", "a", "b", "c"].map(|s| SymbolDB::set_const(s.into()));
181
182 execute_tree(facts, &mut heap, &mut pred_table);
183
184 if let Predicate::Clauses(clauses) = pred_table.get_predicate((p, 2)).unwrap() {
185 let fact = &clauses[0];
186 assert_eq!(
187 &heap[fact[0]..fact[0] + 4],
188 &[(Tag::Func, 3), (Tag::Con, p), (Tag::Con, a), (Tag::Con, b),]
189 );
190 } else {
191 panic!()
192 }
193
194 if let Predicate::Clauses(clauses) = pred_table.get_predicate((q, 1)).unwrap() {
195 let fact = &clauses[0];
196 assert_eq!(
197 &heap[fact[0]..fact[0] + 3],
198 &[(Tag::Func, 2), (Tag::Con, q), (Tag::Con, c),]
199 );
200 } else {
201 panic!()
202 }
203 }
204
205 #[test]
206 fn rules() {
207 let mut heap = Vec::<Cell>::new();
208 let mut pred_table = PredicateTable::new();
209 let facts = TokenStream::new(
210 tokenise("p(X,Y):-q(X,a),q(Y,b). q(X):-r(X). q(X):-p(X).".into()).unwrap(),
211 )
212 .parse_all()
213 .unwrap();
214
215 let [p, q, r, a, b] = ["p", "q", "r", "a", "b"].map(|s| SymbolDB::set_const(s.into()));
216
217 execute_tree(facts, &mut heap, &mut pred_table);
218
219 if let Predicate::Clauses(clauses) = pred_table.get_predicate((p, 2)).unwrap() {
220 let rule = &clauses[0];
221 assert_eq!(
222 &heap[rule[0]..rule[0] + 4],
223 &[(Tag::Func, 3), (Tag::Con, p), (Tag::Arg, 0), (Tag::Arg, 1),]
224 );
225 assert_eq!(
226 &heap[rule[1]..rule[1] + 4],
227 &[(Tag::Func, 3), (Tag::Con, q), (Tag::Arg, 0), (Tag::Con, a),]
228 );
229 assert_eq!(
230 &heap[rule[2]..rule[2] + 4],
231 &[(Tag::Func, 3), (Tag::Con, q), (Tag::Arg, 1), (Tag::Con, b),]
232 );
233 } else {
234 panic!()
235 }
236
237 if let Predicate::Clauses(clauses) = pred_table.get_predicate((q, 1)).unwrap() {
238 let rule = &clauses[0];
239 assert_eq!(
240 &heap[rule[0]..rule[0] + 3],
241 &[(Tag::Func, 2), (Tag::Con, q), (Tag::Arg, 0),]
242 );
243 assert_eq!(
244 &heap[rule[1]..rule[1] + 3],
245 &[(Tag::Func, 2), (Tag::Con, r), (Tag::Arg, 0),]
246 );
247
248 let rule = &clauses[1];
249 assert_eq!(
250 &heap[rule[0]..rule[0] + 3],
251 &[(Tag::Func, 2), (Tag::Con, q), (Tag::Arg, 0),]
252 );
253 assert_eq!(
254 &heap[rule[1]..rule[1] + 3],
255 &[(Tag::Func, 2), (Tag::Con, p), (Tag::Arg, 0),]
256 );
257 } else {
258 panic!()
259 }
260 }
261
262 #[test]
263 fn meta_rules() {
264 let mut heap = Vec::<Cell>::new();
265 let mut pred_table = PredicateTable::new();
266 let facts = TokenStream::new(tokenise("p(X,Y):-Q(X,a),R(Y,b),{Q,R}.".into()).unwrap())
267 .parse_all()
268 .unwrap();
269
270 let [p, _q, _r, a, b] = ["p", "q", "r", "a", "b"].map(|s| SymbolDB::set_const(s.into()));
271
272 execute_tree(facts, &mut heap, &mut pred_table);
273
274 if let Predicate::Clauses(clauses) = pred_table.get_predicate((p, 2)).unwrap() {
275 let meta_rule = &clauses[0];
276 assert_eq!(
277 &heap[meta_rule[0]..meta_rule[0] + 4],
278 &[(Tag::Func, 3), (Tag::Con, p), (Tag::Arg, 0), (Tag::Arg, 1),]
279 );
280 assert_eq!(
281 &heap[meta_rule[1]..meta_rule[1] + 4],
282 &[(Tag::Func, 3), (Tag::Arg, 2), (Tag::Arg, 0), (Tag::Con, a),]
283 );
284 assert_eq!(
285 &heap[meta_rule[2]..meta_rule[2] + 4],
286 &[(Tag::Func, 3), (Tag::Arg, 3), (Tag::Arg, 1), (Tag::Con, b),]
287 );
288 assert!(meta_rule.meta_var(2).unwrap());
289 assert!(meta_rule.meta_var(3).unwrap());
290 assert!(meta_rule.constrained_var(2));
292 assert!(meta_rule.constrained_var(3));
293 assert!(!meta_rule.constrained_var(0));
294 assert!(!meta_rule.constrained_var(1));
295 } else {
296 panic!()
297 }
298 }
299
300 #[test]
301 fn meta_rules_with_unconstrained_list() {
302 let mut heap = Vec::<Cell>::new();
307 let mut pred_table = PredicateTable::new();
308 let facts =
309 TokenStream::new(tokenise("edge(El,Q1,Q2):-q(Q1),q(Q2),{El},[Q1,Q2].".into()).unwrap())
310 .parse_all()
311 .unwrap();
312
313 let edge = SymbolDB::set_const("edge".into());
314 let _q = SymbolDB::set_const("q".into());
315
316 execute_tree(facts, &mut heap, &mut pred_table);
317
318 if let Predicate::Clauses(clauses) = pred_table.get_predicate((edge, 3)).unwrap() {
319 let meta_rule = &clauses[0];
320 assert!(meta_rule.meta_var(0).unwrap()); assert!(meta_rule.meta_var(1).unwrap()); assert!(meta_rule.meta_var(2).unwrap()); assert!(meta_rule.constrained_var(0)); assert!(!meta_rule.constrained_var(1)); assert!(!meta_rule.constrained_var(2)); } else {
329 panic!("Expected clauses for edge/3")
330 }
331 }
332
333 #[test]
334 fn meta_rules_list_only() {
335 let mut heap = Vec::<Cell>::new();
340 let mut pred_table = PredicateTable::new();
341 let facts =
342 TokenStream::new(tokenise("edge(El,Q1,Q2):-q(Q1),q(Q2),[El,Q1,Q2].".into()).unwrap())
343 .parse_all()
344 .unwrap();
345
346 let edge = SymbolDB::set_const("edge".into());
347 let _q = SymbolDB::set_const("q".into());
348
349 execute_tree(facts, &mut heap, &mut pred_table);
350
351 if let Predicate::Clauses(clauses) = pred_table.get_predicate((edge, 3)).unwrap() {
352 let meta_rule = &clauses[0];
353 assert!(meta_rule.meta_var(0).unwrap()); assert!(meta_rule.meta_var(1).unwrap()); assert!(meta_rule.meta_var(2).unwrap()); assert!(!meta_rule.constrained_var(0));
359 assert!(!meta_rule.constrained_var(1));
360 assert!(!meta_rule.constrained_var(2));
361 } else {
362 panic!("Expected clauses for edge/3")
363 }
364 }
365
366 #[test]
367 fn meta_facts() {
368 let mut heap = Vec::<Cell>::new();
369 let mut pred_table = PredicateTable::new();
370 let facts = TokenStream::new(tokenise("Map([],[],X),{Map}.".into()).unwrap())
371 .parse_all()
372 .unwrap();
373
374 execute_tree(facts, &mut heap, &mut pred_table);
375
376 assert!(!heap.is_empty());
383
384 assert_eq!(heap[0], (Tag::Func, 4));
387 assert_eq!(heap[1], (Tag::Arg, 0)); assert_eq!(heap[2].0, Tag::ELis); assert_eq!(heap[3].0, Tag::ELis); assert_eq!(heap[4], (Tag::Arg, 1)); }
392}