1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
use crate::nodes::{
Block, Expression, FieldExpression, Identifier, IndexExpression, Prefix, Variable,
};
use crate::process::{
utils::keywords, DefaultVisitor, Evaluator, LuaValue, NodeProcessor, NodeVisitor,
};
use crate::rules::{
Context, FlawlessRule, RuleConfiguration, RuleConfigurationError, RuleProperties,
};
use super::verify_no_rule_properties;
use std::mem;
#[derive(Debug, Clone, Default)]
struct Converter {
evaluator: Evaluator,
}
fn is_identifier(string: &str) -> bool {
string.starts_with(|c: char| c.is_ascii_alphabetic())
&& string.chars().skip(1).all(|c| c.is_ascii_alphanumeric())
&& !matches!(string, keywords::matches_any!())
}
impl Converter {
fn convert_to_field(&self, index: &IndexExpression) -> Option<FieldExpression> {
if let LuaValue::String(string) = self.evaluator.evaluate(index.get_index()) {
if is_identifier(&string) {
return Some(FieldExpression::new(
index.get_prefix().clone(),
Identifier::new(string),
));
}
}
None
}
}
impl NodeProcessor for Converter {
fn process_expression(&mut self, expression: &mut Expression) {
let field: Option<Expression> = if let Expression::Index(index) = expression {
self.convert_to_field(index).map(Into::into)
} else {
None
};
if let Some(mut field) = field {
mem::swap(expression, &mut field);
}
}
fn process_prefix_expression(&mut self, prefix: &mut Prefix) {
let field: Option<Prefix> = if let Prefix::Index(index) = prefix {
self.convert_to_field(index).map(Into::into)
} else {
None
};
if let Some(mut field) = field {
mem::swap(prefix, &mut field);
}
}
fn process_variable(&mut self, variable: &mut Variable) {
let field: Option<Variable> = if let Variable::Index(index) = variable {
self.convert_to_field(index).map(Into::into)
} else {
None
};
if let Some(mut field) = field {
mem::swap(variable, &mut field);
}
}
}
pub const CONVERT_INDEX_TO_FIELD_RULE_NAME: &str = "convert_index_to_field";
#[derive(Debug, Default, PartialEq, Eq)]
pub struct ConvertIndexToField {}
impl FlawlessRule for ConvertIndexToField {
fn flawless_process(&self, block: &mut Block, _: &mut Context) {
let mut processor = Converter::default();
DefaultVisitor::visit_block(block, &mut processor);
}
}
impl RuleConfiguration for ConvertIndexToField {
fn configure(&mut self, properties: RuleProperties) -> Result<(), RuleConfigurationError> {
verify_no_rule_properties(&properties)?;
Ok(())
}
fn get_name(&self) -> &'static str {
CONVERT_INDEX_TO_FIELD_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() -> ConvertIndexToField {
ConvertIndexToField::default()
}
#[test]
fn serialize_default_rule() {
let rule: Box<dyn Rule> = Box::new(new_rule());
assert_json_snapshot!("default_convert_index_to_field", rule);
}
}