1use std::{collections::BTreeMap, io::Write, thread::JoinHandle, time::Duration};
2
3use adana_script_core::{
4 primitive::{Compiler, NativeFunctionCallResult, Primitive},
5 Value,
6};
7
8#[no_mangle]
9pub fn environ(params: Vec<Primitive>, _compiler: Box<Compiler>) -> NativeFunctionCallResult {
10 if params.is_empty() {
11 let s = std::env::vars()
12 .map(|(k, v)| (k, Primitive::String(v)))
13 .collect::<BTreeMap<_, _>>();
14 Ok(Primitive::Struct(s))
15 } else {
16 let r = std::env::var(params[0].to_string())
17 .ok()
18 .map(Primitive::String)
19 .unwrap_or_else(|| Primitive::Null);
20 Ok(r)
21 }
22}
23#[no_mangle]
24pub fn delay(mut params: Vec<Primitive>, mut compiler: Box<Compiler>) -> NativeFunctionCallResult {
25 if params.is_empty() {
26 Err(anyhow::anyhow!("at least one parameter must be provided"))
27 } else {
28 let delay = match params.remove(0) {
29 Primitive::Int(delay) if delay >= 0 => delay as u64,
30 Primitive::U8(delay) => delay as u64,
31 Primitive::I8(delay) if delay >= 0 => delay as u64,
32 e => {
33 return Err(anyhow::anyhow!(
34 "first parameter must be the sleep duration (int) => {e}"
35 ))
36 }
37 };
38
39 if params.is_empty() {
40 std::thread::sleep(Duration::from_millis(delay as u64));
41 Ok(Primitive::Unit)
42 } else if params.len() == 2 {
43 let handle: JoinHandle<anyhow::Result<()>> = std::thread::spawn(move || {
44 std::thread::sleep(Duration::from_millis(delay as u64));
45
46 let f @ Primitive::Function { .. } = params.remove(0) else {
47 return Err(anyhow::anyhow!("second parameter must be a function"));
48 };
49 let Primitive::Struct(ctx) = params.remove(0) else {
50 return Err(anyhow::anyhow!(
51 "third parameter must be the context (struct)"
52 ));
53 };
54 let function = f.to_value()?;
55 let ctx = ctx
56 .into_iter()
57 .map(|(k, v)| (k, v.ref_prim()))
58 .collect::<BTreeMap<_, _>>();
59
60 let parameters = ctx.keys().cloned().map(Value::String).collect::<Vec<_>>();
61 compiler(
62 Value::FunctionCall {
63 parameters: Box::new(Value::BlockParen(parameters)),
64 function: Box::new(function),
65 },
66 ctx,
67 )?;
68 std::io::stdout().flush()?;
69 Ok(())
70 });
71 std::thread::spawn(move || match handle.join() {
72 Ok(Ok(())) => {}
73 e => eprintln!("{e:?}"),
74 });
75 Ok(Primitive::Unit)
76 } else {
77 Err(anyhow::anyhow!("too many arguments"))
78 }
79 }
80}
81#[no_mangle]
83pub fn api_description(
84 _params: Vec<Primitive>,
85 _compiler: Box<Compiler>,
86) -> NativeFunctionCallResult {
87 Ok(Primitive::Struct(BTreeMap::from([(
88 "environ".into(),
89 Primitive::String(
90 "environ(string) -> struct | string, takes an optional key, return environment variable(s)"
91 .into(),
92 )),
93 ("delay".into(),
94 Primitive::String(
95 r#"delay(int, function, ctx) -> () | sleep for a specified amount of time.
96 Takes optional function and immutable context (struct) as callback.
97 e.g :
98 f = () => {
99 e = process.environ("WEZTERM_PANE")
100 if(e!= null) {
101 println("found env: " + e)
102 }
103 }
104 s = struct {}
105 process.delay(1000, f, s)
106 "#
107 .into(),
108 )),
109 ])))
110}