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>), Lambda(Vec<String>, AST, Box<Env>), Bool(bool),
41 Complex(Complex),
42 Dict(alloc::collections::BTreeMap<String, Value>),
43 Stream(Rc<RefCell<StreamCore>>),
44 Nil,
45}
46
47impl StreamCore {
48 #[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 {
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 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 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 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 #[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 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 f(env, args)
371 }
372 Value::Lambda(arg_names, body_ast, closure_env) => {
373 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 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 env.set(
495 alloc::string::String::from("cwd"),
496 Value::Str(alloc::string::String::from("/user/")),
497 );
498
499 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
508unsafe 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 {}