sphinx/lexer/rules/
strmatcher.rs1use core::str::Chars;
2use std::collections::VecDeque;
3
4use crate::lexer::rules::MatchResult;
5
6#[derive(Clone, Copy)]
9pub enum MatchCase {
10 Sensitive,
11 AsciiInsensitive,
12 }
14
15#[derive(Clone)]
16pub struct StrMatcher<'a> {
17 target: &'a str,
18 match_case: MatchCase,
19
20 chars: Chars<'a>,
21 peek: VecDeque<Option<char>>,
22
23 last_result: MatchResult,
24 count: usize, }
26
27impl<'a> StrMatcher<'a> {
28 pub fn new(target: &'a str, match_case: MatchCase) -> Self {
29 StrMatcher {
30 target,
31 match_case,
32
33 chars: target.chars(),
34 peek: VecDeque::new(),
35
36 last_result: MatchResult::IncompleteMatch,
37 count: 0,
38 }
39 }
40 pub fn case_sensitive(target: &'a str) -> Self { StrMatcher::new(target, MatchCase::Sensitive) }
41 pub fn ascii_case_insensitive(target: &'a str) -> Self { StrMatcher::new(target, MatchCase::AsciiInsensitive) }
42
43
44 pub fn target(&self) -> &'a str { self.target }
45 pub fn match_case(&self) -> MatchCase { self.match_case }
46
47 pub fn last_match_result(&self) -> MatchResult { self.last_result }
48 pub fn count(&self) -> usize { self.count }
49
50 pub fn reset(&mut self) {
51 self.last_result = MatchResult::IncompleteMatch;
52 self.chars = self.target.chars();
53 self.peek.clear();
54 self.count = 0;
55 }
56
57 pub fn reset_target(&mut self, target: &'a str) {
58 self.target = target;
59 self.reset();
60 }
61
62 fn peek_nth(&mut self, n: usize) -> Option<char> {
63 while self.peek.len() < n + 1 {
64 self.peek.push_back(self.chars.next());
65 }
66 self.peek[n]
67 }
68
69 fn advance(&mut self) -> Option<char> {
70 self.count += 1;
71 match self.peek.pop_front() {
72 Some(o) => o,
73 None => self.chars.next()
74 }
75 }
76
77 fn compare_chars(&self, a: &char, b: &char) -> bool {
78 match self.match_case {
79 MatchCase::Sensitive => a == b,
80 MatchCase::AsciiInsensitive => a.eq_ignore_ascii_case(b),
81 }
82 }
83
84 pub fn peek_match(&mut self, next: char) -> MatchResult {
85 if !self.last_result.is_match() {
87 return MatchResult::NoMatch;
88 }
89
90 match self.peek_nth(0) {
91 Some(this_ch) if self.compare_chars(&this_ch, &next) => {
92 if self.peek_nth(1).is_none() {
93 MatchResult::CompleteMatch
94 } else {
95 MatchResult::IncompleteMatch
96 }
97 },
98 _ => MatchResult::NoMatch,
99 }
100 }
101
102 pub fn update_match(&mut self, next: char) -> MatchResult {
103 self.last_result = self.peek_match(next);
104 self.advance();
105
106 self.last_result
107 }
108
109 pub fn try_match(&mut self, next: char) -> MatchResult {
110 let match_result = self.peek_match(next);
111 if match_result.is_match() {
112 self.last_result = match_result;
113 self.advance();
114 }
115 match_result
116 }
117
118}