1use crate::boxed_expressions::*;
4use crate::errors::*;
5use crate::model_builder::ModelBuilder;
6use crate::model_definitions::{DefBusinessKnowledgeModel, DefDefinitions, DefKey};
7use crate::model_evaluator::ModelEvaluator;
8use dmntk_common::Result;
9use dmntk_feel::closure::Closure;
10use dmntk_feel::context::FeelContext;
11use dmntk_feel::values::Value;
12use dmntk_feel::{FeelScope, FeelType, FunctionBody, Name};
13use dmntk_model::*;
14use std::collections::HashMap;
15use std::sync::Arc;
16
17type BusinessKnowledgeModelEvaluatorFn = Box<dyn Fn(&FeelContext, &FeelContext, &ModelEvaluator, &mut FeelContext) -> Name + Send + Sync>;
22
23#[derive(Default)]
25pub struct BusinessKnowledgeModelEvaluator {
26 evaluators: Arc<HashMap<DefKey, BusinessKnowledgeModelEvaluatorFn>>,
27}
28
29impl BusinessKnowledgeModelEvaluator {
30 pub fn new(definitions: &DefDefinitions, model_builder: &ModelBuilder) -> Result<Self> {
32 let mut evaluators = HashMap::new();
33 for business_knowledge_model in definitions.business_knowledge_models() {
34 let function_definition = business_knowledge_model.encapsulated_logic().as_ref().ok_or_else(err_empty_encapsulated_logic)?;
35 let evaluator = build_bkm_evaluator(definitions, business_knowledge_model, function_definition, model_builder)?;
36 let namespace = business_knowledge_model.namespace();
37 let id = business_knowledge_model.id();
38 let name = business_knowledge_model.name().to_string();
39 let output_variable_name = business_knowledge_model.variable().name().to_owned();
40 let def_key = DefKey::new(namespace, id);
41 evaluators.insert(def_key.clone(), evaluator);
42 model_builder.add_bkm_invocable(namespace.to_string(), name, def_key, output_variable_name);
43 }
44 Ok(Self { evaluators: Arc::new(evaluators) })
45 }
46
47 pub fn evaluate(
51 &self,
52 def_key: &DefKey,
53 global_context: &FeelContext,
54 input_data: &FeelContext,
55 model_evaluator: &ModelEvaluator,
56 output_data: &mut FeelContext,
57 ) -> Option<Name> {
58 self
59 .evaluators
60 .get(def_key)
61 .map(|evaluator_entry| evaluator_entry(global_context, input_data, model_evaluator, output_data))
62 }
63}
64
65fn build_bkm_evaluator(
66 definitions: &DefDefinitions,
67 business_knowledge_model: &DefBusinessKnowledgeModel,
68 function_definition: &FunctionDefinition,
69 model_builder: &ModelBuilder,
70) -> Result<BusinessKnowledgeModelEvaluatorFn> {
71 let item_definition_type_evaluator = model_builder.item_definition_type_evaluator();
72 let mut local_context = FeelContext::default();
73 let mut formal_parameters = vec![];
74 for information_item in function_definition.formal_parameters() {
75 let feel_type = item_definition_type_evaluator
76 .information_item_type(information_item.namespace(), information_item.type_ref())
77 .ok_or_else(err_empty_feel_type)?;
78 let feel_name = information_item.feel_name();
79 formal_parameters.push((feel_name.clone(), feel_type.clone()));
80 local_context.set_entry(feel_name, Value::FeelType(feel_type));
81 }
82 let output_variable_name = business_knowledge_model.variable().name().clone();
83 let output_variable_type = item_definition_type_evaluator
84 .information_item_type(business_knowledge_model.variable().namespace(), business_knowledge_model.variable().type_ref())
85 .unwrap_or(FeelType::Any);
86 let mut knowledge_requirements: Vec<DefKey> = vec![];
87 for knowledge_requirement in business_knowledge_model.knowledge_requirements() {
88 knowledge_requirements.push(knowledge_requirement.required_knowledge().into());
89 }
90 bring_knowledge_requirements_into_context(definitions, business_knowledge_model.knowledge_requirements(), &mut local_context)?;
92 if let Some(expression_instance) = function_definition.body() {
94 let scope: FeelScope = local_context.into();
95 build_bkm_expression_instance_evaluator(
96 &scope,
97 formal_parameters,
98 expression_instance,
99 output_variable_name,
100 output_variable_type,
101 knowledge_requirements,
102 model_builder,
103 )
104 } else {
105 let output_variable_name = business_knowledge_model.variable().name().clone();
106 Ok(Box::new(move |_: &FeelContext, _: &FeelContext, _: &ModelEvaluator, _: &mut FeelContext| {
107 output_variable_name.clone()
108 }))
109 }
110}
111
112fn build_bkm_expression_instance_evaluator(
113 scope: &FeelScope,
114 formal_parameters: Vec<(Name, FeelType)>,
115 expression_instance: &ExpressionInstance,
116 output_variable_name: Name,
117 output_variable_type: FeelType,
118 knowledge_requirements: Vec<DefKey>,
119 model_builder: &ModelBuilder,
120) -> Result<BusinessKnowledgeModelEvaluatorFn> {
121 match expression_instance {
122 ExpressionInstance::Context(context) => {
123 build_bkm_context_evaluator(
125 scope, formal_parameters, context, output_variable_name, output_variable_type, knowledge_requirements, model_builder, )
133 }
134 ExpressionInstance::DecisionTable(decision_table) => {
135 build_bkm_decision_table_evaluator(
137 scope, formal_parameters, decision_table, output_variable_name, output_variable_type, knowledge_requirements, model_builder, )
145 }
146 ExpressionInstance::FunctionDefinition(function_definition) => {
147 build_bkm_function_definition_evaluator(
149 scope, formal_parameters, function_definition, output_variable_name, output_variable_type, knowledge_requirements, model_builder, )
157 }
158 ExpressionInstance::Invocation(invocation) => {
159 build_bkm_invocation_evaluator(
161 scope, formal_parameters, invocation, output_variable_name, output_variable_type, knowledge_requirements, model_builder, )
169 }
170 ExpressionInstance::LiteralExpression(literal_expression) => {
171 build_bkm_literal_expression_evaluator(
173 scope, formal_parameters, literal_expression, output_variable_name, output_variable_type, knowledge_requirements, model_builder, )
181 }
182 ExpressionInstance::List(list) => {
183 build_bkm_list_evaluator(
185 scope, formal_parameters, list, output_variable_name, output_variable_type, knowledge_requirements, model_builder, )
193 }
194 ExpressionInstance::Relation(relation) => {
195 build_bkm_relation_evaluator(
197 scope, formal_parameters, relation, output_variable_name, output_variable_type, knowledge_requirements, model_builder, )
205 }
206 }
207}
208
209fn build_bkm_context_evaluator(
210 scope: &FeelScope,
211 formal_parameters: Vec<(Name, FeelType)>,
212 context: &Context,
213 output_variable_name: Name,
214 output_variable_type: FeelType,
215 knowledge_requirements: Vec<DefKey>,
216 model_builder: &ModelBuilder,
217) -> Result<BusinessKnowledgeModelEvaluatorFn> {
218 let (evaluator, _) = build_context_evaluator(scope, context, model_builder)?;
219 let closure = Closure::default();
220 let closure_ctx = FeelContext::default();
221 let function = Value::FunctionDefinition(
222 formal_parameters,
223 FunctionBody::Context(Arc::new(evaluator)),
224 false,
225 closure,
226 closure_ctx,
227 output_variable_type,
228 );
229 build_bkm_evaluator_from_function_definition(output_variable_name, function, knowledge_requirements)
230}
231
232fn build_bkm_decision_table_evaluator(
233 scope: &FeelScope,
234 formal_parameters: Vec<(Name, FeelType)>,
235 decision_table: &DecisionTable,
236 output_variable_name: Name,
237 output_variable_type: FeelType,
238 knowledge_requirements: Vec<DefKey>,
239 model_builder: &ModelBuilder,
240) -> Result<BusinessKnowledgeModelEvaluatorFn> {
241 let (evaluator, _) = build_decision_table_evaluator(scope, decision_table, model_builder)?;
242 let closure = Closure::default();
243 let closure_ctx = FeelContext::default();
244 let function = Value::FunctionDefinition(
245 formal_parameters,
246 FunctionBody::DecisionTable(Arc::new(evaluator)),
247 false,
248 closure,
249 closure_ctx,
250 output_variable_type,
251 );
252 build_bkm_evaluator_from_function_definition(output_variable_name, function, knowledge_requirements)
253}
254
255fn build_bkm_function_definition_evaluator(
256 scope: &FeelScope,
257 formal_parameters: Vec<(Name, FeelType)>,
258 function_definition: &FunctionDefinition,
259 output_variable_name: Name,
260 output_variable_type: FeelType,
261 knowledge_requirements: Vec<DefKey>,
262 model_builder: &ModelBuilder,
263) -> Result<BusinessKnowledgeModelEvaluatorFn> {
264 let (evaluator, _) = build_function_definition_evaluator(scope, function_definition, model_builder)?;
265 let closure = Closure::default();
266 let closure_ctx = FeelContext::default();
267 let function = Value::FunctionDefinition(
268 formal_parameters,
269 FunctionBody::FunctionDefinition(Arc::new(evaluator)),
270 false,
271 closure,
272 closure_ctx,
273 output_variable_type,
274 );
275 build_bkm_evaluator_from_function_definition(output_variable_name, function, knowledge_requirements)
276}
277
278fn build_bkm_invocation_evaluator(
279 scope: &FeelScope,
280 formal_parameters: Vec<(Name, FeelType)>,
281 invocation: &Invocation,
282 output_variable_name: Name,
283 output_variable_type: FeelType,
284 knowledge_requirements: Vec<DefKey>,
285 model_builder: &ModelBuilder,
286) -> Result<BusinessKnowledgeModelEvaluatorFn> {
287 let (evaluator, _) = build_invocation_evaluator(scope, invocation, model_builder)?;
288 let closure = Closure::default();
289 let closure_ctx = FeelContext::default();
290 let function = Value::FunctionDefinition(
291 formal_parameters,
292 FunctionBody::Invocation(Arc::new(evaluator)),
293 false,
294 closure,
295 closure_ctx,
296 output_variable_type,
297 );
298 build_bkm_evaluator_from_function_definition(output_variable_name, function, knowledge_requirements)
299}
300
301fn build_bkm_list_evaluator(
302 scope: &FeelScope,
303 formal_parameters: Vec<(Name, FeelType)>,
304 list: &List,
305 output_variable_name: Name,
306 output_variable_type: FeelType,
307 knowledge_requirements: Vec<DefKey>,
308 model_builder: &ModelBuilder,
309) -> Result<BusinessKnowledgeModelEvaluatorFn> {
310 let (evaluator, _) = build_list_evaluator(scope, list, model_builder)?;
311 let closure = Closure::default();
312 let closure_ctx = FeelContext::default();
313 let function = Value::FunctionDefinition(
314 formal_parameters,
315 FunctionBody::LiteralExpression(Arc::new(evaluator)),
316 false,
317 closure,
318 closure_ctx,
319 output_variable_type,
320 );
321 build_bkm_evaluator_from_function_definition(output_variable_name, function, knowledge_requirements)
322}
323
324fn build_bkm_literal_expression_evaluator(
325 scope: &FeelScope,
326 formal_parameters: Vec<(Name, FeelType)>,
327 literal_expression: &LiteralExpression,
328 output_variable_name: Name,
329 output_variable_type: FeelType,
330 knowledge_requirements: Vec<DefKey>,
331 model_builder: &ModelBuilder,
332) -> Result<BusinessKnowledgeModelEvaluatorFn> {
333 let (evaluator, _) = build_literal_expression_evaluator(scope, literal_expression, model_builder)?;
334 let closure = Closure::default();
335 let closure_ctx = FeelContext::default();
336 let function = Value::FunctionDefinition(
337 formal_parameters,
338 FunctionBody::LiteralExpression(Arc::new(evaluator)),
339 false,
340 closure,
341 closure_ctx,
342 output_variable_type,
343 );
344 build_bkm_evaluator_from_function_definition(output_variable_name, function, knowledge_requirements)
345}
346
347fn build_bkm_relation_evaluator(
348 scope: &FeelScope,
349 formal_parameters: Vec<(Name, FeelType)>,
350 relation: &Relation,
351 output_variable_name: Name,
352 output_variable_type: FeelType,
353 knowledge_requirements: Vec<DefKey>,
354 model_builder: &ModelBuilder,
355) -> Result<BusinessKnowledgeModelEvaluatorFn> {
356 let (evaluator, _) = build_relation_evaluator(scope, relation, model_builder)?;
357 let closure = Closure::default();
358 let closure_ctx = FeelContext::default();
359 let function_definition = Value::FunctionDefinition(
360 formal_parameters,
361 FunctionBody::Relation(Arc::new(evaluator)),
362 false,
363 closure,
364 closure_ctx,
365 output_variable_type,
366 );
367 build_bkm_evaluator_from_function_definition(output_variable_name, function_definition, knowledge_requirements)
368}
369
370fn build_bkm_evaluator_from_function_definition(
371 output_variable_name: Name,
372 function_definition: Value,
373 knowledge_requirements: Vec<DefKey>,
374) -> Result<BusinessKnowledgeModelEvaluatorFn> {
375 Ok(Box::new(
376 move |global_context: &FeelContext, input_data: &FeelContext, model_evaluator: &ModelEvaluator, output_data: &mut FeelContext| {
377 let business_knowledge_model_evaluator = model_evaluator.business_knowledge_model_evaluator();
378 let decision_service_evaluator = model_evaluator.decision_service_evaluator();
379 knowledge_requirements.iter().for_each(|def_key| {
380 business_knowledge_model_evaluator.evaluate(def_key, global_context, input_data, model_evaluator, output_data);
384 decision_service_evaluator.evaluate(def_key, global_context, input_data, model_evaluator, output_data);
385 });
386 output_data.set_entry(&output_variable_name, function_definition.clone());
387 output_variable_name.clone()
388 },
389 ))
390}