dalbit_core/modifiers/
optimize_table_initializers.rs1use 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}