1use crate::evaluator::Evaluator;
2use crate::{parse, LemmaDoc, LemmaError, LemmaResult, ResourceLimits, Response, Validator};
3use std::collections::HashMap;
4
5pub struct Engine {
9 documents: HashMap<String, LemmaDoc>,
10 sources: HashMap<String, String>,
11 validator: Validator,
12 evaluator: Evaluator,
13 limits: ResourceLimits,
14}
15
16impl Default for Engine {
17 fn default() -> Self {
18 Self {
19 documents: HashMap::new(),
20 sources: HashMap::new(),
21 validator: Validator,
22 evaluator: Evaluator,
23 limits: ResourceLimits::default(),
24 }
25 }
26}
27
28impl Engine {
29 pub fn new() -> Self {
30 Self::default()
31 }
32
33 pub fn with_limits(limits: ResourceLimits) -> Self {
35 Self {
36 documents: HashMap::new(),
37 sources: HashMap::new(),
38 validator: Validator,
39 evaluator: Evaluator,
40 limits,
41 }
42 }
43
44 pub fn limits(&self) -> &ResourceLimits {
46 &self.limits
47 }
48
49 pub fn add_lemma_code(&mut self, lemma_code: &str, source: &str) -> LemmaResult<()> {
50 let new_docs = parse(lemma_code, Some(source.to_owned()), &self.limits)?;
51
52 for doc in &new_docs {
53 let source_id = doc.source.clone().unwrap_or_else(|| "<input>".to_owned());
54 self.sources.insert(source_id, lemma_code.to_owned());
55 }
56
57 let mut all_docs: Vec<crate::LemmaDoc> = self.documents.values().cloned().collect();
58 all_docs.extend(new_docs);
59
60 let validated = self.validator.validate_all(all_docs)?;
61
62 for doc in validated.documents {
63 self.documents.insert(doc.name.clone(), doc);
64 }
65
66 Ok(())
67 }
68
69 pub fn remove_document(&mut self, doc_name: &str) {
70 self.documents.remove(doc_name);
71 }
72
73 pub fn list_documents(&self) -> Vec<String> {
74 self.documents.keys().cloned().collect()
75 }
76
77 pub fn get_document(&self, doc_name: &str) -> Option<&crate::LemmaDoc> {
78 self.documents.get(doc_name)
79 }
80
81 pub fn get_document_facts(&self, doc_name: &str) -> Vec<&crate::LemmaFact> {
82 if let Some(doc) = self.documents.get(doc_name) {
83 doc.facts.iter().collect()
84 } else {
85 Vec::new()
86 }
87 }
88
89 pub fn get_document_rules(&self, doc_name: &str) -> Vec<&crate::LemmaRule> {
90 if let Some(doc) = self.documents.get(doc_name) {
91 doc.rules.iter().collect()
92 } else {
93 Vec::new()
94 }
95 }
96
97 pub fn evaluate(
105 &self,
106 doc_name: &str,
107 rule_names: Option<Vec<String>>,
108 fact_overrides: Option<Vec<crate::LemmaFact>>,
109 ) -> LemmaResult<Response> {
110 let overrides = fact_overrides.unwrap_or_default();
111
112 for fact in &overrides {
113 if let crate::FactValue::Literal(lit) = &fact.value {
114 let size = lit.byte_size();
115 if size > self.limits.max_fact_value_bytes {
116 return Err(LemmaError::ResourceLimitExceeded {
117 limit_name: "max_fact_value_bytes".to_string(),
118 limit_value: self.limits.max_fact_value_bytes.to_string(),
119 actual_value: size.to_string(),
120 suggestion: format!(
121 "Reduce the size of fact values to {} bytes or less",
122 self.limits.max_fact_value_bytes
123 ),
124 });
125 }
126 }
127 }
128
129 self.evaluator.evaluate_document(
130 doc_name,
131 &self.documents,
132 &self.sources,
133 overrides,
134 rule_names,
135 &self.limits,
136 )
137 }
138
139 pub fn get_all_documents(&self) -> &HashMap<String, crate::LemmaDoc> {
141 &self.documents
142 }
143
144 pub fn invert(
152 &self,
153 document: &str,
154 rule: &str,
155 target: crate::Target,
156 given_facts: HashMap<String, crate::LiteralValue>,
157 ) -> LemmaResult<Vec<HashMap<crate::FactReference, crate::Domain>>> {
158 let shape = crate::inversion::inverter::invert(
159 document,
160 rule,
161 target,
162 given_facts,
163 &self.documents,
164 )?;
165 crate::inversion::domain_extraction::shape_to_domains(&shape)
166 }
167}