aimx/expressions/
evaluate.rs1use crate::{
7 aim::{ContextLike, WorkflowStatus},
8 expressions::Reference,
9 functions::FunctionRegistry,
10 values::Value,
11};
12use anyhow::{Result, anyhow};
13use std::{
14 mem::replace,
15 sync::Arc,
16};
17
18pub trait ExpressionLike {
23 fn evaluate(&self, context: &mut dyn ContextLike) -> Result<Arc<Value>>;
25
26 fn to_formula(&self) -> String;
27}
28
29pub fn evaluate_and_promote(
34 context: &mut dyn ContextLike,
35 left: &dyn ExpressionLike,
36 right: &dyn ExpressionLike,
37) -> Result<(Arc<Value>, Arc<Value>)> {
38 let left_val = left.evaluate(context)?;
40 let unknown_type = right.evaluate(context)?;
42 match unknown_type.as_type(left_val.clone()) {
44 Ok(right_val) => Ok((left_val, right_val)),
45 Err(err) => {
46 let message = format!("{}~{}", err, right.to_formula());
47 Err(anyhow!(message))
48 }
49 }
50 }
52
53pub fn statically_evaluate(expression: &dyn ExpressionLike) -> Result<Arc<Value>> {
60 struct StaticContext {
62 stack: [(Arc<str>, Arc<Value>); 2],
63 }
64
65 impl StaticContext {
66 pub fn new() -> Self {
67 Self {
68 stack: [(Value::empty_str(), Value::empty()), (Value::empty_str(), Value::empty())],
69 }
70 }
71 }
72
73 impl ContextLike for StaticContext {
74 fn start_closure(&mut self) -> [(Arc<str>, Arc<Value>); 2] {
75 replace(
76 &mut self.stack,
77 [(Value::empty_str(), Value::empty()), (Value::empty_str(), Value::empty())],
78 )
79 }
80
81 fn set_key(&mut self, index: usize, identifier: Arc<str>) {
82 if self.stack[index].0 != identifier {
83 self.stack[index].0 = identifier.clone();
84 }
85 }
86 fn set_parameter(&mut self, index: usize, value: Arc<Value>) {
87 self.stack[index].1 = value.clone();
88 }
89
90 fn end_closure(&mut self, stack: [(Arc<str>, Arc<Value>); 2]) {
91 self.stack = stack;
92 }
93 fn get_value(&mut self, reference: &Reference) -> Result<Arc<Value>> {
94 if *reference == *self.stack[0].0 {
95 Ok(self.stack[0].1.clone())
96 } else if *reference == *self.stack[1].0 {
97 Ok(self.stack[1].1.clone())
98 } else {
99 Err(anyhow!("Non-static expression"))
100 }
101 }
102 fn set_value(&mut self, identifier: &str, value: Arc<Value>) -> Result<()> {
103 if *identifier == *self.stack[0].0 {
104 self.stack[0].1 = value;
105 Ok(())
106 } else if *identifier == *self.stack[1].0 {
107 self.stack[1].1 = value;
108 Ok(())
109 } else {
110 Err(anyhow!("Non-static expression"))
111 }
112 }
113 fn function_call(&mut self, name: Arc<str>, arg: Arc<Value>) -> Result<Arc<Value>> {
114 let registry = FunctionRegistry::read_lock()?;
115 registry.function_call(self, name, arg)
116 }
117 fn method_call(&mut self, name: Arc<str>, value: Arc<Value>, arg: Arc<Value>) -> Result<Arc<Value>> {
118 let registry = FunctionRegistry::read_lock()?;
119 registry.method_call(self, name, value, arg)
120 }
121 fn inference_call(&mut self, _reference: Arc<Reference>, _arg: Arc<Value>) -> Result<Arc<Value>> {
122 Err(anyhow!("Non-static inference"))
123 }
124 fn run_evaluation(&mut self, _start_state: Option<Arc<str>>) -> WorkflowStatus {
125 WorkflowStatus::Failed {
126 state_id: None,
127 errata: None,
128 }
129 }
130 }
131
132 use std::sync::Mutex;
134 use std::sync::OnceLock;
135
136 static INSTANCE: OnceLock<Mutex<StaticContext>> = OnceLock::new();
137
138 let context = INSTANCE.get_or_init(|| Mutex::new(StaticContext::new()));
139
140 let mut context = context.lock().unwrap();
141 expression.evaluate(&mut *context)
142}