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
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
/***************************************
Auteur : Pierre Aubert
Mail : pierre.aubert@lapp.in2p3.fr
Licence : CeCILL-C
****************************************/
use std::collections::HashMap;
use crate::phighlighter::{
pactionhighlight::PActionHighLight, pfileparser::PFileParserIter, phighlighter::PHighlighterGetUntilReplace, phighlither_configuration::{
PHighlighterGetUntil,
PHighlighterSequence,
}
};
///Part of the highlighting tree
#[derive(Debug,Default,Clone)]
pub struct PNodeHighLight{
///Index of the corresponding action to perform once none p_map_sequence or p_vec_oneof have a match (there will be a lot of action dupplication so we diminish the needed memory by factorizing it in the PHighLighter::p_map_action)
p_action_index: usize,
///Pattern or sequence of char to be tested by the node
p_pattern: String,
///Vector of node which match a sequence
p_map_sequence: HashMap<u8, PNodeHighLight>,
///Vector of node which match a oneof (one char match in all chars of the String p_pattern)
p_vec_oneof: Vec<PNodeHighLight>,
}
///Update the available oneof those which as still available while we are trying to parse an other token
/// # Parameters
/// - `vec_available_oneof` : vector of available oneof to be updated with the given char
/// - `vec_current_oneof` : vector of oneof of the current PNodeHighlight
/// - `current_char` : current char which as to be in the remaining oneof
fn update_available_oneof(vec_available_oneof: &mut Vec<PNodeHighLight>, vec_current_oneof: &Vec<PNodeHighLight>, current_char: u8){
//Nothing to update, we stop
if vec_available_oneof.len() == 0 && vec_current_oneof.len() == 0 {
return;
}
let str_char = String::from(current_char as char);
let mut vec_remaning_oneof: Vec<PNodeHighLight> = vec![];
for node in vec_available_oneof.iter() {
if node.p_pattern.contains(&str_char) {
vec_remaning_oneof.push(node.clone());
}
}
for node in vec_current_oneof.iter() {
if node.p_pattern.contains(&str_char) {
vec_remaning_oneof.push(node.clone());
}
}
*vec_available_oneof = vec_remaning_oneof.clone();
}
impl PNodeHighLight {
///Constructor of a PNodeHighLight
/// # Parameters
/// - `action_index` : index of the action to perform if no more match is found
/// - `pattern` : pattern for 'OneOf' search
/// # Returns
/// Initialised PNodeHighLight
pub fn new(action_index: usize, pattern: &String) -> Self{
PNodeHighLight{
p_action_index: action_index,
p_pattern: pattern.clone(),
p_map_sequence: HashMap::default(),
p_vec_oneof: vec![]
}
}
///Add a token in the PNodeHighLight
/// # Parameters
/// - `token` : token to be parsed
/// - `action_index` : index of the action to perform if there is no more match
pub fn add_token(&mut self, token: &String, action_index: usize){
let vec_byte: Vec<u8> = Vec::from(token.clone().into_bytes());
self.add_vec_u8(&vec_byte, action_index);
}
///Add a token in the PNodeHighLight
/// # Parameters
/// - `token` : token to be parsed
/// - `action_index` : index of the action to perform if there is no more match
pub fn add_vec_u8(&mut self, token: &Vec<u8>, action_index: usize){
//Here we need to walk on the vector of u8 and add all the necessary nodes for the parsing
// All new nodes have the action 0 except the last one which has action action_index
let mut last_node = self;
for ch in token.iter() {
let map_sequence = &mut last_node.p_map_sequence;
//If the node does not exist, we create it
if !map_sequence.contains_key(ch) {
let node: PNodeHighLight = Default::default();
map_sequence.insert(*ch, node);
}
//Then we get the next node, and it always exist
last_node = map_sequence.get_mut(ch).unwrap();
// last_node = match map_sequence.get_mut(ch) {
// Some(node) => node,
// None => &mut tmp_node
// };
}
last_node.p_action_index = action_index;
}
///Add a getuntil in the PNodeHighLight
/// # Parameters
/// - `getuntil` : getuntil configuration to be used
/// - `action_index` : index of the action to perform if there is no more match
pub fn add_getuntil(&mut self, getuntil: &PHighlighterGetUntil, action_index: usize){
let vec_byte: Vec<u8> = Vec::from(getuntil.start_token.clone().into_bytes());
self.add_vec_u8(&vec_byte, action_index);
}
///Add a getuntilreplace in the PNodeHighLight
/// # Parameters
/// - `getuntilreplace` : getuntilreplace configuration to be used
/// - `action_index` : index of the action to perform if there is no more match
pub fn add_getuntilreplace(&mut self, getuntilreplace: &PHighlighterGetUntilReplace, action_index: usize){
let vec_byte: Vec<u8> = Vec::from(getuntilreplace.start_token.clone().into_bytes());
self.add_vec_u8(&vec_byte, action_index);
}
///Add a sequence in the PNodeHighligth
/// # Parameters
/// - `sequence` : sequence configuration to be used
/// - `action_index` : index of the action to perform if there is no more match
pub fn add_sequence(&mut self, sequence: &PHighlighterSequence, action_index: usize){
//Let's add all steps of the sequence
let mut last_node = self;
for step in sequence.vec_step.iter(){
//Depending if the step is a match or a getStrComposedOf
// There is no need for an optionnal attribute because we can end after each step
match &step.token {
Some(token) => {
// println!("PNodeHighLight::add_sequence : Add token '{}'", token);
//We have to add the token in the node before calling the other steps
// So we just change the last_node to be used, and where we will call the oneof at some point
let vec_byte: Vec<u8> = Vec::from(token.clone().into_bytes());
last_node = last_node.get_child_mut(&vec_byte);
last_node.p_action_index = action_index;
},
None => match &step.oneof {
Some(oneof) => {
// println!("PNodeHighLight::add_sequence : Add oneof '{}'", oneof);
//We have to add a get_str_of in the current node
// First, we create the node
let oneof_node = PNodeHighLight::new(action_index, oneof);
last_node.p_vec_oneof.push(oneof_node);
//And we add the node into the current one
last_node = last_node.p_vec_oneof.last_mut().unwrap();
},
None => {}
}
};
}
// last_node.p_action_index = action_index;
}
///Get a mutable child at the given token
/// # Parameters
/// - `token` : token to be parsed
/// # Returns
/// Mutable reference to the correspondign child (it will be created if it does not exist)
fn get_child_mut(&mut self, token: &Vec<u8>) -> &mut PNodeHighLight{
let mut last_node = self;
for ch in token.iter() {
let map_sequence = &mut last_node.p_map_sequence;
//If the node does not exist, we create it
if !map_sequence.contains_key(ch) {
let node: PNodeHighLight = Default::default();
map_sequence.insert(*ch, node);
}
//Then we get the next node, and it always exist
last_node = map_sequence.get_mut(ch).unwrap();
// last_node = match map_sequence.get_mut(ch) {
// Some(node) => node,
// None => &mut tmp_node
// };
}
return last_node;
}
///Do the highlight on a PNodeHighLight
/// # Parameters
/// - `body` : output of the highlighting
/// - `current_match_token` : current matched token when walking on the tree of PNodeHighLight children
/// - `it` : iterator on the parser to use
/// - `vec_available_oneof` :
/// - `vec_action` : vector of action to be performed by the highlighter
/// - `token_charset` : charset which contains all characters which composed a token
pub fn highlight(&self, body: &mut String, current_match_token: &mut String, it: &mut PFileParserIter, vec_available_oneof: &mut Vec<PNodeHighLight>,
vec_action: &Vec<PActionHighLight>, token_charset: &String)
{
match it.get_current_char() {
Some(current_char) => {
// println!("PNodeHighlight::highlight : current char = '{}', vec_available_oneof.len() = {}, self.p_vec_oneof.len() = {}", String::from(current_char as char), vec_available_oneof.len(), self.p_vec_oneof.len());
// println!("PNodeHighlight::highlight : current char = '{}'", String::from(current_char as char));
match self.p_map_sequence.get(¤t_char) {
Some(child) => { //We found a match, so we jump on the next PNodeHighLight
it.next(); //We get the next char
*current_match_token += &String::from(current_char as char); //We update the curently parsed token
//Here we have to update the vector of available oneof
update_available_oneof(vec_available_oneof, &self.p_vec_oneof, current_char);
child.highlight(body, current_match_token, it, vec_available_oneof, vec_action, token_charset); //Then we call it on the found child
},
None => { //No more match, so we check the oneof
let mut last_action_index: Option<usize> = None;
for node in self.p_vec_oneof.iter() {
if node.check_oneof(current_match_token, it, &mut last_action_index) {
break;
}
}
//If we found nothing maybe we have a previous oneof which is still valid
if last_action_index == None {
for node in vec_available_oneof.iter(){
if node.check_oneof(current_match_token, it, &mut last_action_index) {
break;
}
}
}
match last_action_index {
Some(action_index) => self.run_action(action_index, current_char, body, current_match_token, it, vec_action, token_charset),
None => self.run_action(self.p_action_index, current_char, body, current_match_token, it, vec_action, token_charset)
};
}
}
},
None => {} //This is the end of parsing
};
}
///Check the oneof of the current PNodeHighlight
/// # Parameters
/// - `current_match_token` : current matched token when walking on the tree of PNodeHighLight children
/// - `it` : iterator on the parser to use
/// - `last_action_index` : index of the last action
/// # Returns
/// True if the oneof matches, false otherwise
fn check_oneof(&self, current_match_token: &mut String, it: &mut PFileParserIter, last_action_index: &mut Option<usize>) -> bool{
let str_composed_of: String = it.get_str_of(&self.p_pattern);
if str_composed_of.len() > 0 {
// println!("PNodeHighLight::highlight : find str of '{}'", str_composed_of);
*current_match_token += &str_composed_of;
//Let's see if we can have a last match
// node.highlight(body, current_match_token, it, vec_action);
*last_action_index = Some(self.p_action_index);
return true;
}
return false;
}
///Run the given action_index
/// # Parameters
/// - `action_index` : index of the action to be performed
/// - `body` : output of the highlighting
/// - `current_match_token` : current matched token when walking on the tree of PNodeHighLight children
/// - `it` : iterator on the parser to use
/// - `vec_action` : vector of action to be performed by the highlighter
/// - `token_charset` : charset which contains all characters which composed a token
fn run_action(&self, action_index: usize, current_char: u8, body: &mut String, current_match_token: &mut String, it: &mut PFileParserIter, vec_action: &Vec<PActionHighLight>, token_charset: &String){
// println!("PNodeHighlight::run_action : current_char = '{}', current_match_token = '{}'", String::from(current_char as char), current_match_token);
match vec_action.get(action_index) {
Some(action) => {
if current_match_token.len() == 0 { //They were no previous match
*body += &String::from(current_char as char);
it.next(); //We get the next char
}else{
//Let's performed the associated action
*body += &action.run(it, ¤t_match_token, token_charset);
//The current char does not match here, but maybe at the begining of a new token
*current_match_token = String::from(""); //We found a token, so we reset the matched token
}
},
None => panic!("PNodeHighLight::run_action : no action {} to be performed at {}", action_index, it.get_location())
}
}
}