tatara_lisp_script/stdlib/
string_ext.rs1use std::sync::Arc;
13
14use tatara_lisp_eval::{Arity, EvalError, Interpreter, Value};
15
16use crate::script_ctx::ScriptCtx;
17use crate::stdlib::env::{int_arg, str_arg};
18
19pub fn install(interp: &mut Interpreter<ScriptCtx>) {
20 interp.register_fn(
21 "string-starts-with?",
22 Arity::Exact(2),
23 |args: &[Value], _ctx: &mut ScriptCtx, sp| {
24 let s = str_arg(&args[0], "string-starts-with?", sp)?;
25 let pfx = str_arg(&args[1], "string-starts-with?", sp)?;
26 Ok(Value::Bool(s.starts_with(&*pfx)))
27 },
28 );
29
30 interp.register_fn(
31 "string-ends-with?",
32 Arity::Exact(2),
33 |args: &[Value], _ctx: &mut ScriptCtx, sp| {
34 let s = str_arg(&args[0], "string-ends-with?", sp)?;
35 let sfx = str_arg(&args[1], "string-ends-with?", sp)?;
36 Ok(Value::Bool(s.ends_with(&*sfx)))
37 },
38 );
39
40 interp.register_fn(
41 "string-repeat",
42 Arity::Exact(2),
43 |args: &[Value], _ctx: &mut ScriptCtx, sp| {
44 let s = str_arg(&args[0], "string-repeat", sp)?;
45 let n = int_arg(&args[1], "string-repeat", sp)?.max(0) as usize;
46 Ok(Value::Str(Arc::from(s.repeat(n))))
47 },
48 );
49
50 interp.register_fn(
51 "string-reverse",
52 Arity::Exact(1),
53 |args: &[Value], _ctx: &mut ScriptCtx, sp| {
54 let s = str_arg(&args[0], "string-reverse", sp)?;
55 Ok(Value::Str(Arc::from(s.chars().rev().collect::<String>())))
56 },
57 );
58
59 interp.register_fn(
60 "string-join",
61 Arity::Exact(2),
62 |args: &[Value], _ctx: &mut ScriptCtx, sp| {
63 let sep = str_arg(&args[0], "string-join", sp)?;
64 let xs = match &args[1] {
65 Value::List(xs) => xs.clone(),
66 Value::Nil => Arc::new(Vec::new()),
67 other => {
68 return Err(EvalError::native_fn(
69 "string-join",
70 format!("expected list, got {}", other.type_name()),
71 sp,
72 ))
73 }
74 };
75 let parts: Vec<String> = xs
76 .iter()
77 .map(|v| match v {
78 Value::Str(s) => s.as_ref().to_owned(),
79 Value::Int(n) => n.to_string(),
80 Value::Float(n) => n.to_string(),
81 Value::Bool(b) => b.to_string(),
82 Value::Nil => String::new(),
83 Value::Symbol(s) | Value::Keyword(s) => s.as_ref().to_owned(),
84 other => format!("{other:?}"),
85 })
86 .collect();
87 Ok(Value::Str(Arc::from(parts.join(&sep))))
88 },
89 );
90
91 interp.register_fn(
92 "string-chars",
93 Arity::Exact(1),
94 |args: &[Value], _ctx: &mut ScriptCtx, sp| {
95 let s = str_arg(&args[0], "string-chars", sp)?;
96 Ok(Value::list(
97 s.chars()
98 .map(|c| Value::Str(Arc::from(c.to_string())))
99 .collect::<Vec<_>>(),
100 ))
101 },
102 );
103
104 interp.register_fn(
105 "string-bytes",
106 Arity::Exact(1),
107 |args: &[Value], _ctx: &mut ScriptCtx, sp| {
108 let s = str_arg(&args[0], "string-bytes", sp)?;
109 Ok(Value::list(
110 s.bytes().map(|b| Value::Int(b as i64)).collect::<Vec<_>>(),
111 ))
112 },
113 );
114
115 interp.register_fn(
116 "string-uppercase",
117 Arity::Exact(1),
118 |args: &[Value], _ctx: &mut ScriptCtx, sp| {
119 let s = str_arg(&args[0], "string-uppercase", sp)?;
120 Ok(Value::Str(Arc::from(s.to_uppercase())))
121 },
122 );
123}