rust_rule_engine/backward/
rule_executor.rs

1/// Rule execution for backward chaining
2///
3/// This module provides proper condition evaluation and action execution
4/// for backward chaining, replacing the "fake" stub implementations.
5
6use crate::engine::rule::{Condition, ConditionExpression, ConditionGroup, Rule};
7use crate::types::{ActionType, Value};
8use crate::{Facts, KnowledgeBase};
9use crate::errors::{Result, RuleEngineError};
10
11/// Rule executor for backward chaining
12pub struct RuleExecutor {
13    knowledge_base: KnowledgeBase,
14}
15
16impl RuleExecutor {
17    /// Create a new rule executor
18    pub fn new(knowledge_base: KnowledgeBase) -> Self {
19        Self { knowledge_base }
20    }
21
22    /// Check if rule conditions are satisfied and execute if they are
23    ///
24    /// Returns:
25    /// - Ok(true) if rule executed successfully
26    /// - Ok(false) if conditions not satisfied
27    /// - Err if execution failed
28    pub fn try_execute_rule(
29        &self,
30        rule: &Rule,
31        facts: &mut Facts,
32    ) -> Result<bool> {
33        // Check if all conditions are satisfied
34        if !self.evaluate_conditions(&rule.conditions, facts)? {
35            return Ok(false);
36        }
37
38        // Conditions satisfied - execute actions
39        self.execute_actions(rule, facts)?;
40
41        Ok(true)
42    }
43
44    /// Evaluate condition group
45    pub fn evaluate_conditions(
46        &self,
47        group: &ConditionGroup,
48        facts: &Facts,
49    ) -> Result<bool> {
50        match group {
51            ConditionGroup::Single(condition) => {
52                self.evaluate_condition(condition, facts)
53            }
54
55            ConditionGroup::Compound { left, operator, right } => {
56                let left_result = self.evaluate_conditions(left, facts)?;
57
58                // Short-circuit evaluation
59                match operator {
60                    crate::types::LogicalOperator::And => {
61                        if !left_result {
62                            return Ok(false);
63                        }
64                        self.evaluate_conditions(right, facts)
65                    }
66                    crate::types::LogicalOperator::Or => {
67                        if left_result {
68                            return Ok(true);
69                        }
70                        self.evaluate_conditions(right, facts)
71                    }
72                    _ => {
73                        Err(RuleEngineError::ExecutionError(
74                            format!("Unsupported logical operator: {:?}", operator)
75                        ))
76                    }
77                }
78            }
79
80            ConditionGroup::Not(inner) => {
81                let result = self.evaluate_conditions(inner, facts)?;
82                Ok(!result)
83            }
84
85            ConditionGroup::Exists(conditions) => {
86                // For backward chaining, exists is simplified
87                // Just check if the conditions can be satisfied
88                self.evaluate_conditions(conditions, facts)
89            }
90
91            ConditionGroup::Forall(conditions) => {
92                // Forall is complex - for now, simplified implementation
93                // Just evaluate the nested conditions
94                self.evaluate_conditions(conditions, facts)
95            }
96
97            ConditionGroup::Accumulate { .. } => {
98                // Accumulate needs special handling - not fully supported in BC yet
99                // Return true for now (TODO: proper implementation)
100                Ok(true)
101            }
102        }
103    }
104
105    /// Evaluate a single condition
106    pub fn evaluate_condition(&self, condition: &Condition, facts: &Facts) -> Result<bool> {
107        match &condition.expression {
108            ConditionExpression::Field(field_name) => {
109                // Get field value
110                if let Some(value) = facts.get_nested(field_name).or_else(|| facts.get(field_name)) {
111                    Ok(condition.operator.evaluate(&value, &condition.value))
112                } else {
113                    // Field not found
114                    // For some operators like NotEqual, this might be true
115                    match condition.operator {
116                        crate::types::Operator::NotEqual => {
117                            // null != value is true
118                            Ok(true)
119                        }
120                        _ => Ok(false),
121                    }
122                }
123            }
124
125            ConditionExpression::FunctionCall { name, args } => {
126                // Execute function call
127                self.evaluate_function_call(name, args, condition, facts)
128            }
129
130            ConditionExpression::Test { name, args } => {
131                // Execute test expression
132                self.evaluate_test_expression(name, args, facts)
133            }
134
135            ConditionExpression::MultiField { field, operation, variable } => {
136                // Handle multi-field operations
137                self.evaluate_multifield(field, operation, variable, condition, facts)
138            }
139        }
140    }
141
142    /// Evaluate function call
143    fn evaluate_function_call(
144        &self,
145        function_name: &str,
146        args: &[String],
147        condition: &Condition,
148        facts: &Facts,
149    ) -> Result<bool> {
150        // For backward chaining, we need to check if the function is available
151        // and execute it with the current facts
152
153        // Get function arguments
154        let mut arg_values = Vec::new();
155        for arg in args {
156            if let Some(value) = facts.get(arg).or_else(|| facts.get_nested(arg)) {
157                arg_values.push(value);
158            } else {
159                // Try to parse as literal
160                if let Ok(val) = self.parse_literal_value(arg) {
161                    arg_values.push(val);
162                } else {
163                    // Argument not available - cannot evaluate
164                    return Ok(false);
165                }
166            }
167        }
168
169        // TODO: Proper function execution
170        // For now, check for common functions
171
172        match function_name {
173            "len" | "length" | "size" => {
174                if arg_values.len() == 1 {
175                    let len = match &arg_values[0] {
176                        Value::String(s) => s.len() as f64,
177                        Value::Array(arr) => arr.len() as f64,
178                        _ => return Ok(false),
179                    };
180
181                    Ok(condition.operator.evaluate(&Value::Number(len), &condition.value))
182                } else {
183                    Ok(false)
184                }
185            }
186
187            "isEmpty" | "is_empty" => {
188                if arg_values.len() == 1 {
189                    let is_empty = match &arg_values[0] {
190                        Value::String(s) => s.is_empty(),
191                        Value::Array(arr) => arr.is_empty(),
192                        Value::Null => true,
193                        _ => false,
194                    };
195
196                    Ok(condition.operator.evaluate(&Value::Boolean(is_empty), &condition.value))
197                } else {
198                    Ok(false)
199                }
200            }
201
202            "contains" => {
203                if arg_values.len() == 2 {
204                    let contains = match (&arg_values[0], &arg_values[1]) {
205                        (Value::String(s), Value::String(substr)) => s.contains(substr.as_str()),
206                        (Value::Array(arr), val) => arr.contains(val),
207                        _ => false,
208                    };
209
210                    Ok(condition.operator.evaluate(&Value::Boolean(contains), &condition.value))
211                } else {
212                    Ok(false)
213                }
214            }
215
216            _ => {
217                // Unknown function - cannot evaluate in backward chaining
218                // Return false instead of true (fix the "lie")
219                Ok(false)
220            }
221        }
222    }
223
224    /// Evaluate test expression
225    fn evaluate_test_expression(
226        &self,
227        function_name: &str,
228        args: &[String],
229        facts: &Facts,
230    ) -> Result<bool> {
231        // Test expressions must return boolean
232        // For now, support common test functions
233
234        match function_name {
235            "exists" => {
236                // Check if field exists
237                if args.len() == 1 {
238                    Ok(facts.get(&args[0]).is_some() || facts.get_nested(&args[0]).is_some())
239                } else {
240                    Ok(false)
241                }
242            }
243
244            "notExists" | "not_exists" => {
245                // Check if field does not exist
246                if args.len() == 1 {
247                    Ok(facts.get(&args[0]).is_none() && facts.get_nested(&args[0]).is_none())
248                } else {
249                    Ok(false)
250                }
251            }
252
253            _ => {
254                // Unknown test function
255                Ok(false)
256            }
257        }
258    }
259
260    /// Evaluate multi-field operation
261    fn evaluate_multifield(
262        &self,
263        field: &str,
264        operation: &str,
265        variable: &Option<String>,
266        condition: &Condition,
267        facts: &Facts,
268    ) -> Result<bool> {
269        // Get field value
270        let field_value = facts.get(field).or_else(|| facts.get_nested(field));
271
272        match operation {
273            "collect" => {
274                // Collect all values - just check if field exists
275                Ok(field_value.is_some())
276            }
277
278            "count" => {
279                // Count elements
280                let count = if let Some(value) = field_value {
281                    match value {
282                        Value::Array(arr) => arr.len() as f64,
283                        _ => 1.0,
284                    }
285                } else {
286                    0.0
287                };
288
289                Ok(condition.operator.evaluate(&Value::Number(count), &condition.value))
290            }
291
292            "first" => {
293                // Get first element
294                if let Some(Value::Array(arr)) = field_value {
295                    if !arr.is_empty() {
296                        Ok(true)
297                    } else {
298                        Ok(false)
299                    }
300                } else {
301                    Ok(false)
302                }
303            }
304
305            "last" => {
306                // Get last element
307                if let Some(Value::Array(arr)) = field_value {
308                    if !arr.is_empty() {
309                        Ok(true)
310                    } else {
311                        Ok(false)
312                    }
313                } else {
314                    Ok(false)
315                }
316            }
317
318            "empty" | "isEmpty" => {
319                // Check if empty
320                let is_empty = if let Some(value) = field_value {
321                    match value {
322                        Value::Array(arr) => arr.is_empty(),
323                        Value::String(s) => s.is_empty(),
324                        Value::Null => true,
325                        _ => false,
326                    }
327                } else {
328                    true
329                };
330
331                Ok(is_empty)
332            }
333
334            "not_empty" | "notEmpty" => {
335                // Check if not empty
336                let is_not_empty = if let Some(value) = field_value {
337                    match value {
338                        Value::Array(arr) => !arr.is_empty(),
339                        Value::String(s) => !s.is_empty(),
340                        Value::Null => false,
341                        _ => true,
342                    }
343                } else {
344                    false
345                };
346
347                Ok(is_not_empty)
348            }
349
350            "contains" => {
351                // Check if array contains value
352                if let Some(Value::Array(arr)) = field_value {
353                    Ok(arr.contains(&condition.value))
354                } else {
355                    Ok(false)
356                }
357            }
358
359            _ => {
360                // Unknown operation
361                Ok(false)
362            }
363        }
364    }
365
366    /// Execute rule actions
367    fn execute_actions(&self, rule: &Rule, facts: &mut Facts) -> Result<()> {
368        for action in &rule.actions {
369            self.execute_action(action, facts)?;
370        }
371
372        Ok(())
373    }
374
375    /// Execute a single action
376    fn execute_action(&self, action: &ActionType, facts: &mut Facts) -> Result<()> {
377        match action {
378            ActionType::Set { field, value } => {
379                // Evaluate value expression if needed
380                let evaluated_value = self.evaluate_value_expression(value, facts)?;
381                facts.set(field, evaluated_value);
382                Ok(())
383            }
384
385            ActionType::MethodCall { object, method, args } => {
386                // Execute method call
387                if let Some(obj_value) = facts.get(object) {
388                    let mut obj_value = obj_value.clone();
389                    // Evaluate arguments
390                    let mut arg_values = Vec::new();
391                    for arg in args {
392                        let val = self.evaluate_value_expression(arg, facts)?;
393                        arg_values.push(val);
394                    }
395
396                    // Call method
397                    let result = obj_value.call_method(method, arg_values)
398                        .map_err(|e| RuleEngineError::ExecutionError(e))?;
399
400                    // Update object
401                    facts.set(object, obj_value);
402
403                    // Store result if there's a return value
404                    if result != Value::Null {
405                        facts.set(&format!("{}._return", object), result);
406                    }
407
408                    Ok(())
409                } else {
410                    Err(RuleEngineError::ExecutionError(
411                        format!("Object not found: {}", object)
412                    ))
413                }
414            }
415
416            ActionType::Retract { object } => {
417                // Retract fact from working memory
418                // In backward chaining, we just remove the fact
419                facts.remove(object);
420                Ok(())
421            }
422
423            ActionType::Log { message } => {
424                // Just log for now
425                println!("[BC Action] {}", message);
426                Ok(())
427            }
428
429            ActionType::Custom { .. } => {
430                // Custom actions not supported in backward chaining yet
431                Ok(())
432            }
433
434            ActionType::ActivateAgendaGroup { .. } => {
435                // Agenda groups not supported in backward chaining
436                Ok(())
437            }
438
439            ActionType::ScheduleRule { .. } => {
440                // Rule scheduling not supported in backward chaining
441                Ok(())
442            }
443
444            ActionType::CompleteWorkflow { .. } => {
445                // Workflows not supported in backward chaining
446                Ok(())
447            }
448
449            ActionType::SetWorkflowData { .. } => {
450                // Workflow data not supported in backward chaining
451                Ok(())
452            }
453        }
454    }
455
456    /// Evaluate value expression
457    fn evaluate_value_expression(&self, value: &Value, facts: &Facts) -> Result<Value> {
458        match value {
459            Value::Expression(expr) => {
460                // Parse and evaluate expression
461                // For now, simple field reference or literal
462                if let Some(val) = facts.get(expr).or_else(|| facts.get_nested(expr)) {
463                    Ok(val)
464                } else if let Ok(lit) = self.parse_literal_value(expr) {
465                    Ok(lit)
466                } else {
467                    Ok(value.clone())
468                }
469            }
470            _ => Ok(value.clone()),
471        }
472    }
473
474    /// Parse literal value from string
475    fn parse_literal_value(&self, s: &str) -> Result<Value> {
476        // Try boolean
477        if s == "true" {
478            return Ok(Value::Boolean(true));
479        }
480        if s == "false" {
481            return Ok(Value::Boolean(false));
482        }
483        if s == "null" {
484            return Ok(Value::Null);
485        }
486
487        // Try number
488        if let Ok(n) = s.parse::<f64>() {
489            return Ok(Value::Number(n));
490        }
491
492        // Try integer
493        if let Ok(i) = s.parse::<i64>() {
494            return Ok(Value::Integer(i));
495        }
496
497        // String
498        Ok(Value::String(s.to_string()))
499    }
500}
501
502#[cfg(test)]
503mod tests {
504    use super::*;
505    use crate::types::Operator;
506
507    #[test]
508    fn test_evaluate_simple_condition() {
509        let kb = KnowledgeBase::new("test");
510        let executor = RuleExecutor::new(kb);
511
512        let mut facts = Facts::new();
513        facts.set("User.Age", Value::Number(25.0));
514
515        let condition = Condition::new(
516            "User.Age".to_string(),
517            Operator::GreaterThan,
518            Value::Number(18.0),
519        );
520
521        let result = executor.evaluate_condition(&condition, &facts).unwrap();
522        assert!(result);
523    }
524
525    #[test]
526    fn test_evaluate_function_call_len() {
527        let kb = KnowledgeBase::new("test");
528        let executor = RuleExecutor::new(kb);
529
530        let mut facts = Facts::new();
531        facts.set("User.Name", Value::String("John".to_string()));
532
533        let condition = Condition::with_function(
534            "len".to_string(),
535            vec!["User.Name".to_string()],
536            Operator::GreaterThan,
537            Value::Number(3.0),
538        );
539
540        let result = executor.evaluate_condition(&condition, &facts).unwrap();
541        assert!(result); // "John".len() = 4 > 3
542    }
543
544    #[test]
545    fn test_execute_set_action() {
546        let kb = KnowledgeBase::new("test");
547        let executor = RuleExecutor::new(kb);
548
549        let mut facts = Facts::new();
550
551        let action = ActionType::Set {
552            field: "User.IsVIP".to_string(),
553            value: Value::Boolean(true),
554        };
555
556        executor.execute_action(&action, &mut facts).unwrap();
557
558        assert_eq!(facts.get("User.IsVIP"), Some(Value::Boolean(true)));
559    }
560}