dalbit_core/modifiers/
optimize_table_initializers.rs

1use std::str::FromStr;
2
3use anyhow::anyhow;
4use darklua_core::{
5    nodes::{Arguments, Block, Expression, Prefix, TableExpression},
6    process::{DefaultVisitor, NodeProcessor, NodeVisitor},
7    rules::{Context, FlawlessRule, RuleConfiguration, RuleConfigurationError, RuleProperties},
8};
9
10pub const OPTIMIZE_TABLE_INITIALIZERS_MODIFIER_NAME: &str = "optimize_table_initializers";
11
12const DEFAULT_TABLE_LIBRARY: &str = "table";
13
14#[non_exhaustive]
15enum OptimizableTableMethod {
16    Create,
17    Freeze,
18}
19
20impl OptimizableTableMethod {
21    fn try_optimize(&self, arguments: &Arguments) -> Option<Expression> {
22        match self {
23            OptimizableTableMethod::Create => {
24                if let Arguments::Tuple(tuple) = arguments {
25                    if tuple.len() < 2 {
26                        return Some(Expression::Table(TableExpression::default()));
27                    }
28                }
29            }
30            OptimizableTableMethod::Freeze => match arguments {
31                Arguments::Tuple(tuple) => {
32                    let first_arg = tuple.iter_values().next();
33                    return first_arg.cloned();
34                }
35                Arguments::Table(table) => {
36                    return Some(Expression::Table(table.to_owned()));
37                }
38                _ => {
39                    return None;
40                }
41            },
42        };
43        None
44    }
45}
46
47impl FromStr for OptimizableTableMethod {
48    type Err = anyhow::Error;
49
50    fn from_str(s: &str) -> Result<Self, Self::Err> {
51        let optimizer = match s {
52            "create" => OptimizableTableMethod::Create,
53            "freeze" => OptimizableTableMethod::Freeze,
54            _ => {
55                return Err(anyhow!("Invalid OptimizableTableMethod `{}`", s));
56            }
57        };
58
59        Ok(optimizer)
60    }
61}
62
63struct Processor {}
64
65impl NodeProcessor for Processor {
66    fn process_expression(&mut self, exp: &mut Expression) {
67        if let Expression::Call(func_call) = exp {
68            let lib_and_call: Option<(&str, &str)> = match func_call.get_prefix() {
69                Prefix::Field(field) => {
70                    if let Prefix::Identifier(identifier) = field.get_prefix() {
71                        Some((identifier.get_name(), field.get_field().get_name()))
72                    } else {
73                        None
74                    }
75                }
76                Prefix::Index(index) => {
77                    if let Expression::String(string) = index.get_index() {
78                        if let Prefix::Identifier(identifier) = index.get_prefix() {
79                            Some((identifier.get_name(), string.get_value()))
80                        } else {
81                            None
82                        }
83                    } else {
84                        None
85                    }
86                }
87                _ => None,
88            };
89            if let Some((lib_name, call_name)) = lib_and_call {
90                if lib_name != DEFAULT_TABLE_LIBRARY {
91                    return;
92                }
93                if let Ok(method) = OptimizableTableMethod::from_str(call_name) {
94                    let new_exp = method.try_optimize(func_call.get_arguments());
95                    if let Some(new_exp) = new_exp {
96                        *exp = new_exp;
97                    }
98                }
99            }
100        }
101    }
102}
103
104#[derive(Default, Debug)]
105pub struct OptimizeTableInitializers {}
106
107impl FlawlessRule for OptimizeTableInitializers {
108    fn flawless_process(&self, block: &mut Block, _: &Context) {
109        let mut processor = Processor {};
110        DefaultVisitor::visit_block(block, &mut processor);
111    }
112}
113
114impl RuleConfiguration for OptimizeTableInitializers {
115    fn configure(&mut self, _: RuleProperties) -> Result<(), RuleConfigurationError> {
116        Ok(())
117    }
118
119    fn get_name(&self) -> &'static str {
120        OPTIMIZE_TABLE_INITIALIZERS_MODIFIER_NAME
121    }
122
123    fn serialize_to_properties(&self) -> darklua_core::rules::RuleProperties {
124        RuleProperties::new()
125    }
126}