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, 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
62impl FlawlessRule for ConvertLocalFunctionToAssign {
63 fn flawless_process(&self, block: &mut Block, _: &Context) {
64 let mut processor = Processor;
65 DefaultVisitor::visit_block(block, &mut processor);
66 }
67}
68
69impl RuleConfiguration for ConvertLocalFunctionToAssign {
70 fn configure(&mut self, properties: RuleProperties) -> Result<(), RuleConfigurationError> {
71 verify_no_rule_properties(&properties)?;
72
73 Ok(())
74 }
75
76 fn get_name(&self) -> &'static str {
77 CONVERT_LOCAL_FUNCTION_TO_ASSIGN_RULE_NAME
78 }
79
80 fn serialize_to_properties(&self) -> RuleProperties {
81 RuleProperties::new()
82 }
83}
84
85impl Serialize for ConvertLocalFunctionToAssign {
86 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
87 serializer.serialize_str(CONVERT_LOCAL_FUNCTION_TO_ASSIGN_RULE_NAME)
88 }
89}
90
91#[cfg(test)]
92mod test {
93 use super::*;
94
95 use crate::rules::Rule;
96
97 use insta::assert_json_snapshot;
98
99 fn new_rule() -> ConvertLocalFunctionToAssign {
100 ConvertLocalFunctionToAssign::default()
101 }
102
103 #[test]
104 fn serialize_default_rule() {
105 assert_json_snapshot!("default_convert_local_function_to_assign", new_rule());
106 }
107
108 #[test]
109 fn configure_with_extra_field_error() {
110 let result = json5::from_str::<Box<dyn Rule>>(
111 r#"{
112 rule: 'convert_local_function_to_assign',
113 prop: "something",
114 }"#,
115 );
116 pretty_assertions::assert_eq!(result.unwrap_err().to_string(), "unexpected field 'prop'");
117 }
118}