1pub mod expression;
8pub mod operations;
9pub mod proof;
10pub mod response;
11
12use crate::evaluation::response::EvaluatedRule;
13use crate::planning::semantics::{Expression, Fact, FactPath, FactValue, LiteralValue, RulePath};
14use crate::planning::ExecutionPlan;
15use indexmap::IndexMap;
16pub use operations::{ComputationKind, OperationKind, OperationRecord, OperationResult};
17pub use response::{Facts, Response, RuleResult};
18use std::collections::HashMap;
19
20pub(crate) struct EvaluationContext {
22 fact_values: HashMap<FactPath, LiteralValue>,
23 pub(crate) rule_results: HashMap<RulePath, OperationResult>,
24 rule_proofs: HashMap<RulePath, crate::evaluation::proof::Proof>,
25 operations: Vec<crate::OperationRecord>,
26 pub(crate) sources: HashMap<String, String>,
27 proof_nodes: HashMap<usize, crate::evaluation::proof::ProofNode>,
28 now: LiteralValue,
30}
31
32impl EvaluationContext {
33 fn new(plan: &ExecutionPlan, now: LiteralValue) -> Self {
34 let fact_values: HashMap<FactPath, LiteralValue> = plan
35 .facts
36 .iter()
37 .filter_map(|(path, d)| d.value().map(|v| (path.clone(), v.clone())))
38 .collect();
39 Self {
40 fact_values,
41 rule_results: HashMap::new(),
42 rule_proofs: HashMap::new(),
43 operations: Vec::new(),
44 sources: plan.sources.clone(),
45 proof_nodes: HashMap::new(),
46 now,
47 }
48 }
49
50 pub(crate) fn now(&self) -> &LiteralValue {
51 &self.now
52 }
53
54 fn get_fact(&self, fact_path: &FactPath) -> Option<&LiteralValue> {
55 self.fact_values.get(fact_path)
56 }
57
58 fn push_operation(&mut self, kind: OperationKind) {
59 self.operations.push(OperationRecord { kind });
60 }
61
62 fn set_proof_node(
63 &mut self,
64 expression: &Expression,
65 node: crate::evaluation::proof::ProofNode,
66 ) {
67 self.proof_nodes
68 .insert(expression as *const Expression as usize, node);
69 }
70
71 fn get_proof_node(
72 &self,
73 expression: &Expression,
74 ) -> Option<&crate::evaluation::proof::ProofNode> {
75 self.proof_nodes
76 .get(&(expression as *const Expression as usize))
77 }
78
79 fn get_rule_proof(&self, rule_path: &RulePath) -> Option<&crate::evaluation::proof::Proof> {
80 self.rule_proofs.get(rule_path)
81 }
82
83 fn set_rule_proof(&mut self, rule_path: RulePath, proof: crate::evaluation::proof::Proof) {
84 self.rule_proofs.insert(rule_path, proof);
85 }
86}
87
88#[derive(Default)]
90pub(crate) struct Evaluator;
91
92impl Evaluator {
93 pub(crate) fn evaluate(&self, plan: &ExecutionPlan, now: LiteralValue) -> Response {
102 let mut context = EvaluationContext::new(plan, now);
103
104 let mut response = Response {
105 spec_name: plan.spec_name.clone(),
106 facts: Vec::new(),
107 results: IndexMap::new(),
108 };
109
110 let mut used_facts: HashMap<FactPath, LiteralValue> = HashMap::new();
111
112 for exec_rule in &plan.rules {
114 context.operations.clear();
115 context.proof_nodes.clear();
116
117 let (result, proof) = expression::evaluate_rule(exec_rule, &mut context);
118
119 context
120 .rule_results
121 .insert(exec_rule.path.clone(), result.clone());
122 context.set_rule_proof(exec_rule.path.clone(), proof.clone());
123
124 let rule_operations = context.operations.clone();
125
126 for op in &rule_operations {
127 if let OperationKind::FactUsed { fact_ref, value } = &op.kind {
128 used_facts.entry(fact_ref.clone()).or_insert(value.clone());
129 }
130 }
131
132 if !exec_rule.path.segments.is_empty() {
133 continue;
134 }
135
136 let unless_branches: Vec<(Option<Expression>, Expression)> = exec_rule.branches[1..]
137 .iter()
138 .map(|b| (b.condition.clone(), b.result.clone()))
139 .collect();
140
141 response.add_result(RuleResult {
142 rule: EvaluatedRule {
143 name: exec_rule.name.clone(),
144 path: exec_rule.path.clone(),
145 default_expression: exec_rule.branches[0].result.clone(),
146 unless_branches,
147 source_location: exec_rule.source.clone(),
148 rule_type: exec_rule.rule_type.clone(),
149 },
150 result,
151 facts: vec![],
152 operations: rule_operations,
153 proof: Some(proof),
154 rule_type: exec_rule.rule_type.clone(),
155 });
156 }
157
158 let fact_list: Vec<Fact> = plan
160 .facts
161 .keys()
162 .filter_map(|path| {
163 used_facts.remove(path).map(|value| Fact {
164 path: path.clone(),
165 value: FactValue::Literal(value),
166 source: None,
167 })
168 })
169 .collect();
170
171 if !fact_list.is_empty() {
172 response.facts = vec![Facts {
173 fact_path: String::new(),
174 referencing_fact_name: String::new(),
175 facts: fact_list,
176 }];
177 }
178
179 response
180 }
181}