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, RuleMetadata, 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_n(Expression::nil(), 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_n(Expression::nil(), 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 metadata: RuleMetadata,
106}
107
108impl FlawlessRule for GroupLocalAssignment {
109 fn flawless_process(&self, block: &mut Block, _: &Context) {
110 let mut processor = GroupLocalProcessor::default();
111 DefaultVisitor::visit_block(block, &mut processor);
112 }
113}
114
115impl RuleConfiguration for GroupLocalAssignment {
116 fn configure(&mut self, properties: RuleProperties) -> Result<(), RuleConfigurationError> {
117 verify_no_rule_properties(&properties)?;
118
119 Ok(())
120 }
121
122 fn get_name(&self) -> &'static str {
123 GROUP_LOCAL_ASSIGNMENT_RULE_NAME
124 }
125
126 fn serialize_to_properties(&self) -> RuleProperties {
127 RuleProperties::new()
128 }
129
130 fn set_metadata(&mut self, metadata: RuleMetadata) {
131 self.metadata = metadata;
132 }
133
134 fn metadata(&self) -> &RuleMetadata {
135 &self.metadata
136 }
137}
138
139#[cfg(test)]
140mod test {
141 use super::*;
142 use crate::rules::Rule;
143
144 use insta::assert_json_snapshot;
145
146 fn new_rule() -> GroupLocalAssignment {
147 GroupLocalAssignment::default()
148 }
149
150 #[test]
151 fn serialize_default_rule() {
152 let rule: Box<dyn Rule> = Box::new(new_rule());
153
154 assert_json_snapshot!(rule, @r###""group_local_assignment""###);
155 }
156}