dalbit_core/modifiers/
remove_redeclared_keys.rs1use darklua_core::nodes::{
2 AssignStatement, Block, Expression, FunctionCall, FunctionExpression, Identifier,
3 IndexExpression, LocalAssignStatement, ParentheseExpression, ReturnStatement, Statement,
4 StringExpression, TableEntry, TableExpression,
5};
6use darklua_core::process::{DefaultVisitor, Evaluator, LuaValue, NodeProcessor, NodeVisitor};
7use darklua_core::rules::{Context, RuleConfiguration, RuleConfigurationError, RuleProperties};
8
9use super::runtime_identifier::RuntimeIdentifierBuilder;
10use darklua_core::rules::{Rule, RuleProcessResult};
11
12#[derive(Default)]
13struct Processor {
14 evaluator: Evaluator,
15 table_identifier: String,
16 skip_next_table_exp: bool,
17}
18
19impl Processor {
20 fn skip(&mut self, active: bool) {
21 self.skip_next_table_exp = active;
22 }
23}
24
25use std::collections::HashMap;
26use std::fmt::Debug;
27
28impl NodeProcessor for Processor {
29 fn process_expression(&mut self, exp: &mut Expression) {
30 if let Expression::Table(table_exp) = exp {
31 if self.skip_next_table_exp {
32 self.skip(false);
33 return;
34 }
35 let entries = table_exp.mutate_entries();
36 let mut numeral_table = HashMap::new();
37 let mut str_table = HashMap::new();
38 let mut num_index: usize = 0;
39 let mut side_effect_stmts: Vec<Statement> = Vec::new();
40
41 for (i, entry) in entries.iter().enumerate() {
42 match entry {
43 TableEntry::Index(index_entry) => {
44 let value = self.evaluator.evaluate(index_entry.get_key());
45 match value {
46 LuaValue::Number(lua_index) => {
47 if lua_index.fract() == 0.0 && lua_index > 0.0 {
48 let key = (lua_index as usize) - 1;
49 if side_effect_stmts.is_empty() {
50 numeral_table.insert(key, i);
51 } else {
52 let assignment = AssignStatement::from_variable(
53 IndexExpression::new(
54 Identifier::new(self.table_identifier.as_str()),
55 key + 1,
56 ),
57 index_entry.get_value().clone(),
58 );
59 side_effect_stmts.push(assignment.into());
60 }
61 }
62 }
63 LuaValue::String(key) => {
64 if side_effect_stmts.is_empty() {
65 str_table.insert(key, i);
66 } else {
67 let assignment = AssignStatement::from_variable(
68 IndexExpression::new(
69 Identifier::new(self.table_identifier.as_str()),
70 StringExpression::from_value(key),
71 ),
72 index_entry.get_value().clone(),
73 );
74 side_effect_stmts.push(assignment.into());
75 }
76 }
77 LuaValue::Unknown => {
78 let assignment = AssignStatement::from_variable(
79 IndexExpression::new(
80 Identifier::new(self.table_identifier.as_str()),
81 index_entry.get_key().clone(),
82 ),
83 index_entry.get_value().clone(),
84 );
85 side_effect_stmts.push(assignment.into());
86 }
87 _ => (),
88 }
89 }
90 TableEntry::Value(_) => {
91 numeral_table.insert(num_index, i);
92 num_index += 1;
93 }
94 TableEntry::Field(field_entry) => {
95 let key = field_entry.get_field().get_name();
96 str_table.insert(key.to_owned(), i);
97 }
98 }
99 }
100
101 let mut keys: Vec<_> = numeral_table.keys().collect();
102 keys.sort();
103 let mut new_entries: Vec<TableEntry> = Vec::new();
104
105 for i in keys {
106 let v = numeral_table[i];
107 let entry = &entries[v];
108 let new_entry = match entry {
109 TableEntry::Index(index_entry) => {
110 if *i <= num_index {
111 Some(TableEntry::Value(index_entry.get_value().clone()))
112 } else {
113 Some(TableEntry::Index(index_entry.clone()))
114 }
115 }
116 TableEntry::Value(exp) => Some(TableEntry::Value(exp.clone())),
117 _ => None,
118 };
119 if let Some(new_entry) = new_entry {
120 new_entries.push(new_entry);
121 }
122 }
123
124 for (_, v) in str_table {
125 let entry = &entries[v];
126 new_entries.push(entry.clone());
127 }
128
129 entries.clear();
130 for ent in new_entries {
131 entries.push(ent);
132 }
133
134 if !side_effect_stmts.is_empty() {
135 let var = Identifier::new(self.table_identifier.as_str());
136 let table_stmt = TableExpression::new(entries.clone());
137 self.skip(true);
138 let local_assign_stmt =
139 LocalAssignStatement::new(vec![var.clone().into()], vec![table_stmt.into()]);
140 side_effect_stmts.insert(0, local_assign_stmt.into());
141 let return_stmt = ReturnStatement::one(var);
142 let func_block = Block::new(side_effect_stmts, Some(return_stmt.into()));
143 let func = Expression::Function(FunctionExpression::from_block(func_block));
144 let parenthese_func = ParentheseExpression::new(func);
145 let func_call = FunctionCall::from_prefix(parenthese_func);
146 let call_exp = Expression::Call(Box::new(func_call));
147 *exp = call_exp;
148 }
149 }
150 }
151}
152
153pub const REMOVE_REDECLARED_KEYS_RULE_NAME: &str = "remove_redeclared_keys";
154
155#[derive(Debug, PartialEq, Eq)]
157pub struct RemoveRedeclaredKeys {
158 runtime_identifier_format: String,
159}
160
161impl Default for RemoveRedeclaredKeys {
162 fn default() -> Self {
163 Self {
164 runtime_identifier_format: "_DARKLUA_REMOVE_REDECLARED_KEYS_{name}{hash}".to_string(),
165 }
166 }
167}
168
169impl Rule for RemoveRedeclaredKeys {
170 fn process(&self, block: &mut Block, _: &Context) -> RuleProcessResult {
171 let var_builder = RuntimeIdentifierBuilder::new(
172 self.runtime_identifier_format.as_str(),
173 format!("{block:?}").as_bytes(),
174 None,
175 )?;
176 let mut processor = Processor {
177 evaluator: Evaluator::default(),
178 table_identifier: var_builder.build("tbl")?,
179 skip_next_table_exp: false,
180 };
181 DefaultVisitor::visit_block(block, &mut processor);
182 Ok(())
183 }
184}
185
186impl RuleConfiguration for RemoveRedeclaredKeys {
187 fn configure(&mut self, _: RuleProperties) -> Result<(), RuleConfigurationError> {
188 Ok(())
189 }
190
191 fn get_name(&self) -> &'static str {
192 REMOVE_REDECLARED_KEYS_RULE_NAME
193 }
194
195 fn serialize_to_properties(&self) -> RuleProperties {
196 RuleProperties::new()
197 }
198}