1use std::string::ToString;
2use std::{collections::HashMap, str::FromStr};
3
4use full_moon::ast::punctuated::Pair;
5use full_moon::ast::Do;
6use full_moon::node::Node;
7use full_moon::tokenizer::{Symbol, Token, TokenType};
8use full_moon::{
9 ast::{
10 punctuated::Punctuated, BinOp, Call, Expression, FunctionArgs, FunctionCall, Index, Stmt,
11 Suffix, UnOp, Var,
12 },
13 tokenizer::TokenReference,
14 visitors::VisitorMut,
15};
16use strum_macros::{Display, EnumString};
17
18use super::ast_util;
19
20pub const CONVERT_BIT32_MODIFIER_NAME: &str = "convert_bit32";
21const DEFAULT_BIT32_IDENTIFIER: &str = "bit32";
22const MASKING_NUMBER_TOKEN_SYMBOL: &str = "0xFFFFFFFF";
23
24#[inline]
25fn mask_32bit(exp: Expression) -> Expression {
26 ast_util::create_binary_operator(
27 exp,
28 BinOp::Ampersand(TokenReference::symbol("&").unwrap()),
29 ast_util::create_number(MASKING_NUMBER_TOKEN_SYMBOL),
30 )
31}
32
33fn index_to_string(index: &Index) -> Option<String> {
34 match index {
35 Index::Brackets {
36 brackets: _,
37 expression,
38 } => {
39 let mut string = expression.to_string();
40 string.remove(0);
41 string.pop();
42 Some(string)
43 }
44 Index::Dot { dot: _, name: _ } => {
45 let mut string = index.to_string();
46 string.remove(0);
47 Some(string)
48 }
49 _ => None,
50 }
51}
52
53#[derive(Debug, Display, EnumString)]
54enum Bit32Method {
55 #[strum(serialize = "rshift")]
56 RightShift,
57 #[strum(serialize = "lshift")]
58 LeftShift,
59 #[strum(serialize = "band")]
60 And,
61 #[strum(serialize = "bor")]
62 Or,
63 #[strum(serialize = "bxor")]
64 Xor,
65 #[strum(serialize = "bnot")]
66 Not,
67 #[strum(serialize = "btest")]
68 Test,
69}
70
71impl Bit32Method {
72 fn convert(&self, call: &Call) -> Option<Expression> {
73 if let Call::AnonymousCall(args) = call {
74 if let FunctionArgs::Parentheses {
75 parentheses,
76 arguments,
77 } = args
78 {
79 let mut iter = arguments.iter();
80 let first_arg = iter.next()?;
81
82 let binop = match self {
83 Bit32Method::RightShift => {
84 BinOp::DoubleGreaterThan(TokenReference::symbol(">>").unwrap())
85 }
86 Bit32Method::LeftShift => {
87 BinOp::DoubleLessThan(TokenReference::symbol("<<").unwrap())
88 }
89 Bit32Method::And => BinOp::Ampersand(TokenReference::symbol("&").unwrap()),
90 Bit32Method::Or => BinOp::Pipe(TokenReference::symbol("|").unwrap()),
91 Bit32Method::Xor => BinOp::Tilde(TokenReference::symbol("~").unwrap()),
92 Bit32Method::Not => {
93 let masking_arg = mask_32bit(first_arg.clone());
94 let parenthese = ast_util::create_parentheses(masking_arg, None);
95 let bnot_exp = ast_util::create_unary_operator(
96 UnOp::Tilde(TokenReference::symbol("~").unwrap()),
97 parenthese,
98 );
99 let masking_unop = mask_32bit(bnot_exp);
100 return Some(ast_util::create_parentheses(
101 masking_unop,
102 Some(parentheses.clone()),
103 ));
104 }
105 Bit32Method::Test => {
106 let second_arg = iter.next()?;
107 let band_exp = ast_util::create_binary_operator(
108 first_arg.clone(),
109 BinOp::Ampersand(TokenReference::symbol("&").unwrap()),
110 second_arg.clone(),
111 );
112 let parenthese = ast_util::create_parentheses(band_exp, None);
113 let masking_bin_exp = mask_32bit(parenthese);
114 let not_equal_exp = ast_util::create_binary_operator(
115 masking_bin_exp,
116 BinOp::TildeEqual(TokenReference::symbol("~=").unwrap()),
117 ast_util::create_number("0"),
118 );
119 return Some(ast_util::create_parentheses(
120 not_equal_exp,
121 Some(parentheses.clone()),
122 ));
123 }
124 };
125
126 let second_arg = iter.next()?;
127 let bitop_exp =
128 ast_util::create_binary_operator(first_arg.clone(), binop, second_arg.clone());
129 let parenthese = ast_util::create_parentheses(bitop_exp, None);
130 let masking_bin_exp = mask_32bit(parenthese);
131 return Some(ast_util::create_parentheses(
132 masking_bin_exp,
133 Some(parentheses.clone()),
134 ));
135 }
136 }
137 None
138 }
139}
140
141#[derive(Debug)]
142pub struct ConvertBit32 {
143 bit32_identifier: String,
144 bit32_methods: HashMap<String, Bit32Method>,
145}
146
147impl Default for ConvertBit32 {
148 fn default() -> Self {
149 Self {
150 bit32_identifier: DEFAULT_BIT32_IDENTIFIER.to_owned(),
151 bit32_methods: HashMap::new(),
152 }
153 }
154}
155
156impl VisitorMut for ConvertBit32 {
157 fn visit_stmt(&mut self, stmt: Stmt) -> Stmt {
158 match &stmt {
159 Stmt::FunctionCall(func_call) => {
160 if let Some(_) = self.convert(func_call) {
161 if let Suffix::Call(Call::AnonymousCall(FunctionArgs::Parentheses {
162 parentheses,
163 arguments: _,
164 })) = func_call.suffixes().last().unwrap()
165 {
166 return Stmt::Do(
167 Do::new()
168 .with_do_token(TokenReference::new(
169 func_call
170 .surrounding_trivia()
171 .0
172 .into_iter()
173 .cloned()
174 .collect(),
175 Token::new(TokenType::Symbol { symbol: Symbol::Do }),
176 vec![Token::new(TokenType::Whitespace {
177 characters: " ".into(),
178 })],
179 ))
180 .with_end_token(TokenReference::new(
181 Vec::new(),
182 Token::new(TokenType::Symbol {
183 symbol: Symbol::End,
184 }),
185 parentheses
186 .tokens()
187 .1
188 .trailing_trivia()
189 .cloned()
190 .chain(std::iter::once(Token::new(TokenType::Whitespace {
191 characters: " ".into(),
192 })))
193 .collect(),
194 )),
195 );
196 }
197 }
198 }
199 Stmt::Assignment(assign) => {
200 if self.check_replaced(assign.variables(), assign.expressions()) {
201 let mut do_trailing_trivia: Vec<Token> = Vec::new();
202 for token_ref in assign.tokens() {
203 for t in token_ref.leading_trivia() {
204 do_trailing_trivia.push(t.to_owned());
205 }
206 for t in token_ref.trailing_trivia() {
207 do_trailing_trivia.push(t.to_owned());
208 }
209 }
210 return Stmt::Do(
211 Do::new()
212 .with_do_token(TokenReference::new(
213 vec![Token::new(TokenType::Whitespace {
214 characters: " ".into(),
215 })],
216 Token::new(TokenType::Symbol { symbol: Symbol::Do }),
217 do_trailing_trivia,
218 ))
219 .with_end_token(TokenReference::new(
220 vec![Token::new(TokenType::Whitespace {
221 characters: " ".into(),
222 })],
223 Token::new(TokenType::Symbol {
224 symbol: Symbol::End,
225 }),
226 vec![Token::new(TokenType::Whitespace {
227 characters: " ".into(),
228 })],
229 )),
230 );
231 }
232 }
233 Stmt::LocalAssignment(local_assign) => {
234 let mut variables: Punctuated<Var> = Punctuated::new();
235 for token in local_assign.names() {
236 variables.push(Pair::new(Var::Name(token.clone()), None));
237 }
238 if self.check_replaced(&variables, local_assign.expressions()) {
239 let mut do_trailing_trivia: Vec<Token> = Vec::new();
240 for token_ref in local_assign.tokens() {
241 for t in token_ref.leading_trivia() {
242 do_trailing_trivia.push(t.to_owned());
243 }
244 for t in token_ref.trailing_trivia() {
245 do_trailing_trivia.push(t.to_owned());
246 }
247 }
248 return Stmt::Do(
249 Do::new()
250 .with_do_token(TokenReference::new(
251 vec![Token::new(TokenType::Whitespace {
252 characters: " ".into(),
253 })],
254 Token::new(TokenType::Symbol { symbol: Symbol::Do }),
255 do_trailing_trivia,
256 ))
257 .with_end_token(TokenReference::new(
258 Vec::new(),
259 Token::new(TokenType::Symbol {
260 symbol: Symbol::End,
261 }),
262 vec![Token::new(TokenType::Whitespace {
263 characters: " ".into(),
264 })],
265 )),
266 );
267 }
268 }
269 _ => {}
270 }
271 stmt
272 }
273
274 fn visit_expression(&mut self, exp: Expression) -> Expression {
278 if let Expression::FunctionCall(func_call) = &exp {
279 if let Some(exp) = self.convert(func_call) {
280 return exp;
281 }
282 }
283 exp
284 }
285}
286
287impl ConvertBit32 {
288 #[inline]
289 fn is_bit32_identifier(&self, string: impl Into<String>) -> bool {
290 string.into() == self.bit32_identifier
291 }
292
293 fn check_replaced(
294 &mut self,
295 variables: &Punctuated<Var>,
296 expressions: &Punctuated<Expression>,
297 ) -> bool {
298 for (var, exp) in variables.iter().zip(expressions.iter()) {
299 if let Expression::Var(exp) = exp {
301 match exp {
302 Var::Expression(var_exp) => {
303 if !self.is_bit32_identifier(var_exp.prefix().to_string()) {
304 return false;
305 }
306 let mut iter = var_exp.suffixes();
307 let first = iter.next();
308 if let Some(first) = first {
309 if let Suffix::Index(index) = first {
311 let index = index_to_string(index);
312 if let Some(index) = index {
313 if let Ok(method) = Bit32Method::from_str(index.trim()) {
314 self.bit32_methods
315 .insert(var.to_string().trim().to_owned(), method);
316 return true;
317 }
318 }
319 }
320 }
321 }
322 Var::Name(_) => {
323 if self.is_bit32_identifier(exp.to_string().trim().to_owned()) {
324 self.bit32_identifier = var.to_string().trim().to_owned();
325 return true;
326 }
327 }
328 _ => {}
329 }
330 }
331 }
332 false
333 }
334
335 fn convert(&mut self, func_call: &FunctionCall) -> Option<Expression> {
336 let mut iter = func_call.suffixes();
337 let first = iter.next();
338 let second = iter.next();
339 let prefix = func_call.prefix().to_string();
340 match (first, second) {
341 (Some(first), Some(second)) => {
342 if !self.is_bit32_identifier(prefix) {
343 return None;
344 }
345 match (first, second) {
346 (Suffix::Index(index), Suffix::Call(call)) => {
348 let index = index_to_string(index)?;
349 if let Ok(method) = Bit32Method::from_str(index.trim()) {
350 return method.convert(call);
351 }
352 None
353 }
354 _ => None,
355 }
356 }
357 (Some(first), None) => {
358 if let Suffix::Call(call) = first {
360 if let Some(method) = self.bit32_methods.get(&prefix) {
361 return method.convert(call);
362 }
363 }
364 None
365 }
366 _ => None,
367 }
368 }
369}