tatara_lisp_script/stdlib/
env.rs1use std::sync::Arc;
17
18use tatara_lisp_eval::{Arity, EvalError, Interpreter, Value};
19
20use crate::script_ctx::ScriptCtx;
21
22pub fn install(interp: &mut Interpreter<ScriptCtx>) {
23 interp.register_fn(
24 "env-get",
25 Arity::Range(1, 2),
26 |args: &[Value], _ctx: &mut ScriptCtx, sp| {
27 let name = str_arg(&args[0], "env-get", sp)?;
28 match std::env::var(&*name) {
29 Ok(v) => Ok(Value::Str(Arc::from(v))),
30 Err(_) => Ok(args.get(1).cloned().unwrap_or(Value::Nil)),
31 }
32 },
33 );
34
35 interp.register_fn(
36 "env-required",
37 Arity::Exact(1),
38 |args: &[Value], _ctx: &mut ScriptCtx, sp| {
39 let name = str_arg(&args[0], "env-required", sp)?;
40 std::env::var(&*name)
41 .map(|v| Value::Str(Arc::from(v)))
42 .map_err(|_| {
43 EvalError::native_fn(
44 "env-required",
45 format!("environment variable {name} is not set"),
46 sp,
47 )
48 })
49 },
50 );
51
52 interp.register_fn(
53 "env-set",
54 Arity::Exact(2),
55 |args: &[Value], _ctx: &mut ScriptCtx, sp| {
56 let name = str_arg(&args[0], "env-set", sp)?;
57 let value = str_arg(&args[1], "env-set", sp)?;
58 unsafe {
65 std::env::set_var(&*name, &*value);
66 }
67 Ok(Value::Nil)
68 },
69 );
70
71 interp.register_fn(
72 "argv",
73 Arity::Exact(0),
74 |_args: &[Value], ctx: &mut ScriptCtx, _sp| {
75 Ok(Value::list(
76 ctx.argv
77 .iter()
78 .map(|s| Value::Str(Arc::from(s.as_str())))
79 .collect::<Vec<_>>(),
80 ))
81 },
82 );
83
84 interp.register_fn(
85 "argv-get",
86 Arity::Range(1, 2),
87 |args: &[Value], ctx: &mut ScriptCtx, sp| {
88 let n = int_arg(&args[0], "argv-get", sp)?;
89 if n < 0 {
90 return Err(EvalError::native_fn(
91 "argv-get",
92 format!("index must be >= 0, got {n}"),
93 sp,
94 ));
95 }
96 let idx = n as usize;
97 if idx < ctx.argv.len() {
98 Ok(Value::Str(Arc::from(ctx.argv[idx].as_str())))
99 } else {
100 Ok(args.get(1).cloned().unwrap_or(Value::Nil))
101 }
102 },
103 );
104}
105
106pub(crate) fn str_arg(
107 v: &Value,
108 fname: &'static str,
109 sp: tatara_lisp::Span,
110) -> Result<Arc<str>, EvalError> {
111 match v {
112 Value::Str(s) => Ok(s.clone()),
113 other => Err(EvalError::type_mismatch("string", other.type_name(), sp))
114 .map_err(|e| EvalError::native_fn(fname, format!("expected string, got {e:?}"), sp)),
115 }
116}
117
118pub(crate) fn int_arg(
119 v: &Value,
120 fname: &'static str,
121 sp: tatara_lisp::Span,
122) -> Result<i64, EvalError> {
123 match v {
124 Value::Int(n) => Ok(*n),
125 other => Err(EvalError::native_fn(
126 fname,
127 format!("expected integer, got {}", other.type_name()),
128 sp,
129 )),
130 }
131}