1use super::prologgoalbuilder_type::PrologGoalBuilder;
6use super::types::{
7 DcgRhs, DcgRule, PrologArith, PrologAssertionBuilder, PrologBackend, PrologClause,
8 PrologClauseBuilder, PrologConstraints, PrologDCGBuilder, PrologDirective,
9 PrologMetaPredicates, PrologMode, PrologModule, PrologModuleBuilder, PrologPredicate,
10 PrologPredicateBuilder, PrologSnippets, PrologTerm, PrologType, PrologTypeSig,
11};
12use std::fmt;
13
14pub(super) fn fmt_dcg_seq(f: &mut fmt::Formatter<'_>, parts: &[DcgRhs]) -> fmt::Result {
15 for (i, p) in parts.iter().enumerate() {
16 if i > 0 {
17 write!(f, ", ")?;
18 }
19 write!(f, "{}", p)?;
20 }
21 Ok(())
22}
23pub fn atom(s: impl Into<String>) -> PrologTerm {
25 PrologTerm::Atom(s.into())
26}
27pub fn var(s: impl Into<String>) -> PrologTerm {
29 PrologTerm::Variable(s.into())
30}
31pub fn int(n: i64) -> PrologTerm {
33 PrologTerm::Integer(n)
34}
35pub fn float_term(x: f64) -> PrologTerm {
37 PrologTerm::Float(x)
38}
39pub fn compound(functor: impl Into<String>, args: Vec<PrologTerm>) -> PrologTerm {
41 PrologTerm::Compound(functor.into(), args)
42}
43pub fn list(elems: Vec<PrologTerm>) -> PrologTerm {
45 PrologTerm::List(elems, None)
46}
47pub fn op_term(op: impl Into<String>, l: PrologTerm, r: PrologTerm) -> PrologTerm {
49 PrologTerm::Op(op.into(), Box::new(l), Box::new(r))
50}
51#[cfg(test)]
52mod tests {
53 use super::*;
54 #[test]
55 pub(super) fn test_atom_display() {
56 assert_eq!(format!("{}", atom("foo")), "foo");
57 assert_eq!(format!("{}", atom("Hello")), "'Hello'");
58 assert_eq!(format!("{}", atom("hello world")), "'hello world'");
59 assert_eq!(format!("{}", PrologTerm::Nil), "[]");
60 assert_eq!(format!("{}", PrologTerm::Cut), "!");
61 assert_eq!(format!("{}", PrologTerm::Anon), "_");
62 }
63 #[test]
64 pub(super) fn test_integer_float_display() {
65 assert_eq!(format!("{}", int(42)), "42");
66 assert_eq!(format!("{}", int(-7)), "-7");
67 assert_eq!(format!("{}", float_term(3.14)), "3.14");
68 assert_eq!(format!("{}", float_term(1.0)), "1.0");
69 let ft = PrologTerm::Float(1.0);
70 let s = format!("{}", ft);
71 assert!(s == "1.0" || s == "1", "got: {}", s);
72 }
73 #[test]
74 pub(super) fn test_compound_display() {
75 let t = compound("f", vec![atom("a"), var("X"), int(1)]);
76 assert_eq!(format!("{}", t), "f(a, X, 1)");
77 }
78 #[test]
79 pub(super) fn test_list_display() {
80 let t = list(vec![int(1), int(2), int(3)]);
81 assert_eq!(format!("{}", t), "[1, 2, 3]");
82 let partial = PrologTerm::list_partial(vec![var("H")], var("T"));
83 assert_eq!(format!("{}", partial), "[H|T]");
84 assert_eq!(format!("{}", PrologTerm::Nil), "[]");
85 }
86 #[test]
87 pub(super) fn test_op_display() {
88 let t = op_term("is", var("X"), op_term("+", var("Y"), int(1)));
89 let s = format!("{}", t);
90 assert!(s.contains("is"), "got: {}", s);
91 assert!(s.contains('+'), "got: {}", s);
92 }
93 #[test]
94 pub(super) fn test_fact_emit() {
95 let f = PrologClause::fact(compound(
96 "member",
97 vec![var("X"), list(vec![var("X"), var("_")])],
98 ));
99 let s = f.emit();
100 assert!(s.ends_with('.'));
101 assert!(s.contains("member"));
102 assert!(!s.contains(":-"));
103 }
104 #[test]
105 pub(super) fn test_rule_emit() {
106 let head = compound(
107 "member",
108 vec![var("X"), compound(".", vec![var("_"), var("T")])],
109 );
110 let body = vec![compound("member", vec![var("X"), var("T")])];
111 let r = PrologClause::rule(head, body);
112 let s = r.emit();
113 assert!(s.contains(":-"), "got: {}", s);
114 assert!(s.ends_with('.'));
115 assert!(s.contains("member(X, T)"));
116 }
117 #[test]
118 pub(super) fn test_rule_multigoal_emit() {
119 let head = compound(
120 "append",
121 vec![
122 compound(".", vec![var("H"), var("T")]),
123 var("L"),
124 compound(".", vec![var("H"), var("R")]),
125 ],
126 );
127 let body = vec![compound("append", vec![var("T"), var("L"), var("R")])];
128 let r = PrologClause::rule(head, body);
129 let s = r.emit();
130 assert!(s.contains(":-"));
131 assert!(s.ends_with('.'));
132 }
133 #[test]
134 pub(super) fn test_predicate_emit() {
135 let mut pred = PrologPredicate::new("length", 2).dynamic().exported();
136 pred.add_clause(PrologClause::fact(compound(
137 "length",
138 vec![PrologTerm::Nil, int(0)],
139 )));
140 pred.add_clause(PrologClause::rule(
141 compound(
142 "length",
143 vec![compound(".", vec![var("_"), var("T")]), var("N")],
144 ),
145 vec![
146 compound("length", vec![var("T"), var("N1")]),
147 op_term("is", var("N"), op_term("+", var("N1"), int(1))),
148 ],
149 ));
150 let s = pred.emit();
151 assert!(s.contains(":- dynamic length/2."));
152 assert!(s.contains("length([], 0)."));
153 assert!(s.contains(":-"));
154 assert_eq!(pred.indicator(), "length/2");
155 }
156 #[test]
157 pub(super) fn test_directive_emit() {
158 let d = PrologDirective::Module("lists".into(), vec!["member/2".into(), "append/3".into()]);
159 let s = d.emit();
160 assert!(s.starts_with(":- module(lists,"));
161 assert!(s.contains("member/2"));
162 assert!(s.contains("append/3"));
163 let d2 = PrologDirective::UseModuleLibrary("lists".into());
164 assert_eq!(d2.emit(), ":- use_module(library(lists)).");
165 let d3 = PrologDirective::Dynamic("fact".into(), 1);
166 assert_eq!(d3.emit(), ":- dynamic fact/1.");
167 let d4 = PrologDirective::Op(700, "xfx".into(), "===".into());
168 assert_eq!(d4.emit(), ":- op(700, xfx, ===).");
169 }
170 #[test]
171 pub(super) fn test_dcg_rule_emit() {
172 let rule = DcgRule {
173 lhs: compound("sentence", vec![var("S")]),
174 rhs: vec![
175 DcgRhs::NonTerminal(compound("np", vec![var("S")])),
176 DcgRhs::NonTerminal(atom("vp")),
177 ],
178 guards: vec![],
179 comment: None,
180 };
181 let s = rule.emit();
182 assert!(s.contains("-->"), "got: {}", s);
183 assert!(s.contains("np(S)"), "got: {}", s);
184 assert!(s.contains("vp"), "got: {}", s);
185 }
186 #[test]
187 pub(super) fn test_dcg_terminals_emit() {
188 let rule = DcgRule {
189 lhs: atom("greeting"),
190 rhs: vec![
191 DcgRhs::Terminals(vec![atom("hello")]),
192 DcgRhs::NonTerminal(atom("name")),
193 ],
194 guards: vec![],
195 comment: Some("Match a greeting phrase".into()),
196 };
197 let s = rule.emit();
198 assert!(s.starts_with("% Match a greeting phrase"));
199 assert!(s.contains("[hello]"), "got: {}", s);
200 }
201 #[test]
202 pub(super) fn test_module_emit() {
203 let backend = PrologBackend::swi();
204 let mut module = PrologModule::new("mylist");
205 module.export("member/2");
206 module.export("append/3");
207 module.directive(PrologDirective::UseModuleLibrary("lists".into()));
208 module.blank();
209 let mut member_pred = PrologPredicate::new("member", 2).exported();
210 member_pred.add_clause(PrologClause::fact(compound(
211 "member",
212 vec![var("X"), list(vec![var("X"), var("_")])],
213 )));
214 member_pred.add_clause(PrologClause::rule(
215 compound(
216 "member",
217 vec![var("X"), compound(".", vec![var("_"), var("T")])],
218 ),
219 vec![compound("member", vec![var("X"), var("T")])],
220 ));
221 module.predicate(member_pred);
222 let s = backend.emit_module(&module);
223 assert!(s.contains(":- module(mylist,"), "got: {}", s);
224 assert!(s.contains("member/2"), "got: {}", s);
225 assert!(s.contains("append/3"), "got: {}", s);
226 assert!(s.contains(":- use_module(library(lists))."), "got: {}", s);
227 assert!(s.contains("member(X, [X, _])."), "got: {}", s);
228 }
229 #[test]
230 pub(super) fn test_swi_preamble() {
231 let backend = PrologBackend::swi();
232 let preamble = backend.build_swi_preamble(
233 "utils",
234 &[("helper", 1), ("transform", 2)],
235 &["lists", "aggregate"],
236 );
237 assert!(preamble.contains(":- module(utils,"));
238 assert!(preamble.contains("helper/1"));
239 assert!(preamble.contains("transform/2"));
240 assert!(preamble.contains(":- use_module(library(lists))."));
241 assert!(preamble.contains(":- use_module(library(aggregate))."));
242 }
243}
244#[allow(dead_code)]
246pub fn not_provable(goal: PrologTerm) -> PrologTerm {
247 PrologTerm::PrefixOp("\\+".to_string(), Box::new(goal))
248}
249#[allow(dead_code)]
251pub fn if_then_else(cond: PrologTerm, then_: PrologTerm, else_: PrologTerm) -> PrologTerm {
252 PrologTerm::Op(
253 ";".to_string(),
254 Box::new(PrologTerm::Op(
255 "->".to_string(),
256 Box::new(cond),
257 Box::new(then_),
258 )),
259 Box::new(else_),
260 )
261}
262#[allow(dead_code)]
264pub fn conjunction(a: PrologTerm, b: PrologTerm) -> PrologTerm {
265 PrologTerm::Op(",".to_string(), Box::new(a), Box::new(b))
266}
267#[allow(dead_code)]
269pub fn disjunction(a: PrologTerm, b: PrologTerm) -> PrologTerm {
270 PrologTerm::Op(";".to_string(), Box::new(a), Box::new(b))
271}
272#[allow(dead_code)]
274pub fn unify(x: PrologTerm, y: PrologTerm) -> PrologTerm {
275 PrologTerm::Op("=".to_string(), Box::new(x), Box::new(y))
276}
277#[allow(dead_code)]
279pub fn not_unify(x: PrologTerm, y: PrologTerm) -> PrologTerm {
280 PrologTerm::Op("\\=".to_string(), Box::new(x), Box::new(y))
281}
282#[allow(dead_code)]
284pub fn strict_eq(x: PrologTerm, y: PrologTerm) -> PrologTerm {
285 PrologTerm::Op("==".to_string(), Box::new(x), Box::new(y))
286}
287#[allow(dead_code)]
289pub fn strict_neq(x: PrologTerm, y: PrologTerm) -> PrologTerm {
290 PrologTerm::Op("\\==".to_string(), Box::new(x), Box::new(y))
291}
292#[allow(dead_code)]
294pub fn is_eval(x: PrologTerm, expr: PrologTerm) -> PrologTerm {
295 PrologTerm::Op("is".to_string(), Box::new(x), Box::new(expr))
296}
297#[allow(dead_code)]
299pub fn arith_eq(x: PrologTerm, y: PrologTerm) -> PrologTerm {
300 PrologTerm::Op("=:=".to_string(), Box::new(x), Box::new(y))
301}
302#[allow(dead_code)]
304pub fn arith_neq(x: PrologTerm, y: PrologTerm) -> PrologTerm {
305 PrologTerm::Op("=\\=".to_string(), Box::new(x), Box::new(y))
306}
307#[allow(dead_code)]
309pub fn arith_lt(x: PrologTerm, y: PrologTerm) -> PrologTerm {
310 PrologTerm::Op("<".to_string(), Box::new(x), Box::new(y))
311}
312#[allow(dead_code)]
314pub fn arith_gt(x: PrologTerm, y: PrologTerm) -> PrologTerm {
315 PrologTerm::Op(">".to_string(), Box::new(x), Box::new(y))
316}
317#[allow(dead_code)]
319pub fn term_lt(x: PrologTerm, y: PrologTerm) -> PrologTerm {
320 PrologTerm::Op("@<".to_string(), Box::new(x), Box::new(y))
321}
322#[allow(dead_code)]
324pub fn term_gt(x: PrologTerm, y: PrologTerm) -> PrologTerm {
325 PrologTerm::Op("@>".to_string(), Box::new(x), Box::new(y))
326}
327#[allow(dead_code)]
329pub fn arith_add(x: PrologTerm, y: PrologTerm) -> PrologTerm {
330 PrologTerm::Op("+".to_string(), Box::new(x), Box::new(y))
331}
332#[allow(dead_code)]
334pub fn arith_sub(x: PrologTerm, y: PrologTerm) -> PrologTerm {
335 PrologTerm::Op("-".to_string(), Box::new(x), Box::new(y))
336}
337#[allow(dead_code)]
339pub fn arith_mul(x: PrologTerm, y: PrologTerm) -> PrologTerm {
340 PrologTerm::Op("*".to_string(), Box::new(x), Box::new(y))
341}
342#[allow(dead_code)]
344pub fn arith_mod(x: PrologTerm, y: PrologTerm) -> PrologTerm {
345 PrologTerm::Op("mod".to_string(), Box::new(x), Box::new(y))
346}
347#[allow(dead_code)]
349pub fn arith_div(x: PrologTerm, y: PrologTerm) -> PrologTerm {
350 PrologTerm::Op("div".to_string(), Box::new(x), Box::new(y))
351}
352#[cfg(test)]
353mod extended_prolog_tests {
354 use super::*;
355 #[test]
356 pub(super) fn test_not_provable() {
357 let t = not_provable(atom("foo"));
358 let s = format!("{}", t);
359 assert!(s.contains("\\+"));
360 assert!(s.contains("foo"));
361 }
362 #[test]
363 pub(super) fn test_conjunction() {
364 let t = conjunction(atom("a"), atom("b"));
365 let s = format!("{}", t);
366 assert!(s.contains("a"));
367 assert!(s.contains("b"));
368 assert!(s.contains(","));
369 }
370 #[test]
371 pub(super) fn test_disjunction() {
372 let t = disjunction(atom("a"), atom("b"));
373 let s = format!("{}", t);
374 assert!(s.contains(";"));
375 }
376 #[test]
377 pub(super) fn test_unify_ops() {
378 let t = unify(var("X"), int(5));
379 let s = format!("{}", t);
380 assert!(s.contains('='));
381 let t2 = not_unify(var("X"), var("Y"));
382 assert!(format!("{}", t2).contains("\\="));
383 }
384 #[test]
385 pub(super) fn test_strict_eq_neq() {
386 let t = strict_eq(var("X"), var("Y"));
387 assert!(format!("{}", t).contains("=="));
388 let t2 = strict_neq(var("X"), var("Y"));
389 assert!(format!("{}", t2).contains("\\=="));
390 }
391 #[test]
392 pub(super) fn test_arith_ops() {
393 let t = is_eval(var("X"), arith_add(var("Y"), int(1)));
394 let s = format!("{}", t);
395 assert!(s.contains("is"));
396 assert!(s.contains('+'));
397 let sub = arith_sub(var("A"), var("B"));
398 assert!(format!("{}", sub).contains('-'));
399 let mul = arith_mul(var("A"), var("B"));
400 assert!(format!("{}", mul).contains('*'));
401 let md = arith_mod(var("A"), int(2));
402 assert!(format!("{}", md).contains("mod"));
403 let dv = arith_div(var("A"), int(2));
404 assert!(format!("{}", dv).contains("div"));
405 }
406 #[test]
407 pub(super) fn test_if_then_else() {
408 let t = if_then_else(atom("cond"), atom("then"), atom("els"));
409 let s = format!("{}", t);
410 assert!(s.contains("->") || s.contains(';'));
411 }
412 #[test]
413 pub(super) fn test_goal_builder() {
414 let goals = PrologGoalBuilder::new()
415 .is(var("N"), arith_add(var("M"), int(1)))
416 .writeln(var("N"))
417 .cut()
418 .build();
419 assert_eq!(goals.len(), 3);
420 let clause = PrologGoalBuilder::new()
421 .member(var("X"), var("List"))
422 .to_clause(compound("find_member", vec![var("X"), var("List")]));
423 assert!(!clause.body.is_empty());
424 }
425 #[test]
426 pub(super) fn test_goal_builder_list_ops() {
427 let goals = PrologGoalBuilder::new()
428 .length(var("L"), var("N"))
429 .append(var("A"), var("B"), var("C"))
430 .reverse(var("L"), var("R"))
431 .sort(var("L"), var("S"))
432 .msort(var("L"), var("M"))
433 .build();
434 assert_eq!(goals.len(), 5);
435 }
436 #[test]
437 pub(super) fn test_goal_builder_meta() {
438 let goals = PrologGoalBuilder::new()
439 .maplist1(atom("atom"), var("List"))
440 .maplist2(atom("succ"), var("L"), var("R"))
441 .include(atom("integer"), var("L"), var("Ints"))
442 .exclude(atom("integer"), var("L"), var("NonInts"))
443 .build();
444 assert_eq!(goals.len(), 4);
445 }
446 #[test]
447 pub(super) fn test_arith_builder() {
448 let a = PrologArith::add(var("X"), int(1));
449 assert!(format!("{}", a).contains('+'));
450 let b = PrologArith::abs(var("X"));
451 assert!(format!("{}", b).contains("abs"));
452 let m = PrologArith::max(int(3), int(5));
453 assert!(format!("{}", m).contains("max"));
454 let pw = PrologArith::pow(var("X"), int(2));
455 assert!(format!("{}", pw).contains('^'));
456 let ba = PrologArith::bitand(var("X"), var("Y"));
457 assert!(format!("{}", ba).contains("/\\"));
458 let bo = PrologArith::bitor(var("X"), var("Y"));
459 assert!(format!("{}", bo).contains("\\/"));
460 }
461 #[test]
462 pub(super) fn test_prolog_type_display() {
463 assert_eq!(format!("{}", PrologType::Integer), "integer");
464 assert_eq!(format!("{}", PrologType::Atom), "atom");
465 assert_eq!(format!("{}", PrologType::Boolean), "boolean");
466 let list_ty = PrologType::List(Box::new(PrologType::Integer));
467 assert!(format!("{}", list_ty).contains("list(integer)"));
468 }
469 #[test]
470 pub(super) fn test_prolog_mode_display() {
471 assert_eq!(format!("{}", PrologMode::In), "+");
472 assert_eq!(format!("{}", PrologMode::Out), "-");
473 assert_eq!(format!("{}", PrologMode::InOut), "?");
474 assert_eq!(format!("{}", PrologMode::Meta), ":");
475 }
476 #[test]
477 pub(super) fn test_prolog_type_sig_pldoc() {
478 let sig = PrologTypeSig {
479 name: "append".to_string(),
480 params: vec![
481 (PrologMode::In, PrologType::List(Box::new(PrologType::Term))),
482 (PrologMode::In, PrologType::List(Box::new(PrologType::Term))),
483 (
484 PrologMode::Out,
485 PrologType::List(Box::new(PrologType::Term)),
486 ),
487 ],
488 description: Some("Append two lists.".to_string()),
489 };
490 let s = sig.emit_pldoc();
491 assert!(s.contains("%% append/3"));
492 assert!(s.contains("list"));
493 let s2 = sig.emit_pred_directive();
494 assert!(s2.contains(":- pred"));
495 }
496 #[test]
497 pub(super) fn test_meta_predicates() {
498 let t = PrologMetaPredicates::maplist(atom("write"), var("L"));
499 assert!(format!("{}", t).contains("maplist"));
500 let t2 = PrologMetaPredicates::findall(var("X"), atom("goal"), var("Bag"));
501 assert!(format!("{}", t2).contains("findall"));
502 let t3 = PrologMetaPredicates::once(atom("goal"));
503 assert!(format!("{}", t3).contains("once"));
504 let t4 = PrologMetaPredicates::forall(atom("cond"), atom("act"));
505 assert!(format!("{}", t4).contains("forall"));
506 }
507 #[test]
508 pub(super) fn test_assertion_builder() {
509 let t = PrologAssertionBuilder::assertz_fact(compound("fact", vec![int(1)]));
510 assert!(format!("{}", t).contains("assertz"));
511 let t2 = PrologAssertionBuilder::retractall(compound("fact", vec![var("_")]));
512 assert!(format!("{}", t2).contains("retractall"));
513 let t3 = PrologAssertionBuilder::abolish("fact", 1);
514 assert!(format!("{}", t3).contains("abolish"));
515 }
516 #[test]
517 pub(super) fn test_constraints() {
518 let c1 = PrologConstraints::clp_eq(var("X"), int(5));
519 assert!(format!("{}", c1).contains("#="));
520 let c2 = PrologConstraints::clp_lt(var("X"), int(10));
521 assert!(format!("{}", c2).contains("#<"));
522 let c3 = PrologConstraints::all_different(vec![var("X"), var("Y"), var("Z")]);
523 assert!(format!("{}", c3).contains("all_different"));
524 let c4 = PrologConstraints::label(vec![var("X")]);
525 assert!(format!("{}", c4).contains("label"));
526 }
527 #[test]
528 pub(super) fn test_snippets_member() {
529 let pred = PrologSnippets::member_predicate();
530 let s = pred.emit();
531 assert!(s.contains("member"));
532 assert_eq!(pred.arity, 2);
533 }
534 #[test]
535 pub(super) fn test_snippets_append() {
536 let pred = PrologSnippets::append_predicate();
537 let s = pred.emit();
538 assert!(s.contains("append"));
539 assert_eq!(pred.arity, 3);
540 }
541 #[test]
542 pub(super) fn test_snippets_length() {
543 let pred = PrologSnippets::length_predicate();
544 let s = pred.emit();
545 assert!(s.contains("my_length"));
546 }
547 #[test]
548 pub(super) fn test_snippets_max_list() {
549 let pred = PrologSnippets::max_list_predicate();
550 let s = pred.emit();
551 assert!(s.contains("max_list"));
552 }
553 #[test]
554 pub(super) fn test_snippets_sum_list() {
555 let pred = PrologSnippets::sum_list_predicate();
556 let s = pred.emit();
557 assert!(s.contains("sum_list"));
558 }
559 #[test]
560 pub(super) fn test_snippets_last() {
561 let pred = PrologSnippets::last_predicate();
562 let s = pred.emit();
563 assert!(s.contains("my_last"));
564 }
565 #[test]
566 pub(super) fn test_module_builder() {
567 let s = PrologModuleBuilder::new("utils")
568 .export("member/2")
569 .use_library("lists")
570 .add_predicate(PrologSnippets::member_predicate())
571 .blank()
572 .section("List utilities")
573 .comment("End of module")
574 .emit();
575 assert!(s.contains(":- module(utils,"));
576 assert!(s.contains("member/2"));
577 assert!(s.contains(":- use_module(library(lists))."));
578 }
579 #[test]
580 pub(super) fn test_clause_builder_fact() {
581 let clause = PrologClauseBuilder::head(compound("hello", vec![atom("world")]))
582 .comment("A greeting fact")
583 .build();
584 let s = clause.emit();
585 assert!(s.contains("hello"));
586 assert!(s.ends_with('.'));
587 assert!(s.contains("A greeting fact"));
588 }
589 #[test]
590 pub(super) fn test_clause_builder_rule() {
591 let clause = PrologClauseBuilder::head(compound("greet", vec![var("X")]))
592 .goal(compound(
593 "format",
594 vec![atom("Hello ~w!~n"), PrologTerm::list(vec![var("X")])],
595 ))
596 .build();
597 let s = clause.emit();
598 assert!(s.contains("greet(X) :-"));
599 assert!(s.ends_with('.'));
600 }
601 #[test]
602 pub(super) fn test_predicate_builder() {
603 let s = PrologPredicateBuilder::new("count", 2)
604 .dynamic()
605 .exported()
606 .doc("Count occurrences.")
607 .fact(compound("count", vec![PrologTerm::Nil, int(0)]))
608 .rule(
609 compound("count", vec![var("L"), var("N")]),
610 vec![compound("length", vec![var("L"), var("N")])],
611 )
612 .emit();
613 assert!(s.contains(":- dynamic count/2."));
614 assert!(s.contains("count([], 0)."));
615 }
616 #[test]
617 pub(super) fn test_dcg_builder() {
618 let s = PrologDCGBuilder::lhs(atom("sentence"))
619 .nonterminal(atom("np"))
620 .nonterminal(atom("vp"))
621 .comment("A simple sentence rule")
622 .emit();
623 assert!(s.contains("-->"));
624 assert!(s.contains("np"));
625 assert!(s.contains("vp"));
626 assert!(s.contains("A simple sentence rule"));
627 }
628 #[test]
629 pub(super) fn test_dcg_builder_terminals() {
630 let s = PrologDCGBuilder::lhs(atom("greeting"))
631 .terminals(vec![atom("hello")])
632 .nonterminal(atom("name"))
633 .emit();
634 assert!(s.contains("[hello]"));
635 assert!(s.contains("name"));
636 }
637 #[test]
638 pub(super) fn test_dcg_builder_with_guard() {
639 let s = PrologDCGBuilder::lhs(compound("number", vec![var("N")]))
640 .nonterminal(compound("digit", vec![var("D")]))
641 .guard(is_eval(var("N"), var("D")))
642 .emit();
643 assert!(s.contains("digit"));
644 assert!(s.contains('{'));
645 }
646 #[test]
647 pub(super) fn test_nth0_predicate() {
648 let pred = PrologSnippets::nth0_predicate();
649 let s = pred.emit();
650 assert!(s.contains("my_nth0"));
651 assert_eq!(pred.arity, 3);
652 }
653 #[test]
654 pub(super) fn test_flatten_predicate() {
655 let pred = PrologSnippets::flatten_predicate();
656 let s = pred.emit();
657 assert!(s.contains("my_flatten"));
658 assert!(s.contains("is_list"));
659 }
660 #[test]
661 pub(super) fn test_term_order_ops() {
662 let lt = term_lt(var("X"), var("Y"));
663 assert!(format!("{}", lt).contains("@<"));
664 let gt = term_gt(var("X"), var("Y"));
665 assert!(format!("{}", gt).contains("@>"));
666 }
667 #[test]
668 pub(super) fn test_arith_eq_neq() {
669 let eq = arith_eq(var("X"), var("Y"));
670 assert!(format!("{}", eq).contains("=:="));
671 let neq = arith_neq(var("X"), var("Y"));
672 assert!(format!("{}", neq).contains("=\\="));
673 }
674 #[test]
675 pub(super) fn test_arith_lt_gt() {
676 let lt = arith_lt(var("X"), int(10));
677 assert!(format!("{}", lt).contains('<'));
678 let gt = arith_gt(var("X"), int(0));
679 assert!(format!("{}", gt).contains('>'));
680 }
681}