suiron/
built_in_functions.rs

1//! Functions to support Suiron's built-in functions (SFunction).
2//!
3
4use std::rc::Rc;
5use super::s_complex::*;
6use super::parse_terms::*;
7use super::parse_goals::*;
8use super::substitution_set::*;
9use super::unifiable::Unifiable;
10use super::built_in_join::*;
11use super::built_in_arithmetic::*;
12
13use crate::str_to_chars;
14use crate::chars_to_string;
15
16/// Unify an SFunction with another Unifiable term.
17///
18/// When the function [unify()](../unifiable/enum.Unifiable.html#method.unify)
19/// tries to unify an 
20/// [SFunction](../unifiable/enum.Unifiable.html#variant.SFunction)
21/// with another term, it calls `unify_sfunction()`.
22/// This function evaluates its arguments (`terms`), and unifies the result
23/// with the `other` [Unifiable](../unifiable/enum.Unifiable.html) term.
24/// 
25/// # Arguments
26/// * name of function
27/// * terms - vector of Unifiable terms
28/// * other Unifiable term
29/// * [SubstitutionSet](../substitution_set/index.html)
30/// # Returns
31/// * [SubstitutionSet](../substitution_set/index.html) or None.
32/// # Usage
33/// ```
34/// use std::rc::Rc;
35/// use suiron::*;
36///
37/// // Try:  $X = add(1, 2, 3)
38/// let x = logic_var!(next_id(), "$X");
39/// let ss = empty_ss!();
40/// let terms = vec![SInteger(1), SInteger(2), SInteger(3)];
41///
42/// match unify_sfunction("add", &terms, &x, &ss) {
43///     Some(ss) => {
44///         let res = get_ground_term(&x, &ss).unwrap();
45///         println!("{}", res);
46///     },
47///     None => { println!("No solution."); },
48/// }
49/// // Should print: 6
50/// ```
51///
52pub fn unify_sfunction<'a>(name: &str, terms: &'a Vec<Unifiable>,
53                           other: &'a Unifiable, ss: &'a Rc<SubstitutionSet<'a>>)
54                           -> Option<Rc<SubstitutionSet<'a>>> {
55
56    let name = name.to_string();
57
58    if name.eq("join") {
59        let result = evaluate_join(terms, ss);
60        return result.unify(other, ss);
61    }
62    else if name.eq("add") {
63        let result = evaluate_add(terms, ss);
64        return result.unify(other, ss);
65    }
66    else if name.eq("subtract") {
67        let result = evaluate_subtract(terms, ss);
68        return result.unify(other, ss);
69    }
70    else if name.eq("multiply") {
71        let result = evaluate_multiply(terms, ss);
72        return result.unify(other, ss);
73    }
74    else if name.eq("divide") {
75        let result = evaluate_divide(terms, ss);
76        return result.unify(other, ss);
77    }
78
79    return None;
80
81} // unify_sfunction()
82
83/// Parses a string to produce a built-in function (SFunction).
84///
85/// # Note
86/// * parse_function() is very similar to
87/// [parse_complex()](../s_complex/fn.parse_complex.html).
88/// # Arguments
89/// * string to parse
90/// # Returns
91/// * [SFunction](../unifiable/enum.Unifiable.html#variant.SFunction)
92/// or error message
93/// # Usage
94/// ```
95/// use suiron::*;
96///
97/// match parse_function("add(7, 9, 4)") {
98///     Ok(term) => { println!("{}", term); },
99///     Err(msg) => { println!("{}", msg); },
100/// }
101/// ```
102/// Should print: add(7, 9, 4)
103pub fn parse_function(to_parse: &str) -> Result<Unifiable, String> {
104
105    let s = to_parse.trim();
106    let chrs = str_to_chars!(s);
107
108    // Built-in functions have the same form as complex terms.
109    // That is: name(term1, term2...)
110    match validate_complex(s, &chrs) {
111        Some(error_message) => { return Err(error_message); },
112        None => {},
113    }
114
115    // Get indices.
116    match indices_of_parentheses(&chrs) {
117        Ok(indices) => {
118            match indices {
119                Some((left, right)) => {
120
121                    let name = chars_to_string!(chrs[0..left]);
122                    let terms_str = chars_to_string!(chrs[left + 1..right]);
123                    if terms_str.len() == 0 {
124                        let err = format!("parse_function - No arguments: {}", s);
125                        return Err(err);
126                    }
127
128                    let mut new_terms: Vec<Unifiable> = vec![];
129                    match parse_arguments(&terms_str) {
130                        Ok(terms) => {
131                            // If everything parsed correctly, return SFunction.
132                            for term in terms { new_terms.push(term); }
133                            return Ok(Unifiable::SFunction{name, terms: new_terms});
134                        },
135                        Err(err) => {
136                            let err = format!("{}{}", err, s);
137                            return Err(err);
138                        },
139                    }
140                },
141                None => {
142                    let err = format!("parse_function() - Invalid function: {}", s);
143                    return Err(err);
144                },
145            } // match
146        },
147        Err(err) => { return Err(err); }
148    } // match
149
150} // parse_function()
151
152
153#[cfg(test)]
154mod test {
155
156    use crate::*;
157    use super::*;
158
159    #[test]
160    fn test_parse_function() {
161        match parse_function("add(5, 6, 7)") {
162            Ok(sf) => {
163                if matches!(sf, Unifiable::SFunction{name: _, terms: _}) {
164                    assert_eq!("add(5, 6, 7)", sf.to_string());
165                } else {
166                    panic!("parse_function() - \
167                            Should create a function: {}", sf);
168                }
169            },
170            Err(err) => { panic!("{}", err); },
171        }
172        match parse_function("add") {
173            Ok(c) => {
174                panic!("parse_function() - Should generate error: {}", c)
175            },
176            Err(err) => {
177                assert_eq!(err, "parse_function() - Invalid function: add");
178            },
179        }
180        match parse_function("add(, 6, 7)") {
181            Ok(c) => {
182                panic!("parse_function() - Should generate error: {}", c)
183            },
184            Err(err) => {
185                assert_eq!(err, "parse_arguments() - \
186                                 Missing first argument: add(, 6, 7)");
187            },
188        }
189        match parse_function("add(5, 6, )") {
190            Ok(c) => {
191                panic!("parse_function() - Should generate error: {}", c)
192            },
193            Err(err) => {
194                assert_eq!(err, "parse_arguments() - \
195                                 Missing last argument: add(5, 6, )");
196            },
197        }
198        match parse_function("add()") {
199            Ok(c) => {
200                panic!("parse_function() - Should generate error: {}", c)
201            },
202            Err(err) => {
203                assert_eq!(err, "parse_function - No arguments: add()");
204            },
205        }
206    } // test_parse_function()
207
208} // test