darklua_core/rules/
no_local_function.rs1use crate::nodes::{
2 Block, FunctionExpression, LocalAssignStatement, LocalFunctionStatement, Statement,
3};
4use crate::process::{processors::FindVariables, DefaultVisitor, NodeProcessor, NodeVisitor};
5use crate::rules::{
6 Context, FlawlessRule, RuleConfiguration, RuleConfigurationError, RuleMetadata, RuleProperties,
7};
8
9use serde::ser::{Serialize, Serializer};
10use std::mem;
11
12use super::verify_no_rule_properties;
13
14struct Processor;
15
16impl Processor {
17 fn convert(&self, local_function: &mut LocalFunctionStatement) -> Statement {
18 let mut function_expression = FunctionExpression::default();
19 function_expression.set_variadic(local_function.is_variadic());
20 mem::swap(
21 function_expression.mutate_block(),
22 local_function.mutate_block(),
23 );
24 mem::swap(
25 function_expression.mutate_parameters(),
26 local_function.mutate_parameters(),
27 );
28
29 LocalAssignStatement::from_variable(local_function.get_name())
30 .with_value(function_expression)
31 .into()
32 }
33}
34
35impl NodeProcessor for Processor {
36 fn process_statement(&mut self, statement: &mut Statement) {
37 if let Statement::LocalFunction(local_function) = statement {
38 let name = local_function.get_name().to_owned();
39
40 if local_function.has_parameter(&name) {
41 let mut assign = self.convert(local_function);
42 mem::swap(statement, &mut assign)
43 } else {
44 let mut find_usage = FindVariables::new(&name);
45 DefaultVisitor::visit_block(local_function.mutate_block(), &mut find_usage);
46
47 if !find_usage.has_found_usage() {
48 let mut assign = self.convert(local_function);
49 mem::swap(statement, &mut assign)
50 }
51 }
52 };
53 }
54}
55
56pub const CONVERT_LOCAL_FUNCTION_TO_ASSIGN_RULE_NAME: &str = "convert_local_function_to_assign";
57
58#[derive(Debug, Default, PartialEq, Eq)]
60pub struct ConvertLocalFunctionToAssign {
61 metadata: RuleMetadata,
62}
63
64impl FlawlessRule for ConvertLocalFunctionToAssign {
65 fn flawless_process(&self, block: &mut Block, _: &Context) {
66 let mut processor = Processor;
67 DefaultVisitor::visit_block(block, &mut processor);
68 }
69}
70
71impl RuleConfiguration for ConvertLocalFunctionToAssign {
72 fn configure(&mut self, properties: RuleProperties) -> Result<(), RuleConfigurationError> {
73 verify_no_rule_properties(&properties)?;
74
75 Ok(())
76 }
77
78 fn get_name(&self) -> &'static str {
79 CONVERT_LOCAL_FUNCTION_TO_ASSIGN_RULE_NAME
80 }
81
82 fn serialize_to_properties(&self) -> RuleProperties {
83 RuleProperties::new()
84 }
85
86 fn set_metadata(&mut self, metadata: RuleMetadata) {
87 self.metadata = metadata;
88 }
89
90 fn metadata(&self) -> &RuleMetadata {
91 &self.metadata
92 }
93}
94
95impl Serialize for ConvertLocalFunctionToAssign {
96 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
97 serializer.serialize_str(CONVERT_LOCAL_FUNCTION_TO_ASSIGN_RULE_NAME)
98 }
99}
100
101#[cfg(test)]
102mod test {
103 use super::*;
104
105 use crate::rules::Rule;
106
107 use insta::assert_json_snapshot;
108
109 fn new_rule() -> ConvertLocalFunctionToAssign {
110 ConvertLocalFunctionToAssign::default()
111 }
112
113 #[test]
114 fn serialize_default_rule() {
115 assert_json_snapshot!(new_rule(), @r###""convert_local_function_to_assign""###);
116 }
117
118 #[test]
119 fn configure_with_extra_field_error() {
120 let result = json5::from_str::<Box<dyn Rule>>(
121 r#"{
122 rule: 'convert_local_function_to_assign',
123 prop: "something",
124 }"#,
125 );
126 insta::assert_snapshot!(result.unwrap_err().to_string(), @"unexpected field 'prop' at line 1 column 1")
127 }
128}