1pub mod pattern;
2pub mod rule;
3use self::{pattern::BoxDynPattern, rule::Matcher};
4use crate::mesdoc::{constants::NAME_SELECTOR_ALL, error::Error};
5use lazy_static::lazy_static;
6pub use pattern::MatchedQueue;
7use pattern::{exec, Matched};
8use rule::{Rule, RULES};
9use std::{
10 str::FromStr,
11 sync::{Arc, Mutex},
12};
13
14lazy_static! {
15 static ref SPLITTER: Mutex<Vec<BoxDynPattern>> =
16 Mutex::new(Rule::get_queues(r##"{regexp#(\s*[>,~+]\s*|\s+)#}"##));
17 static ref ALL_RULE: Mutex<Option<Arc<Rule>>> = Mutex::new(None);
18}
19#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
20pub enum Combinator {
21 ChildrenAll,
23 Children,
25 Parent,
27 ParentAll,
29 NextAll,
31 Next,
33 PrevAll,
35 Prev,
37 Siblings,
39 Chain,
41}
42
43impl From<&str> for Combinator {
45 fn from(comb: &str) -> Self {
46 use Combinator::*;
47 match comb {
48 "" => ChildrenAll,
49 ">" => Children,
50 "~" => NextAll,
51 "+" => Next,
52 _ => panic!("Not supported combinator string '{}'", comb),
53 }
54 }
55}
56
57impl Combinator {
58 pub fn reverse(&self) -> Self {
59 use Combinator::*;
60 match self {
61 ChildrenAll => ParentAll,
62 Children => Parent,
63 NextAll => PrevAll,
64 Next => Prev,
65 Chain => Chain,
66 _ => panic!("Not supported combinator reverse for '{:?}'", self),
67 }
68 }
69}
70
71pub type SelectorSegment = (Matcher, Combinator);
72#[derive(Default, Debug)]
73pub struct QueryProcess {
74 pub should_in: Option<SelectorGroupsItem>,
75 pub query: SelectorGroupsItem,
76}
77
78#[derive(Default, Debug)]
79pub struct Selector {
80 pub process: Vec<QueryProcess>,
81}
82
83type SelectorGroupsItem = Vec<Vec<SelectorSegment>>;
84type SelectorGroups = Vec<SelectorGroupsItem>;
85impl Selector {
86 pub fn new() -> Self {
87 Selector {
88 process: Vec::with_capacity(1),
89 }
90 }
91 pub fn from_str(context: &str, use_lookup: bool) -> Result<Self, Error> {
92 let chars: Vec<char> = context.chars().collect();
93 let total_len = chars.len();
94 let mut selector = Selector::new();
95 if total_len > 0 {
96 let mut index: usize = 0;
97 let mut comb = Combinator::ChildrenAll;
98 let mut prev_in = PrevInSelector::Begin;
99 let mut last_in = prev_in;
100 let mut groups: SelectorGroups = Vec::new();
101 let splitter = SPLITTER.lock().unwrap();
102 let rules = RULES.lock().unwrap();
103 Selector::add_group(&mut groups);
104 while index < total_len {
105 let next_chars = &chars[index..];
106 if let Some((matched, len, _)) = Rule::exec_queues(&splitter, next_chars) {
108 let op = matched[0].chars.iter().collect::<String>();
109 let op = op.trim();
110 if prev_in == PrevInSelector::Splitter {
111 return Err(Error::InvalidSelector {
113 context: String::from(context),
114 reason: format!(
115 "Wrong combinator '{}' at index {}",
116 matched[0].chars.iter().collect::<String>(),
117 index
118 ),
119 });
120 }
121 index += len;
123 if op == "," {
125 if prev_in != PrevInSelector::Selector {
126 return Err(Error::InvalidSelector {
127 context: String::from(context),
128 reason: format!("Wrong empty selector before ',' at index {}", index),
129 });
130 }
131 Selector::add_group(&mut groups);
132 comb = Combinator::ChildrenAll;
133 } else {
134 comb = Combinator::from(op);
135 }
136 if op.is_empty() {
138 last_in = prev_in;
139 prev_in = PrevInSelector::Splitter;
140 } else {
141 prev_in = PrevInSelector::Splitter;
142 last_in = prev_in;
143 }
144 continue;
145 }
146 let mut is_new_item = true;
148 if prev_in == PrevInSelector::Selector {
149 comb = Combinator::Chain;
150 is_new_item = false;
151 } else {
152 prev_in = PrevInSelector::Selector;
153 last_in = prev_in;
154 }
155 let mut finded = false;
156 for (_, r) in rules.iter() {
157 if let Some((mut matched, len, queue_num)) = r.exec(next_chars) {
158 index += len;
160 let queues = &r.queues;
161 if queue_num == queues.len() {
162 Selector::add_group_item(&mut groups, (r.make(matched), comb), is_new_item);
164 finded = true;
165 } else if queues[queue_num].is_nested() {
166 let (len, nested_matched) = Selector::parse_until(
168 &chars[index..],
169 &queues[queue_num + 1..],
170 &rules,
171 &splitter,
172 0,
173 )?;
174 index += len;
175 matched.extend(nested_matched);
176 Selector::add_group_item(&mut groups, (r.make(matched), comb), is_new_item);
177 finded = true;
178 }
179 break;
180 }
181 }
182 if !finded {
183 return Err(Error::InvalidSelector {
185 context: String::from(context),
186 reason: format!(
187 "Unrecognized selector '{}' at index {}",
188 next_chars.iter().collect::<String>(),
189 index
190 ),
191 });
192 }
193 }
194 if last_in != PrevInSelector::Selector {
195 return Err(Error::InvalidSelector {
196 context: String::from(context),
197 reason: String::from("Wrong selector rule at last"),
198 });
199 }
200 selector.optimize(groups, use_lookup);
202 }
203 Ok(selector)
204 }
205 fn add_group(groups: &mut SelectorGroups) {
207 groups.push(Vec::with_capacity(2));
208 }
209 fn add_group_item(groups: &mut SelectorGroups, item: SelectorSegment, is_new: bool) {
211 if let Some(last_group) = groups.last_mut() {
212 if is_new {
213 last_group.push(vec![item]);
214 } else if let Some(last) = last_group.last_mut() {
215 last.push(item);
216 }
217 }
218 }
219 fn optimize(&mut self, groups: SelectorGroups, use_lookup: bool) {
221 let mut process: Vec<QueryProcess> = Vec::with_capacity(groups.len());
222 for mut group in groups {
223 let mut max_index: usize = 0;
225 let mut max_priority: u32 = 0;
226 for (index, r) in group.iter_mut().enumerate() {
227 let mut total_priority = 0;
228 if r.len() > 1 {
229 let chain_comb = r[0].1;
230 r.sort_by(|a, b| b.0.priority.partial_cmp(&a.0.priority).unwrap());
231 let now_first = &mut r[0];
232 if now_first.1 != chain_comb {
233 now_first.1 = chain_comb;
234 total_priority += now_first.0.priority;
235 for n in &mut r[1..] {
236 n.1 = Combinator::Chain;
237 total_priority += n.0.priority;
238 }
239 }
240 }
241 if use_lookup {
242 total_priority = r.iter().map(|p| p.0.priority).sum();
243 if total_priority > max_priority {
244 max_priority = total_priority;
245 max_index = index;
246 }
247 }
248 }
249 if use_lookup && max_index > 0 {
251 let is_child = matches!(
252 group[0][0].1,
253 Combinator::Children | Combinator::ChildrenAll
254 );
255 if is_child {
256 let query = group.split_off(max_index);
257 let should_in = Some(group);
258 process.push(QueryProcess { should_in, query });
259 continue;
260 }
261 }
262 process.push(QueryProcess {
263 should_in: None,
264 query: group,
265 });
266 }
267 self.process = process;
268 }
269 pub fn head_combinator(&mut self, comb: Combinator) {
271 for p in &mut self.process {
272 let v = if let Some(should_in) = &mut p.should_in {
273 should_in
274 } else {
275 &mut p.query
276 };
277 if let Some(rule) = v.get_mut(0) {
278 let first_comb = rule[0].1;
279 match first_comb {
280 Combinator::ChildrenAll => rule[0].1 = comb,
281 _ => {
282 let segment = Selector::make_comb_all(comb);
283 v.insert(0, vec![segment]);
284 }
285 };
286 }
287 }
288 }
289 pub fn make_comb_all(comb: Combinator) -> SelectorSegment {
291 let mut all_rule = ALL_RULE.lock().unwrap();
292 if all_rule.is_none() {
293 let rules = RULES.lock().unwrap();
294 for (name, rule) in &rules[..] {
295 if *name == NAME_SELECTOR_ALL {
296 *all_rule = Some(Arc::clone(rule));
297 break;
298 }
299 }
300 }
301 let cur_rule = Arc::clone(all_rule.as_ref().expect("All rule must add to rules"));
302 let matcher = cur_rule.make(vec![]);
303 (matcher, comb)
304 }
305 pub fn from_segment(segment: SelectorSegment) -> Self {
307 let process = QueryProcess {
308 query: vec![vec![segment]],
309 should_in: None,
310 };
311 Selector {
312 process: vec![process],
313 }
314 }
315 pub fn parse_until(
317 chars: &[char],
318 until: &[BoxDynPattern],
319 rules: &[(&str, Arc<Rule>)],
320 splitter: &[BoxDynPattern],
321 level: usize,
322 ) -> Result<(usize, MatchedQueue), Error> {
323 let mut index = 0;
324 let total = chars.len();
325 let mut matched: MatchedQueue = Vec::with_capacity(until.len() + 1);
326 while index < total {
327 let next_chars = &chars[index..];
328 if let Some((_, len, _)) = Rule::exec_queues(splitter, next_chars) {
329 index += len;
330 continue;
331 }
332 let mut finded = false;
333 for (_, r) in rules.iter() {
334 if let Some((_, len, queue_num)) = r.exec(next_chars) {
335 let queues = &r.queues;
336 index += len;
338 if queue_num == queues.len() {
339 finded = true;
341 } else {
342 let (nest_count, _) = Selector::parse_until(
343 &chars[index..],
344 &queues[queue_num + 1..],
345 rules,
346 splitter,
347 level + 1,
348 )?;
349 index += nest_count;
350 }
351 break;
352 }
353 }
354 if !finded {
355 if level == 0 {
356 matched.push(Matched {
357 chars: chars[0..index].to_vec(),
358 name: "selector",
359 ..Default::default()
360 });
361 }
362 if !until.is_empty() {
363 let (util_matched, count, queue_num, _) = exec(until, &chars[index..]);
364 if queue_num != until.len() {
365 let context = chars[index..].iter().collect::<String>();
366 return Err(Error::InvalidSelector {
367 context,
368 reason: format!("Nested selector parse error at index {}", index),
369 });
370 } else {
371 index += count;
372 if level == 0 {
373 matched.extend(util_matched);
374 }
375 }
376 }
377 break;
378 }
379 }
380 Ok((index, matched))
381 }
382}
383
384#[derive(PartialEq, Eq, Clone, Copy, Debug)]
385enum PrevInSelector {
386 Begin,
387 Splitter,
388 Selector,
389}
390
391impl FromStr for Selector {
392 type Err = Error;
393 fn from_str(selector: &str) -> Result<Self, Self::Err> {
394 Selector::from_str(selector, true)
395 }
396}
397
398#[cfg(test)]
399mod tests {
400 use super::{Combinator, QueryProcess, Selector};
401 #[test]
402 fn test_default() {
403 let def_selector = Selector::default();
404 assert!(def_selector.process.is_empty());
405 let def_process = QueryProcess::default();
406 assert!(def_process.should_in.is_none());
407 assert!(def_process.query.is_empty());
408 }
409 #[test]
410 fn test_combinator() {
411 let comb: Combinator = ">".into();
412 assert_eq!(comb, Combinator::Children);
413 assert_eq!(comb.reverse(), Combinator::Parent);
414 }
415
416 #[test]
417 fn test_combinator_reverse() {
418 assert_eq!(Combinator::Chain.reverse(), Combinator::Chain);
419 }
420
421 #[test]
422 #[should_panic]
423 fn test_combinator_unable_reverse() {
424 let _ = Combinator::Parent.reverse();
425 }
426
427 #[test]
428 #[should_panic]
429 fn test_wrong_combinator_string() {
430 let _: Combinator = "<".into();
431 }
432}