1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
use std::{collections::BTreeMap, io::Write, thread::JoinHandle, time::Duration};

use adana_script_core::{
    primitive::{Compiler, NativeFunctionCallResult, Primitive},
    Value,
};

#[no_mangle]
pub fn environ(params: Vec<Primitive>, _compiler: Box<Compiler>) -> NativeFunctionCallResult {
    if params.is_empty() {
        let s = std::env::vars()
            .map(|(k, v)| (k, Primitive::String(v)))
            .collect::<BTreeMap<_, _>>();
        Ok(Primitive::Struct(s))
    } else {
        let r = std::env::var(params[0].to_string())
            .ok()
            .map(Primitive::String)
            .unwrap_or_else(|| Primitive::Null);
        Ok(r)
    }
}
#[no_mangle]
pub fn delay(mut params: Vec<Primitive>, mut compiler: Box<Compiler>) -> NativeFunctionCallResult {
    if params.is_empty() {
        Err(anyhow::anyhow!("at least one parameter must be provided"))
    } else {
        let delay = match params.remove(0) {
            Primitive::Int(delay) if delay >= 0 => delay as u64,
            Primitive::U8(delay) => delay as u64,
            Primitive::I8(delay) if delay >= 0 => delay as u64,
            e => {
                return Err(anyhow::anyhow!(
                    "first parameter must be the sleep duration (int) => {e}"
                ))
            }
        };

        if params.is_empty() {
            std::thread::sleep(Duration::from_millis(delay as u64));
            Ok(Primitive::Unit)
        } else if params.len() == 2 {
            let handle: JoinHandle<anyhow::Result<()>> = std::thread::spawn(move || {
                std::thread::sleep(Duration::from_millis(delay as u64));

                let f @ Primitive::Function { .. } = params.remove(0) else {
                    return Err(anyhow::anyhow!("second parameter must be a function"));
                };
                let Primitive::Struct(ctx) = params.remove(0) else {
                    return Err(anyhow::anyhow!(
                        "third parameter must be the context (struct)"
                    ));
                };
                let function = f.to_value()?;
                let ctx = ctx
                    .into_iter()
                    .map(|(k, v)| (k, v.ref_prim()))
                    .collect::<BTreeMap<_, _>>();

                let parameters = ctx.keys().cloned().map(Value::String).collect::<Vec<_>>();
                compiler(
                    Value::FunctionCall {
                        parameters: Box::new(Value::BlockParen(parameters)),
                        function: Box::new(function),
                    },
                    ctx,
                )?;
                std::io::stdout().flush()?;
                Ok(())
            });
            std::thread::spawn(move || match handle.join() {
                Ok(Ok(())) => {}
                e => eprintln!("{e:?}"),
            });
            Ok(Primitive::Unit)
        } else {
            Err(anyhow::anyhow!("too many arguments"))
        }
    }
}
/// Api description
#[no_mangle]
pub fn api_description(
    _params: Vec<Primitive>,
    _compiler: Box<Compiler>,
) -> NativeFunctionCallResult {
    Ok(Primitive::Struct(BTreeMap::from([(
        "environ".into(),
        Primitive::String(
            "environ(string) -> struct | string, takes an optional key, return environment variable(s)"
                .into(),
        )),
        ("delay".into(),
        Primitive::String(
            r#"delay(int, function, ctx) -> () | sleep for a specified amount of time. 
            Takes optional function and immutable context (struct) as callback.
            e.g : 
               f = () => {
                    e = process.environ("WEZTERM_PANE")
                    if(e!= null) {
                        println("found env: " + e)
                    }
               }
               s = struct {}
               process.delay(1000, f, s)
               "#
            .into(),
        )),
    ])))
}