tatara_lisp_script/stdlib/
yaml.rs1use std::sync::Arc;
9
10use tatara_lisp_eval::{Arity, EvalError, Interpreter, Value};
11
12use crate::script_ctx::ScriptCtx;
13use crate::stdlib::env::str_arg;
14
15pub fn install(interp: &mut Interpreter<ScriptCtx>) {
16 interp.register_fn(
17 "yaml-parse",
18 Arity::Exact(1),
19 |args: &[Value], _ctx: &mut ScriptCtx, sp| {
20 let s = str_arg(&args[0], "yaml-parse", sp)?;
21 let parsed: serde_yaml::Value = serde_yaml::from_str(&s)
22 .map_err(|e| EvalError::native_fn("yaml-parse", e.to_string(), sp))?;
23 Ok(yaml_to_value(&parsed))
24 },
25 );
26
27 interp.register_fn(
28 "yaml-read",
29 Arity::Exact(1),
30 |args: &[Value], _ctx: &mut ScriptCtx, sp| {
31 let path = str_arg(&args[0], "yaml-read", sp)?;
32 let body = std::fs::read_to_string(&*path)
33 .map_err(|e| EvalError::native_fn("yaml-read", format!("{path}: {e}"), sp))?;
34 let parsed: serde_yaml::Value = serde_yaml::from_str(&body)
35 .map_err(|e| EvalError::native_fn("yaml-read", format!("{path}: {e}"), sp))?;
36 Ok(yaml_to_value(&parsed))
37 },
38 );
39}
40
41fn yaml_to_value(y: &serde_yaml::Value) -> Value {
42 match y {
43 serde_yaml::Value::Null => Value::Nil,
44 serde_yaml::Value::Bool(b) => Value::Bool(*b),
45 serde_yaml::Value::Number(n) => {
46 if let Some(i) = n.as_i64() {
47 Value::Int(i)
48 } else {
49 Value::Float(n.as_f64().unwrap_or(0.0))
50 }
51 }
52 serde_yaml::Value::String(s) => Value::Str(Arc::from(s.as_str())),
53 serde_yaml::Value::Sequence(xs) => {
54 Value::list(xs.iter().map(yaml_to_value).collect::<Vec<_>>())
55 }
56 serde_yaml::Value::Mapping(m) => Value::list(
57 m.iter()
58 .map(|(k, v)| {
59 let key_str = match k {
60 serde_yaml::Value::String(s) => s.clone(),
61 other => serde_yaml::to_string(other)
62 .unwrap_or_default()
63 .trim()
64 .to_string(),
65 };
66 Value::list(vec![Value::Str(Arc::from(key_str)), yaml_to_value(v)])
67 })
68 .collect::<Vec<_>>(),
69 ),
70 serde_yaml::Value::Tagged(t) => yaml_to_value(&t.value),
71 }
72}