darklua_core/rules/
group_local.rs1use crate::nodes::{Block, Expression, LocalAssignStatement, Statement};
2use crate::process::processors::FindVariables;
3use crate::process::{DefaultVisitor, NodeProcessor, NodeVisitor};
4use crate::rules::{
5 Context, FlawlessRule, RuleConfiguration, RuleConfigurationError, RuleProperties,
6};
7
8use std::iter;
9
10use super::verify_no_rule_properties;
11
12#[derive(Debug, Clone, Default)]
13struct GroupLocalProcessor {}
14
15impl GroupLocalProcessor {
16 fn filter_statements(&self, block: &mut Block) -> Vec<Statement> {
17 let mut statements = block.take_statements();
18 let mut filter_statements = Vec::new();
19 let mut iter = statements.drain(..);
20 let mut previous_statement = iter.next();
21 let mut current_statement = iter.next();
22
23 while let Some(current) = current_statement {
24 previous_statement = if let Some(previous) = previous_statement {
25 use Statement::LocalAssign;
26
27 match (previous, current) {
28 (LocalAssign(mut previous), LocalAssign(mut current)) => {
29 if self.should_merge(&previous, &mut current) {
30 self.merge(&mut previous, current);
31
32 Some(LocalAssign(previous))
33 } else {
34 filter_statements.push(LocalAssign(previous));
35 Some(LocalAssign(current))
36 }
37 }
38 (previous, current) => {
39 filter_statements.push(previous);
40 Some(current)
41 }
42 }
43 } else {
44 None
45 };
46
47 current_statement = iter.next();
48 }
49
50 if let Some(previous) = previous_statement {
51 filter_statements.push(previous);
52 }
53
54 filter_statements
55 }
56
57 fn should_merge(&self, first: &LocalAssignStatement, next: &mut LocalAssignStatement) -> bool {
58 let first_value_count = first.values_len();
59
60 if first.variables_len() > first_value_count && first_value_count != 0 {
61 return false;
62 }
63
64 let mut find_variables: FindVariables = first
65 .iter_variables()
66 .map(|variable| variable.get_name().as_str())
67 .collect();
68
69 next.iter_mut_values().all(|expression| {
70 DefaultVisitor::visit_expression(expression, &mut find_variables);
71 !find_variables.has_found_usage()
72 })
73 }
74
75 fn merge(&self, first: &mut LocalAssignStatement, mut other: LocalAssignStatement) {
76 if first.values_len() == 0 && other.values_len() != 0 {
77 let variable_count = first.variables_len();
78 first.extend_values(iter::repeat(Expression::nil()).take(variable_count));
79 }
80
81 if other.values_len() == 0 && first.values_len() != 0 {
82 let variable_count = other.variables_len();
83 other.extend_values(iter::repeat(Expression::nil()).take(variable_count));
84 }
85
86 let (mut variables, mut values) = other.into_assignments();
87 first.append_variables(&mut variables);
88 first.append_values(&mut values);
89 }
90}
91
92impl NodeProcessor for GroupLocalProcessor {
93 fn process_block(&mut self, block: &mut Block) {
94 let filter_statements = self.filter_statements(block);
95
96 block.set_statements(filter_statements);
97 }
98}
99
100pub const GROUP_LOCAL_ASSIGNMENT_RULE_NAME: &str = "group_local_assignment";
101
102#[derive(Debug, Default, PartialEq, Eq)]
104pub struct GroupLocalAssignment {}
105
106impl FlawlessRule for GroupLocalAssignment {
107 fn flawless_process(&self, block: &mut Block, _: &Context) {
108 let mut processor = GroupLocalProcessor::default();
109 DefaultVisitor::visit_block(block, &mut processor);
110 }
111}
112
113impl RuleConfiguration for GroupLocalAssignment {
114 fn configure(&mut self, properties: RuleProperties) -> Result<(), RuleConfigurationError> {
115 verify_no_rule_properties(&properties)?;
116
117 Ok(())
118 }
119
120 fn get_name(&self) -> &'static str {
121 GROUP_LOCAL_ASSIGNMENT_RULE_NAME
122 }
123
124 fn serialize_to_properties(&self) -> RuleProperties {
125 RuleProperties::new()
126 }
127}
128
129#[cfg(test)]
130mod test {
131 use super::*;
132 use crate::rules::Rule;
133
134 use insta::assert_json_snapshot;
135
136 fn new_rule() -> GroupLocalAssignment {
137 GroupLocalAssignment::default()
138 }
139
140 #[test]
141 fn serialize_default_rule() {
142 let rule: Box<dyn Rule> = Box::new(new_rule());
143
144 assert_json_snapshot!("default_group_local_assignment", rule);
145 }
146}