1use crate::mtry;
2use crate::ArgSpec;
3use crate::NativeModule;
4use crate::RcStr;
5use crate::Value;
6use regex::Regex;
7
8pub const NAME: &str = "a.regex";
9
10pub(super) fn new() -> NativeModule {
11 NativeModule::new(NAME, |m| {
12 m.class::<Regex, _>("Regex", |cls| {
13 cls.doc("Binding to Rust/Cargo's 'regex' crate");
14 cls.sfunc("__call", ["pattern"], "", |globals, args, _| {
15 let mut args = args.into_iter();
16 let pattern = args.next().unwrap().into_string()?;
17 let re = mtry!(Regex::new(&pattern));
18 globals.new_handle::<Regex>(re).map(From::from)
19 });
20 cls.ifunc(
21 "find",
22 ArgSpec::builder()
23 .req("text")
24 .def("start", ())
25 .def("end", ()),
26 "",
27 |owner, globals, args, _| {
28 let mut args = args.into_iter();
29 let text = args.next().unwrap().into_string()?;
30 let len = text.len();
31 let start = args.next().unwrap().to_start_index(len)?;
32 let end = args.next().unwrap().to_end_index(len)?;
33 let match_ = owner.borrow().find(&text[start..end]);
34 Ok(match match_ {
35 Some(match_) => globals
36 .new_handle(OwnedMatch {
37 text: text.clone(),
38 start: start + match_.start(),
39 end: start + match_.end(),
40 })?
41 .into(),
42 None => Value::Nil,
43 })
44 },
45 );
46 cls.ifunc(
47 "replace",
48 ["text", "replacement"],
49 "",
50 |owner, _globals, args, _| {
51 let mut args = args.into_iter();
52 let text = args.next().unwrap().into_string()?;
53 let replacement = args.next().unwrap().into_string()?;
54 Ok(owner
55 .borrow()
56 .replace(&text, replacement.str())
57 .into_owned()
58 .into())
59 },
60 );
61 });
62 m.class::<OwnedMatch, _>("Match", |cls| {
63 cls.str(|match_| match_.str().into());
64 cls.repr(|match_| format!("Match({:?})", match_.str()).into());
65 cls.ifunc("start", (), "", |owner, _, _, _| {
66 Ok(owner.borrow().start.into())
67 });
68 cls.ifunc("end", (), "", |owner, _, _, _| {
69 Ok(owner.borrow().end.into())
70 });
71 cls.ifunc("str", (), "", |owner, _, _, _| {
72 Ok(owner.borrow().str().into())
73 });
74 });
75 })
76}
77
78pub struct OwnedMatch {
79 text: RcStr,
80 start: usize,
81 end: usize,
82}
83
84impl OwnedMatch {
85 pub fn str(&self) -> &str {
86 &self.text[self.start..self.end]
87 }
88}