suiron/macros.rs
1//! Utilities for creating logic variables, complex terms, lists, etc.
2//!
3//! [add_rules!](../macro.add_rules.html) -
4//! Adds facts and rules to a knowledge base.<br>
5//! [anon!](../macro.anon.html) - Creates an anonymous variable.<br>
6//! [atom!](../macro.atom.html) - Makes an atom from a string slice.<br>
7//! [chars_to_string!](../macro.chars_to_string.html) -
8//! Converts a vector or array of chars to a String.<br>
9//! [cons_node!](../macro.cons_node.html) -
10//! Constructs one node of a singly linked list.<br>
11//! [empty_ss](../macro.empty_ss.html) -
12//! Creates an empty substitution set, with an Rc-pointer.<br>
13//! [logic_var!](../macro.logic_var.html) -
14//! Creates a logic variable from a string slice and an optional ID.<br>
15//! [and_goal!](../macro.and_goal.html) -
16//! Creates an And goal from a list of goals.<br>
17//! [or_goal!](../macro.or_goal.html) -
18//! Creates an Or goal from a list of goals.<br>
19//! [pred!](../macro.pred.html)
20//! Creates a built-in predicate or complex term, and wraps it in a Goal.<br>
21//! [query!](../macro.query.html) -
22//! Creates a query from a list of terms.<br>
23//! [rc_cell!](../macro.rc_cell.html) -
24//! Creates a smart pointer to mutable data.<br>
25//! [scomplex!](../macro.scomplex.html) -
26//! Creates a complex term (= compound term).<br>
27//! [sfunction!](../macro.sfunction.html) -
28//! Creates a built-in function.<br>
29//! [slist!](../macro.slist.html) - Builds a Suiron list.<br>
30//! [str_to_chars!](../macro.str_to_chars.html) -
31//! Converts a string slice to a vector of characters.<br>
32//! [unify](../macro.unify.html)
33//! Creates a Unify goal (=).
34
35/// Constructs one node of a singly linked list.
36///
37/// # Notes
38/// * This macro does no validation.
39/// * Ordinarily, use
40/// [slist!](../suiron/macro.slist.html) to make a Suiron list.
41/// # Arguments
42/// * `term` - [Unifiable](../suiron/unifiable/enum.Unifiable.html)
43/// * `next` - must be an
44/// [SLinkedList](../suiron/unifiable/enum.Unifiable.html#variant.SLinkedList) or
45/// [Nil](../suiron/unifiable/enum.Unifiable.html#variant.Nil)
46/// * `count` - number of nodes in the linked list
47/// * `tail_var` - boolean, true indicates that the term is a tail variable
48/// # Return
49/// * `node` -
50/// [SLinkedList](../suiron/unifiable/enum.Unifiable.html#variant.SLinkedList)
51/// # Usage
52/// * To build: [a | $X]
53///
54/// ```
55/// use suiron::*;
56///
57/// let x = logic_var!("$X");
58/// let a = atom!("a");
59/// let node1 = cons_node!(x, Nil, 1, true); // tail variable
60/// let node2 = cons_node!(a, node1, 2, false);
61/// println!("{}", node2); // Prints: [a | $X]
62/// ```
63#[macro_export]
64macro_rules! cons_node {
65 ($term:expr, $next:expr, $count:expr, $tail_var:expr) => {
66 Unifiable::SLinkedList{term: Box::new($term), next: Box::new($next),
67 count: $count, tail_var: $tail_var}
68 };
69}
70
71/// Builds a Suiron list.
72///
73/// Suiron lists are defined and used the same way as Prolog lists. Examples:<br>
74/// <blockquote>
75/// [a, b, c]<br>
76/// [a, b, c | $Tail]<br>
77/// [$Head | $Tail]
78/// </blockquote>
79/// Internally, these lists are implemented as singly linked lists.
80///
81/// # Arguments
82/// * `vbar` - boolean, true if there is a vertical bar (pipe): [a, b, c | $X]
83/// * `terms` - list of [Unifiable](../suiron/unifiable/enum.Unifiable.html) terms
84/// # Return
85/// * list -
86/// [SLinkedList](../suiron/unifiable/enum.Unifiable.html#variant.SLinkedList)
87/// # Usage
88/// * To build: [a, b, c]
89///
90/// ```
91/// use suiron::*;
92///
93/// let a = atom!("a");
94/// let b = atom!("b");
95/// let c = atom!("c");
96/// let list1 = slist!(false, a, b, c);
97/// ```
98///
99/// * To build: [a, b, c | $X]
100///
101/// ```
102/// use suiron::*;
103///
104/// let a = atom!("a");
105/// let b = atom!("b");
106/// let c = atom!("c");
107/// let x = logic_var!(next_id(), "$X");
108/// let list2 = slist!(true, a, b, c, x);
109/// ```
110///
111/// * To build: []
112///
113/// ```
114/// use suiron::*;
115///
116/// let list3 = slist!();
117/// ```
118#[macro_export]
119macro_rules! slist {
120 () => ( cons_node!(Unifiable::Nil, Unifiable::Nil, 0, false) ); // empty list
121 ($vbar:expr, $($terms:expr),*) => (
122 make_linked_list($vbar, vec!($($terms),*))
123 );
124}
125
126/// Adds facts and rules to a knowledge base.
127///
128/// # Arguments
129/// * [knowledge base](../suiron/knowledge_base/index.html)
130/// * list of [facts and rules](../suiron/rule/index.html)
131///
132/// # Usage
133///
134/// ```
135/// use suiron::*;
136///
137/// let rule1 = parse_rule("parent($X, $Y) :- mother($X, $Y).").unwrap();
138/// let rule2 = parse_rule("parent($X, $Y) :- father($X, $Y).").unwrap();
139/// let fact1 = parse_rule("music(The Cure, Just Like Heaven).").unwrap();
140/// let fact2 = parse_rule("music(China Crisis, Black Man Ray).").unwrap();
141///
142/// let mut kb = KnowledgeBase::new();
143/// add_rules!(&mut kb, rule1, rule2, fact1, fact2);
144/// print_kb(&kb);
145/// ```
146///
147/// Should print:
148/// <pre>
149/// ########## Contents of Knowledge Base ##########
150/// music/2
151/// music(The Cure, Just Like Heaven).
152/// music(China Crisis, Black Man Ray).
153/// parent/2
154/// parent($X, $Y) :- mother($X, $Y).
155/// parent($X, $Y) :- father($X, $Y).
156/// </pre>
157///
158/// # Note
159/// This macro calls the function
160/// [add_rules()](../suiron/knowledge_base/fn.add_rules.html).
161#[macro_export]
162macro_rules! add_rules {
163 ($kb:expr, $($rules:expr),*) => (
164 add_rules($kb, vec!($($rules),*))
165 );
166}
167
168/// Makes an atom from a string slice.
169///
170/// [Atom](../suiron/unifiable/enum.Unifiable.html#variant.Atom)s are
171/// string constants. Unlike Prolog, Suiron's atoms can be capitalized
172/// or lower case.<br>
173/// For example, in the complex term 'father(Anakin, Luke)',
174/// the terms 'father', 'Anakin', and 'Luke' are all atoms.
175///
176/// # Usage
177/// ```
178/// use suiron::*;
179///
180/// let functor = atom!("father");
181/// let term1 = atom!("Anakin");
182/// let term2 = atom!("Luke");
183/// ```
184///
185#[macro_export]
186macro_rules! atom {
187 ($the_str:expr) => {
188 Unifiable::Atom($the_str.to_string())
189 };
190}
191
192/// Creates a logic variable from a string slice and an optional ID.
193///
194/// Suiron variables are similar to Prolog variables, except that the
195/// names begin with a dollar sign.<br>
196/// For example:
197/// <blockquote>
198/// [1, 2, 3, 4] = [$Head | $Tail]
199/// </blockquote>
200///
201/// # Notes
202/// * Logic variable names should begin with a dollar sign followed by
203/// a letter (eg. $Age), but this macro does not check.
204/// * If the ID argument is missing, it is set to 0 by default.
205/// # Arguments
206/// * `id` - positive integer
207/// * `name` - &str
208/// # Return
209/// * [LogicVar](../suiron/unifiable/enum.Unifiable.html#variant.LogicVar)
210/// # Usage
211/// ```
212/// use suiron::*;
213///
214/// let x = logic_var!(next_id(), "$X");
215/// let y = logic_var!("$Y"); // ID is 0
216/// ```
217#[macro_export]
218macro_rules! logic_var {
219 ($name:expr) => {
220 Unifiable::LogicVar{ id: 0, name: $name.to_string() }
221 };
222 ($id:expr, $name:expr) => {
223 Unifiable::LogicVar{ id: $id, name: $name.to_string() }
224 };
225}
226
227/// Creates an anonymous variable.
228///
229/// [Anonymous](../suiron/unifiable/enum.Unifiable.html#variant.Anonymous)
230/// is a unifiable term which unifies with any other term.<br>
231/// Suiron source code represents the anonymous variable as $_ . Eg.:
232/// <blockquote>
233/// check_noun_verb($_, $_, $_, past) :- !.
234/// </blockquote>
235///
236/// # Usage
237/// ```
238/// use suiron::*;
239///
240/// let dont_care = anon!();
241/// ```
242#[macro_export]
243macro_rules! anon {
244 () => { Unifiable::Anonymous };
245}
246
247/// Creates a complex term (= compound term).
248///
249/// As in Prolog, complex terms consist of a functor, followed by
250/// a sequence of arguments (terms) enclosed in parentheses.
251/// For example:
252/// <blockquote>
253/// animal(horse, mammal, herbivore)
254/// </blockquote>
255///
256/// See also: [make_complex()](../suiron/s_complex/fn.make_complex.html).
257///
258/// # Arguments
259/// * list of [Unifiable](../suiron/unifiable/enum.Unifiable.html) terms<br>
260/// # Return
261/// * [SComplex](../suiron/unifiable/enum.Unifiable.html#variant.SComplex)
262/// # Usage
263/// * To build: pronoun(I, subject, first, singular)
264///
265/// ```
266/// use suiron::*;
267///
268/// let functor = atom!("pronoun");
269/// let word = atom!("I");
270/// let case = atom!("subject");
271/// let person = atom!("first");
272/// let sing_plur = atom!("singular");
273/// let pronoun = scomplex!(functor, word, case, person, sing_plur);
274/// ```
275/// # Note
276/// * The first term must be an
277/// [Atom](../suiron/unifiable/enum.Unifiable.html#variant.Atom),
278/// but this macro does not check.
279#[macro_export]
280macro_rules! scomplex {
281 ($($term:expr),*) => (
282 Unifiable::SComplex(vec!($($term),*))
283 );
284} // scomplex!
285
286/// Creates an And operator, and wraps it in a Goal.
287///
288/// The [And](../suiron/operator/enum.Operator.html#variant.And)
289/// operator is represented in Suiron source code by a comma separated
290/// list of goals.<br>For example, the following source code:<br>
291///
292/// <blockquote>
293/// parent($X, $Z), parent($Z, $Y), male($X)
294/// </blockquote>
295///
296/// represents 'parent And parent And male':
297///
298/// # Arguments
299/// * list of [Goals](../suiron/goal/enum.Goal.html)
300/// # Return
301/// * [Goal](../suiron/goal/enum.Goal.html#variant.OperatorGoal)
302/// # Usage
303/// ```
304/// use suiron::*;
305///
306/// // parent($Grandfather, $P), parent($P, $Child), male($Grandfather)
307/// let g1 = parse_subgoal("parent($Grandfather, $P)").unwrap();
308/// let g2 = parse_subgoal("parent($P, $Child)").unwrap();
309/// let g3 = parse_subgoal("male($Grandfather)").unwrap();
310/// let the_and = and_goal!(g1, g2, g3);
311/// ```
312#[macro_export]
313macro_rules! and_goal {
314 ($($goal:expr),*) => (
315 Goal::OperatorGoal(Operator::And(vec!($($goal),*)))
316 );
317} // and_goal!
318
319/// Creates an Or operator, and wraps it in a Goal.
320///
321/// The [Or](../suiron/operator/enum.Operator.html#variant.Or)
322/// operator is represented in Suiron source by a list of goals
323/// separated by semicolons.<br>For example, the following source code:<br>
324///
325/// <blockquote>
326/// mother($P, $C); father($P, $C)
327/// </blockquote>
328///
329/// means 'mother Or father'.
330///
331/// # Arguments
332/// * list of [Goals](../suiron/goal/enum.Goal.html)
333/// # Return
334/// * [Goal](../suiron/goal/enum.Goal.html#variant.OperatorGoal)
335/// # Usage
336/// ```
337/// use suiron::*;
338///
339/// // mother($X, $Y); father($X, $Y)
340/// let g1 = parse_subgoal("mother($X, $Y)").unwrap();
341/// let g2 = parse_subgoal("father($X, $Y)").unwrap();
342/// let the_or = or_goal!(g1, g2);
343/// ```
344#[macro_export]
345macro_rules! or_goal {
346 ($($goal:expr),*) => (
347 Goal::OperatorGoal(Operator::Or(vec!($($goal),*)))
348 );
349} // or_goal!
350
351/// Converts a string slice to a vector of characters.
352///
353/// # Usage
354/// ```
355/// use suiron::*;
356///
357/// let city = str_to_chars!("渋谷");
358/// let n = city.len(); // n == 2
359/// ```
360#[macro_export]
361macro_rules! str_to_chars {
362 ($st:expr) => { $st.chars().collect::<Vec<char>>() };
363}
364
365/// Converts a vector or array of chars to a String.
366///
367/// # Usage
368/// ```
369/// use suiron::*;
370///
371/// let city_of_light = chars_to_string!(['P', 'a', 'r', 'i', 's']);
372/// ```
373#[macro_export]
374macro_rules! chars_to_string {
375 ($chrs:expr) => { $chrs.iter().collect::<String>() };
376}
377
378/// Creates an empty
379/// [substitution set](../suiron/substitution_set/index.html),
380/// pointed to by an Rc-pointer.
381///
382/// # Return
383/// * Rc<[SubstitutionSet](../suiron/substitution_set/type.SubstitutionSet.html)>
384/// # Usage
385/// ```
386/// use std::rc::Rc;
387/// use suiron::*;
388///
389/// let ss = empty_ss!();
390/// ```
391#[macro_export]
392macro_rules! empty_ss {
393 () => { Rc::new(SubstitutionSet::new()) };
394}
395
396/// Creates a smart pointer to mutable data.
397///
398/// rc_cell!(data) is equivalent to Rc::new(RefCell::new(data)).
399///
400/// # Note
401/// Rc and RefCell must be imported, as shown below.
402///
403/// # Usage
404/// ```
405/// use std::rc::Rc;
406/// use std::cell::RefCell;
407/// use suiron::*;
408///
409/// let data = atom!("Fawlty Towers");
410/// let r = rc_cell!(data);
411/// println!("{:?}", r.borrow()); // Prints: Atom("Fawlty Towers") }
412/// ```
413#[macro_export]
414macro_rules! rc_cell {
415 ($data:expr) => { Rc::new(RefCell::new($data)) };
416}
417
418/// Creates a query from a list of terms.
419///
420/// A query is a [Goal](../suiron/goal/index.html), a logic expression to be solved.
421/// It has the same form as a
422/// [complex term](../suiron/unifiable/enum.Unifiable.html#variant.SComplex),
423/// consisting of a functor with arguments (terms) enclosed in parentheses:
424/// `functor(term1, term2, term3)`.
425///
426/// The functor must be an
427/// [atom](../suiron/unifiable/enum.Unifiable.html#variant.Atom),
428/// but a term can be any [unifiable term](../suiron/unifiable/enum.Unifiable.html).
429///
430/// This utility calls [make_query()](../suiron/s_complex/fn.make_query.html),
431/// which [clears](../suiron/logic_var/fn.clear_id.html) the logic variable ID,
432/// and [recreates](../suiron/unifiable/enum.Unifiable.html#method.recreate_variables)
433/// all logic variables within the query.
434///
435/// The macro returns an Rc pointer to the newly created query, which can be
436/// passed to the function [make_base_node()](../suiron/goal/fn.make_base_node.html).
437///
438/// See also: [parse_query()](../suiron/s_complex/fn.parse_query.html)
439///
440/// # Usage
441/// ```
442/// use std::rc::Rc;
443/// use suiron::*;
444///
445/// let kb = test_kb();
446/// let functor = atom!("loves");
447/// let who = logic_var!("$Who");
448/// let penny = atom!("Penny");
449///
450/// // Query is: loves($Who, Penny).
451/// let query = query!(functor, who, penny);
452/// let base_node = make_base_node(Rc::clone(&query), &kb);
453/// println!("{}", solve(base_node)); // Prints: $Who = Leonard
454/// ```
455#[macro_export]
456macro_rules! query {
457 ($($term:expr),*) => (
458 Rc::new(make_query((vec!($($term),*))))
459 );
460}
461
462/// Creates a Unify goal.
463///
464/// Calling `unify!($X, 7)` in Rust is equivalent to `$X = 7` in Suiron source code.
465///
466/// # Usage
467/// ```
468/// use suiron::*;
469///
470/// let x = logic_var!(next_id(), "$X");
471/// let number = SInteger(7);
472/// let goal = unify!(x, number); // Goal is: $X = 7
473/// ```
474#[macro_export]
475macro_rules! unify {
476 ($left:expr, $right:expr) => {
477 Goal::BuiltInGoal(
478 BuiltInPredicate::new("unify".to_string(), Some(vec![$left, $right]))
479 )
480 };
481}
482
483/// Creates a built-in function.
484///
485/// # Arguments
486/// * name of function
487/// * list of [Unifiable](../suiron/unifiable/enum.Unifiable.html) terms
488/// # Return
489/// * [SFunction](../suiron/unifiable/enum.Unifiable.html#variant.SFunction)
490///
491/// # Usage
492/// ```
493/// use suiron::*;
494///
495/// // Define: add(7.0, 3.0)
496/// let add_func = sfunction!("add", SFloat(7.0), SFloat(3.0));
497/// ```
498#[macro_export]
499macro_rules! sfunction {
500 ($name:expr, $($term:expr),*) => {
501 Unifiable::SFunction{ name: $name.to_string(), terms: vec!($($term),*) }
502 };
503}
504
505/// Creates a built-in predicate or complex term, and wraps it in a Goal.
506///
507/// # Arguments
508/// * functor
509/// * list of [Unifiable](../suiron/unifiable/enum.Unifiable.html) terms (If any.)
510/// # Return
511/// * [Goal](../suiron/goal/enum.Goal.html)
512///
513/// # Usage
514/// ```
515/// use suiron::*;
516///
517/// // Make a fail predicate. (No arguments.)
518/// let fail_pred = pred!("fail");
519///
520/// // Make a unify predicate.
521/// let x = logic_var!("$X");
522/// let n = SFloat(3.0);
523/// let unify_pred = pred!("unify", x, n);
524/// println!("{}", unify_pred); // Prints: $X = 3
525/// ```
526#[macro_export]
527macro_rules! pred {
528 ($functor:expr) => { // For predicates without arguments.
529 make_goal_no_args($functor)
530 };
531 ($functor:expr, $($term:expr),*) => {
532 make_goal($functor, vec!($($term),*))
533 };
534}