darklua_core/rules/
remove_if_expression.rs

1use crate::nodes::{
2    BinaryExpression, BinaryOperator, Block, Expression, IndexExpression, TableEntry,
3    TableExpression,
4};
5use crate::process::{DefaultVisitor, Evaluator, NodeProcessor, NodeVisitor};
6use crate::rules::{
7    Context, FlawlessRule, RuleConfiguration, RuleConfigurationError, RuleProperties,
8};
9
10use super::verify_no_rule_properties;
11
12#[derive(Default)]
13struct Processor {
14    evaluator: Evaluator,
15}
16
17impl Processor {
18    fn wrap_in_table(&self, expression: Expression) -> Expression {
19        TableExpression::new(vec![TableEntry::Value({
20            if self.evaluator.can_return_multiple_values(&expression) {
21                expression.in_parentheses()
22            } else {
23                expression
24            }
25        })])
26        .into()
27    }
28
29    fn convert_if_branch(
30        &self,
31        condition: Expression,
32        result: Expression,
33        else_result: Expression,
34    ) -> Expression {
35        if self
36            .evaluator
37            .evaluate(&result)
38            .is_truthy()
39            .unwrap_or_default()
40        {
41            BinaryExpression::new(
42                BinaryOperator::Or,
43                BinaryExpression::new(BinaryOperator::And, condition, result),
44                else_result,
45            )
46            .into()
47        } else {
48            IndexExpression::new(
49                Expression::from(BinaryExpression::new(
50                    BinaryOperator::Or,
51                    BinaryExpression::new(
52                        BinaryOperator::And,
53                        condition,
54                        self.wrap_in_table(result),
55                    ),
56                    self.wrap_in_table(else_result),
57                )),
58                Expression::from(1),
59            )
60            .into()
61        }
62    }
63}
64
65impl NodeProcessor for Processor {
66    fn process_expression(&mut self, expression: &mut Expression) {
67        if let Expression::If(if_expression) = expression {
68            let else_result = if_expression.iter_branches().fold(
69                if_expression.get_else_result().clone(),
70                |else_result, branch| {
71                    self.convert_if_branch(
72                        branch.get_condition().clone(),
73                        branch.get_result().clone(),
74                        else_result,
75                    )
76                },
77            );
78
79            *expression = self.convert_if_branch(
80                if_expression.get_condition().clone(),
81                if_expression.get_result().clone(),
82                else_result,
83            );
84        }
85    }
86}
87
88pub const REMOVE_IF_EXPRESSION_RULE_NAME: &str = "remove_if_expression";
89
90/// A rule that removes trailing `nil` in local assignments.
91#[derive(Debug, Default, PartialEq, Eq)]
92pub struct RemoveIfExpression {}
93
94impl FlawlessRule for RemoveIfExpression {
95    fn flawless_process(&self, block: &mut Block, _: &Context) {
96        let mut processor = Processor::default();
97        DefaultVisitor::visit_block(block, &mut processor);
98    }
99}
100
101impl RuleConfiguration for RemoveIfExpression {
102    fn configure(&mut self, properties: RuleProperties) -> Result<(), RuleConfigurationError> {
103        verify_no_rule_properties(&properties)?;
104
105        Ok(())
106    }
107
108    fn get_name(&self) -> &'static str {
109        REMOVE_IF_EXPRESSION_RULE_NAME
110    }
111
112    fn serialize_to_properties(&self) -> RuleProperties {
113        RuleProperties::new()
114    }
115}
116
117#[cfg(test)]
118mod test {
119    use super::*;
120    use crate::rules::Rule;
121
122    use insta::assert_json_snapshot;
123
124    fn new_rule() -> RemoveIfExpression {
125        RemoveIfExpression::default()
126    }
127
128    #[test]
129    fn serialize_default_rule() {
130        let rule: Box<dyn Rule> = Box::new(new_rule());
131
132        assert_json_snapshot!("default_remove_if_expression", rule);
133    }
134
135    #[test]
136    fn configure_with_extra_field_error() {
137        let result = json5::from_str::<Box<dyn Rule>>(
138            r#"{
139            rule: 'remove_if_expression',
140            prop: "something",
141        }"#,
142        );
143        pretty_assertions::assert_eq!(result.unwrap_err().to_string(), "unexpected field 'prop'");
144    }
145}