From 10584c99316456d34ee4e7a2931df0909b6a505e Mon Sep 17 00:00:00 2001 From: jiwonz Date: Wed, 4 Sep 2024 01:08:16 +0900 Subject: [PATCH 01/17] Initial commit --- src/rules/mod.rs | 5 ++ src/rules/remove_generalized_iteration.rs | 81 +++++++++++++++++++++++ 2 files changed, 86 insertions(+) create mode 100644 src/rules/remove_generalized_iteration.rs diff --git a/src/rules/mod.rs b/src/rules/mod.rs index 35479da7..809178fa 100644 --- a/src/rules/mod.rs +++ b/src/rules/mod.rs @@ -30,6 +30,7 @@ mod rule_property; mod shift_token_line; mod unused_if_branch; mod unused_while; +mod remove_generalized_iteration; pub use append_text_comment::*; pub use call_parens::*; @@ -58,6 +59,7 @@ pub use rule_property::*; pub(crate) use shift_token_line::*; pub use unused_if_branch::*; pub use unused_while::*; +pub use remove_generalized_iteration::*; use crate::nodes::Block; use crate::Resources; @@ -214,6 +216,7 @@ pub fn get_default_rules() -> Vec> { Box::::default(), Box::::default(), Box::::default(), + Box::::default(), ] } @@ -242,6 +245,7 @@ pub fn get_all_rule_names() -> Vec<&'static str> { REMOVE_UNUSED_VARIABLE_RULE_NAME, REMOVE_UNUSED_WHILE_RULE_NAME, RENAME_VARIABLES_RULE_NAME, + REMOVE_GENERALIZED_ITERATION_RULE_NAME, ] } @@ -275,6 +279,7 @@ impl FromStr for Box { REMOVE_UNUSED_VARIABLE_RULE_NAME => Box::::default(), REMOVE_UNUSED_WHILE_RULE_NAME => Box::::default(), RENAME_VARIABLES_RULE_NAME => Box::::default(), + REMOVE_GENERALIZED_ITERATION => Box::::default(), _ => return Err(format!("invalid rule name: {}", string)), }; diff --git a/src/rules/remove_generalized_iteration.rs b/src/rules/remove_generalized_iteration.rs new file mode 100644 index 00000000..890d4308 --- /dev/null +++ b/src/rules/remove_generalized_iteration.rs @@ -0,0 +1,81 @@ +use crate::nodes::{Block, Expression, GenericForStatement, LocalAssignStatement}; +use crate::process::{DefaultVisitor, Evaluator, NodeProcessor, NodeVisitor}; +use crate::rules::{ + Context, FlawlessRule, RuleConfiguration, RuleConfigurationError, RuleProperties, +}; + +use super::verify_no_rule_properties; + +#[derive(Default)] +struct Processor {} + +impl NodeProcessor for Processor { + fn process_generic_for_statement(&mut self, generic_for: &mut crate::nodes::GenericForStatement) { + let iter_mut = generic_for.iter_mut_expressions(); + if iter_mut.count() > 1 { + return; + } + for exp in iter_mut { + + } + } +} + +pub const REMOVE_GENERALIZED_ITERATION_RULE_NAME: &str = "remove_generalized_iteration"; + +/// A rule that removes trailing `nil` in local assignments. +#[derive(Debug, Default, PartialEq, Eq)] +pub struct RemoveGeneralizedIteration {} + +impl FlawlessRule for RemoveGeneralizedIteration { + fn flawless_process(&self, block: &mut Block, _: &Context) { + let mut processor = Processor::default(); + DefaultVisitor::visit_block(block, &mut processor); + } +} + +impl RuleConfiguration for RemoveGeneralizedIteration { + fn configure(&mut self, properties: RuleProperties) -> Result<(), RuleConfigurationError> { + verify_no_rule_properties(&properties)?; + + Ok(()) + } + + fn get_name(&self) -> &'static str { + REMOVE_GENERALIZED_ITERATION_RULE_NAME + } + + fn serialize_to_properties(&self) -> RuleProperties { + RuleProperties::new() + } +} + +#[cfg(test)] +mod test { + use super::*; + use crate::rules::Rule; + + use insta::assert_json_snapshot; + + fn new_rule() -> RemoveGeneralizedIteration { + RemoveGeneralizedIteration::default() + } + + #[test] + fn serialize_default_rule() { + let rule: Box = Box::new(new_rule()); + + assert_json_snapshot!("default_remove_generalized_iteration", rule); + } + + #[test] + fn configure_with_extra_field_error() { + let result = json5::from_str::>( + r#"{ + rule: 'remove_generalized_iteration', + prop: "something", + }"#, + ); + pretty_assertions::assert_eq!(result.unwrap_err().to_string(), "unexpected field 'prop'"); + } +} From 61c76888a098317508fdfebfbaa2027f45cabe34 Mon Sep 17 00:00:00 2001 From: jiwonz Date: Fri, 27 Sep 2024 01:14:22 +0900 Subject: [PATCH 02/17] Add remove_generalized_iteration rule --- Cargo.lock | 53 ++++- Cargo.toml | 3 + src/nodes/statements/generic_for.rs | 5 + src/rules/mod.rs | 11 +- src/rules/remove_generalized_iteration.rs | 241 ++++++++++++++++++++-- 5 files changed, 284 insertions(+), 29 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ad9e24dd..8239c401 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -66,6 +66,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + [[package]] name = "arrayvec" version = "0.7.4" @@ -111,6 +117,19 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +[[package]] +name = "blake3" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d82033247fd8e890df8f740e407ad4d038debb9eb1f40533fffb32e7d17dc6f7" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if 1.0.0", + "constant_time_eq", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -171,9 +190,12 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.0.97" +version = "1.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4" +checksum = "07b1695e2c7e8fc85310cde85aeaab7e3097f593c91d209d3f9df76c928100f0" +dependencies = [ + "shlex", +] [[package]] name = "cfg-if" @@ -298,6 +320,12 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "constant_time_eq" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" + [[package]] name = "convert_case" version = "0.4.0" @@ -415,6 +443,7 @@ version = "0.13.1" dependencies = [ "anstyle", "assert_cmd", + "blake3", "clap", "criterion", "ctrlc", @@ -422,6 +451,7 @@ dependencies = [ "elsa", "env_logger", "full_moon", + "hex", "include_dir", "insta", "json5", @@ -439,6 +469,7 @@ dependencies = [ "serde_bytes", "serde_json", "serde_yaml", + "strfmt", "tempfile", "toml", "tracing", @@ -686,6 +717,12 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "humantime" version = "2.1.0" @@ -1490,6 +1527,12 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "similar" version = "2.5.0" @@ -1530,6 +1573,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "strfmt" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a8348af2d9fc3258c8733b8d9d8db2e56f54b2363a4b5b81585c7875ed65e65" + [[package]] name = "strsim" version = "0.11.1" diff --git a/Cargo.toml b/Cargo.toml index 025450b0..191d1037 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,11 +29,13 @@ stacker = ["full_moon/stacker"] [dependencies] anstyle = "1.0.6" +blake3 = "1.5.4" clap = { version = "4.5.3", features = ["derive"] } durationfmt = "0.1.1" elsa = "1.10.0" env_logger = "0.11.3" full_moon = { version = "0.19.0", features = ["roblox"] } +hex = "0.4.3" json5 = "0.4.1" log = "0.4.21" pathdiff = "0.2.1" @@ -41,6 +43,7 @@ regex = "1.10.4" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0.114" serde_yaml = "0.9.32" +strfmt = "0.2.4" toml = "0.8.11" tracing = { version = "0.1", optional = true } wax = "0.5.0" diff --git a/src/nodes/statements/generic_for.rs b/src/nodes/statements/generic_for.rs index eac78872..76027420 100644 --- a/src/nodes/statements/generic_for.rs +++ b/src/nodes/statements/generic_for.rs @@ -94,6 +94,11 @@ impl GenericForStatement { self.expressions.iter_mut() } + #[inline] + pub fn mutate_expressions(&mut self) -> &mut Vec { + &mut self.expressions + } + #[inline] pub fn mutate_block(&mut self) -> &mut Block { &mut self.block diff --git a/src/rules/mod.rs b/src/rules/mod.rs index 809178fa..278106d7 100644 --- a/src/rules/mod.rs +++ b/src/rules/mod.rs @@ -18,6 +18,7 @@ mod remove_call_match; mod remove_comments; mod remove_compound_assign; mod remove_debug_profiling; +mod remove_generalized_iteration; mod remove_interpolated_string; mod remove_nil_declarations; mod remove_spaces; @@ -27,10 +28,10 @@ mod rename_variables; mod replace_referenced_tokens; pub(crate) mod require; mod rule_property; +pub(crate) mod runtime_variable; mod shift_token_line; mod unused_if_branch; mod unused_while; -mod remove_generalized_iteration; pub use append_text_comment::*; pub use call_parens::*; @@ -48,6 +49,7 @@ pub use remove_assertions::*; pub use remove_comments::*; pub use remove_compound_assign::*; pub use remove_debug_profiling::*; +pub use remove_generalized_iteration::*; pub use remove_interpolated_string::*; pub use remove_nil_declarations::*; pub use remove_spaces::*; @@ -59,7 +61,6 @@ pub use rule_property::*; pub(crate) use shift_token_line::*; pub use unused_if_branch::*; pub use unused_while::*; -pub use remove_generalized_iteration::*; use crate::nodes::Block; use crate::Resources; @@ -216,7 +217,7 @@ pub fn get_default_rules() -> Vec> { Box::::default(), Box::::default(), Box::::default(), - Box::::default(), + Box::::default(), ] } @@ -245,7 +246,7 @@ pub fn get_all_rule_names() -> Vec<&'static str> { REMOVE_UNUSED_VARIABLE_RULE_NAME, REMOVE_UNUSED_WHILE_RULE_NAME, RENAME_VARIABLES_RULE_NAME, - REMOVE_GENERALIZED_ITERATION_RULE_NAME, + REMOVE_GENERALIZED_ITERATION_RULE_NAME, ] } @@ -279,7 +280,7 @@ impl FromStr for Box { REMOVE_UNUSED_VARIABLE_RULE_NAME => Box::::default(), REMOVE_UNUSED_WHILE_RULE_NAME => Box::::default(), RENAME_VARIABLES_RULE_NAME => Box::::default(), - REMOVE_GENERALIZED_ITERATION => Box::::default(), + REMOVE_GENERALIZED_ITERATION_RULE_NAME => Box::::default(), _ => return Err(format!("invalid rule name: {}", string)), }; diff --git a/src/rules/remove_generalized_iteration.rs b/src/rules/remove_generalized_iteration.rs index 890d4308..e4d71d72 100644 --- a/src/rules/remove_generalized_iteration.rs +++ b/src/rules/remove_generalized_iteration.rs @@ -1,42 +1,239 @@ -use crate::nodes::{Block, Expression, GenericForStatement, LocalAssignStatement}; -use crate::process::{DefaultVisitor, Evaluator, NodeProcessor, NodeVisitor}; -use crate::rules::{ - Context, FlawlessRule, RuleConfiguration, RuleConfigurationError, RuleProperties, +use crate::nodes::{ + AssignStatement, BinaryExpression, BinaryOperator, Block, DoStatement, Expression, + FieldExpression, FunctionCall, Identifier, IfBranch, IfStatement, LocalAssignStatement, Prefix, + Statement, StringExpression, TupleArguments, TypedIdentifier, Variable, }; +use crate::process::{DefaultVisitor, NodeProcessor, NodeVisitor}; +use crate::rules::{Context, RuleConfiguration, RuleConfigurationError, RuleProperties}; -use super::verify_no_rule_properties; +use super::runtime_variable::{ + RuntimeVariable, RuntimeVariableBuilder, DEFAULT_RUNTIME_VARIABLE_FORMAT, +}; +use super::{Rule, RuleProcessResult}; + +const VARIABLE_PREFIX: &str = "_DARKLUA_REMOVE_GENERALIZED_ITERATION"; +const METATABLE_VARIABLE_NAME: &str = "_m"; + +struct Processor { + iterator_variable: RuntimeVariable, + invariant_variable: RuntimeVariable, + control_variable: RuntimeVariable, + skip_block_once: bool, +} + +// impl Processor { +// fn process_generic_for<'a>(&self, block: &'a mut Block, iterator_identifier: &TypedIdentifier) -> Vec<(usize, Expression)> { +// let mut stmts: Vec<&mut Statement> = block.iter_mut_statements().collect(); +// let mut generic_for_indexes: Vec<(usize, Expression)> = Vec::new(); +// for (i, stmt) in (0..stmts.len()).zip(stmts.iter_mut()) { +// if let Statement::GenericFor(generic_for) = stmt { +// let mut exps: Vec<&mut Expression> = generic_for.iter_mut_expressions().collect(); +// if exps.len() == 1 { +// *exps[0] = Expression::Identifier(iterator_identifier.get_identifier().clone()); +// generic_for_indexes.push((i, exps[0].to_owned())); +// } +// } +// } +// generic_for_indexes +// } +// } + +fn get_type_condition(arg: Expression, type_name: &str) -> Box { + let type_call = Box::new(FunctionCall::new( + Prefix::from_name("type"), + TupleArguments::new(vec![arg]).into(), + None, + )); + Box::new(BinaryExpression::new( + BinaryOperator::Equal, + Expression::Call(type_call), + Expression::String(StringExpression::from_value(type_name)), + )) +} + +impl Processor { + fn process_into_do(&self, block: &mut Block) -> Option { + for stmt in block.iter_mut_statements() { + if let Statement::GenericFor(generic_for) = stmt { + let exps = generic_for.mutate_expressions(); + if exps.len() == 1 { + let mut stmts: Vec = Vec::new(); + let iterator_typed_identifier = + self.iterator_variable.generate_typed_identifier(); + let iterator_identifier = iterator_typed_identifier.get_identifier().clone(); + + let invariant_typed_identifier = + self.invariant_variable.generate_typed_identifier(); + let invariant_identifier = invariant_typed_identifier.get_identifier().clone(); + + let control_typed_identifier = + self.control_variable.generate_typed_identifier(); + let control_identifier = control_typed_identifier.get_identifier().clone(); + + let iterator_local_assign = LocalAssignStatement::new( + vec![ + iterator_typed_identifier, + invariant_typed_identifier, + control_typed_identifier, + ], + vec![exps[0].to_owned()], + ); + + let iterator_exp = Expression::Identifier(iterator_identifier.clone()); + exps[0] = iterator_exp.clone(); + let invariant_exp = Expression::Identifier(invariant_identifier.clone()); + exps.push(invariant_exp); + let control_exp = Expression::Identifier(control_identifier.clone()); + exps.push(control_exp); + + let if_table_condition = get_type_condition(iterator_exp.clone(), "table"); + + let mt_typed_identifier = TypedIdentifier::new(METATABLE_VARIABLE_NAME); + let mt_identifier = mt_typed_identifier.get_identifier().clone(); + + let get_mt_call = FunctionCall::new( + Prefix::from_name("getmetatable"), + TupleArguments::new(vec![iterator_exp.clone()]).into(), + None, + ); + let mt_local_assign = LocalAssignStatement::new( + vec![mt_typed_identifier], + vec![get_mt_call.into()], + ); -#[derive(Default)] -struct Processor {} + let if_mt_table_condition = + get_type_condition(mt_identifier.clone().into(), "table"); + let mt_iter = FieldExpression::new( + Prefix::Identifier(mt_identifier), + Identifier::new("__iter"), + ); + let if_mt_iter_function_condition = + get_type_condition(mt_iter.clone().into(), "function"); + + let mt_iter_call = FunctionCall::from_prefix(Prefix::Field(Box::new(mt_iter))); + let assign_from_iter = AssignStatement::new( + vec![ + Variable::Identifier(iterator_identifier.clone()), + Variable::Identifier(invariant_identifier.clone()), + Variable::Identifier(control_identifier.clone()), + ], + vec![mt_iter_call.into()], + ); + + let pairs_call = FunctionCall::new( + Prefix::from_name("pairs"), + TupleArguments::new(vec![iterator_identifier.clone().into()]).into(), + None, + ); + let assign_from_pairs = AssignStatement::new( + vec![ + Variable::Identifier(iterator_identifier), + Variable::Identifier(invariant_identifier), + Variable::Identifier(control_identifier), + ], + vec![pairs_call.into()], + ); + + let if_mt_table_block = Block::new(vec![assign_from_iter.into()], None); + let if_not_mt_table_block = Block::new(vec![assign_from_pairs.into()], None); + let if_mt_table_branch = IfBranch::new( + Expression::Binary(Box::new(BinaryExpression::new( + BinaryOperator::And, + Expression::Binary(if_mt_table_condition), + Expression::Binary(if_mt_iter_function_condition), + ))), + if_mt_table_block, + ); + let if_mt_table_stmt = + IfStatement::new(vec![if_mt_table_branch], Some(if_not_mt_table_block)); + + let if_table_block = + Block::new(vec![mt_local_assign.into(), if_mt_table_stmt.into()], None); + let if_table_branch = + IfBranch::new(Expression::Binary(if_table_condition), if_table_block); + let if_table_stmt = IfStatement::new(vec![if_table_branch], None); + + stmts.push(iterator_local_assign.into()); + stmts.push(if_table_stmt.into()); + stmts.push(generic_for.clone().into()); + + return Some(DoStatement::new(Block::new(stmts, None)).into()); + } + } + } + None + } +} impl NodeProcessor for Processor { - fn process_generic_for_statement(&mut self, generic_for: &mut crate::nodes::GenericForStatement) { - let iter_mut = generic_for.iter_mut_expressions(); - if iter_mut.count() > 1 { - return; - } - for exp in iter_mut { - - } - } + fn process_block(&mut self, block: &mut Block) { + // let iterator_identifier = TypedIdentifier::new(&self.iterator_variable_name); + // let generic_for_indexes = self.process_generic_for(block, &iterator_identifier); + // for (i, input_exp) in generic_for_indexes.iter() { + // let iterator_local_assign = LocalAssignStatement::new( + // vec![iterator_identifier.clone()], + // vec![input_exp.to_owned()] + // ); + // block.insert_statement(*i, Statement::LocalAssign(iterator_local_assign.into())); + // } + if self.skip_block_once { + self.skip_block_once = false; + return; + } + let do_stmt = self.process_into_do(block); + if let Some(stmt) = do_stmt { + self.skip_block_once = true; + block.clear(); + block.insert_statement(0, stmt); + } + } } pub const REMOVE_GENERALIZED_ITERATION_RULE_NAME: &str = "remove_generalized_iteration"; /// A rule that removes trailing `nil` in local assignments. -#[derive(Debug, Default, PartialEq, Eq)] -pub struct RemoveGeneralizedIteration {} +#[derive(Debug, PartialEq, Eq)] +pub struct RemoveGeneralizedIteration { + runtime_variable_format: String, +} -impl FlawlessRule for RemoveGeneralizedIteration { - fn flawless_process(&self, block: &mut Block, _: &Context) { - let mut processor = Processor::default(); +impl Default for RemoveGeneralizedIteration { + fn default() -> Self { + Self { + runtime_variable_format: DEFAULT_RUNTIME_VARIABLE_FORMAT.to_string(), + } + } +} + +impl Rule for RemoveGeneralizedIteration { + fn process(&self, block: &mut Block, _: &Context) -> RuleProcessResult { + let var_builder = RuntimeVariableBuilder::new( + VARIABLE_PREFIX, + self.runtime_variable_format.as_str(), + format!("{block:?}").as_bytes(), + Some(vec![METATABLE_VARIABLE_NAME.to_string()]), + ); + let mut processor = Processor { + iterator_variable: var_builder.build("iter")?, + invariant_variable: var_builder.build("invar")?, + control_variable: var_builder.build("control")?, + skip_block_once: false, + }; DefaultVisitor::visit_block(block, &mut processor); + Ok(()) } } impl RuleConfiguration for RemoveGeneralizedIteration { fn configure(&mut self, properties: RuleProperties) -> Result<(), RuleConfigurationError> { - verify_no_rule_properties(&properties)?; + for (key, value) in properties { + match key.as_str() { + "runtime_variable_format" => { + self.runtime_variable_format = value.expect_string(&key)?; + } + _ => return Err(RuleConfigurationError::UnexpectedProperty(key)), + } + } Ok(()) } From 62380c1ba1fe37f769c7e68a2159c4d9a2e1f338 Mon Sep 17 00:00:00 2001 From: jiwonz Date: Fri, 27 Sep 2024 01:14:38 +0900 Subject: [PATCH 03/17] Add RuntimeVariable --- src/rules/runtime_variable.rs | 78 +++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 src/rules/runtime_variable.rs diff --git a/src/rules/runtime_variable.rs b/src/rules/runtime_variable.rs new file mode 100644 index 00000000..3b84966e --- /dev/null +++ b/src/rules/runtime_variable.rs @@ -0,0 +1,78 @@ +use blake3; +use hex; +use std::collections::HashMap; +use strfmt::strfmt; + +// use crate::nodes::{ +// AssignStatement, Expression, Identifier, LocalAssignStatement, TypedIdentifier, +// }; +use crate::nodes::TypedIdentifier; + +pub const DEFAULT_RUNTIME_VARIABLE_FORMAT: &str = "{prefix}_{name}{hash}"; + +pub struct RuntimeVariable { + name: String, +} + +impl RuntimeVariable { + pub fn generate_typed_identifier(&self) -> TypedIdentifier { + TypedIdentifier::new(&self.name) + } + + // pub fn generate_identifier(&self) -> Identifier { + // Identifier::new(&self.name) + // } + + // pub fn generate_local_assignment(&self, value: Option) -> LocalAssignStatement { + // if let Some(value) = value { + // LocalAssignStatement::new(vec![self.generate_typed_identifier()], vec![value]) + // } else { + // LocalAssignStatement::from_variable(self.generate_identifier()) + // } + // } + + // pub fn generate_assignment(&self, value: Expression) -> AssignStatement { + // AssignStatement::new(vec![self.generate_identifier().into()], vec![value]) + // } +} + +pub struct RuntimeVariableBuilder { + prefix: String, + format: String, + hash: String, + keywords: Option>, +} + +impl RuntimeVariableBuilder { + pub fn new( + prefix: impl Into, + format: impl Into, + identifier: &[u8], + keywords: Option>, + ) -> Self { + let hash = blake3::hash(identifier); + Self { + prefix: prefix.into(), + format: format.into(), + hash: hex::encode(&hash.as_bytes()[..8]), + keywords, + } + } + + pub fn build(&self, name: &str) -> Result { + let mut vars = HashMap::new(); + vars.insert("prefix".to_string(), self.prefix.as_str()); + vars.insert("name".to_string(), name); + vars.insert("hash".to_string(), self.hash.as_str()); + + let name = strfmt(&self.format, &vars).map_err(|err| err.to_string())?; + + if let Some(keywords) = &self.keywords { + if keywords.contains(&name) { + Err(format!("Runtime variable `{name}` cannot be set because it contains a reserved keyword."))?; + } + } + + Ok(RuntimeVariable { name }) + } +} From c7eda0cb76e2aac4b7bff8b82df55e81b13dc364 Mon Sep 17 00:00:00 2001 From: jiwonz Date: Fri, 27 Sep 2024 01:16:43 +0900 Subject: [PATCH 04/17] Remove commented codes and fix docs comment --- src/rules/remove_generalized_iteration.rs | 28 +---------------------- 1 file changed, 1 insertion(+), 27 deletions(-) diff --git a/src/rules/remove_generalized_iteration.rs b/src/rules/remove_generalized_iteration.rs index e4d71d72..59139ad4 100644 --- a/src/rules/remove_generalized_iteration.rs +++ b/src/rules/remove_generalized_iteration.rs @@ -21,23 +21,6 @@ struct Processor { skip_block_once: bool, } -// impl Processor { -// fn process_generic_for<'a>(&self, block: &'a mut Block, iterator_identifier: &TypedIdentifier) -> Vec<(usize, Expression)> { -// let mut stmts: Vec<&mut Statement> = block.iter_mut_statements().collect(); -// let mut generic_for_indexes: Vec<(usize, Expression)> = Vec::new(); -// for (i, stmt) in (0..stmts.len()).zip(stmts.iter_mut()) { -// if let Statement::GenericFor(generic_for) = stmt { -// let mut exps: Vec<&mut Expression> = generic_for.iter_mut_expressions().collect(); -// if exps.len() == 1 { -// *exps[0] = Expression::Identifier(iterator_identifier.get_identifier().clone()); -// generic_for_indexes.push((i, exps[0].to_owned())); -// } -// } -// } -// generic_for_indexes -// } -// } - fn get_type_condition(arg: Expression, type_name: &str) -> Box { let type_call = Box::new(FunctionCall::new( Prefix::from_name("type"), @@ -167,15 +150,6 @@ impl Processor { impl NodeProcessor for Processor { fn process_block(&mut self, block: &mut Block) { - // let iterator_identifier = TypedIdentifier::new(&self.iterator_variable_name); - // let generic_for_indexes = self.process_generic_for(block, &iterator_identifier); - // for (i, input_exp) in generic_for_indexes.iter() { - // let iterator_local_assign = LocalAssignStatement::new( - // vec![iterator_identifier.clone()], - // vec![input_exp.to_owned()] - // ); - // block.insert_statement(*i, Statement::LocalAssign(iterator_local_assign.into())); - // } if self.skip_block_once { self.skip_block_once = false; return; @@ -191,7 +165,7 @@ impl NodeProcessor for Processor { pub const REMOVE_GENERALIZED_ITERATION_RULE_NAME: &str = "remove_generalized_iteration"; -/// A rule that removes trailing `nil` in local assignments. +/// A rule that removes generalized iteration. #[derive(Debug, PartialEq, Eq)] pub struct RemoveGeneralizedIteration { runtime_variable_format: String, From 668f0d8a9ad992cb43e6c0ed83d67361cf5ffb6f Mon Sep 17 00:00:00 2001 From: jiwonz Date: Fri, 27 Sep 2024 11:50:53 +0900 Subject: [PATCH 05/17] Fix runtime variable --- src/rules/remove_generalized_iteration.rs | 20 ++++++------- src/rules/runtime_variable.rs | 35 ++--------------------- 2 files changed, 12 insertions(+), 43 deletions(-) diff --git a/src/rules/remove_generalized_iteration.rs b/src/rules/remove_generalized_iteration.rs index 59139ad4..e4c770d8 100644 --- a/src/rules/remove_generalized_iteration.rs +++ b/src/rules/remove_generalized_iteration.rs @@ -7,7 +7,7 @@ use crate::process::{DefaultVisitor, NodeProcessor, NodeVisitor}; use crate::rules::{Context, RuleConfiguration, RuleConfigurationError, RuleProperties}; use super::runtime_variable::{ - RuntimeVariable, RuntimeVariableBuilder, DEFAULT_RUNTIME_VARIABLE_FORMAT, + RuntimeVariableBuilder, DEFAULT_RUNTIME_VARIABLE_FORMAT, }; use super::{Rule, RuleProcessResult}; @@ -15,9 +15,9 @@ const VARIABLE_PREFIX: &str = "_DARKLUA_REMOVE_GENERALIZED_ITERATION"; const METATABLE_VARIABLE_NAME: &str = "_m"; struct Processor { - iterator_variable: RuntimeVariable, - invariant_variable: RuntimeVariable, - control_variable: RuntimeVariable, + iterator_variable_name: String, + invariant_variable_name: String, + control_variable_name: String, skip_block_once: bool, } @@ -42,15 +42,15 @@ impl Processor { if exps.len() == 1 { let mut stmts: Vec = Vec::new(); let iterator_typed_identifier = - self.iterator_variable.generate_typed_identifier(); + TypedIdentifier::new(self.iterator_variable_name.as_str()); let iterator_identifier = iterator_typed_identifier.get_identifier().clone(); let invariant_typed_identifier = - self.invariant_variable.generate_typed_identifier(); + TypedIdentifier::new(self.invariant_variable_name.as_str()); let invariant_identifier = invariant_typed_identifier.get_identifier().clone(); let control_typed_identifier = - self.control_variable.generate_typed_identifier(); + TypedIdentifier::new(self.control_variable_name.as_str()); let control_identifier = control_typed_identifier.get_identifier().clone(); let iterator_local_assign = LocalAssignStatement::new( @@ -188,9 +188,9 @@ impl Rule for RemoveGeneralizedIteration { Some(vec![METATABLE_VARIABLE_NAME.to_string()]), ); let mut processor = Processor { - iterator_variable: var_builder.build("iter")?, - invariant_variable: var_builder.build("invar")?, - control_variable: var_builder.build("control")?, + iterator_variable_name: var_builder.build("iter")?, + invariant_variable_name: var_builder.build("invar")?, + control_variable_name: var_builder.build("control")?, skip_block_once: false, }; DefaultVisitor::visit_block(block, &mut processor); diff --git a/src/rules/runtime_variable.rs b/src/rules/runtime_variable.rs index 3b84966e..055f9114 100644 --- a/src/rules/runtime_variable.rs +++ b/src/rules/runtime_variable.rs @@ -3,39 +3,8 @@ use hex; use std::collections::HashMap; use strfmt::strfmt; -// use crate::nodes::{ -// AssignStatement, Expression, Identifier, LocalAssignStatement, TypedIdentifier, -// }; -use crate::nodes::TypedIdentifier; - pub const DEFAULT_RUNTIME_VARIABLE_FORMAT: &str = "{prefix}_{name}{hash}"; -pub struct RuntimeVariable { - name: String, -} - -impl RuntimeVariable { - pub fn generate_typed_identifier(&self) -> TypedIdentifier { - TypedIdentifier::new(&self.name) - } - - // pub fn generate_identifier(&self) -> Identifier { - // Identifier::new(&self.name) - // } - - // pub fn generate_local_assignment(&self, value: Option) -> LocalAssignStatement { - // if let Some(value) = value { - // LocalAssignStatement::new(vec![self.generate_typed_identifier()], vec![value]) - // } else { - // LocalAssignStatement::from_variable(self.generate_identifier()) - // } - // } - - // pub fn generate_assignment(&self, value: Expression) -> AssignStatement { - // AssignStatement::new(vec![self.generate_identifier().into()], vec![value]) - // } -} - pub struct RuntimeVariableBuilder { prefix: String, format: String, @@ -59,7 +28,7 @@ impl RuntimeVariableBuilder { } } - pub fn build(&self, name: &str) -> Result { + pub fn build(&self, name: &str) -> Result { let mut vars = HashMap::new(); vars.insert("prefix".to_string(), self.prefix.as_str()); vars.insert("name".to_string(), name); @@ -73,6 +42,6 @@ impl RuntimeVariableBuilder { } } - Ok(RuntimeVariable { name }) + Ok(name) } } From 0486cbe43b585b42c82e0265ad12cc15d96e946d Mon Sep 17 00:00:00 2001 From: jiwonz Date: Fri, 27 Sep 2024 12:10:26 +0900 Subject: [PATCH 06/17] Update runtime variable --- src/rules/remove_generalized_iteration.rs | 4 +--- src/rules/runtime_variable.rs | 6 +----- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/rules/remove_generalized_iteration.rs b/src/rules/remove_generalized_iteration.rs index e4c770d8..3aefa9a7 100644 --- a/src/rules/remove_generalized_iteration.rs +++ b/src/rules/remove_generalized_iteration.rs @@ -11,7 +11,6 @@ use super::runtime_variable::{ }; use super::{Rule, RuleProcessResult}; -const VARIABLE_PREFIX: &str = "_DARKLUA_REMOVE_GENERALIZED_ITERATION"; const METATABLE_VARIABLE_NAME: &str = "_m"; struct Processor { @@ -174,7 +173,7 @@ pub struct RemoveGeneralizedIteration { impl Default for RemoveGeneralizedIteration { fn default() -> Self { Self { - runtime_variable_format: DEFAULT_RUNTIME_VARIABLE_FORMAT.to_string(), + runtime_variable_format: "_DARKLUA_REMOVE_GENERALIZED_ITERATION_{name}{hash}".to_string(), } } } @@ -182,7 +181,6 @@ impl Default for RemoveGeneralizedIteration { impl Rule for RemoveGeneralizedIteration { fn process(&self, block: &mut Block, _: &Context) -> RuleProcessResult { let var_builder = RuntimeVariableBuilder::new( - VARIABLE_PREFIX, self.runtime_variable_format.as_str(), format!("{block:?}").as_bytes(), Some(vec![METATABLE_VARIABLE_NAME.to_string()]), diff --git a/src/rules/runtime_variable.rs b/src/rules/runtime_variable.rs index 055f9114..73d19cc9 100644 --- a/src/rules/runtime_variable.rs +++ b/src/rules/runtime_variable.rs @@ -3,10 +3,9 @@ use hex; use std::collections::HashMap; use strfmt::strfmt; -pub const DEFAULT_RUNTIME_VARIABLE_FORMAT: &str = "{prefix}_{name}{hash}"; +pub const DEFAULT_RUNTIME_VARIABLE_FORMAT: &str = "{name}{hash}"; pub struct RuntimeVariableBuilder { - prefix: String, format: String, hash: String, keywords: Option>, @@ -14,14 +13,12 @@ pub struct RuntimeVariableBuilder { impl RuntimeVariableBuilder { pub fn new( - prefix: impl Into, format: impl Into, identifier: &[u8], keywords: Option>, ) -> Self { let hash = blake3::hash(identifier); Self { - prefix: prefix.into(), format: format.into(), hash: hex::encode(&hash.as_bytes()[..8]), keywords, @@ -30,7 +27,6 @@ impl RuntimeVariableBuilder { pub fn build(&self, name: &str) -> Result { let mut vars = HashMap::new(); - vars.insert("prefix".to_string(), self.prefix.as_str()); vars.insert("name".to_string(), name); vars.insert("hash".to_string(), self.hash.as_str()); From 7b6753d64867dfa4c51e6705b984bb5225b61603 Mon Sep 17 00:00:00 2001 From: jiwonz Date: Fri, 27 Sep 2024 12:25:15 +0900 Subject: [PATCH 07/17] cargo fmt and fix runtime variable --- src/rules/remove_generalized_iteration.rs | 7 +++---- src/rules/runtime_variable.rs | 2 -- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/rules/remove_generalized_iteration.rs b/src/rules/remove_generalized_iteration.rs index 3aefa9a7..f27da228 100644 --- a/src/rules/remove_generalized_iteration.rs +++ b/src/rules/remove_generalized_iteration.rs @@ -6,9 +6,7 @@ use crate::nodes::{ use crate::process::{DefaultVisitor, NodeProcessor, NodeVisitor}; use crate::rules::{Context, RuleConfiguration, RuleConfigurationError, RuleProperties}; -use super::runtime_variable::{ - RuntimeVariableBuilder, DEFAULT_RUNTIME_VARIABLE_FORMAT, -}; +use super::runtime_variable::RuntimeVariableBuilder; use super::{Rule, RuleProcessResult}; const METATABLE_VARIABLE_NAME: &str = "_m"; @@ -173,7 +171,8 @@ pub struct RemoveGeneralizedIteration { impl Default for RemoveGeneralizedIteration { fn default() -> Self { Self { - runtime_variable_format: "_DARKLUA_REMOVE_GENERALIZED_ITERATION_{name}{hash}".to_string(), + runtime_variable_format: "_DARKLUA_REMOVE_GENERALIZED_ITERATION_{name}{hash}" + .to_string(), } } } diff --git a/src/rules/runtime_variable.rs b/src/rules/runtime_variable.rs index 73d19cc9..cb0dcf43 100644 --- a/src/rules/runtime_variable.rs +++ b/src/rules/runtime_variable.rs @@ -3,8 +3,6 @@ use hex; use std::collections::HashMap; use strfmt::strfmt; -pub const DEFAULT_RUNTIME_VARIABLE_FORMAT: &str = "{name}{hash}"; - pub struct RuntimeVariableBuilder { format: String, hash: String, From 7eb420d6ff90d88a22aaaddb3c44d598f92ff658 Mon Sep 17 00:00:00 2001 From: jiwonz Date: Fri, 27 Sep 2024 13:49:27 +0900 Subject: [PATCH 08/17] Add tests --- src/rules/remove_generalized_iteration.rs | 1 + ..._default_remove_generalized_iteration.snap | 5 ++++ ...lua_core__rules__test__all_rule_names.snap | 3 ++- ...klua_core__rules__test__default_rules.snap | 3 ++- tests/rule_tests/mod.rs | 1 + .../remove_generalized_iteration.rs | 24 +++++++++++++++++++ 6 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 src/rules/snapshots/darklua_core__rules__remove_generalized_iteration__test__default_remove_generalized_iteration.snap create mode 100644 tests/rule_tests/remove_generalized_iteration.rs diff --git a/src/rules/remove_generalized_iteration.rs b/src/rules/remove_generalized_iteration.rs index f27da228..0ff3fa67 100644 --- a/src/rules/remove_generalized_iteration.rs +++ b/src/rules/remove_generalized_iteration.rs @@ -241,6 +241,7 @@ mod test { let result = json5::from_str::>( r#"{ rule: 'remove_generalized_iteration', + runtime_variable_format: '{name}', prop: "something", }"#, ); diff --git a/src/rules/snapshots/darklua_core__rules__remove_generalized_iteration__test__default_remove_generalized_iteration.snap b/src/rules/snapshots/darklua_core__rules__remove_generalized_iteration__test__default_remove_generalized_iteration.snap new file mode 100644 index 00000000..6926519f --- /dev/null +++ b/src/rules/snapshots/darklua_core__rules__remove_generalized_iteration__test__default_remove_generalized_iteration.snap @@ -0,0 +1,5 @@ +--- +source: src/rules/remove_generalized_iteration.rs +expression: rule +--- +"remove_generalized_iteration" diff --git a/src/rules/snapshots/darklua_core__rules__test__all_rule_names.snap b/src/rules/snapshots/darklua_core__rules__test__all_rule_names.snap index 15321a21..9c0812eb 100644 --- a/src/rules/snapshots/darklua_core__rules__test__all_rule_names.snap +++ b/src/rules/snapshots/darklua_core__rules__test__all_rule_names.snap @@ -25,5 +25,6 @@ expression: rule_names "remove_unused_if_branch", "remove_unused_variable", "remove_unused_while", - "rename_variables" + "rename_variables", + "remove_generalized_iteration" ] diff --git a/src/rules/snapshots/darklua_core__rules__test__default_rules.snap b/src/rules/snapshots/darklua_core__rules__test__default_rules.snap index d87f8de3..df034bb0 100644 --- a/src/rules/snapshots/darklua_core__rules__test__default_rules.snap +++ b/src/rules/snapshots/darklua_core__rules__test__default_rules.snap @@ -15,5 +15,6 @@ expression: rules "convert_index_to_field", "remove_nil_declaration", "rename_variables", - "remove_function_call_parens" + "remove_function_call_parens", + "remove_generalized_iteration" ] diff --git a/tests/rule_tests/mod.rs b/tests/rule_tests/mod.rs index 35ef77f3..50b56d95 100644 --- a/tests/rule_tests/mod.rs +++ b/tests/rule_tests/mod.rs @@ -312,3 +312,4 @@ mod remove_unused_if_branch; mod remove_unused_variable; mod remove_unused_while; mod rename_variables; +mod remove_generalized_iteration; diff --git a/tests/rule_tests/remove_generalized_iteration.rs b/tests/rule_tests/remove_generalized_iteration.rs new file mode 100644 index 00000000..0f901e88 --- /dev/null +++ b/tests/rule_tests/remove_generalized_iteration.rs @@ -0,0 +1,24 @@ +use darklua_core::rules::Rule; + +test_rule!( + remove_generalized_iteration, + json5::from_str::>( + r#"{ + rule: 'remove_generalized_iteration', + runtime_variable_format: '{name}' + }"# + ).unwrap(), + generic_for("for i,v in {1,2,3} do end") + => "do local iter,invar,control={1,2,3} if type(iter)=='table' then local _m=getmetatable(iter) if type(_m)=='table' and type(_m.__iter)=='function' then iter,invar,control=_m.__iter() else iter,invar,control=pairs(iter) end end for i,v in iter,invar,control do end end" +); + +#[test] +fn deserialize_from_object_notation() { + json5::from_str::>( + r#"{ + rule: 'remove_generalized_iteration', + runtime_variable_format: '{name}' + }"#, + ) + .unwrap(); +} From 8f524f5315469303eacb087e4f3437c851652240 Mon Sep 17 00:00:00 2001 From: jiwonz Date: Fri, 27 Sep 2024 16:45:19 +0900 Subject: [PATCH 09/17] runtime variable checks 'name' field now --- src/rules/remove_generalized_iteration.rs | 12 +++++++++--- src/rules/runtime_variable.rs | 12 ++++++++---- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/rules/remove_generalized_iteration.rs b/src/rules/remove_generalized_iteration.rs index 0ff3fa67..5dbf1237 100644 --- a/src/rules/remove_generalized_iteration.rs +++ b/src/rules/remove_generalized_iteration.rs @@ -53,11 +53,16 @@ impl Processor { let iterator_local_assign = LocalAssignStatement::new( vec![ iterator_typed_identifier, - invariant_typed_identifier, - control_typed_identifier, ], vec![exps[0].to_owned()], ); + let invar_control_local_assign = LocalAssignStatement::new( + vec![ + invariant_typed_identifier, + control_typed_identifier, + ], + Vec::new() + ); let iterator_exp = Expression::Identifier(iterator_identifier.clone()); exps[0] = iterator_exp.clone(); @@ -134,6 +139,7 @@ impl Processor { let if_table_stmt = IfStatement::new(vec![if_table_branch], None); stmts.push(iterator_local_assign.into()); + stmts.push(invar_control_local_assign.into()); stmts.push(if_table_stmt.into()); stmts.push(generic_for.clone().into()); @@ -183,7 +189,7 @@ impl Rule for RemoveGeneralizedIteration { self.runtime_variable_format.as_str(), format!("{block:?}").as_bytes(), Some(vec![METATABLE_VARIABLE_NAME.to_string()]), - ); + )?; let mut processor = Processor { iterator_variable_name: var_builder.build("iter")?, invariant_variable_name: var_builder.build("invar")?, diff --git a/src/rules/runtime_variable.rs b/src/rules/runtime_variable.rs index cb0dcf43..f1782fa2 100644 --- a/src/rules/runtime_variable.rs +++ b/src/rules/runtime_variable.rs @@ -14,13 +14,17 @@ impl RuntimeVariableBuilder { format: impl Into, identifier: &[u8], keywords: Option>, - ) -> Self { + ) -> Result { + let format: String = format.into(); + if !format.as_str().contains("{name}") { + return Err("`name` field is required for runtime variable".to_string()) + } let hash = blake3::hash(identifier); - Self { - format: format.into(), + Ok(Self { + format, hash: hex::encode(&hash.as_bytes()[..8]), keywords, - } + }) } pub fn build(&self, name: &str) -> Result { From 5add45885597bcc555d8bdbbfb9da475c04cd35a Mon Sep 17 00:00:00 2001 From: jiwonz Date: Fri, 27 Sep 2024 16:46:22 +0900 Subject: [PATCH 10/17] Fix indentation --- src/rules/remove_generalized_iteration.rs | 16 ++++++++-------- src/rules/runtime_variable.rs | 8 ++++---- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/rules/remove_generalized_iteration.rs b/src/rules/remove_generalized_iteration.rs index 5dbf1237..509e53a5 100644 --- a/src/rules/remove_generalized_iteration.rs +++ b/src/rules/remove_generalized_iteration.rs @@ -56,13 +56,13 @@ impl Processor { ], vec![exps[0].to_owned()], ); - let invar_control_local_assign = LocalAssignStatement::new( - vec![ - invariant_typed_identifier, + let invar_control_local_assign = LocalAssignStatement::new( + vec![ + invariant_typed_identifier, control_typed_identifier, - ], - Vec::new() - ); + ], + Vec::new() + ); let iterator_exp = Expression::Identifier(iterator_identifier.clone()); exps[0] = iterator_exp.clone(); @@ -139,7 +139,7 @@ impl Processor { let if_table_stmt = IfStatement::new(vec![if_table_branch], None); stmts.push(iterator_local_assign.into()); - stmts.push(invar_control_local_assign.into()); + stmts.push(invar_control_local_assign.into()); stmts.push(if_table_stmt.into()); stmts.push(generic_for.clone().into()); @@ -247,7 +247,7 @@ mod test { let result = json5::from_str::>( r#"{ rule: 'remove_generalized_iteration', - runtime_variable_format: '{name}', + runtime_variable_format: '{name}', prop: "something", }"#, ); diff --git a/src/rules/runtime_variable.rs b/src/rules/runtime_variable.rs index f1782fa2..470661ae 100644 --- a/src/rules/runtime_variable.rs +++ b/src/rules/runtime_variable.rs @@ -15,10 +15,10 @@ impl RuntimeVariableBuilder { identifier: &[u8], keywords: Option>, ) -> Result { - let format: String = format.into(); - if !format.as_str().contains("{name}") { - return Err("`name` field is required for runtime variable".to_string()) - } + let format: String = format.into(); + if !format.as_str().contains("{name}") { + return Err("`name` field is required for runtime variable".to_string()) + } let hash = blake3::hash(identifier); Ok(Self { format, From 0bd6748056855217ebd396e4a9d3fd6795bc8f55 Mon Sep 17 00:00:00 2001 From: jiwonz Date: Fri, 27 Sep 2024 16:46:40 +0900 Subject: [PATCH 11/17] cargo fmt --- src/rules/remove_generalized_iteration.rs | 11 +++-------- src/rules/runtime_variable.rs | 2 +- tests/rule_tests/mod.rs | 2 +- tests/rule_tests/remove_generalized_iteration.rs | 4 ++-- 4 files changed, 7 insertions(+), 12 deletions(-) diff --git a/src/rules/remove_generalized_iteration.rs b/src/rules/remove_generalized_iteration.rs index 509e53a5..7bb86ca4 100644 --- a/src/rules/remove_generalized_iteration.rs +++ b/src/rules/remove_generalized_iteration.rs @@ -51,17 +51,12 @@ impl Processor { let control_identifier = control_typed_identifier.get_identifier().clone(); let iterator_local_assign = LocalAssignStatement::new( - vec![ - iterator_typed_identifier, - ], + vec![iterator_typed_identifier], vec![exps[0].to_owned()], ); let invar_control_local_assign = LocalAssignStatement::new( - vec![ - invariant_typed_identifier, - control_typed_identifier, - ], - Vec::new() + vec![invariant_typed_identifier, control_typed_identifier], + Vec::new(), ); let iterator_exp = Expression::Identifier(iterator_identifier.clone()); diff --git a/src/rules/runtime_variable.rs b/src/rules/runtime_variable.rs index 470661ae..5b0c3422 100644 --- a/src/rules/runtime_variable.rs +++ b/src/rules/runtime_variable.rs @@ -17,7 +17,7 @@ impl RuntimeVariableBuilder { ) -> Result { let format: String = format.into(); if !format.as_str().contains("{name}") { - return Err("`name` field is required for runtime variable".to_string()) + return Err("`name` field is required for runtime variable".to_string()); } let hash = blake3::hash(identifier); Ok(Self { diff --git a/tests/rule_tests/mod.rs b/tests/rule_tests/mod.rs index 50b56d95..204e0797 100644 --- a/tests/rule_tests/mod.rs +++ b/tests/rule_tests/mod.rs @@ -304,6 +304,7 @@ mod remove_comments; mod remove_compound_assignment; mod remove_debug_profiling; mod remove_empty_do; +mod remove_generalized_iteration; mod remove_interpolated_string; mod remove_method_definition; mod remove_nil_declaration; @@ -312,4 +313,3 @@ mod remove_unused_if_branch; mod remove_unused_variable; mod remove_unused_while; mod rename_variables; -mod remove_generalized_iteration; diff --git a/tests/rule_tests/remove_generalized_iteration.rs b/tests/rule_tests/remove_generalized_iteration.rs index 0f901e88..9a8c710b 100644 --- a/tests/rule_tests/remove_generalized_iteration.rs +++ b/tests/rule_tests/remove_generalized_iteration.rs @@ -8,8 +8,8 @@ test_rule!( runtime_variable_format: '{name}' }"# ).unwrap(), - generic_for("for i,v in {1,2,3} do end") - => "do local iter,invar,control={1,2,3} if type(iter)=='table' then local _m=getmetatable(iter) if type(_m)=='table' and type(_m.__iter)=='function' then iter,invar,control=_m.__iter() else iter,invar,control=pairs(iter) end end for i,v in iter,invar,control do end end" + generic_for("for i,v in {1,2,3} do end") + => "do local iter,invar,control={1,2,3} if type(iter)=='table' then local _m=getmetatable(iter) if type(_m)=='table' and type(_m.__iter)=='function' then iter,invar,control=_m.__iter() else iter,invar,control=pairs(iter) end end for i,v in iter,invar,control do end end" ); #[test] From ff660504ba816da3a4c8e8d52ec5799a203da049 Mon Sep 17 00:00:00 2001 From: jiwonz Date: Fri, 27 Sep 2024 21:36:21 +0900 Subject: [PATCH 12/17] Fix critical bug and block.mutate_statements() added --- src/nodes/block.rs | 5 +++++ src/rules/remove_generalized_iteration.rs | 14 ++++++++------ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/nodes/block.rs b/src/nodes/block.rs index 6306c331..6ae4509c 100644 --- a/src/nodes/block.rs +++ b/src/nodes/block.rs @@ -167,6 +167,11 @@ impl Block { self.statements.iter_mut() } + #[inline] + pub fn mutate_statements(&mut self) -> &mut Vec { + &mut self.statements + } + #[inline] pub fn first_statement(&self) -> Option<&Statement> { self.statements.first() diff --git a/src/rules/remove_generalized_iteration.rs b/src/rules/remove_generalized_iteration.rs index 7bb86ca4..09544fd4 100644 --- a/src/rules/remove_generalized_iteration.rs +++ b/src/rules/remove_generalized_iteration.rs @@ -32,8 +32,9 @@ fn get_type_condition(arg: Expression, type_name: &str) -> Box } impl Processor { - fn process_into_do(&self, block: &mut Block) -> Option { - for stmt in block.iter_mut_statements() { + fn process_into_do(&self, block: &mut Block) -> Option<(usize, Statement)> { + let block_stmts = block.mutate_statements(); + for (i, stmt) in block_stmts.iter_mut().enumerate() { if let Statement::GenericFor(generic_for) = stmt { let exps = generic_for.mutate_expressions(); if exps.len() == 1 { @@ -138,7 +139,9 @@ impl Processor { stmts.push(if_table_stmt.into()); stmts.push(generic_for.clone().into()); - return Some(DoStatement::new(Block::new(stmts, None)).into()); + block_stmts.remove(i); + + return Some((i, DoStatement::new(Block::new(stmts, None)).into())); } } } @@ -153,10 +156,9 @@ impl NodeProcessor for Processor { return; } let do_stmt = self.process_into_do(block); - if let Some(stmt) = do_stmt { + if let Some((i, stmt)) = do_stmt { self.skip_block_once = true; - block.clear(); - block.insert_statement(0, stmt); + block.insert_statement(i, stmt); } } } From 50ed9ef62452de048348eda0b96d2332439e8a2f Mon Sep 17 00:00:00 2001 From: jiwonz Date: Fri, 27 Sep 2024 21:41:03 +0900 Subject: [PATCH 13/17] Fix test --- tests/rule_tests/remove_generalized_iteration.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/rule_tests/remove_generalized_iteration.rs b/tests/rule_tests/remove_generalized_iteration.rs index 9a8c710b..a97aee90 100644 --- a/tests/rule_tests/remove_generalized_iteration.rs +++ b/tests/rule_tests/remove_generalized_iteration.rs @@ -9,7 +9,7 @@ test_rule!( }"# ).unwrap(), generic_for("for i,v in {1,2,3} do end") - => "do local iter,invar,control={1,2,3} if type(iter)=='table' then local _m=getmetatable(iter) if type(_m)=='table' and type(_m.__iter)=='function' then iter,invar,control=_m.__iter() else iter,invar,control=pairs(iter) end end for i,v in iter,invar,control do end end" + => "do local iter={1,2,3} local invar,control if type(iter)=='table' then local _m=getmetatable(iter) if type(_m)=='table' and type(_m.__iter)=='function' then iter,invar,control=_m.__iter() else iter,invar,control=pairs(iter) end end for i,v in iter,invar,control do end end" ); #[test] From 548c13bd21898bb263e88c485d554456032b2e08 Mon Sep 17 00:00:00 2001 From: jiwonz Date: Fri, 27 Sep 2024 21:58:54 +0900 Subject: [PATCH 14/17] cargo fmt --- src/nodes/block.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nodes/block.rs b/src/nodes/block.rs index 6ae4509c..8a73c43a 100644 --- a/src/nodes/block.rs +++ b/src/nodes/block.rs @@ -167,7 +167,7 @@ impl Block { self.statements.iter_mut() } - #[inline] + #[inline] pub fn mutate_statements(&mut self) -> &mut Vec { &mut self.statements } From 8f67224265073b20734d273bd7ad58456875f4e9 Mon Sep 17 00:00:00 2001 From: jiwonz Date: Tue, 1 Oct 2024 13:29:21 +0900 Subject: [PATCH 15/17] Add getmetatable option to set/inject a custom getmetatable function for avoiding __metatable metamethod purpose --- src/rules/remove_generalized_iteration.rs | 11 +++++++++-- .../remove_generalized_iteration.rs | 19 ++++++++++++++++--- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/rules/remove_generalized_iteration.rs b/src/rules/remove_generalized_iteration.rs index 09544fd4..3110a8a1 100644 --- a/src/rules/remove_generalized_iteration.rs +++ b/src/rules/remove_generalized_iteration.rs @@ -9,13 +9,14 @@ use crate::rules::{Context, RuleConfiguration, RuleConfigurationError, RulePrope use super::runtime_variable::RuntimeVariableBuilder; use super::{Rule, RuleProcessResult}; -const METATABLE_VARIABLE_NAME: &str = "_m"; +const METATABLE_VARIABLE_NAME: &str = "m"; struct Processor { iterator_variable_name: String, invariant_variable_name: String, control_variable_name: String, skip_block_once: bool, + getmetatable: String, } fn get_type_condition(arg: Expression, type_name: &str) -> Box { @@ -73,7 +74,7 @@ impl Processor { let mt_identifier = mt_typed_identifier.get_identifier().clone(); let get_mt_call = FunctionCall::new( - Prefix::from_name("getmetatable"), + Prefix::from_name(self.getmetatable.as_str()), TupleArguments::new(vec![iterator_exp.clone()]).into(), None, ); @@ -169,6 +170,7 @@ pub const REMOVE_GENERALIZED_ITERATION_RULE_NAME: &str = "remove_generalized_ite #[derive(Debug, PartialEq, Eq)] pub struct RemoveGeneralizedIteration { runtime_variable_format: String, + getmetatable: String, } impl Default for RemoveGeneralizedIteration { @@ -176,6 +178,7 @@ impl Default for RemoveGeneralizedIteration { Self { runtime_variable_format: "_DARKLUA_REMOVE_GENERALIZED_ITERATION_{name}{hash}" .to_string(), + getmetatable: "getmetatable".to_string(), } } } @@ -192,6 +195,7 @@ impl Rule for RemoveGeneralizedIteration { invariant_variable_name: var_builder.build("invar")?, control_variable_name: var_builder.build("control")?, skip_block_once: false, + getmetatable: self.getmetatable.to_owned(), }; DefaultVisitor::visit_block(block, &mut processor); Ok(()) @@ -205,6 +209,9 @@ impl RuleConfiguration for RemoveGeneralizedIteration { "runtime_variable_format" => { self.runtime_variable_format = value.expect_string(&key)?; } + "getmetatable" => { + self.getmetatable = value.expect_string(&key)?; + } _ => return Err(RuleConfigurationError::UnexpectedProperty(key)), } } diff --git a/tests/rule_tests/remove_generalized_iteration.rs b/tests/rule_tests/remove_generalized_iteration.rs index a97aee90..0ec1a5d1 100644 --- a/tests/rule_tests/remove_generalized_iteration.rs +++ b/tests/rule_tests/remove_generalized_iteration.rs @@ -5,11 +5,24 @@ test_rule!( json5::from_str::>( r#"{ rule: 'remove_generalized_iteration', - runtime_variable_format: '{name}' + runtime_variable_format: '{name}' }"# ).unwrap(), generic_for("for i,v in {1,2,3} do end") - => "do local iter={1,2,3} local invar,control if type(iter)=='table' then local _m=getmetatable(iter) if type(_m)=='table' and type(_m.__iter)=='function' then iter,invar,control=_m.__iter() else iter,invar,control=pairs(iter) end end for i,v in iter,invar,control do end end" + => "do local iter={1,2,3} local invar,control if type(iter)=='table' then local m=getmetatable(iter) if type(m)=='table' and type(m.__iter)=='function' then iter,invar,control=m.__iter() else iter,invar,control=pairs(iter) end end for i,v in iter,invar,control do end end" +); + +test_rule!( + remove_generalized_iteration_with_custom_getmetatable, + json5::from_str::>( + r#"{ + rule: 'remove_generalized_iteration', + runtime_variable_format: '{name}', + getmetatable: '_custom_getmetatable' + }"# + ).unwrap(), + generic_for("for i,v in {1,2,3} do end") + => "do local iter={1,2,3} local invar,control if type(iter)=='table' then local m=_custom_getmetatable(iter) if type(m)=='table' and type(m.__iter)=='function' then iter,invar,control=m.__iter() else iter,invar,control=pairs(iter) end end for i,v in iter,invar,control do end end" ); #[test] @@ -17,7 +30,7 @@ fn deserialize_from_object_notation() { json5::from_str::>( r#"{ rule: 'remove_generalized_iteration', - runtime_variable_format: '{name}' + runtime_variable_format: '{name}' }"#, ) .unwrap(); From 067062c7a27c0596d76b0988b861d312f95a5425 Mon Sep 17 00:00:00 2001 From: jiwonz Date: Sat, 26 Oct 2024 13:01:32 +0900 Subject: [PATCH 16/17] Remove getmetatable config and renamed runtime_variable to runtime_identifier --- src/rules/mod.rs | 2 +- src/rules/remove_generalized_iteration.rs | 43 ++++++++----------- ...time_variable.rs => runtime_identifier.rs} | 10 ++--- .../remove_generalized_iteration.rs | 17 +------- 4 files changed, 26 insertions(+), 46 deletions(-) rename src/rules/{runtime_variable.rs => runtime_identifier.rs} (79%) diff --git a/src/rules/mod.rs b/src/rules/mod.rs index 278106d7..24201914 100644 --- a/src/rules/mod.rs +++ b/src/rules/mod.rs @@ -28,7 +28,7 @@ mod rename_variables; mod replace_referenced_tokens; pub(crate) mod require; mod rule_property; -pub(crate) mod runtime_variable; +pub(crate) mod runtime_identifier; mod shift_token_line; mod unused_if_branch; mod unused_while; diff --git a/src/rules/remove_generalized_iteration.rs b/src/rules/remove_generalized_iteration.rs index 3110a8a1..7fbe9820 100644 --- a/src/rules/remove_generalized_iteration.rs +++ b/src/rules/remove_generalized_iteration.rs @@ -6,17 +6,16 @@ use crate::nodes::{ use crate::process::{DefaultVisitor, NodeProcessor, NodeVisitor}; use crate::rules::{Context, RuleConfiguration, RuleConfigurationError, RuleProperties}; -use super::runtime_variable::RuntimeVariableBuilder; +use super::runtime_identifier::RuntimeIdentifierBuilder; use super::{Rule, RuleProcessResult}; const METATABLE_VARIABLE_NAME: &str = "m"; struct Processor { - iterator_variable_name: String, - invariant_variable_name: String, - control_variable_name: String, + iterator_identifier: String, + invariant_identifier: String, + control_identifier: String, skip_block_once: bool, - getmetatable: String, } fn get_type_condition(arg: Expression, type_name: &str) -> Box { @@ -41,15 +40,15 @@ impl Processor { if exps.len() == 1 { let mut stmts: Vec = Vec::new(); let iterator_typed_identifier = - TypedIdentifier::new(self.iterator_variable_name.as_str()); + TypedIdentifier::new(self.iterator_identifier.as_str()); let iterator_identifier = iterator_typed_identifier.get_identifier().clone(); let invariant_typed_identifier = - TypedIdentifier::new(self.invariant_variable_name.as_str()); + TypedIdentifier::new(self.invariant_identifier.as_str()); let invariant_identifier = invariant_typed_identifier.get_identifier().clone(); let control_typed_identifier = - TypedIdentifier::new(self.control_variable_name.as_str()); + TypedIdentifier::new(self.control_identifier.as_str()); let control_identifier = control_typed_identifier.get_identifier().clone(); let iterator_local_assign = LocalAssignStatement::new( @@ -74,7 +73,7 @@ impl Processor { let mt_identifier = mt_typed_identifier.get_identifier().clone(); let get_mt_call = FunctionCall::new( - Prefix::from_name(self.getmetatable.as_str()), + Prefix::from_name("getmetatable"), TupleArguments::new(vec![iterator_exp.clone()]).into(), None, ); @@ -169,33 +168,30 @@ pub const REMOVE_GENERALIZED_ITERATION_RULE_NAME: &str = "remove_generalized_ite /// A rule that removes generalized iteration. #[derive(Debug, PartialEq, Eq)] pub struct RemoveGeneralizedIteration { - runtime_variable_format: String, - getmetatable: String, + runtime_identifier_format: String, } impl Default for RemoveGeneralizedIteration { fn default() -> Self { Self { - runtime_variable_format: "_DARKLUA_REMOVE_GENERALIZED_ITERATION_{name}{hash}" + runtime_identifier_format: "_DARKLUA_REMOVE_GENERALIZED_ITERATION_{name}{hash}" .to_string(), - getmetatable: "getmetatable".to_string(), } } } impl Rule for RemoveGeneralizedIteration { fn process(&self, block: &mut Block, _: &Context) -> RuleProcessResult { - let var_builder = RuntimeVariableBuilder::new( - self.runtime_variable_format.as_str(), + let var_builder = RuntimeIdentifierBuilder::new( + self.runtime_identifier_format.as_str(), format!("{block:?}").as_bytes(), Some(vec![METATABLE_VARIABLE_NAME.to_string()]), )?; let mut processor = Processor { - iterator_variable_name: var_builder.build("iter")?, - invariant_variable_name: var_builder.build("invar")?, - control_variable_name: var_builder.build("control")?, + iterator_identifier: var_builder.build("iter")?, + invariant_identifier: var_builder.build("invar")?, + control_identifier: var_builder.build("control")?, skip_block_once: false, - getmetatable: self.getmetatable.to_owned(), }; DefaultVisitor::visit_block(block, &mut processor); Ok(()) @@ -206,11 +202,8 @@ impl RuleConfiguration for RemoveGeneralizedIteration { fn configure(&mut self, properties: RuleProperties) -> Result<(), RuleConfigurationError> { for (key, value) in properties { match key.as_str() { - "runtime_variable_format" => { - self.runtime_variable_format = value.expect_string(&key)?; - } - "getmetatable" => { - self.getmetatable = value.expect_string(&key)?; + "runtime_identifier_format" => { + self.runtime_identifier_format = value.expect_string(&key)?; } _ => return Err(RuleConfigurationError::UnexpectedProperty(key)), } @@ -251,7 +244,7 @@ mod test { let result = json5::from_str::>( r#"{ rule: 'remove_generalized_iteration', - runtime_variable_format: '{name}', + runtime_identifier_format: '{name}', prop: "something", }"#, ); diff --git a/src/rules/runtime_variable.rs b/src/rules/runtime_identifier.rs similarity index 79% rename from src/rules/runtime_variable.rs rename to src/rules/runtime_identifier.rs index 5b0c3422..8bfe5504 100644 --- a/src/rules/runtime_variable.rs +++ b/src/rules/runtime_identifier.rs @@ -3,13 +3,13 @@ use hex; use std::collections::HashMap; use strfmt::strfmt; -pub struct RuntimeVariableBuilder { +pub struct RuntimeIdentifierBuilder { format: String, hash: String, keywords: Option>, } -impl RuntimeVariableBuilder { +impl RuntimeIdentifierBuilder { pub fn new( format: impl Into, identifier: &[u8], @@ -17,7 +17,7 @@ impl RuntimeVariableBuilder { ) -> Result { let format: String = format.into(); if !format.as_str().contains("{name}") { - return Err("`name` field is required for runtime variable".to_string()); + return Err("`name` field is required for runtime identifier".to_string()); } let hash = blake3::hash(identifier); Ok(Self { @@ -29,8 +29,8 @@ impl RuntimeVariableBuilder { pub fn build(&self, name: &str) -> Result { let mut vars = HashMap::new(); - vars.insert("name".to_string(), name); - vars.insert("hash".to_string(), self.hash.as_str()); + vars.insert("name".to_owned(), name); + vars.insert("hash".to_owned(), self.hash.as_str()); let name = strfmt(&self.format, &vars).map_err(|err| err.to_string())?; diff --git a/tests/rule_tests/remove_generalized_iteration.rs b/tests/rule_tests/remove_generalized_iteration.rs index 0ec1a5d1..f1abe753 100644 --- a/tests/rule_tests/remove_generalized_iteration.rs +++ b/tests/rule_tests/remove_generalized_iteration.rs @@ -5,32 +5,19 @@ test_rule!( json5::from_str::>( r#"{ rule: 'remove_generalized_iteration', - runtime_variable_format: '{name}' + runtime_identifier_format: '{name}' }"# ).unwrap(), generic_for("for i,v in {1,2,3} do end") => "do local iter={1,2,3} local invar,control if type(iter)=='table' then local m=getmetatable(iter) if type(m)=='table' and type(m.__iter)=='function' then iter,invar,control=m.__iter() else iter,invar,control=pairs(iter) end end for i,v in iter,invar,control do end end" ); -test_rule!( - remove_generalized_iteration_with_custom_getmetatable, - json5::from_str::>( - r#"{ - rule: 'remove_generalized_iteration', - runtime_variable_format: '{name}', - getmetatable: '_custom_getmetatable' - }"# - ).unwrap(), - generic_for("for i,v in {1,2,3} do end") - => "do local iter={1,2,3} local invar,control if type(iter)=='table' then local m=_custom_getmetatable(iter) if type(m)=='table' and type(m.__iter)=='function' then iter,invar,control=m.__iter() else iter,invar,control=pairs(iter) end end for i,v in iter,invar,control do end end" -); - #[test] fn deserialize_from_object_notation() { json5::from_str::>( r#"{ rule: 'remove_generalized_iteration', - runtime_variable_format: '{name}' + runtime_identifier_format: '{name}' }"#, ) .unwrap(); From 10cc9d8d51e73d6795749d0d9b330a1b256c9c04 Mon Sep 17 00:00:00 2001 From: jiwonz Date: Sat, 9 Nov 2024 17:43:59 +0900 Subject: [PATCH 17/17] runtime identifier is now public --- src/rules/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rules/mod.rs b/src/rules/mod.rs index 4078a83c..f5e5ce33 100644 --- a/src/rules/mod.rs +++ b/src/rules/mod.rs @@ -29,7 +29,7 @@ mod rename_variables; mod replace_referenced_tokens; pub(crate) mod require; mod rule_property; -pub(crate) mod runtime_identifier; +pub mod runtime_identifier; mod shift_token_line; mod unused_if_branch; mod unused_while;