darklua_core/rules/
compute_expression.rs1use crate::nodes::{BinaryOperator, Block, Expression};
2use crate::process::{DefaultVisitor, Evaluator, NodeProcessor, NodeVisitor};
3use crate::rules::{
4 Context, FlawlessRule, RuleConfiguration, RuleConfigurationError, RuleMetadata, RuleProperties,
5};
6
7use super::verify_no_rule_properties;
8
9#[derive(Debug, Clone, Default)]
10struct Computer {
11 evaluator: Evaluator,
12}
13
14impl Computer {
15 fn replace_with(&mut self, expression: &Expression) -> Option<Expression> {
16 match expression {
17 Expression::Unary(_) => {
18 if !self.evaluator.has_side_effects(expression) {
19 self.evaluator.evaluate(expression).to_expression()
20 } else {
21 None
22 }
23 }
24 Expression::Binary(binary) => {
25 if !self.evaluator.has_side_effects(expression) {
26 self.evaluator
27 .evaluate(expression)
28 .to_expression()
29 .or_else(|| {
30 match binary.operator() {
31 BinaryOperator::And => {
32 self.evaluator.evaluate(binary.left()).is_truthy().map(
33 |is_truthy| {
34 if is_truthy {
35 binary.right().clone()
36 } else {
37 binary.left().clone()
38 }
39 },
40 )
41 }
42 BinaryOperator::Or => {
43 self.evaluator.evaluate(binary.left()).is_truthy().map(
44 |is_truthy| {
45 if is_truthy {
46 binary.left().clone()
47 } else {
48 binary.right().clone()
49 }
50 },
51 )
52 }
53 _ => None,
54 }
55 .map(|mut expression| {
56 self.process_expression(&mut expression);
57 expression
58 })
59 })
60 } else {
61 match binary.operator() {
62 BinaryOperator::And => {
63 if !self.evaluator.has_side_effects(binary.left()) {
64 self.evaluator.evaluate(binary.left()).is_truthy().map(
65 |is_truthy| {
66 if is_truthy {
67 binary.right().clone()
68 } else {
69 binary.left().clone()
70 }
71 },
72 )
73 } else {
74 None
75 }
76 }
77 BinaryOperator::Or => {
78 if !self.evaluator.has_side_effects(binary.left()) {
79 self.evaluator.evaluate(binary.left()).is_truthy().map(
80 |is_truthy| {
81 if is_truthy {
82 binary.left().clone()
83 } else {
84 binary.right().clone()
85 }
86 },
87 )
88 } else {
89 None
90 }
91 }
92 _ => None,
93 }
94 }
95 }
96 Expression::If(_) => {
97 if !self.evaluator.has_side_effects(expression) {
98 self.evaluator.evaluate(expression).to_expression()
99 } else {
100 None
101 }
102 }
103 _ => None,
104 }
105 }
106}
107
108impl NodeProcessor for Computer {
109 fn process_expression(&mut self, expression: &mut Expression) {
110 if let Some(replace_with) = self.replace_with(expression) {
111 *expression = replace_with;
112 }
113 }
114}
115
116pub const COMPUTE_EXPRESSIONS_RULE_NAME: &str = "compute_expression";
117
118#[derive(Debug, Default, PartialEq, Eq)]
120pub struct ComputeExpression {
121 metadata: RuleMetadata,
122}
123
124impl FlawlessRule for ComputeExpression {
125 fn flawless_process(&self, block: &mut Block, _: &Context) {
126 let mut processor = Computer::default();
127 DefaultVisitor::visit_block(block, &mut processor);
128 }
129}
130
131impl RuleConfiguration for ComputeExpression {
132 fn configure(&mut self, properties: RuleProperties) -> Result<(), RuleConfigurationError> {
133 verify_no_rule_properties(&properties)?;
134
135 Ok(())
136 }
137
138 fn get_name(&self) -> &'static str {
139 COMPUTE_EXPRESSIONS_RULE_NAME
140 }
141
142 fn serialize_to_properties(&self) -> RuleProperties {
143 RuleProperties::new()
144 }
145
146 fn set_metadata(&mut self, metadata: RuleMetadata) {
147 self.metadata = metadata;
148 }
149
150 fn metadata(&self) -> &RuleMetadata {
151 &self.metadata
152 }
153}
154
155#[cfg(test)]
156mod test {
157 use super::*;
158 use crate::rules::Rule;
159
160 use insta::assert_json_snapshot;
161
162 fn new_rule() -> ComputeExpression {
163 ComputeExpression::default()
164 }
165
166 #[test]
167 fn serialize_default_rule() {
168 let rule: Box<dyn Rule> = Box::new(new_rule());
169
170 assert_json_snapshot!(rule, @r###""compute_expression""###);
171 }
172}