Skip to main content

tatara_lisp_script/stdlib/
io.rs

1//! File I/O + stdout/stderr.
2//!
3//!   (print-line STR)              → STR to stdout + newline, returns nil
4//!   (eprint-line STR)             → STR to stderr + newline, returns nil
5//!   (read-file PATH)              → file contents as string
6//!   (write-file PATH STR)         → nil (truncates if exists)
7//!   (path-exists? PATH)           → bool
8//!   (exit CODE)                   → never returns; terminates process
9
10use std::sync::Arc;
11
12use tatara_lisp_eval::{Arity, EvalError, Interpreter, Value};
13
14use crate::script_ctx::ScriptCtx;
15use crate::stdlib::env::{int_arg, str_arg};
16
17pub fn install(interp: &mut Interpreter<ScriptCtx>) {
18    interp.register_fn(
19        "print-line",
20        Arity::Exact(1),
21        |args: &[Value], _ctx: &mut ScriptCtx, sp| {
22            let s = str_arg(&args[0], "print-line", sp)?;
23            println!("{s}");
24            Ok(Value::Nil)
25        },
26    );
27
28    interp.register_fn(
29        "eprint-line",
30        Arity::Exact(1),
31        |args: &[Value], _ctx: &mut ScriptCtx, sp| {
32            let s = str_arg(&args[0], "eprint-line", sp)?;
33            eprintln!("{s}");
34            Ok(Value::Nil)
35        },
36    );
37
38    interp.register_fn(
39        "read-file",
40        Arity::Exact(1),
41        |args: &[Value], _ctx: &mut ScriptCtx, sp| {
42            let path = str_arg(&args[0], "read-file", sp)?;
43            let contents = std::fs::read_to_string(&*path)
44                .map_err(|e| EvalError::native_fn("read-file", format!("{path}: {e}"), sp))?;
45            Ok(Value::Str(Arc::from(contents)))
46        },
47    );
48
49    interp.register_fn(
50        "write-file",
51        Arity::Exact(2),
52        |args: &[Value], _ctx: &mut ScriptCtx, sp| {
53            let path = str_arg(&args[0], "write-file", sp)?;
54            let body = str_arg(&args[1], "write-file", sp)?;
55            std::fs::write(&*path, body.as_bytes())
56                .map_err(|e| EvalError::native_fn("write-file", format!("{path}: {e}"), sp))?;
57            Ok(Value::Nil)
58        },
59    );
60
61    interp.register_fn(
62        "path-exists?",
63        Arity::Exact(1),
64        |args: &[Value], _ctx: &mut ScriptCtx, sp| {
65            let path = str_arg(&args[0], "path-exists?", sp)?;
66            Ok(Value::Bool(std::path::Path::new(&*path).exists()))
67        },
68    );
69
70    interp.register_fn(
71        "exit",
72        Arity::Exact(1),
73        |args: &[Value], _ctx: &mut ScriptCtx, sp| {
74            let code = int_arg(&args[0], "exit", sp)?;
75            std::process::exit(code as i32)
76        },
77    );
78}