lemma/evaluator/
context.rs1use crate::{
6 FactReference, FactType, FactValue, LemmaDoc, LemmaError, LemmaFact, LiteralValue,
7 OperationRecord, OperationResult, ResourceLimits,
8};
9use std::collections::HashMap;
10
11use super::timeout::TimeoutTracker;
12
13pub struct EvaluationContext<'a> {
21 pub current_doc: &'a LemmaDoc,
23
24 pub all_documents: &'a HashMap<String, LemmaDoc>,
26
27 pub sources: &'a HashMap<String, String>,
30
31 pub facts: HashMap<FactReference, LiteralValue>,
35
36 pub timeout_tracker: &'a TimeoutTracker,
38
39 pub limits: &'a ResourceLimits,
41
42 pub rule_results: HashMap<crate::RulePath, OperationResult>,
45
46 pub operations: Vec<OperationRecord>,
48}
49
50impl<'a> EvaluationContext<'a> {
51 pub fn new(
53 current_doc: &'a LemmaDoc,
54 all_documents: &'a HashMap<String, LemmaDoc>,
55 sources: &'a HashMap<String, String>,
56 facts: HashMap<FactReference, LiteralValue>,
57 timeout_tracker: &'a TimeoutTracker,
58 limits: &'a ResourceLimits,
59 ) -> Self {
60 Self {
61 current_doc,
62 all_documents,
63 sources,
64 facts,
65 rule_results: HashMap::new(),
66 operations: Vec::new(),
67 timeout_tracker,
68 limits,
69 }
70 }
71
72 pub fn check_timeout(&self) -> Result<(), crate::LemmaError> {
74 self.timeout_tracker.check_timeout(self.limits)
75 }
76}
77
78pub fn build_fact_map(
86 doc: &LemmaDoc,
87 doc_facts: &[LemmaFact],
88 overrides: &[LemmaFact],
89 all_documents: &HashMap<String, LemmaDoc>,
90) -> Result<HashMap<FactReference, LiteralValue>, LemmaError> {
91 let mut facts = HashMap::new();
92
93 for fact in doc_facts {
95 match &fact.value {
96 FactValue::Literal(lit) => {
97 let path = get_fact_path(fact);
98 facts.insert(path, lit.clone());
99 }
100 FactValue::DocumentReference(doc_name) => {
101 if let Some(referenced_doc) = all_documents.get(doc_name) {
103 let fact_prefix = get_fact_path(fact);
104 let referenced_facts =
106 build_fact_map(referenced_doc, &referenced_doc.facts, &[], all_documents)?;
107 for (ref_fact_path, lit) in referenced_facts {
108 let mut qualified_reference = fact_prefix.reference.clone();
110 qualified_reference.extend_from_slice(&ref_fact_path.reference);
111 let qualified_path = FactReference {
112 reference: qualified_reference,
113 };
114 facts.insert(qualified_path, lit);
115 }
116 }
117 }
118 FactValue::TypeAnnotation(_) => {
119 }
121 }
122 }
123
124 for fact in overrides {
126 if let FactValue::Literal(lit) = &fact.value {
127 let path = get_fact_path(fact);
128
129 if let Some(expected_type) = doc.get_fact_type(&path) {
131 let actual_type = lit.to_type();
132 if expected_type != actual_type {
133 return Err(LemmaError::Engine(format!(
134 "Type mismatch for fact '{}': expected {}, got {}",
135 path, expected_type, actual_type
136 )));
137 }
138 }
139
140 facts.insert(path, lit.clone());
141 }
142 }
143
144 Ok(facts)
145}
146
147fn get_fact_path(fact: &LemmaFact) -> FactReference {
149 match &fact.fact_type {
150 FactType::Local(name) => FactReference {
151 reference: vec![name.clone()],
152 },
153 FactType::Foreign(foreign_ref) => FactReference {
154 reference: foreign_ref.reference.clone(),
155 },
156 }
157}