1use std::collections::HashSet;
9use std::fmt;
10
11use super::expression_evaluation_context::ExpressionEvaluationContext;
12use super::expression_parse_exception::ExpressionParseException;
13use super::expression_parser::ExpressionParser;
14use super::expression_variant::ExpressionVariant;
15use crate::numerics::InvariantF32;
16
17#[derive(Clone, Debug, PartialEq)]
19pub enum Expression {
20 Conditional(ConditionalExpression),
21 Constant(ConstantExpression),
22 FunctionCall(FunctionCallExpression),
23 MemberAccess(MemberAccessExpression),
24 Parameter(ParameterExpression),
25 Keyword(KeywordExpression),
26 Unary(UnaryExpression),
27 Binary(BinaryExpression),
28}
29
30impl Expression {
31 pub fn expression_type(&self) -> ExpressionType {
33 match self {
34 Expression::Conditional(_) => ExpressionType::ConditionalExpression,
35 Expression::Constant(_) => ExpressionType::Constant,
36 Expression::FunctionCall(_) => ExpressionType::FunctionCall,
37 Expression::MemberAccess(_) => ExpressionType::MemberAccess,
38 Expression::Parameter(_) => ExpressionType::Parameter,
39 Expression::Keyword(_) => ExpressionType::Keyword,
40 Expression::Unary(e) => e.expression_type,
41 Expression::Binary(e) => e.expression_type,
42 }
43 }
44
45 pub fn parse(expression: &str) -> Result<Expression, ExpressionParseException> {
47 ExpressionParser::parse(expression)
48 }
49
50 pub fn evaluate(&self, context: &ExpressionEvaluationContext<'_>) -> ExpressionVariant {
59 match self {
60 Expression::Conditional(e) => e.evaluate(context),
61 Expression::Constant(e) => e.evaluate(context),
62 Expression::FunctionCall(e) => e.evaluate(context),
63 Expression::MemberAccess(e) => e.evaluate(context),
64 Expression::Parameter(e) => e.evaluate(context),
65 Expression::Keyword(e) => e.evaluate(context),
66 Expression::Unary(e) => e.evaluate(context),
67 Expression::Binary(e) => e.evaluate(context),
68 }
69 }
70
71 pub fn collect_references(&self, references: &mut HashSet<(String, String)>) {
75 match self {
76 Expression::Conditional(e) => e.collect_references(references),
77 Expression::FunctionCall(e) => e.collect_references(references),
78 Expression::MemberAccess(e) => e.collect_references(references),
79 Expression::Unary(e) => e.collect_references(references),
80 Expression::Binary(e) => e.collect_references(references),
81 Expression::Constant(_) | Expression::Parameter(_) | Expression::Keyword(_) => {}
82 }
83 }
84
85 pub fn operator_name(t: ExpressionType) -> &'static str {
88 match t {
89 ExpressionType::Add => "+",
90 ExpressionType::Subtract => "-",
91 ExpressionType::Divide => "/",
92 ExpressionType::Multiply => "*",
93 ExpressionType::MoreThan => ">",
94 ExpressionType::LessThan => "<",
95 ExpressionType::MoreThanOrEqual => ">=",
96 ExpressionType::LessThanOrEqual => "<=",
97 ExpressionType::LogicalAnd => "&&",
98 ExpressionType::LogicalOr => "||",
99 ExpressionType::Remainder => "%",
100 ExpressionType::Equals => "Equals",
105 ExpressionType::NotEquals => "!=",
106 ExpressionType::Not => "!",
107 ExpressionType::UnaryMinus => "-",
108 ExpressionType::MemberAccess => "MemberAccess",
109 ExpressionType::Parameter => "Parameter",
110 ExpressionType::FunctionCall => "FunctionCall",
111 ExpressionType::Keyword => "Keyword",
112 ExpressionType::Constant => "Constant",
113 ExpressionType::ConditionalExpression => "ConditionalExpression",
114 }
115 }
116}
117
118impl fmt::Display for Expression {
119 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
120 match self {
121 Expression::Conditional(e) => e.fmt(f),
122 Expression::Constant(e) => e.fmt(f),
123 Expression::FunctionCall(e) => e.fmt(f),
124 Expression::MemberAccess(e) => e.fmt(f),
125 Expression::Parameter(e) => e.fmt(f),
126 Expression::Keyword(e) => e.fmt(f),
127 Expression::Unary(e) => e.fmt(f),
128 Expression::Binary(e) => e.fmt(f),
129 }
130 }
131}
132
133macro_rules! into_expression {
134 ($($variant:ident($ty:ident)),+ $(,)?) => {
135 $(impl From<$ty> for Expression {
136 #[inline]
137 fn from(value: $ty) -> Expression {
138 Expression::$variant(value)
139 }
140 })+
141 };
142}
143
144into_expression!(
145 Conditional(ConditionalExpression),
146 Constant(ConstantExpression),
147 FunctionCall(FunctionCallExpression),
148 MemberAccess(MemberAccessExpression),
149 Parameter(ParameterExpression),
150 Keyword(KeywordExpression),
151 Unary(UnaryExpression),
152 Binary(BinaryExpression),
153);
154
155#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
157pub enum ExpressionType {
158 Add,
160 Subtract,
161 Divide,
162 Multiply,
163 MoreThan,
164 LessThan,
165 MoreThanOrEqual,
166 LessThanOrEqual,
167 LogicalAnd,
168 LogicalOr,
169 Remainder,
170 Equals,
171 NotEquals,
172 Not,
174 UnaryMinus,
175 MemberAccess,
177 Parameter,
178 FunctionCall,
179 Keyword,
180 Constant,
181 ConditionalExpression,
182}
183
184#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
186pub enum ExpressionKeyword {
187 StartingValue,
188 CurrentValue,
189 FinalValue,
190 Target,
191 Pi,
192 True,
193 False,
194}
195
196pub struct ExpressionKeywords;
198
199impl ExpressionKeywords {
200 pub const STARTING_VALUE: &'static str = "this.startingvalue";
201 pub const CURRENT_VALUE: &'static str = "this.currentvalue";
202 pub const FINAL_VALUE: &'static str = "this.finalvalue";
203 pub const PI: &'static str = "pi";
204 pub const TRUE: &'static str = "true";
205 pub const FALSE: &'static str = "false";
206 pub const TARGET: &'static str = "this.target";
207}
208
209#[derive(Clone, Debug, PartialEq)]
211pub struct ConditionalExpression {
212 pub condition: Box<Expression>,
213 pub true_part: Box<Expression>,
214 pub false_part: Box<Expression>,
215}
216
217impl ConditionalExpression {
218 pub fn new(condition: Expression, true_part: Expression, false_part: Expression) -> Self {
219 Self {
220 condition: Box::new(condition),
221 true_part: Box::new(true_part),
222 false_part: Box::new(false_part),
223 }
224 }
225
226 pub fn evaluate(&self, context: &ExpressionEvaluationContext<'_>) -> ExpressionVariant {
227 let cond = self.condition.evaluate(context);
228 if cond == ExpressionVariant::Boolean(true) {
229 return self.true_part.evaluate(context);
230 }
231 self.false_part.evaluate(context)
232 }
233
234 pub fn collect_references(&self, references: &mut HashSet<(String, String)>) {
235 self.condition.collect_references(references);
236 self.true_part.collect_references(references);
237 self.false_part.collect_references(references);
238 }
239}
240
241impl fmt::Display for ConditionalExpression {
242 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
243 write!(f, "({}) ? ({}) : ({})", self.condition, self.true_part, self.false_part)
244 }
245}
246
247#[derive(Clone, Debug, PartialEq)]
249pub struct ConstantExpression {
250 pub constant: f32,
251}
252
253impl ConstantExpression {
254 pub fn new(constant: f32) -> Self {
255 Self { constant }
256 }
257
258 pub fn evaluate(&self, _context: &ExpressionEvaluationContext<'_>) -> ExpressionVariant {
259 self.constant.into()
260 }
261}
262
263impl fmt::Display for ConstantExpression {
264 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
265 InvariantF32(self.constant).fmt(f)
266 }
267}
268
269#[derive(Clone, Debug, PartialEq)]
271pub struct FunctionCallExpression {
272 pub name: String,
273 pub parameters: Vec<Expression>,
274}
275
276impl FunctionCallExpression {
277 pub fn new(name: impl Into<String>, parameters: Vec<Expression>) -> Self {
278 Self {
279 name: name.into(),
280 parameters,
281 }
282 }
283
284 pub fn evaluate(&self, context: &ExpressionEvaluationContext<'_>) -> ExpressionVariant {
285 let mut args = Vec::with_capacity(self.parameters.len());
286 for expr in &self.parameters {
287 args.push(expr.evaluate(context));
288 }
289 context
290 .foreign_function_interface
291 .expect("the expression evaluation context has no foreign function interface")
292 .call(&self.name, &args)
293 .unwrap_or_default()
294 }
295
296 pub fn collect_references(&self, references: &mut HashSet<(String, String)>) {
297 for arg in &self.parameters {
298 arg.collect_references(references);
299 }
300 }
301}
302
303impl fmt::Display for FunctionCallExpression {
304 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
305 write!(f, "{}( (", self.name)?;
306 for (i, parameter) in self.parameters.iter().enumerate() {
307 if i != 0 {
308 f.write_str("), (")?;
309 }
310 parameter.fmt(f)?;
311 }
312 f.write_str(") )")
313 }
314}
315
316#[derive(Clone, Debug, PartialEq)]
318pub struct MemberAccessExpression {
319 pub target: Box<Expression>,
320 pub member: String,
321}
322
323impl MemberAccessExpression {
324 pub fn new(target: Expression, member: impl Into<String>) -> Self {
325 Self {
326 target: Box::new(target),
327 member: member.into(),
328 }
329 }
330
331 pub fn collect_references(&self, references: &mut HashSet<(String, String)>) {
332 self.target.collect_references(references);
333 match &*self.target {
334 Expression::Parameter(pe) => {
335 references.insert((pe.name.clone(), self.member.clone()));
336 }
337 Expression::Keyword(KeywordExpression {
338 keyword: ExpressionKeyword::Target,
339 }) => {
340 references.insert((ExpressionKeywords::TARGET.to_owned(), self.member.clone()));
341 }
342 _ => {}
343 }
344 }
345
346 pub fn evaluate(&self, context: &ExpressionEvaluationContext<'_>) -> ExpressionVariant {
347 match &*self.target {
348 Expression::Keyword(ke) if ke.keyword == ExpressionKeyword::Target => {
349 return context
350 .target
351 .expect("the expression evaluation context has no target")
352 .get_property(&self.member);
353 }
354 Expression::Parameter(pe) => {
355 if let Some(obj) = context.parameters.and_then(|p| p.get_object_parameter(&pe.name)) {
356 return obj.get_property(&self.member);
357 }
358 }
359 _ => {}
360 }
361 self.target.evaluate(context).get_property(&self.member)
363 }
364}
365
366impl fmt::Display for MemberAccessExpression {
367 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
368 write!(f, "({}).{}", self.target, self.member)
369 }
370}
371
372#[derive(Clone, Debug, PartialEq)]
374pub struct ParameterExpression {
375 pub name: String,
376}
377
378impl ParameterExpression {
379 pub fn new(name: impl Into<String>) -> Self {
380 Self { name: name.into() }
381 }
382
383 pub fn evaluate(&self, context: &ExpressionEvaluationContext<'_>) -> ExpressionVariant {
384 context
385 .parameters
386 .map(|p| p.get_parameter(&self.name))
387 .unwrap_or_default()
388 }
389}
390
391impl fmt::Display for ParameterExpression {
392 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
393 write!(f, "{{{}}}", self.name)
394 }
395}
396
397#[derive(Clone, Debug, PartialEq)]
399pub struct KeywordExpression {
400 pub keyword: ExpressionKeyword,
401}
402
403impl KeywordExpression {
404 pub fn new(keyword: ExpressionKeyword) -> Self {
405 Self { keyword }
406 }
407
408 pub fn evaluate(&self, context: &ExpressionEvaluationContext<'_>) -> ExpressionVariant {
409 match self.keyword {
410 ExpressionKeyword::StartingValue => context.starting_value,
411 ExpressionKeyword::CurrentValue => context.current_value,
412 ExpressionKeyword::FinalValue => context.final_value,
413 ExpressionKeyword::Target => ExpressionVariant::Invalid,
415 ExpressionKeyword::True => true.into(),
416 ExpressionKeyword::False => false.into(),
417 ExpressionKeyword::Pi => std::f32::consts::PI.into(),
418 }
419 }
420}
421
422impl fmt::Display for KeywordExpression {
423 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
424 write!(f, "[{:?}]", self.keyword)
425 }
426}
427
428#[derive(Clone, Debug, PartialEq)]
430pub struct UnaryExpression {
431 pub parameter: Box<Expression>,
432 pub expression_type: ExpressionType,
433}
434
435impl UnaryExpression {
436 pub fn new(parameter: Expression, expression_type: ExpressionType) -> Self {
437 Self {
438 parameter: Box::new(parameter),
439 expression_type,
440 }
441 }
442
443 pub fn evaluate(&self, context: &ExpressionEvaluationContext<'_>) -> ExpressionVariant {
444 match self.expression_type {
445 ExpressionType::Not => !self.parameter.evaluate(context),
446 ExpressionType::UnaryMinus => -self.parameter.evaluate(context),
447 _ => ExpressionVariant::Invalid,
448 }
449 }
450
451 pub fn collect_references(&self, references: &mut HashSet<(String, String)>) {
452 self.parameter.collect_references(references);
453 }
454}
455
456impl fmt::Display for UnaryExpression {
457 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
458 write!(f, "{}{}", Expression::operator_name(self.expression_type), self.parameter)
459 }
460}
461
462#[derive(Clone, Debug, PartialEq)]
464pub struct BinaryExpression {
465 pub left: Box<Expression>,
466 pub right: Box<Expression>,
467 pub expression_type: ExpressionType,
468}
469
470impl BinaryExpression {
471 pub fn new(left: Expression, right: Expression, expression_type: ExpressionType) -> Self {
472 Self {
473 left: Box::new(left),
474 right: Box::new(right),
475 expression_type,
476 }
477 }
478
479 pub fn evaluate(&self, context: &ExpressionEvaluationContext<'_>) -> ExpressionVariant {
480 let left = self.left.evaluate(context);
481 let right = self.right.evaluate(context);
482 match self.expression_type {
483 ExpressionType::Add => left + right,
484 ExpressionType::Subtract => left - right,
485 ExpressionType::Multiply => left * right,
486 ExpressionType::Divide => left / right,
487 ExpressionType::Remainder => left % right,
488 ExpressionType::MoreThan => left.more_than(right),
489 ExpressionType::LessThan => left.less_than(right),
490 ExpressionType::MoreThanOrEqual => left.more_than(right),
492 ExpressionType::LessThanOrEqual => left.less_than(right),
493 ExpressionType::LogicalAnd => left.and(right),
494 ExpressionType::LogicalOr => left.or(right),
495 ExpressionType::Equals => left.equals_to(right),
496 ExpressionType::NotEquals => left.not_equals_to(right),
497 _ => ExpressionVariant::Invalid,
498 }
499 }
500
501 pub fn collect_references(&self, references: &mut HashSet<(String, String)>) {
502 self.left.collect_references(references);
503 self.right.collect_references(references);
504 }
505}
506
507impl fmt::Display for BinaryExpression {
508 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
509 write!(
510 f,
511 "({}{}{})",
512 self.left,
513 Expression::operator_name(self.expression_type),
514 self.right
515 )
516 }
517}