1use crate::{PersistentVector, Value};
2use cljrs_gc::{GcPtr, GcVisitor, MarkVisitor, Trace};
3use regex::{Captures, Regex};
4use std::sync::Mutex;
5
6#[derive(Debug, Clone)]
7pub enum MatchPhase {
8 New,
9 Matching(usize),
10 Complete,
11}
12
13#[derive(Debug, Clone)]
14struct MatcherState {
15 phase: MatchPhase,
16 last_match: Option<MatchResult>,
17}
18
19#[derive(Debug)]
20pub struct Matcher {
21 pub pattern: GcPtr<Regex>,
22 haystack: GcPtr<String>,
23 state: Mutex<MatcherState>,
24 match_all: bool,
25}
26
27#[derive(Debug, Clone)]
28pub struct MatchResult {
29 pub full: String,
30 pub groups: Vec<Option<String>>,
31}
32
33impl Clone for Matcher {
34 fn clone(&self) -> Matcher {
35 let state = self.state.lock().unwrap().clone();
36 Matcher {
37 pattern: self.pattern.clone(),
38 haystack: self.haystack.clone(),
39 state: Mutex::new(state.clone()),
40 match_all: self.match_all,
41 }
42 }
43}
44
45impl Trace for Matcher {
46 fn trace(&self, visitor: &mut MarkVisitor) {
47 visitor.visit(&self.pattern);
48 visitor.visit(&self.haystack);
49 }
50}
51
52impl Matcher {
53 pub fn new(pattern: Regex, source: String, match_all: bool) -> Self {
54 Self {
55 pattern: GcPtr::new(pattern),
56 haystack: GcPtr::new(source),
57 state: Mutex::new(MatcherState {
58 phase: MatchPhase::New,
59 last_match: None,
60 }),
61 match_all,
62 }
63 }
64
65 pub fn next(&self) -> MatchPhase {
66 let mut state = self.state.lock().unwrap();
67 match state.phase {
68 MatchPhase::New => match self.pattern.get().captures(self.haystack.get()) {
69 Some(cap) => {
70 if !self.match_all || cap.len() == self.haystack.get().len() {
71 let match_ = cap.get_match();
72 *state = MatcherState {
73 phase: MatchPhase::Matching(match_.end()),
74 last_match: Some(MatchResult::new(cap)),
75 }
76 }
77 }
78 None => {
79 *state = MatcherState {
80 phase: MatchPhase::Complete,
81 last_match: None,
82 }
83 }
84 },
85 MatchPhase::Matching(n) => {
86 match self.pattern.get().captures_at(self.haystack.get(), n) {
87 Some(cap) => {
88 *state = MatcherState {
89 phase: MatchPhase::Matching(cap.get_match().end()),
90 last_match: Some(MatchResult::new(cap)),
91 }
92 }
93 None => {
94 *state = MatcherState {
95 phase: MatchPhase::Complete,
96 last_match: None,
97 };
98 }
99 }
100 }
101 MatchPhase::Complete => {}
102 }
103 state.phase.clone()
104 }
105
106 pub fn capture(&self) -> Option<MatchResult> {
107 let state = self.state.lock().unwrap();
108 state.last_match.clone()
109 }
110
111 pub fn phase(&self) -> MatchPhase {
112 self.state.lock().unwrap().phase.clone()
113 }
114}
115
116impl MatchResult {
117 pub fn new(cap: Captures) -> Self {
118 Self {
119 full: cap.get_match().as_str().to_string(),
120 groups: cap
121 .iter()
122 .map(|g| g.map(|e| e.as_str().to_string()))
123 .collect(),
124 }
125 }
126
127 pub fn to_value(&self) -> Value {
128 if self.groups.len() == 1 || self.groups.iter().skip(1).all(|g| g.is_none()) {
129 Value::Str(GcPtr::new(self.full.to_string()))
130 } else {
131 let groups: Vec<Value> = self
132 .groups
133 .iter()
134 .map(|g| match g {
135 Some(m) => Value::Str(GcPtr::new(m.to_string())),
136 None => Value::Nil,
137 })
138 .collect();
139 Value::Vector(GcPtr::new(PersistentVector::from_iter(groups)))
140 }
141 }
142}