Skip to main content

cljrs_value/
regex.rs

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}