tatara_lisp_script/stdlib/
regex.rs1use std::sync::Arc;
13
14use regex::Regex;
15use tatara_lisp_eval::{Arity, EvalError, Interpreter, Value};
16
17use crate::script_ctx::ScriptCtx;
18use crate::stdlib::env::str_arg;
19
20pub fn install(interp: &mut Interpreter<ScriptCtx>) {
21 interp.register_fn(
22 "re-match?",
23 Arity::Exact(2),
24 |args: &[Value], _ctx: &mut ScriptCtx, sp| {
25 let re = compile(&args[0], sp)?;
26 let s = str_arg(&args[1], "re-match?", sp)?;
27 Ok(Value::Bool(re.is_match(&s)))
28 },
29 );
30
31 interp.register_fn(
32 "re-find",
33 Arity::Exact(2),
34 |args: &[Value], _ctx: &mut ScriptCtx, sp| {
35 let re = compile(&args[0], sp)?;
36 let s = str_arg(&args[1], "re-find", sp)?;
37 Ok(re
38 .find(&s)
39 .map(|m| Value::Str(Arc::from(m.as_str())))
40 .unwrap_or(Value::Nil))
41 },
42 );
43
44 interp.register_fn(
45 "re-find-all",
46 Arity::Exact(2),
47 |args: &[Value], _ctx: &mut ScriptCtx, sp| {
48 let re = compile(&args[0], sp)?;
49 let s = str_arg(&args[1], "re-find-all", sp)?;
50 Ok(Value::list(
51 re.find_iter(&s)
52 .map(|m| Value::Str(Arc::from(m.as_str())))
53 .collect::<Vec<_>>(),
54 ))
55 },
56 );
57
58 interp.register_fn(
59 "re-captures",
60 Arity::Exact(2),
61 |args: &[Value], _ctx: &mut ScriptCtx, sp| {
62 let re = compile(&args[0], sp)?;
63 let s = str_arg(&args[1], "re-captures", sp)?;
64 let Some(caps) = re.captures(&s) else {
65 return Ok(Value::Nil);
66 };
67 let groups: Vec<Value> = caps
68 .iter()
69 .map(|m| m.map_or(Value::Nil, |m| Value::Str(Arc::from(m.as_str()))))
70 .collect();
71 Ok(Value::list(groups))
72 },
73 );
74
75 interp.register_fn(
76 "re-replace",
77 Arity::Exact(3),
78 |args: &[Value], _ctx: &mut ScriptCtx, sp| {
79 let re = compile(&args[0], sp)?;
80 let s = str_arg(&args[1], "re-replace", sp)?;
81 let repl = str_arg(&args[2], "re-replace", sp)?;
82 Ok(Value::Str(Arc::from(
83 re.replace_all(&s, &*repl).into_owned(),
84 )))
85 },
86 );
87
88 interp.register_fn(
89 "re-split",
90 Arity::Exact(2),
91 |args: &[Value], _ctx: &mut ScriptCtx, sp| {
92 let re = compile(&args[0], sp)?;
93 let s = str_arg(&args[1], "re-split", sp)?;
94 Ok(Value::list(
95 re.split(&s)
96 .map(|p| Value::Str(Arc::from(p)))
97 .collect::<Vec<_>>(),
98 ))
99 },
100 );
101}
102
103fn compile(v: &Value, sp: tatara_lisp::Span) -> Result<Regex, EvalError> {
104 let pat = str_arg(v, "regex", sp)?;
105 Regex::new(&pat)
106 .map_err(|e| EvalError::native_fn("regex", format!("bad pattern {pat:?}: {e}"), sp))
107}