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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
use crate::utils::Utils;
/// Struct for deinition parsing
pub struct DefineParser {
arg_cursor: DefineCursor,
name: String,
args: String,
body: String,
bind: bool,
container: String,
}
impl DefineParser {
pub fn new() -> Self {
Self {
arg_cursor: DefineCursor::Name,
name: String::new(),
args: String::new(),
body: String::new(),
bind: false,
container: String::new(),
}
}
/// Clear state
fn clear(&mut self) {
self.arg_cursor = DefineCursor::Name;
self.name.clear();
self.args.clear();
self.body.clear();
self.bind = false;
self.container.clear();
}
/// Parse macro definition body
///
/// NOTE: This method expects valid form of macro invocation
/// which means given value should be presented without outer prentheses
/// e.g. ) name,a1 a2=body text
///
/// If definition doesn't comply with naming rules or syntaxes, if returnes "None"
pub(crate) fn parse_define(&mut self, text: &str) -> Option<(String, String, String)> {
self.clear(); // Start in fresh state
let char_iter = text.chars().peekable();
for ch in char_iter {
match self.arg_cursor {
DefineCursor::Name => {
if let ParseIgnore::Ignore = self.branch_name(ch) {
continue;
}
// If not valid name return None
if !self.is_valid_char(ch) {
return None;
}
}
DefineCursor::Args => {
if let ParseIgnore::Ignore = self.branch_args(ch) {
continue;
}
// If not valid name return None
if !self.is_valid_char(ch) {
return None;
}
}
// Add everything
DefineCursor::Body => (),
}
self.container.push(ch);
}
// This means pattern such as
// $define(test,Test)
// -> This is not a valid pattern
// self.args.len() is 0, because
// args are added only after equal(=) sign is detected
if self.args.is_empty() && !self.bind {
return None;
}
// End of body
self.body.push_str(&self.container);
Some((self.name.clone(), self.args.clone(), self.body.clone()))
}
/// Check if char complies with naming rule
fn is_valid_char(&self, ch: char) -> bool {
if self.container.is_empty() {
// Start of string
// Not alphabetic
// $define( 1name ) -> Not valid
if !ch.is_alphabetic() {
return false;
}
} else {
// middle of string
// Not alphanumeric and not underscore
// $define( na*1me ) -> Not valid
// $define( na_1me ) -> Valid
if !ch.is_alphanumeric() && ch != '_' {
return false;
}
}
true
}
// ---------
// Start of branche methods
// <DEF_BRANCH>
fn branch_name(&mut self, ch: char) -> ParseIgnore {
// $define(variable=something)
// Don't set argument but directly bind variable to body
if ch == '=' {
self.name.push_str(&self.container);
self.container.clear();
self.arg_cursor = DefineCursor::Body;
self.bind = true;
ParseIgnore::Ignore
} else if Utils::is_blank_char(ch) {
// This means pattern like this
// $define( name ) -> name is registered
// $define( na me ) -> na is ignored and take me instead
if !self.name.is_empty() {
self.container.clear();
ParseIgnore::None
} else {
// Ignore
ParseIgnore::Ignore
}
}
// Comma go to args
else if ch == ',' {
self.name.push_str(&self.container);
self.container.clear();
self.arg_cursor = DefineCursor::Args;
ParseIgnore::Ignore
} else {
ParseIgnore::None
}
}
fn branch_args(&mut self, ch: char) -> ParseIgnore {
// Blank space separates arguments
// TODO: Why check name's length? Is it necessary?
if Utils::is_blank_char(ch) && !self.name.is_empty() {
if !self.container.is_empty() {
self.args.push_str(&self.container);
self.args.push(' ');
self.container.clear();
}
ParseIgnore::Ignore
}
// Go to body
else if ch == '=' {
self.args.push_str(&self.container);
self.container.clear();
self.arg_cursor = DefineCursor::Body;
ParseIgnore::Ignore
}
// Others
else {
ParseIgnore::None
}
}
// End of branche methods
// </DEF_BRANCH>
// ---------
}
pub(crate) enum DefineCursor {
Name,
Args,
Body,
}
enum ParseIgnore {
Ignore,
None,
}