darklua_core/rules/
call_parens.rs

1use crate::nodes::{Arguments, Block, Expression, FunctionCall, StringExpression, TableExpression};
2use crate::process::{DefaultVisitor, NodeProcessor, NodeVisitor};
3use crate::rules::{
4    Context, FlawlessRule, RuleConfiguration, RuleConfigurationError, RuleProperties,
5};
6
7use std::mem;
8
9use super::verify_no_rule_properties;
10
11#[derive(Debug, Clone, Default)]
12struct Processor {}
13
14impl NodeProcessor for Processor {
15    fn process_function_call(&mut self, call: &mut FunctionCall) {
16        let new_arguments = match call.mutate_arguments() {
17            Arguments::Tuple(tuple) if tuple.len() == 1 => {
18                let expression = tuple.iter_mut_values().next().unwrap();
19
20                match expression {
21                    Expression::String(string) => {
22                        let mut steal_string = StringExpression::empty();
23                        mem::swap(string, &mut steal_string);
24                        Some(Arguments::String(steal_string))
25                    }
26                    Expression::Table(table) => {
27                        let mut steal_table = TableExpression::default();
28                        mem::swap(table, &mut steal_table);
29                        Some(Arguments::Table(steal_table))
30                    }
31                    _ => None,
32                }
33            }
34            _ => None,
35        };
36
37        if let Some(new_arguments) = new_arguments {
38            *call.mutate_arguments() = new_arguments;
39        }
40    }
41}
42
43pub const REMOVE_FUNCTION_CALL_PARENS_RULE_NAME: &str = "remove_function_call_parens";
44
45/// A rule that removes parentheses when calling functions with a string or a table.
46#[derive(Debug, Default, PartialEq, Eq)]
47pub struct RemoveFunctionCallParens {}
48
49impl FlawlessRule for RemoveFunctionCallParens {
50    fn flawless_process(&self, block: &mut Block, _: &Context) {
51        let mut processor = Processor::default();
52        DefaultVisitor::visit_block(block, &mut processor);
53    }
54}
55
56impl RuleConfiguration for RemoveFunctionCallParens {
57    fn configure(&mut self, properties: RuleProperties) -> Result<(), RuleConfigurationError> {
58        verify_no_rule_properties(&properties)?;
59
60        Ok(())
61    }
62
63    fn get_name(&self) -> &'static str {
64        REMOVE_FUNCTION_CALL_PARENS_RULE_NAME
65    }
66
67    fn serialize_to_properties(&self) -> RuleProperties {
68        RuleProperties::new()
69    }
70}
71
72#[cfg(test)]
73mod test {
74    use super::*;
75    use crate::rules::Rule;
76
77    use insta::assert_json_snapshot;
78
79    fn new_rule() -> RemoveFunctionCallParens {
80        RemoveFunctionCallParens::default()
81    }
82
83    #[test]
84    fn serialize_default_rule() {
85        let rule: Box<dyn Rule> = Box::new(new_rule());
86
87        assert_json_snapshot!("default_remove_function_call_parens", rule);
88    }
89
90    #[test]
91    fn configure_with_extra_field_error() {
92        let result = json5::from_str::<Box<dyn Rule>>(
93            r#"{
94            rule: 'remove_function_call_parens',
95            prop: "something",
96        }"#,
97        );
98        pretty_assertions::assert_eq!(result.unwrap_err().to_string(), "unexpected field 'prop'");
99    }
100}