Skip to main content

atmos/os_lib/aura/
eval.rs

1use alloc::boxed::Box;
2use alloc::rc::Rc;
3use alloc::string::String;
4use alloc::vec::Vec;
5use core::cell::RefCell;
6
7use super::builtins;
8use super::number::{BigInt, Complex, Ratio};
9use super::parser::AST;
10
11#[derive(Clone)]
12pub enum StreamCore {
13    Range {
14        current: BigInt,
15        end: Option<BigInt>,
16        step: BigInt,
17    },
18    Map {
19        source: Box<Value>,
20        func: Box<Value>,
21        env: Box<Env>,
22    },
23    Filter {
24        source: Box<Value>,
25        func: Box<Value>,
26        env: Box<Env>,
27    },
28}
29
30#[derive(Clone)]
31pub enum Value {
32    Num(BigInt),
33    Ratio(Ratio),
34    Str(String),
35    Symbol(String),
36    List(Vec<Value>),
37    BuiltinFunc(fn(&mut Env, &[AST]) -> Result<Value, String>),
38    Thunk(AST, Box<Env>),               // Lazy evaluation thunk
39    Lambda(Vec<String>, AST, Box<Env>), // User-defined function
40    Bool(bool),
41    Complex(Complex),
42    Dict(alloc::collections::BTreeMap<String, Value>),
43    Stream(Rc<RefCell<StreamCore>>),
44    Nil,
45}
46
47impl StreamCore {
48    // Iterator::next とはシグネチャ(Result を返す)が異なる独自イテレータ。
49    #[allow(clippy::should_implement_trait)]
50    pub fn next(&mut self) -> Result<Option<Value>, String> {
51        match self {
52            StreamCore::Range { current, end, step } => {
53                if let Some(e) = end {
54                    if current >= e {
55                        return Ok(None);
56                    }
57                }
58                let val = current.clone();
59                *current = current.add(step);
60                Ok(Some(Value::Num(val)))
61            }
62            StreamCore::Map {
63                source,
64                func,
65                env: _,
66            } => {
67                let s = source.clone();
68                // Filter と異なり 1 要素評価して必ず return するためループ構造は不要
69                {
70                    let next_val = if let Value::Stream(rc) = &*s {
71                        rc.borrow_mut().next()?
72                    } else {
73                        return Err(String::from("Map source is not a stream"));
74                    };
75
76                    if let Some(val) = next_val {
77                        // 関数呼び出し
78                        match &**func {
79                            Value::Lambda(arg_names, body_ast, closure_env) => {
80                                if arg_names.len() != 1 {
81                                    return Err(String::from(
82                                        "Map function must take exactly 1 argument",
83                                    ));
84                                }
85                                let mut local_env = Env::with_parent(*closure_env.clone());
86                                local_env.set(arg_names[0].clone(), val);
87                                let res = super::eval::eval(&mut local_env, body_ast)?;
88                                Ok(Some(super::eval::force_eval(&mut local_env, res)?))
89                            }
90                            Value::BuiltinFunc(_f) => {
91                                // Builtin function takes AST. We need to wrap `val` back into AST.
92                                // It's tricky to map builtins directly like this, so we recommend lambdas.
93                                // For now, we construct an AST::Symbol and inject it, or just unsupported.
94                                Err(String::from("Map with builtin functions directly is currently not supported for streams, please wrap in lambda"))
95                            }
96                            _ => Err(String::from("Invalid map function")),
97                        }
98                    } else {
99                        Ok(None)
100                    }
101                }
102            }
103            StreamCore::Filter {
104                source,
105                func,
106                env: _,
107            } => {
108                let s = source.clone();
109                loop {
110                    let next_val = if let Value::Stream(rc) = &*s {
111                        rc.borrow_mut().next()?
112                    } else {
113                        return Err(String::from("Filter source is not a stream"));
114                    };
115
116                    if let Some(val) = next_val {
117                        // 関数呼び出しで条件判定
118                        let is_true = match &**func {
119                            Value::Lambda(arg_names, body_ast, closure_env) => {
120                                if arg_names.len() != 1 {
121                                    return Err(String::from(
122                                        "Filter function must take exactly 1 argument",
123                                    ));
124                                }
125                                let mut local_env = Env::with_parent(*closure_env.clone());
126                                local_env.set(arg_names[0].clone(), val.clone());
127                                let res = super::eval::eval(&mut local_env, body_ast)?;
128                                let res = super::eval::force_eval(&mut local_env, res)?;
129                                is_truthy(&res)?
130                            }
131                            _ => return Err(String::from("Invalid filter function")),
132                        };
133
134                        if is_true {
135                            return Ok(Some(val));
136                        }
137                    } else {
138                        return Ok(None);
139                    }
140                }
141            }
142        }
143    }
144}
145
146impl Value {
147    // Aura の表示用整形(選別テストが出力に依存するため Display 化せず温存)。
148    #[allow(clippy::inherent_to_string)]
149    pub fn to_string(&self) -> String {
150        match self {
151            Value::Num(n) => n.to_string(),
152            Value::Ratio(r) => r.to_string(),
153            Value::Str(s) => alloc::format!("\"{}\"", s),
154            Value::Symbol(s) => s.clone(),
155            Value::List(l) => {
156                let mut s = String::from("(");
157                for (i, v) in l.iter().enumerate() {
158                    if i > 0 {
159                        s.push(' ');
160                    }
161                    s.push_str(&v.to_string());
162                }
163                s.push(')');
164                s
165            }
166            Value::BuiltinFunc(_) => String::from("<builtin-function>"),
167            Value::Thunk(_, _) => String::from("<thunk>"),
168            Value::Lambda(_, _, _) => String::from("<lambda-function>"),
169            Value::Bool(b) => {
170                if *b {
171                    String::from("True")
172                } else {
173                    String::from("False")
174                }
175            }
176            Value::Complex(c) => c.to_string(),
177            Value::Dict(d) => {
178                let mut s = String::from("{");
179                for (i, (k, v)) in d.iter().enumerate() {
180                    if i > 0 {
181                        s.push_str(", ");
182                    }
183                    s.push_str(&alloc::format!("\"{}\": {}", k, v.to_string()));
184                }
185                s.push('}');
186                s
187            }
188            Value::Nil => String::from("nil"),
189            Value::Stream(_) => String::from("<stream>"),
190        }
191    }
192}
193
194#[derive(Clone)]
195pub struct OSContext {
196    pub kbd_ptr: *mut crate::kernel::keyboard::Keyboard,
197}
198
199#[derive(Clone)]
200pub struct Env {
201    vars: Vec<(String, Value)>,
202    parent: Option<Box<Env>>,
203    pub context: Option<*mut crate::kernel::keyboard::Keyboard>,
204    pub sandbox: Option<crate::kernel::app_sandbox::AppSandbox>,
205}
206
207impl Default for Env {
208    fn default() -> Self {
209        Self::new()
210    }
211}
212
213impl Env {
214    pub fn new() -> Self {
215        Env {
216            vars: Vec::new(),
217            parent: None,
218            context: None,
219            sandbox: None,
220        }
221    }
222
223    pub fn with_context(kbd: *mut crate::kernel::keyboard::Keyboard) -> Self {
224        Env {
225            vars: Vec::new(),
226            parent: None,
227            context: Some(kbd),
228            sandbox: None,
229        }
230    }
231
232    pub fn with_sandbox(sandbox: crate::kernel::app_sandbox::AppSandbox) -> Self {
233        Env {
234            vars: Vec::new(),
235            parent: None,
236            context: None,
237            sandbox: Some(sandbox),
238        }
239    }
240
241    pub fn with_parent(parent: Env) -> Self {
242        let sandbox = parent.sandbox.clone();
243        Env {
244            vars: Vec::new(),
245            parent: Some(Box::new(parent)),
246            context: None,
247            sandbox,
248        }
249    }
250
251    pub fn set(&mut self, name: String, val: Value) {
252        for (k, v) in self.vars.iter_mut() {
253            if *k == name {
254                *v = val;
255                return;
256            }
257        }
258        self.vars.push((name, val));
259    }
260
261    pub fn get(&self, name: &str) -> Option<Value> {
262        for (k, v) in self.vars.iter().rev() {
263            if k == name {
264                return Some(v.clone());
265            }
266        }
267        if let Some(p) = &self.parent {
268            p.get(name)
269        } else {
270            None
271        }
272    }
273}
274
275pub fn force_eval(_env: &mut Env, val: Value) -> Result<Value, String> {
276    match val {
277        Value::Thunk(ast, mut thunk_env) => eval(&mut thunk_env, &ast),
278        _ => Ok(val),
279    }
280}
281
282pub fn is_truthy(val: &Value) -> Result<bool, String> {
283    match val {
284        Value::Nil => Err(String::from(
285            "TypeError: nil cannot be evaluated as a boolean condition",
286        )),
287        Value::Bool(b) => Ok(*b),
288        Value::Num(n) => Ok(!n.is_zero()),
289        _ => Ok(true),
290    }
291}
292
293pub fn eval(env: &mut Env, ast: &AST) -> Result<Value, String> {
294    match ast {
295        AST::Num(n) => Ok(Value::Num(n.clone())),
296        AST::Ratio(r) => Ok(Value::Ratio(r.clone())),
297        AST::Str(s) => Ok(Value::Str(s.clone())),
298        AST::Symbol(sym) => {
299            if let Some(val) = env.get(sym) {
300                force_eval(env, val)
301            } else if sym.contains('.') {
302                let parts: alloc::vec::Vec<&str> = sym.split('.').collect();
303                if let Some(mut current_val) = env.get(parts[0]) {
304                    current_val = force_eval(env, current_val)?;
305                    for i in 1..parts.len() {
306                        if let Value::Dict(ref d) = current_val {
307                            if let Some(v) = d.get(parts[i]) {
308                                current_val = force_eval(env, v.clone())?;
309                            } else {
310                                return Err(alloc::format!(
311                                    "Key '{}' not found in dictionary",
312                                    parts[i]
313                                ));
314                            }
315                        } else {
316                            return Err(alloc::format!(
317                                "Cannot access '{}' of non-dictionary value",
318                                parts[i]
319                            ));
320                        }
321                    }
322                    Ok(current_val)
323                } else {
324                    Err(alloc::format!(
325                        "Command or variable not found: {}",
326                        parts[0]
327                    ))
328                }
329            } else {
330                let fs = crate::kernel::fs::get_fs();
331                let manifest_path = alloc::format!("/apps/{}/manifest.json", sym);
332                let main_path = alloc::format!("/apps/{}/main.aura", sym);
333                if fs.read_file(&manifest_path).is_some() || fs.read_file(&main_path).is_some() {
334                    let run_args = alloc::vec![AST::Str(sym.clone())];
335                    crate::os_lib::aura::builtins::builtin_run(env, &run_args)
336                } else {
337                    Err(alloc::format!("Command or variable not found: {}", sym))
338                }
339            }
340        }
341        AST::Dict(d) => {
342            let mut dict = alloc::collections::BTreeMap::new();
343            for (k, v_ast) in d {
344                let v = eval(env, v_ast)?;
345                let v = force_eval(env, v)?;
346                dict.insert(k.clone(), v);
347            }
348            Ok(Value::Dict(dict))
349        }
350        AST::List(list) => {
351            if list.is_empty() {
352                return Ok(Value::Nil);
353            }
354            let mut evaluated = Vec::new();
355            for item in list {
356                let val = eval(env, item)?;
357                evaluated.push(force_eval(env, val)?);
358            }
359            Ok(Value::List(evaluated))
360        }
361        AST::FuncCall(func_ast, args) => {
362            // First element must evaluate to a function
363            let func_val = eval(env, func_ast)?;
364            let func_val = force_eval(env, func_val)?;
365
366            match func_val {
367                Value::BuiltinFunc(f) => {
368                    // Pass the rest of the AST directly to the builtin.
369                    // This allows builtins to decide whether to evaluate arguments (lazy/macro).
370                    f(env, args)
371                }
372                Value::Lambda(arg_names, body_ast, closure_env) => {
373                    // Evaluate arguments eagerly
374                    let mut arg_vals = Vec::new();
375                    for arg_ast in args {
376                        let val = eval(env, arg_ast)?;
377                        arg_vals.push(force_eval(env, val)?);
378                    }
379
380                    if arg_vals.len() != arg_names.len() {
381                        return Err(alloc::format!(
382                            "Lambda expected {} arguments, got {}",
383                            arg_names.len(),
384                            arg_vals.len()
385                        ));
386                    }
387
388                    let mut local_env = Env::with_parent(*closure_env.clone());
389                    for (name, val) in arg_names.iter().zip(arg_vals) {
390                        local_env.set(name.clone(), val);
391                    }
392
393                    let res = eval(&mut local_env, &body_ast)?;
394                    force_eval(&mut local_env, res)
395                }
396                Value::List(data) => {
397                    // List called as a function (index or slice access)
398                    let mut evaluated_args = Vec::new();
399                    for arg_ast in args {
400                        let val = eval(env, arg_ast)?;
401                        evaluated_args.push(force_eval(env, val)?);
402                    }
403
404                    if evaluated_args.len() == 1 {
405                        if let Value::Num(n) = &evaluated_args[0] {
406                            let idx = n.to_i64().unwrap_or(-1);
407                            if idx >= 0 && idx < data.len() as i64 {
408                                Ok(data[idx as usize].clone())
409                            } else {
410                                Ok(Value::Nil)
411                            }
412                        } else {
413                            Err(String::from("List index must be a number"))
414                        }
415                    } else if evaluated_args.len() == 2 {
416                        if let (Value::Num(n1), Value::Num(n2)) =
417                            (&evaluated_args[0], &evaluated_args[1])
418                        {
419                            let start =
420                                n1.to_i64().unwrap_or(0).max(0).min(data.len() as i64) as usize;
421                            let end = n2
422                                .to_i64()
423                                .unwrap_or(data.len() as i64)
424                                .max(0)
425                                .min(data.len() as i64)
426                                as usize;
427                            if start <= end {
428                                Ok(Value::List(data[start..end].to_vec()))
429                            } else {
430                                Ok(Value::List(Vec::new()))
431                            }
432                        } else {
433                            Err(String::from("List slice indices must be numbers"))
434                        }
435                    } else {
436                        Err(String::from(
437                            "List access requires exactly 1 or 2 arguments",
438                        ))
439                    }
440                }
441                _ => {
442                    if let AST::Symbol(sym) = &**func_ast {
443                        let fs = crate::kernel::fs::get_fs();
444                        let manifest_path = alloc::format!("/apps/{}/manifest.json", sym);
445                        let main_path = alloc::format!("/apps/{}/main.aura", sym);
446                        if fs.read_file(&manifest_path).is_some()
447                            || fs.read_file(&main_path).is_some()
448                        {
449                            let mut run_args = alloc::vec::Vec::new();
450                            run_args.push(AST::Str(sym.clone()));
451                            for arg in args {
452                                run_args.push(arg.clone());
453                            }
454                            return crate::os_lib::aura::builtins::builtin_run(env, &run_args);
455                        }
456                    }
457
458                    let func_expr = if let AST::Symbol(sym) = &**func_ast {
459                        alloc::format!("'{}'", sym)
460                    } else {
461                        alloc::format!("{:?}", func_ast)
462                    };
463
464                    let (type_name, hint) = match &func_val {
465                        Value::Num(_) => ("number", "Numbers cannot be called as functions"),
466                        Value::Ratio(_) => ("rational number", "Rational numbers cannot be called as functions"),
467                        Value::Str(_) => ("string", "Strings cannot be called as functions"),
468                        Value::Symbol(_) => ("symbol", "Undefined variable or command"),
469                        Value::Bool(_) => ("boolean", "Booleans cannot be called as functions"),
470                        Value::Complex(_) => ("complex number", "Complex numbers cannot be called as functions"),
471                        Value::Dict(_) => ("dict (object)", "Did you forget to access a property? Use 'obj:key' or 'obj.key' to get the function from the dict"),
472                        Value::Nil => ("nil", "Nil cannot be called as a function"),
473                        Value::Stream(_) => ("stream", "Streams cannot be called as functions"),
474                        Value::Thunk(_, _) => ("thunk", "Thunks cannot be called as functions directly"),
475                        _ => ("unknown", "This value cannot be called as a function"),
476                    };
477
478                    Err(alloc::format!(
479                        "EvalError: cannot call {} as function\n  Type: {}\n  Hint: {}",
480                        func_expr,
481                        type_name,
482                        hint
483                    ))
484                }
485            }
486        }
487    }
488}
489
490pub fn setup_global_env(kbd: *mut crate::kernel::keyboard::Keyboard) -> Env {
491    let mut env = Env::with_context(kbd);
492    builtins::register(&mut env);
493    // システムの初期カレントディレクトリを設定
494    env.set(
495        alloc::string::String::from("cwd"),
496        Value::Str(alloc::string::String::from("/user/")),
497    );
498
499    // 真偽値の初期定数 (true/false, True/False)
500    env.set(alloc::string::String::from("true"), Value::Bool(true));
501    env.set(alloc::string::String::from("false"), Value::Bool(false));
502    env.set(alloc::string::String::from("True"), Value::Bool(true));
503    env.set(alloc::string::String::from("False"), Value::Bool(false));
504    env.set(alloc::string::String::from("nil"), Value::Nil);
505    env
506}
507
508// スレッド間共有のためのSend/Sync実装
509unsafe impl Send for Value {}
510unsafe impl Sync for Value {}
511unsafe impl Send for Env {}
512unsafe impl Sync for Env {}
513unsafe impl Send for StreamCore {}
514unsafe impl Sync for StreamCore {}