suiron/
built_in_append.rs

1//! Appends terms (including lists) to make a new linked list.
2
3use std::rc::Rc;
4
5use super::unifiable::*;
6use super::s_linked_list::*;
7use super::substitution_set::*;
8use super::built_in_predicates::*;
9
10/// Evaluates a solution node for the append() predicate.
11///
12/// Appends terms together to create a list.
13///
14/// The append() predicate requires at least two arguments.
15/// The first n - 1 arguments are input arguments, and the
16/// last argument is the output argument. (All arguments are
17/// unifiable terms.)
18///
19/// This function is called by
20/// [next_solution_bip()](../built_in_predicates/fn.next_solution_bip.html)
21/// in built_in_predicates.rs.
22///
23/// # Arguments
24/// * [BuiltInPredicate](../built_in_predicates/struct.BuiltInPredicate.html)
25/// * [SubstitutionSet](../substitution_set/type.SubstitutionSet.html)
26/// # Return
27/// * [SubstitutionSet](../substitution_set/type.SubstitutionSet.html) or None
28///
29pub fn next_solution_append<'a>(bip: BuiltInPredicate,
30                                ss: &'a Rc<SubstitutionSet<'a>>)
31                                -> Option<Rc<SubstitutionSet<'a>>> {
32
33    if let Some(terms) = bip.terms {
34
35        let length = terms.len();
36        if length < 2 { return None; }
37
38        let mut out_terms: Vec<Unifiable> = vec![];
39
40        for i in 0..(length - 1) {
41
42            let mut t = terms[i].clone();
43
44            // If logic variable, get ground term.
45            if let Unifiable::LogicVar{id: _, name: _} = t {
46                match get_ground_term(&t, &ss) {
47                    Some(new_term) => { t = new_term.clone(); },
48                    None => {},
49                }
50            }
51
52            match t {
53                Unifiable::Nil |
54                Unifiable::Anonymous |
55                Unifiable::Atom(_) |
56                Unifiable::SInteger(_) |
57                Unifiable::SFloat(_) |
58                Unifiable::SFunction{name: _, terms: _} |
59                Unifiable::SComplex(_) => { out_terms.push(t); },
60                Unifiable::SLinkedList{term: _, next: _, count: _, tail_var: _} => {
61                    let mut list = t;
62                    loop {
63                        if let Unifiable::SLinkedList{term, next,
64                                          count: _, tail_var: _} = list {
65                            if *term == Unifiable::Nil { break; }
66                            out_terms.push(*term);
67                            list = *next;
68                        }
69                    }
70                },
71                // LogicVar was dealt with above.
72                Unifiable::LogicVar{id: _, name: _} => {},
73            } // match
74
75        } // for
76
77        let out = make_linked_list(false, out_terms);
78        let last_term = terms[length - 1].clone();
79
80        // Unify new list with last term.
81        return last_term.unify(&out, &ss);
82    }
83    return None;
84
85} // next_solution_append()
86
87#[cfg(test)]
88mod test {
89
90    use std::rc::Rc;
91    use crate::*;
92    use super::*;
93
94    // Test append() predicate.
95    #[test]
96    fn test_append() {
97
98        let kb = KnowledgeBase::new();
99
100        // Make a base solution node.
101        let query = parse_query("go").unwrap();
102        let base_node = make_base_node(Rc::new(query), &kb);
103
104        // Make an append() predicate.
105        let append_pred = match parse_subgoal(
106                          "append(3.14159, [A, B, C], 6, $Out)") {
107            Ok(goal) => { goal },
108            Err(err) => { panic!("{}", err); },
109        };
110
111        // Recreate variables.
112        let mut var_map = VarMap::new();
113        let append_pred = append_pred.recreate_variables(&mut var_map);
114
115        // Create a solution node.
116        let sn = make_solution_node(Rc::new(append_pred), &kb,
117                                    empty_ss!(), base_node);
118
119        // Get the solution. This will run next_solution_append().
120        match next_solution(sn) {
121            Some(ss) => {
122                let term = ss[1].clone().unwrap();
123                let s = format!("{}", *term);
124                assert_eq!("[3.14159, A, B, C, 6]", s)
125            },
126            None => { panic!("Append() should join terms together."); },
127        } // match
128
129    } // test_append()
130
131} // test