Skip to main content

mailang_stdlib/stdlib/
io.rs

1//! I/O built-in functions
2
3use super::value_to_string;
4use mailang_bytecode::Value;
5use std::io::{self, Write};
6
7#[cfg(feature = "capture-output")]
8use super::capture;
9
10pub fn builtin_println(args: &[Value]) -> Result<Value, String> {
11    let parts: Vec<String> = args.iter().map(value_to_string).collect();
12    let line = parts.join(" ");
13
14    #[cfg(feature = "capture-output")]
15    {
16        if capture::is_captured() {
17            capture::push_line(line);
18            return Ok(Value::Null);
19        }
20    }
21
22    println!("{}", line);
23    Ok(Value::Null)
24}
25
26pub fn builtin_print(args: &[Value]) -> Result<Value, String> {
27    let parts: Vec<String> = args.iter().map(value_to_string).collect();
28    let text = parts.join(" ");
29
30    #[cfg(feature = "capture-output")]
31    {
32        if capture::is_captured() {
33            capture::push_text(text);
34            return Ok(Value::Null);
35        }
36    }
37
38    print!("{}", text);
39    io::stdout().flush().map_err(|e| e.to_string())?;
40    Ok(Value::Null)
41}
42
43pub fn builtin_input(args: &[Value]) -> Result<Value, String> {
44    if !args.is_empty() {
45        print!("{}", value_to_string(&args[0]));
46        io::stdout().flush().map_err(|e| e.to_string())?;
47    }
48    let mut input = String::new();
49    io::stdin()
50        .read_line(&mut input)
51        .map_err(|e| e.to_string())?;
52    Ok(Value::Str(input.trim_end().into()))
53}
54
55/// `read_file(path)` → str contents (host filesystem).
56pub fn builtin_read_file(args: &[Value]) -> Result<Value, String> {
57    let path = match args.first() {
58        Some(Value::Str(p)) => p.to_string(),
59        _ => return Err("read_file(path): path must be a string".into()),
60    };
61    let data = std::fs::read_to_string(&path).map_err(|e| format!("read_file: {e}"))?;
62    Ok(Value::Str(data.into()))
63}
64
65/// `write_file(path, contents)` → null.
66pub fn builtin_write_file(args: &[Value]) -> Result<Value, String> {
67    let path = match args.first() {
68        Some(Value::Str(p)) => p.to_string(),
69        _ => return Err("write_file(path, contents): path must be a string".into()),
70    };
71    let data = match args.get(1) {
72        Some(v) => value_to_string(v),
73        None => String::new(),
74    };
75    std::fs::write(&path, data).map_err(|e| format!("write_file: {e}"))?;
76    Ok(Value::Null)
77}