1use crate::interpreter::{
46 ActorInner, BuiltInFn, ChannelInner, Evidence, Function, Interpreter, RuntimeError, Value,
47};
48use std::cell::RefCell;
49use std::collections::HashMap;
50use std::io::Write;
51use std::net::{TcpListener, TcpStream};
52use std::rc::Rc;
53use std::sync::atomic::{AtomicU64, Ordering};
54use std::sync::{mpsc, Arc, Mutex, OnceLock};
55use std::thread;
56use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
57
58static TCP_LISTENERS: OnceLock<Mutex<HashMap<u64, TcpListener>>> = OnceLock::new();
60static TCP_STREAMS: OnceLock<Mutex<HashMap<u64, TcpStream>>> = OnceLock::new();
61static BUF_READERS: OnceLock<Mutex<HashMap<u64, std::io::BufReader<TcpStream>>>> = OnceLock::new();
62static LISTENER_ID_COUNTER: AtomicU64 = AtomicU64::new(1);
63static STREAM_ID_COUNTER: AtomicU64 = AtomicU64::new(1);
64static BUFREADER_ID_COUNTER: AtomicU64 = AtomicU64::new(1);
65
66pub fn get_listener_registry() -> &'static Mutex<HashMap<u64, TcpListener>> {
67 TCP_LISTENERS.get_or_init(|| Mutex::new(HashMap::new()))
68}
69
70pub fn get_stream_registry() -> &'static Mutex<HashMap<u64, TcpStream>> {
71 TCP_STREAMS.get_or_init(|| Mutex::new(HashMap::new()))
72}
73
74pub fn get_bufreader_registry() -> &'static Mutex<HashMap<u64, std::io::BufReader<TcpStream>>> {
75 BUF_READERS.get_or_init(|| Mutex::new(HashMap::new()))
76}
77
78pub fn store_bufreader(reader: std::io::BufReader<TcpStream>) -> u64 {
79 let id = BUFREADER_ID_COUNTER.fetch_add(1, Ordering::SeqCst);
80 get_bufreader_registry().lock().unwrap().insert(id, reader);
81 id
82}
83
84fn store_listener(listener: TcpListener) -> u64 {
85 let id = LISTENER_ID_COUNTER.fetch_add(1, Ordering::SeqCst);
86 get_listener_registry().lock().unwrap().insert(id, listener);
87 id
88}
89
90pub fn store_tcp_stream(stream: TcpStream) -> u64 {
91 let id = STREAM_ID_COUNTER.fetch_add(1, Ordering::SeqCst);
92 get_stream_registry().lock().unwrap().insert(id, stream);
93 id
94}
95
96pub fn get_tcp_stream(id: u64) -> Option<std::sync::MutexGuard<'static, HashMap<u64, TcpStream>>> {
97 let guard = get_stream_registry().lock().unwrap();
98 if guard.contains_key(&id) {
99 Some(guard)
100 } else {
101 None
102 }
103}
104
105use base64::{engine::general_purpose, Engine as _};
107use md5::Md5;
108use regex::Regex;
109use sha2::{Digest, Sha256, Sha512};
110use unicode_normalization::UnicodeNormalization;
111use unicode_segmentation::UnicodeSegmentation;
112use uuid::Uuid;
113
114use deunicode::deunicode;
116use icu_casemap::titlecase::TitlecaseOptions;
117use icu_casemap::CaseMapper;
118use icu_collator::{Collator, CollatorOptions};
119use icu_locid::{LanguageIdentifier, Locale};
120use icu_segmenter::{SentenceSegmenter, WordSegmenter};
121use unicode_bidi::BidiInfo;
122use unicode_script::{Script, UnicodeScript};
123use unicode_width::UnicodeWidthStr;
124
125use rust_stemmers::{Algorithm as StemAlgorithm, Stemmer};
127use tiktoken_rs::{cl100k_base, p50k_base, r50k_base};
128use whatlang::{detect, Lang, Script as WhatLangScript};
129
130use rand::Rng;
132
133pub fn register_stdlib(interp: &mut Interpreter) {
135 register_core(interp);
136 register_math(interp);
137 register_collections(interp);
138 register_string(interp);
139 register_evidence(interp);
140 register_affect(interp);
141 register_iter(interp);
142 register_io(interp);
143 register_time(interp);
144 register_random(interp);
145 register_convert(interp);
146 register_cycle(interp);
147 register_simd(interp);
148 register_graphics_math(interp);
149 register_concurrency(interp);
150 register_json(interp);
152 register_fs(interp);
153 register_crypto(interp);
154 register_regex(interp);
155 register_uuid(interp);
156 register_system(interp);
157 register_stats(interp);
158 register_matrix(interp);
159 register_functional(interp);
161 register_benchmark(interp);
162 register_itertools(interp);
163 register_ranges(interp);
164 register_bitwise(interp);
165 register_format(interp);
166 register_pattern(interp);
168 register_devex(interp);
170 register_soa(interp);
172 register_tensor(interp);
173 register_autodiff(interp);
174 register_spatial(interp);
175 register_physics(interp);
176 register_geometric_algebra(interp);
178 register_dimensional(interp);
179 register_ecs(interp);
180 register_polycultural_text(interp);
182 register_text_intelligence(interp);
184 register_hologram(interp);
186 register_experimental_crypto(interp);
187 register_sketch(interp);
189 register_multibase(interp);
191 register_audio(interp);
193 register_spirituality(interp);
195 register_color(interp);
197 register_protocol(interp);
199 register_agent_tools(interp);
201 register_agent_llm(interp);
202 register_agent_memory(interp);
203 register_agent_planning(interp);
204 register_agent_vectors(interp);
205 register_agent_swarm(interp);
207 register_agent_reasoning(interp);
208 register_terminal(interp);
210}
211
212fn define(
214 interp: &mut Interpreter,
215 name: &str,
216 arity: Option<usize>,
217 func: fn(&mut Interpreter, Vec<Value>) -> Result<Value, RuntimeError>,
218) {
219 let builtin = Value::BuiltIn(Rc::new(BuiltInFn {
220 name: name.to_string(),
221 arity,
222 func,
223 }));
224 interp
225 .globals
226 .borrow_mut()
227 .define(name.to_string(), builtin);
228}
229
230fn values_equal_simple(a: &Value, b: &Value) -> bool {
232 match (a, b) {
233 (Value::Int(x), Value::Int(y)) => x == y,
234 (Value::Float(x), Value::Float(y)) => (x - y).abs() < f64::EPSILON,
235 (Value::Int(x), Value::Float(y)) | (Value::Float(y), Value::Int(x)) => {
236 (*x as f64 - y).abs() < f64::EPSILON
237 }
238 (Value::Bool(x), Value::Bool(y)) => x == y,
239 (Value::String(x), Value::String(y)) => x == y,
240 (Value::Char(x), Value::Char(y)) => x == y,
241 (Value::Null, Value::Null) => true,
242 (Value::Empty, Value::Empty) => true,
243 (Value::Infinity, Value::Infinity) => true,
244 _ => false,
245 }
246}
247
248fn register_core(interp: &mut Interpreter) {
253 interp
256 .globals
257 .borrow_mut()
258 .define("u64·MAX".to_string(), Value::Int(u64::MAX as i64));
259 interp
260 .globals
261 .borrow_mut()
262 .define("u64·MIN".to_string(), Value::Int(0));
263 interp
264 .globals
265 .borrow_mut()
266 .define("i64·MAX".to_string(), Value::Int(i64::MAX));
267 interp
268 .globals
269 .borrow_mut()
270 .define("i64·MIN".to_string(), Value::Int(i64::MIN));
271 interp
272 .globals
273 .borrow_mut()
274 .define("u32·MAX".to_string(), Value::Int(u32::MAX as i64));
275 interp
276 .globals
277 .borrow_mut()
278 .define("u32·MIN".to_string(), Value::Int(0));
279 interp
280 .globals
281 .borrow_mut()
282 .define("i32·MAX".to_string(), Value::Int(i32::MAX as i64));
283 interp
284 .globals
285 .borrow_mut()
286 .define("i32·MIN".to_string(), Value::Int(i32::MIN as i64));
287 interp
288 .globals
289 .borrow_mut()
290 .define("u16·MAX".to_string(), Value::Int(u16::MAX as i64));
291 interp
292 .globals
293 .borrow_mut()
294 .define("u8·MAX".to_string(), Value::Int(u8::MAX as i64));
295 interp
296 .globals
297 .borrow_mut()
298 .define("usize·MAX".to_string(), Value::Int(usize::MAX as i64));
299 interp
300 .globals
301 .borrow_mut()
302 .define("isize·MAX".to_string(), Value::Int(isize::MAX as i64));
303 interp
304 .globals
305 .borrow_mut()
306 .define("isize·MIN".to_string(), Value::Int(isize::MIN as i64));
307 interp
308 .globals
309 .borrow_mut()
310 .define("f64·INFINITY".to_string(), Value::Float(f64::INFINITY));
311 interp.globals.borrow_mut().define(
312 "f64·NEG_INFINITY".to_string(),
313 Value::Float(f64::NEG_INFINITY),
314 );
315 interp
316 .globals
317 .borrow_mut()
318 .define("f64·NAN".to_string(), Value::Float(f64::NAN));
319
320 interp.variant_constructors.insert(
322 "SeekFrom·Start".to_string(),
323 ("SeekFrom".to_string(), "Start".to_string(), 1),
324 );
325 interp.variant_constructors.insert(
326 "SeekFrom·End".to_string(),
327 ("SeekFrom".to_string(), "End".to_string(), 1),
328 );
329 interp.variant_constructors.insert(
330 "SeekFrom·Current".to_string(),
331 ("SeekFrom".to_string(), "Current".to_string(), 1),
332 );
333
334 let ordering_variants = ["SeqCst", "Acquire", "Release", "AcqRel", "Relaxed"];
336 for variant in ordering_variants {
337 let full_name = format!("std·sync·atomic·Ordering·{}", variant);
338 let short_name = format!("Ordering·{}", variant);
339 interp.globals.borrow_mut().define(
340 full_name,
341 Value::Variant {
342 enum_name: "Ordering".to_string(),
343 variant_name: variant.to_string(),
344 fields: None,
345 },
346 );
347 interp.globals.borrow_mut().define(
348 short_name,
349 Value::Variant {
350 enum_name: "Ordering".to_string(),
351 variant_name: variant.to_string(),
352 fields: None,
353 },
354 );
355 }
356
357 let error_kind_variants = [
359 "NotFound",
360 "PermissionDenied",
361 "ConnectionRefused",
362 "ConnectionReset",
363 "ConnectionAborted",
364 "NotConnected",
365 "AddrInUse",
366 "AddrNotAvailable",
367 "BrokenPipe",
368 "AlreadyExists",
369 "WouldBlock",
370 "InvalidInput",
371 "InvalidData",
372 "TimedOut",
373 "WriteZero",
374 "Interrupted",
375 "UnexpectedEof",
376 "Other",
377 ];
378 for variant in error_kind_variants {
379 let full_name = format!("std·io·ErrorKind·{}", variant);
380 let short_name = format!("ErrorKind·{}", variant);
381 interp.globals.borrow_mut().define(
382 full_name,
383 Value::Variant {
384 enum_name: "ErrorKind".to_string(),
385 variant_name: variant.to_string(),
386 fields: None,
387 },
388 );
389 interp.globals.borrow_mut().define(
390 short_name,
391 Value::Variant {
392 enum_name: "ErrorKind".to_string(),
393 variant_name: variant.to_string(),
394 fields: None,
395 },
396 );
397 }
398
399 define(interp, "print", None, |interp, args| {
401 let output: Vec<String> = args.iter().map(|v| format!("{}", v)).collect();
402 let line = output.join(" ");
403 print!("{}", line);
404 std::io::stdout().flush().ok();
405 interp.output.push(line);
406 Ok(Value::Null)
407 });
408
409 define(interp, "println", None, |interp, args| {
411 let output: Vec<String> = args.iter().map(|v| format!("{}", v)).collect();
412 let line = output.join(" ");
413 println!("{}", line);
414 interp.output.push(line);
415 Ok(Value::Null)
416 });
417
418 define(interp, "eprint", None, |interp, args| {
420 let output: Vec<String> = args.iter().map(|v| format!("{}", v)).collect();
421 let line = output.join(" ");
422 eprint!("{}", line);
423 std::io::stderr().flush().ok();
424 interp.output.push(line);
425 Ok(Value::Null)
426 });
427
428 define(interp, "eprintln", None, |interp, args| {
430 let output: Vec<String> = args.iter().map(|v| format!("{}", v)).collect();
431 let line = output.join(" ");
432 eprintln!("{}", line);
433 interp.output.push(line);
434 Ok(Value::Null)
435 });
436
437 define(interp, "dbg", Some(1), |interp, args| {
439 let output = format!("[DEBUG] {:?}", args[0]);
440 println!("{}", output);
441 interp.output.push(output);
442 Ok(args[0].clone())
443 });
444
445 define(interp, "type_of", Some(1), |_, args| {
447 let type_name = match &args[0] {
448 Value::Null => "null",
449 Value::Bool(_) => "bool",
450 Value::Int(_) => "i64",
451 Value::Float(_) => "f64",
452 Value::String(_) => "str",
453 Value::Char(_) => "char",
454 Value::Array(_) => "array",
455 Value::Tuple(_) => "tuple",
456 Value::Struct { name, .. } => name,
457 Value::Variant { enum_name, .. } => enum_name,
458 Value::Function(_) => "fn",
459 Value::BuiltIn(_) => "builtin",
460 Value::Ref(_) => "ref",
461 Value::Infinity => "infinity",
462 Value::Empty => "empty",
463 Value::Evidential { evidence, .. } => match evidence {
464 Evidence::Known => "known",
465 Evidence::Uncertain => "uncertain",
466 Evidence::Reported => "reported",
467 Evidence::Predicted => "predicted",
468 Evidence::Paradox => "paradox",
469 },
470 Value::Affective { .. } => "affective",
471 Value::Map(_) => "map",
472 Value::Set(_) => "set",
473 Value::Channel(_) => "channel",
474 Value::ThreadHandle(_) => "thread",
475 Value::Actor(_) => "actor",
476 Value::Future(_) => "future",
477 Value::VariantConstructor { .. } => "variant_constructor",
478 Value::DefaultConstructor { .. } => "default_constructor",
479 Value::Range { .. } => "range",
480 };
481 Ok(Value::String(Rc::new(type_name.to_string())))
482 });
483
484 define(interp, "assert", None, |_, args| {
486 if args.is_empty() {
487 return Err(RuntimeError::new("assert() requires at least one argument"));
488 }
489 let condition = match &args[0] {
490 Value::Bool(b) => *b,
491 _ => return Err(RuntimeError::new("assert() condition must be bool")),
492 };
493 if !condition {
494 let msg = if args.len() > 1 {
495 format!("{}", args[1])
496 } else {
497 "assertion failed".to_string()
498 };
499 return Err(RuntimeError::new(format!("Assertion failed: {}", msg)));
500 }
501 Ok(Value::Null)
502 });
503
504 define(interp, "panic", None, |_, args| {
506 let msg = if args.is_empty() {
507 "explicit panic".to_string()
508 } else {
509 args.iter()
510 .map(|v| format!("{}", v))
511 .collect::<Vec<_>>()
512 .join(" ")
513 };
514 Err(RuntimeError::new(format!("PANIC: {}", msg)))
515 });
516
517 define(interp, "todo", None, |_, args| {
519 let msg = if args.is_empty() {
520 "not yet implemented".to_string()
521 } else {
522 format!("{}", args[0])
523 };
524 Err(RuntimeError::new(format!("TODO: {}", msg)))
525 });
526
527 define(interp, "unreachable", None, |_, args| {
529 let msg = if args.is_empty() {
530 "entered unreachable code".to_string()
531 } else {
532 format!("{}", args[0])
533 };
534 Err(RuntimeError::new(format!("UNREACHABLE: {}", msg)))
535 });
536
537 define(interp, "clone", Some(1), |_, args| Ok(deep_clone(&args[0])));
539
540 define(interp, "id", Some(1), |_, args| Ok(args[0].clone()));
542
543 define(interp, "default", None, |interp, args| {
546 let type_name = if args.is_empty() {
547 match &interp.current_self_type {
550 Some(t) => t.clone(),
551 None => {
552 return Ok(Value::Struct {
553 name: "Default".to_string(),
554 fields: Rc::new(RefCell::new(std::collections::HashMap::new())),
555 })
556 }
557 }
558 } else {
559 match &args[0] {
560 Value::String(s) => s.to_string(),
561 _ => return Err(RuntimeError::new("default() requires type name string")),
562 }
563 };
564 let type_name = type_name.as_str();
565 match type_name {
566 "bool" => Ok(Value::Bool(false)),
567 "i64" | "int" => Ok(Value::Int(0)),
568 "f64" | "float" => Ok(Value::Float(0.0)),
569 "str" | "string" => Ok(Value::String(Rc::new(String::new()))),
570 "array" => Ok(Value::Array(Rc::new(RefCell::new(Vec::new())))),
571 _ => {
572 if let Some(struct_def) = interp.default_structs.get(type_name).cloned() {
574 use crate::ast::StructFields;
575 let mut fields = std::collections::HashMap::new();
576 if let StructFields::Named(field_defs) = &struct_def.fields {
577 for field in field_defs {
578 let default_val = if let Some(ref default_expr) = field.default {
580 match interp.evaluate(default_expr) {
581 Ok(v) => v,
582 Err(_) => Value::Null,
583 }
584 } else {
585 Value::Null
586 };
587 fields.insert(field.name.name.clone(), default_val);
588 }
589 }
590 Ok(Value::Struct {
591 name: type_name.to_string(),
592 fields: Rc::new(RefCell::new(fields)),
593 })
594 } else {
595 Ok(Value::Struct {
597 name: type_name.to_string(),
598 fields: Rc::new(RefCell::new(std::collections::HashMap::new())),
599 })
600 }
601 }
602 }
603 });
604
605 define(interp, "Result·Ok", Some(1), |_, args| {
607 Ok(Value::Variant {
608 enum_name: "Result".to_string(),
609 variant_name: "Ok".to_string(),
610 fields: Some(Rc::new(vec![args[0].clone()])),
611 })
612 });
613
614 define(interp, "Ok", Some(1), |_, args| {
616 Ok(Value::Variant {
617 enum_name: "Result".to_string(),
618 variant_name: "Ok".to_string(),
619 fields: Some(Rc::new(vec![args[0].clone()])),
620 })
621 });
622
623 define(interp, "Result·Err", Some(1), |_, args| {
625 Ok(Value::Variant {
626 enum_name: "Result".to_string(),
627 variant_name: "Err".to_string(),
628 fields: Some(Rc::new(vec![args[0].clone()])),
629 })
630 });
631
632 define(interp, "Err", Some(1), |_, args| {
634 Ok(Value::Variant {
635 enum_name: "Result".to_string(),
636 variant_name: "Err".to_string(),
637 fields: Some(Rc::new(vec![args[0].clone()])),
638 })
639 });
640
641 define(interp, "Option·Some", Some(1), |_, args| {
643 Ok(Value::Variant {
644 enum_name: "Option".to_string(),
645 variant_name: "Some".to_string(),
646 fields: Some(Rc::new(vec![args[0].clone()])),
647 })
648 });
649
650 define(interp, "Some", Some(1), |_, args| {
652 Ok(Value::Variant {
653 enum_name: "Option".to_string(),
654 variant_name: "Some".to_string(),
655 fields: Some(Rc::new(vec![args[0].clone()])),
656 })
657 });
658
659 interp.globals.borrow_mut().define(
661 "Option·None".to_string(),
662 Value::Variant {
663 enum_name: "Option".to_string(),
664 variant_name: "None".to_string(),
665 fields: None,
666 },
667 );
668
669 interp.globals.borrow_mut().define(
671 "None".to_string(),
672 Value::Variant {
673 enum_name: "Option".to_string(),
674 variant_name: "None".to_string(),
675 fields: None,
676 },
677 );
678
679 define(interp, "Map·new", Some(0), |_, _| {
681 Ok(Value::Map(Rc::new(RefCell::new(HashMap::new()))))
682 });
683
684 define(interp, "HashMap·new", Some(0), |_, _| {
686 Ok(Value::Map(Rc::new(RefCell::new(HashMap::new()))))
687 });
688
689 define(interp, "HashMap·with_capacity", Some(1), |_, _args| {
691 Ok(Value::Map(Rc::new(RefCell::new(HashMap::new()))))
693 });
694
695 define(interp, "std·collections·HashMap·new", Some(0), |_, _| {
697 Ok(Value::Map(Rc::new(RefCell::new(HashMap::new()))))
698 });
699
700 define(
702 interp,
703 "std·collections·HashMap·with_capacity",
704 Some(1),
705 |_, _args| Ok(Value::Map(Rc::new(RefCell::new(HashMap::new())))),
706 );
707
708 define(interp, "HashSet·new", Some(0), |_, _| {
710 Ok(Value::Set(Rc::new(RefCell::new(
711 std::collections::HashSet::new(),
712 ))))
713 });
714
715 define(interp, "HashSet·with_capacity", Some(1), |_, _args| {
717 Ok(Value::Set(Rc::new(RefCell::new(
718 std::collections::HashSet::new(),
719 ))))
720 });
721
722 define(interp, "std·collections·HashSet·new", Some(0), |_, _| {
724 Ok(Value::Set(Rc::new(RefCell::new(
725 std::collections::HashSet::new(),
726 ))))
727 });
728
729 define(interp, "Vec·new", Some(0), |_, _| {
731 Ok(Value::Array(Rc::new(RefCell::new(Vec::new()))))
732 });
733
734 define(interp, "String·new", Some(0), |_, _| {
736 Ok(Value::String(Rc::new(String::new())))
737 });
738
739 define(interp, "String·from", Some(1), |_, args| {
741 let s = match &args[0] {
742 Value::String(s) => (**s).clone(),
743 Value::Int(n) => n.to_string(),
744 Value::Float(f) => f.to_string(),
745 Value::Bool(b) => b.to_string(),
746 Value::Char(c) => c.to_string(),
747 _ => format!("{}", args[0]),
748 };
749 Ok(Value::String(Rc::new(s)))
750 });
751
752 define(interp, "Box·new", Some(1), |_, args| Ok(args[0].clone()));
754
755 define(interp, "String·from_raw_parts", Some(3), |_, args| {
757 match &args[0] {
759 Value::String(s) => Ok(Value::String(s.clone())),
760 Value::Null => Ok(Value::String(Rc::new(String::new()))),
761 _ => Ok(Value::String(Rc::new(format!("{}", args[0])))),
762 }
763 });
764
765 define(interp, "slice·from_raw_parts", Some(2), |_, args| {
767 match &args[0] {
769 Value::String(s) => Ok(Value::String(s.clone())),
770 Value::Array(arr) => Ok(Value::Array(arr.clone())),
771 _ => Ok(args[0].clone()),
772 }
773 });
774}
775
776fn deep_clone(value: &Value) -> Value {
778 match value {
779 Value::Array(arr) => {
780 let cloned: Vec<Value> = arr.borrow().iter().map(deep_clone).collect();
781 Value::Array(Rc::new(RefCell::new(cloned)))
782 }
783 Value::Struct { name, fields } => {
784 let cloned: HashMap<String, Value> = fields
785 .borrow()
786 .iter()
787 .map(|(k, v)| (k.clone(), deep_clone(v)))
788 .collect();
789 Value::Struct {
790 name: name.clone(),
791 fields: Rc::new(RefCell::new(cloned)),
792 }
793 }
794 Value::Evidential { value, evidence } => Value::Evidential {
795 value: Box::new(deep_clone(value)),
796 evidence: *evidence,
797 },
798 other => other.clone(),
799 }
800}
801
802fn register_math(interp: &mut Interpreter) {
807 define(interp, "abs", Some(1), |_, args| match &args[0] {
809 Value::Int(n) => Ok(Value::Int(n.abs())),
810 Value::Float(n) => Ok(Value::Float(n.abs())),
811 _ => Err(RuntimeError::new("abs() requires number")),
812 });
813
814 define(interp, "neg", Some(1), |_, args| match &args[0] {
815 Value::Int(n) => Ok(Value::Int(-n)),
816 Value::Float(n) => Ok(Value::Float(-n)),
817 _ => Err(RuntimeError::new("neg() requires number")),
818 });
819
820 define(interp, "sqrt", Some(1), |_, args| match &args[0] {
821 Value::Int(n) => Ok(Value::Float((*n as f64).sqrt())),
822 Value::Float(n) => Ok(Value::Float(n.sqrt())),
823 _ => Err(RuntimeError::new("sqrt() requires number")),
824 });
825
826 define(interp, "cbrt", Some(1), |_, args| match &args[0] {
827 Value::Int(n) => Ok(Value::Float((*n as f64).cbrt())),
828 Value::Float(n) => Ok(Value::Float(n.cbrt())),
829 _ => Err(RuntimeError::new("cbrt() requires number")),
830 });
831
832 define(interp, "pow", Some(2), |_, args| {
833 match (&args[0], &args[1]) {
834 (Value::Int(base), Value::Int(exp)) => {
835 if *exp >= 0 {
836 Ok(Value::Int(base.pow(*exp as u32)))
837 } else {
838 Ok(Value::Float((*base as f64).powi(*exp as i32)))
839 }
840 }
841 (Value::Float(base), Value::Int(exp)) => Ok(Value::Float(base.powi(*exp as i32))),
842 (Value::Float(base), Value::Float(exp)) => Ok(Value::Float(base.powf(*exp))),
843 (Value::Int(base), Value::Float(exp)) => Ok(Value::Float((*base as f64).powf(*exp))),
844 _ => Err(RuntimeError::new("pow() requires numbers")),
845 }
846 });
847
848 define(interp, "exp", Some(1), |_, args| match &args[0] {
849 Value::Int(n) => Ok(Value::Float((*n as f64).exp())),
850 Value::Float(n) => Ok(Value::Float(n.exp())),
851 _ => Err(RuntimeError::new("exp() requires number")),
852 });
853
854 define(interp, "ln", Some(1), |_, args| match &args[0] {
855 Value::Int(n) => Ok(Value::Float((*n as f64).ln())),
856 Value::Float(n) => Ok(Value::Float(n.ln())),
857 _ => Err(RuntimeError::new("ln() requires number")),
858 });
859
860 define(interp, "log", Some(2), |_, args| {
861 let (value, base) = match (&args[0], &args[1]) {
862 (Value::Int(v), Value::Int(b)) => (*v as f64, *b as f64),
863 (Value::Float(v), Value::Int(b)) => (*v, *b as f64),
864 (Value::Int(v), Value::Float(b)) => (*v as f64, *b),
865 (Value::Float(v), Value::Float(b)) => (*v, *b),
866 _ => return Err(RuntimeError::new("log() requires numbers")),
867 };
868 Ok(Value::Float(value.log(base)))
869 });
870
871 define(interp, "log10", Some(1), |_, args| match &args[0] {
872 Value::Int(n) => Ok(Value::Float((*n as f64).log10())),
873 Value::Float(n) => Ok(Value::Float(n.log10())),
874 _ => Err(RuntimeError::new("log10() requires number")),
875 });
876
877 define(interp, "log2", Some(1), |_, args| match &args[0] {
878 Value::Int(n) => Ok(Value::Float((*n as f64).log2())),
879 Value::Float(n) => Ok(Value::Float(n.log2())),
880 _ => Err(RuntimeError::new("log2() requires number")),
881 });
882
883 define(interp, "sin", Some(1), |_, args| match &args[0] {
885 Value::Int(n) => Ok(Value::Float((*n as f64).sin())),
886 Value::Float(n) => Ok(Value::Float(n.sin())),
887 _ => Err(RuntimeError::new("sin() requires number")),
888 });
889
890 define(interp, "cos", Some(1), |_, args| match &args[0] {
891 Value::Int(n) => Ok(Value::Float((*n as f64).cos())),
892 Value::Float(n) => Ok(Value::Float(n.cos())),
893 _ => Err(RuntimeError::new("cos() requires number")),
894 });
895
896 define(interp, "tan", Some(1), |_, args| match &args[0] {
897 Value::Int(n) => Ok(Value::Float((*n as f64).tan())),
898 Value::Float(n) => Ok(Value::Float(n.tan())),
899 _ => Err(RuntimeError::new("tan() requires number")),
900 });
901
902 define(interp, "asin", Some(1), |_, args| match &args[0] {
903 Value::Int(n) => Ok(Value::Float((*n as f64).asin())),
904 Value::Float(n) => Ok(Value::Float(n.asin())),
905 _ => Err(RuntimeError::new("asin() requires number")),
906 });
907
908 define(interp, "acos", Some(1), |_, args| match &args[0] {
909 Value::Int(n) => Ok(Value::Float((*n as f64).acos())),
910 Value::Float(n) => Ok(Value::Float(n.acos())),
911 _ => Err(RuntimeError::new("acos() requires number")),
912 });
913
914 define(interp, "atan", Some(1), |_, args| match &args[0] {
915 Value::Int(n) => Ok(Value::Float((*n as f64).atan())),
916 Value::Float(n) => Ok(Value::Float(n.atan())),
917 _ => Err(RuntimeError::new("atan() requires number")),
918 });
919
920 define(interp, "atan2", Some(2), |_, args| {
921 let (y, x) = match (&args[0], &args[1]) {
922 (Value::Int(y), Value::Int(x)) => (*y as f64, *x as f64),
923 (Value::Float(y), Value::Int(x)) => (*y, *x as f64),
924 (Value::Int(y), Value::Float(x)) => (*y as f64, *x),
925 (Value::Float(y), Value::Float(x)) => (*y, *x),
926 _ => return Err(RuntimeError::new("atan2() requires numbers")),
927 };
928 Ok(Value::Float(y.atan2(x)))
929 });
930
931 define(interp, "sinh", Some(1), |_, args| match &args[0] {
933 Value::Int(n) => Ok(Value::Float((*n as f64).sinh())),
934 Value::Float(n) => Ok(Value::Float(n.sinh())),
935 _ => Err(RuntimeError::new("sinh() requires number")),
936 });
937
938 define(interp, "cosh", Some(1), |_, args| match &args[0] {
939 Value::Int(n) => Ok(Value::Float((*n as f64).cosh())),
940 Value::Float(n) => Ok(Value::Float(n.cosh())),
941 _ => Err(RuntimeError::new("cosh() requires number")),
942 });
943
944 define(interp, "tanh", Some(1), |_, args| match &args[0] {
945 Value::Int(n) => Ok(Value::Float((*n as f64).tanh())),
946 Value::Float(n) => Ok(Value::Float(n.tanh())),
947 _ => Err(RuntimeError::new("tanh() requires number")),
948 });
949
950 define(interp, "floor", Some(1), |_, args| match &args[0] {
952 Value::Int(n) => Ok(Value::Int(*n)),
953 Value::Float(n) => Ok(Value::Int(n.floor() as i64)),
954 _ => Err(RuntimeError::new("floor() requires number")),
955 });
956
957 define(interp, "ceil", Some(1), |_, args| match &args[0] {
958 Value::Int(n) => Ok(Value::Int(*n)),
959 Value::Float(n) => Ok(Value::Int(n.ceil() as i64)),
960 _ => Err(RuntimeError::new("ceil() requires number")),
961 });
962
963 define(interp, "round", Some(1), |_, args| match &args[0] {
964 Value::Int(n) => Ok(Value::Int(*n)),
965 Value::Float(n) => Ok(Value::Int(n.round() as i64)),
966 _ => Err(RuntimeError::new("round() requires number")),
967 });
968
969 define(interp, "trunc", Some(1), |_, args| match &args[0] {
970 Value::Int(n) => Ok(Value::Int(*n)),
971 Value::Float(n) => Ok(Value::Int(n.trunc() as i64)),
972 _ => Err(RuntimeError::new("trunc() requires number")),
973 });
974
975 define(interp, "fract", Some(1), |_, args| match &args[0] {
976 Value::Int(_) => Ok(Value::Float(0.0)),
977 Value::Float(n) => Ok(Value::Float(n.fract())),
978 _ => Err(RuntimeError::new("fract() requires number")),
979 });
980
981 define(interp, "min", Some(2), |_, args| {
983 match (&args[0], &args[1]) {
984 (Value::Int(a), Value::Int(b)) => Ok(Value::Int(*a.min(b))),
985 (Value::Float(a), Value::Float(b)) => Ok(Value::Float(a.min(*b))),
986 (Value::Int(a), Value::Float(b)) => Ok(Value::Float((*a as f64).min(*b))),
987 (Value::Float(a), Value::Int(b)) => Ok(Value::Float(a.min(*b as f64))),
988 _ => Err(RuntimeError::new("min() requires numbers")),
989 }
990 });
991
992 define(interp, "max", Some(2), |_, args| {
993 match (&args[0], &args[1]) {
994 (Value::Int(a), Value::Int(b)) => Ok(Value::Int(*a.max(b))),
995 (Value::Float(a), Value::Float(b)) => Ok(Value::Float(a.max(*b))),
996 (Value::Int(a), Value::Float(b)) => Ok(Value::Float((*a as f64).max(*b))),
997 (Value::Float(a), Value::Int(b)) => Ok(Value::Float(a.max(*b as f64))),
998 _ => Err(RuntimeError::new("max() requires numbers")),
999 }
1000 });
1001
1002 define(interp, "clamp", Some(3), |_, args| {
1003 match (&args[0], &args[1], &args[2]) {
1004 (Value::Int(val), Value::Int(min), Value::Int(max)) => {
1005 Ok(Value::Int(*val.max(min).min(max)))
1006 }
1007 (Value::Float(val), Value::Float(min), Value::Float(max)) => {
1008 Ok(Value::Float(val.max(*min).min(*max)))
1009 }
1010 _ => Err(RuntimeError::new("clamp() requires matching number types")),
1011 }
1012 });
1013
1014 define(interp, "sign", Some(1), |_, args| match &args[0] {
1016 Value::Int(n) => Ok(Value::Int(n.signum())),
1017 Value::Float(n) => Ok(Value::Float(if *n > 0.0 {
1018 1.0
1019 } else if *n < 0.0 {
1020 -1.0
1021 } else {
1022 0.0
1023 })),
1024 _ => Err(RuntimeError::new("sign() requires number")),
1025 });
1026
1027 define(interp, "PI", Some(0), |_, _| {
1029 Ok(Value::Float(std::f64::consts::PI))
1030 });
1031 define(interp, "E", Some(0), |_, _| {
1032 Ok(Value::Float(std::f64::consts::E))
1033 });
1034 define(interp, "TAU", Some(0), |_, _| {
1035 Ok(Value::Float(std::f64::consts::TAU))
1036 });
1037 define(interp, "PHI", Some(0), |_, _| {
1038 Ok(Value::Float(1.618033988749895))
1039 }); define(interp, "gcd", Some(2), |_, args| {
1043 match (&args[0], &args[1]) {
1044 (Value::Int(a), Value::Int(b)) => Ok(Value::Int(gcd(*a, *b))),
1045 _ => Err(RuntimeError::new("gcd() requires integers")),
1046 }
1047 });
1048
1049 define(interp, "lcm", Some(2), |_, args| {
1050 match (&args[0], &args[1]) {
1051 (Value::Int(a), Value::Int(b)) => {
1052 let g = gcd(*a, *b);
1053 Ok(Value::Int((a * b).abs() / g))
1054 }
1055 _ => Err(RuntimeError::new("lcm() requires integers")),
1056 }
1057 });
1058
1059 define(interp, "factorial", Some(1), |_, args| match &args[0] {
1061 Value::Int(n) if *n >= 0 => {
1062 let mut result: i64 = 1;
1063 for i in 2..=(*n as u64) {
1064 result = result.saturating_mul(i as i64);
1065 }
1066 Ok(Value::Int(result))
1067 }
1068 Value::Int(_) => Err(RuntimeError::new(
1069 "factorial() requires non-negative integer",
1070 )),
1071 _ => Err(RuntimeError::new("factorial() requires integer")),
1072 });
1073
1074 define(interp, "is_nan", Some(1), |_, args| match &args[0] {
1076 Value::Float(n) => Ok(Value::Bool(n.is_nan())),
1077 Value::Int(_) => Ok(Value::Bool(false)),
1078 _ => Err(RuntimeError::new("is_nan() requires number")),
1079 });
1080
1081 define(interp, "is_infinite", Some(1), |_, args| match &args[0] {
1082 Value::Float(n) => Ok(Value::Bool(n.is_infinite())),
1083 Value::Int(_) => Ok(Value::Bool(false)),
1084 Value::Infinity => Ok(Value::Bool(true)),
1085 _ => Err(RuntimeError::new("is_infinite() requires number")),
1086 });
1087
1088 define(interp, "is_finite", Some(1), |_, args| match &args[0] {
1089 Value::Float(n) => Ok(Value::Bool(n.is_finite())),
1090 Value::Int(_) => Ok(Value::Bool(true)),
1091 Value::Infinity => Ok(Value::Bool(false)),
1092 _ => Err(RuntimeError::new("is_finite() requires number")),
1093 });
1094
1095 define(interp, "is_even", Some(1), |_, args| match &args[0] {
1096 Value::Int(n) => Ok(Value::Bool(n % 2 == 0)),
1097 _ => Err(RuntimeError::new("is_even() requires integer")),
1098 });
1099
1100 define(interp, "is_odd", Some(1), |_, args| match &args[0] {
1101 Value::Int(n) => Ok(Value::Bool(n % 2 != 0)),
1102 _ => Err(RuntimeError::new("is_odd() requires integer")),
1103 });
1104
1105 define(interp, "is_prime", Some(1), |_, args| match &args[0] {
1106 Value::Int(n) => Ok(Value::Bool(is_prime(*n))),
1107 _ => Err(RuntimeError::new("is_prime() requires integer")),
1108 });
1109}
1110
1111fn gcd(mut a: i64, mut b: i64) -> i64 {
1112 a = a.abs();
1113 b = b.abs();
1114 while b != 0 {
1115 let t = b;
1116 b = a % b;
1117 a = t;
1118 }
1119 a
1120}
1121
1122fn is_prime(n: i64) -> bool {
1123 if n < 2 {
1124 return false;
1125 }
1126 if n == 2 {
1127 return true;
1128 }
1129 if n % 2 == 0 {
1130 return false;
1131 }
1132 let sqrt = (n as f64).sqrt() as i64;
1133 for i in (3..=sqrt).step_by(2) {
1134 if n % i == 0 {
1135 return false;
1136 }
1137 }
1138 true
1139}
1140
1141fn register_collections(interp: &mut Interpreter) {
1146 define(interp, "len", Some(1), |_, args| match &args[0] {
1148 Value::Array(arr) => Ok(Value::Int(arr.borrow().len() as i64)),
1149 Value::String(s) => Ok(Value::Int(s.chars().count() as i64)),
1150 Value::Tuple(t) => Ok(Value::Int(t.len() as i64)),
1151 Value::Map(m) => Ok(Value::Int(m.borrow().len() as i64)),
1152 Value::Set(s) => Ok(Value::Int(s.borrow().len() as i64)),
1153 _ => Err(RuntimeError::new(
1154 "len() requires array, string, tuple, map, or set",
1155 )),
1156 });
1157
1158 define(interp, "is_empty", Some(1), |_, args| match &args[0] {
1159 Value::Array(arr) => Ok(Value::Bool(arr.borrow().is_empty())),
1160 Value::String(s) => Ok(Value::Bool(s.is_empty())),
1161 Value::Tuple(t) => Ok(Value::Bool(t.is_empty())),
1162 Value::Map(m) => Ok(Value::Bool(m.borrow().is_empty())),
1163 Value::Set(s) => Ok(Value::Bool(s.borrow().is_empty())),
1164 _ => Err(RuntimeError::new("is_empty() requires collection")),
1165 });
1166
1167 define(interp, "push", Some(2), |_, args| match &args[0] {
1169 Value::Array(arr) => {
1170 arr.borrow_mut().push(args[1].clone());
1171 Ok(Value::Null)
1172 }
1173 _ => Err(RuntimeError::new("push() requires array")),
1174 });
1175
1176 define(interp, "pop", Some(1), |_, args| match &args[0] {
1177 Value::Array(arr) => arr
1178 .borrow_mut()
1179 .pop()
1180 .ok_or_else(|| RuntimeError::new("pop() on empty array")),
1181 _ => Err(RuntimeError::new("pop() requires array")),
1182 });
1183
1184 define(interp, "first", Some(1), |_, args| match &args[0] {
1185 Value::Array(arr) => arr
1186 .borrow()
1187 .first()
1188 .cloned()
1189 .ok_or_else(|| RuntimeError::new("first() on empty array")),
1190 Value::Tuple(t) => t
1191 .first()
1192 .cloned()
1193 .ok_or_else(|| RuntimeError::new("first() on empty tuple")),
1194 _ => Err(RuntimeError::new("first() requires array or tuple")),
1195 });
1196
1197 define(interp, "last", Some(1), |_, args| match &args[0] {
1198 Value::Array(arr) => arr
1199 .borrow()
1200 .last()
1201 .cloned()
1202 .ok_or_else(|| RuntimeError::new("last() on empty array")),
1203 Value::Tuple(t) => t
1204 .last()
1205 .cloned()
1206 .ok_or_else(|| RuntimeError::new("last() on empty tuple")),
1207 _ => Err(RuntimeError::new("last() requires array or tuple")),
1208 });
1209
1210 define(interp, "middle", Some(1), |_, args| match &args[0] {
1212 Value::Array(arr) => {
1213 let arr = arr.borrow();
1214 if arr.is_empty() {
1215 return Err(RuntimeError::new("middle() on empty array"));
1216 }
1217 let mid = arr.len() / 2;
1218 Ok(arr[mid].clone())
1219 }
1220 Value::Tuple(t) => {
1221 if t.is_empty() {
1222 return Err(RuntimeError::new("middle() on empty tuple"));
1223 }
1224 let mid = t.len() / 2;
1225 Ok(t[mid].clone())
1226 }
1227 _ => Err(RuntimeError::new("middle() requires array or tuple")),
1228 });
1229
1230 define(interp, "choice", Some(1), |_, args| {
1232 use std::time::{SystemTime, UNIX_EPOCH};
1233 match &args[0] {
1234 Value::Array(arr) => {
1235 let arr = arr.borrow();
1236 if arr.is_empty() {
1237 return Err(RuntimeError::new("choice() on empty array"));
1238 }
1239 let seed = SystemTime::now()
1240 .duration_since(UNIX_EPOCH)
1241 .unwrap_or(std::time::Duration::ZERO)
1242 .as_nanos() as u64;
1243 let idx = ((seed.wrapping_mul(1103515245).wrapping_add(12345)) >> 16) as usize
1244 % arr.len();
1245 Ok(arr[idx].clone())
1246 }
1247 Value::Tuple(t) => {
1248 if t.is_empty() {
1249 return Err(RuntimeError::new("choice() on empty tuple"));
1250 }
1251 let seed = SystemTime::now()
1252 .duration_since(UNIX_EPOCH)
1253 .unwrap_or(std::time::Duration::ZERO)
1254 .as_nanos() as u64;
1255 let idx =
1256 ((seed.wrapping_mul(1103515245).wrapping_add(12345)) >> 16) as usize % t.len();
1257 Ok(t[idx].clone())
1258 }
1259 _ => Err(RuntimeError::new("choice() requires array or tuple")),
1260 }
1261 });
1262
1263 define(interp, "nth", Some(2), |_, args| {
1265 let n = match &args[1] {
1266 Value::Int(i) => *i,
1267 _ => return Err(RuntimeError::new("nth() index must be integer")),
1268 };
1269 match &args[0] {
1270 Value::Array(arr) => {
1271 let arr = arr.borrow();
1272 if n < 0 || n as usize >= arr.len() {
1273 return Err(RuntimeError::new("nth() index out of bounds"));
1274 }
1275 Ok(arr[n as usize].clone())
1276 }
1277 Value::Tuple(t) => {
1278 if n < 0 || n as usize >= t.len() {
1279 return Err(RuntimeError::new("nth() index out of bounds"));
1280 }
1281 Ok(t[n as usize].clone())
1282 }
1283 _ => Err(RuntimeError::new("nth() requires array or tuple")),
1284 }
1285 });
1286
1287 define(interp, "next", Some(1), |_, args| match &args[0] {
1289 Value::Array(arr) => {
1290 let mut arr = arr.borrow_mut();
1291 if arr.is_empty() {
1292 return Err(RuntimeError::new("next() on empty array"));
1293 }
1294 Ok(arr.remove(0))
1295 }
1296 _ => Err(RuntimeError::new("next() requires array")),
1297 });
1298
1299 define(interp, "peek", Some(1), |_, args| match &args[0] {
1301 Value::Array(arr) => arr
1302 .borrow()
1303 .first()
1304 .cloned()
1305 .ok_or_else(|| RuntimeError::new("peek() on empty array")),
1306 _ => Err(RuntimeError::new("peek() requires array")),
1307 });
1308
1309 define(interp, "get", Some(2), |_, args| {
1310 let index = match &args[1] {
1311 Value::Int(i) => *i,
1312 _ => return Err(RuntimeError::new("get() index must be integer")),
1313 };
1314 match &args[0] {
1315 Value::Array(arr) => {
1316 let arr = arr.borrow();
1317 let idx = if index < 0 {
1318 arr.len() as i64 + index
1319 } else {
1320 index
1321 } as usize;
1322 arr.get(idx)
1323 .cloned()
1324 .ok_or_else(|| RuntimeError::new("index out of bounds"))
1325 }
1326 Value::Tuple(t) => {
1327 let idx = if index < 0 {
1328 t.len() as i64 + index
1329 } else {
1330 index
1331 } as usize;
1332 t.get(idx)
1333 .cloned()
1334 .ok_or_else(|| RuntimeError::new("index out of bounds"))
1335 }
1336 _ => Err(RuntimeError::new("get() requires array or tuple")),
1337 }
1338 });
1339
1340 define(interp, "set", Some(3), |_, args| {
1341 let index = match &args[1] {
1342 Value::Int(i) => *i as usize,
1343 _ => return Err(RuntimeError::new("set() index must be integer")),
1344 };
1345 match &args[0] {
1346 Value::Array(arr) => {
1347 let mut arr = arr.borrow_mut();
1348 if index >= arr.len() {
1349 return Err(RuntimeError::new("index out of bounds"));
1350 }
1351 arr[index] = args[2].clone();
1352 Ok(Value::Null)
1353 }
1354 _ => Err(RuntimeError::new("set() requires array")),
1355 }
1356 });
1357
1358 define(interp, "insert", Some(3), |_, args| {
1359 let index = match &args[1] {
1360 Value::Int(i) => *i as usize,
1361 _ => return Err(RuntimeError::new("insert() index must be integer")),
1362 };
1363 match &args[0] {
1364 Value::Array(arr) => {
1365 let mut arr = arr.borrow_mut();
1366 if index > arr.len() {
1367 return Err(RuntimeError::new("index out of bounds"));
1368 }
1369 arr.insert(index, args[2].clone());
1370 Ok(Value::Null)
1371 }
1372 _ => Err(RuntimeError::new("insert() requires array")),
1373 }
1374 });
1375
1376 define(interp, "remove", Some(2), |_, args| {
1377 let index = match &args[1] {
1378 Value::Int(i) => *i as usize,
1379 _ => return Err(RuntimeError::new("remove() index must be integer")),
1380 };
1381 match &args[0] {
1382 Value::Array(arr) => {
1383 let mut arr = arr.borrow_mut();
1384 if index >= arr.len() {
1385 return Err(RuntimeError::new("index out of bounds"));
1386 }
1387 Ok(arr.remove(index))
1388 }
1389 _ => Err(RuntimeError::new("remove() requires array")),
1390 }
1391 });
1392
1393 define(interp, "clear", Some(1), |_, args| match &args[0] {
1394 Value::Array(arr) => {
1395 arr.borrow_mut().clear();
1396 Ok(Value::Null)
1397 }
1398 _ => Err(RuntimeError::new("clear() requires array")),
1399 });
1400
1401 define(interp, "contains", Some(2), |_, args| match &args[0] {
1403 Value::Array(arr) => Ok(Value::Bool(
1404 arr.borrow().iter().any(|v| values_equal(v, &args[1])),
1405 )),
1406 Value::String(s) => match &args[1] {
1407 Value::String(sub) => Ok(Value::Bool(s.contains(sub.as_str()))),
1408 Value::Char(c) => Ok(Value::Bool(s.contains(*c))),
1409 _ => Err(RuntimeError::new(
1410 "string contains() requires string or char",
1411 )),
1412 },
1413 _ => Err(RuntimeError::new("contains() requires array or string")),
1414 });
1415
1416 define(interp, "index_of", Some(2), |_, args| match &args[0] {
1417 Value::Array(arr) => {
1418 let idx = arr.borrow().iter().position(|v| values_equal(v, &args[1]));
1419 match idx {
1420 Some(i) => Ok(Value::Int(i as i64)),
1421 None => Ok(Value::Int(-1)),
1422 }
1423 }
1424 Value::String(s) => match &args[1] {
1425 Value::String(sub) => match s.find(sub.as_str()) {
1426 Some(i) => Ok(Value::Int(i as i64)),
1427 None => Ok(Value::Int(-1)),
1428 },
1429 Value::Char(c) => match s.find(*c) {
1430 Some(i) => Ok(Value::Int(i as i64)),
1431 None => Ok(Value::Int(-1)),
1432 },
1433 _ => Err(RuntimeError::new(
1434 "string index_of() requires string or char",
1435 )),
1436 },
1437 _ => Err(RuntimeError::new("index_of() requires array or string")),
1438 });
1439
1440 define(interp, "reverse", Some(1), |_, args| match &args[0] {
1442 Value::Array(arr) => {
1443 let mut reversed: Vec<Value> = arr.borrow().clone();
1444 reversed.reverse();
1445 Ok(Value::Array(Rc::new(RefCell::new(reversed))))
1446 }
1447 Value::String(s) => {
1448 let reversed: String = s.chars().rev().collect();
1449 Ok(Value::String(Rc::new(reversed)))
1450 }
1451 _ => Err(RuntimeError::new("reverse() requires array or string")),
1452 });
1453
1454 define(interp, "sort", Some(1), |_, args| match &args[0] {
1455 Value::Array(arr) => {
1456 let mut sorted: Vec<Value> = arr.borrow().clone();
1457 sorted.sort_by(compare_values);
1458 Ok(Value::Array(Rc::new(RefCell::new(sorted))))
1459 }
1460 _ => Err(RuntimeError::new("sort() requires array")),
1461 });
1462
1463 define(interp, "sort_desc", Some(1), |_, args| match &args[0] {
1464 Value::Array(arr) => {
1465 let mut sorted: Vec<Value> = arr.borrow().clone();
1466 sorted.sort_by(|a, b| compare_values(b, a));
1467 Ok(Value::Array(Rc::new(RefCell::new(sorted))))
1468 }
1469 _ => Err(RuntimeError::new("sort_desc() requires array")),
1470 });
1471
1472 define(interp, "unique", Some(1), |_, args| match &args[0] {
1473 Value::Array(arr) => {
1474 let arr = arr.borrow();
1475 let mut seen = Vec::new();
1476 let unique: Vec<Value> = arr
1477 .iter()
1478 .filter(|v| {
1479 if seen.iter().any(|s| values_equal(s, v)) {
1480 false
1481 } else {
1482 seen.push((*v).clone());
1483 true
1484 }
1485 })
1486 .cloned()
1487 .collect();
1488 Ok(Value::Array(Rc::new(RefCell::new(unique))))
1489 }
1490 _ => Err(RuntimeError::new("unique() requires array")),
1491 });
1492
1493 define(interp, "flatten", Some(1), |_, args| match &args[0] {
1494 Value::Array(arr) => {
1495 let mut flattened = Vec::new();
1496 for item in arr.borrow().iter() {
1497 match item {
1498 Value::Array(inner) => flattened.extend(inner.borrow().clone()),
1499 other => flattened.push(other.clone()),
1500 }
1501 }
1502 Ok(Value::Array(Rc::new(RefCell::new(flattened))))
1503 }
1504 _ => Err(RuntimeError::new("flatten() requires array")),
1505 });
1506
1507 define(interp, "concat", Some(2), |_, args| {
1509 match (&args[0], &args[1]) {
1510 (Value::Array(a), Value::Array(b)) => {
1511 let mut result = a.borrow().clone();
1512 result.extend(b.borrow().clone());
1513 Ok(Value::Array(Rc::new(RefCell::new(result))))
1514 }
1515 (Value::String(a), Value::String(b)) => {
1516 Ok(Value::String(Rc::new(format!("{}{}", a, b))))
1517 }
1518 _ => Err(RuntimeError::new(
1519 "concat() requires two arrays or two strings",
1520 )),
1521 }
1522 });
1523
1524 define(interp, "zip", Some(2), |_, args| {
1525 match (&args[0], &args[1]) {
1526 (Value::Array(a), Value::Array(b)) => {
1527 let a = a.borrow();
1528 let b = b.borrow();
1529 let zipped: Vec<Value> = a
1530 .iter()
1531 .zip(b.iter())
1532 .map(|(x, y)| Value::Tuple(Rc::new(vec![x.clone(), y.clone()])))
1533 .collect();
1534 Ok(Value::Array(Rc::new(RefCell::new(zipped))))
1535 }
1536 _ => Err(RuntimeError::new("zip() requires two arrays")),
1537 }
1538 });
1539
1540 define(interp, "enumerate", Some(1), |_, args| match &args[0] {
1541 Value::Array(arr) => {
1542 let enumerated: Vec<Value> = arr
1543 .borrow()
1544 .iter()
1545 .enumerate()
1546 .map(|(i, v)| Value::Tuple(Rc::new(vec![Value::Int(i as i64), v.clone()])))
1547 .collect();
1548 Ok(Value::Array(Rc::new(RefCell::new(enumerated))))
1549 }
1550 _ => Err(RuntimeError::new("enumerate() requires array")),
1551 });
1552
1553 define(interp, "zip_with", Some(3), |_, args| {
1556 let mode = match &args[2] {
1557 Value::String(s) => s.as_str(),
1558 _ => return Err(RuntimeError::new("zip_with() mode must be string")),
1559 };
1560 match (&args[0], &args[1]) {
1561 (Value::Array(a), Value::Array(b)) => {
1562 let a = a.borrow();
1563 let b = b.borrow();
1564 let result: Result<Vec<Value>, RuntimeError> = a
1565 .iter()
1566 .zip(b.iter())
1567 .map(|(x, y)| match (x, y, mode) {
1568 (Value::Int(a), Value::Int(b), "add") => Ok(Value::Int(a + b)),
1569 (Value::Int(a), Value::Int(b), "sub") => Ok(Value::Int(a - b)),
1570 (Value::Int(a), Value::Int(b), "mul") => Ok(Value::Int(a * b)),
1571 (Value::Float(a), Value::Float(b), "add") => Ok(Value::Float(a + b)),
1572 (Value::Float(a), Value::Float(b), "sub") => Ok(Value::Float(a - b)),
1573 (Value::Float(a), Value::Float(b), "mul") => Ok(Value::Float(a * b)),
1574 (_, _, "pair") => Ok(Value::Tuple(Rc::new(vec![x.clone(), y.clone()]))),
1575 _ => Err(RuntimeError::new("zip_with() incompatible types or mode")),
1576 })
1577 .collect();
1578 Ok(Value::Array(Rc::new(RefCell::new(result?))))
1579 }
1580 _ => Err(RuntimeError::new("zip_with() requires two arrays")),
1581 }
1582 });
1583
1584 define(interp, "supremum", Some(2), |_, args| {
1586 match (&args[0], &args[1]) {
1587 (Value::Int(a), Value::Int(b)) => Ok(Value::Int(*a.max(b))),
1588 (Value::Float(a), Value::Float(b)) => Ok(Value::Float(a.max(*b))),
1589 (Value::Array(a), Value::Array(b)) => {
1590 let a = a.borrow();
1592 let b = b.borrow();
1593 let result: Result<Vec<Value>, RuntimeError> = a
1594 .iter()
1595 .zip(b.iter())
1596 .map(|(x, y)| match (x, y) {
1597 (Value::Int(a), Value::Int(b)) => Ok(Value::Int(*a.max(b))),
1598 (Value::Float(a), Value::Float(b)) => Ok(Value::Float(a.max(*b))),
1599 _ => Err(RuntimeError::new("supremum() requires numeric arrays")),
1600 })
1601 .collect();
1602 Ok(Value::Array(Rc::new(RefCell::new(result?))))
1603 }
1604 _ => Err(RuntimeError::new(
1605 "supremum() requires numeric values or arrays",
1606 )),
1607 }
1608 });
1609
1610 define(interp, "infimum", Some(2), |_, args| {
1612 match (&args[0], &args[1]) {
1613 (Value::Int(a), Value::Int(b)) => Ok(Value::Int(*a.min(b))),
1614 (Value::Float(a), Value::Float(b)) => Ok(Value::Float(a.min(*b))),
1615 (Value::Array(a), Value::Array(b)) => {
1616 let a = a.borrow();
1618 let b = b.borrow();
1619 let result: Result<Vec<Value>, RuntimeError> = a
1620 .iter()
1621 .zip(b.iter())
1622 .map(|(x, y)| match (x, y) {
1623 (Value::Int(a), Value::Int(b)) => Ok(Value::Int(*a.min(b))),
1624 (Value::Float(a), Value::Float(b)) => Ok(Value::Float(a.min(*b))),
1625 _ => Err(RuntimeError::new("infimum() requires numeric arrays")),
1626 })
1627 .collect();
1628 Ok(Value::Array(Rc::new(RefCell::new(result?))))
1629 }
1630 _ => Err(RuntimeError::new(
1631 "infimum() requires numeric values or arrays",
1632 )),
1633 }
1634 });
1635
1636 define(interp, "slice", Some(3), |_, args| {
1638 let start = match &args[1] {
1639 Value::Int(i) => *i as usize,
1640 _ => return Err(RuntimeError::new("slice() start must be integer")),
1641 };
1642 let end = match &args[2] {
1643 Value::Int(i) => *i as usize,
1644 _ => return Err(RuntimeError::new("slice() end must be integer")),
1645 };
1646 match &args[0] {
1647 Value::Array(arr) => {
1648 let arr = arr.borrow();
1649 let end = end.min(arr.len());
1650 let sliced: Vec<Value> = arr[start..end].to_vec();
1651 Ok(Value::Array(Rc::new(RefCell::new(sliced))))
1652 }
1653 Value::String(s) => {
1654 let chars: Vec<char> = s.chars().collect();
1655 let end = end.min(chars.len());
1656 let sliced: String = chars[start..end].iter().collect();
1657 Ok(Value::String(Rc::new(sliced)))
1658 }
1659 _ => Err(RuntimeError::new("slice() requires array or string")),
1660 }
1661 });
1662
1663 define(interp, "take", Some(2), |_, args| {
1664 let n = match &args[1] {
1665 Value::Int(i) => *i as usize,
1666 _ => return Err(RuntimeError::new("take() n must be integer")),
1667 };
1668 match &args[0] {
1669 Value::Array(arr) => {
1670 let taken: Vec<Value> = arr.borrow().iter().take(n).cloned().collect();
1671 Ok(Value::Array(Rc::new(RefCell::new(taken))))
1672 }
1673 _ => Err(RuntimeError::new("take() requires array")),
1674 }
1675 });
1676
1677 define(interp, "skip", Some(2), |_, args| {
1678 let n = match &args[1] {
1679 Value::Int(i) => *i as usize,
1680 _ => return Err(RuntimeError::new("skip() n must be integer")),
1681 };
1682 match &args[0] {
1683 Value::Array(arr) => {
1684 let skipped: Vec<Value> = arr.borrow().iter().skip(n).cloned().collect();
1685 Ok(Value::Array(Rc::new(RefCell::new(skipped))))
1686 }
1687 _ => Err(RuntimeError::new("skip() requires array")),
1688 }
1689 });
1690
1691 define(interp, "chunk", Some(2), |_, args| {
1692 let size = match &args[1] {
1693 Value::Int(i) if *i > 0 => *i as usize,
1694 _ => return Err(RuntimeError::new("chunk() size must be positive integer")),
1695 };
1696 match &args[0] {
1697 Value::Array(arr) => {
1698 let chunks: Vec<Value> = arr
1699 .borrow()
1700 .chunks(size)
1701 .map(|c| Value::Array(Rc::new(RefCell::new(c.to_vec()))))
1702 .collect();
1703 Ok(Value::Array(Rc::new(RefCell::new(chunks))))
1704 }
1705 _ => Err(RuntimeError::new("chunk() requires array")),
1706 }
1707 });
1708
1709 define(interp, "range", Some(2), |_, args| {
1711 let start = match &args[0] {
1712 Value::Int(n) => *n,
1713 _ => return Err(RuntimeError::new("range() requires integers")),
1714 };
1715 let end = match &args[1] {
1716 Value::Int(n) => *n,
1717 _ => return Err(RuntimeError::new("range() requires integers")),
1718 };
1719 let values: Vec<Value> = (start..end).map(Value::Int).collect();
1720 Ok(Value::Array(Rc::new(RefCell::new(values))))
1721 });
1722
1723 define(interp, "range_inclusive", Some(2), |_, args| {
1724 let start = match &args[0] {
1725 Value::Int(n) => *n,
1726 _ => return Err(RuntimeError::new("range_inclusive() requires integers")),
1727 };
1728 let end = match &args[1] {
1729 Value::Int(n) => *n,
1730 _ => return Err(RuntimeError::new("range_inclusive() requires integers")),
1731 };
1732 let values: Vec<Value> = (start..=end).map(Value::Int).collect();
1733 Ok(Value::Array(Rc::new(RefCell::new(values))))
1734 });
1735
1736 define(interp, "repeat", Some(2), |_, args| {
1737 let n = match &args[1] {
1738 Value::Int(i) if *i >= 0 => *i as usize,
1739 _ => {
1740 return Err(RuntimeError::new(
1741 "repeat() count must be non-negative integer",
1742 ))
1743 }
1744 };
1745 let repeated: Vec<Value> = std::iter::repeat(args[0].clone()).take(n).collect();
1746 Ok(Value::Array(Rc::new(RefCell::new(repeated))))
1747 });
1748
1749 define(interp, "map_new", Some(0), |_, _| {
1755 Ok(Value::Map(Rc::new(RefCell::new(HashMap::new()))))
1756 });
1757
1758 define(interp, "map_get", Some(2), |_, args| {
1760 let key = match &args[1] {
1761 Value::String(s) => s.to_string(),
1762 _ => return Err(RuntimeError::new("map_get() key must be string")),
1763 };
1764 match &args[0] {
1765 Value::Map(map) => Ok(map.borrow().get(&key).cloned().unwrap_or(Value::Null)),
1766 _ => Err(RuntimeError::new("map_get() requires map")),
1767 }
1768 });
1769
1770 define(interp, "map_set", Some(3), |_, args| {
1772 let key = match &args[1] {
1773 Value::String(s) => s.to_string(),
1774 _ => return Err(RuntimeError::new("map_set() key must be string")),
1775 };
1776 match &args[0] {
1777 Value::Map(map) => {
1778 map.borrow_mut().insert(key, args[2].clone());
1779 Ok(Value::Null)
1780 }
1781 _ => Err(RuntimeError::new("map_set() requires map")),
1782 }
1783 });
1784
1785 define(interp, "map_has", Some(2), |_, args| {
1787 let key = match &args[1] {
1788 Value::String(s) => s.to_string(),
1789 _ => return Err(RuntimeError::new("map_has() key must be string")),
1790 };
1791 match &args[0] {
1792 Value::Map(map) => Ok(Value::Bool(map.borrow().contains_key(&key))),
1793 _ => Err(RuntimeError::new("map_has() requires map")),
1794 }
1795 });
1796
1797 define(interp, "map_remove", Some(2), |_, args| {
1799 let key = match &args[1] {
1800 Value::String(s) => s.to_string(),
1801 _ => return Err(RuntimeError::new("map_remove() key must be string")),
1802 };
1803 match &args[0] {
1804 Value::Map(map) => Ok(map.borrow_mut().remove(&key).unwrap_or(Value::Null)),
1805 _ => Err(RuntimeError::new("map_remove() requires map")),
1806 }
1807 });
1808
1809 define(interp, "map_keys", Some(1), |_, args| match &args[0] {
1811 Value::Map(map) => {
1812 let keys: Vec<Value> = map
1813 .borrow()
1814 .keys()
1815 .map(|k| Value::String(Rc::new(k.clone())))
1816 .collect();
1817 Ok(Value::Array(Rc::new(RefCell::new(keys))))
1818 }
1819 _ => Err(RuntimeError::new("map_keys() requires map")),
1820 });
1821
1822 define(interp, "map_values", Some(1), |_, args| match &args[0] {
1824 Value::Map(map) => {
1825 let values: Vec<Value> = map.borrow().values().cloned().collect();
1826 Ok(Value::Array(Rc::new(RefCell::new(values))))
1827 }
1828 _ => Err(RuntimeError::new("map_values() requires map")),
1829 });
1830
1831 define(interp, "map_len", Some(1), |_, args| match &args[0] {
1833 Value::Map(map) => Ok(Value::Int(map.borrow().len() as i64)),
1834 _ => Err(RuntimeError::new("map_len() requires map")),
1835 });
1836
1837 define(interp, "map_clear", Some(1), |_, args| match &args[0] {
1839 Value::Map(map) => {
1840 map.borrow_mut().clear();
1841 Ok(Value::Null)
1842 }
1843 _ => Err(RuntimeError::new("map_clear() requires map")),
1844 });
1845
1846 define(interp, "set_new", Some(0), |_, _| {
1852 Ok(Value::Set(Rc::new(RefCell::new(
1853 std::collections::HashSet::new(),
1854 ))))
1855 });
1856
1857 define(interp, "set_add", Some(2), |_, args| {
1859 let item = match &args[1] {
1860 Value::String(s) => s.to_string(),
1861 _ => return Err(RuntimeError::new("set_add() item must be string")),
1862 };
1863 match &args[0] {
1864 Value::Set(set) => {
1865 set.borrow_mut().insert(item);
1866 Ok(Value::Null)
1867 }
1868 _ => Err(RuntimeError::new("set_add() requires set")),
1869 }
1870 });
1871
1872 define(interp, "set_has", Some(2), |_, args| {
1874 let item = match &args[1] {
1875 Value::String(s) => s.to_string(),
1876 _ => return Err(RuntimeError::new("set_has() item must be string")),
1877 };
1878 match &args[0] {
1879 Value::Set(set) => Ok(Value::Bool(set.borrow().contains(&item))),
1880 _ => Err(RuntimeError::new("set_has() requires set")),
1881 }
1882 });
1883
1884 define(interp, "set_remove", Some(2), |_, args| {
1886 let item = match &args[1] {
1887 Value::String(s) => s.to_string(),
1888 _ => return Err(RuntimeError::new("set_remove() item must be string")),
1889 };
1890 match &args[0] {
1891 Value::Set(set) => Ok(Value::Bool(set.borrow_mut().remove(&item))),
1892 _ => Err(RuntimeError::new("set_remove() requires set")),
1893 }
1894 });
1895
1896 define(interp, "set_to_array", Some(1), |_, args| match &args[0] {
1898 Value::Set(set) => {
1899 let items: Vec<Value> = set
1900 .borrow()
1901 .iter()
1902 .map(|s| Value::String(Rc::new(s.clone())))
1903 .collect();
1904 Ok(Value::Array(Rc::new(RefCell::new(items))))
1905 }
1906 _ => Err(RuntimeError::new("set_to_array() requires set")),
1907 });
1908
1909 define(interp, "set_len", Some(1), |_, args| match &args[0] {
1911 Value::Set(set) => Ok(Value::Int(set.borrow().len() as i64)),
1912 _ => Err(RuntimeError::new("set_len() requires set")),
1913 });
1914
1915 define(interp, "set_clear", Some(1), |_, args| match &args[0] {
1917 Value::Set(set) => {
1918 set.borrow_mut().clear();
1919 Ok(Value::Null)
1920 }
1921 _ => Err(RuntimeError::new("set_clear() requires set")),
1922 });
1923}
1924
1925fn values_equal(a: &Value, b: &Value) -> bool {
1926 match (a, b) {
1927 (Value::Null, Value::Null) => true,
1928 (Value::Bool(a), Value::Bool(b)) => a == b,
1929 (Value::Int(a), Value::Int(b)) => a == b,
1930 (Value::Float(a), Value::Float(b)) => (a - b).abs() < f64::EPSILON,
1931 (Value::String(a), Value::String(b)) => a == b,
1932 (Value::Char(a), Value::Char(b)) => a == b,
1933 (Value::Array(a), Value::Array(b)) => {
1934 let a = a.borrow();
1935 let b = b.borrow();
1936 a.len() == b.len() && a.iter().zip(b.iter()).all(|(x, y)| values_equal(x, y))
1937 }
1938 (Value::Tuple(a), Value::Tuple(b)) => {
1939 a.len() == b.len() && a.iter().zip(b.iter()).all(|(x, y)| values_equal(x, y))
1940 }
1941 _ => false,
1942 }
1943}
1944
1945fn compare_values(a: &Value, b: &Value) -> std::cmp::Ordering {
1946 match (a, b) {
1947 (Value::Int(a), Value::Int(b)) => a.cmp(b),
1948 (Value::Float(a), Value::Float(b)) => a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal),
1949 (Value::String(a), Value::String(b)) => a.cmp(b),
1950 (Value::Char(a), Value::Char(b)) => a.cmp(b),
1951 _ => std::cmp::Ordering::Equal,
1952 }
1953}
1954
1955fn register_string(interp: &mut Interpreter) {
1960 define(interp, "chars", Some(1), |_, args| match &args[0] {
1961 Value::String(s) => {
1962 let chars: Vec<Value> = s.chars().map(Value::Char).collect();
1963 Ok(Value::Array(Rc::new(RefCell::new(chars))))
1964 }
1965 _ => Err(RuntimeError::new("chars() requires string")),
1966 });
1967
1968 define(interp, "bytes", Some(1), |_, args| match &args[0] {
1969 Value::String(s) => {
1970 let bytes: Vec<Value> = s.bytes().map(|b| Value::Int(b as i64)).collect();
1971 Ok(Value::Array(Rc::new(RefCell::new(bytes))))
1972 }
1973 _ => Err(RuntimeError::new("bytes() requires string")),
1974 });
1975
1976 define(interp, "split", Some(2), |_, args| {
1977 match (&args[0], &args[1]) {
1978 (Value::String(s), Value::String(sep)) => {
1979 let parts: Vec<Value> = s
1980 .split(sep.as_str())
1981 .map(|p| Value::String(Rc::new(p.to_string())))
1982 .collect();
1983 Ok(Value::Array(Rc::new(RefCell::new(parts))))
1984 }
1985 (Value::String(s), Value::Char(sep)) => {
1986 let parts: Vec<Value> = s
1987 .split(*sep)
1988 .map(|p| Value::String(Rc::new(p.to_string())))
1989 .collect();
1990 Ok(Value::Array(Rc::new(RefCell::new(parts))))
1991 }
1992 _ => Err(RuntimeError::new("split() requires string and separator")),
1993 }
1994 });
1995
1996 define(interp, "join", Some(2), |_, args| {
1997 match (&args[0], &args[1]) {
1998 (Value::Array(arr), Value::String(sep)) => {
1999 let parts: Vec<String> = arr.borrow().iter().map(|v| format!("{}", v)).collect();
2000 Ok(Value::String(Rc::new(parts.join(sep.as_str()))))
2001 }
2002 _ => Err(RuntimeError::new(
2003 "join() requires array and separator string",
2004 )),
2005 }
2006 });
2007
2008 define(interp, "trim", Some(1), |_, args| match &args[0] {
2009 Value::String(s) => Ok(Value::String(Rc::new(s.trim().to_string()))),
2010 _ => Err(RuntimeError::new("trim() requires string")),
2011 });
2012
2013 define(interp, "trim_start", Some(1), |_, args| match &args[0] {
2014 Value::String(s) => Ok(Value::String(Rc::new(s.trim_start().to_string()))),
2015 _ => Err(RuntimeError::new("trim_start() requires string")),
2016 });
2017
2018 define(interp, "trim_end", Some(1), |_, args| match &args[0] {
2019 Value::String(s) => Ok(Value::String(Rc::new(s.trim_end().to_string()))),
2020 _ => Err(RuntimeError::new("trim_end() requires string")),
2021 });
2022
2023 define(interp, "upper", Some(1), |_, args| match &args[0] {
2024 Value::String(s) => Ok(Value::String(Rc::new(s.to_uppercase()))),
2025 Value::Char(c) => Ok(Value::Char(c.to_uppercase().next().unwrap_or(*c))),
2026 _ => Err(RuntimeError::new("upper() requires string or char")),
2027 });
2028
2029 define(interp, "lower", Some(1), |_, args| match &args[0] {
2030 Value::String(s) => Ok(Value::String(Rc::new(s.to_lowercase()))),
2031 Value::Char(c) => Ok(Value::Char(c.to_lowercase().next().unwrap_or(*c))),
2032 _ => Err(RuntimeError::new("lower() requires string or char")),
2033 });
2034
2035 define(interp, "capitalize", Some(1), |_, args| match &args[0] {
2036 Value::String(s) => {
2037 let mut chars = s.chars();
2038 let capitalized = match chars.next() {
2039 None => String::new(),
2040 Some(c) => c.to_uppercase().chain(chars).collect(),
2041 };
2042 Ok(Value::String(Rc::new(capitalized)))
2043 }
2044 _ => Err(RuntimeError::new("capitalize() requires string")),
2045 });
2046
2047 define(interp, "replace", Some(3), |_, args| {
2048 match (&args[0], &args[1], &args[2]) {
2049 (Value::String(s), Value::String(from), Value::String(to)) => Ok(Value::String(
2050 Rc::new(s.replace(from.as_str(), to.as_str())),
2051 )),
2052 _ => Err(RuntimeError::new("replace() requires three strings")),
2053 }
2054 });
2055
2056 define(interp, "starts_with", Some(2), |_, args| {
2057 match (&args[0], &args[1]) {
2058 (Value::String(s), Value::String(prefix)) => {
2059 Ok(Value::Bool(s.starts_with(prefix.as_str())))
2060 }
2061 _ => Err(RuntimeError::new("starts_with() requires two strings")),
2062 }
2063 });
2064
2065 define(interp, "ends_with", Some(2), |_, args| {
2066 match (&args[0], &args[1]) {
2067 (Value::String(s), Value::String(suffix)) => {
2068 Ok(Value::Bool(s.ends_with(suffix.as_str())))
2069 }
2070 _ => Err(RuntimeError::new("ends_with() requires two strings")),
2071 }
2072 });
2073
2074 define(interp, "repeat_str", Some(2), |_, args| {
2075 match (&args[0], &args[1]) {
2076 (Value::String(s), Value::Int(n)) if *n >= 0 => {
2077 Ok(Value::String(Rc::new(s.repeat(*n as usize))))
2078 }
2079 _ => Err(RuntimeError::new(
2080 "repeat_str() requires string and non-negative integer",
2081 )),
2082 }
2083 });
2084
2085 define(interp, "pad_left", Some(3), |_, args| {
2086 match (&args[0], &args[1], &args[2]) {
2087 (Value::String(s), Value::Int(width), Value::Char(c)) => {
2088 let width = *width as usize;
2089 if s.len() >= width {
2090 Ok(Value::String(s.clone()))
2091 } else {
2092 let padding: String = std::iter::repeat(*c).take(width - s.len()).collect();
2093 Ok(Value::String(Rc::new(format!("{}{}", padding, s))))
2094 }
2095 }
2096 _ => Err(RuntimeError::new(
2097 "pad_left() requires string, width, and char",
2098 )),
2099 }
2100 });
2101
2102 define(interp, "pad_right", Some(3), |_, args| {
2103 match (&args[0], &args[1], &args[2]) {
2104 (Value::String(s), Value::Int(width), Value::Char(c)) => {
2105 let width = *width as usize;
2106 if s.len() >= width {
2107 Ok(Value::String(s.clone()))
2108 } else {
2109 let padding: String = std::iter::repeat(*c).take(width - s.len()).collect();
2110 Ok(Value::String(Rc::new(format!("{}{}", s, padding))))
2111 }
2112 }
2113 _ => Err(RuntimeError::new(
2114 "pad_right() requires string, width, and char",
2115 )),
2116 }
2117 });
2118
2119 define(interp, "lines", Some(1), |_, args| match &args[0] {
2120 Value::String(s) => {
2121 let lines: Vec<Value> = s
2122 .lines()
2123 .map(|l| Value::String(Rc::new(l.to_string())))
2124 .collect();
2125 Ok(Value::Array(Rc::new(RefCell::new(lines))))
2126 }
2127 _ => Err(RuntimeError::new("lines() requires string")),
2128 });
2129
2130 define(interp, "words", Some(1), |_, args| match &args[0] {
2131 Value::String(s) => {
2132 let words: Vec<Value> = s
2133 .split_whitespace()
2134 .map(|w| Value::String(Rc::new(w.to_string())))
2135 .collect();
2136 Ok(Value::Array(Rc::new(RefCell::new(words))))
2137 }
2138 _ => Err(RuntimeError::new("words() requires string")),
2139 });
2140
2141 define(interp, "is_alpha", Some(1), |_, args| match &args[0] {
2142 Value::String(s) => Ok(Value::Bool(
2143 !s.is_empty() && s.chars().all(|c| c.is_alphabetic()),
2144 )),
2145 Value::Char(c) => Ok(Value::Bool(c.is_alphabetic())),
2146 _ => Err(RuntimeError::new("is_alpha() requires string or char")),
2147 });
2148
2149 define(interp, "is_digit", Some(1), |_, args| match &args[0] {
2150 Value::String(s) => Ok(Value::Bool(
2151 !s.is_empty() && s.chars().all(|c| c.is_ascii_digit()),
2152 )),
2153 Value::Char(c) => Ok(Value::Bool(c.is_ascii_digit())),
2154 _ => Err(RuntimeError::new("is_digit() requires string or char")),
2155 });
2156
2157 define(interp, "is_alnum", Some(1), |_, args| match &args[0] {
2158 Value::String(s) => Ok(Value::Bool(
2159 !s.is_empty() && s.chars().all(|c| c.is_alphanumeric()),
2160 )),
2161 Value::Char(c) => Ok(Value::Bool(c.is_alphanumeric())),
2162 _ => Err(RuntimeError::new("is_alnum() requires string or char")),
2163 });
2164
2165 define(interp, "is_space", Some(1), |_, args| match &args[0] {
2166 Value::String(s) => Ok(Value::Bool(
2167 !s.is_empty() && s.chars().all(|c| c.is_whitespace()),
2168 )),
2169 Value::Char(c) => Ok(Value::Bool(c.is_whitespace())),
2170 _ => Err(RuntimeError::new("is_space() requires string or char")),
2171 });
2172
2173 define(interp, "find", Some(2), |_, args| {
2179 match (&args[0], &args[1]) {
2180 (Value::String(s), Value::String(sub)) => {
2181 match s.find(sub.as_str()) {
2182 Some(byte_idx) => {
2183 let char_idx = s[..byte_idx].chars().count() as i64;
2185 Ok(Value::Int(char_idx))
2186 }
2187 None => Ok(Value::Int(-1)),
2188 }
2189 }
2190 (Value::String(s), Value::Char(c)) => match s.find(*c) {
2191 Some(byte_idx) => {
2192 let char_idx = s[..byte_idx].chars().count() as i64;
2193 Ok(Value::Int(char_idx))
2194 }
2195 None => Ok(Value::Int(-1)),
2196 },
2197 _ => Err(RuntimeError::new(
2198 "find() requires string and substring/char",
2199 )),
2200 }
2201 });
2202
2203 define(interp, "index_of", Some(2), |_, args| {
2205 match (&args[0], &args[1]) {
2206 (Value::String(s), Value::String(sub)) => match s.find(sub.as_str()) {
2207 Some(byte_idx) => {
2208 let char_idx = s[..byte_idx].chars().count() as i64;
2209 Ok(Value::Int(char_idx))
2210 }
2211 None => Ok(Value::Int(-1)),
2212 },
2213 (Value::String(s), Value::Char(c)) => match s.find(*c) {
2214 Some(byte_idx) => {
2215 let char_idx = s[..byte_idx].chars().count() as i64;
2216 Ok(Value::Int(char_idx))
2217 }
2218 None => Ok(Value::Int(-1)),
2219 },
2220 (Value::Array(arr), search) => {
2221 for (i, v) in arr.borrow().iter().enumerate() {
2223 if values_equal_simple(v, search) {
2224 return Ok(Value::Int(i as i64));
2225 }
2226 }
2227 Ok(Value::Int(-1))
2228 }
2229 _ => Err(RuntimeError::new(
2230 "index_of() requires array/string and element/substring",
2231 )),
2232 }
2233 });
2234
2235 define(interp, "last_index_of", Some(2), |_, args| {
2237 match (&args[0], &args[1]) {
2238 (Value::String(s), Value::String(sub)) => match s.rfind(sub.as_str()) {
2239 Some(byte_idx) => {
2240 let char_idx = s[..byte_idx].chars().count() as i64;
2241 Ok(Value::Int(char_idx))
2242 }
2243 None => Ok(Value::Int(-1)),
2244 },
2245 (Value::String(s), Value::Char(c)) => match s.rfind(*c) {
2246 Some(byte_idx) => {
2247 let char_idx = s[..byte_idx].chars().count() as i64;
2248 Ok(Value::Int(char_idx))
2249 }
2250 None => Ok(Value::Int(-1)),
2251 },
2252 _ => Err(RuntimeError::new(
2253 "last_index_of() requires string and substring/char",
2254 )),
2255 }
2256 });
2257
2258 define(interp, "substring", Some(3), |_, args| {
2260 let s = match &args[0] {
2261 Value::String(s) => (**s).clone(),
2262 _ => {
2263 return Err(RuntimeError::new(
2264 "substring: first argument must be a string",
2265 ))
2266 }
2267 };
2268 let start = match &args[1] {
2269 Value::Int(n) if *n >= 0 => *n as usize,
2270 _ => {
2271 return Err(RuntimeError::new(
2272 "substring: start must be a non-negative integer",
2273 ))
2274 }
2275 };
2276 let end = match &args[2] {
2277 Value::Int(n) if *n >= 0 => *n as usize,
2278 _ => {
2279 return Err(RuntimeError::new(
2280 "substring: end must be a non-negative integer",
2281 ))
2282 }
2283 };
2284 let chars: Vec<char> = s.chars().collect();
2285 let len = chars.len();
2286 let actual_start = start.min(len);
2287 let actual_end = end.min(len);
2288 if actual_start >= actual_end {
2289 return Ok(Value::String(Rc::new(String::new())));
2290 }
2291 let result: String = chars[actual_start..actual_end].iter().collect();
2292 Ok(Value::String(Rc::new(result)))
2293 });
2294
2295 define(interp, "count", Some(2), |_, args| {
2297 match (&args[0], &args[1]) {
2298 (Value::String(s), Value::String(sub)) => {
2299 if sub.is_empty() {
2300 return Err(RuntimeError::new("count: cannot count empty string"));
2301 }
2302 let count = s.matches(sub.as_str()).count() as i64;
2303 Ok(Value::Int(count))
2304 }
2305 (Value::String(s), Value::Char(c)) => {
2306 let count = s.chars().filter(|&ch| ch == *c).count() as i64;
2307 Ok(Value::Int(count))
2308 }
2309 _ => Err(RuntimeError::new(
2310 "count() requires string and substring/char",
2311 )),
2312 }
2313 });
2314
2315 define(interp, "char_at", Some(2), |_, args| {
2318 let s = match &args[0] {
2319 Value::String(s) => (**s).clone(),
2320 _ => {
2321 return Err(RuntimeError::new(
2322 "char_at: first argument must be a string",
2323 ))
2324 }
2325 };
2326 let idx = match &args[1] {
2327 Value::Int(n) => *n,
2328 _ => {
2329 return Err(RuntimeError::new(
2330 "char_at: second argument must be an integer",
2331 ))
2332 }
2333 };
2334 let actual_idx = if idx < 0 {
2336 (s.len() as i64 + idx) as usize
2338 } else {
2339 idx as usize
2340 };
2341 if actual_idx < s.len() {
2342 let remaining = &s[actual_idx..];
2343 match remaining.chars().next() {
2344 Some(c) => Ok(Value::Char(c)),
2345 None => Ok(Value::Null),
2346 }
2347 } else {
2348 Ok(Value::Null)
2349 }
2350 });
2351
2352 define(interp, "char_code_at", Some(2), |_, args| {
2354 let s = match &args[0] {
2355 Value::String(s) => (**s).clone(),
2356 _ => {
2357 return Err(RuntimeError::new(
2358 "char_code_at: first argument must be a string",
2359 ))
2360 }
2361 };
2362 let idx = match &args[1] {
2363 Value::Int(n) => *n,
2364 _ => {
2365 return Err(RuntimeError::new(
2366 "char_code_at: second argument must be an integer",
2367 ))
2368 }
2369 };
2370 let chars: Vec<char> = s.chars().collect();
2371 let actual_idx = if idx < 0 {
2372 (chars.len() as i64 + idx) as usize
2373 } else {
2374 idx as usize
2375 };
2376 match chars.get(actual_idx) {
2377 Some(c) => Ok(Value::Int(*c as i64)),
2378 None => Ok(Value::Null),
2379 }
2380 });
2381
2382 define(interp, "from_char_code", Some(1), |_, args| {
2384 let code = match &args[0] {
2385 Value::Int(n) => *n as u32,
2386 _ => {
2387 return Err(RuntimeError::new(
2388 "from_char_code: argument must be an integer",
2389 ))
2390 }
2391 };
2392 match char::from_u32(code) {
2393 Some(c) => Ok(Value::String(Rc::new(c.to_string()))),
2394 None => Err(RuntimeError::new(
2395 "from_char_code: invalid Unicode code point",
2396 )),
2397 }
2398 });
2399
2400 define(interp, "insert", Some(3), |_, args| {
2402 let s = match &args[0] {
2403 Value::String(s) => (**s).clone(),
2404 _ => return Err(RuntimeError::new("insert: first argument must be a string")),
2405 };
2406 let idx = match &args[1] {
2407 Value::Int(n) if *n >= 0 => *n as usize,
2408 _ => {
2409 return Err(RuntimeError::new(
2410 "insert: index must be a non-negative integer",
2411 ))
2412 }
2413 };
2414 let insertion = match &args[2] {
2415 Value::String(s) => (**s).clone(),
2416 _ => return Err(RuntimeError::new("insert: third argument must be a string")),
2417 };
2418 let chars: Vec<char> = s.chars().collect();
2419 let actual_idx = idx.min(chars.len());
2420 let mut result: String = chars[..actual_idx].iter().collect();
2421 result.push_str(&insertion);
2422 result.extend(chars[actual_idx..].iter());
2423 Ok(Value::String(Rc::new(result)))
2424 });
2425
2426 define(interp, "remove", Some(3), |_, args| {
2428 let s = match &args[0] {
2429 Value::String(s) => (**s).clone(),
2430 _ => return Err(RuntimeError::new("remove: first argument must be a string")),
2431 };
2432 let start = match &args[1] {
2433 Value::Int(n) if *n >= 0 => *n as usize,
2434 _ => {
2435 return Err(RuntimeError::new(
2436 "remove: start must be a non-negative integer",
2437 ))
2438 }
2439 };
2440 let len = match &args[2] {
2441 Value::Int(n) if *n >= 0 => *n as usize,
2442 _ => {
2443 return Err(RuntimeError::new(
2444 "remove: length must be a non-negative integer",
2445 ))
2446 }
2447 };
2448 let chars: Vec<char> = s.chars().collect();
2449 let str_len = chars.len();
2450 let actual_start = start.min(str_len);
2451 let actual_end = (start + len).min(str_len);
2452 let mut result: String = chars[..actual_start].iter().collect();
2453 result.extend(chars[actual_end..].iter());
2454 Ok(Value::String(Rc::new(result)))
2455 });
2456
2457 define(interp, "compare", Some(2), |_, args| {
2459 match (&args[0], &args[1]) {
2460 (Value::String(a), Value::String(b)) => {
2461 let result = match a.cmp(b) {
2462 std::cmp::Ordering::Less => -1,
2463 std::cmp::Ordering::Equal => 0,
2464 std::cmp::Ordering::Greater => 1,
2465 };
2466 Ok(Value::Int(result))
2467 }
2468 _ => Err(RuntimeError::new("compare() requires two strings")),
2469 }
2470 });
2471
2472 define(interp, "compare_ignore_case", Some(2), |_, args| {
2474 match (&args[0], &args[1]) {
2475 (Value::String(a), Value::String(b)) => {
2476 let result = match a.to_lowercase().cmp(&b.to_lowercase()) {
2477 std::cmp::Ordering::Less => -1,
2478 std::cmp::Ordering::Equal => 0,
2479 std::cmp::Ordering::Greater => 1,
2480 };
2481 Ok(Value::Int(result))
2482 }
2483 _ => Err(RuntimeError::new(
2484 "compare_ignore_case() requires two strings",
2485 )),
2486 }
2487 });
2488
2489 define(interp, "char_count", Some(1), |_, args| match &args[0] {
2491 Value::String(s) => Ok(Value::Int(s.chars().count() as i64)),
2492 _ => Err(RuntimeError::new("char_count() requires string")),
2493 });
2494
2495 define(interp, "byte_count", Some(1), |_, args| match &args[0] {
2497 Value::String(s) => Ok(Value::Int(s.len() as i64)),
2498 _ => Err(RuntimeError::new("byte_count() requires string")),
2499 });
2500
2501 define(interp, "is_empty", Some(1), |_, args| match &args[0] {
2503 Value::String(s) => Ok(Value::Bool(s.is_empty())),
2504 Value::Array(arr) => Ok(Value::Bool(arr.borrow().is_empty())),
2505 _ => Err(RuntimeError::new("is_empty() requires string or array")),
2506 });
2507
2508 define(interp, "is_blank", Some(1), |_, args| match &args[0] {
2510 Value::String(s) => Ok(Value::Bool(s.trim().is_empty())),
2511 _ => Err(RuntimeError::new("is_blank() requires string")),
2512 });
2513
2514 define(interp, "nfc", Some(1), |_, args| match &args[0] {
2520 Value::String(s) => Ok(Value::String(Rc::new(s.nfc().collect()))),
2521 _ => Err(RuntimeError::new("nfc() requires string")),
2522 });
2523
2524 define(interp, "nfd", Some(1), |_, args| match &args[0] {
2526 Value::String(s) => Ok(Value::String(Rc::new(s.nfd().collect()))),
2527 _ => Err(RuntimeError::new("nfd() requires string")),
2528 });
2529
2530 define(interp, "nfkc", Some(1), |_, args| match &args[0] {
2532 Value::String(s) => Ok(Value::String(Rc::new(s.nfkc().collect()))),
2533 _ => Err(RuntimeError::new("nfkc() requires string")),
2534 });
2535
2536 define(interp, "nfkd", Some(1), |_, args| match &args[0] {
2538 Value::String(s) => Ok(Value::String(Rc::new(s.nfkd().collect()))),
2539 _ => Err(RuntimeError::new("nfkd() requires string")),
2540 });
2541
2542 define(interp, "is_nfc", Some(1), |_, args| match &args[0] {
2544 Value::String(s) => {
2545 let normalized: String = s.nfc().collect();
2546 Ok(Value::Bool(*s.as_ref() == normalized))
2547 }
2548 _ => Err(RuntimeError::new("is_nfc() requires string")),
2549 });
2550
2551 define(interp, "is_nfd", Some(1), |_, args| match &args[0] {
2553 Value::String(s) => {
2554 let normalized: String = s.nfd().collect();
2555 Ok(Value::Bool(*s.as_ref() == normalized))
2556 }
2557 _ => Err(RuntimeError::new("is_nfd() requires string")),
2558 });
2559
2560 define(interp, "graphemes", Some(1), |_, args| match &args[0] {
2566 Value::String(s) => {
2567 let graphemes: Vec<Value> = s
2568 .graphemes(true)
2569 .map(|g| Value::String(Rc::new(g.to_string())))
2570 .collect();
2571 Ok(Value::Array(Rc::new(RefCell::new(graphemes))))
2572 }
2573 _ => Err(RuntimeError::new("graphemes() requires string")),
2574 });
2575
2576 define(interp, "grapheme_count", Some(1), |_, args| {
2578 match &args[0] {
2579 Value::String(s) => Ok(Value::Int(s.graphemes(true).count() as i64)),
2580 _ => Err(RuntimeError::new("grapheme_count() requires string")),
2581 }
2582 });
2583
2584 define(interp, "grapheme_at", Some(2), |_, args| {
2586 let s = match &args[0] {
2587 Value::String(s) => (**s).clone(),
2588 _ => {
2589 return Err(RuntimeError::new(
2590 "grapheme_at: first argument must be a string",
2591 ))
2592 }
2593 };
2594 let idx = match &args[1] {
2595 Value::Int(n) => *n,
2596 _ => {
2597 return Err(RuntimeError::new(
2598 "grapheme_at: second argument must be an integer",
2599 ))
2600 }
2601 };
2602 let graphemes: Vec<&str> = s.graphemes(true).collect();
2603 let actual_idx = if idx < 0 {
2604 (graphemes.len() as i64 + idx) as usize
2605 } else {
2606 idx as usize
2607 };
2608 match graphemes.get(actual_idx) {
2609 Some(g) => Ok(Value::String(Rc::new(g.to_string()))),
2610 None => Ok(Value::Null),
2611 }
2612 });
2613
2614 define(interp, "grapheme_slice", Some(3), |_, args| {
2616 let s = match &args[0] {
2617 Value::String(s) => (**s).clone(),
2618 _ => {
2619 return Err(RuntimeError::new(
2620 "grapheme_slice: first argument must be a string",
2621 ))
2622 }
2623 };
2624 let start = match &args[1] {
2625 Value::Int(n) if *n >= 0 => *n as usize,
2626 _ => {
2627 return Err(RuntimeError::new(
2628 "grapheme_slice: start must be a non-negative integer",
2629 ))
2630 }
2631 };
2632 let end = match &args[2] {
2633 Value::Int(n) if *n >= 0 => *n as usize,
2634 _ => {
2635 return Err(RuntimeError::new(
2636 "grapheme_slice: end must be a non-negative integer",
2637 ))
2638 }
2639 };
2640 let graphemes: Vec<&str> = s.graphemes(true).collect();
2641 let len = graphemes.len();
2642 let actual_start = start.min(len);
2643 let actual_end = end.min(len);
2644 if actual_start >= actual_end {
2645 return Ok(Value::String(Rc::new(String::new())));
2646 }
2647 let result: String = graphemes[actual_start..actual_end].join("");
2648 Ok(Value::String(Rc::new(result)))
2649 });
2650
2651 define(interp, "grapheme_reverse", Some(1), |_, args| {
2653 match &args[0] {
2654 Value::String(s) => {
2655 let reversed: String = s.graphemes(true).rev().collect();
2656 Ok(Value::String(Rc::new(reversed)))
2657 }
2658 _ => Err(RuntimeError::new("grapheme_reverse() requires string")),
2659 }
2660 });
2661
2662 define(interp, "word_boundaries", Some(1), |_, args| {
2664 match &args[0] {
2665 Value::String(s) => {
2666 let words: Vec<Value> = s
2667 .unicode_words()
2668 .map(|w| Value::String(Rc::new(w.to_string())))
2669 .collect();
2670 Ok(Value::Array(Rc::new(RefCell::new(words))))
2671 }
2672 _ => Err(RuntimeError::new("word_boundaries() requires string")),
2673 }
2674 });
2675
2676 define(interp, "string_builder", Some(0), |_, _| {
2683 Ok(Value::String(Rc::new(String::new())))
2684 });
2685
2686 define(interp, "concat_all", Some(1), |_, args| match &args[0] {
2688 Value::Array(arr) => {
2689 let parts: Vec<String> = arr
2690 .borrow()
2691 .iter()
2692 .map(|v| match v {
2693 Value::String(s) => (**s).clone(),
2694 other => format!("{}", other),
2695 })
2696 .collect();
2697 Ok(Value::String(Rc::new(parts.join(""))))
2698 }
2699 _ => Err(RuntimeError::new("concat_all() requires array")),
2700 });
2701
2702 define(interp, "repeat_join", Some(3), |_, args| {
2704 let s = match &args[0] {
2705 Value::String(s) => (**s).clone(),
2706 _ => {
2707 return Err(RuntimeError::new(
2708 "repeat_join: first argument must be a string",
2709 ))
2710 }
2711 };
2712 let n = match &args[1] {
2713 Value::Int(n) if *n >= 0 => *n as usize,
2714 _ => {
2715 return Err(RuntimeError::new(
2716 "repeat_join: count must be a non-negative integer",
2717 ))
2718 }
2719 };
2720 let sep = match &args[2] {
2721 Value::String(s) => (**s).clone(),
2722 _ => return Err(RuntimeError::new("repeat_join: separator must be a string")),
2723 };
2724 if n == 0 {
2725 return Ok(Value::String(Rc::new(String::new())));
2726 }
2727 let parts: Vec<&str> = std::iter::repeat(s.as_str()).take(n).collect();
2728 Ok(Value::String(Rc::new(parts.join(&sep))))
2729 });
2730}
2731
2732fn register_evidence(interp: &mut Interpreter) {
2737 use crate::interpreter::RuntimeConfidence;
2738
2739 define(interp, "known", Some(1), |_, args| {
2741 Ok(Value::Evidential {
2742 value: Box::new(args[0].clone()),
2743 evidence: Evidence::Known,
2744 })
2745 });
2746
2747 define(interp, "uncertain", Some(1), |_, args| {
2748 Ok(Value::Evidential {
2749 value: Box::new(args[0].clone()),
2750 evidence: Evidence::Uncertain,
2751 })
2752 });
2753
2754 define(interp, "reported", Some(1), |_, args| {
2755 Ok(Value::Evidential {
2756 value: Box::new(args[0].clone()),
2757 evidence: Evidence::Reported,
2758 })
2759 });
2760
2761 define(interp, "paradox", Some(1), |_, args| {
2762 Ok(Value::Evidential {
2763 value: Box::new(args[0].clone()),
2764 evidence: Evidence::Paradox,
2765 })
2766 });
2767
2768 define(interp, "evidence_of", Some(1), |_, args| {
2770 match &args[0] {
2771 Value::Evidential { evidence, .. } => {
2772 let level = match evidence {
2773 Evidence::Known => "known",
2774 Evidence::Uncertain => "uncertain",
2775 Evidence::Reported => "reported",
2776 Evidence::Predicted => "predicted",
2777 Evidence::Paradox => "paradox",
2778 };
2779 Ok(Value::String(Rc::new(level.to_string())))
2780 }
2781 _ => Ok(Value::String(Rc::new("known".to_string()))), }
2783 });
2784
2785 define(interp, "is_known", Some(1), |_, args| {
2786 match &args[0] {
2787 Value::Evidential {
2788 evidence: Evidence::Known,
2789 ..
2790 } => Ok(Value::Bool(true)),
2791 Value::Evidential { .. } => Ok(Value::Bool(false)),
2792 _ => Ok(Value::Bool(true)), }
2794 });
2795
2796 define(interp, "is_uncertain", Some(1), |_, args| match &args[0] {
2797 Value::Evidential {
2798 evidence: Evidence::Uncertain,
2799 ..
2800 } => Ok(Value::Bool(true)),
2801 _ => Ok(Value::Bool(false)),
2802 });
2803
2804 define(interp, "is_reported", Some(1), |_, args| match &args[0] {
2805 Value::Evidential {
2806 evidence: Evidence::Reported,
2807 ..
2808 } => Ok(Value::Bool(true)),
2809 _ => Ok(Value::Bool(false)),
2810 });
2811
2812 define(interp, "is_paradox", Some(1), |_, args| match &args[0] {
2813 Value::Evidential {
2814 evidence: Evidence::Paradox,
2815 ..
2816 } => Ok(Value::Bool(true)),
2817 _ => Ok(Value::Bool(false)),
2818 });
2819
2820 define(interp, "strip_evidence", Some(1), |_, args| {
2822 match &args[0] {
2823 Value::Evidential { value, .. } => Ok(*value.clone()),
2824 other => Ok(other.clone()),
2825 }
2826 });
2827
2828 define(interp, "trust", Some(1), |_, args| {
2830 match &args[0] {
2832 Value::Evidential { value, .. } => Ok(Value::Evidential {
2833 value: value.clone(),
2834 evidence: Evidence::Known,
2835 }),
2836 other => Ok(other.clone()),
2837 }
2838 });
2839
2840 define(interp, "verify", Some(2), |_, args| {
2841 let pred_result = match &args[1] {
2843 Value::Bool(b) => *b,
2844 _ => return Err(RuntimeError::new("verify() predicate must be bool")),
2845 };
2846
2847 if pred_result {
2848 match &args[0] {
2849 Value::Evidential { value, .. } => Ok(Value::Evidential {
2850 value: value.clone(),
2851 evidence: Evidence::Known,
2852 }),
2853 other => Ok(other.clone()),
2854 }
2855 } else {
2856 Ok(args[0].clone()) }
2858 });
2859
2860 define(interp, "combine_evidence", Some(2), |_, args| {
2862 let ev1 = match &args[0] {
2863 Value::Evidential { evidence, .. } => *evidence,
2864 _ => Evidence::Known,
2865 };
2866 let ev2 = match &args[1] {
2867 Value::Evidential { evidence, .. } => *evidence,
2868 _ => Evidence::Known,
2869 };
2870
2871 let combined = match (ev1, ev2) {
2873 (Evidence::Paradox, _) | (_, Evidence::Paradox) => Evidence::Paradox,
2874 (Evidence::Reported, _) | (_, Evidence::Reported) => Evidence::Reported,
2875 (Evidence::Predicted, _) | (_, Evidence::Predicted) => Evidence::Predicted,
2876 (Evidence::Uncertain, _) | (_, Evidence::Uncertain) => Evidence::Uncertain,
2877 _ => Evidence::Known,
2878 };
2879
2880 Ok(Value::String(Rc::new(
2881 match combined {
2882 Evidence::Known => "known",
2883 Evidence::Uncertain => "uncertain",
2884 Evidence::Reported => "reported",
2885 Evidence::Predicted => "predicted",
2886 Evidence::Paradox => "paradox",
2887 }
2888 .to_string(),
2889 )))
2890 });
2891
2892 define(interp, "affect_to_evidence", Some(1), |_, args| {
2896 match &args[0] {
2897 Value::Affective { affect, .. } => {
2898 if affect.sarcasm {
2900 return Ok(Value::String(Rc::new("uncertain".to_string())));
2901 }
2902 match affect.confidence {
2904 Some(RuntimeConfidence::High) => {
2905 Ok(Value::String(Rc::new("known".to_string())))
2906 }
2907 Some(RuntimeConfidence::Low) => {
2908 Ok(Value::String(Rc::new("uncertain".to_string())))
2909 }
2910 _ => Ok(Value::String(Rc::new("known".to_string()))),
2911 }
2912 }
2913 _ => Ok(Value::String(Rc::new("known".to_string()))),
2914 }
2915 });
2916
2917 define(
2919 interp,
2920 "affect_as_evidence",
2921 Some(1),
2922 |_, args| match &args[0] {
2923 Value::Affective { value, affect } => {
2924 let evidence = if affect.sarcasm {
2925 Evidence::Uncertain
2926 } else {
2927 match affect.confidence {
2928 Some(RuntimeConfidence::High) => Evidence::Known,
2929 Some(RuntimeConfidence::Low) => Evidence::Uncertain,
2930 _ => Evidence::Known,
2931 }
2932 };
2933 Ok(Value::Evidential {
2934 value: value.clone(),
2935 evidence,
2936 })
2937 }
2938 other => Ok(other.clone()),
2939 },
2940 );
2941
2942 define(
2944 interp,
2945 "is_affect_uncertain",
2946 Some(1),
2947 |_, args| match &args[0] {
2948 Value::Affective { affect, .. } => {
2949 let uncertain =
2950 affect.sarcasm || matches!(affect.confidence, Some(RuntimeConfidence::Low));
2951 Ok(Value::Bool(uncertain))
2952 }
2953 _ => Ok(Value::Bool(false)),
2954 },
2955 );
2956
2957 define(interp, "with_affect_evidence", Some(2), |_, args| {
2959 match &args[0] {
2961 Value::Affective { affect, .. } => {
2962 let evidence = if affect.sarcasm {
2963 Evidence::Uncertain
2964 } else {
2965 match affect.confidence {
2966 Some(RuntimeConfidence::High) => Evidence::Known,
2967 Some(RuntimeConfidence::Low) => Evidence::Uncertain,
2968 _ => Evidence::Known,
2969 }
2970 };
2971 Ok(Value::Evidential {
2972 value: Box::new(args[1].clone()),
2973 evidence,
2974 })
2975 }
2976 Value::Evidential { evidence, .. } => {
2977 Ok(Value::Evidential {
2979 value: Box::new(args[1].clone()),
2980 evidence: *evidence,
2981 })
2982 }
2983 _ => Ok(args[1].clone()),
2984 }
2985 });
2986}
2987
2988fn register_affect(interp: &mut Interpreter) {
2993 use crate::interpreter::{
2994 RuntimeAffect, RuntimeConfidence, RuntimeEmotion, RuntimeFormality, RuntimeIntensity,
2995 RuntimeSentiment,
2996 };
2997
2998 define(interp, "positive", Some(1), |_, args| {
3002 Ok(Value::Affective {
3003 value: Box::new(args[0].clone()),
3004 affect: RuntimeAffect {
3005 sentiment: Some(RuntimeSentiment::Positive),
3006 sarcasm: false,
3007 intensity: None,
3008 formality: None,
3009 emotion: None,
3010 confidence: None,
3011 },
3012 })
3013 });
3014
3015 define(interp, "negative", Some(1), |_, args| {
3016 Ok(Value::Affective {
3017 value: Box::new(args[0].clone()),
3018 affect: RuntimeAffect {
3019 sentiment: Some(RuntimeSentiment::Negative),
3020 sarcasm: false,
3021 intensity: None,
3022 formality: None,
3023 emotion: None,
3024 confidence: None,
3025 },
3026 })
3027 });
3028
3029 define(interp, "neutral", Some(1), |_, args| {
3030 Ok(Value::Affective {
3031 value: Box::new(args[0].clone()),
3032 affect: RuntimeAffect {
3033 sentiment: Some(RuntimeSentiment::Neutral),
3034 sarcasm: false,
3035 intensity: None,
3036 formality: None,
3037 emotion: None,
3038 confidence: None,
3039 },
3040 })
3041 });
3042
3043 define(interp, "sarcastic", Some(1), |_, args| {
3045 Ok(Value::Affective {
3046 value: Box::new(args[0].clone()),
3047 affect: RuntimeAffect {
3048 sentiment: None,
3049 sarcasm: true,
3050 intensity: None,
3051 formality: None,
3052 emotion: None,
3053 confidence: None,
3054 },
3055 })
3056 });
3057
3058 define(interp, "intensify", Some(1), |_, args| {
3060 Ok(Value::Affective {
3061 value: Box::new(args[0].clone()),
3062 affect: RuntimeAffect {
3063 sentiment: None,
3064 sarcasm: false,
3065 intensity: Some(RuntimeIntensity::Up),
3066 formality: None,
3067 emotion: None,
3068 confidence: None,
3069 },
3070 })
3071 });
3072
3073 define(interp, "dampen", Some(1), |_, args| {
3074 Ok(Value::Affective {
3075 value: Box::new(args[0].clone()),
3076 affect: RuntimeAffect {
3077 sentiment: None,
3078 sarcasm: false,
3079 intensity: Some(RuntimeIntensity::Down),
3080 formality: None,
3081 emotion: None,
3082 confidence: None,
3083 },
3084 })
3085 });
3086
3087 define(interp, "maximize", Some(1), |_, args| {
3088 Ok(Value::Affective {
3089 value: Box::new(args[0].clone()),
3090 affect: RuntimeAffect {
3091 sentiment: None,
3092 sarcasm: false,
3093 intensity: Some(RuntimeIntensity::Max),
3094 formality: None,
3095 emotion: None,
3096 confidence: None,
3097 },
3098 })
3099 });
3100
3101 define(interp, "formal", Some(1), |_, args| {
3103 Ok(Value::Affective {
3104 value: Box::new(args[0].clone()),
3105 affect: RuntimeAffect {
3106 sentiment: None,
3107 sarcasm: false,
3108 intensity: None,
3109 formality: Some(RuntimeFormality::Formal),
3110 emotion: None,
3111 confidence: None,
3112 },
3113 })
3114 });
3115
3116 define(interp, "informal", Some(1), |_, args| {
3117 Ok(Value::Affective {
3118 value: Box::new(args[0].clone()),
3119 affect: RuntimeAffect {
3120 sentiment: None,
3121 sarcasm: false,
3122 intensity: None,
3123 formality: Some(RuntimeFormality::Informal),
3124 emotion: None,
3125 confidence: None,
3126 },
3127 })
3128 });
3129
3130 define(interp, "joyful", Some(1), |_, args| {
3132 Ok(Value::Affective {
3133 value: Box::new(args[0].clone()),
3134 affect: RuntimeAffect {
3135 sentiment: None,
3136 sarcasm: false,
3137 intensity: None,
3138 formality: None,
3139 emotion: Some(RuntimeEmotion::Joy),
3140 confidence: None,
3141 },
3142 })
3143 });
3144
3145 define(interp, "sad", Some(1), |_, args| {
3146 Ok(Value::Affective {
3147 value: Box::new(args[0].clone()),
3148 affect: RuntimeAffect {
3149 sentiment: None,
3150 sarcasm: false,
3151 intensity: None,
3152 formality: None,
3153 emotion: Some(RuntimeEmotion::Sadness),
3154 confidence: None,
3155 },
3156 })
3157 });
3158
3159 define(interp, "angry", Some(1), |_, args| {
3160 Ok(Value::Affective {
3161 value: Box::new(args[0].clone()),
3162 affect: RuntimeAffect {
3163 sentiment: None,
3164 sarcasm: false,
3165 intensity: None,
3166 formality: None,
3167 emotion: Some(RuntimeEmotion::Anger),
3168 confidence: None,
3169 },
3170 })
3171 });
3172
3173 define(interp, "fearful", Some(1), |_, args| {
3174 Ok(Value::Affective {
3175 value: Box::new(args[0].clone()),
3176 affect: RuntimeAffect {
3177 sentiment: None,
3178 sarcasm: false,
3179 intensity: None,
3180 formality: None,
3181 emotion: Some(RuntimeEmotion::Fear),
3182 confidence: None,
3183 },
3184 })
3185 });
3186
3187 define(interp, "surprised", Some(1), |_, args| {
3188 Ok(Value::Affective {
3189 value: Box::new(args[0].clone()),
3190 affect: RuntimeAffect {
3191 sentiment: None,
3192 sarcasm: false,
3193 intensity: None,
3194 formality: None,
3195 emotion: Some(RuntimeEmotion::Surprise),
3196 confidence: None,
3197 },
3198 })
3199 });
3200
3201 define(interp, "loving", Some(1), |_, args| {
3202 Ok(Value::Affective {
3203 value: Box::new(args[0].clone()),
3204 affect: RuntimeAffect {
3205 sentiment: None,
3206 sarcasm: false,
3207 intensity: None,
3208 formality: None,
3209 emotion: Some(RuntimeEmotion::Love),
3210 confidence: None,
3211 },
3212 })
3213 });
3214
3215 define(interp, "high_confidence", Some(1), |_, args| {
3217 Ok(Value::Affective {
3218 value: Box::new(args[0].clone()),
3219 affect: RuntimeAffect {
3220 sentiment: None,
3221 sarcasm: false,
3222 intensity: None,
3223 formality: None,
3224 emotion: None,
3225 confidence: Some(RuntimeConfidence::High),
3226 },
3227 })
3228 });
3229
3230 define(interp, "medium_confidence", Some(1), |_, args| {
3231 Ok(Value::Affective {
3232 value: Box::new(args[0].clone()),
3233 affect: RuntimeAffect {
3234 sentiment: None,
3235 sarcasm: false,
3236 intensity: None,
3237 formality: None,
3238 emotion: None,
3239 confidence: Some(RuntimeConfidence::Medium),
3240 },
3241 })
3242 });
3243
3244 define(interp, "low_confidence", Some(1), |_, args| {
3245 Ok(Value::Affective {
3246 value: Box::new(args[0].clone()),
3247 affect: RuntimeAffect {
3248 sentiment: None,
3249 sarcasm: false,
3250 intensity: None,
3251 formality: None,
3252 emotion: None,
3253 confidence: Some(RuntimeConfidence::Low),
3254 },
3255 })
3256 });
3257
3258 define(interp, "affect_of", Some(1), |_, args| match &args[0] {
3261 Value::Affective { affect, .. } => {
3262 let mut parts = Vec::new();
3263 if let Some(s) = &affect.sentiment {
3264 parts.push(match s {
3265 RuntimeSentiment::Positive => "positive",
3266 RuntimeSentiment::Negative => "negative",
3267 RuntimeSentiment::Neutral => "neutral",
3268 });
3269 }
3270 if affect.sarcasm {
3271 parts.push("sarcastic");
3272 }
3273 if let Some(i) = &affect.intensity {
3274 parts.push(match i {
3275 RuntimeIntensity::Up => "intensified",
3276 RuntimeIntensity::Down => "dampened",
3277 RuntimeIntensity::Max => "maximized",
3278 });
3279 }
3280 if let Some(f) = &affect.formality {
3281 parts.push(match f {
3282 RuntimeFormality::Formal => "formal",
3283 RuntimeFormality::Informal => "informal",
3284 });
3285 }
3286 if let Some(e) = &affect.emotion {
3287 parts.push(match e {
3288 RuntimeEmotion::Joy => "joyful",
3289 RuntimeEmotion::Sadness => "sad",
3290 RuntimeEmotion::Anger => "angry",
3291 RuntimeEmotion::Fear => "fearful",
3292 RuntimeEmotion::Surprise => "surprised",
3293 RuntimeEmotion::Love => "loving",
3294 });
3295 }
3296 if let Some(c) = &affect.confidence {
3297 parts.push(match c {
3298 RuntimeConfidence::High => "high_confidence",
3299 RuntimeConfidence::Medium => "medium_confidence",
3300 RuntimeConfidence::Low => "low_confidence",
3301 });
3302 }
3303 Ok(Value::String(Rc::new(parts.join(", "))))
3304 }
3305 _ => Ok(Value::String(Rc::new("none".to_string()))),
3306 });
3307
3308 define(interp, "is_sarcastic", Some(1), |_, args| match &args[0] {
3309 Value::Affective { affect, .. } => Ok(Value::Bool(affect.sarcasm)),
3310 _ => Ok(Value::Bool(false)),
3311 });
3312
3313 define(interp, "is_positive", Some(1), |_, args| match &args[0] {
3314 Value::Affective { affect, .. } => Ok(Value::Bool(matches!(
3315 affect.sentiment,
3316 Some(RuntimeSentiment::Positive)
3317 ))),
3318 _ => Ok(Value::Bool(false)),
3319 });
3320
3321 define(interp, "is_negative", Some(1), |_, args| match &args[0] {
3322 Value::Affective { affect, .. } => Ok(Value::Bool(matches!(
3323 affect.sentiment,
3324 Some(RuntimeSentiment::Negative)
3325 ))),
3326 _ => Ok(Value::Bool(false)),
3327 });
3328
3329 define(interp, "is_formal", Some(1), |_, args| match &args[0] {
3330 Value::Affective { affect, .. } => Ok(Value::Bool(matches!(
3331 affect.formality,
3332 Some(RuntimeFormality::Formal)
3333 ))),
3334 _ => Ok(Value::Bool(false)),
3335 });
3336
3337 define(interp, "is_informal", Some(1), |_, args| match &args[0] {
3338 Value::Affective { affect, .. } => Ok(Value::Bool(matches!(
3339 affect.formality,
3340 Some(RuntimeFormality::Informal)
3341 ))),
3342 _ => Ok(Value::Bool(false)),
3343 });
3344
3345 define(interp, "emotion_of", Some(1), |_, args| match &args[0] {
3346 Value::Affective { affect, .. } => {
3347 let emotion_str = match &affect.emotion {
3348 Some(RuntimeEmotion::Joy) => "joy",
3349 Some(RuntimeEmotion::Sadness) => "sadness",
3350 Some(RuntimeEmotion::Anger) => "anger",
3351 Some(RuntimeEmotion::Fear) => "fear",
3352 Some(RuntimeEmotion::Surprise) => "surprise",
3353 Some(RuntimeEmotion::Love) => "love",
3354 None => "none",
3355 };
3356 Ok(Value::String(Rc::new(emotion_str.to_string())))
3357 }
3358 _ => Ok(Value::String(Rc::new("none".to_string()))),
3359 });
3360
3361 define(interp, "confidence_of", Some(1), |_, args| match &args[0] {
3362 Value::Affective { affect, .. } => {
3363 let conf_str = match &affect.confidence {
3364 Some(RuntimeConfidence::High) => "high",
3365 Some(RuntimeConfidence::Medium) => "medium",
3366 Some(RuntimeConfidence::Low) => "low",
3367 None => "none",
3368 };
3369 Ok(Value::String(Rc::new(conf_str.to_string())))
3370 }
3371 _ => Ok(Value::String(Rc::new("none".to_string()))),
3372 });
3373
3374 define(interp, "strip_affect", Some(1), |_, args| match &args[0] {
3376 Value::Affective { value, .. } => Ok(*value.clone()),
3377 other => Ok(other.clone()),
3378 });
3379
3380 define(interp, "with_affect", None, |_, args| {
3382 if args.is_empty() {
3383 return Err(RuntimeError::new(
3384 "with_affect requires at least one argument",
3385 ));
3386 }
3387
3388 let base_value = args[0].clone();
3389 let mut affect = RuntimeAffect {
3390 sentiment: None,
3391 sarcasm: false,
3392 intensity: None,
3393 formality: None,
3394 emotion: None,
3395 confidence: None,
3396 };
3397
3398 for arg in args.iter().skip(1) {
3400 if let Value::String(s) = arg {
3401 match s.as_str() {
3402 "positive" | "⊕" => affect.sentiment = Some(RuntimeSentiment::Positive),
3403 "negative" | "⊖" => affect.sentiment = Some(RuntimeSentiment::Negative),
3404 "neutral" | "⊜" => affect.sentiment = Some(RuntimeSentiment::Neutral),
3405 "sarcastic" | "⸮" => affect.sarcasm = true,
3406 "intensify" | "↑" => affect.intensity = Some(RuntimeIntensity::Up),
3407 "dampen" | "↓" => affect.intensity = Some(RuntimeIntensity::Down),
3408 "maximize" | "⇈" => affect.intensity = Some(RuntimeIntensity::Max),
3409 "formal" | "♔" => affect.formality = Some(RuntimeFormality::Formal),
3410 "informal" | "♟" => affect.formality = Some(RuntimeFormality::Informal),
3411 "joy" | "☺" => affect.emotion = Some(RuntimeEmotion::Joy),
3412 "sadness" | "☹" => affect.emotion = Some(RuntimeEmotion::Sadness),
3413 "anger" | "⚡" => affect.emotion = Some(RuntimeEmotion::Anger),
3414 "fear" | "❄" => affect.emotion = Some(RuntimeEmotion::Fear),
3415 "surprise" | "✦" => affect.emotion = Some(RuntimeEmotion::Surprise),
3416 "love" | "♡" => affect.emotion = Some(RuntimeEmotion::Love),
3417 "high" | "◉" => affect.confidence = Some(RuntimeConfidence::High),
3418 "medium" | "◎" => affect.confidence = Some(RuntimeConfidence::Medium),
3419 "low" | "○" => affect.confidence = Some(RuntimeConfidence::Low),
3420 _ => {}
3421 }
3422 }
3423 }
3424
3425 Ok(Value::Affective {
3426 value: Box::new(base_value),
3427 affect,
3428 })
3429 });
3430}
3431
3432fn register_iter(interp: &mut Interpreter) {
3437 define(interp, "sum", Some(1), |_, args| match &args[0] {
3439 Value::Array(arr) => {
3440 let mut sum_int: i64 = 0;
3441 let mut sum_float: f64 = 0.0;
3442 let mut is_float = false;
3443
3444 for val in arr.borrow().iter() {
3445 match val {
3446 Value::Int(n) => {
3447 if is_float {
3448 sum_float += *n as f64;
3449 } else {
3450 sum_int += n;
3451 }
3452 }
3453 Value::Float(n) => {
3454 if !is_float {
3455 sum_float = sum_int as f64;
3456 is_float = true;
3457 }
3458 sum_float += n;
3459 }
3460 _ => return Err(RuntimeError::new("sum() requires array of numbers")),
3461 }
3462 }
3463
3464 if is_float {
3465 Ok(Value::Float(sum_float))
3466 } else {
3467 Ok(Value::Int(sum_int))
3468 }
3469 }
3470 _ => Err(RuntimeError::new("sum() requires array")),
3471 });
3472
3473 define(interp, "product", Some(1), |_, args| match &args[0] {
3475 Value::Array(arr) => {
3476 let mut prod_int: i64 = 1;
3477 let mut prod_float: f64 = 1.0;
3478 let mut is_float = false;
3479
3480 for val in arr.borrow().iter() {
3481 match val {
3482 Value::Int(n) => {
3483 if is_float {
3484 prod_float *= *n as f64;
3485 } else {
3486 prod_int *= n;
3487 }
3488 }
3489 Value::Float(n) => {
3490 if !is_float {
3491 prod_float = prod_int as f64;
3492 is_float = true;
3493 }
3494 prod_float *= n;
3495 }
3496 _ => return Err(RuntimeError::new("product() requires array of numbers")),
3497 }
3498 }
3499
3500 if is_float {
3501 Ok(Value::Float(prod_float))
3502 } else {
3503 Ok(Value::Int(prod_int))
3504 }
3505 }
3506 _ => Err(RuntimeError::new("product() requires array")),
3507 });
3508
3509 define(interp, "mean", Some(1), |_, args| match &args[0] {
3511 Value::Array(arr) => {
3512 let arr = arr.borrow();
3513 if arr.is_empty() {
3514 return Err(RuntimeError::new("mean() on empty array"));
3515 }
3516
3517 let mut sum: f64 = 0.0;
3518 for val in arr.iter() {
3519 match val {
3520 Value::Int(n) => sum += *n as f64,
3521 Value::Float(n) => sum += n,
3522 _ => return Err(RuntimeError::new("mean() requires array of numbers")),
3523 }
3524 }
3525
3526 Ok(Value::Float(sum / arr.len() as f64))
3527 }
3528 _ => Err(RuntimeError::new("mean() requires array")),
3529 });
3530
3531 define(interp, "median", Some(1), |_, args| match &args[0] {
3533 Value::Array(arr) => {
3534 let arr = arr.borrow();
3535 if arr.is_empty() {
3536 return Err(RuntimeError::new("median() on empty array"));
3537 }
3538
3539 let mut nums: Vec<f64> = Vec::new();
3540 for val in arr.iter() {
3541 match val {
3542 Value::Int(n) => nums.push(*n as f64),
3543 Value::Float(n) => nums.push(*n),
3544 _ => return Err(RuntimeError::new("median() requires array of numbers")),
3545 }
3546 }
3547
3548 nums.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
3549 let mid = nums.len() / 2;
3550
3551 if nums.len() % 2 == 0 {
3552 Ok(Value::Float((nums[mid - 1] + nums[mid]) / 2.0))
3553 } else {
3554 Ok(Value::Float(nums[mid]))
3555 }
3556 }
3557 _ => Err(RuntimeError::new("median() requires array")),
3558 });
3559
3560 define(interp, "min_of", Some(1), |_, args| match &args[0] {
3562 Value::Array(arr) => {
3563 let arr = arr.borrow();
3564 if arr.is_empty() {
3565 return Err(RuntimeError::new("min_of() on empty array"));
3566 }
3567
3568 let mut min = &arr[0];
3569 for val in arr.iter().skip(1) {
3570 if matches!(compare_values(val, min), std::cmp::Ordering::Less) {
3571 min = val;
3572 }
3573 }
3574 Ok(min.clone())
3575 }
3576 _ => Err(RuntimeError::new("min_of() requires array")),
3577 });
3578
3579 define(interp, "max_of", Some(1), |_, args| match &args[0] {
3581 Value::Array(arr) => {
3582 let arr = arr.borrow();
3583 if arr.is_empty() {
3584 return Err(RuntimeError::new("max_of() on empty array"));
3585 }
3586
3587 let mut max = &arr[0];
3588 for val in arr.iter().skip(1) {
3589 if matches!(compare_values(val, max), std::cmp::Ordering::Greater) {
3590 max = val;
3591 }
3592 }
3593 Ok(max.clone())
3594 }
3595 _ => Err(RuntimeError::new("max_of() requires array")),
3596 });
3597
3598 define(interp, "count", Some(1), |_, args| match &args[0] {
3600 Value::Array(arr) => Ok(Value::Int(arr.borrow().len() as i64)),
3601 Value::String(s) => Ok(Value::Int(s.chars().count() as i64)),
3602 _ => Err(RuntimeError::new("count() requires array or string")),
3603 });
3604
3605 define(interp, "any", Some(1), |_, args| match &args[0] {
3607 Value::Array(arr) => {
3608 for val in arr.borrow().iter() {
3609 if is_truthy(val) {
3610 return Ok(Value::Bool(true));
3611 }
3612 }
3613 Ok(Value::Bool(false))
3614 }
3615 _ => Err(RuntimeError::new("any() requires array")),
3616 });
3617
3618 define(interp, "all", Some(1), |_, args| match &args[0] {
3620 Value::Array(arr) => {
3621 for val in arr.borrow().iter() {
3622 if !is_truthy(val) {
3623 return Ok(Value::Bool(false));
3624 }
3625 }
3626 Ok(Value::Bool(true))
3627 }
3628 _ => Err(RuntimeError::new("all() requires array")),
3629 });
3630
3631 define(interp, "none", Some(1), |_, args| match &args[0] {
3633 Value::Array(arr) => {
3634 for val in arr.borrow().iter() {
3635 if is_truthy(val) {
3636 return Ok(Value::Bool(false));
3637 }
3638 }
3639 Ok(Value::Bool(true))
3640 }
3641 _ => Err(RuntimeError::new("none() requires array")),
3642 });
3643}
3644
3645fn is_truthy(val: &Value) -> bool {
3646 match val {
3647 Value::Null | Value::Empty => false,
3648 Value::Bool(b) => *b,
3649 Value::Int(n) => *n != 0,
3650 Value::Float(n) => *n != 0.0 && !n.is_nan(),
3651 Value::String(s) => !s.is_empty(),
3652 Value::Array(arr) => !arr.borrow().is_empty(),
3653 Value::Evidential { value, .. } => is_truthy(value),
3654 _ => true,
3655 }
3656}
3657
3658fn register_io(interp: &mut Interpreter) {
3663 define(interp, "read_file", Some(1), |_, args| {
3665 match &args[0] {
3666 Value::String(path) => {
3667 match std::fs::read_to_string(path.as_str()) {
3668 Ok(content) => Ok(Value::Evidential {
3669 value: Box::new(Value::String(Rc::new(content))),
3670 evidence: Evidence::Reported, }),
3672 Err(e) => Err(RuntimeError::new(format!("read_file failed: {}", e))),
3673 }
3674 }
3675 _ => Err(RuntimeError::new("read_file() requires path string")),
3676 }
3677 });
3678
3679 define(interp, "write_file", Some(2), |_, args| {
3681 match (&args[0], &args[1]) {
3682 (Value::String(path), Value::String(content)) => {
3683 match std::fs::write(path.as_str(), content.as_str()) {
3684 Ok(_) => Ok(Value::Bool(true)),
3685 Err(e) => Err(RuntimeError::new(format!("write_file failed: {}", e))),
3686 }
3687 }
3688 _ => Err(RuntimeError::new(
3689 "write_file() requires path and content strings",
3690 )),
3691 }
3692 });
3693
3694 define(interp, "append_file", Some(2), |_, args| {
3696 match (&args[0], &args[1]) {
3697 (Value::String(path), Value::String(content)) => {
3698 use std::fs::OpenOptions;
3699 let result = OpenOptions::new()
3700 .create(true)
3701 .append(true)
3702 .open(path.as_str())
3703 .and_then(|mut f| f.write_all(content.as_bytes()));
3704 match result {
3705 Ok(_) => Ok(Value::Bool(true)),
3706 Err(e) => Err(RuntimeError::new(format!("append_file failed: {}", e))),
3707 }
3708 }
3709 _ => Err(RuntimeError::new(
3710 "append_file() requires path and content strings",
3711 )),
3712 }
3713 });
3714
3715 define(interp, "file_exists", Some(1), |_, args| match &args[0] {
3717 Value::String(path) => Ok(Value::Bool(std::path::Path::new(path.as_str()).exists())),
3718 _ => Err(RuntimeError::new("file_exists() requires path string")),
3719 });
3720
3721 define(interp, "read_lines", Some(1), |_, args| match &args[0] {
3723 Value::String(path) => match std::fs::read_to_string(path.as_str()) {
3724 Ok(content) => {
3725 let lines: Vec<Value> = content
3726 .lines()
3727 .map(|l| Value::String(Rc::new(l.to_string())))
3728 .collect();
3729 Ok(Value::Evidential {
3730 value: Box::new(Value::Array(Rc::new(RefCell::new(lines)))),
3731 evidence: Evidence::Reported,
3732 })
3733 }
3734 Err(e) => Err(RuntimeError::new(format!("read_lines failed: {}", e))),
3735 },
3736 _ => Err(RuntimeError::new("read_lines() requires path string")),
3737 });
3738
3739 define(interp, "env", Some(1), |_, args| {
3741 match &args[0] {
3742 Value::String(name) => {
3743 match std::env::var(name.as_str()) {
3744 Ok(value) => Ok(Value::Evidential {
3745 value: Box::new(Value::String(Rc::new(value))),
3746 evidence: Evidence::Reported, }),
3748 Err(_) => Ok(Value::Null),
3749 }
3750 }
3751 _ => Err(RuntimeError::new("env() requires variable name string")),
3752 }
3753 });
3754
3755 define(interp, "env·var", Some(1), |_, args| match &args[0] {
3757 Value::String(name) => match std::env::var(name.as_str()) {
3758 Ok(value) => Ok(Value::Variant {
3759 enum_name: "Result".to_string(),
3760 variant_name: "Ok".to_string(),
3761 fields: Some(Rc::new(vec![Value::String(Rc::new(value))])),
3762 }),
3763 Err(_) => Ok(Value::Variant {
3764 enum_name: "Result".to_string(),
3765 variant_name: "Err".to_string(),
3766 fields: Some(Rc::new(vec![Value::String(Rc::new(
3767 "environment variable not found".to_string(),
3768 ))])),
3769 }),
3770 },
3771 _ => Err(RuntimeError::new(
3772 "env::var() requires variable name string",
3773 )),
3774 });
3775
3776 define(interp, "env_or", Some(2), |_, args| {
3778 match (&args[0], &args[1]) {
3779 (Value::String(name), default) => match std::env::var(name.as_str()) {
3780 Ok(value) => Ok(Value::Evidential {
3781 value: Box::new(Value::String(Rc::new(value))),
3782 evidence: Evidence::Reported,
3783 }),
3784 Err(_) => Ok(default.clone()),
3785 },
3786 _ => Err(RuntimeError::new("env_or() requires variable name string")),
3787 }
3788 });
3789
3790 define(interp, "cwd", Some(0), |_, _| {
3792 match std::env::current_dir() {
3793 Ok(path) => Ok(Value::String(Rc::new(path.to_string_lossy().to_string()))),
3794 Err(e) => Err(RuntimeError::new(format!("cwd() failed: {}", e))),
3795 }
3796 });
3797
3798 define(interp, "args", Some(0), |interp, _| {
3800 let args: Vec<Value> = if interp
3801 .program_args
3802 .as_ref()
3803 .map(|v| v.is_empty())
3804 .unwrap_or(true)
3805 {
3806 std::env::args()
3808 .map(|a| Value::String(Rc::new(a)))
3809 .collect()
3810 } else {
3811 interp
3813 .program_args
3814 .as_ref()
3815 .unwrap()
3816 .iter()
3817 .map(|a| Value::String(Rc::new(a.clone())))
3818 .collect()
3819 };
3820 Ok(Value::Array(Rc::new(RefCell::new(args))))
3821 });
3822}
3823
3824fn register_time(interp: &mut Interpreter) {
3829 define(interp, "now", Some(0), |_, _| {
3831 let duration = SystemTime::now()
3832 .duration_since(UNIX_EPOCH)
3833 .unwrap_or(Duration::ZERO);
3834 Ok(Value::Int(duration.as_millis() as i64))
3835 });
3836
3837 define(interp, "now_secs", Some(0), |_, _| {
3839 let duration = SystemTime::now()
3840 .duration_since(UNIX_EPOCH)
3841 .unwrap_or(Duration::ZERO);
3842 Ok(Value::Int(duration.as_secs() as i64))
3843 });
3844
3845 define(interp, "now_micros", Some(0), |_, _| {
3847 let duration = SystemTime::now()
3848 .duration_since(UNIX_EPOCH)
3849 .unwrap_or(Duration::ZERO);
3850 Ok(Value::Int(duration.as_micros() as i64))
3851 });
3852
3853 define(interp, "sleep", Some(1), |_, args| match &args[0] {
3855 Value::Int(ms) if *ms >= 0 => {
3856 std::thread::sleep(Duration::from_millis(*ms as u64));
3857 Ok(Value::Null)
3858 }
3859 _ => Err(RuntimeError::new(
3860 "sleep() requires non-negative integer milliseconds",
3861 )),
3862 });
3863
3864 define(interp, "UNIX_EPOCH", Some(0), |_, _| {
3870 let mut fields = std::collections::HashMap::new();
3872 fields.insert("secs".to_string(), Value::Int(0));
3873 fields.insert("nanos".to_string(), Value::Int(0));
3874 Ok(Value::Struct {
3875 name: "SystemTime".to_string(),
3876 fields: Rc::new(RefCell::new(fields)),
3877 })
3878 });
3879
3880 define(interp, "std·time·UNIX_EPOCH", Some(0), |_, _| {
3882 let mut fields = std::collections::HashMap::new();
3883 fields.insert("secs".to_string(), Value::Int(0));
3884 fields.insert("nanos".to_string(), Value::Int(0));
3885 Ok(Value::Struct {
3886 name: "SystemTime".to_string(),
3887 fields: Rc::new(RefCell::new(fields)),
3888 })
3889 });
3890
3891 define(interp, "timer_start", Some(0), |_, _| {
3893 let now = Instant::now();
3894 Ok(Value::Int(now.elapsed().as_nanos() as i64)) });
3897}
3898
3899fn register_random(interp: &mut Interpreter) {
3904 define(interp, "random", Some(0), |_, _| {
3906 use std::time::SystemTime;
3908 let seed = SystemTime::now()
3909 .duration_since(UNIX_EPOCH)
3910 .unwrap_or(Duration::ZERO)
3911 .as_nanos() as u64;
3912 let rand = ((seed.wrapping_mul(1103515245).wrapping_add(12345)) >> 16) as f64;
3913 Ok(Value::Float(rand / u32::MAX as f64))
3914 });
3915
3916 define(interp, "random_int", Some(2), |_, args| {
3918 match (&args[0], &args[1]) {
3919 (Value::Int(min), Value::Int(max)) if max > min => {
3920 use std::time::SystemTime;
3921 let seed = SystemTime::now()
3922 .duration_since(UNIX_EPOCH)
3923 .unwrap_or(Duration::ZERO)
3924 .as_nanos() as u64;
3925 let range = (max - min) as u64;
3926 let rand = ((seed.wrapping_mul(1103515245).wrapping_add(12345)) >> 16) % range;
3927 Ok(Value::Int(*min + rand as i64))
3928 }
3929 _ => Err(RuntimeError::new(
3930 "random_int() requires min < max integers",
3931 )),
3932 }
3933 });
3934
3935 define(interp, "shuffle", Some(1), |_, args| match &args[0] {
3937 Value::Array(arr) => {
3938 let mut arr = arr.borrow_mut();
3939 use std::time::SystemTime;
3940 let mut seed = SystemTime::now()
3941 .duration_since(UNIX_EPOCH)
3942 .unwrap_or(Duration::ZERO)
3943 .as_nanos() as u64;
3944
3945 for i in (1..arr.len()).rev() {
3946 seed = seed.wrapping_mul(1103515245).wrapping_add(12345);
3947 let j = ((seed >> 16) as usize) % (i + 1);
3948 arr.swap(i, j);
3949 }
3950 Ok(Value::Null)
3951 }
3952 _ => Err(RuntimeError::new("shuffle() requires array")),
3953 });
3954
3955 define(interp, "sample", Some(1), |_, args| match &args[0] {
3957 Value::Array(arr) => {
3958 let arr = arr.borrow();
3959 if arr.is_empty() {
3960 return Err(RuntimeError::new("sample() on empty array"));
3961 }
3962
3963 use std::time::SystemTime;
3964 let seed = SystemTime::now()
3965 .duration_since(UNIX_EPOCH)
3966 .unwrap_or(Duration::ZERO)
3967 .as_nanos() as u64;
3968 let idx =
3969 ((seed.wrapping_mul(1103515245).wrapping_add(12345)) >> 16) as usize % arr.len();
3970 Ok(arr[idx].clone())
3971 }
3972 _ => Err(RuntimeError::new("sample() requires array")),
3973 });
3974}
3975
3976fn register_convert(interp: &mut Interpreter) {
3981 define(interp, "to_string", Some(1), |_, args| {
3983 Ok(Value::String(Rc::new(format!("{}", args[0]))))
3984 });
3985
3986 define(interp, "to_int", Some(1), |_, args| match &args[0] {
3988 Value::Int(n) => Ok(Value::Int(*n)),
3989 Value::Float(n) => Ok(Value::Int(*n as i64)),
3990 Value::Bool(b) => Ok(Value::Int(if *b { 1 } else { 0 })),
3991 Value::Char(c) => Ok(Value::Int(*c as i64)),
3992 Value::String(s) => s
3993 .parse::<i64>()
3994 .map(Value::Int)
3995 .map_err(|_| RuntimeError::new(format!("cannot parse '{}' as integer", s))),
3996 _ => Err(RuntimeError::new("to_int() cannot convert this type")),
3997 });
3998
3999 define(interp, "to_float", Some(1), |_, args| match &args[0] {
4001 Value::Int(n) => Ok(Value::Float(*n as f64)),
4002 Value::Float(n) => Ok(Value::Float(*n)),
4003 Value::Bool(b) => Ok(Value::Float(if *b { 1.0 } else { 0.0 })),
4004 Value::String(s) => s
4005 .parse::<f64>()
4006 .map(Value::Float)
4007 .map_err(|_| RuntimeError::new(format!("cannot parse '{}' as float", s))),
4008 _ => Err(RuntimeError::new("to_float() cannot convert this type")),
4009 });
4010
4011 define(interp, "to_bool", Some(1), |_, args| {
4013 Ok(Value::Bool(is_truthy(&args[0])))
4014 });
4015
4016 define(interp, "to_char", Some(1), |_, args| match &args[0] {
4018 Value::Char(c) => Ok(Value::Char(*c)),
4019 Value::Int(n) => char::from_u32(*n as u32)
4020 .map(Value::Char)
4021 .ok_or_else(|| RuntimeError::new(format!("invalid char code: {}", n))),
4022 Value::String(s) => s
4023 .chars()
4024 .next()
4025 .map(Value::Char)
4026 .ok_or_else(|| RuntimeError::new("to_char() on empty string")),
4027 _ => Err(RuntimeError::new("to_char() cannot convert this type")),
4028 });
4029
4030 define(interp, "to_array", Some(1), |_, args| match &args[0] {
4032 Value::Array(arr) => Ok(Value::Array(arr.clone())),
4033 Value::Tuple(t) => Ok(Value::Array(Rc::new(RefCell::new(t.as_ref().clone())))),
4034 Value::String(s) => {
4035 let chars: Vec<Value> = s.chars().map(Value::Char).collect();
4036 Ok(Value::Array(Rc::new(RefCell::new(chars))))
4037 }
4038 _ => Ok(Value::Array(Rc::new(RefCell::new(vec![args[0].clone()])))),
4039 });
4040
4041 define(interp, "to_tuple", Some(1), |_, args| match &args[0] {
4043 Value::Tuple(t) => Ok(Value::Tuple(t.clone())),
4044 Value::Array(arr) => Ok(Value::Tuple(Rc::new(arr.borrow().clone()))),
4045 _ => Ok(Value::Tuple(Rc::new(vec![args[0].clone()]))),
4046 });
4047
4048 define(interp, "char_code", Some(1), |_, args| match &args[0] {
4050 Value::Char(c) => Ok(Value::Int(*c as i64)),
4051 _ => Err(RuntimeError::new("char_code() requires char")),
4052 });
4053
4054 define(interp, "from_char_code", Some(1), |_, args| {
4056 match &args[0] {
4057 Value::Int(n) => char::from_u32(*n as u32)
4058 .map(Value::Char)
4059 .ok_or_else(|| RuntimeError::new(format!("invalid char code: {}", n))),
4060 _ => Err(RuntimeError::new("from_char_code() requires integer")),
4061 }
4062 });
4063
4064 define(interp, "hex", Some(1), |_, args| match &args[0] {
4066 Value::Int(n) => Ok(Value::String(Rc::new(format!("{:x}", n)))),
4067 _ => Err(RuntimeError::new("hex() requires integer")),
4068 });
4069
4070 define(interp, "oct", Some(1), |_, args| match &args[0] {
4072 Value::Int(n) => Ok(Value::String(Rc::new(format!("{:o}", n)))),
4073 _ => Err(RuntimeError::new("oct() requires integer")),
4074 });
4075
4076 define(interp, "bin", Some(1), |_, args| match &args[0] {
4078 Value::Int(n) => Ok(Value::String(Rc::new(format!("{:b}", n)))),
4079 _ => Err(RuntimeError::new("bin() requires integer")),
4080 });
4081
4082 define(interp, "parse_int", Some(2), |_, args| {
4084 match (&args[0], &args[1]) {
4085 (Value::String(s), Value::Int(base)) if *base >= 2 && *base <= 36 => {
4086 i64::from_str_radix(s.trim(), *base as u32)
4087 .map(Value::Int)
4088 .map_err(|_| {
4089 RuntimeError::new(format!("cannot parse '{}' as base-{} integer", s, base))
4090 })
4091 }
4092 _ => Err(RuntimeError::new(
4093 "parse_int() requires string and base 2-36",
4094 )),
4095 }
4096 });
4097}
4098
4099fn register_cycle(interp: &mut Interpreter) {
4105 define(interp, "cycle", Some(2), |_, args| {
4107 match (&args[0], &args[1]) {
4108 (Value::Int(value), Value::Int(modulus)) if *modulus > 0 => {
4109 let normalized = value.rem_euclid(*modulus);
4110 Ok(Value::Tuple(Rc::new(vec![
4111 Value::Int(normalized),
4112 Value::Int(*modulus),
4113 ])))
4114 }
4115 _ => Err(RuntimeError::new(
4116 "cycle() requires value and positive modulus",
4117 )),
4118 }
4119 });
4120
4121 define(interp, "mod_add", Some(3), |_, args| {
4123 match (&args[0], &args[1], &args[2]) {
4124 (Value::Int(a), Value::Int(b), Value::Int(m)) if *m > 0 => {
4125 Ok(Value::Int((a + b).rem_euclid(*m)))
4126 }
4127 _ => Err(RuntimeError::new(
4128 "mod_add() requires two integers and positive modulus",
4129 )),
4130 }
4131 });
4132
4133 define(interp, "mod_sub", Some(3), |_, args| {
4135 match (&args[0], &args[1], &args[2]) {
4136 (Value::Int(a), Value::Int(b), Value::Int(m)) if *m > 0 => {
4137 Ok(Value::Int((a - b).rem_euclid(*m)))
4138 }
4139 _ => Err(RuntimeError::new(
4140 "mod_sub() requires two integers and positive modulus",
4141 )),
4142 }
4143 });
4144
4145 define(interp, "mod_mul", Some(3), |_, args| {
4147 match (&args[0], &args[1], &args[2]) {
4148 (Value::Int(a), Value::Int(b), Value::Int(m)) if *m > 0 => {
4149 Ok(Value::Int((a * b).rem_euclid(*m)))
4150 }
4151 _ => Err(RuntimeError::new(
4152 "mod_mul() requires two integers and positive modulus",
4153 )),
4154 }
4155 });
4156
4157 define(interp, "mod_pow", Some(3), |_, args| {
4159 match (&args[0], &args[1], &args[2]) {
4160 (Value::Int(base), Value::Int(exp), Value::Int(m)) if *m > 0 && *exp >= 0 => {
4161 Ok(Value::Int(mod_pow(*base, *exp as u64, *m)))
4162 }
4163 _ => Err(RuntimeError::new(
4164 "mod_pow() requires base, non-negative exp, and positive modulus",
4165 )),
4166 }
4167 });
4168
4169 define(interp, "mod_inv", Some(2), |_, args| {
4171 match (&args[0], &args[1]) {
4172 (Value::Int(a), Value::Int(m)) if *m > 0 => match mod_inverse(*a, *m) {
4173 Some(inv) => Ok(Value::Int(inv)),
4174 None => Err(RuntimeError::new(format!(
4175 "no modular inverse of {} mod {}",
4176 a, m
4177 ))),
4178 },
4179 _ => Err(RuntimeError::new(
4180 "mod_inv() requires integer and positive modulus",
4181 )),
4182 }
4183 });
4184
4185 define(interp, "octave", Some(1), |_, args| {
4188 match &args[0] {
4189 Value::Int(note) => Ok(Value::Int(note.rem_euclid(12))),
4190 Value::Float(freq) => {
4191 let semitones = 12.0 * (freq / 440.0).log2();
4193 Ok(Value::Float(semitones.rem_euclid(12.0)))
4194 }
4195 _ => Err(RuntimeError::new("octave() requires number")),
4196 }
4197 });
4198
4199 define(interp, "interval", Some(2), |_, args| {
4201 match (&args[0], &args[1]) {
4202 (Value::Int(a), Value::Int(b)) => Ok(Value::Int((b - a).rem_euclid(12))),
4203 _ => Err(RuntimeError::new("interval() requires two integers")),
4204 }
4205 });
4206
4207 define(interp, "cents", Some(1), |_, args| match &args[0] {
4209 Value::Int(semitones) => Ok(Value::Int(*semitones * 100)),
4210 Value::Float(semitones) => Ok(Value::Float(*semitones * 100.0)),
4211 _ => Err(RuntimeError::new("cents() requires number")),
4212 });
4213
4214 define(interp, "freq", Some(1), |_, args| match &args[0] {
4216 Value::Int(midi) => {
4217 let freq = 440.0 * 2.0_f64.powf((*midi as f64 - 69.0) / 12.0);
4218 Ok(Value::Float(freq))
4219 }
4220 _ => Err(RuntimeError::new("freq() requires integer MIDI note")),
4221 });
4222
4223 define(interp, "midi", Some(1), |_, args| match &args[0] {
4225 Value::Float(freq) if *freq > 0.0 => {
4226 let midi = 69.0 + 12.0 * (freq / 440.0).log2();
4227 Ok(Value::Int(midi.round() as i64))
4228 }
4229 Value::Int(freq) if *freq > 0 => {
4230 let midi = 69.0 + 12.0 * (*freq as f64 / 440.0).log2();
4231 Ok(Value::Int(midi.round() as i64))
4232 }
4233 _ => Err(RuntimeError::new("midi() requires positive frequency")),
4234 });
4235}
4236
4237fn mod_pow(mut base: i64, mut exp: u64, modulus: i64) -> i64 {
4239 if modulus == 1 {
4240 return 0;
4241 }
4242 let mut result: i64 = 1;
4243 base = base.rem_euclid(modulus);
4244 while exp > 0 {
4245 if exp % 2 == 1 {
4246 result = (result * base).rem_euclid(modulus);
4247 }
4248 exp /= 2;
4249 base = (base * base).rem_euclid(modulus);
4250 }
4251 result
4252}
4253
4254fn register_simd(interp: &mut Interpreter) {
4260 define(interp, "simd_new", Some(4), |_, args| {
4262 let values: Result<Vec<f64>, _> = args
4263 .iter()
4264 .map(|v| match v {
4265 Value::Float(f) => Ok(*f),
4266 Value::Int(i) => Ok(*i as f64),
4267 _ => Err(RuntimeError::new("simd_new() requires numbers")),
4268 })
4269 .collect();
4270 let values = values?;
4271 Ok(Value::Array(Rc::new(RefCell::new(vec![
4272 Value::Float(values[0]),
4273 Value::Float(values[1]),
4274 Value::Float(values[2]),
4275 Value::Float(values[3]),
4276 ]))))
4277 });
4278
4279 define(interp, "simd_splat", Some(1), |_, args| {
4281 let v = match &args[0] {
4282 Value::Float(f) => *f,
4283 Value::Int(i) => *i as f64,
4284 _ => return Err(RuntimeError::new("simd_splat() requires number")),
4285 };
4286 Ok(Value::Array(Rc::new(RefCell::new(vec![
4287 Value::Float(v),
4288 Value::Float(v),
4289 Value::Float(v),
4290 Value::Float(v),
4291 ]))))
4292 });
4293
4294 define(interp, "simd_add", Some(2), |_, args| {
4296 simd_binary_op(&args[0], &args[1], |a, b| a + b, "simd_add")
4297 });
4298
4299 define(interp, "simd_sub", Some(2), |_, args| {
4301 simd_binary_op(&args[0], &args[1], |a, b| a - b, "simd_sub")
4302 });
4303
4304 define(interp, "simd_mul", Some(2), |_, args| {
4306 simd_binary_op(&args[0], &args[1], |a, b| a * b, "simd_mul")
4307 });
4308
4309 define(interp, "simd_div", Some(2), |_, args| {
4311 simd_binary_op(&args[0], &args[1], |a, b| a / b, "simd_div")
4312 });
4313
4314 define(interp, "simd_dot", Some(2), |_, args| {
4316 let a = extract_simd(&args[0], "simd_dot")?;
4317 let b = extract_simd(&args[1], "simd_dot")?;
4318 let dot = a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
4319 Ok(Value::Float(dot))
4320 });
4321
4322 define(interp, "simd_cross", Some(2), |_, args| {
4324 let a = extract_simd(&args[0], "simd_cross")?;
4325 let b = extract_simd(&args[1], "simd_cross")?;
4326 Ok(Value::Array(Rc::new(RefCell::new(vec![
4327 Value::Float(a[1] * b[2] - a[2] * b[1]),
4328 Value::Float(a[2] * b[0] - a[0] * b[2]),
4329 Value::Float(a[0] * b[1] - a[1] * b[0]),
4330 Value::Float(0.0),
4331 ]))))
4332 });
4333
4334 define(interp, "simd_length", Some(1), |_, args| {
4336 let v = extract_simd(&args[0], "simd_length")?;
4337 let len_sq = v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3];
4338 Ok(Value::Float(len_sq.sqrt()))
4339 });
4340
4341 define(interp, "simd_normalize", Some(1), |_, args| {
4343 let v = extract_simd(&args[0], "simd_normalize")?;
4344 let len_sq = v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3];
4345 let len = len_sq.sqrt();
4346 if len < 1e-10 {
4347 return Ok(Value::Array(Rc::new(RefCell::new(vec![
4348 Value::Float(0.0),
4349 Value::Float(0.0),
4350 Value::Float(0.0),
4351 Value::Float(0.0),
4352 ]))));
4353 }
4354 let inv_len = 1.0 / len;
4355 Ok(Value::Array(Rc::new(RefCell::new(vec![
4356 Value::Float(v[0] * inv_len),
4357 Value::Float(v[1] * inv_len),
4358 Value::Float(v[2] * inv_len),
4359 Value::Float(v[3] * inv_len),
4360 ]))))
4361 });
4362
4363 define(interp, "simd_min", Some(2), |_, args| {
4365 simd_binary_op(&args[0], &args[1], |a, b| a.min(b), "simd_min")
4366 });
4367
4368 define(interp, "simd_max", Some(2), |_, args| {
4370 simd_binary_op(&args[0], &args[1], |a, b| a.max(b), "simd_max")
4371 });
4372
4373 define(interp, "simd_hadd", Some(1), |_, args| {
4375 let v = extract_simd(&args[0], "simd_hadd")?;
4376 Ok(Value::Float(v[0] + v[1] + v[2] + v[3]))
4377 });
4378
4379 define(interp, "simd_extract", Some(2), |_, args| {
4381 let v = extract_simd(&args[0], "simd_extract")?;
4382 let idx = match &args[1] {
4383 Value::Int(i) => *i as usize,
4384 _ => return Err(RuntimeError::new("simd_extract() requires integer index")),
4385 };
4386 if idx > 3 {
4387 return Err(RuntimeError::new("simd_extract() index must be 0-3"));
4388 }
4389 Ok(Value::Float(v[idx]))
4390 });
4391
4392 define(interp, "simd_free", Some(1), |_, _| Ok(Value::Null));
4394
4395 define(interp, "simd_lerp", Some(3), |_, args| {
4397 let a = extract_simd(&args[0], "simd_lerp")?;
4398 let b = extract_simd(&args[1], "simd_lerp")?;
4399 let t = match &args[2] {
4400 Value::Float(f) => *f,
4401 Value::Int(i) => *i as f64,
4402 _ => return Err(RuntimeError::new("simd_lerp() requires float t")),
4403 };
4404 let one_t = 1.0 - t;
4405 Ok(Value::Array(Rc::new(RefCell::new(vec![
4406 Value::Float(a[0] * one_t + b[0] * t),
4407 Value::Float(a[1] * one_t + b[1] * t),
4408 Value::Float(a[2] * one_t + b[2] * t),
4409 Value::Float(a[3] * one_t + b[3] * t),
4410 ]))))
4411 });
4412}
4413
4414fn extract_simd(val: &Value, fn_name: &str) -> Result<[f64; 4], RuntimeError> {
4416 match val {
4417 Value::Array(arr) => {
4418 let arr = arr.borrow();
4419 if arr.len() < 4 {
4420 return Err(RuntimeError::new(format!(
4421 "{}() requires 4-element array",
4422 fn_name
4423 )));
4424 }
4425 let mut result = [0.0; 4];
4426 for (i, v) in arr.iter().take(4).enumerate() {
4427 result[i] = match v {
4428 Value::Float(f) => *f,
4429 Value::Int(n) => *n as f64,
4430 _ => {
4431 return Err(RuntimeError::new(format!(
4432 "{}() requires numeric array",
4433 fn_name
4434 )))
4435 }
4436 };
4437 }
4438 Ok(result)
4439 }
4440 _ => Err(RuntimeError::new(format!(
4441 "{}() requires array argument",
4442 fn_name
4443 ))),
4444 }
4445}
4446
4447fn simd_binary_op<F>(a: &Value, b: &Value, op: F, fn_name: &str) -> Result<Value, RuntimeError>
4449where
4450 F: Fn(f64, f64) -> f64,
4451{
4452 let a = extract_simd(a, fn_name)?;
4453 let b = extract_simd(b, fn_name)?;
4454 Ok(Value::Array(Rc::new(RefCell::new(vec![
4455 Value::Float(op(a[0], b[0])),
4456 Value::Float(op(a[1], b[1])),
4457 Value::Float(op(a[2], b[2])),
4458 Value::Float(op(a[3], b[3])),
4459 ]))))
4460}
4461
4462fn register_graphics_math(interp: &mut Interpreter) {
4473 define(interp, "quat_new", Some(4), |_, args| {
4481 let w = extract_number(&args[0], "quat_new")?;
4482 let x = extract_number(&args[1], "quat_new")?;
4483 let y = extract_number(&args[2], "quat_new")?;
4484 let z = extract_number(&args[3], "quat_new")?;
4485 Ok(make_vec4(w, x, y, z))
4486 });
4487
4488 define(interp, "quat_identity", Some(0), |_, _| {
4490 Ok(make_vec4(1.0, 0.0, 0.0, 0.0))
4491 });
4492
4493 define(interp, "quat_from_axis_angle", Some(2), |_, args| {
4495 let axis = extract_vec3(&args[0], "quat_from_axis_angle")?;
4496 let angle = extract_number(&args[1], "quat_from_axis_angle")?;
4497
4498 let len = (axis[0] * axis[0] + axis[1] * axis[1] + axis[2] * axis[2]).sqrt();
4500 if len < 1e-10 {
4501 return Ok(make_vec4(1.0, 0.0, 0.0, 0.0)); }
4503 let ax = axis[0] / len;
4504 let ay = axis[1] / len;
4505 let az = axis[2] / len;
4506
4507 let half_angle = angle / 2.0;
4508 let s = half_angle.sin();
4509 let c = half_angle.cos();
4510
4511 Ok(make_vec4(c, ax * s, ay * s, az * s))
4512 });
4513
4514 define(interp, "quat_from_euler", Some(3), |_, args| {
4517 let pitch = extract_number(&args[0], "quat_from_euler")?; let yaw = extract_number(&args[1], "quat_from_euler")?; let roll = extract_number(&args[2], "quat_from_euler")?; let (sp, cp) = (pitch / 2.0).sin_cos();
4522 let (sy, cy) = (yaw / 2.0).sin_cos();
4523 let (sr, cr) = (roll / 2.0).sin_cos();
4524
4525 let w = cp * cy * cr + sp * sy * sr;
4527 let x = sp * cy * cr - cp * sy * sr;
4528 let y = cp * sy * cr + sp * cy * sr;
4529 let z = cp * cy * sr - sp * sy * cr;
4530
4531 Ok(make_vec4(w, x, y, z))
4532 });
4533
4534 define(interp, "quat_mul", Some(2), |_, args| {
4536 let q1 = extract_vec4(&args[0], "quat_mul")?;
4537 let q2 = extract_vec4(&args[1], "quat_mul")?;
4538
4539 let w = q1[0] * q2[0] - q1[1] * q2[1] - q1[2] * q2[2] - q1[3] * q2[3];
4541 let x = q1[0] * q2[1] + q1[1] * q2[0] + q1[2] * q2[3] - q1[3] * q2[2];
4542 let y = q1[0] * q2[2] - q1[1] * q2[3] + q1[2] * q2[0] + q1[3] * q2[1];
4543 let z = q1[0] * q2[3] + q1[1] * q2[2] - q1[2] * q2[1] + q1[3] * q2[0];
4544
4545 Ok(make_vec4(w, x, y, z))
4546 });
4547
4548 define(interp, "quat_conjugate", Some(1), |_, args| {
4550 let q = extract_vec4(&args[0], "quat_conjugate")?;
4551 Ok(make_vec4(q[0], -q[1], -q[2], -q[3]))
4552 });
4553
4554 define(interp, "quat_inverse", Some(1), |_, args| {
4556 let q = extract_vec4(&args[0], "quat_inverse")?;
4557 let norm_sq = q[0] * q[0] + q[1] * q[1] + q[2] * q[2] + q[3] * q[3];
4558 if norm_sq < 1e-10 {
4559 return Err(RuntimeError::new(
4560 "quat_inverse: cannot invert zero quaternion",
4561 ));
4562 }
4563 Ok(make_vec4(
4564 q[0] / norm_sq,
4565 -q[1] / norm_sq,
4566 -q[2] / norm_sq,
4567 -q[3] / norm_sq,
4568 ))
4569 });
4570
4571 define(interp, "quat_normalize", Some(1), |_, args| {
4573 let q = extract_vec4(&args[0], "quat_normalize")?;
4574 let len = (q[0] * q[0] + q[1] * q[1] + q[2] * q[2] + q[3] * q[3]).sqrt();
4575 if len < 1e-10 {
4576 return Ok(make_vec4(1.0, 0.0, 0.0, 0.0));
4577 }
4578 Ok(make_vec4(q[0] / len, q[1] / len, q[2] / len, q[3] / len))
4579 });
4580
4581 define(interp, "quat_rotate", Some(2), |_, args| {
4583 let q = extract_vec4(&args[0], "quat_rotate")?;
4584 let v = extract_vec3(&args[1], "quat_rotate")?;
4585
4586 let qw = q[0];
4588 let qx = q[1];
4589 let qy = q[2];
4590 let qz = q[3];
4591 let vx = v[0];
4592 let vy = v[1];
4593 let vz = v[2];
4594
4595 let tx = 2.0 * (qy * vz - qz * vy);
4597 let ty = 2.0 * (qz * vx - qx * vz);
4598 let tz = 2.0 * (qx * vy - qy * vx);
4599
4600 let rx = vx + qw * tx + (qy * tz - qz * ty);
4602 let ry = vy + qw * ty + (qz * tx - qx * tz);
4603 let rz = vz + qw * tz + (qx * ty - qy * tx);
4604
4605 Ok(make_vec3(rx, ry, rz))
4606 });
4607
4608 define(interp, "quat_slerp", Some(3), |_, args| {
4610 let q1 = extract_vec4(&args[0], "quat_slerp")?;
4611 let mut q2 = extract_vec4(&args[1], "quat_slerp")?;
4612 let t = extract_number(&args[2], "quat_slerp")?;
4613
4614 let mut dot = q1[0] * q2[0] + q1[1] * q2[1] + q1[2] * q2[2] + q1[3] * q2[3];
4616
4617 if dot < 0.0 {
4619 q2 = [-q2[0], -q2[1], -q2[2], -q2[3]];
4620 dot = -dot;
4621 }
4622
4623 if dot > 0.9995 {
4625 let w = q1[0] + t * (q2[0] - q1[0]);
4626 let x = q1[1] + t * (q2[1] - q1[1]);
4627 let y = q1[2] + t * (q2[2] - q1[2]);
4628 let z = q1[3] + t * (q2[3] - q1[3]);
4629 let len = (w * w + x * x + y * y + z * z).sqrt();
4630 return Ok(make_vec4(w / len, x / len, y / len, z / len));
4631 }
4632
4633 let theta_0 = dot.acos();
4635 let theta = theta_0 * t;
4636 let sin_theta = theta.sin();
4637 let sin_theta_0 = theta_0.sin();
4638
4639 let s0 = (theta_0 - theta).cos() - dot * sin_theta / sin_theta_0;
4640 let s1 = sin_theta / sin_theta_0;
4641
4642 Ok(make_vec4(
4643 s0 * q1[0] + s1 * q2[0],
4644 s0 * q1[1] + s1 * q2[1],
4645 s0 * q1[2] + s1 * q2[2],
4646 s0 * q1[3] + s1 * q2[3],
4647 ))
4648 });
4649
4650 define(interp, "quat_to_euler", Some(1), |_, args| {
4652 let q = extract_vec4(&args[0], "quat_to_euler")?;
4653 let (w, x, y, z) = (q[0], q[1], q[2], q[3]);
4654
4655 let sinr_cosp = 2.0 * (w * x + y * z);
4657 let cosr_cosp = 1.0 - 2.0 * (x * x + y * y);
4658 let roll = sinr_cosp.atan2(cosr_cosp);
4659
4660 let sinp = 2.0 * (w * y - z * x);
4662 let pitch = if sinp.abs() >= 1.0 {
4663 std::f64::consts::FRAC_PI_2.copysign(sinp)
4664 } else {
4665 sinp.asin()
4666 };
4667
4668 let siny_cosp = 2.0 * (w * z + x * y);
4670 let cosy_cosp = 1.0 - 2.0 * (y * y + z * z);
4671 let yaw = siny_cosp.atan2(cosy_cosp);
4672
4673 Ok(make_vec3(pitch, yaw, roll))
4674 });
4675
4676 define(interp, "quat_to_mat4", Some(1), |_, args| {
4678 let q = extract_vec4(&args[0], "quat_to_mat4")?;
4679 let (w, x, y, z) = (q[0], q[1], q[2], q[3]);
4680
4681 let xx = x * x;
4682 let yy = y * y;
4683 let zz = z * z;
4684 let xy = x * y;
4685 let xz = x * z;
4686 let yz = y * z;
4687 let wx = w * x;
4688 let wy = w * y;
4689 let wz = w * z;
4690
4691 Ok(make_mat4([
4693 1.0 - 2.0 * (yy + zz),
4694 2.0 * (xy + wz),
4695 2.0 * (xz - wy),
4696 0.0,
4697 2.0 * (xy - wz),
4698 1.0 - 2.0 * (xx + zz),
4699 2.0 * (yz + wx),
4700 0.0,
4701 2.0 * (xz + wy),
4702 2.0 * (yz - wx),
4703 1.0 - 2.0 * (xx + yy),
4704 0.0,
4705 0.0,
4706 0.0,
4707 0.0,
4708 1.0,
4709 ]))
4710 });
4711
4712 define(interp, "vec2", Some(2), |_, args| {
4718 let x = extract_number(&args[0], "vec2")?;
4719 let y = extract_number(&args[1], "vec2")?;
4720 Ok(make_vec2(x, y))
4721 });
4722
4723 define(interp, "vec3", Some(3), |_, args| {
4725 let x = extract_number(&args[0], "vec3")?;
4726 let y = extract_number(&args[1], "vec3")?;
4727 let z = extract_number(&args[2], "vec3")?;
4728 Ok(make_vec3(x, y, z))
4729 });
4730
4731 define(interp, "vec4", Some(4), |_, args| {
4733 let x = extract_number(&args[0], "vec4")?;
4734 let y = extract_number(&args[1], "vec4")?;
4735 let z = extract_number(&args[2], "vec4")?;
4736 let w = extract_number(&args[3], "vec4")?;
4737 Ok(make_vec4(x, y, z, w))
4738 });
4739
4740 define(interp, "vec3_add", Some(2), |_, args| {
4742 let a = extract_vec3(&args[0], "vec3_add")?;
4743 let b = extract_vec3(&args[1], "vec3_add")?;
4744 Ok(make_vec3(a[0] + b[0], a[1] + b[1], a[2] + b[2]))
4745 });
4746
4747 define(interp, "vec3_sub", Some(2), |_, args| {
4749 let a = extract_vec3(&args[0], "vec3_sub")?;
4750 let b = extract_vec3(&args[1], "vec3_sub")?;
4751 Ok(make_vec3(a[0] - b[0], a[1] - b[1], a[2] - b[2]))
4752 });
4753
4754 define(interp, "vec3_scale", Some(2), |_, args| {
4756 let v = extract_vec3(&args[0], "vec3_scale")?;
4757 let s = extract_number(&args[1], "vec3_scale")?;
4758 Ok(make_vec3(v[0] * s, v[1] * s, v[2] * s))
4759 });
4760
4761 define(interp, "vec3_dot", Some(2), |_, args| {
4763 let a = extract_vec3(&args[0], "vec3_dot")?;
4764 let b = extract_vec3(&args[1], "vec3_dot")?;
4765 Ok(Value::Float(a[0] * b[0] + a[1] * b[1] + a[2] * b[2]))
4766 });
4767
4768 define(interp, "vec3_cross", Some(2), |_, args| {
4770 let a = extract_vec3(&args[0], "vec3_cross")?;
4771 let b = extract_vec3(&args[1], "vec3_cross")?;
4772 Ok(make_vec3(
4773 a[1] * b[2] - a[2] * b[1],
4774 a[2] * b[0] - a[0] * b[2],
4775 a[0] * b[1] - a[1] * b[0],
4776 ))
4777 });
4778
4779 define(interp, "vec3_length", Some(1), |_, args| {
4781 let v = extract_vec3(&args[0], "vec3_length")?;
4782 Ok(Value::Float(
4783 (v[0] * v[0] + v[1] * v[1] + v[2] * v[2]).sqrt(),
4784 ))
4785 });
4786
4787 define(interp, "vec3_normalize", Some(1), |_, args| {
4789 let v = extract_vec3(&args[0], "vec3_normalize")?;
4790 let len = (v[0] * v[0] + v[1] * v[1] + v[2] * v[2]).sqrt();
4791 if len < 1e-10 {
4792 return Ok(make_vec3(0.0, 0.0, 0.0));
4793 }
4794 Ok(make_vec3(v[0] / len, v[1] / len, v[2] / len))
4795 });
4796
4797 define(interp, "vec3_lerp", Some(3), |_, args| {
4799 let a = extract_vec3(&args[0], "vec3_lerp")?;
4800 let b = extract_vec3(&args[1], "vec3_lerp")?;
4801 let t = extract_number(&args[2], "vec3_lerp")?;
4802 Ok(make_vec3(
4803 a[0] + t * (b[0] - a[0]),
4804 a[1] + t * (b[1] - a[1]),
4805 a[2] + t * (b[2] - a[2]),
4806 ))
4807 });
4808
4809 define(interp, "vec3_reflect", Some(2), |_, args| {
4811 let i = extract_vec3(&args[0], "vec3_reflect")?;
4812 let n = extract_vec3(&args[1], "vec3_reflect")?;
4813 let dot = i[0] * n[0] + i[1] * n[1] + i[2] * n[2];
4814 Ok(make_vec3(
4815 i[0] - 2.0 * dot * n[0],
4816 i[1] - 2.0 * dot * n[1],
4817 i[2] - 2.0 * dot * n[2],
4818 ))
4819 });
4820
4821 define(interp, "vec3_refract", Some(3), |_, args| {
4823 let i = extract_vec3(&args[0], "vec3_refract")?;
4824 let n = extract_vec3(&args[1], "vec3_refract")?;
4825 let eta = extract_number(&args[2], "vec3_refract")?;
4826
4827 let dot = i[0] * n[0] + i[1] * n[1] + i[2] * n[2];
4828 let k = 1.0 - eta * eta * (1.0 - dot * dot);
4829
4830 if k < 0.0 {
4831 return Ok(make_vec3(0.0, 0.0, 0.0));
4833 }
4834
4835 let coeff = eta * dot + k.sqrt();
4836 Ok(make_vec3(
4837 eta * i[0] - coeff * n[0],
4838 eta * i[1] - coeff * n[1],
4839 eta * i[2] - coeff * n[2],
4840 ))
4841 });
4842
4843 define(interp, "vec4_dot", Some(2), |_, args| {
4845 let a = extract_vec4(&args[0], "vec4_dot")?;
4846 let b = extract_vec4(&args[1], "vec4_dot")?;
4847 Ok(Value::Float(
4848 a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3],
4849 ))
4850 });
4851
4852 define(interp, "mat4_identity", Some(0), |_, _| {
4858 Ok(make_mat4([
4859 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0,
4860 ]))
4861 });
4862
4863 define(interp, "mat4_mul", Some(2), |_, args| {
4865 let a = extract_mat4(&args[0], "mat4_mul")?;
4866 let b = extract_mat4(&args[1], "mat4_mul")?;
4867
4868 let mut result = [0.0f64; 16];
4869 for col in 0..4 {
4870 for row in 0..4 {
4871 let mut sum = 0.0;
4872 for k in 0..4 {
4873 sum += a[k * 4 + row] * b[col * 4 + k];
4874 }
4875 result[col * 4 + row] = sum;
4876 }
4877 }
4878 Ok(make_mat4(result))
4879 });
4880
4881 define(interp, "mat4_transform", Some(2), |_, args| {
4883 let m = extract_mat4(&args[0], "mat4_transform")?;
4884 let v = extract_vec4(&args[1], "mat4_transform")?;
4885
4886 Ok(make_vec4(
4887 m[0] * v[0] + m[4] * v[1] + m[8] * v[2] + m[12] * v[3],
4888 m[1] * v[0] + m[5] * v[1] + m[9] * v[2] + m[13] * v[3],
4889 m[2] * v[0] + m[6] * v[1] + m[10] * v[2] + m[14] * v[3],
4890 m[3] * v[0] + m[7] * v[1] + m[11] * v[2] + m[15] * v[3],
4891 ))
4892 });
4893
4894 define(interp, "mat4_translate", Some(3), |_, args| {
4896 let tx = extract_number(&args[0], "mat4_translate")?;
4897 let ty = extract_number(&args[1], "mat4_translate")?;
4898 let tz = extract_number(&args[2], "mat4_translate")?;
4899 Ok(make_mat4([
4900 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, tx, ty, tz, 1.0,
4901 ]))
4902 });
4903
4904 define(interp, "mat4_scale", Some(3), |_, args| {
4906 let sx = extract_number(&args[0], "mat4_scale")?;
4907 let sy = extract_number(&args[1], "mat4_scale")?;
4908 let sz = extract_number(&args[2], "mat4_scale")?;
4909 Ok(make_mat4([
4910 sx, 0.0, 0.0, 0.0, 0.0, sy, 0.0, 0.0, 0.0, 0.0, sz, 0.0, 0.0, 0.0, 0.0, 1.0,
4911 ]))
4912 });
4913
4914 define(interp, "mat4_rotate_x", Some(1), |_, args| {
4916 let angle = extract_number(&args[0], "mat4_rotate_x")?;
4917 let (s, c) = angle.sin_cos();
4918 Ok(make_mat4([
4919 1.0, 0.0, 0.0, 0.0, 0.0, c, s, 0.0, 0.0, -s, c, 0.0, 0.0, 0.0, 0.0, 1.0,
4920 ]))
4921 });
4922
4923 define(interp, "mat4_rotate_y", Some(1), |_, args| {
4925 let angle = extract_number(&args[0], "mat4_rotate_y")?;
4926 let (s, c) = angle.sin_cos();
4927 Ok(make_mat4([
4928 c, 0.0, -s, 0.0, 0.0, 1.0, 0.0, 0.0, s, 0.0, c, 0.0, 0.0, 0.0, 0.0, 1.0,
4929 ]))
4930 });
4931
4932 define(interp, "mat4_rotate_z", Some(1), |_, args| {
4934 let angle = extract_number(&args[0], "mat4_rotate_z")?;
4935 let (s, c) = angle.sin_cos();
4936 Ok(make_mat4([
4937 c, s, 0.0, 0.0, -s, c, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0,
4938 ]))
4939 });
4940
4941 define(interp, "mat4_perspective", Some(4), |_, args| {
4943 let fov_y = extract_number(&args[0], "mat4_perspective")?;
4944 let aspect = extract_number(&args[1], "mat4_perspective")?;
4945 let near = extract_number(&args[2], "mat4_perspective")?;
4946 let far = extract_number(&args[3], "mat4_perspective")?;
4947
4948 let f = 1.0 / (fov_y / 2.0).tan();
4949 let nf = 1.0 / (near - far);
4950
4951 Ok(make_mat4([
4952 f / aspect,
4953 0.0,
4954 0.0,
4955 0.0,
4956 0.0,
4957 f,
4958 0.0,
4959 0.0,
4960 0.0,
4961 0.0,
4962 (far + near) * nf,
4963 -1.0,
4964 0.0,
4965 0.0,
4966 2.0 * far * near * nf,
4967 0.0,
4968 ]))
4969 });
4970
4971 define(interp, "mat4_ortho", Some(6), |_, args| {
4973 let left = extract_number(&args[0], "mat4_ortho")?;
4974 let right = extract_number(&args[1], "mat4_ortho")?;
4975 let bottom = extract_number(&args[2], "mat4_ortho")?;
4976 let top = extract_number(&args[3], "mat4_ortho")?;
4977 let near = extract_number(&args[4], "mat4_ortho")?;
4978 let far = extract_number(&args[5], "mat4_ortho")?;
4979
4980 let lr = 1.0 / (left - right);
4981 let bt = 1.0 / (bottom - top);
4982 let nf = 1.0 / (near - far);
4983
4984 Ok(make_mat4([
4985 -2.0 * lr,
4986 0.0,
4987 0.0,
4988 0.0,
4989 0.0,
4990 -2.0 * bt,
4991 0.0,
4992 0.0,
4993 0.0,
4994 0.0,
4995 2.0 * nf,
4996 0.0,
4997 (left + right) * lr,
4998 (top + bottom) * bt,
4999 (far + near) * nf,
5000 1.0,
5001 ]))
5002 });
5003
5004 define(interp, "mat4_look_at", Some(3), |_, args| {
5006 let eye = extract_vec3(&args[0], "mat4_look_at")?;
5007 let center = extract_vec3(&args[1], "mat4_look_at")?;
5008 let up = extract_vec3(&args[2], "mat4_look_at")?;
5009
5010 let fx = center[0] - eye[0];
5012 let fy = center[1] - eye[1];
5013 let fz = center[2] - eye[2];
5014 let flen = (fx * fx + fy * fy + fz * fz).sqrt();
5015 let (fx, fy, fz) = (fx / flen, fy / flen, fz / flen);
5016
5017 let rx = fy * up[2] - fz * up[1];
5019 let ry = fz * up[0] - fx * up[2];
5020 let rz = fx * up[1] - fy * up[0];
5021 let rlen = (rx * rx + ry * ry + rz * rz).sqrt();
5022 let (rx, ry, rz) = (rx / rlen, ry / rlen, rz / rlen);
5023
5024 let ux = ry * fz - rz * fy;
5026 let uy = rz * fx - rx * fz;
5027 let uz = rx * fy - ry * fx;
5028
5029 Ok(make_mat4([
5030 rx,
5031 ux,
5032 -fx,
5033 0.0,
5034 ry,
5035 uy,
5036 -fy,
5037 0.0,
5038 rz,
5039 uz,
5040 -fz,
5041 0.0,
5042 -(rx * eye[0] + ry * eye[1] + rz * eye[2]),
5043 -(ux * eye[0] + uy * eye[1] + uz * eye[2]),
5044 -(-fx * eye[0] - fy * eye[1] - fz * eye[2]),
5045 1.0,
5046 ]))
5047 });
5048
5049 define(interp, "mat4_inverse", Some(1), |_, args| {
5051 let m = extract_mat4(&args[0], "mat4_inverse")?;
5052
5053 let a00 = m[0];
5055 let a01 = m[1];
5056 let a02 = m[2];
5057 let a03 = m[3];
5058 let a10 = m[4];
5059 let a11 = m[5];
5060 let a12 = m[6];
5061 let a13 = m[7];
5062 let a20 = m[8];
5063 let a21 = m[9];
5064 let a22 = m[10];
5065 let a23 = m[11];
5066 let a30 = m[12];
5067 let a31 = m[13];
5068 let a32 = m[14];
5069 let a33 = m[15];
5070
5071 let b00 = a00 * a11 - a01 * a10;
5072 let b01 = a00 * a12 - a02 * a10;
5073 let b02 = a00 * a13 - a03 * a10;
5074 let b03 = a01 * a12 - a02 * a11;
5075 let b04 = a01 * a13 - a03 * a11;
5076 let b05 = a02 * a13 - a03 * a12;
5077 let b06 = a20 * a31 - a21 * a30;
5078 let b07 = a20 * a32 - a22 * a30;
5079 let b08 = a20 * a33 - a23 * a30;
5080 let b09 = a21 * a32 - a22 * a31;
5081 let b10 = a21 * a33 - a23 * a31;
5082 let b11 = a22 * a33 - a23 * a32;
5083
5084 let det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
5085
5086 if det.abs() < 1e-10 {
5087 return Err(RuntimeError::new("mat4_inverse: singular matrix"));
5088 }
5089
5090 let inv_det = 1.0 / det;
5091
5092 Ok(make_mat4([
5093 (a11 * b11 - a12 * b10 + a13 * b09) * inv_det,
5094 (a02 * b10 - a01 * b11 - a03 * b09) * inv_det,
5095 (a31 * b05 - a32 * b04 + a33 * b03) * inv_det,
5096 (a22 * b04 - a21 * b05 - a23 * b03) * inv_det,
5097 (a12 * b08 - a10 * b11 - a13 * b07) * inv_det,
5098 (a00 * b11 - a02 * b08 + a03 * b07) * inv_det,
5099 (a32 * b02 - a30 * b05 - a33 * b01) * inv_det,
5100 (a20 * b05 - a22 * b02 + a23 * b01) * inv_det,
5101 (a10 * b10 - a11 * b08 + a13 * b06) * inv_det,
5102 (a01 * b08 - a00 * b10 - a03 * b06) * inv_det,
5103 (a30 * b04 - a31 * b02 + a33 * b00) * inv_det,
5104 (a21 * b02 - a20 * b04 - a23 * b00) * inv_det,
5105 (a11 * b07 - a10 * b09 - a12 * b06) * inv_det,
5106 (a00 * b09 - a01 * b07 + a02 * b06) * inv_det,
5107 (a31 * b01 - a30 * b03 - a32 * b00) * inv_det,
5108 (a20 * b03 - a21 * b01 + a22 * b00) * inv_det,
5109 ]))
5110 });
5111
5112 define(interp, "mat4_transpose", Some(1), |_, args| {
5114 let m = extract_mat4(&args[0], "mat4_transpose")?;
5115 Ok(make_mat4([
5116 m[0], m[4], m[8], m[12], m[1], m[5], m[9], m[13], m[2], m[6], m[10], m[14], m[3], m[7],
5117 m[11], m[15],
5118 ]))
5119 });
5120
5121 define(interp, "mat3_identity", Some(0), |_, _| {
5127 Ok(make_mat3([1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0]))
5128 });
5129
5130 define(interp, "mat3_from_mat4", Some(1), |_, args| {
5132 let m = extract_mat4(&args[0], "mat3_from_mat4")?;
5133 Ok(make_mat3([
5134 m[0], m[1], m[2], m[4], m[5], m[6], m[8], m[9], m[10],
5135 ]))
5136 });
5137
5138 define(interp, "mat3_mul", Some(2), |_, args| {
5140 let a = extract_mat3(&args[0], "mat3_mul")?;
5141 let b = extract_mat3(&args[1], "mat3_mul")?;
5142
5143 let mut result = [0.0f64; 9];
5144 for col in 0..3 {
5145 for row in 0..3 {
5146 let mut sum = 0.0;
5147 for k in 0..3 {
5148 sum += a[k * 3 + row] * b[col * 3 + k];
5149 }
5150 result[col * 3 + row] = sum;
5151 }
5152 }
5153 Ok(make_mat3(result))
5154 });
5155
5156 define(interp, "mat3_transform", Some(2), |_, args| {
5158 let m = extract_mat3(&args[0], "mat3_transform")?;
5159 let v = extract_vec3(&args[1], "mat3_transform")?;
5160
5161 Ok(make_vec3(
5162 m[0] * v[0] + m[3] * v[1] + m[6] * v[2],
5163 m[1] * v[0] + m[4] * v[1] + m[7] * v[2],
5164 m[2] * v[0] + m[5] * v[1] + m[8] * v[2],
5165 ))
5166 });
5167
5168 define(interp, "mat3_inverse", Some(1), |_, args| {
5170 let m = extract_mat3(&args[0], "mat3_inverse")?;
5171
5172 let det = m[0] * (m[4] * m[8] - m[5] * m[7]) - m[3] * (m[1] * m[8] - m[2] * m[7])
5173 + m[6] * (m[1] * m[5] - m[2] * m[4]);
5174
5175 if det.abs() < 1e-10 {
5176 return Err(RuntimeError::new("mat3_inverse: singular matrix"));
5177 }
5178
5179 let inv_det = 1.0 / det;
5180
5181 Ok(make_mat3([
5182 (m[4] * m[8] - m[5] * m[7]) * inv_det,
5183 (m[2] * m[7] - m[1] * m[8]) * inv_det,
5184 (m[1] * m[5] - m[2] * m[4]) * inv_det,
5185 (m[5] * m[6] - m[3] * m[8]) * inv_det,
5186 (m[0] * m[8] - m[2] * m[6]) * inv_det,
5187 (m[2] * m[3] - m[0] * m[5]) * inv_det,
5188 (m[3] * m[7] - m[4] * m[6]) * inv_det,
5189 (m[1] * m[6] - m[0] * m[7]) * inv_det,
5190 (m[0] * m[4] - m[1] * m[3]) * inv_det,
5191 ]))
5192 });
5193
5194 define(interp, "mat3_transpose", Some(1), |_, args| {
5196 let m = extract_mat3(&args[0], "mat3_transpose")?;
5197 Ok(make_mat3([
5198 m[0], m[3], m[6], m[1], m[4], m[7], m[2], m[5], m[8],
5199 ]))
5200 });
5201}
5202
5203fn extract_number(v: &Value, fn_name: &str) -> Result<f64, RuntimeError> {
5205 match v {
5206 Value::Float(f) => Ok(*f),
5207 Value::Int(i) => Ok(*i as f64),
5208 _ => Err(RuntimeError::new(format!(
5209 "{}() requires number argument",
5210 fn_name
5211 ))),
5212 }
5213}
5214
5215fn extract_vec2(v: &Value, fn_name: &str) -> Result<[f64; 2], RuntimeError> {
5216 match v {
5217 Value::Array(arr) => {
5218 let arr = arr.borrow();
5219 if arr.len() < 2 {
5220 return Err(RuntimeError::new(format!(
5221 "{}() requires vec2 (2 elements)",
5222 fn_name
5223 )));
5224 }
5225 Ok([
5226 extract_number(&arr[0], fn_name)?,
5227 extract_number(&arr[1], fn_name)?,
5228 ])
5229 }
5230 _ => Err(RuntimeError::new(format!(
5231 "{}() requires vec2 array",
5232 fn_name
5233 ))),
5234 }
5235}
5236
5237fn extract_vec3(v: &Value, fn_name: &str) -> Result<[f64; 3], RuntimeError> {
5238 match v {
5239 Value::Array(arr) => {
5240 let arr = arr.borrow();
5241 if arr.len() < 3 {
5242 return Err(RuntimeError::new(format!(
5243 "{}() requires vec3 (3 elements)",
5244 fn_name
5245 )));
5246 }
5247 Ok([
5248 extract_number(&arr[0], fn_name)?,
5249 extract_number(&arr[1], fn_name)?,
5250 extract_number(&arr[2], fn_name)?,
5251 ])
5252 }
5253 _ => Err(RuntimeError::new(format!(
5254 "{}() requires vec3 array",
5255 fn_name
5256 ))),
5257 }
5258}
5259
5260fn extract_vec4(v: &Value, fn_name: &str) -> Result<[f64; 4], RuntimeError> {
5261 match v {
5262 Value::Array(arr) => {
5263 let arr = arr.borrow();
5264 if arr.len() < 4 {
5265 return Err(RuntimeError::new(format!(
5266 "{}() requires vec4 (4 elements)",
5267 fn_name
5268 )));
5269 }
5270 Ok([
5271 extract_number(&arr[0], fn_name)?,
5272 extract_number(&arr[1], fn_name)?,
5273 extract_number(&arr[2], fn_name)?,
5274 extract_number(&arr[3], fn_name)?,
5275 ])
5276 }
5277 _ => Err(RuntimeError::new(format!(
5278 "{}() requires vec4 array",
5279 fn_name
5280 ))),
5281 }
5282}
5283
5284fn extract_mat3(v: &Value, fn_name: &str) -> Result<[f64; 9], RuntimeError> {
5285 match v {
5286 Value::Array(arr) => {
5287 let arr = arr.borrow();
5288 if arr.len() < 9 {
5289 return Err(RuntimeError::new(format!(
5290 "{}() requires mat3 (9 elements)",
5291 fn_name
5292 )));
5293 }
5294 let mut result = [0.0f64; 9];
5295 for i in 0..9 {
5296 result[i] = extract_number(&arr[i], fn_name)?;
5297 }
5298 Ok(result)
5299 }
5300 _ => Err(RuntimeError::new(format!(
5301 "{}() requires mat3 array",
5302 fn_name
5303 ))),
5304 }
5305}
5306
5307fn extract_mat4(v: &Value, fn_name: &str) -> Result<[f64; 16], RuntimeError> {
5308 match v {
5309 Value::Array(arr) => {
5310 let arr = arr.borrow();
5311 if arr.len() < 16 {
5312 return Err(RuntimeError::new(format!(
5313 "{}() requires mat4 (16 elements)",
5314 fn_name
5315 )));
5316 }
5317 let mut result = [0.0f64; 16];
5318 for i in 0..16 {
5319 result[i] = extract_number(&arr[i], fn_name)?;
5320 }
5321 Ok(result)
5322 }
5323 _ => Err(RuntimeError::new(format!(
5324 "{}() requires mat4 array",
5325 fn_name
5326 ))),
5327 }
5328}
5329
5330fn make_vec2(x: f64, y: f64) -> Value {
5331 Value::Array(Rc::new(RefCell::new(vec![
5332 Value::Float(x),
5333 Value::Float(y),
5334 ])))
5335}
5336
5337fn make_vec3(x: f64, y: f64, z: f64) -> Value {
5338 Value::Array(Rc::new(RefCell::new(vec![
5339 Value::Float(x),
5340 Value::Float(y),
5341 Value::Float(z),
5342 ])))
5343}
5344
5345fn make_vec3_arr(v: [f64; 3]) -> Value {
5347 make_vec3(v[0], v[1], v[2])
5348}
5349
5350fn make_vec4(x: f64, y: f64, z: f64, w: f64) -> Value {
5351 Value::Array(Rc::new(RefCell::new(vec![
5352 Value::Float(x),
5353 Value::Float(y),
5354 Value::Float(z),
5355 Value::Float(w),
5356 ])))
5357}
5358
5359fn make_mat3(m: [f64; 9]) -> Value {
5360 Value::Array(Rc::new(RefCell::new(
5361 m.iter().map(|&v| Value::Float(v)).collect(),
5362 )))
5363}
5364
5365fn make_mat4(m: [f64; 16]) -> Value {
5366 Value::Array(Rc::new(RefCell::new(
5367 m.iter().map(|&v| Value::Float(v)).collect(),
5368 )))
5369}
5370
5371fn register_concurrency(interp: &mut Interpreter) {
5388 define(interp, "channel_new", Some(0), |_, _| {
5392 let (sender, receiver) = mpsc::channel();
5393 let inner = ChannelInner {
5394 sender: Mutex::new(sender),
5395 receiver: Mutex::new(receiver),
5396 };
5397 Ok(Value::Channel(Arc::new(inner)))
5398 });
5399
5400 define(interp, "channel_send", Some(2), |_, args| {
5402 let channel = match &args[0] {
5403 Value::Channel(ch) => ch.clone(),
5404 _ => {
5405 return Err(RuntimeError::new(
5406 "channel_send() requires channel as first argument",
5407 ))
5408 }
5409 };
5410 let value = args[1].clone();
5411
5412 let sender = channel
5413 .sender
5414 .lock()
5415 .map_err(|_| RuntimeError::new("channel mutex poisoned"))?;
5416 sender
5417 .send(value)
5418 .map_err(|_| RuntimeError::new("channel_send() failed: receiver dropped"))?;
5419
5420 Ok(Value::Null)
5421 });
5422
5423 define(interp, "channel_recv", Some(1), |_, args| {
5425 let channel = match &args[0] {
5426 Value::Channel(ch) => ch.clone(),
5427 _ => {
5428 return Err(RuntimeError::new(
5429 "channel_recv() requires channel argument",
5430 ))
5431 }
5432 };
5433
5434 let receiver = channel
5435 .receiver
5436 .lock()
5437 .map_err(|_| RuntimeError::new("channel mutex poisoned"))?;
5438 match receiver.recv() {
5439 Ok(value) => Ok(value),
5440 Err(_) => Err(RuntimeError::new("channel_recv() failed: sender dropped")),
5441 }
5442 });
5443
5444 define(interp, "channel_try_recv", Some(1), |_, args| {
5446 let channel = match &args[0] {
5447 Value::Channel(ch) => ch.clone(),
5448 _ => {
5449 return Err(RuntimeError::new(
5450 "channel_try_recv() requires channel argument",
5451 ))
5452 }
5453 };
5454
5455 let receiver = channel
5456 .receiver
5457 .lock()
5458 .map_err(|_| RuntimeError::new("channel mutex poisoned"))?;
5459 match receiver.try_recv() {
5460 Ok(value) => {
5461 Ok(Value::Variant {
5463 enum_name: "Option".to_string(),
5464 variant_name: "Some".to_string(),
5465 fields: Some(Rc::new(vec![value])),
5466 })
5467 }
5468 Err(mpsc::TryRecvError::Empty) => {
5469 Ok(Value::Variant {
5471 enum_name: "Option".to_string(),
5472 variant_name: "None".to_string(),
5473 fields: None,
5474 })
5475 }
5476 Err(mpsc::TryRecvError::Disconnected) => Err(RuntimeError::new(
5477 "channel_try_recv() failed: sender dropped",
5478 )),
5479 }
5480 });
5481
5482 define(interp, "channel_recv_timeout", Some(2), |_, args| {
5484 let channel = match &args[0] {
5485 Value::Channel(ch) => ch.clone(),
5486 _ => {
5487 return Err(RuntimeError::new(
5488 "channel_recv_timeout() requires a channel as first argument.\n\
5489 Create a channel with channel_new():\n\
5490 let ch = channel_new();\n\
5491 channel_send(ch, value);\n\
5492 let result = channel_recv_timeout(ch, 1000); // 1 second timeout",
5493 ))
5494 }
5495 };
5496 let timeout_ms = match &args[1] {
5497 Value::Int(ms) => *ms as u64,
5498 _ => {
5499 return Err(RuntimeError::new(
5500 "channel_recv_timeout() requires timeout in milliseconds (integer).\n\
5501 Example: channel_recv_timeout(ch, 1000) // Wait up to 1 second",
5502 ))
5503 }
5504 };
5505
5506 let receiver = channel
5507 .receiver
5508 .lock()
5509 .map_err(|_| RuntimeError::new("channel mutex poisoned"))?;
5510 match receiver.recv_timeout(std::time::Duration::from_millis(timeout_ms)) {
5511 Ok(value) => Ok(Value::Variant {
5512 enum_name: "Option".to_string(),
5513 variant_name: "Some".to_string(),
5514 fields: Some(Rc::new(vec![value])),
5515 }),
5516 Err(mpsc::RecvTimeoutError::Timeout) => Ok(Value::Variant {
5517 enum_name: "Option".to_string(),
5518 variant_name: "None".to_string(),
5519 fields: None,
5520 }),
5521 Err(mpsc::RecvTimeoutError::Disconnected) => Err(RuntimeError::new(
5522 "channel_recv_timeout() failed: sender dropped",
5523 )),
5524 }
5525 });
5526
5527 define(interp, "thread_spawn_detached", Some(0), |_, _| {
5535 thread::spawn(|| {
5538 });
5540 Ok(Value::Null)
5541 });
5542
5543 define(interp, "std·thread·spawn", Some(1), |interp, args| {
5547 match &args[0] {
5549 Value::Function(f) => {
5550 match interp.call_function(f, vec![]) {
5553 Ok(_) => {}
5554 Err(e) => eprintln!("[Sigil thread] Error: {}", e),
5555 }
5556 let mut map = HashMap::new();
5558 map.insert(
5559 "__type__".to_string(),
5560 Value::String(Rc::new("JoinHandle".to_string())),
5561 );
5562 map.insert("done".to_string(), Value::Bool(true));
5563 Ok(Value::Map(Rc::new(RefCell::new(map))))
5564 }
5565 Value::BuiltIn(b) => {
5566 match (b.func)(interp, vec![]) {
5567 Ok(_) => {}
5568 Err(e) => eprintln!("[Sigil thread] Error: {}", e),
5569 }
5570 let mut map = HashMap::new();
5571 map.insert(
5572 "__type__".to_string(),
5573 Value::String(Rc::new("JoinHandle".to_string())),
5574 );
5575 map.insert("done".to_string(), Value::Bool(true));
5576 Ok(Value::Map(Rc::new(RefCell::new(map))))
5577 }
5578 _ => Err(RuntimeError::new("std::thread::spawn requires a closure")),
5579 }
5580 });
5581
5582 define(interp, "thread_join", Some(1), |_, args| {
5585 match &args[0] {
5586 Value::ThreadHandle(h) => {
5587 let mut guard = h
5588 .lock()
5589 .map_err(|_| RuntimeError::new("thread handle mutex poisoned"))?;
5590 if let Some(handle) = guard.take() {
5591 match handle.join() {
5592 Ok(v) => Ok(v),
5593 Err(_) => Err(RuntimeError::new("thread panicked")),
5594 }
5595 } else {
5596 Err(RuntimeError::new("thread already joined"))
5597 }
5598 }
5599 _ => Ok(args[0].clone()),
5601 }
5602 });
5603
5604 define(interp, "thread_sleep", Some(1), |_, args| {
5606 let ms = match &args[0] {
5607 Value::Int(ms) => *ms as u64,
5608 Value::Float(ms) => *ms as u64,
5609 _ => {
5610 return Err(RuntimeError::new(
5611 "thread_sleep() requires integer milliseconds",
5612 ))
5613 }
5614 };
5615
5616 thread::sleep(std::time::Duration::from_millis(ms));
5617 Ok(Value::Null)
5618 });
5619
5620 define(interp, "thread_yield", Some(0), |_, _| {
5622 thread::yield_now();
5623 Ok(Value::Null)
5624 });
5625
5626 define(interp, "thread_id", Some(0), |_, _| {
5628 let id = thread::current().id();
5629 Ok(Value::String(Rc::new(format!("{:?}", id))))
5630 });
5631
5632 define(interp, "parking_lot·Mutex·new", Some(1), |_, args| {
5636 let mut map = HashMap::new();
5637 map.insert(
5638 "__type__".to_string(),
5639 Value::String(Rc::new("Mutex".to_string())),
5640 );
5641 map.insert("inner".to_string(), args[0].clone());
5642 Ok(Value::Map(Rc::new(RefCell::new(map))))
5643 });
5644
5645 define(interp, "std·sync·Mutex·new", Some(1), |_, args| {
5647 let mut map = HashMap::new();
5648 map.insert(
5649 "__type__".to_string(),
5650 Value::String(Rc::new("Mutex".to_string())),
5651 );
5652 map.insert("inner".to_string(), args[0].clone());
5653 Ok(Value::Map(Rc::new(RefCell::new(map))))
5654 });
5655
5656 define(interp, "parking_lot·RwLock·new", Some(1), |_, args| {
5658 let mut map = HashMap::new();
5659 map.insert(
5660 "__type__".to_string(),
5661 Value::String(Rc::new("RwLock".to_string())),
5662 );
5663 map.insert("inner".to_string(), args[0].clone());
5664 Ok(Value::Map(Rc::new(RefCell::new(map))))
5665 });
5666
5667 define(interp, "std·sync·RwLock·new", Some(1), |_, args| {
5669 let mut map = HashMap::new();
5670 map.insert(
5671 "__type__".to_string(),
5672 Value::String(Rc::new("RwLock".to_string())),
5673 );
5674 map.insert("inner".to_string(), args[0].clone());
5675 Ok(Value::Map(Rc::new(RefCell::new(map))))
5676 });
5677
5678 define(interp, "RwLock·new", Some(1), |_, args| {
5680 let mut map = HashMap::new();
5681 map.insert(
5682 "__type__".to_string(),
5683 Value::String(Rc::new("RwLock".to_string())),
5684 );
5685 map.insert("inner".to_string(), args[0].clone());
5686 Ok(Value::Map(Rc::new(RefCell::new(map))))
5687 });
5688
5689 define(interp, "AtomicU64·new", Some(1), |_, args| {
5691 let val = match &args[0] {
5692 Value::Int(i) => *i,
5693 _ => 0,
5694 };
5695 let mut map = HashMap::new();
5696 map.insert(
5697 "__type__".to_string(),
5698 Value::String(Rc::new("AtomicU64".to_string())),
5699 );
5700 map.insert("value".to_string(), Value::Int(val));
5701 Ok(Value::Map(Rc::new(RefCell::new(map))))
5702 });
5703
5704 define(
5706 interp,
5707 "std·sync·atomic·AtomicU64·new",
5708 Some(1),
5709 |_, args| {
5710 let val = match &args[0] {
5711 Value::Int(i) => *i,
5712 _ => 0,
5713 };
5714 let mut map = HashMap::new();
5715 map.insert(
5716 "__type__".to_string(),
5717 Value::String(Rc::new("AtomicU64".to_string())),
5718 );
5719 map.insert("value".to_string(), Value::Int(val));
5720 Ok(Value::Map(Rc::new(RefCell::new(map))))
5721 },
5722 );
5723
5724 define(interp, "AtomicBool·new", Some(1), |_, args| {
5726 let val = match &args[0] {
5727 Value::Bool(b) => *b,
5728 _ => false,
5729 };
5730 let mut map = HashMap::new();
5731 map.insert(
5732 "__type__".to_string(),
5733 Value::String(Rc::new("AtomicBool".to_string())),
5734 );
5735 map.insert("value".to_string(), Value::Bool(val));
5736 Ok(Value::Map(Rc::new(RefCell::new(map))))
5737 });
5738
5739 define(
5740 interp,
5741 "std·sync·atomic·AtomicBool·new",
5742 Some(1),
5743 |_, args| {
5744 let val = match &args[0] {
5745 Value::Bool(b) => *b,
5746 _ => false,
5747 };
5748 let mut map = HashMap::new();
5749 map.insert(
5750 "__type__".to_string(),
5751 Value::String(Rc::new("AtomicBool".to_string())),
5752 );
5753 map.insert("value".to_string(), Value::Bool(val));
5754 Ok(Value::Map(Rc::new(RefCell::new(map))))
5755 },
5756 );
5757
5758 define(interp, "Arc·new", Some(1), |_, args| {
5760 let mut map = HashMap::new();
5761 map.insert(
5762 "__type__".to_string(),
5763 Value::String(Rc::new("Arc".to_string())),
5764 );
5765 map.insert("inner".to_string(), args[0].clone());
5766 Ok(Value::Map(Rc::new(RefCell::new(map))))
5767 });
5768
5769 define(interp, "std·sync·Arc·new", Some(1), |_, args| {
5770 let mut map = HashMap::new();
5771 map.insert(
5772 "__type__".to_string(),
5773 Value::String(Rc::new("Arc".to_string())),
5774 );
5775 map.insert("inner".to_string(), args[0].clone());
5776 Ok(Value::Map(Rc::new(RefCell::new(map))))
5777 });
5778
5779 define(interp, "TcpListener·bind", Some(1), |_, args| {
5784 let addr_str = match &args[0] {
5785 Value::String(s) => s.to_string(),
5786 Value::Ref(r) => {
5787 if let Value::String(s) = &*r.borrow() {
5788 s.to_string()
5789 } else {
5790 return Err(RuntimeError::new(
5791 "TcpListener::bind requires string address",
5792 ));
5793 }
5794 }
5795 Value::Map(m) => {
5797 let borrowed = m.borrow();
5798 if let Some(Value::String(addr)) = borrowed.get("addr") {
5799 addr.to_string()
5800 } else if let Some(Value::String(_)) = borrowed.get("__type__") {
5801 if let Some(Value::String(addr)) = borrowed.get("addr") {
5803 addr.to_string()
5804 } else {
5805 return Err(RuntimeError::new("SocketAddr missing addr field"));
5806 }
5807 } else {
5808 return Err(RuntimeError::new(
5809 "TcpListener::bind requires string or SocketAddr",
5810 ));
5811 }
5812 }
5813 _ => {
5814 return Err(RuntimeError::new(
5815 "TcpListener::bind requires string address",
5816 ))
5817 }
5818 };
5819
5820 let addr: std::net::SocketAddr = match addr_str.parse() {
5822 Ok(a) => a,
5823 Err(e) => return Err(RuntimeError::new(format!("Invalid address: {}", e))),
5824 };
5825
5826 let listener = match std::net::TcpListener::bind(addr) {
5828 Ok(l) => l,
5829 Err(e) => return Err(RuntimeError::new(format!("Failed to bind: {}", e))),
5830 };
5831
5832 let local_addr = listener
5833 .local_addr()
5834 .map(|a| a.to_string())
5835 .unwrap_or_default();
5836
5837 let listener_id = store_listener(listener);
5839
5840 let mut map = HashMap::new();
5841 map.insert(
5842 "__type__".to_string(),
5843 Value::String(Rc::new("TcpListener".to_string())),
5844 );
5845 map.insert("addr".to_string(), Value::String(Rc::new(addr_str)));
5846 map.insert("local_addr".to_string(), Value::String(Rc::new(local_addr)));
5847 map.insert(
5848 "__listener_id__".to_string(),
5849 Value::Int(listener_id as i64),
5850 );
5851
5852 eprintln!("[Sigil] TcpListener bound to {} (id={})", addr, listener_id);
5853
5854 Ok(Value::Variant {
5855 enum_name: "Result".to_string(),
5856 variant_name: "Ok".to_string(),
5857 fields: Some(Rc::new(vec![Value::Map(Rc::new(RefCell::new(map)))])),
5858 })
5859 });
5860
5861 define(interp, "std·net·TcpListener·bind", Some(1), |_, args| {
5862 let addr_str = match &args[0] {
5863 Value::String(s) => s.to_string(),
5864 Value::Ref(r) => {
5865 if let Value::String(s) = &*r.borrow() {
5866 s.to_string()
5867 } else {
5868 return Err(RuntimeError::new(
5869 "TcpListener::bind requires string address",
5870 ));
5871 }
5872 }
5873 Value::Map(m) => {
5875 let borrowed = m.borrow();
5876 if let Some(Value::String(addr)) = borrowed.get("addr") {
5877 addr.to_string()
5878 } else {
5879 return Err(RuntimeError::new(
5880 "TcpListener::bind requires string or SocketAddr",
5881 ));
5882 }
5883 }
5884 _ => {
5885 return Err(RuntimeError::new(
5886 "TcpListener::bind requires string address",
5887 ))
5888 }
5889 };
5890
5891 let addr: std::net::SocketAddr = match addr_str.parse() {
5892 Ok(a) => a,
5893 Err(e) => return Err(RuntimeError::new(format!("Invalid address: {}", e))),
5894 };
5895
5896 let _listener = match std::net::TcpListener::bind(addr) {
5897 Ok(l) => l,
5898 Err(e) => return Err(RuntimeError::new(format!("Failed to bind: {}", e))),
5899 };
5900
5901 let mut map = HashMap::new();
5902 map.insert(
5903 "__type__".to_string(),
5904 Value::String(Rc::new("TcpListener".to_string())),
5905 );
5906 map.insert("addr".to_string(), Value::String(Rc::new(addr_str)));
5907
5908 eprintln!("[Sigil] TcpListener bound to {}", addr);
5909
5910 Ok(Value::Variant {
5911 enum_name: "Result".to_string(),
5912 variant_name: "Ok".to_string(),
5913 fields: Some(Rc::new(vec![Value::Map(Rc::new(RefCell::new(map)))])),
5914 })
5915 });
5916
5917 define(interp, "SocketAddr·parse", Some(1), |_, args| {
5919 let addr_str = match &args[0] {
5920 Value::String(s) => s.to_string(),
5921 _ => return Err(RuntimeError::new("SocketAddr::parse requires string")),
5922 };
5923
5924 match addr_str.parse::<std::net::SocketAddr>() {
5925 Ok(_) => {
5926 let mut map = HashMap::new();
5927 map.insert(
5928 "__type__".to_string(),
5929 Value::String(Rc::new("SocketAddr".to_string())),
5930 );
5931 map.insert("addr".to_string(), Value::String(Rc::new(addr_str)));
5932 Ok(Value::Variant {
5933 enum_name: "Result".to_string(),
5934 variant_name: "Ok".to_string(),
5935 fields: Some(Rc::new(vec![Value::Map(Rc::new(RefCell::new(map)))])),
5936 })
5937 }
5938 Err(e) => Ok(Value::Variant {
5939 enum_name: "Result".to_string(),
5940 variant_name: "Err".to_string(),
5941 fields: Some(Rc::new(vec![Value::String(Rc::new(e.to_string()))])),
5942 }),
5943 }
5944 });
5945
5946 define(interp, "TcpStream·peer_addr", Some(1), |_, args| {
5951 let stream_id = match &args[0] {
5952 Value::Map(m) => {
5953 let borrowed = m.borrow();
5954 if let Some(Value::Int(id)) = borrowed.get("__stream_id__") {
5955 *id as u64
5956 } else {
5957 return Err(RuntimeError::new("TcpStream missing __stream_id__"));
5958 }
5959 }
5960 _ => return Err(RuntimeError::new("peer_addr requires TcpStream")),
5961 };
5962
5963 if let Some(guard) = get_stream_registry().lock().ok() {
5964 if let Some(stream) = guard.get(&stream_id) {
5965 match stream.peer_addr() {
5966 Ok(addr) => {
5967 let mut map = HashMap::new();
5968 map.insert(
5969 "__type__".to_string(),
5970 Value::String(Rc::new("SocketAddr".to_string())),
5971 );
5972 map.insert("addr".to_string(), Value::String(Rc::new(addr.to_string())));
5973 Ok(Value::Variant {
5974 enum_name: "Result".to_string(),
5975 variant_name: "Ok".to_string(),
5976 fields: Some(Rc::new(vec![Value::Map(Rc::new(RefCell::new(map)))])),
5977 })
5978 }
5979 Err(e) => Ok(Value::Variant {
5980 enum_name: "Result".to_string(),
5981 variant_name: "Err".to_string(),
5982 fields: Some(Rc::new(vec![Value::String(Rc::new(e.to_string()))])),
5983 }),
5984 }
5985 } else {
5986 Err(RuntimeError::new("TcpStream not found in registry"))
5987 }
5988 } else {
5989 Err(RuntimeError::new("Failed to lock stream registry"))
5990 }
5991 });
5992
5993 define(interp, "TcpStream·read", Some(2), |_, args| {
5995 use std::io::Read;
5996
5997 let stream_id = match &args[0] {
5998 Value::Map(m) => {
5999 let borrowed = m.borrow();
6000 if let Some(Value::Int(id)) = borrowed.get("__stream_id__") {
6001 *id as u64
6002 } else {
6003 return Err(RuntimeError::new("TcpStream missing __stream_id__"));
6004 }
6005 }
6006 _ => return Err(RuntimeError::new("read requires TcpStream")),
6007 };
6008
6009 let size = match &args[1] {
6010 Value::Int(n) => *n as usize,
6011 _ => return Err(RuntimeError::new("read requires size as integer")),
6012 };
6013
6014 if let Some(mut guard) = get_stream_registry().lock().ok() {
6015 if let Some(stream) = guard.get_mut(&stream_id) {
6016 let mut buf = vec![0u8; size];
6017 match stream.read(&mut buf) {
6018 Ok(n) => {
6019 buf.truncate(n);
6020 let bytes: Vec<Value> = buf.iter().map(|b| Value::Int(*b as i64)).collect();
6021 Ok(Value::Variant {
6022 enum_name: "Result".to_string(),
6023 variant_name: "Ok".to_string(),
6024 fields: Some(Rc::new(vec![Value::Array(Rc::new(RefCell::new(bytes)))])),
6025 })
6026 }
6027 Err(e) => Ok(Value::Variant {
6028 enum_name: "Result".to_string(),
6029 variant_name: "Err".to_string(),
6030 fields: Some(Rc::new(vec![Value::String(Rc::new(e.to_string()))])),
6031 }),
6032 }
6033 } else {
6034 Err(RuntimeError::new("TcpStream not found in registry"))
6035 }
6036 } else {
6037 Err(RuntimeError::new("Failed to lock stream registry"))
6038 }
6039 });
6040
6041 define(interp, "TcpStream·read_exact", Some(2), |_, args| {
6043 use std::io::Read;
6044
6045 let stream_id = match &args[0] {
6046 Value::Map(m) => {
6047 let borrowed = m.borrow();
6048 if let Some(Value::Int(id)) = borrowed.get("__stream_id__") {
6049 *id as u64
6050 } else {
6051 return Err(RuntimeError::new("TcpStream missing __stream_id__"));
6052 }
6053 }
6054 _ => return Err(RuntimeError::new("read_exact requires TcpStream")),
6055 };
6056
6057 let size = match &args[1] {
6058 Value::Int(n) => *n as usize,
6059 _ => return Err(RuntimeError::new("read_exact requires size as integer")),
6060 };
6061
6062 if let Some(mut guard) = get_stream_registry().lock().ok() {
6063 if let Some(stream) = guard.get_mut(&stream_id) {
6064 let mut buf = vec![0u8; size];
6065 match stream.read_exact(&mut buf) {
6066 Ok(()) => {
6067 let bytes: Vec<Value> = buf.iter().map(|b| Value::Int(*b as i64)).collect();
6068 Ok(Value::Variant {
6069 enum_name: "Result".to_string(),
6070 variant_name: "Ok".to_string(),
6071 fields: Some(Rc::new(vec![Value::Array(Rc::new(RefCell::new(bytes)))])),
6072 })
6073 }
6074 Err(e) => Ok(Value::Variant {
6075 enum_name: "Result".to_string(),
6076 variant_name: "Err".to_string(),
6077 fields: Some(Rc::new(vec![Value::String(Rc::new(e.to_string()))])),
6078 }),
6079 }
6080 } else {
6081 Err(RuntimeError::new("TcpStream not found in registry"))
6082 }
6083 } else {
6084 Err(RuntimeError::new("Failed to lock stream registry"))
6085 }
6086 });
6087
6088 define(interp, "TcpStream·write_all", Some(2), |_, args| {
6090 use std::io::Write;
6091
6092 let stream_id = match &args[0] {
6093 Value::Map(m) => {
6094 let borrowed = m.borrow();
6095 if let Some(Value::Int(id)) = borrowed.get("__stream_id__") {
6096 *id as u64
6097 } else {
6098 return Err(RuntimeError::new("TcpStream missing __stream_id__"));
6099 }
6100 }
6101 _ => return Err(RuntimeError::new("write_all requires TcpStream")),
6102 };
6103
6104 let data: Vec<u8> = match &args[1] {
6106 Value::String(s) => s.as_bytes().to_vec(),
6107 Value::Array(arr) => arr
6108 .borrow()
6109 .iter()
6110 .filter_map(|v| {
6111 if let Value::Int(n) = v {
6112 Some(*n as u8)
6113 } else {
6114 None
6115 }
6116 })
6117 .collect(),
6118 Value::Ref(r) => {
6119 if let Value::String(s) = &*r.borrow() {
6120 s.as_bytes().to_vec()
6121 } else {
6122 return Err(RuntimeError::new("write_all requires string or byte array"));
6123 }
6124 }
6125 _ => return Err(RuntimeError::new("write_all requires string or byte array")),
6126 };
6127
6128 if let Some(mut guard) = get_stream_registry().lock().ok() {
6129 if let Some(stream) = guard.get_mut(&stream_id) {
6130 match stream.write_all(&data) {
6131 Ok(()) => Ok(Value::Variant {
6132 enum_name: "Result".to_string(),
6133 variant_name: "Ok".to_string(),
6134 fields: Some(Rc::new(vec![Value::Null])),
6135 }),
6136 Err(e) => Ok(Value::Variant {
6137 enum_name: "Result".to_string(),
6138 variant_name: "Err".to_string(),
6139 fields: Some(Rc::new(vec![Value::String(Rc::new(e.to_string()))])),
6140 }),
6141 }
6142 } else {
6143 Err(RuntimeError::new("TcpStream not found in registry"))
6144 }
6145 } else {
6146 Err(RuntimeError::new("Failed to lock stream registry"))
6147 }
6148 });
6149
6150 define(interp, "TcpStream·flush", Some(1), |_, args| {
6152 use std::io::Write;
6153
6154 let stream_id = match &args[0] {
6155 Value::Map(m) => {
6156 let borrowed = m.borrow();
6157 if let Some(Value::Int(id)) = borrowed.get("__stream_id__") {
6158 *id as u64
6159 } else {
6160 return Err(RuntimeError::new("TcpStream missing __stream_id__"));
6161 }
6162 }
6163 _ => return Err(RuntimeError::new("flush requires TcpStream")),
6164 };
6165
6166 if let Some(mut guard) = get_stream_registry().lock().ok() {
6167 if let Some(stream) = guard.get_mut(&stream_id) {
6168 match stream.flush() {
6169 Ok(()) => Ok(Value::Variant {
6170 enum_name: "Result".to_string(),
6171 variant_name: "Ok".to_string(),
6172 fields: Some(Rc::new(vec![Value::Null])),
6173 }),
6174 Err(e) => Ok(Value::Variant {
6175 enum_name: "Result".to_string(),
6176 variant_name: "Err".to_string(),
6177 fields: Some(Rc::new(vec![Value::String(Rc::new(e.to_string()))])),
6178 }),
6179 }
6180 } else {
6181 Err(RuntimeError::new("TcpStream not found in registry"))
6182 }
6183 } else {
6184 Err(RuntimeError::new("Failed to lock stream registry"))
6185 }
6186 });
6187
6188 define(interp, "BufReader·new", Some(1), |_, args| {
6192 use std::io::BufReader as StdBufReader;
6193
6194 let stream_id = match &args[0] {
6196 Value::Map(m) => {
6197 let borrowed = m.borrow();
6198 if let Some(Value::Int(id)) = borrowed.get("__stream_id__") {
6199 *id as u64
6200 } else {
6201 return Err(RuntimeError::new("BufReader::new requires TcpStream"));
6202 }
6203 }
6204 Value::Ref(r) => {
6205 let inner = r.borrow();
6207 if let Value::Map(m) = &*inner {
6208 let borrowed = m.borrow();
6209 if let Some(Value::Int(id)) = borrowed.get("__stream_id__") {
6210 *id as u64
6211 } else {
6212 return Err(RuntimeError::new(
6213 "BufReader::new requires TcpStream (missing stream_id in Ref)",
6214 ));
6215 }
6216 } else {
6217 return Err(RuntimeError::new(
6218 "BufReader::new requires TcpStream (Ref does not contain Map)",
6219 ));
6220 }
6221 }
6222 _ => return Err(RuntimeError::new("BufReader::new requires TcpStream")),
6223 };
6224
6225 let reader_id = if let Some(mut guard) = get_stream_registry().lock().ok() {
6227 if let Some(stream) = guard.get_mut(&stream_id) {
6228 let stream_clone = match stream.try_clone() {
6229 Ok(s) => s,
6230 Err(e) => {
6231 return Err(RuntimeError::new(format!("Failed to clone stream: {}", e)))
6232 }
6233 };
6234 let reader = StdBufReader::new(stream_clone);
6235 store_bufreader(reader)
6236 } else {
6237 return Err(RuntimeError::new("Stream not found in registry"));
6238 }
6239 } else {
6240 return Err(RuntimeError::new("Failed to lock stream registry"));
6241 };
6242
6243 let mut map = HashMap::new();
6244 map.insert(
6245 "__type__".to_string(),
6246 Value::String(Rc::new("BufReader".to_string())),
6247 );
6248 map.insert("__stream_id__".to_string(), Value::Int(stream_id as i64));
6249 map.insert("__reader_id__".to_string(), Value::Int(reader_id as i64));
6250 Ok(Value::Map(Rc::new(RefCell::new(map))))
6251 });
6252
6253 define(interp, "BufReader·read_line", Some(1), |_, args| {
6255 use std::io::BufRead;
6256
6257 let reader_id = match &args[0] {
6258 Value::Map(m) => {
6259 let borrowed = m.borrow();
6260 if let Some(Value::Int(id)) = borrowed.get("__reader_id__") {
6261 *id as u64
6262 } else {
6263 return Err(RuntimeError::new("BufReader missing __reader_id__"));
6264 }
6265 }
6266 _ => return Err(RuntimeError::new("read_line requires BufReader")),
6267 };
6268
6269 if let Some(mut guard) = get_bufreader_registry().lock().ok() {
6270 if let Some(reader) = guard.get_mut(&reader_id) {
6271 let mut line = String::new();
6272
6273 match reader.read_line(&mut line) {
6274 Ok(n) => {
6275 if n == 0 {
6276 Ok(Value::Variant {
6278 enum_name: "Result".to_string(),
6279 variant_name: "Ok".to_string(),
6280 fields: Some(Rc::new(vec![Value::Null])),
6281 })
6282 } else {
6283 Ok(Value::Variant {
6284 enum_name: "Result".to_string(),
6285 variant_name: "Ok".to_string(),
6286 fields: Some(Rc::new(vec![Value::String(Rc::new(line))])),
6287 })
6288 }
6289 }
6290 Err(e) => Ok(Value::Variant {
6291 enum_name: "Result".to_string(),
6292 variant_name: "Err".to_string(),
6293 fields: Some(Rc::new(vec![Value::String(Rc::new(e.to_string()))])),
6294 }),
6295 }
6296 } else {
6297 Err(RuntimeError::new("BufReader not found in registry"))
6298 }
6299 } else {
6300 Err(RuntimeError::new("Failed to lock bufreader registry"))
6301 }
6302 });
6303
6304 define(
6309 interp,
6310 "styx_http·middleware·Logger·new",
6311 Some(0),
6312 |_, _| {
6313 let mut map = HashMap::new();
6314 map.insert(
6315 "__type__".to_string(),
6316 Value::String(Rc::new("Logger".to_string())),
6317 );
6318 map.insert(
6319 "format".to_string(),
6320 Value::String(Rc::new("Common".to_string())),
6321 );
6322 Ok(Value::Map(Rc::new(RefCell::new(map))))
6323 },
6324 );
6325
6326 define(interp, "Logger·new", Some(0), |_, _| {
6327 let mut map = HashMap::new();
6328 map.insert(
6329 "__type__".to_string(),
6330 Value::String(Rc::new("Logger".to_string())),
6331 );
6332 map.insert(
6333 "format".to_string(),
6334 Value::String(Rc::new("Common".to_string())),
6335 );
6336 Ok(Value::Map(Rc::new(RefCell::new(map))))
6337 });
6338
6339 define(
6341 interp,
6342 "styx_http·middleware·Cors·new",
6343 Some(0),
6344 |_, _| {
6345 let mut map = HashMap::new();
6346 map.insert(
6347 "__type__".to_string(),
6348 Value::String(Rc::new("Cors".to_string())),
6349 );
6350 map.insert(
6351 "origins".to_string(),
6352 Value::Array(Rc::new(RefCell::new(vec![]))),
6353 );
6354 Ok(Value::Map(Rc::new(RefCell::new(map))))
6355 },
6356 );
6357
6358 define(interp, "Cors·new", Some(0), |_, _| {
6359 let mut map = HashMap::new();
6360 map.insert(
6361 "__type__".to_string(),
6362 Value::String(Rc::new("Cors".to_string())),
6363 );
6364 map.insert(
6365 "origins".to_string(),
6366 Value::Array(Rc::new(RefCell::new(vec![]))),
6367 );
6368 Ok(Value::Map(Rc::new(RefCell::new(map))))
6369 });
6370
6371 define(
6373 interp,
6374 "styx_http·middleware·SecurityHeaders·new",
6375 Some(0),
6376 |_, _| {
6377 let mut map = HashMap::new();
6378 map.insert(
6379 "__type__".to_string(),
6380 Value::String(Rc::new("SecurityHeaders".to_string())),
6381 );
6382 Ok(Value::Map(Rc::new(RefCell::new(map))))
6383 },
6384 );
6385
6386 define(interp, "SecurityHeaders·new", Some(0), |_, _| {
6387 let mut map = HashMap::new();
6388 map.insert(
6389 "__type__".to_string(),
6390 Value::String(Rc::new("SecurityHeaders".to_string())),
6391 );
6392 Ok(Value::Map(Rc::new(RefCell::new(map))))
6393 });
6394
6395 define(
6397 interp,
6398 "styx_http·middleware·RateLimiter·new",
6399 Some(0),
6400 |_, _| {
6401 let mut map = HashMap::new();
6402 map.insert(
6403 "__type__".to_string(),
6404 Value::String(Rc::new("RateLimiter".to_string())),
6405 );
6406 Ok(Value::Map(Rc::new(RefCell::new(map))))
6407 },
6408 );
6409
6410 define(interp, "RateLimiter·new", Some(0), |_, _| {
6411 let mut map = HashMap::new();
6412 map.insert(
6413 "__type__".to_string(),
6414 Value::String(Rc::new("RateLimiter".to_string())),
6415 );
6416 Ok(Value::Map(Rc::new(RefCell::new(map))))
6417 });
6418
6419 define(
6421 interp,
6422 "styx_http·middleware·RateLimit·new",
6423 None,
6424 |_, args| {
6425 let mut map = HashMap::new();
6426 map.insert(
6427 "__type__".to_string(),
6428 Value::String(Rc::new("RateLimit".to_string())),
6429 );
6430 if args.len() >= 2 {
6431 map.insert("rate".to_string(), args[0].clone());
6432 map.insert("burst".to_string(), args[1].clone());
6433 }
6434 Ok(Value::Map(Rc::new(RefCell::new(map))))
6435 },
6436 );
6437
6438 define(interp, "RateLimit·new", None, |_, args| {
6439 let mut map = HashMap::new();
6440 map.insert(
6441 "__type__".to_string(),
6442 Value::String(Rc::new("RateLimit".to_string())),
6443 );
6444 if args.len() >= 2 {
6445 map.insert("rate".to_string(), args[0].clone());
6446 map.insert("burst".to_string(), args[1].clone());
6447 }
6448 Ok(Value::Map(Rc::new(RefCell::new(map))))
6449 });
6450
6451 define(
6453 interp,
6454 "styx_http·middleware·Compression·new",
6455 Some(0),
6456 |_, _| {
6457 let mut map = HashMap::new();
6458 map.insert(
6459 "__type__".to_string(),
6460 Value::String(Rc::new("Compression".to_string())),
6461 );
6462 Ok(Value::Map(Rc::new(RefCell::new(map))))
6463 },
6464 );
6465
6466 define(interp, "Compression·new", Some(0), |_, _| {
6467 let mut map = HashMap::new();
6468 map.insert(
6469 "__type__".to_string(),
6470 Value::String(Rc::new("Compression".to_string())),
6471 );
6472 Ok(Value::Map(Rc::new(RefCell::new(map))))
6473 });
6474
6475 define(interp, "AuthMiddleware·optional", Some(0), |_, _| {
6477 let mut map = HashMap::new();
6478 map.insert(
6479 "__type__".to_string(),
6480 Value::String(Rc::new("AuthMiddleware".to_string())),
6481 );
6482 map.insert(
6483 "mode".to_string(),
6484 Value::String(Rc::new("optional".to_string())),
6485 );
6486 Ok(Value::Map(Rc::new(RefCell::new(map))))
6487 });
6488
6489 define(interp, "AuthMiddleware·required", Some(0), |_, _| {
6490 let mut map = HashMap::new();
6491 map.insert(
6492 "__type__".to_string(),
6493 Value::String(Rc::new("AuthMiddleware".to_string())),
6494 );
6495 map.insert(
6496 "mode".to_string(),
6497 Value::String(Rc::new("required".to_string())),
6498 );
6499 Ok(Value::Map(Rc::new(RefCell::new(map))))
6500 });
6501
6502 define(interp, "AuthMiddleware·new", Some(0), |_, _| {
6503 let mut map = HashMap::new();
6504 map.insert(
6505 "__type__".to_string(),
6506 Value::String(Rc::new("AuthMiddleware".to_string())),
6507 );
6508 map.insert(
6509 "mode".to_string(),
6510 Value::String(Rc::new("required".to_string())),
6511 );
6512 Ok(Value::Map(Rc::new(RefCell::new(map))))
6513 });
6514
6515 define(interp, "spawn_actor", Some(1), |_, args| {
6522 let name = match &args[0] {
6523 Value::String(s) => s.to_string(),
6524 _ => return Err(RuntimeError::new("actor_spawn() requires string name")),
6525 };
6526
6527 let inner = ActorInner {
6528 name,
6529 message_queue: Mutex::new(Vec::new()),
6530 message_count: std::sync::atomic::AtomicUsize::new(0),
6531 };
6532
6533 Ok(Value::Actor(Arc::new(inner)))
6534 });
6535
6536 define(interp, "send_to_actor", Some(3), |_, args| {
6539 let actor = match &args[0] {
6540 Value::Actor(a) => a.clone(),
6541 _ => {
6542 return Err(RuntimeError::new(
6543 "actor_send() requires actor as first argument",
6544 ))
6545 }
6546 };
6547 let msg_type = match &args[1] {
6548 Value::String(s) => s.to_string(),
6549 _ => {
6550 return Err(RuntimeError::new(
6551 "actor_send() requires string message type",
6552 ))
6553 }
6554 };
6555 let msg_data = format!("{}", args[2]);
6556
6557 let mut queue = actor
6558 .message_queue
6559 .lock()
6560 .map_err(|_| RuntimeError::new("actor queue poisoned"))?;
6561 queue.push((msg_type, msg_data));
6562 actor
6563 .message_count
6564 .fetch_add(1, std::sync::atomic::Ordering::SeqCst);
6565
6566 Ok(Value::Null)
6567 });
6568
6569 define(interp, "tell_actor", Some(3), |_, args| {
6571 let actor = match &args[0] {
6572 Value::Actor(a) => a.clone(),
6573 _ => {
6574 return Err(RuntimeError::new(
6575 "actor_tell() requires actor as first argument",
6576 ))
6577 }
6578 };
6579 let msg_type = match &args[1] {
6580 Value::String(s) => s.to_string(),
6581 _ => {
6582 return Err(RuntimeError::new(
6583 "actor_tell() requires string message type",
6584 ))
6585 }
6586 };
6587 let msg_data = format!("{}", args[2]);
6588
6589 let mut queue = actor
6590 .message_queue
6591 .lock()
6592 .map_err(|_| RuntimeError::new("actor queue poisoned"))?;
6593 queue.push((msg_type, msg_data));
6594 actor
6595 .message_count
6596 .fetch_add(1, std::sync::atomic::Ordering::SeqCst);
6597
6598 Ok(Value::Null)
6599 });
6600
6601 define(interp, "recv_from_actor", Some(1), |_, args| {
6604 let actor = match &args[0] {
6605 Value::Actor(a) => a.clone(),
6606 _ => return Err(RuntimeError::new("actor_recv() requires actor argument")),
6607 };
6608
6609 let mut queue = actor
6610 .message_queue
6611 .lock()
6612 .map_err(|_| RuntimeError::new("actor queue poisoned"))?;
6613 match queue.pop() {
6614 Some((msg_type, msg_data)) => {
6615 Ok(Value::Variant {
6617 enum_name: "Option".to_string(),
6618 variant_name: "Some".to_string(),
6619 fields: Some(Rc::new(vec![Value::Tuple(Rc::new(vec![
6620 Value::String(Rc::new(msg_type)),
6621 Value::String(Rc::new(msg_data)),
6622 ]))])),
6623 })
6624 }
6625 None => Ok(Value::Variant {
6626 enum_name: "Option".to_string(),
6627 variant_name: "None".to_string(),
6628 fields: None,
6629 }),
6630 }
6631 });
6632
6633 define(interp, "get_actor_msg_count", Some(1), |_, args| {
6635 let a = match &args[0] {
6636 Value::Actor(a) => a.clone(),
6637 _ => {
6638 return Err(RuntimeError::new(
6639 "get_actor_msg_count() requires actor argument",
6640 ))
6641 }
6642 };
6643
6644 let count = a.message_count.load(std::sync::atomic::Ordering::SeqCst);
6645 Ok(Value::Int(count as i64))
6646 });
6647
6648 define(interp, "get_actor_name", Some(1), |_, args| {
6650 let a = match &args[0] {
6651 Value::Actor(a) => a.clone(),
6652 _ => {
6653 return Err(RuntimeError::new(
6654 "get_actor_name() requires actor argument",
6655 ))
6656 }
6657 };
6658
6659 Ok(Value::String(Rc::new(a.name.clone())))
6660 });
6661
6662 define(interp, "get_actor_pending", Some(1), |_, args| {
6664 let a = match &args[0] {
6665 Value::Actor(a) => a.clone(),
6666 _ => {
6667 return Err(RuntimeError::new(
6668 "get_actor_pending() requires actor argument",
6669 ))
6670 }
6671 };
6672
6673 let queue = a
6674 .message_queue
6675 .lock()
6676 .map_err(|_| RuntimeError::new("actor queue poisoned"))?;
6677 Ok(Value::Int(queue.len() as i64))
6678 });
6679
6680 define(interp, "mutex_new", Some(1), |_, args| {
6684 let value = args[0].clone();
6685 let mut map = std::collections::HashMap::new();
6687 map.insert("__mutex_value".to_string(), value);
6688 map.insert("__mutex_locked".to_string(), Value::Bool(false));
6689 Ok(Value::Map(Rc::new(RefCell::new(map))))
6690 });
6691
6692 define(interp, "mutex_lock", Some(1), |_, args| {
6694 let mutex = match &args[0] {
6695 Value::Map(m) => m.clone(),
6696 _ => return Err(RuntimeError::new("mutex_lock() requires mutex")),
6697 };
6698
6699 let mut map = mutex.borrow_mut();
6700 map.insert("__mutex_locked".to_string(), Value::Bool(true));
6702
6703 match map.get("__mutex_value") {
6704 Some(v) => Ok(v.clone()),
6705 None => Err(RuntimeError::new("invalid mutex")),
6706 }
6707 });
6708
6709 define(interp, "mutex_unlock", Some(2), |_, args| {
6711 let mutex = match &args[0] {
6712 Value::Map(m) => m.clone(),
6713 _ => return Err(RuntimeError::new("mutex_unlock() requires mutex")),
6714 };
6715 let new_value = args[1].clone();
6716
6717 let mut map = mutex.borrow_mut();
6718 map.insert("__mutex_value".to_string(), new_value);
6719 map.insert("__mutex_locked".to_string(), Value::Bool(false));
6720
6721 Ok(Value::Null)
6722 });
6723
6724 define(interp, "atomic_new", Some(1), |_, args| {
6726 let value = match &args[0] {
6727 Value::Int(i) => *i,
6728 _ => return Err(RuntimeError::new("atomic_new() requires integer")),
6729 };
6730
6731 let mut map = std::collections::HashMap::new();
6733 map.insert("__atomic_value".to_string(), Value::Int(value));
6734 Ok(Value::Map(Rc::new(RefCell::new(map))))
6735 });
6736
6737 define(interp, "atomic_load", Some(1), |_, args| {
6739 let atomic = match &args[0] {
6740 Value::Map(m) => m.clone(),
6741 _ => return Err(RuntimeError::new("atomic_load() requires atomic")),
6742 };
6743
6744 let map = atomic.borrow();
6745 match map.get("__atomic_value") {
6746 Some(v) => Ok(v.clone()),
6747 None => Err(RuntimeError::new("invalid atomic")),
6748 }
6749 });
6750
6751 define(interp, "atomic_store", Some(2), |_, args| {
6753 let atomic = match &args[0] {
6754 Value::Map(m) => m.clone(),
6755 _ => return Err(RuntimeError::new("atomic_store() requires atomic")),
6756 };
6757 let value = match &args[1] {
6758 Value::Int(i) => *i,
6759 _ => return Err(RuntimeError::new("atomic_store() requires integer value")),
6760 };
6761
6762 let mut map = atomic.borrow_mut();
6763 map.insert("__atomic_value".to_string(), Value::Int(value));
6764 Ok(Value::Null)
6765 });
6766
6767 define(interp, "atomic_add", Some(2), |_, args| {
6769 let atomic = match &args[0] {
6770 Value::Map(m) => m.clone(),
6771 _ => return Err(RuntimeError::new("atomic_add() requires atomic")),
6772 };
6773 let delta = match &args[1] {
6774 Value::Int(i) => *i,
6775 _ => return Err(RuntimeError::new("atomic_add() requires integer delta")),
6776 };
6777
6778 let mut map = atomic.borrow_mut();
6779 let old = match map.get("__atomic_value") {
6780 Some(Value::Int(i)) => *i,
6781 _ => return Err(RuntimeError::new("invalid atomic")),
6782 };
6783 map.insert("__atomic_value".to_string(), Value::Int(old + delta));
6784 Ok(Value::Int(old))
6785 });
6786
6787 define(interp, "atomic_cas", Some(3), |_, args| {
6789 let atomic = match &args[0] {
6790 Value::Map(m) => m.clone(),
6791 _ => return Err(RuntimeError::new("atomic_cas() requires atomic")),
6792 };
6793 let expected = match &args[1] {
6794 Value::Int(i) => *i,
6795 _ => return Err(RuntimeError::new("atomic_cas() requires integer expected")),
6796 };
6797 let new_value = match &args[2] {
6798 Value::Int(i) => *i,
6799 _ => return Err(RuntimeError::new("atomic_cas() requires integer new value")),
6800 };
6801
6802 let mut map = atomic.borrow_mut();
6803 let current = match map.get("__atomic_value") {
6804 Some(Value::Int(i)) => *i,
6805 _ => return Err(RuntimeError::new("invalid atomic")),
6806 };
6807
6808 if current == expected {
6809 map.insert("__atomic_value".to_string(), Value::Int(new_value));
6810 Ok(Value::Bool(true))
6811 } else {
6812 Ok(Value::Bool(false))
6813 }
6814 });
6815
6816 define(interp, "parallel_map", Some(2), |_, args| {
6820 let arr = match &args[0] {
6821 Value::Array(a) => a.borrow().clone(),
6822 _ => return Err(RuntimeError::new("parallel_map() requires array")),
6823 };
6824 let _func = args[1].clone();
6825
6826 Ok(Value::Array(Rc::new(RefCell::new(arr))))
6829 });
6830
6831 define(interp, "parallel_for", Some(3), |_, args| {
6833 let start = match &args[0] {
6834 Value::Int(i) => *i,
6835 _ => return Err(RuntimeError::new("parallel_for() requires integer start")),
6836 };
6837 let end = match &args[1] {
6838 Value::Int(i) => *i,
6839 _ => return Err(RuntimeError::new("parallel_for() requires integer end")),
6840 };
6841 let _func = args[2].clone();
6842
6843 let range: Vec<Value> = (start..end).map(|i| Value::Int(i)).collect();
6846 Ok(Value::Array(Rc::new(RefCell::new(range))))
6847 });
6848
6849 define(interp, "async_sleep", Some(1), |interp, args| {
6867 let ms = match &args[0] {
6868 Value::Int(ms) => *ms as u64,
6869 Value::Float(ms) => *ms as u64,
6870 _ => {
6871 return Err(RuntimeError::new(
6872 "async_sleep() requires integer milliseconds",
6873 ))
6874 }
6875 };
6876
6877 Ok(interp.make_future_timer(std::time::Duration::from_millis(ms)))
6878 });
6879
6880 define(interp, "future_ready", Some(1), |interp, args| {
6882 Ok(interp.make_future_immediate(args[0].clone()))
6883 });
6884
6885 define(interp, "future_pending", Some(0), |_, _| {
6887 Ok(Value::Future(Rc::new(RefCell::new(
6888 crate::interpreter::FutureInner {
6889 state: crate::interpreter::FutureState::Pending,
6890 computation: None,
6891 complete_at: None,
6892 },
6893 ))))
6894 });
6895
6896 define(interp, "is_future", Some(1), |_, args| {
6898 Ok(Value::Bool(matches!(&args[0], Value::Future(_))))
6899 });
6900
6901 define(interp, "is_ready", Some(1), |_, args| {
6903 match &args[0] {
6904 Value::Future(fut) => {
6905 let f = fut.borrow();
6906 Ok(Value::Bool(matches!(
6907 f.state,
6908 crate::interpreter::FutureState::Ready(_)
6909 )))
6910 }
6911 _ => Ok(Value::Bool(true)), }
6913 });
6914
6915 define(interp, "join_futures", Some(1), |_, args| {
6917 let futures = match &args[0] {
6918 Value::Array(arr) => {
6919 let arr = arr.borrow();
6920 let mut futs = Vec::new();
6921 for v in arr.iter() {
6922 match v {
6923 Value::Future(f) => futs.push(f.clone()),
6924 _ => {
6925 return Err(RuntimeError::new(
6926 "join_futures() requires array of futures",
6927 ))
6928 }
6929 }
6930 }
6931 futs
6932 }
6933 _ => {
6934 return Err(RuntimeError::new(
6935 "join_futures() requires array of futures",
6936 ))
6937 }
6938 };
6939
6940 Ok(Value::Future(Rc::new(RefCell::new(
6941 crate::interpreter::FutureInner {
6942 state: crate::interpreter::FutureState::Pending,
6943 computation: Some(crate::interpreter::FutureComputation::Join(futures)),
6944 complete_at: None,
6945 },
6946 ))))
6947 });
6948
6949 define(interp, "race_futures", Some(1), |_, args| {
6951 let futures = match &args[0] {
6952 Value::Array(arr) => {
6953 let arr = arr.borrow();
6954 let mut futs = Vec::new();
6955 for v in arr.iter() {
6956 match v {
6957 Value::Future(f) => futs.push(f.clone()),
6958 _ => {
6959 return Err(RuntimeError::new(
6960 "race_futures() requires array of futures",
6961 ))
6962 }
6963 }
6964 }
6965 futs
6966 }
6967 _ => {
6968 return Err(RuntimeError::new(
6969 "race_futures() requires array of futures",
6970 ))
6971 }
6972 };
6973
6974 Ok(Value::Future(Rc::new(RefCell::new(
6975 crate::interpreter::FutureInner {
6976 state: crate::interpreter::FutureState::Pending,
6977 computation: Some(crate::interpreter::FutureComputation::Race(futures)),
6978 complete_at: None,
6979 },
6980 ))))
6981 });
6982
6983 define(interp, "poll_future", Some(1), |_, args| {
6985 match &args[0] {
6986 Value::Future(fut) => {
6987 let f = fut.borrow();
6988 match &f.state {
6989 crate::interpreter::FutureState::Ready(v) => Ok(Value::Variant {
6990 enum_name: "Option".to_string(),
6991 variant_name: "Some".to_string(),
6992 fields: Some(Rc::new(vec![(**v).clone()])),
6993 }),
6994 _ => Ok(Value::Variant {
6995 enum_name: "Option".to_string(),
6996 variant_name: "None".to_string(),
6997 fields: None,
6998 }),
6999 }
7000 }
7001 other => Ok(Value::Variant {
7003 enum_name: "Option".to_string(),
7004 variant_name: "Some".to_string(),
7005 fields: Some(Rc::new(vec![other.clone()])),
7006 }),
7007 }
7008 });
7009}
7010
7011fn register_json(interp: &mut Interpreter) {
7016 define(interp, "json_parse", Some(1), |_, args| {
7018 let json_str = match &args[0] {
7019 Value::String(s) => s.as_str(),
7020 _ => return Err(RuntimeError::new("json_parse() requires string argument")),
7021 };
7022
7023 fn json_to_value(json: &serde_json::Value) -> Value {
7024 match json {
7025 serde_json::Value::Null => Value::Null,
7026 serde_json::Value::Bool(b) => Value::Bool(*b),
7027 serde_json::Value::Number(n) => {
7028 if let Some(i) = n.as_i64() {
7029 Value::Int(i)
7030 } else if let Some(f) = n.as_f64() {
7031 Value::Float(f)
7032 } else {
7033 Value::Null
7034 }
7035 }
7036 serde_json::Value::String(s) => Value::String(Rc::new(s.clone())),
7037 serde_json::Value::Array(arr) => {
7038 let values: Vec<Value> = arr.iter().map(json_to_value).collect();
7039 Value::Array(Rc::new(RefCell::new(values)))
7040 }
7041 serde_json::Value::Object(obj) => {
7042 let mut map = HashMap::new();
7043 for (k, v) in obj {
7044 map.insert(k.clone(), json_to_value(v));
7045 }
7046 Value::Map(Rc::new(RefCell::new(map)))
7047 }
7048 }
7049 }
7050
7051 match serde_json::from_str(json_str) {
7052 Ok(json) => Ok(json_to_value(&json)),
7053 Err(e) => Err(RuntimeError::new(format!("JSON parse error: {}", e))),
7054 }
7055 });
7056
7057 define(interp, "json_stringify", Some(1), |_, args| {
7059 fn value_to_json(val: &Value) -> serde_json::Value {
7060 match val {
7061 Value::Null => serde_json::Value::Null,
7062 Value::Bool(b) => serde_json::Value::Bool(*b),
7063 Value::Int(n) => serde_json::Value::Number(serde_json::Number::from(*n)),
7064 Value::Float(f) => serde_json::Number::from_f64(*f)
7065 .map(serde_json::Value::Number)
7066 .unwrap_or(serde_json::Value::Null),
7067 Value::String(s) => serde_json::Value::String(s.to_string()),
7068 Value::Array(arr) => {
7069 let arr = arr.borrow();
7070 serde_json::Value::Array(arr.iter().map(value_to_json).collect())
7071 }
7072 Value::Tuple(t) => serde_json::Value::Array(t.iter().map(value_to_json).collect()),
7073 Value::Map(map) => {
7074 let map = map.borrow();
7075 let obj: serde_json::Map<String, serde_json::Value> = map
7076 .iter()
7077 .map(|(k, v)| (k.clone(), value_to_json(v)))
7078 .collect();
7079 serde_json::Value::Object(obj)
7080 }
7081 Value::Struct { fields, .. } => {
7082 let fields = fields.borrow();
7083 let obj: serde_json::Map<String, serde_json::Value> = fields
7084 .iter()
7085 .map(|(k, v)| (k.clone(), value_to_json(v)))
7086 .collect();
7087 serde_json::Value::Object(obj)
7088 }
7089 _ => serde_json::Value::String(format!("{}", val)),
7090 }
7091 }
7092
7093 let json = value_to_json(&args[0]);
7094 Ok(Value::String(Rc::new(json.to_string())))
7095 });
7096
7097 define(interp, "json_pretty", Some(1), |_, args| {
7099 fn value_to_json(val: &Value) -> serde_json::Value {
7100 match val {
7101 Value::Null => serde_json::Value::Null,
7102 Value::Bool(b) => serde_json::Value::Bool(*b),
7103 Value::Int(n) => serde_json::Value::Number(serde_json::Number::from(*n)),
7104 Value::Float(f) => serde_json::Number::from_f64(*f)
7105 .map(serde_json::Value::Number)
7106 .unwrap_or(serde_json::Value::Null),
7107 Value::String(s) => serde_json::Value::String(s.to_string()),
7108 Value::Array(arr) => {
7109 let arr = arr.borrow();
7110 serde_json::Value::Array(arr.iter().map(value_to_json).collect())
7111 }
7112 Value::Map(map) => {
7113 let map = map.borrow();
7114 let obj: serde_json::Map<String, serde_json::Value> = map
7115 .iter()
7116 .map(|(k, v)| (k.clone(), value_to_json(v)))
7117 .collect();
7118 serde_json::Value::Object(obj)
7119 }
7120 _ => serde_json::Value::String(format!("{}", val)),
7121 }
7122 }
7123
7124 let json = value_to_json(&args[0]);
7125 match serde_json::to_string_pretty(&json) {
7126 Ok(s) => Ok(Value::String(Rc::new(s))),
7127 Err(e) => Err(RuntimeError::new(format!("JSON stringify error: {}", e))),
7128 }
7129 });
7130
7131 define(interp, "json_get", Some(2), |_, args| {
7133 let path = match &args[1] {
7134 Value::String(s) => s.to_string(),
7135 _ => return Err(RuntimeError::new("json_get() requires string path")),
7136 };
7137
7138 let mut current = args[0].clone();
7139 for key in path.split('.') {
7140 current = match ¤t {
7141 Value::Map(map) => {
7142 let map = map.borrow();
7143 map.get(key).cloned().unwrap_or(Value::Null)
7144 }
7145 Value::Array(arr) => {
7146 if let Ok(idx) = key.parse::<usize>() {
7147 let arr = arr.borrow();
7148 arr.get(idx).cloned().unwrap_or(Value::Null)
7149 } else {
7150 Value::Null
7151 }
7152 }
7153 _ => Value::Null,
7154 };
7155 }
7156 Ok(current)
7157 });
7158
7159 define(interp, "json_set", Some(3), |_, args| {
7161 let path = match &args[1] {
7162 Value::String(s) => s.to_string(),
7163 _ => return Err(RuntimeError::new("json_set() requires string path")),
7164 };
7165 let new_value = args[2].clone();
7166
7167 match &args[0] {
7169 Value::Map(map) => {
7170 let mut map = map.borrow_mut();
7171 map.insert(path, new_value);
7172 Ok(Value::Map(Rc::new(RefCell::new(map.clone()))))
7173 }
7174 _ => Err(RuntimeError::new("json_set() requires map/object")),
7175 }
7176 });
7177}
7178
7179fn register_fs(interp: &mut Interpreter) {
7184 define(interp, "fs_read", Some(1), |_, args| {
7186 let path = match &args[0] {
7187 Value::String(s) => s.to_string(),
7188 _ => return Err(RuntimeError::new("fs_read() requires string path")),
7189 };
7190
7191 match std::fs::read_to_string(&path) {
7192 Ok(content) => Ok(Value::String(Rc::new(content))),
7193 Err(e) => Err(RuntimeError::new(format!("fs_read() error: {}", e))),
7194 }
7195 });
7196
7197 define(interp, "fs_read_bytes", Some(1), |_, args| {
7199 let path = match &args[0] {
7200 Value::String(s) => s.to_string(),
7201 _ => return Err(RuntimeError::new("fs_read_bytes() requires string path")),
7202 };
7203
7204 match std::fs::read(&path) {
7205 Ok(bytes) => {
7206 let values: Vec<Value> = bytes.iter().map(|b| Value::Int(*b as i64)).collect();
7207 Ok(Value::Array(Rc::new(RefCell::new(values))))
7208 }
7209 Err(e) => Err(RuntimeError::new(format!("fs_read_bytes() error: {}", e))),
7210 }
7211 });
7212
7213 define(interp, "fs_write", Some(2), |_, args| {
7215 let path = match &args[0] {
7216 Value::String(s) => s.to_string(),
7217 _ => return Err(RuntimeError::new("fs_write() requires string path")),
7218 };
7219 let content = format!("{}", args[1]);
7220
7221 match std::fs::write(&path, content) {
7222 Ok(()) => Ok(Value::Null),
7223 Err(e) => Err(RuntimeError::new(format!("fs_write() error: {}", e))),
7224 }
7225 });
7226
7227 define(interp, "fs_append", Some(2), |_, args| {
7229 let path = match &args[0] {
7230 Value::String(s) => s.to_string(),
7231 _ => return Err(RuntimeError::new("fs_append() requires string path")),
7232 };
7233 let content = format!("{}", args[1]);
7234
7235 use std::fs::OpenOptions;
7236 match OpenOptions::new().append(true).create(true).open(&path) {
7237 Ok(mut file) => {
7238 use std::io::Write;
7239 match file.write_all(content.as_bytes()) {
7240 Ok(()) => Ok(Value::Null),
7241 Err(e) => Err(RuntimeError::new(format!("fs_append() write error: {}", e))),
7242 }
7243 }
7244 Err(e) => Err(RuntimeError::new(format!("fs_append() error: {}", e))),
7245 }
7246 });
7247
7248 define(interp, "fs_exists", Some(1), |_, args| {
7250 let path = match &args[0] {
7251 Value::String(s) => s.to_string(),
7252 _ => return Err(RuntimeError::new("fs_exists() requires string path")),
7253 };
7254 Ok(Value::Bool(std::path::Path::new(&path).exists()))
7255 });
7256
7257 define(interp, "fs_is_file", Some(1), |_, args| {
7259 let path = match &args[0] {
7260 Value::String(s) => s.to_string(),
7261 _ => return Err(RuntimeError::new("fs_is_file() requires string path")),
7262 };
7263 Ok(Value::Bool(std::path::Path::new(&path).is_file()))
7264 });
7265
7266 define(interp, "fs_is_dir", Some(1), |_, args| {
7268 let path = match &args[0] {
7269 Value::String(s) => s.to_string(),
7270 _ => return Err(RuntimeError::new("fs_is_dir() requires string path")),
7271 };
7272 Ok(Value::Bool(std::path::Path::new(&path).is_dir()))
7273 });
7274
7275 define(interp, "fs_mkdir", Some(1), |_, args| {
7277 let path = match &args[0] {
7278 Value::String(s) => s.to_string(),
7279 _ => return Err(RuntimeError::new("fs_mkdir() requires string path")),
7280 };
7281
7282 match std::fs::create_dir_all(&path) {
7283 Ok(()) => Ok(Value::Null),
7284 Err(e) => Err(RuntimeError::new(format!("fs_mkdir() error: {}", e))),
7285 }
7286 });
7287
7288 define(interp, "fs_remove", Some(1), |_, args| {
7290 let path = match &args[0] {
7291 Value::String(s) => s.to_string(),
7292 _ => return Err(RuntimeError::new("fs_remove() requires string path")),
7293 };
7294
7295 let p = std::path::Path::new(&path);
7296 let result = if p.is_dir() {
7297 std::fs::remove_dir_all(&path)
7298 } else {
7299 std::fs::remove_file(&path)
7300 };
7301
7302 match result {
7303 Ok(()) => Ok(Value::Null),
7304 Err(e) => Err(RuntimeError::new(format!("fs_remove() error: {}", e))),
7305 }
7306 });
7307
7308 define(interp, "fs_list", Some(1), |_, args| {
7310 let path = match &args[0] {
7311 Value::String(s) => s.to_string(),
7312 _ => return Err(RuntimeError::new("fs_list() requires string path")),
7313 };
7314
7315 match std::fs::read_dir(&path) {
7316 Ok(entries) => {
7317 let mut files = Vec::new();
7318 for entry in entries.flatten() {
7319 if let Some(name) = entry.file_name().to_str() {
7320 files.push(Value::String(Rc::new(name.to_string())));
7321 }
7322 }
7323 Ok(Value::Array(Rc::new(RefCell::new(files))))
7324 }
7325 Err(e) => Err(RuntimeError::new(format!("fs_list() error: {}", e))),
7326 }
7327 });
7328
7329 define(interp, "fs_copy", Some(2), |_, args| {
7331 let src = match &args[0] {
7332 Value::String(s) => s.to_string(),
7333 _ => return Err(RuntimeError::new("fs_copy() requires string source path")),
7334 };
7335 let dst = match &args[1] {
7336 Value::String(s) => s.to_string(),
7337 _ => {
7338 return Err(RuntimeError::new(
7339 "fs_copy() requires string destination path",
7340 ))
7341 }
7342 };
7343
7344 match std::fs::copy(&src, &dst) {
7345 Ok(bytes) => Ok(Value::Int(bytes as i64)),
7346 Err(e) => Err(RuntimeError::new(format!("fs_copy() error: {}", e))),
7347 }
7348 });
7349
7350 define(interp, "fs_rename", Some(2), |_, args| {
7352 let src = match &args[0] {
7353 Value::String(s) => s.to_string(),
7354 _ => return Err(RuntimeError::new("fs_rename() requires string source path")),
7355 };
7356 let dst = match &args[1] {
7357 Value::String(s) => s.to_string(),
7358 _ => {
7359 return Err(RuntimeError::new(
7360 "fs_rename() requires string destination path",
7361 ))
7362 }
7363 };
7364
7365 match std::fs::rename(&src, &dst) {
7366 Ok(()) => Ok(Value::Null),
7367 Err(e) => Err(RuntimeError::new(format!("fs_rename() error: {}", e))),
7368 }
7369 });
7370
7371 define(interp, "fs_size", Some(1), |_, args| {
7373 let path = match &args[0] {
7374 Value::String(s) => s.to_string(),
7375 _ => return Err(RuntimeError::new("fs_size() requires string path")),
7376 };
7377
7378 match std::fs::metadata(&path) {
7379 Ok(meta) => Ok(Value::Int(meta.len() as i64)),
7380 Err(e) => Err(RuntimeError::new(format!("fs_size() error: {}", e))),
7381 }
7382 });
7383
7384 define(interp, "path_join", None, |_, args| {
7386 let mut path = std::path::PathBuf::new();
7387 for arg in &args {
7388 match arg {
7389 Value::String(s) => path.push(s.as_str()),
7390 Value::Array(arr) => {
7391 for v in arr.borrow().iter() {
7392 if let Value::String(s) = v {
7393 path.push(s.as_str());
7394 }
7395 }
7396 }
7397 _ => {}
7398 }
7399 }
7400 Ok(Value::String(Rc::new(path.to_string_lossy().to_string())))
7401 });
7402
7403 define(interp, "path_parent", Some(1), |_, args| {
7405 let path = match &args[0] {
7406 Value::String(s) => s.to_string(),
7407 _ => return Err(RuntimeError::new("path_parent() requires string path")),
7408 };
7409
7410 let p = std::path::Path::new(&path);
7411 match p.parent() {
7412 Some(parent) => Ok(Value::String(Rc::new(parent.to_string_lossy().to_string()))),
7413 None => Ok(Value::Null),
7414 }
7415 });
7416
7417 define(interp, "path_filename", Some(1), |_, args| {
7419 let path = match &args[0] {
7420 Value::String(s) => s.to_string(),
7421 _ => return Err(RuntimeError::new("path_filename() requires string path")),
7422 };
7423
7424 let p = std::path::Path::new(&path);
7425 match p.file_name() {
7426 Some(name) => Ok(Value::String(Rc::new(name.to_string_lossy().to_string()))),
7427 None => Ok(Value::Null),
7428 }
7429 });
7430
7431 define(interp, "path_extension", Some(1), |_, args| {
7433 let path = match &args[0] {
7434 Value::String(s) => s.to_string(),
7435 _ => return Err(RuntimeError::new("path_extension() requires string path")),
7436 };
7437
7438 let p = std::path::Path::new(&path);
7439 match p.extension() {
7440 Some(ext) => Ok(Value::String(Rc::new(ext.to_string_lossy().to_string()))),
7441 None => Ok(Value::Null),
7442 }
7443 });
7444
7445 use std::cell::RefCell;
7452 use std::collections::HashMap;
7453 thread_local! {
7454 static LAST_FILE_CONTENT: RefCell<String> = RefCell::new(String::new());
7455 static FAKE_PTR_MAP: RefCell<HashMap<i64, String>> = RefCell::new(HashMap::new());
7457 }
7458
7459 define(interp, "sigil_read_file", Some(2), |_, args| {
7463 let path = match &args[0] {
7465 Value::String(s) => s.to_string(),
7466 Value::Int(ptr_id) => {
7467 FAKE_PTR_MAP
7469 .with(|map| map.borrow().get(ptr_id).cloned())
7470 .ok_or_else(|| {
7471 RuntimeError::new(format!("sigil_read_file: invalid pointer {}", ptr_id))
7472 })?
7473 }
7474 _ => return Err(RuntimeError::new("sigil_read_file() requires string path")),
7475 };
7476
7477 match std::fs::read_to_string(&path) {
7478 Ok(content) => {
7479 LAST_FILE_CONTENT.with(|last| {
7481 *last.borrow_mut() = content.clone();
7482 });
7483 Ok(Value::String(Rc::new(content)))
7485 }
7486 Err(_) => Ok(Value::Null), }
7488 });
7489
7490 define(interp, "sigil_file_len", Some(0), |_, _| {
7492 LAST_FILE_CONTENT.with(|last| Ok(Value::Int(last.borrow().len() as i64)))
7493 });
7494
7495 define(interp, "sigil_write_file", Some(4), |_, args| {
7497 let path = match &args[0] {
7499 Value::String(s) => s.to_string(),
7500 _ => return Err(RuntimeError::new("sigil_write_file() requires string path")),
7501 };
7502 let content = match &args[2] {
7503 Value::String(s) => s.to_string(),
7504 _ => {
7505 return Err(RuntimeError::new(
7506 "sigil_write_file() requires string content",
7507 ))
7508 }
7509 };
7510
7511 match std::fs::write(&path, content) {
7512 Ok(()) => Ok(Value::Bool(true)),
7513 Err(_) => Ok(Value::Bool(false)),
7514 }
7515 });
7516
7517 define(interp, "write", Some(3), |_, args| {
7519 let fd = match &args[0] {
7520 Value::Int(n) => *n,
7521 _ => return Err(RuntimeError::new("write() requires int fd")),
7522 };
7523
7524 let content = match &args[1] {
7526 Value::String(s) => s.to_string(),
7527 Value::Int(ptr_id) => {
7528 FAKE_PTR_MAP
7530 .with(|map| map.borrow().get(ptr_id).cloned())
7531 .unwrap_or_else(|| format!("{}", ptr_id))
7532 }
7533 _ => format!("{}", args[1]),
7534 };
7535
7536 let len = match &args[2] {
7538 Value::Int(n) => *n as usize,
7539 _ => content.len(),
7540 };
7541
7542 let output = &content[..std::cmp::min(len, content.len())];
7543
7544 match fd {
7545 1 => {
7546 print!("{}", output);
7547 use std::io::Write;
7548 std::io::stdout().flush().ok();
7549 Ok(Value::Int(output.len() as i64))
7550 }
7551 2 => {
7552 eprint!("{}", output);
7553 use std::io::Write;
7554 std::io::stderr().flush().ok();
7555 Ok(Value::Int(output.len() as i64))
7556 }
7557 _ => Err(RuntimeError::new(format!("write() unsupported fd: {}", fd))),
7558 }
7559 });
7560
7561 define(interp, "PathBuf·from", Some(1), |_, args| {
7563 let path = match &args[0] {
7564 Value::String(s) => s.to_string(),
7565 Value::Ref(r) => {
7566 if let Value::String(s) = &*r.borrow() {
7567 s.to_string()
7568 } else {
7569 return Err(RuntimeError::new("PathBuf::from() requires string"));
7570 }
7571 }
7572 _ => return Err(RuntimeError::new("PathBuf::from() requires string")),
7573 };
7574 Ok(Value::String(Rc::new(path)))
7575 });
7576
7577 define(interp, "std·path·PathBuf·from", Some(1), |_, args| {
7579 let path = match &args[0] {
7580 Value::String(s) => s.to_string(),
7581 Value::Ref(r) => {
7582 if let Value::String(s) = &*r.borrow() {
7583 s.to_string()
7584 } else {
7585 return Err(RuntimeError::new("PathBuf::from() requires string"));
7586 }
7587 }
7588 _ => return Err(RuntimeError::new("PathBuf::from() requires string")),
7589 };
7590 Ok(Value::String(Rc::new(path)))
7591 });
7592
7593 define(interp, "Path·new", Some(1), |_, args| {
7595 let path = match &args[0] {
7596 Value::String(s) => s.to_string(),
7597 Value::Ref(r) => {
7598 if let Value::String(s) = &*r.borrow() {
7599 s.to_string()
7600 } else {
7601 return Err(RuntimeError::new("Path::new() requires string"));
7602 }
7603 }
7604 _ => return Err(RuntimeError::new("Path::new() requires string")),
7605 };
7606 Ok(Value::String(Rc::new(path)))
7607 });
7608
7609 define(interp, "std·path·Path·new", Some(1), |_, args| {
7611 let path = match &args[0] {
7612 Value::String(s) => s.to_string(),
7613 _ => return Err(RuntimeError::new("Path::new() requires string")),
7614 };
7615 Ok(Value::String(Rc::new(path)))
7616 });
7617
7618 define(interp, "std·fs·read_to_string", Some(1), |_, args| {
7620 let path = match &args[0] {
7621 Value::String(s) => s.to_string(),
7622 _ => return Err(RuntimeError::new("read_to_string() requires string path")),
7623 };
7624 match std::fs::read_to_string(&path) {
7625 Ok(content) => Ok(Value::String(Rc::new(content))),
7626 Err(e) => Err(RuntimeError::new(format!("read_to_string() error: {}", e))),
7627 }
7628 });
7629
7630 define(interp, "std·fs·write", Some(2), |_, args| {
7632 let path = match &args[0] {
7633 Value::String(s) => s.to_string(),
7634 _ => return Err(RuntimeError::new("fs::write() requires string path")),
7635 };
7636 let content = format!("{}", args[1]);
7637 match std::fs::write(&path, content) {
7638 Ok(()) => Ok(Value::Null),
7639 Err(e) => Err(RuntimeError::new(format!("fs::write() error: {}", e))),
7640 }
7641 });
7642
7643 define(interp, "std·fs·create_dir_all", Some(1), |_, args| {
7645 let path = match &args[0] {
7646 Value::String(s) => s.to_string(),
7647 _ => return Err(RuntimeError::new("create_dir_all() requires string path")),
7648 };
7649 match std::fs::create_dir_all(&path) {
7650 Ok(()) => Ok(Value::Null),
7651 Err(e) => Err(RuntimeError::new(format!("create_dir_all() error: {}", e))),
7652 }
7653 });
7654
7655 define(interp, "OpenOptions·new", Some(0), |_, _| {
7658 let mut opts = HashMap::new();
7659 opts.insert("read".to_string(), Value::Bool(false));
7660 opts.insert("write".to_string(), Value::Bool(false));
7661 opts.insert("append".to_string(), Value::Bool(false));
7662 opts.insert("truncate".to_string(), Value::Bool(false));
7663 opts.insert("create".to_string(), Value::Bool(false));
7664 opts.insert("create_new".to_string(), Value::Bool(false));
7665 opts.insert(
7666 "__type__".to_string(),
7667 Value::String(Rc::new("OpenOptions".to_string())),
7668 );
7669 Ok(Value::Map(Rc::new(RefCell::new(opts))))
7670 });
7671
7672 define(interp, "std·fs·OpenOptions·new", Some(0), |_, _| {
7674 let mut opts = HashMap::new();
7675 opts.insert("read".to_string(), Value::Bool(false));
7676 opts.insert("write".to_string(), Value::Bool(false));
7677 opts.insert("append".to_string(), Value::Bool(false));
7678 opts.insert("truncate".to_string(), Value::Bool(false));
7679 opts.insert("create".to_string(), Value::Bool(false));
7680 opts.insert("create_new".to_string(), Value::Bool(false));
7681 opts.insert(
7682 "__type__".to_string(),
7683 Value::String(Rc::new("OpenOptions".to_string())),
7684 );
7685 Ok(Value::Map(Rc::new(RefCell::new(opts))))
7686 });
7687
7688 define(interp, "File·create", Some(1), |_, args| {
7690 let path = match &args[0] {
7691 Value::String(s) => s.to_string(),
7692 _ => return Err(RuntimeError::new("File::create() requires string path")),
7693 };
7694 let mut handle = HashMap::new();
7696 handle.insert("path".to_string(), Value::String(Rc::new(path.clone())));
7697 handle.insert(
7698 "mode".to_string(),
7699 Value::String(Rc::new("write".to_string())),
7700 );
7701 handle.insert(
7702 "__type__".to_string(),
7703 Value::String(Rc::new("File".to_string())),
7704 );
7705 match std::fs::File::create(&path) {
7707 Ok(_) => Ok(Value::Map(Rc::new(RefCell::new(handle)))),
7708 Err(e) => Err(RuntimeError::new(format!("File::create() error: {}", e))),
7709 }
7710 });
7711
7712 define(interp, "std·fs·File·create", Some(1), |_, args| {
7714 let path = match &args[0] {
7715 Value::String(s) => s.to_string(),
7716 _ => return Err(RuntimeError::new("File::create() requires string path")),
7717 };
7718 let mut handle = HashMap::new();
7719 handle.insert("path".to_string(), Value::String(Rc::new(path.clone())));
7720 handle.insert(
7721 "mode".to_string(),
7722 Value::String(Rc::new("write".to_string())),
7723 );
7724 handle.insert(
7725 "__type__".to_string(),
7726 Value::String(Rc::new("File".to_string())),
7727 );
7728 match std::fs::File::create(&path) {
7729 Ok(_) => Ok(Value::Map(Rc::new(RefCell::new(handle)))),
7730 Err(e) => Err(RuntimeError::new(format!("File::create() error: {}", e))),
7731 }
7732 });
7733
7734 define(interp, "File·open", Some(1), |_, args| {
7736 let path = match &args[0] {
7737 Value::String(s) => s.to_string(),
7738 _ => return Err(RuntimeError::new("File::open() requires string path")),
7739 };
7740 let mut handle = HashMap::new();
7741 handle.insert("path".to_string(), Value::String(Rc::new(path.clone())));
7742 handle.insert(
7743 "mode".to_string(),
7744 Value::String(Rc::new("read".to_string())),
7745 );
7746 handle.insert(
7747 "__type__".to_string(),
7748 Value::String(Rc::new("File".to_string())),
7749 );
7750 match std::fs::File::open(&path) {
7751 Ok(_) => Ok(Value::Map(Rc::new(RefCell::new(handle)))),
7752 Err(e) => Err(RuntimeError::new(format!("File::open() error: {}", e))),
7753 }
7754 });
7755
7756 define(interp, "std·fs·File·open", Some(1), |_, args| {
7758 let path = match &args[0] {
7759 Value::String(s) => s.to_string(),
7760 _ => return Err(RuntimeError::new("File::open() requires string path")),
7761 };
7762 let mut handle = HashMap::new();
7763 handle.insert("path".to_string(), Value::String(Rc::new(path.clone())));
7764 handle.insert(
7765 "mode".to_string(),
7766 Value::String(Rc::new("read".to_string())),
7767 );
7768 handle.insert(
7769 "__type__".to_string(),
7770 Value::String(Rc::new("File".to_string())),
7771 );
7772 match std::fs::File::open(&path) {
7773 Ok(_) => Ok(Value::Map(Rc::new(RefCell::new(handle)))),
7774 Err(e) => Err(RuntimeError::new(format!("File::open() error: {}", e))),
7775 }
7776 });
7777
7778 define(interp, "BufWriter·new", Some(1), |_, args| {
7780 match &args[0] {
7783 Value::Map(file_map) => {
7784 let mut wrapper = HashMap::new();
7785 wrapper.insert("inner".to_string(), Value::Map(file_map.clone()));
7786 wrapper.insert(
7787 "buffer".to_string(),
7788 Value::Array(Rc::new(RefCell::new(Vec::new()))),
7789 );
7790 wrapper.insert(
7791 "__type__".to_string(),
7792 Value::String(Rc::new("BufWriter".to_string())),
7793 );
7794 Ok(Value::Map(Rc::new(RefCell::new(wrapper))))
7795 }
7796 _ => Err(RuntimeError::new("BufWriter::new requires a file handle")),
7797 }
7798 });
7799
7800 define(
7802 interp,
7803 "std·io·BufWriter·new",
7804 Some(1),
7805 |_, args| match &args[0] {
7806 Value::Map(file_map) => {
7807 let mut wrapper = HashMap::new();
7808 wrapper.insert("inner".to_string(), Value::Map(file_map.clone()));
7809 wrapper.insert(
7810 "buffer".to_string(),
7811 Value::Array(Rc::new(RefCell::new(Vec::new()))),
7812 );
7813 wrapper.insert(
7814 "__type__".to_string(),
7815 Value::String(Rc::new("BufWriter".to_string())),
7816 );
7817 Ok(Value::Map(Rc::new(RefCell::new(wrapper))))
7818 }
7819 _ => Err(RuntimeError::new("BufWriter::new requires a file handle")),
7820 },
7821 );
7822
7823 define(interp, "BufReader·new", Some(1), |_, args| {
7825 use std::io::BufReader as StdBufReader;
7826
7827 let get_map = |val: &Value| -> Option<Rc<RefCell<HashMap<String, Value>>>> {
7829 match val {
7830 Value::Map(m) => Some(m.clone()),
7831 Value::Ref(r) => {
7832 let inner = r.borrow();
7833 if let Value::Map(m) = &*inner {
7834 Some(m.clone())
7835 } else {
7836 None
7837 }
7838 }
7839 _ => None,
7840 }
7841 };
7842
7843 if let Some(file_map) = get_map(&args[0]) {
7844 let borrowed = file_map.borrow();
7845 let mut wrapper = HashMap::new();
7846
7847 if let Some(Value::String(t)) = borrowed.get("__type__") {
7849 if t.as_str() == "TcpStream" {
7850 if let Some(Value::Int(stream_id)) = borrowed.get("__stream_id__") {
7851 let stream_id_val = *stream_id as u64;
7852 drop(borrowed);
7853
7854 if let Some(mut guard) = get_stream_registry().lock().ok() {
7856 if let Some(stream) = guard.get_mut(&stream_id_val) {
7857 let stream_clone = match stream.try_clone() {
7858 Ok(s) => s,
7859 Err(e) => {
7860 return Err(RuntimeError::new(format!(
7861 "Failed to clone stream: {}",
7862 e
7863 )))
7864 }
7865 };
7866 let reader = StdBufReader::new(stream_clone);
7867 let reader_id = store_bufreader(reader);
7868
7869 wrapper.insert(
7870 "__type__".to_string(),
7871 Value::String(Rc::new("BufReader".to_string())),
7872 );
7873 wrapper.insert(
7874 "__stream_id__".to_string(),
7875 Value::Int(stream_id_val as i64),
7876 );
7877 wrapper.insert(
7878 "__reader_id__".to_string(),
7879 Value::Int(reader_id as i64),
7880 );
7881 return Ok(Value::Map(Rc::new(RefCell::new(wrapper))));
7882 }
7883 }
7884 return Err(RuntimeError::new("TcpStream not found in registry"));
7885 }
7886 }
7887 }
7888
7889 drop(borrowed);
7891 wrapper.insert("inner".to_string(), Value::Map(file_map.clone()));
7892 wrapper.insert(
7893 "__type__".to_string(),
7894 Value::String(Rc::new("BufReader".to_string())),
7895 );
7896 Ok(Value::Map(Rc::new(RefCell::new(wrapper))))
7897 } else {
7898 Err(RuntimeError::new(
7899 "BufReader::new requires a file handle or TcpStream",
7900 ))
7901 }
7902 });
7903
7904 define(interp, "std·io·BufReader·new", Some(1), |_, args| {
7906 let get_map = |val: &Value| -> Option<Rc<RefCell<HashMap<String, Value>>>> {
7908 match val {
7909 Value::Map(m) => Some(m.clone()),
7910 Value::Ref(r) => {
7911 let inner = r.borrow();
7912 if let Value::Map(m) = &*inner {
7913 Some(m.clone())
7914 } else {
7915 None
7916 }
7917 }
7918 _ => None,
7919 }
7920 };
7921
7922 if let Some(file_map) = get_map(&args[0]) {
7923 let borrowed = file_map.borrow();
7924 let mut wrapper = HashMap::new();
7925
7926 if let Some(Value::String(t)) = borrowed.get("__type__") {
7928 if t.as_str() == "TcpStream" {
7929 if let Some(Value::Int(stream_id)) = borrowed.get("__stream_id__") {
7930 wrapper.insert("__stream_id__".to_string(), Value::Int(*stream_id));
7931 }
7932 }
7933 }
7934
7935 drop(borrowed);
7936 wrapper.insert("inner".to_string(), Value::Map(file_map.clone()));
7937 wrapper.insert(
7938 "__type__".to_string(),
7939 Value::String(Rc::new("BufReader".to_string())),
7940 );
7941 Ok(Value::Map(Rc::new(RefCell::new(wrapper))))
7942 } else {
7943 Err(RuntimeError::new(
7944 "BufReader::new requires a file handle or TcpStream",
7945 ))
7946 }
7947 });
7948
7949 define(
7951 interp,
7952 "dirs_next·config_dir",
7953 Some(0),
7954 |_, _| match dirs::config_dir() {
7955 Some(path) => Ok(Value::String(Rc::new(path.to_string_lossy().to_string()))),
7956 None => Ok(Value::Null),
7957 },
7958 );
7959
7960 define(
7962 interp,
7963 "dirs_next·data_dir",
7964 Some(0),
7965 |_, _| match dirs::data_dir() {
7966 Some(path) => Ok(Value::String(Rc::new(path.to_string_lossy().to_string()))),
7967 None => Ok(Value::Null),
7968 },
7969 );
7970
7971 define(
7973 interp,
7974 "dirs_next·home_dir",
7975 Some(0),
7976 |_, _| match dirs::home_dir() {
7977 Some(path) => Ok(Value::String(Rc::new(path.to_string_lossy().to_string()))),
7978 None => Ok(Value::Null),
7979 },
7980 );
7981}
7982
7983fn register_crypto(interp: &mut Interpreter) {
8015 fn extract_bytes(v: &Value, fn_name: &str) -> Result<Vec<u8>, RuntimeError> {
8017 match v {
8018 Value::String(s) => Ok(s.as_bytes().to_vec()),
8019 Value::Array(arr) => {
8020 let arr = arr.borrow();
8021 Ok(arr
8022 .iter()
8023 .filter_map(|v| {
8024 if let Value::Int(n) = v {
8025 Some(*n as u8)
8026 } else {
8027 None
8028 }
8029 })
8030 .collect())
8031 }
8032 _ => Err(RuntimeError::new(format!(
8033 "{}() requires string or byte array",
8034 fn_name
8035 ))),
8036 }
8037 }
8038
8039 fn bytes_to_array(bytes: &[u8]) -> Value {
8040 let values: Vec<Value> = bytes.iter().map(|b| Value::Int(*b as i64)).collect();
8041 Value::Array(Rc::new(RefCell::new(values)))
8042 }
8043
8044 define(interp, "sha256", Some(1), |_, args| {
8050 let data = extract_bytes(&args[0], "sha256")?;
8051 let mut hasher = Sha256::new();
8052 hasher.update(&data);
8053 let result = hasher.finalize();
8054 Ok(Value::String(Rc::new(
8055 result.iter().map(|b| format!("{:02x}", b)).collect(),
8056 )))
8057 });
8058
8059 define(interp, "sha512", Some(1), |_, args| {
8061 let data = extract_bytes(&args[0], "sha512")?;
8062 let mut hasher = Sha512::new();
8063 hasher.update(&data);
8064 let result = hasher.finalize();
8065 Ok(Value::String(Rc::new(
8066 result.iter().map(|b| format!("{:02x}", b)).collect(),
8067 )))
8068 });
8069
8070 define(interp, "sha3_256", Some(1), |_, args| {
8072 use sha3::{Digest as Sha3Digest, Sha3_256};
8073 let data = extract_bytes(&args[0], "sha3_256")?;
8074 let mut hasher = Sha3_256::new();
8075 hasher.update(&data);
8076 let result = hasher.finalize();
8077 Ok(Value::String(Rc::new(
8078 result.iter().map(|b| format!("{:02x}", b)).collect(),
8079 )))
8080 });
8081
8082 define(interp, "sha3_512", Some(1), |_, args| {
8084 use sha3::{Digest as Sha3Digest, Sha3_512};
8085 let data = extract_bytes(&args[0], "sha3_512")?;
8086 let mut hasher = Sha3_512::new();
8087 hasher.update(&data);
8088 let result = hasher.finalize();
8089 Ok(Value::String(Rc::new(
8090 result.iter().map(|b| format!("{:02x}", b)).collect(),
8091 )))
8092 });
8093
8094 define(interp, "blake3", Some(1), |_, args| {
8096 let data = extract_bytes(&args[0], "blake3")?;
8097 let hash = blake3::hash(&data);
8098 Ok(Value::String(Rc::new(hash.to_hex().to_string())))
8099 });
8100
8101 define(interp, "blake3_keyed", Some(2), |_, args| {
8103 let key = extract_bytes(&args[0], "blake3_keyed")?;
8104 let data = extract_bytes(&args[1], "blake3_keyed")?;
8105 if key.len() != 32 {
8106 return Err(RuntimeError::new("blake3_keyed() requires 32-byte key"));
8107 }
8108 let mut key_arr = [0u8; 32];
8109 key_arr.copy_from_slice(&key);
8110 let hash = blake3::keyed_hash(&key_arr, &data);
8111 Ok(Value::String(Rc::new(hash.to_hex().to_string())))
8112 });
8113
8114 define(interp, "md5", Some(1), |_, args| {
8116 let data = extract_bytes(&args[0], "md5")?;
8117 let mut hasher = Md5::new();
8118 hasher.update(&data);
8119 let result = hasher.finalize();
8120 Ok(Value::String(Rc::new(
8121 result.iter().map(|b| format!("{:02x}", b)).collect(),
8122 )))
8123 });
8124
8125 define(interp, "aes_gcm_encrypt", Some(2), |_, args| {
8131 use aes_gcm::{aead::Aead, Aes256Gcm, KeyInit, Nonce};
8132 use rand::RngCore;
8133
8134 let key = extract_bytes(&args[0], "aes_gcm_encrypt")?;
8135 let plaintext = extract_bytes(&args[1], "aes_gcm_encrypt")?;
8136
8137 if key.len() != 32 {
8138 return Err(RuntimeError::new("aes_gcm_encrypt() requires 32-byte key"));
8139 }
8140
8141 let cipher = Aes256Gcm::new_from_slice(&key)
8142 .map_err(|e| RuntimeError::new(format!("AES key error: {}", e)))?;
8143
8144 let mut nonce_bytes = [0u8; 12];
8145 rand::thread_rng().fill_bytes(&mut nonce_bytes);
8146 let nonce = Nonce::from_slice(&nonce_bytes);
8147
8148 let ciphertext = cipher
8149 .encrypt(nonce, plaintext.as_ref())
8150 .map_err(|e| RuntimeError::new(format!("AES encryption error: {}", e)))?;
8151
8152 let mut result = HashMap::new();
8153 result.insert("ciphertext".to_string(), bytes_to_array(&ciphertext));
8154 result.insert("nonce".to_string(), bytes_to_array(&nonce_bytes));
8155 Ok(Value::Map(Rc::new(RefCell::new(result))))
8156 });
8157
8158 define(interp, "aes_gcm_decrypt", Some(3), |_, args| {
8160 use aes_gcm::{aead::Aead, Aes256Gcm, KeyInit, Nonce};
8161
8162 let key = extract_bytes(&args[0], "aes_gcm_decrypt")?;
8163 let ciphertext = extract_bytes(&args[1], "aes_gcm_decrypt")?;
8164 let nonce_bytes = extract_bytes(&args[2], "aes_gcm_decrypt")?;
8165
8166 if key.len() != 32 {
8167 return Err(RuntimeError::new("aes_gcm_decrypt() requires 32-byte key"));
8168 }
8169 if nonce_bytes.len() != 12 {
8170 return Err(RuntimeError::new(
8171 "aes_gcm_decrypt() requires 12-byte nonce",
8172 ));
8173 }
8174
8175 let cipher = Aes256Gcm::new_from_slice(&key)
8176 .map_err(|e| RuntimeError::new(format!("AES key error: {}", e)))?;
8177 let nonce = Nonce::from_slice(&nonce_bytes);
8178
8179 let plaintext = cipher
8180 .decrypt(nonce, ciphertext.as_ref())
8181 .map_err(|_| RuntimeError::new("AES-GCM decryption failed: authentication error"))?;
8182
8183 match String::from_utf8(plaintext.clone()) {
8184 Ok(s) => Ok(Value::String(Rc::new(s))),
8185 Err(_) => Ok(bytes_to_array(&plaintext)),
8186 }
8187 });
8188
8189 define(interp, "chacha20_encrypt", Some(2), |_, args| {
8191 use chacha20poly1305::{aead::Aead, ChaCha20Poly1305, KeyInit, Nonce};
8192 use rand::RngCore;
8193
8194 let key = extract_bytes(&args[0], "chacha20_encrypt")?;
8195 let plaintext = extract_bytes(&args[1], "chacha20_encrypt")?;
8196
8197 if key.len() != 32 {
8198 return Err(RuntimeError::new("chacha20_encrypt() requires 32-byte key"));
8199 }
8200
8201 let cipher = ChaCha20Poly1305::new_from_slice(&key)
8202 .map_err(|e| RuntimeError::new(format!("ChaCha20 key error: {}", e)))?;
8203
8204 let mut nonce_bytes = [0u8; 12];
8205 rand::thread_rng().fill_bytes(&mut nonce_bytes);
8206 let nonce = Nonce::from_slice(&nonce_bytes);
8207
8208 let ciphertext = cipher
8209 .encrypt(nonce, plaintext.as_ref())
8210 .map_err(|e| RuntimeError::new(format!("ChaCha20 encryption error: {}", e)))?;
8211
8212 let mut result = HashMap::new();
8213 result.insert("ciphertext".to_string(), bytes_to_array(&ciphertext));
8214 result.insert("nonce".to_string(), bytes_to_array(&nonce_bytes));
8215 Ok(Value::Map(Rc::new(RefCell::new(result))))
8216 });
8217
8218 define(interp, "chacha20_decrypt", Some(3), |_, args| {
8220 use chacha20poly1305::{aead::Aead, ChaCha20Poly1305, KeyInit, Nonce};
8221
8222 let key = extract_bytes(&args[0], "chacha20_decrypt")?;
8223 let ciphertext = extract_bytes(&args[1], "chacha20_decrypt")?;
8224 let nonce_bytes = extract_bytes(&args[2], "chacha20_decrypt")?;
8225
8226 if key.len() != 32 {
8227 return Err(RuntimeError::new("chacha20_decrypt() requires 32-byte key"));
8228 }
8229 if nonce_bytes.len() != 12 {
8230 return Err(RuntimeError::new(
8231 "chacha20_decrypt() requires 12-byte nonce",
8232 ));
8233 }
8234
8235 let cipher = ChaCha20Poly1305::new_from_slice(&key)
8236 .map_err(|e| RuntimeError::new(format!("ChaCha20 key error: {}", e)))?;
8237 let nonce = Nonce::from_slice(&nonce_bytes);
8238
8239 let plaintext = cipher
8240 .decrypt(nonce, ciphertext.as_ref())
8241 .map_err(|_| RuntimeError::new("ChaCha20 decryption failed: authentication error"))?;
8242
8243 match String::from_utf8(plaintext.clone()) {
8244 Ok(s) => Ok(Value::String(Rc::new(s))),
8245 Err(_) => Ok(bytes_to_array(&plaintext)),
8246 }
8247 });
8248
8249 define(interp, "ed25519_keygen", Some(0), |_, _| {
8255 use ed25519_dalek::SigningKey;
8256 use rand::rngs::OsRng;
8257
8258 let signing_key = SigningKey::generate(&mut OsRng);
8259 let verifying_key = signing_key.verifying_key();
8260
8261 let mut result = HashMap::new();
8262 result.insert(
8263 "private_key".to_string(),
8264 Value::String(Rc::new(
8265 signing_key
8266 .to_bytes()
8267 .iter()
8268 .map(|b| format!("{:02x}", b))
8269 .collect(),
8270 )),
8271 );
8272 result.insert(
8273 "public_key".to_string(),
8274 Value::String(Rc::new(
8275 verifying_key
8276 .to_bytes()
8277 .iter()
8278 .map(|b| format!("{:02x}", b))
8279 .collect(),
8280 )),
8281 );
8282 Ok(Value::Map(Rc::new(RefCell::new(result))))
8283 });
8284
8285 define(interp, "ed25519_sign", Some(2), |_, args| {
8287 use ed25519_dalek::{Signer, SigningKey};
8288
8289 let private_key_hex = match &args[0] {
8290 Value::String(s) => s.to_string(),
8291 _ => return Err(RuntimeError::new("ed25519_sign() requires hex private key")),
8292 };
8293 let message = extract_bytes(&args[1], "ed25519_sign")?;
8294
8295 let key_bytes: Vec<u8> = (0..private_key_hex.len())
8296 .step_by(2)
8297 .map(|i| u8::from_str_radix(&private_key_hex[i..i + 2], 16))
8298 .collect::<Result<Vec<_>, _>>()
8299 .map_err(|_| RuntimeError::new("Invalid private key hex"))?;
8300
8301 if key_bytes.len() != 32 {
8302 return Err(RuntimeError::new(
8303 "ed25519_sign() requires 32-byte private key",
8304 ));
8305 }
8306
8307 let mut key_arr = [0u8; 32];
8308 key_arr.copy_from_slice(&key_bytes);
8309 let signing_key = SigningKey::from_bytes(&key_arr);
8310 let signature = signing_key.sign(&message);
8311
8312 Ok(Value::String(Rc::new(
8313 signature
8314 .to_bytes()
8315 .iter()
8316 .map(|b| format!("{:02x}", b))
8317 .collect(),
8318 )))
8319 });
8320
8321 define(interp, "ed25519_verify", Some(3), |_, args| {
8323 use ed25519_dalek::{Signature, Verifier, VerifyingKey};
8324
8325 let public_key_hex = match &args[0] {
8326 Value::String(s) => s.to_string(),
8327 _ => {
8328 return Err(RuntimeError::new(
8329 "ed25519_verify() requires hex public key",
8330 ))
8331 }
8332 };
8333 let message = extract_bytes(&args[1], "ed25519_verify")?;
8334 let signature_hex = match &args[2] {
8335 Value::String(s) => s.to_string(),
8336 _ => return Err(RuntimeError::new("ed25519_verify() requires hex signature")),
8337 };
8338
8339 let key_bytes: Vec<u8> = (0..public_key_hex.len())
8340 .step_by(2)
8341 .map(|i| u8::from_str_radix(&public_key_hex[i..i + 2], 16))
8342 .collect::<Result<Vec<_>, _>>()
8343 .map_err(|_| RuntimeError::new("Invalid public key hex"))?;
8344 let sig_bytes: Vec<u8> = (0..signature_hex.len())
8345 .step_by(2)
8346 .map(|i| u8::from_str_radix(&signature_hex[i..i + 2], 16))
8347 .collect::<Result<Vec<_>, _>>()
8348 .map_err(|_| RuntimeError::new("Invalid signature hex"))?;
8349
8350 if key_bytes.len() != 32 {
8351 return Err(RuntimeError::new(
8352 "ed25519_verify() requires 32-byte public key",
8353 ));
8354 }
8355 if sig_bytes.len() != 64 {
8356 return Err(RuntimeError::new(
8357 "ed25519_verify() requires 64-byte signature",
8358 ));
8359 }
8360
8361 let mut key_arr = [0u8; 32];
8362 key_arr.copy_from_slice(&key_bytes);
8363 let mut sig_arr = [0u8; 64];
8364 sig_arr.copy_from_slice(&sig_bytes);
8365
8366 let verifying_key = VerifyingKey::from_bytes(&key_arr)
8367 .map_err(|e| RuntimeError::new(format!("Invalid public key: {}", e)))?;
8368 let signature = Signature::from_bytes(&sig_arr);
8369
8370 match verifying_key.verify(&message, &signature) {
8371 Ok(_) => Ok(Value::Bool(true)),
8372 Err(_) => Ok(Value::Bool(false)),
8373 }
8374 });
8375
8376 define(interp, "x25519_keygen", Some(0), |_, _| {
8378 use rand::rngs::OsRng;
8379 use x25519_dalek::{PublicKey, StaticSecret};
8380
8381 let secret = StaticSecret::random_from_rng(OsRng);
8382 let public = PublicKey::from(&secret);
8383
8384 let mut result = HashMap::new();
8385 result.insert(
8386 "private_key".to_string(),
8387 Value::String(Rc::new(
8388 secret
8389 .as_bytes()
8390 .iter()
8391 .map(|b| format!("{:02x}", b))
8392 .collect(),
8393 )),
8394 );
8395 result.insert(
8396 "public_key".to_string(),
8397 Value::String(Rc::new(
8398 public
8399 .as_bytes()
8400 .iter()
8401 .map(|b| format!("{:02x}", b))
8402 .collect(),
8403 )),
8404 );
8405 Ok(Value::Map(Rc::new(RefCell::new(result))))
8406 });
8407
8408 define(interp, "x25519_exchange", Some(2), |_, args| {
8410 use x25519_dalek::{PublicKey, StaticSecret};
8411
8412 let my_private_hex = match &args[0] {
8413 Value::String(s) => s.to_string(),
8414 _ => {
8415 return Err(RuntimeError::new(
8416 "x25519_exchange() requires hex private key",
8417 ))
8418 }
8419 };
8420 let their_public_hex = match &args[1] {
8421 Value::String(s) => s.to_string(),
8422 _ => {
8423 return Err(RuntimeError::new(
8424 "x25519_exchange() requires hex public key",
8425 ))
8426 }
8427 };
8428
8429 let my_private_bytes: Vec<u8> = (0..my_private_hex.len())
8430 .step_by(2)
8431 .map(|i| u8::from_str_radix(&my_private_hex[i..i + 2], 16))
8432 .collect::<Result<Vec<_>, _>>()
8433 .map_err(|_| RuntimeError::new("Invalid private key hex"))?;
8434 let their_public_bytes: Vec<u8> = (0..their_public_hex.len())
8435 .step_by(2)
8436 .map(|i| u8::from_str_radix(&their_public_hex[i..i + 2], 16))
8437 .collect::<Result<Vec<_>, _>>()
8438 .map_err(|_| RuntimeError::new("Invalid public key hex"))?;
8439
8440 if my_private_bytes.len() != 32 || their_public_bytes.len() != 32 {
8441 return Err(RuntimeError::new("x25519_exchange() requires 32-byte keys"));
8442 }
8443
8444 let mut priv_arr = [0u8; 32];
8445 priv_arr.copy_from_slice(&my_private_bytes);
8446 let mut pub_arr = [0u8; 32];
8447 pub_arr.copy_from_slice(&their_public_bytes);
8448
8449 let my_secret = StaticSecret::from(priv_arr);
8450 let their_public = PublicKey::from(pub_arr);
8451 let shared_secret = my_secret.diffie_hellman(&their_public);
8452
8453 Ok(Value::String(Rc::new(
8454 shared_secret
8455 .as_bytes()
8456 .iter()
8457 .map(|b| format!("{:02x}", b))
8458 .collect(),
8459 )))
8460 });
8461
8462 define(interp, "argon2_hash", Some(1), |_, args| {
8468 use argon2::{
8469 password_hash::{PasswordHasher, SaltString},
8470 Argon2,
8471 };
8472 use rand::rngs::OsRng;
8473
8474 let password = extract_bytes(&args[0], "argon2_hash")?;
8475 let salt = SaltString::generate(&mut OsRng);
8476 let argon2 = Argon2::default();
8477
8478 let hash = argon2
8479 .hash_password(&password, &salt)
8480 .map_err(|e| RuntimeError::new(format!("Argon2 error: {}", e)))?;
8481
8482 let mut result = HashMap::new();
8483 result.insert("hash".to_string(), Value::String(Rc::new(hash.to_string())));
8484 result.insert("salt".to_string(), Value::String(Rc::new(salt.to_string())));
8485 Ok(Value::Map(Rc::new(RefCell::new(result))))
8486 });
8487
8488 define(interp, "argon2_verify", Some(2), |_, args| {
8490 use argon2::{Argon2, PasswordHash, PasswordVerifier};
8491
8492 let password = extract_bytes(&args[0], "argon2_verify")?;
8493 let hash_str = match &args[1] {
8494 Value::String(s) => s.to_string(),
8495 _ => return Err(RuntimeError::new("argon2_verify() requires hash string")),
8496 };
8497
8498 let parsed_hash = PasswordHash::new(&hash_str)
8499 .map_err(|e| RuntimeError::new(format!("Invalid hash: {}", e)))?;
8500
8501 match Argon2::default().verify_password(&password, &parsed_hash) {
8502 Ok(_) => Ok(Value::Bool(true)),
8503 Err(_) => Ok(Value::Bool(false)),
8504 }
8505 });
8506
8507 define(interp, "hkdf_expand", Some(3), |_, args| {
8509 use hkdf::Hkdf;
8510
8511 let ikm = extract_bytes(&args[0], "hkdf_expand")?;
8512 let salt = extract_bytes(&args[1], "hkdf_expand")?;
8513 let info = extract_bytes(&args[2], "hkdf_expand")?;
8514
8515 let hk = Hkdf::<Sha256>::new(Some(&salt), &ikm);
8516 let mut okm = [0u8; 32];
8517 hk.expand(&info, &mut okm)
8518 .map_err(|e| RuntimeError::new(format!("HKDF error: {}", e)))?;
8519
8520 Ok(Value::String(Rc::new(
8521 okm.iter().map(|b| format!("{:02x}", b)).collect(),
8522 )))
8523 });
8524
8525 define(interp, "pbkdf2_derive", Some(3), |_, args| {
8527 let password = extract_bytes(&args[0], "pbkdf2_derive")?;
8528 let salt = extract_bytes(&args[1], "pbkdf2_derive")?;
8529 let iterations = match &args[2] {
8530 Value::Int(n) => *n as u32,
8531 _ => {
8532 return Err(RuntimeError::new(
8533 "pbkdf2_derive() requires integer iterations",
8534 ))
8535 }
8536 };
8537
8538 let mut key = [0u8; 32];
8539 pbkdf2::pbkdf2_hmac::<Sha256>(&password, &salt, iterations, &mut key);
8540 Ok(Value::String(Rc::new(
8541 key.iter().map(|b| format!("{:02x}", b)).collect(),
8542 )))
8543 });
8544
8545 define(interp, "hmac_sha256", Some(2), |_, args| {
8551 use hmac::{Hmac, Mac};
8552 type HmacSha256 = Hmac<Sha256>;
8553
8554 let key = extract_bytes(&args[0], "hmac_sha256")?;
8555 let message = extract_bytes(&args[1], "hmac_sha256")?;
8556
8557 let mut mac = HmacSha256::new_from_slice(&key)
8558 .map_err(|e| RuntimeError::new(format!("HMAC key error: {}", e)))?;
8559 mac.update(&message);
8560 let result = mac.finalize();
8561 Ok(Value::String(Rc::new(
8562 result
8563 .into_bytes()
8564 .iter()
8565 .map(|b| format!("{:02x}", b))
8566 .collect(),
8567 )))
8568 });
8569
8570 define(interp, "hmac_sha512", Some(2), |_, args| {
8572 use hmac::{Hmac, Mac};
8573 type HmacSha512 = Hmac<Sha512>;
8574
8575 let key = extract_bytes(&args[0], "hmac_sha512")?;
8576 let message = extract_bytes(&args[1], "hmac_sha512")?;
8577
8578 let mut mac = HmacSha512::new_from_slice(&key)
8579 .map_err(|e| RuntimeError::new(format!("HMAC key error: {}", e)))?;
8580 mac.update(&message);
8581 let result = mac.finalize();
8582 Ok(Value::String(Rc::new(
8583 result
8584 .into_bytes()
8585 .iter()
8586 .map(|b| format!("{:02x}", b))
8587 .collect(),
8588 )))
8589 });
8590
8591 define(interp, "hmac_verify", Some(3), |_, args| {
8593 use hmac::{Hmac, Mac};
8594 type HmacSha256 = Hmac<Sha256>;
8595
8596 let key = extract_bytes(&args[0], "hmac_verify")?;
8597 let message = extract_bytes(&args[1], "hmac_verify")?;
8598 let expected_hex = match &args[2] {
8599 Value::String(s) => s.to_string(),
8600 _ => return Err(RuntimeError::new("hmac_verify() requires hex MAC")),
8601 };
8602
8603 let expected: Vec<u8> = (0..expected_hex.len())
8604 .step_by(2)
8605 .map(|i| u8::from_str_radix(&expected_hex[i..i + 2], 16))
8606 .collect::<Result<Vec<_>, _>>()
8607 .map_err(|_| RuntimeError::new("Invalid MAC hex"))?;
8608
8609 let mut mac = HmacSha256::new_from_slice(&key)
8610 .map_err(|e| RuntimeError::new(format!("HMAC key error: {}", e)))?;
8611 mac.update(&message);
8612
8613 match mac.verify_slice(&expected) {
8614 Ok(_) => Ok(Value::Bool(true)),
8615 Err(_) => Ok(Value::Bool(false)),
8616 }
8617 });
8618
8619 define(interp, "secure_random_bytes", Some(1), |_, args| {
8625 use rand::RngCore;
8626
8627 let length = match &args[0] {
8628 Value::Int(n) => *n as usize,
8629 _ => {
8630 return Err(RuntimeError::new(
8631 "secure_random_bytes() requires integer length",
8632 ))
8633 }
8634 };
8635
8636 if length > 1024 * 1024 {
8637 return Err(RuntimeError::new("secure_random_bytes() max 1MB"));
8638 }
8639
8640 let mut bytes = vec![0u8; length];
8641 rand::thread_rng().fill_bytes(&mut bytes);
8642 Ok(bytes_to_array(&bytes))
8643 });
8644
8645 define(interp, "secure_random_hex", Some(1), |_, args| {
8647 use rand::RngCore;
8648
8649 let byte_length = match &args[0] {
8650 Value::Int(n) => *n as usize,
8651 _ => {
8652 return Err(RuntimeError::new(
8653 "secure_random_hex() requires integer length",
8654 ))
8655 }
8656 };
8657
8658 if byte_length > 1024 * 1024 {
8659 return Err(RuntimeError::new("secure_random_hex() max 1MB"));
8660 }
8661
8662 let mut bytes = vec![0u8; byte_length];
8663 rand::thread_rng().fill_bytes(&mut bytes);
8664 Ok(Value::String(Rc::new(
8665 bytes.iter().map(|b| format!("{:02x}", b)).collect(),
8666 )))
8667 });
8668
8669 define(interp, "generate_key", Some(1), |_, args| {
8671 use rand::RngCore;
8672
8673 let bits = match &args[0] {
8674 Value::Int(n) => *n as usize,
8675 _ => return Err(RuntimeError::new("generate_key() requires bit length")),
8676 };
8677
8678 if bits % 8 != 0 {
8679 return Err(RuntimeError::new(
8680 "generate_key() bit length must be multiple of 8",
8681 ));
8682 }
8683 if bits > 512 {
8684 return Err(RuntimeError::new("generate_key() max 512 bits"));
8685 }
8686
8687 let bytes = bits / 8;
8688 let mut key = vec![0u8; bytes];
8689 rand::thread_rng().fill_bytes(&mut key);
8690 Ok(Value::String(Rc::new(
8691 key.iter().map(|b| format!("{:02x}", b)).collect(),
8692 )))
8693 });
8694
8695 define(interp, "base64_encode", Some(1), |_, args| {
8701 let data = extract_bytes(&args[0], "base64_encode")?;
8702 Ok(Value::String(Rc::new(
8703 general_purpose::STANDARD.encode(&data),
8704 )))
8705 });
8706
8707 define(interp, "base64_decode", Some(1), |_, args| {
8709 let encoded = match &args[0] {
8710 Value::String(s) => s.to_string(),
8711 _ => return Err(RuntimeError::new("base64_decode() requires string")),
8712 };
8713
8714 match general_purpose::STANDARD.decode(&encoded) {
8715 Ok(bytes) => match String::from_utf8(bytes.clone()) {
8716 Ok(s) => Ok(Value::String(Rc::new(s))),
8717 Err(_) => Ok(bytes_to_array(&bytes)),
8718 },
8719 Err(e) => Err(RuntimeError::new(format!("base64_decode() error: {}", e))),
8720 }
8721 });
8722
8723 define(interp, "hex_encode", Some(1), |_, args| {
8725 let data = extract_bytes(&args[0], "hex_encode")?;
8726 Ok(Value::String(Rc::new(
8727 data.iter().map(|b| format!("{:02x}", b)).collect(),
8728 )))
8729 });
8730
8731 define(interp, "hex_decode", Some(1), |_, args| {
8733 let hex_str = match &args[0] {
8734 Value::String(s) => s.to_string(),
8735 _ => return Err(RuntimeError::new("hex_decode() requires string")),
8736 };
8737
8738 let hex_str = hex_str.trim();
8739 if hex_str.len() % 2 != 0 {
8740 return Err(RuntimeError::new(
8741 "hex_decode() requires even-length hex string",
8742 ));
8743 }
8744
8745 let bytes: Vec<Value> = (0..hex_str.len())
8746 .step_by(2)
8747 .map(|i| u8::from_str_radix(&hex_str[i..i + 2], 16).map(|b| Value::Int(b as i64)))
8748 .collect::<Result<Vec<_>, _>>()
8749 .map_err(|_| RuntimeError::new("hex_decode() invalid hex"))?;
8750 Ok(Value::Array(Rc::new(RefCell::new(bytes))))
8751 });
8752
8753 define(interp, "constant_time_eq", Some(2), |_, args| {
8759 let a = extract_bytes(&args[0], "constant_time_eq")?;
8760 let b = extract_bytes(&args[1], "constant_time_eq")?;
8761
8762 if a.len() != b.len() {
8763 return Ok(Value::Bool(false));
8764 }
8765
8766 let mut result = 0u8;
8767 for (x, y) in a.iter().zip(b.iter()) {
8768 result |= x ^ y;
8769 }
8770 Ok(Value::Bool(result == 0))
8771 });
8772
8773 define(interp, "crypto_info", Some(0), |_, _| {
8779 let mut info = HashMap::new();
8780 info.insert(
8781 "version".to_string(),
8782 Value::String(Rc::new("2.0".to_string())),
8783 );
8784 info.insert(
8785 "phase".to_string(),
8786 Value::String(Rc::new("Evidential Cryptography".to_string())),
8787 );
8788
8789 let capabilities = vec![
8790 "sha256",
8791 "sha512",
8792 "sha3_256",
8793 "sha3_512",
8794 "blake3",
8795 "md5",
8796 "aes_gcm_encrypt",
8797 "aes_gcm_decrypt",
8798 "chacha20_encrypt",
8799 "chacha20_decrypt",
8800 "ed25519_keygen",
8801 "ed25519_sign",
8802 "ed25519_verify",
8803 "x25519_keygen",
8804 "x25519_exchange",
8805 "argon2_hash",
8806 "argon2_verify",
8807 "hkdf_expand",
8808 "pbkdf2_derive",
8809 "hmac_sha256",
8810 "hmac_sha512",
8811 "hmac_verify",
8812 "secure_random_bytes",
8813 "secure_random_hex",
8814 "generate_key",
8815 "base64_encode",
8816 "base64_decode",
8817 "hex_encode",
8818 "hex_decode",
8819 "constant_time_eq",
8820 ];
8821 let cap_values: Vec<Value> = capabilities
8822 .iter()
8823 .map(|s| Value::String(Rc::new(s.to_string())))
8824 .collect();
8825 info.insert(
8826 "functions".to_string(),
8827 Value::Array(Rc::new(RefCell::new(cap_values))),
8828 );
8829
8830 Ok(Value::Map(Rc::new(RefCell::new(info))))
8831 });
8832}
8833
8834fn register_regex(interp: &mut Interpreter) {
8839 define(interp, "regex_match", Some(2), |_, args| {
8841 let pattern = match &args[0] {
8842 Value::String(s) => s.to_string(),
8843 _ => return Err(RuntimeError::new("regex_match() requires string pattern")),
8844 };
8845 let text = match &args[1] {
8846 Value::String(s) => s.to_string(),
8847 _ => return Err(RuntimeError::new("regex_match() requires string text")),
8848 };
8849
8850 match Regex::new(&pattern) {
8851 Ok(re) => Ok(Value::Bool(re.is_match(&text))),
8852 Err(e) => Err(RuntimeError::new(format!(
8853 "regex_match() invalid pattern: {}",
8854 e
8855 ))),
8856 }
8857 });
8858
8859 define(interp, "regex_find", Some(2), |_, args| {
8861 let pattern = match &args[0] {
8862 Value::String(s) => s.to_string(),
8863 _ => return Err(RuntimeError::new("regex_find() requires string pattern")),
8864 };
8865 let text = match &args[1] {
8866 Value::String(s) => s.to_string(),
8867 _ => return Err(RuntimeError::new("regex_find() requires string text")),
8868 };
8869
8870 match Regex::new(&pattern) {
8871 Ok(re) => match re.find(&text) {
8872 Some(m) => Ok(Value::String(Rc::new(m.as_str().to_string()))),
8873 None => Ok(Value::Null),
8874 },
8875 Err(e) => Err(RuntimeError::new(format!(
8876 "regex_find() invalid pattern: {}",
8877 e
8878 ))),
8879 }
8880 });
8881
8882 define(interp, "regex_find_all", Some(2), |_, args| {
8884 let pattern = match &args[0] {
8885 Value::String(s) => s.to_string(),
8886 _ => {
8887 return Err(RuntimeError::new(
8888 "regex_find_all() requires string pattern",
8889 ))
8890 }
8891 };
8892 let text = match &args[1] {
8893 Value::String(s) => s.to_string(),
8894 _ => return Err(RuntimeError::new("regex_find_all() requires string text")),
8895 };
8896
8897 match Regex::new(&pattern) {
8898 Ok(re) => {
8899 let matches: Vec<Value> = re
8900 .find_iter(&text)
8901 .map(|m| Value::String(Rc::new(m.as_str().to_string())))
8902 .collect();
8903 Ok(Value::Array(Rc::new(RefCell::new(matches))))
8904 }
8905 Err(e) => Err(RuntimeError::new(format!(
8906 "regex_find_all() invalid pattern: {}",
8907 e
8908 ))),
8909 }
8910 });
8911
8912 define(interp, "regex_replace", Some(3), |_, args| {
8914 let pattern = match &args[0] {
8915 Value::String(s) => s.to_string(),
8916 _ => return Err(RuntimeError::new("regex_replace() requires string pattern")),
8917 };
8918 let text = match &args[1] {
8919 Value::String(s) => s.to_string(),
8920 _ => return Err(RuntimeError::new("regex_replace() requires string text")),
8921 };
8922 let replacement = match &args[2] {
8923 Value::String(s) => s.to_string(),
8924 _ => {
8925 return Err(RuntimeError::new(
8926 "regex_replace() requires string replacement",
8927 ))
8928 }
8929 };
8930
8931 match Regex::new(&pattern) {
8932 Ok(re) => {
8933 let result = re.replace(&text, replacement.as_str());
8934 Ok(Value::String(Rc::new(result.to_string())))
8935 }
8936 Err(e) => Err(RuntimeError::new(format!(
8937 "regex_replace() invalid pattern: {}",
8938 e
8939 ))),
8940 }
8941 });
8942
8943 define(interp, "regex_replace_all", Some(3), |_, args| {
8945 let pattern = match &args[0] {
8946 Value::String(s) => s.to_string(),
8947 _ => {
8948 return Err(RuntimeError::new(
8949 "regex_replace_all() requires string pattern",
8950 ))
8951 }
8952 };
8953 let text = match &args[1] {
8954 Value::String(s) => s.to_string(),
8955 _ => {
8956 return Err(RuntimeError::new(
8957 "regex_replace_all() requires string text",
8958 ))
8959 }
8960 };
8961 let replacement = match &args[2] {
8962 Value::String(s) => s.to_string(),
8963 _ => {
8964 return Err(RuntimeError::new(
8965 "regex_replace_all() requires string replacement",
8966 ))
8967 }
8968 };
8969
8970 match Regex::new(&pattern) {
8971 Ok(re) => {
8972 let result = re.replace_all(&text, replacement.as_str());
8973 Ok(Value::String(Rc::new(result.to_string())))
8974 }
8975 Err(e) => Err(RuntimeError::new(format!(
8976 "regex_replace_all() invalid pattern: {}",
8977 e
8978 ))),
8979 }
8980 });
8981
8982 define(interp, "regex_split", Some(2), |_, args| {
8984 let pattern = match &args[0] {
8985 Value::String(s) => s.to_string(),
8986 _ => return Err(RuntimeError::new("regex_split() requires string pattern")),
8987 };
8988 let text = match &args[1] {
8989 Value::String(s) => s.to_string(),
8990 _ => return Err(RuntimeError::new("regex_split() requires string text")),
8991 };
8992
8993 match Regex::new(&pattern) {
8994 Ok(re) => {
8995 let parts: Vec<Value> = re
8996 .split(&text)
8997 .map(|s| Value::String(Rc::new(s.to_string())))
8998 .collect();
8999 Ok(Value::Array(Rc::new(RefCell::new(parts))))
9000 }
9001 Err(e) => Err(RuntimeError::new(format!(
9002 "regex_split() invalid pattern: {}",
9003 e
9004 ))),
9005 }
9006 });
9007
9008 define(interp, "regex_captures", Some(2), |_, args| {
9010 let pattern = match &args[0] {
9011 Value::String(s) => s.to_string(),
9012 _ => {
9013 return Err(RuntimeError::new(
9014 "regex_captures() requires string pattern",
9015 ))
9016 }
9017 };
9018 let text = match &args[1] {
9019 Value::String(s) => s.to_string(),
9020 _ => return Err(RuntimeError::new("regex_captures() requires string text")),
9021 };
9022
9023 match Regex::new(&pattern) {
9024 Ok(re) => match re.captures(&text) {
9025 Some(caps) => {
9026 let captures: Vec<Value> = caps
9027 .iter()
9028 .map(|m| {
9029 m.map(|m| Value::String(Rc::new(m.as_str().to_string())))
9030 .unwrap_or(Value::Null)
9031 })
9032 .collect();
9033 Ok(Value::Array(Rc::new(RefCell::new(captures))))
9034 }
9035 None => Ok(Value::Null),
9036 },
9037 Err(e) => Err(RuntimeError::new(format!(
9038 "regex_captures() invalid pattern: {}",
9039 e
9040 ))),
9041 }
9042 });
9043}
9044
9045fn register_uuid(interp: &mut Interpreter) {
9050 define(interp, "uuid_v4", Some(0), |_, _| {
9052 let id = Uuid::new_v4();
9053 Ok(Value::String(Rc::new(id.to_string())))
9054 });
9055
9056 define(interp, "uuid_nil", Some(0), |_, _| {
9058 Ok(Value::String(Rc::new(Uuid::nil().to_string())))
9059 });
9060
9061 define(interp, "uuid_parse", Some(1), |_, args| {
9063 let s = match &args[0] {
9064 Value::String(s) => s.to_string(),
9065 _ => return Err(RuntimeError::new("uuid_parse() requires string")),
9066 };
9067
9068 match Uuid::parse_str(&s) {
9069 Ok(id) => Ok(Value::String(Rc::new(id.to_string()))),
9070 Err(e) => Err(RuntimeError::new(format!("uuid_parse() error: {}", e))),
9071 }
9072 });
9073
9074 define(interp, "uuid_is_valid", Some(1), |_, args| {
9076 let s = match &args[0] {
9077 Value::String(s) => s.to_string(),
9078 _ => return Ok(Value::Bool(false)),
9079 };
9080 Ok(Value::Bool(Uuid::parse_str(&s).is_ok()))
9081 });
9082}
9083
9084fn register_system(interp: &mut Interpreter) {
9089 define(interp, "env_get", Some(1), |_, args| {
9091 let key = match &args[0] {
9092 Value::String(s) => s.to_string(),
9093 _ => return Err(RuntimeError::new("env_get() requires string key")),
9094 };
9095
9096 match std::env::var(&key) {
9097 Ok(val) => Ok(Value::String(Rc::new(val))),
9098 Err(_) => Ok(Value::Null),
9099 }
9100 });
9101
9102 define(interp, "env_set", Some(2), |_, args| {
9104 let key = match &args[0] {
9105 Value::String(s) => s.to_string(),
9106 _ => return Err(RuntimeError::new("env_set() requires string key")),
9107 };
9108 let val = match &args[1] {
9109 Value::String(s) => s.to_string(),
9110 _ => format!("{}", args[1]),
9111 };
9112
9113 std::env::set_var(&key, &val);
9114 Ok(Value::Null)
9115 });
9116
9117 define(interp, "env_remove", Some(1), |_, args| {
9119 let key = match &args[0] {
9120 Value::String(s) => s.to_string(),
9121 _ => return Err(RuntimeError::new("env_remove() requires string key")),
9122 };
9123
9124 std::env::remove_var(&key);
9125 Ok(Value::Null)
9126 });
9127
9128 define(interp, "env_vars", Some(0), |_, _| {
9130 let mut map = HashMap::new();
9131 for (key, val) in std::env::vars() {
9132 map.insert(key, Value::String(Rc::new(val)));
9133 }
9134 Ok(Value::Map(Rc::new(RefCell::new(map))))
9135 });
9136
9137 define(interp, "std·env·var", Some(1), |_, args| {
9139 let key = match &args[0] {
9140 Value::String(s) => s.as_str().to_string(),
9141 _ => return Err(RuntimeError::new("env::var expects string key")),
9142 };
9143 match std::env::var(&key) {
9144 Ok(val) => Ok(Value::Variant {
9145 enum_name: "Result".to_string(),
9146 variant_name: "Ok".to_string(),
9147 fields: Some(Rc::new(vec![Value::String(Rc::new(val))])),
9148 }),
9149 Err(_) => Ok(Value::Variant {
9150 enum_name: "Result".to_string(),
9151 variant_name: "Err".to_string(),
9152 fields: Some(Rc::new(vec![Value::String(Rc::new(
9153 "environment variable not found".to_string(),
9154 ))])),
9155 }),
9156 }
9157 });
9158
9159 define(interp, "std·env·temp_dir", Some(0), |_, _| {
9161 let temp_dir = std::env::temp_dir();
9162 Ok(Value::String(Rc::new(
9163 temp_dir.to_string_lossy().to_string(),
9164 )))
9165 });
9166
9167 define(interp, "temp_dir", Some(0), |_, _| {
9169 let temp_dir = std::env::temp_dir();
9170 Ok(Value::String(Rc::new(
9171 temp_dir.to_string_lossy().to_string(),
9172 )))
9173 });
9174
9175 define(
9177 interp,
9178 "std·env·current_dir",
9179 Some(0),
9180 |_, _| match std::env::current_dir() {
9181 Ok(path) => Ok(Value::String(Rc::new(path.to_string_lossy().to_string()))),
9182 Err(e) => Err(RuntimeError::new(format!("current_dir() error: {}", e))),
9183 },
9184 );
9185
9186 define(interp, "std·env·args", Some(0), |interp, _| {
9188 let args: Vec<Value> = if interp
9189 .program_args
9190 .as_ref()
9191 .map(|v| v.is_empty())
9192 .unwrap_or(true)
9193 {
9194 std::env::args()
9196 .map(|s| Value::String(Rc::new(s)))
9197 .collect()
9198 } else {
9199 interp
9201 .program_args
9202 .as_ref()
9203 .unwrap()
9204 .iter()
9205 .map(|a| Value::String(Rc::new(a.clone())))
9206 .collect()
9207 };
9208 Ok(Value::Array(Rc::new(RefCell::new(args))))
9209 });
9210
9211 define(interp, "args", Some(0), |interp, _| {
9213 let args: Vec<Value> = if interp
9214 .program_args
9215 .as_ref()
9216 .map(|v| v.is_empty())
9217 .unwrap_or(true)
9218 {
9219 std::env::args()
9221 .map(|s| Value::String(Rc::new(s)))
9222 .collect()
9223 } else {
9224 interp
9226 .program_args
9227 .as_ref()
9228 .unwrap()
9229 .iter()
9230 .map(|a| Value::String(Rc::new(a.clone())))
9231 .collect()
9232 };
9233 Ok(Value::Array(Rc::new(RefCell::new(args))))
9234 });
9235
9236 define(interp, "cwd", Some(0), |_, _| {
9238 match std::env::current_dir() {
9239 Ok(path) => Ok(Value::String(Rc::new(path.to_string_lossy().to_string()))),
9240 Err(e) => Err(RuntimeError::new(format!("cwd() error: {}", e))),
9241 }
9242 });
9243
9244 define(interp, "chdir", Some(1), |_, args| {
9246 let path = match &args[0] {
9247 Value::String(s) => s.to_string(),
9248 _ => return Err(RuntimeError::new("chdir() requires string path")),
9249 };
9250
9251 match std::env::set_current_dir(&path) {
9252 Ok(()) => Ok(Value::Null),
9253 Err(e) => Err(RuntimeError::new(format!("chdir() error: {}", e))),
9254 }
9255 });
9256
9257 define(interp, "hostname", Some(0), |_, _| {
9259 match std::fs::read_to_string("/etc/hostname") {
9261 Ok(name) => Ok(Value::String(Rc::new(name.trim().to_string()))),
9262 Err(_) => Ok(Value::String(Rc::new("unknown".to_string()))),
9263 }
9264 });
9265
9266 define(interp, "pid", Some(0), |_, _| {
9268 Ok(Value::Int(std::process::id() as i64))
9269 });
9270
9271 define(interp, "exit", Some(1), |_, args| {
9273 let code = match &args[0] {
9274 Value::Int(n) => *n as i32,
9275 _ => 0,
9276 };
9277 std::process::exit(code);
9278 });
9279
9280 define(interp, "std·process·exit", Some(1), |_, args| {
9282 let code = match &args[0] {
9283 Value::Int(n) => *n as i32,
9284 _ => 0,
9285 };
9286 std::process::exit(code);
9287 });
9288
9289 define(interp, "shell", Some(1), |_, args| {
9291 let cmd = match &args[0] {
9292 Value::String(s) => s.to_string(),
9293 _ => return Err(RuntimeError::new("shell() requires string command")),
9294 };
9295
9296 match std::process::Command::new("sh")
9297 .arg("-c")
9298 .arg(&cmd)
9299 .output()
9300 {
9301 Ok(output) => {
9302 let stdout = String::from_utf8_lossy(&output.stdout).to_string();
9303 let stderr = String::from_utf8_lossy(&output.stderr).to_string();
9304 let code = output.status.code().unwrap_or(-1);
9305
9306 let mut result = HashMap::new();
9307 result.insert("stdout".to_string(), Value::String(Rc::new(stdout)));
9308 result.insert("stderr".to_string(), Value::String(Rc::new(stderr)));
9309 result.insert("code".to_string(), Value::Int(code as i64));
9310 result.insert("success".to_string(), Value::Bool(output.status.success()));
9311
9312 Ok(Value::Map(Rc::new(RefCell::new(result))))
9313 }
9314 Err(e) => Err(RuntimeError::new(format!("shell() error: {}", e))),
9315 }
9316 });
9317
9318 define(interp, "platform", Some(0), |_, _| {
9320 Ok(Value::String(Rc::new(std::env::consts::OS.to_string())))
9321 });
9322
9323 define(interp, "arch", Some(0), |_, _| {
9325 Ok(Value::String(Rc::new(std::env::consts::ARCH.to_string())))
9326 });
9327
9328 define(interp, "num_cpus·get", Some(0), |_, _| {
9330 Ok(Value::Int(num_cpus::get() as i64))
9331 });
9332
9333 define(interp, "num_cpus·get_physical", Some(0), |_, _| {
9335 Ok(Value::Int(num_cpus::get_physical() as i64))
9336 });
9337}
9338
9339fn register_stats(interp: &mut Interpreter) {
9344 fn extract_numbers(val: &Value) -> Result<Vec<f64>, RuntimeError> {
9346 match val {
9347 Value::Array(arr) => {
9348 let arr = arr.borrow();
9349 let mut nums = Vec::new();
9350 for v in arr.iter() {
9351 match v {
9352 Value::Int(n) => nums.push(*n as f64),
9353 Value::Float(f) => nums.push(*f),
9354 _ => {
9355 return Err(RuntimeError::new("stats functions require numeric array"))
9356 }
9357 }
9358 }
9359 Ok(nums)
9360 }
9361 _ => Err(RuntimeError::new("stats functions require array")),
9362 }
9363 }
9364
9365 define(interp, "mean", Some(1), |_, args| {
9367 let nums = extract_numbers(&args[0])?;
9368 if nums.is_empty() {
9369 return Ok(Value::Float(0.0));
9370 }
9371 let sum: f64 = nums.iter().sum();
9372 Ok(Value::Float(sum / nums.len() as f64))
9373 });
9374
9375 define(interp, "median", Some(1), |_, args| {
9377 let mut nums = extract_numbers(&args[0])?;
9378 if nums.is_empty() {
9379 return Ok(Value::Float(0.0));
9380 }
9381 nums.sort_by(|a, b| a.partial_cmp(b).unwrap());
9382 let len = nums.len();
9383 if len % 2 == 0 {
9384 Ok(Value::Float((nums[len / 2 - 1] + nums[len / 2]) / 2.0))
9385 } else {
9386 Ok(Value::Float(nums[len / 2]))
9387 }
9388 });
9389
9390 define(interp, "mode", Some(1), |_, args| {
9392 let nums = extract_numbers(&args[0])?;
9393 if nums.is_empty() {
9394 return Ok(Value::Null);
9395 }
9396
9397 let mut counts: HashMap<String, usize> = HashMap::new();
9398 for n in &nums {
9399 let key = format!("{:.10}", n);
9400 *counts.entry(key).or_insert(0) += 1;
9401 }
9402
9403 let max_count = counts.values().max().unwrap_or(&0);
9404 for n in &nums {
9405 let key = format!("{:.10}", n);
9406 if counts.get(&key) == Some(max_count) {
9407 return Ok(Value::Float(*n));
9408 }
9409 }
9410 Ok(Value::Null)
9411 });
9412
9413 define(interp, "variance", Some(1), |_, args| {
9415 let nums = extract_numbers(&args[0])?;
9416 if nums.is_empty() {
9417 return Ok(Value::Float(0.0));
9418 }
9419 let mean: f64 = nums.iter().sum::<f64>() / nums.len() as f64;
9420 let variance: f64 =
9421 nums.iter().map(|x| (x - mean).powi(2)).sum::<f64>() / nums.len() as f64;
9422 Ok(Value::Float(variance))
9423 });
9424
9425 define(interp, "stddev", Some(1), |_, args| {
9427 let nums = extract_numbers(&args[0])?;
9428 if nums.is_empty() {
9429 return Ok(Value::Float(0.0));
9430 }
9431 let mean: f64 = nums.iter().sum::<f64>() / nums.len() as f64;
9432 let variance: f64 =
9433 nums.iter().map(|x| (x - mean).powi(2)).sum::<f64>() / nums.len() as f64;
9434 Ok(Value::Float(variance.sqrt()))
9435 });
9436
9437 define(interp, "percentile", Some(2), |_, args| {
9439 let mut nums = extract_numbers(&args[0])?;
9440 let p = match &args[1] {
9441 Value::Int(n) => *n as f64,
9442 Value::Float(f) => *f,
9443 _ => {
9444 return Err(RuntimeError::new(
9445 "percentile() requires numeric percentile",
9446 ))
9447 }
9448 };
9449
9450 if nums.is_empty() {
9451 return Ok(Value::Float(0.0));
9452 }
9453
9454 nums.sort_by(|a, b| a.partial_cmp(b).unwrap());
9455 let idx = (p / 100.0 * (nums.len() - 1) as f64).round() as usize;
9456 Ok(Value::Float(nums[idx.min(nums.len() - 1)]))
9457 });
9458
9459 define(interp, "correlation", Some(2), |_, args| {
9461 let x = extract_numbers(&args[0])?;
9462 let y = extract_numbers(&args[1])?;
9463
9464 if x.len() != y.len() || x.is_empty() {
9465 return Err(RuntimeError::new(
9466 "correlation() requires equal-length non-empty arrays",
9467 ));
9468 }
9469
9470 let n = x.len() as f64;
9471 let mean_x: f64 = x.iter().sum::<f64>() / n;
9472 let mean_y: f64 = y.iter().sum::<f64>() / n;
9473
9474 let mut cov = 0.0;
9475 let mut var_x = 0.0;
9476 let mut var_y = 0.0;
9477
9478 for i in 0..x.len() {
9479 let dx = x[i] - mean_x;
9480 let dy = y[i] - mean_y;
9481 cov += dx * dy;
9482 var_x += dx * dx;
9483 var_y += dy * dy;
9484 }
9485
9486 if var_x == 0.0 || var_y == 0.0 {
9487 return Ok(Value::Float(0.0));
9488 }
9489
9490 Ok(Value::Float(cov / (var_x.sqrt() * var_y.sqrt())))
9491 });
9492
9493 define(interp, "range", Some(1), |_, args| {
9495 let nums = extract_numbers(&args[0])?;
9496 if nums.is_empty() {
9497 return Ok(Value::Float(0.0));
9498 }
9499 let min = nums.iter().cloned().fold(f64::INFINITY, f64::min);
9500 let max = nums.iter().cloned().fold(f64::NEG_INFINITY, f64::max);
9501 Ok(Value::Float(max - min))
9502 });
9503
9504 define(interp, "zscore", Some(1), |_, args| {
9506 let nums = extract_numbers(&args[0])?;
9507 if nums.is_empty() {
9508 return Ok(Value::Array(Rc::new(RefCell::new(vec![]))));
9509 }
9510
9511 let mean: f64 = nums.iter().sum::<f64>() / nums.len() as f64;
9512 let variance: f64 =
9513 nums.iter().map(|x| (x - mean).powi(2)).sum::<f64>() / nums.len() as f64;
9514 let stddev = variance.sqrt();
9515
9516 if stddev == 0.0 {
9517 let zeros: Vec<Value> = nums.iter().map(|_| Value::Float(0.0)).collect();
9518 return Ok(Value::Array(Rc::new(RefCell::new(zeros))));
9519 }
9520
9521 let zscores: Vec<Value> = nums
9522 .iter()
9523 .map(|x| Value::Float((x - mean) / stddev))
9524 .collect();
9525 Ok(Value::Array(Rc::new(RefCell::new(zscores))))
9526 });
9527}
9528
9529fn register_matrix(interp: &mut Interpreter) {
9534 fn extract_matrix(val: &Value) -> Result<Vec<Vec<f64>>, RuntimeError> {
9536 match val {
9537 Value::Array(arr) => {
9538 let arr = arr.borrow();
9539 let mut matrix = Vec::new();
9540 for row in arr.iter() {
9541 match row {
9542 Value::Array(row_arr) => {
9543 let row_arr = row_arr.borrow();
9544 let mut row_vec = Vec::new();
9545 for v in row_arr.iter() {
9546 match v {
9547 Value::Int(n) => row_vec.push(*n as f64),
9548 Value::Float(f) => row_vec.push(*f),
9549 _ => {
9550 return Err(RuntimeError::new(
9551 "matrix requires numeric values",
9552 ))
9553 }
9554 }
9555 }
9556 matrix.push(row_vec);
9557 }
9558 _ => return Err(RuntimeError::new("matrix requires 2D array")),
9559 }
9560 }
9561 Ok(matrix)
9562 }
9563 _ => Err(RuntimeError::new("matrix requires array")),
9564 }
9565 }
9566
9567 fn matrix_to_value(m: Vec<Vec<f64>>) -> Value {
9568 let rows: Vec<Value> = m
9569 .into_iter()
9570 .map(|row| {
9571 let cols: Vec<Value> = row.into_iter().map(Value::Float).collect();
9572 Value::Array(Rc::new(RefCell::new(cols)))
9573 })
9574 .collect();
9575 Value::Array(Rc::new(RefCell::new(rows)))
9576 }
9577
9578 define(interp, "matrix_new", Some(3), |_, args| {
9580 let rows = match &args[0] {
9581 Value::Int(n) => *n as usize,
9582 _ => return Err(RuntimeError::new("matrix_new() requires integer rows")),
9583 };
9584 let cols = match &args[1] {
9585 Value::Int(n) => *n as usize,
9586 _ => return Err(RuntimeError::new("matrix_new() requires integer cols")),
9587 };
9588 let fill = match &args[2] {
9589 Value::Int(n) => *n as f64,
9590 Value::Float(f) => *f,
9591 _ => 0.0,
9592 };
9593
9594 let matrix = vec![vec![fill; cols]; rows];
9595 Ok(matrix_to_value(matrix))
9596 });
9597
9598 define(interp, "matrix_identity", Some(1), |_, args| {
9600 let size = match &args[0] {
9601 Value::Int(n) => *n as usize,
9602 _ => return Err(RuntimeError::new("matrix_identity() requires integer size")),
9603 };
9604
9605 let mut matrix = vec![vec![0.0; size]; size];
9606 for i in 0..size {
9607 matrix[i][i] = 1.0;
9608 }
9609 Ok(matrix_to_value(matrix))
9610 });
9611
9612 define(interp, "matrix_add", Some(2), |_, args| {
9614 let a = extract_matrix(&args[0])?;
9615 let b = extract_matrix(&args[1])?;
9616
9617 if a.len() != b.len() || a.is_empty() || a[0].len() != b[0].len() {
9618 return Err(RuntimeError::new(
9619 "matrix_add() requires same-size matrices",
9620 ));
9621 }
9622
9623 let result: Vec<Vec<f64>> = a
9624 .iter()
9625 .zip(b.iter())
9626 .map(|(row_a, row_b)| row_a.iter().zip(row_b.iter()).map(|(x, y)| x + y).collect())
9627 .collect();
9628
9629 Ok(matrix_to_value(result))
9630 });
9631
9632 define(interp, "matrix_sub", Some(2), |_, args| {
9634 let a = extract_matrix(&args[0])?;
9635 let b = extract_matrix(&args[1])?;
9636
9637 if a.len() != b.len() || a.is_empty() || a[0].len() != b[0].len() {
9638 return Err(RuntimeError::new(
9639 "matrix_sub() requires same-size matrices",
9640 ));
9641 }
9642
9643 let result: Vec<Vec<f64>> = a
9644 .iter()
9645 .zip(b.iter())
9646 .map(|(row_a, row_b)| row_a.iter().zip(row_b.iter()).map(|(x, y)| x - y).collect())
9647 .collect();
9648
9649 Ok(matrix_to_value(result))
9650 });
9651
9652 define(interp, "matrix_mul", Some(2), |_, args| {
9654 let a = extract_matrix(&args[0])?;
9655 let b = extract_matrix(&args[1])?;
9656
9657 if a.is_empty() || b.is_empty() || a[0].len() != b.len() {
9658 return Err(RuntimeError::new(
9659 "matrix_mul() requires compatible matrices (a.cols == b.rows)",
9660 ));
9661 }
9662
9663 let rows = a.len();
9664 let cols = b[0].len();
9665 let inner = b.len();
9666
9667 let mut result = vec![vec![0.0; cols]; rows];
9668 for i in 0..rows {
9669 for j in 0..cols {
9670 for k in 0..inner {
9671 result[i][j] += a[i][k] * b[k][j];
9672 }
9673 }
9674 }
9675
9676 Ok(matrix_to_value(result))
9677 });
9678
9679 define(interp, "matrix_scale", Some(2), |_, args| {
9681 let m = extract_matrix(&args[0])?;
9682 let scale = match &args[1] {
9683 Value::Int(n) => *n as f64,
9684 Value::Float(f) => *f,
9685 _ => return Err(RuntimeError::new("matrix_scale() requires numeric scalar")),
9686 };
9687
9688 let result: Vec<Vec<f64>> = m
9689 .iter()
9690 .map(|row| row.iter().map(|x| x * scale).collect())
9691 .collect();
9692
9693 Ok(matrix_to_value(result))
9694 });
9695
9696 define(interp, "matrix_transpose", Some(1), |_, args| {
9698 let m = extract_matrix(&args[0])?;
9699 if m.is_empty() {
9700 return Ok(Value::Array(Rc::new(RefCell::new(vec![]))));
9701 }
9702
9703 let rows = m.len();
9704 let cols = m[0].len();
9705 let mut result = vec![vec![0.0; rows]; cols];
9706
9707 for i in 0..rows {
9708 for j in 0..cols {
9709 result[j][i] = m[i][j];
9710 }
9711 }
9712
9713 Ok(matrix_to_value(result))
9714 });
9715
9716 define(interp, "matrix_det", Some(1), |_, args| {
9718 let m = extract_matrix(&args[0])?;
9719
9720 if m.is_empty() || m.len() != m[0].len() {
9721 return Err(RuntimeError::new("matrix_det() requires square matrix"));
9722 }
9723
9724 let n = m.len();
9725 match n {
9726 1 => Ok(Value::Float(m[0][0])),
9727 2 => Ok(Value::Float(m[0][0] * m[1][1] - m[0][1] * m[1][0])),
9728 3 => {
9729 let det = m[0][0] * (m[1][1] * m[2][2] - m[1][2] * m[2][1])
9730 - m[0][1] * (m[1][0] * m[2][2] - m[1][2] * m[2][0])
9731 + m[0][2] * (m[1][0] * m[2][1] - m[1][1] * m[2][0]);
9732 Ok(Value::Float(det))
9733 }
9734 _ => Err(RuntimeError::new(
9735 "matrix_det() only supports up to 3x3 matrices",
9736 )),
9737 }
9738 });
9739
9740 define(interp, "matrix_trace", Some(1), |_, args| {
9742 let m = extract_matrix(&args[0])?;
9743
9744 let size = m.len().min(if m.is_empty() { 0 } else { m[0].len() });
9745 let trace: f64 = (0..size).map(|i| m[i][i]).sum();
9746
9747 Ok(Value::Float(trace))
9748 });
9749
9750 define(interp, "matrix_dot", Some(2), |_, args| {
9752 fn extract_vector(val: &Value) -> Result<Vec<f64>, RuntimeError> {
9753 match val {
9754 Value::Array(arr) => {
9755 let arr = arr.borrow();
9756 let mut vec = Vec::new();
9757 for v in arr.iter() {
9758 match v {
9759 Value::Int(n) => vec.push(*n as f64),
9760 Value::Float(f) => vec.push(*f),
9761 _ => {
9762 return Err(RuntimeError::new(
9763 "dot product requires numeric vectors",
9764 ))
9765 }
9766 }
9767 }
9768 Ok(vec)
9769 }
9770 _ => Err(RuntimeError::new("dot product requires arrays")),
9771 }
9772 }
9773
9774 let a = extract_vector(&args[0])?;
9775 let b = extract_vector(&args[1])?;
9776
9777 if a.len() != b.len() {
9778 return Err(RuntimeError::new(
9779 "matrix_dot() requires same-length vectors",
9780 ));
9781 }
9782
9783 let dot: f64 = a.iter().zip(b.iter()).map(|(x, y)| x * y).sum();
9784 Ok(Value::Float(dot))
9785 });
9786}
9787
9788fn mod_inverse(a: i64, m: i64) -> Option<i64> {
9790 let (mut old_r, mut r) = (a, m);
9791 let (mut old_s, mut s) = (1i64, 0i64);
9792
9793 while r != 0 {
9794 let q = old_r / r;
9795 (old_r, r) = (r, old_r - q * r);
9796 (old_s, s) = (s, old_s - q * s);
9797 }
9798
9799 if old_r != 1 {
9800 None } else {
9802 Some(old_s.rem_euclid(m))
9803 }
9804}
9805
9806fn register_functional(interp: &mut Interpreter) {
9812 define(interp, "identity", Some(1), |_, args| Ok(args[0].clone()));
9814
9815 define(interp, "const_fn", Some(1), |_, args| Ok(args[0].clone()));
9817
9818 define(interp, "apply", Some(2), |interp, args| {
9820 let func = match &args[0] {
9821 Value::Function(f) => f.clone(),
9822 _ => {
9823 return Err(RuntimeError::new(
9824 "apply: first argument must be a function",
9825 ))
9826 }
9827 };
9828 let fn_args = match &args[1] {
9829 Value::Array(arr) => arr.borrow().clone(),
9830 _ => return Err(RuntimeError::new("apply: second argument must be an array")),
9831 };
9832 interp.call_function(&func, fn_args)
9833 });
9834
9835 define(interp, "flip", Some(3), |interp, args| {
9837 let func = match &args[0] {
9838 Value::Function(f) => f.clone(),
9839 _ => return Err(RuntimeError::new("flip: first argument must be a function")),
9840 };
9841 let flipped_args = vec![args[2].clone(), args[1].clone()];
9842 interp.call_function(&func, flipped_args)
9843 });
9844
9845 define(interp, "tap", Some(2), |interp, args| {
9847 let val = args[0].clone();
9848 let func = match &args[1] {
9849 Value::Function(f) => f.clone(),
9850 _ => return Err(RuntimeError::new("tap: second argument must be a function")),
9851 };
9852 let _ = interp.call_function(&func, vec![val.clone()]);
9853 Ok(val)
9854 });
9855
9856 define(interp, "thunk", Some(1), |_, args| {
9858 Ok(Value::Array(Rc::new(RefCell::new(vec![args[0].clone()]))))
9859 });
9860
9861 define(interp, "force", Some(1), |interp, args| match &args[0] {
9863 Value::Array(arr) => {
9864 let arr = arr.borrow();
9865 if arr.len() == 1 {
9866 if let Value::Function(f) = &arr[0] {
9867 return interp.call_function(f, vec![]);
9868 }
9869 }
9870 Ok(arr.get(0).cloned().unwrap_or(Value::Null))
9871 }
9872 v => Ok(v.clone()),
9873 });
9874
9875 define(interp, "negate", Some(2), |interp, args| {
9877 let func = match &args[0] {
9878 Value::Function(f) => f.clone(),
9879 _ => {
9880 return Err(RuntimeError::new(
9881 "negate: first argument must be a function",
9882 ))
9883 }
9884 };
9885 let result = interp.call_function(&func, vec![args[1].clone()])?;
9886 Ok(Value::Bool(!is_truthy(&result)))
9887 });
9888
9889 define(interp, "complement", Some(2), |interp, args| {
9891 let func = match &args[0] {
9892 Value::Function(f) => f.clone(),
9893 _ => {
9894 return Err(RuntimeError::new(
9895 "complement: first argument must be a function",
9896 ))
9897 }
9898 };
9899 let result = interp.call_function(&func, vec![args[1].clone()])?;
9900 Ok(Value::Bool(!is_truthy(&result)))
9901 });
9902
9903 define(interp, "partial", None, |interp, args| {
9905 if args.len() < 2 {
9906 return Err(RuntimeError::new(
9907 "partial: requires at least function and one argument",
9908 ));
9909 }
9910 let func = match &args[0] {
9911 Value::Function(f) => f.clone(),
9912 _ => {
9913 return Err(RuntimeError::new(
9914 "partial: first argument must be a function",
9915 ))
9916 }
9917 };
9918 let partial_args: Vec<Value> = args[1..].to_vec();
9919 interp.call_function(&func, partial_args)
9920 });
9921
9922 define(interp, "juxt", None, |interp, args| {
9924 if args.len() < 2 {
9925 return Err(RuntimeError::new("juxt: requires functions and a value"));
9926 }
9927 let val = args.last().unwrap().clone();
9928 let results: Result<Vec<Value>, _> = args[..args.len() - 1]
9929 .iter()
9930 .map(|f| match f {
9931 Value::Function(func) => interp.call_function(func, vec![val.clone()]),
9932 _ => Err(RuntimeError::new(
9933 "juxt: all but last argument must be functions",
9934 )),
9935 })
9936 .collect();
9937 Ok(Value::Array(Rc::new(RefCell::new(results?))))
9938 });
9939}
9940
9941fn register_benchmark(interp: &mut Interpreter) {
9943 define(interp, "bench", Some(2), |interp, args| {
9945 let func = match &args[0] {
9946 Value::Function(f) => f.clone(),
9947 _ => {
9948 return Err(RuntimeError::new(
9949 "bench: first argument must be a function",
9950 ))
9951 }
9952 };
9953 let iterations = match &args[1] {
9954 Value::Int(n) => *n as usize,
9955 _ => {
9956 return Err(RuntimeError::new(
9957 "bench: second argument must be an integer",
9958 ))
9959 }
9960 };
9961
9962 let start = std::time::Instant::now();
9963 for _ in 0..iterations {
9964 let _ = interp.call_function(&func, vec![])?;
9965 }
9966 let elapsed = start.elapsed();
9967 let avg_ms = elapsed.as_secs_f64() * 1000.0 / iterations as f64;
9968 Ok(Value::Float(avg_ms))
9969 });
9970
9971 define(interp, "time_it", Some(1), |interp, args| {
9973 let func = match &args[0] {
9974 Value::Function(f) => f.clone(),
9975 _ => return Err(RuntimeError::new("time_it: argument must be a function")),
9976 };
9977
9978 let start = std::time::Instant::now();
9979 let result = interp.call_function(&func, vec![])?;
9980 let elapsed_ms = start.elapsed().as_secs_f64() * 1000.0;
9981
9982 Ok(Value::Tuple(Rc::new(vec![
9983 result,
9984 Value::Float(elapsed_ms),
9985 ])))
9986 });
9987
9988 define(interp, "stopwatch_start", Some(0), |_, _| {
9990 let elapsed = std::time::SystemTime::now()
9991 .duration_since(std::time::UNIX_EPOCH)
9992 .unwrap_or_default();
9993 Ok(Value::Float(elapsed.as_secs_f64() * 1000.0))
9994 });
9995
9996 define(interp, "stopwatch_elapsed", Some(1), |_, args| {
9998 let start_ms = match &args[0] {
9999 Value::Float(f) => *f,
10000 Value::Int(n) => *n as f64,
10001 _ => {
10002 return Err(RuntimeError::new(
10003 "stopwatch_elapsed: argument must be a number",
10004 ))
10005 }
10006 };
10007 let now = std::time::SystemTime::now()
10008 .duration_since(std::time::UNIX_EPOCH)
10009 .unwrap_or_default();
10010 let now_ms = now.as_secs_f64() * 1000.0;
10011 Ok(Value::Float(now_ms - start_ms))
10012 });
10013
10014 define(interp, "compare_bench", Some(3), |interp, args| {
10016 let func1 = match &args[0] {
10017 Value::Function(f) => f.clone(),
10018 _ => {
10019 return Err(RuntimeError::new(
10020 "compare_bench: first argument must be a function",
10021 ))
10022 }
10023 };
10024 let func2 = match &args[1] {
10025 Value::Function(f) => f.clone(),
10026 _ => {
10027 return Err(RuntimeError::new(
10028 "compare_bench: second argument must be a function",
10029 ))
10030 }
10031 };
10032 let iterations = match &args[2] {
10033 Value::Int(n) => *n as usize,
10034 _ => {
10035 return Err(RuntimeError::new(
10036 "compare_bench: third argument must be an integer",
10037 ))
10038 }
10039 };
10040
10041 let start1 = std::time::Instant::now();
10042 for _ in 0..iterations {
10043 let _ = interp.call_function(&func1, vec![])?;
10044 }
10045 let time1 = start1.elapsed().as_secs_f64();
10046
10047 let start2 = std::time::Instant::now();
10048 for _ in 0..iterations {
10049 let _ = interp.call_function(&func2, vec![])?;
10050 }
10051 let time2 = start2.elapsed().as_secs_f64();
10052
10053 let mut results = std::collections::HashMap::new();
10054 results.insert("time1_ms".to_string(), Value::Float(time1 * 1000.0));
10055 results.insert("time2_ms".to_string(), Value::Float(time2 * 1000.0));
10056 results.insert("speedup".to_string(), Value::Float(time1 / time2));
10057 results.insert("iterations".to_string(), Value::Int(iterations as i64));
10058
10059 Ok(Value::Struct {
10060 name: "BenchResult".to_string(),
10061 fields: Rc::new(RefCell::new(results)),
10062 })
10063 });
10064
10065 define(interp, "memory_usage", Some(0), |_, _| Ok(Value::Int(0)));
10067}
10068
10069fn register_itertools(interp: &mut Interpreter) {
10071 define(interp, "cycle", Some(2), |_, args| {
10073 let arr = match &args[0] {
10074 Value::Array(a) => a.borrow().clone(),
10075 _ => return Err(RuntimeError::new("cycle: first argument must be an array")),
10076 };
10077 let n = match &args[1] {
10078 Value::Int(n) => *n as usize,
10079 _ => {
10080 return Err(RuntimeError::new(
10081 "cycle: second argument must be an integer",
10082 ))
10083 }
10084 };
10085
10086 if arr.is_empty() {
10087 return Ok(Value::Array(Rc::new(RefCell::new(vec![]))));
10088 }
10089
10090 let result: Vec<Value> = (0..n).map(|i| arr[i % arr.len()].clone()).collect();
10091 Ok(Value::Array(Rc::new(RefCell::new(result))))
10092 });
10093
10094 define(interp, "repeat_val", Some(2), |_, args| {
10096 let val = args[0].clone();
10097 let n = match &args[1] {
10098 Value::Int(n) => *n as usize,
10099 _ => {
10100 return Err(RuntimeError::new(
10101 "repeat_val: second argument must be an integer",
10102 ))
10103 }
10104 };
10105
10106 let result: Vec<Value> = std::iter::repeat(val).take(n).collect();
10107 Ok(Value::Array(Rc::new(RefCell::new(result))))
10108 });
10109
10110 define(interp, "take_while", Some(2), |interp, args| {
10112 let arr = match &args[0] {
10113 Value::Array(a) => a.borrow().clone(),
10114 _ => {
10115 return Err(RuntimeError::new(
10116 "take_while: first argument must be an array",
10117 ))
10118 }
10119 };
10120 let pred = match &args[1] {
10121 Value::Function(f) => f.clone(),
10122 _ => {
10123 return Err(RuntimeError::new(
10124 "take_while: second argument must be a function",
10125 ))
10126 }
10127 };
10128
10129 let mut result = Vec::new();
10130 for item in arr {
10131 let keep = interp.call_function(&pred, vec![item.clone()])?;
10132 if is_truthy(&keep) {
10133 result.push(item);
10134 } else {
10135 break;
10136 }
10137 }
10138 Ok(Value::Array(Rc::new(RefCell::new(result))))
10139 });
10140
10141 define(interp, "drop_while", Some(2), |interp, args| {
10143 let arr = match &args[0] {
10144 Value::Array(a) => a.borrow().clone(),
10145 _ => {
10146 return Err(RuntimeError::new(
10147 "drop_while: first argument must be an array",
10148 ))
10149 }
10150 };
10151 let pred = match &args[1] {
10152 Value::Function(f) => f.clone(),
10153 _ => {
10154 return Err(RuntimeError::new(
10155 "drop_while: second argument must be a function",
10156 ))
10157 }
10158 };
10159
10160 let mut dropping = true;
10161 let mut result = Vec::new();
10162 for item in arr {
10163 if dropping {
10164 let drop = interp.call_function(&pred, vec![item.clone()])?;
10165 if !is_truthy(&drop) {
10166 dropping = false;
10167 result.push(item);
10168 }
10169 } else {
10170 result.push(item);
10171 }
10172 }
10173 Ok(Value::Array(Rc::new(RefCell::new(result))))
10174 });
10175
10176 define(interp, "group_by", Some(2), |interp, args| {
10178 let arr = match &args[0] {
10179 Value::Array(a) => a.borrow().clone(),
10180 _ => {
10181 return Err(RuntimeError::new(
10182 "group_by: first argument must be an array",
10183 ))
10184 }
10185 };
10186 let key_fn = match &args[1] {
10187 Value::Function(f) => f.clone(),
10188 _ => {
10189 return Err(RuntimeError::new(
10190 "group_by: second argument must be a function",
10191 ))
10192 }
10193 };
10194
10195 let mut groups: Vec<Value> = Vec::new();
10196 let mut current_group: Vec<Value> = Vec::new();
10197 let mut current_key: Option<Value> = None;
10198
10199 for item in arr {
10200 let key = interp.call_function(&key_fn, vec![item.clone()])?;
10201 match ¤t_key {
10202 Some(k) if value_eq(k, &key) => {
10203 current_group.push(item);
10204 }
10205 _ => {
10206 if !current_group.is_empty() {
10207 groups.push(Value::Array(Rc::new(RefCell::new(current_group))));
10208 }
10209 current_group = vec![item];
10210 current_key = Some(key);
10211 }
10212 }
10213 }
10214 if !current_group.is_empty() {
10215 groups.push(Value::Array(Rc::new(RefCell::new(current_group))));
10216 }
10217
10218 Ok(Value::Array(Rc::new(RefCell::new(groups))))
10219 });
10220
10221 define(interp, "partition", Some(2), |interp, args| {
10223 let arr = match &args[0] {
10224 Value::Array(a) => a.borrow().clone(),
10225 _ => {
10226 return Err(RuntimeError::new(
10227 "partition: first argument must be an array",
10228 ))
10229 }
10230 };
10231 let pred = match &args[1] {
10232 Value::Function(f) => f.clone(),
10233 _ => {
10234 return Err(RuntimeError::new(
10235 "partition: second argument must be a function",
10236 ))
10237 }
10238 };
10239
10240 let mut true_items = Vec::new();
10241 let mut false_items = Vec::new();
10242
10243 for item in arr {
10244 let result = interp.call_function(&pred, vec![item.clone()])?;
10245 if is_truthy(&result) {
10246 true_items.push(item);
10247 } else {
10248 false_items.push(item);
10249 }
10250 }
10251
10252 Ok(Value::Tuple(Rc::new(vec![
10253 Value::Array(Rc::new(RefCell::new(true_items))),
10254 Value::Array(Rc::new(RefCell::new(false_items))),
10255 ])))
10256 });
10257
10258 define(interp, "interleave", Some(2), |_, args| {
10260 let arr1 = match &args[0] {
10261 Value::Array(a) => a.borrow().clone(),
10262 _ => {
10263 return Err(RuntimeError::new(
10264 "interleave: first argument must be an array",
10265 ))
10266 }
10267 };
10268 let arr2 = match &args[1] {
10269 Value::Array(a) => a.borrow().clone(),
10270 _ => {
10271 return Err(RuntimeError::new(
10272 "interleave: second argument must be an array",
10273 ))
10274 }
10275 };
10276
10277 let mut result = Vec::new();
10278 let mut i1 = arr1.into_iter();
10279 let mut i2 = arr2.into_iter();
10280
10281 loop {
10282 match (i1.next(), i2.next()) {
10283 (Some(a), Some(b)) => {
10284 result.push(a);
10285 result.push(b);
10286 }
10287 (Some(a), None) => {
10288 result.push(a);
10289 result.extend(i1);
10290 break;
10291 }
10292 (None, Some(b)) => {
10293 result.push(b);
10294 result.extend(i2);
10295 break;
10296 }
10297 (None, None) => break,
10298 }
10299 }
10300
10301 Ok(Value::Array(Rc::new(RefCell::new(result))))
10302 });
10303
10304 define(interp, "chunks", Some(2), |_, args| {
10306 let arr = match &args[0] {
10307 Value::Array(a) => a.borrow().clone(),
10308 _ => return Err(RuntimeError::new("chunks: first argument must be an array")),
10309 };
10310 let size = match &args[1] {
10311 Value::Int(n) if *n > 0 => *n as usize,
10312 _ => {
10313 return Err(RuntimeError::new(
10314 "chunks: second argument must be a positive integer",
10315 ))
10316 }
10317 };
10318
10319 let chunks: Vec<Value> = arr
10320 .chunks(size)
10321 .map(|chunk| Value::Array(Rc::new(RefCell::new(chunk.to_vec()))))
10322 .collect();
10323
10324 Ok(Value::Array(Rc::new(RefCell::new(chunks))))
10325 });
10326
10327 define(interp, "windows", Some(2), |_, args| {
10329 let arr = match &args[0] {
10330 Value::Array(a) => a.borrow().clone(),
10331 _ => {
10332 return Err(RuntimeError::new(
10333 "windows: first argument must be an array",
10334 ))
10335 }
10336 };
10337 let size = match &args[1] {
10338 Value::Int(n) if *n > 0 => *n as usize,
10339 _ => {
10340 return Err(RuntimeError::new(
10341 "windows: second argument must be a positive integer",
10342 ))
10343 }
10344 };
10345
10346 if arr.len() < size {
10347 return Ok(Value::Array(Rc::new(RefCell::new(vec![]))));
10348 }
10349
10350 let windows: Vec<Value> = arr
10351 .windows(size)
10352 .map(|window| Value::Array(Rc::new(RefCell::new(window.to_vec()))))
10353 .collect();
10354
10355 Ok(Value::Array(Rc::new(RefCell::new(windows))))
10356 });
10357
10358 define(interp, "scan", Some(3), |interp, args| {
10360 let arr = match &args[0] {
10361 Value::Array(a) => a.borrow().clone(),
10362 _ => return Err(RuntimeError::new("scan: first argument must be an array")),
10363 };
10364 let init = args[1].clone();
10365 let func = match &args[2] {
10366 Value::Function(f) => f.clone(),
10367 _ => return Err(RuntimeError::new("scan: third argument must be a function")),
10368 };
10369
10370 let mut results = vec![init.clone()];
10371 let mut acc = init;
10372
10373 for item in arr {
10374 acc = interp.call_function(&func, vec![acc, item])?;
10375 results.push(acc.clone());
10376 }
10377
10378 Ok(Value::Array(Rc::new(RefCell::new(results))))
10379 });
10380
10381 define(interp, "frequencies", Some(1), |_, args| {
10383 let arr = match &args[0] {
10384 Value::Array(a) => a.borrow().clone(),
10385 _ => return Err(RuntimeError::new("frequencies: argument must be an array")),
10386 };
10387
10388 let mut counts: std::collections::HashMap<String, i64> = std::collections::HashMap::new();
10389 for item in &arr {
10390 let key = format!("{}", item);
10391 *counts.entry(key).or_insert(0) += 1;
10392 }
10393
10394 let result: std::collections::HashMap<String, Value> = counts
10395 .into_iter()
10396 .map(|(k, v)| (k, Value::Int(v)))
10397 .collect();
10398
10399 Ok(Value::Map(Rc::new(RefCell::new(result))))
10400 });
10401
10402 define(interp, "dedupe", Some(1), |_, args| {
10404 let arr = match &args[0] {
10405 Value::Array(a) => a.borrow().clone(),
10406 _ => return Err(RuntimeError::new("dedupe: argument must be an array")),
10407 };
10408
10409 let mut result = Vec::new();
10410 let mut prev: Option<Value> = None;
10411
10412 for item in arr {
10413 match &prev {
10414 Some(p) if value_eq(p, &item) => continue,
10415 _ => {
10416 result.push(item.clone());
10417 prev = Some(item);
10418 }
10419 }
10420 }
10421
10422 Ok(Value::Array(Rc::new(RefCell::new(result))))
10423 });
10424
10425 define(interp, "unique", Some(1), |_, args| {
10427 let arr = match &args[0] {
10428 Value::Array(a) => a.borrow().clone(),
10429 _ => return Err(RuntimeError::new("unique: argument must be an array")),
10430 };
10431
10432 let mut seen = std::collections::HashSet::new();
10433 let mut result = Vec::new();
10434
10435 for item in arr {
10436 let key = format!("{}", item);
10437 if seen.insert(key) {
10438 result.push(item);
10439 }
10440 }
10441
10442 Ok(Value::Array(Rc::new(RefCell::new(result))))
10443 });
10444}
10445
10446fn register_ranges(interp: &mut Interpreter) {
10448 define(interp, "range_step", Some(3), |_, args| {
10450 let start = match &args[0] {
10451 Value::Int(n) => *n,
10452 Value::Float(f) => *f as i64,
10453 _ => return Err(RuntimeError::new("range_step: start must be a number")),
10454 };
10455 let end = match &args[1] {
10456 Value::Int(n) => *n,
10457 Value::Float(f) => *f as i64,
10458 _ => return Err(RuntimeError::new("range_step: end must be a number")),
10459 };
10460 let step = match &args[2] {
10461 Value::Int(n) if *n != 0 => *n,
10462 Value::Float(f) if *f != 0.0 => *f as i64,
10463 _ => {
10464 return Err(RuntimeError::new(
10465 "range_step: step must be a non-zero number",
10466 ))
10467 }
10468 };
10469
10470 let mut result = Vec::new();
10471 if step > 0 {
10472 let mut i = start;
10473 while i < end {
10474 result.push(Value::Int(i));
10475 i += step;
10476 }
10477 } else {
10478 let mut i = start;
10479 while i > end {
10480 result.push(Value::Int(i));
10481 i += step;
10482 }
10483 }
10484
10485 Ok(Value::Array(Rc::new(RefCell::new(result))))
10486 });
10487
10488 define(interp, "linspace", Some(3), |_, args| {
10490 let start = match &args[0] {
10491 Value::Int(n) => *n as f64,
10492 Value::Float(f) => *f,
10493 _ => return Err(RuntimeError::new("linspace: start must be a number")),
10494 };
10495 let end = match &args[1] {
10496 Value::Int(n) => *n as f64,
10497 Value::Float(f) => *f,
10498 _ => return Err(RuntimeError::new("linspace: end must be a number")),
10499 };
10500 let n = match &args[2] {
10501 Value::Int(n) if *n > 0 => *n as usize,
10502 _ => {
10503 return Err(RuntimeError::new(
10504 "linspace: count must be a positive integer",
10505 ))
10506 }
10507 };
10508
10509 if n == 1 {
10510 return Ok(Value::Array(Rc::new(RefCell::new(vec![Value::Float(
10511 start,
10512 )]))));
10513 }
10514
10515 let step = (end - start) / (n - 1) as f64;
10516 let result: Vec<Value> = (0..n)
10517 .map(|i| Value::Float(start + step * i as f64))
10518 .collect();
10519
10520 Ok(Value::Array(Rc::new(RefCell::new(result))))
10521 });
10522
10523 define(interp, "logspace", Some(3), |_, args| {
10525 let start_exp = match &args[0] {
10526 Value::Int(n) => *n as f64,
10527 Value::Float(f) => *f,
10528 _ => {
10529 return Err(RuntimeError::new(
10530 "logspace: start exponent must be a number",
10531 ))
10532 }
10533 };
10534 let end_exp = match &args[1] {
10535 Value::Int(n) => *n as f64,
10536 Value::Float(f) => *f,
10537 _ => return Err(RuntimeError::new("logspace: end exponent must be a number")),
10538 };
10539 let n = match &args[2] {
10540 Value::Int(n) if *n > 0 => *n as usize,
10541 _ => {
10542 return Err(RuntimeError::new(
10543 "logspace: count must be a positive integer",
10544 ))
10545 }
10546 };
10547
10548 if n == 1 {
10549 return Ok(Value::Array(Rc::new(RefCell::new(vec![Value::Float(
10550 10f64.powf(start_exp),
10551 )]))));
10552 }
10553
10554 let step = (end_exp - start_exp) / (n - 1) as f64;
10555 let result: Vec<Value> = (0..n)
10556 .map(|i| Value::Float(10f64.powf(start_exp + step * i as f64)))
10557 .collect();
10558
10559 Ok(Value::Array(Rc::new(RefCell::new(result))))
10560 });
10561
10562 define(interp, "arange", Some(3), |_, args| {
10564 let start = match &args[0] {
10565 Value::Int(n) => *n as f64,
10566 Value::Float(f) => *f,
10567 _ => return Err(RuntimeError::new("arange: start must be a number")),
10568 };
10569 let stop = match &args[1] {
10570 Value::Int(n) => *n as f64,
10571 Value::Float(f) => *f,
10572 _ => return Err(RuntimeError::new("arange: stop must be a number")),
10573 };
10574 let step = match &args[2] {
10575 Value::Int(n) if *n != 0 => *n as f64,
10576 Value::Float(f) if *f != 0.0 => *f,
10577 _ => return Err(RuntimeError::new("arange: step must be a non-zero number")),
10578 };
10579
10580 let mut result = Vec::new();
10581 if step > 0.0 {
10582 let mut x = start;
10583 while x < stop {
10584 result.push(Value::Float(x));
10585 x += step;
10586 }
10587 } else {
10588 let mut x = start;
10589 while x > stop {
10590 result.push(Value::Float(x));
10591 x += step;
10592 }
10593 }
10594
10595 Ok(Value::Array(Rc::new(RefCell::new(result))))
10596 });
10597
10598 define(interp, "geomspace", Some(3), |_, args| {
10600 let start = match &args[0] {
10601 Value::Int(n) if *n > 0 => *n as f64,
10602 Value::Float(f) if *f > 0.0 => *f,
10603 _ => {
10604 return Err(RuntimeError::new(
10605 "geomspace: start must be a positive number",
10606 ))
10607 }
10608 };
10609 let end = match &args[1] {
10610 Value::Int(n) if *n > 0 => *n as f64,
10611 Value::Float(f) if *f > 0.0 => *f,
10612 _ => {
10613 return Err(RuntimeError::new(
10614 "geomspace: end must be a positive number",
10615 ))
10616 }
10617 };
10618 let n = match &args[2] {
10619 Value::Int(n) if *n > 0 => *n as usize,
10620 _ => {
10621 return Err(RuntimeError::new(
10622 "geomspace: count must be a positive integer",
10623 ))
10624 }
10625 };
10626
10627 if n == 1 {
10628 return Ok(Value::Array(Rc::new(RefCell::new(vec![Value::Float(
10629 start,
10630 )]))));
10631 }
10632
10633 let ratio = (end / start).powf(1.0 / (n - 1) as f64);
10634 let result: Vec<Value> = (0..n)
10635 .map(|i| Value::Float(start * ratio.powi(i as i32)))
10636 .collect();
10637
10638 Ok(Value::Array(Rc::new(RefCell::new(result))))
10639 });
10640}
10641
10642fn register_bitwise(interp: &mut Interpreter) {
10644 define(interp, "bit_and", Some(2), |_, args| {
10645 let a = match &args[0] {
10646 Value::Int(n) => *n,
10647 _ => return Err(RuntimeError::new("bit_and: arguments must be integers")),
10648 };
10649 let b = match &args[1] {
10650 Value::Int(n) => *n,
10651 _ => return Err(RuntimeError::new("bit_and: arguments must be integers")),
10652 };
10653 Ok(Value::Int(a & b))
10654 });
10655
10656 define(interp, "bit_or", Some(2), |_, args| {
10657 let a = match &args[0] {
10658 Value::Int(n) => *n,
10659 _ => return Err(RuntimeError::new("bit_or: arguments must be integers")),
10660 };
10661 let b = match &args[1] {
10662 Value::Int(n) => *n,
10663 _ => return Err(RuntimeError::new("bit_or: arguments must be integers")),
10664 };
10665 Ok(Value::Int(a | b))
10666 });
10667
10668 define(interp, "bit_xor", Some(2), |_, args| {
10669 let a = match &args[0] {
10670 Value::Int(n) => *n,
10671 _ => return Err(RuntimeError::new("bit_xor: arguments must be integers")),
10672 };
10673 let b = match &args[1] {
10674 Value::Int(n) => *n,
10675 _ => return Err(RuntimeError::new("bit_xor: arguments must be integers")),
10676 };
10677 Ok(Value::Int(a ^ b))
10678 });
10679
10680 define(interp, "bit_not", Some(1), |_, args| {
10681 let a = match &args[0] {
10682 Value::Int(n) => *n,
10683 _ => return Err(RuntimeError::new("bit_not: argument must be an integer")),
10684 };
10685 Ok(Value::Int(!a))
10686 });
10687
10688 define(interp, "bit_shl", Some(2), |_, args| {
10689 let a = match &args[0] {
10690 Value::Int(n) => *n,
10691 _ => {
10692 return Err(RuntimeError::new(
10693 "bit_shl: first argument must be an integer",
10694 ))
10695 }
10696 };
10697 let b = match &args[1] {
10698 Value::Int(n) if *n >= 0 && *n < 64 => *n as u32,
10699 _ => return Err(RuntimeError::new("bit_shl: shift amount must be 0-63")),
10700 };
10701 Ok(Value::Int(a << b))
10702 });
10703
10704 define(interp, "bit_shr", Some(2), |_, args| {
10705 let a = match &args[0] {
10706 Value::Int(n) => *n,
10707 _ => {
10708 return Err(RuntimeError::new(
10709 "bit_shr: first argument must be an integer",
10710 ))
10711 }
10712 };
10713 let b = match &args[1] {
10714 Value::Int(n) if *n >= 0 && *n < 64 => *n as u32,
10715 _ => return Err(RuntimeError::new("bit_shr: shift amount must be 0-63")),
10716 };
10717 Ok(Value::Int(a >> b))
10718 });
10719
10720 define(interp, "popcount", Some(1), |_, args| {
10721 let a = match &args[0] {
10722 Value::Int(n) => *n,
10723 _ => return Err(RuntimeError::new("popcount: argument must be an integer")),
10724 };
10725 Ok(Value::Int(a.count_ones() as i64))
10726 });
10727
10728 define(interp, "leading_zeros", Some(1), |_, args| {
10729 let a = match &args[0] {
10730 Value::Int(n) => *n,
10731 _ => {
10732 return Err(RuntimeError::new(
10733 "leading_zeros: argument must be an integer",
10734 ))
10735 }
10736 };
10737 Ok(Value::Int(a.leading_zeros() as i64))
10738 });
10739
10740 define(interp, "trailing_zeros", Some(1), |_, args| {
10741 let a = match &args[0] {
10742 Value::Int(n) => *n,
10743 _ => {
10744 return Err(RuntimeError::new(
10745 "trailing_zeros: argument must be an integer",
10746 ))
10747 }
10748 };
10749 Ok(Value::Int(a.trailing_zeros() as i64))
10750 });
10751
10752 define(interp, "bit_test", Some(2), |_, args| {
10753 let a = match &args[0] {
10754 Value::Int(n) => *n,
10755 _ => {
10756 return Err(RuntimeError::new(
10757 "bit_test: first argument must be an integer",
10758 ))
10759 }
10760 };
10761 let pos = match &args[1] {
10762 Value::Int(n) if *n >= 0 && *n < 64 => *n as u32,
10763 _ => return Err(RuntimeError::new("bit_test: position must be 0-63")),
10764 };
10765 Ok(Value::Bool((a >> pos) & 1 == 1))
10766 });
10767
10768 define(interp, "bit_set", Some(2), |_, args| {
10769 let a = match &args[0] {
10770 Value::Int(n) => *n,
10771 _ => {
10772 return Err(RuntimeError::new(
10773 "bit_set: first argument must be an integer",
10774 ))
10775 }
10776 };
10777 let pos = match &args[1] {
10778 Value::Int(n) if *n >= 0 && *n < 64 => *n as u32,
10779 _ => return Err(RuntimeError::new("bit_set: position must be 0-63")),
10780 };
10781 Ok(Value::Int(a | (1 << pos)))
10782 });
10783
10784 define(interp, "bit_clear", Some(2), |_, args| {
10785 let a = match &args[0] {
10786 Value::Int(n) => *n,
10787 _ => {
10788 return Err(RuntimeError::new(
10789 "bit_clear: first argument must be an integer",
10790 ))
10791 }
10792 };
10793 let pos = match &args[1] {
10794 Value::Int(n) if *n >= 0 && *n < 64 => *n as u32,
10795 _ => return Err(RuntimeError::new("bit_clear: position must be 0-63")),
10796 };
10797 Ok(Value::Int(a & !(1 << pos)))
10798 });
10799
10800 define(interp, "bit_toggle", Some(2), |_, args| {
10801 let a = match &args[0] {
10802 Value::Int(n) => *n,
10803 _ => {
10804 return Err(RuntimeError::new(
10805 "bit_toggle: first argument must be an integer",
10806 ))
10807 }
10808 };
10809 let pos = match &args[1] {
10810 Value::Int(n) if *n >= 0 && *n < 64 => *n as u32,
10811 _ => return Err(RuntimeError::new("bit_toggle: position must be 0-63")),
10812 };
10813 Ok(Value::Int(a ^ (1 << pos)))
10814 });
10815
10816 define(interp, "to_binary", Some(1), |_, args| {
10817 let a = match &args[0] {
10818 Value::Int(n) => *n,
10819 _ => return Err(RuntimeError::new("to_binary: argument must be an integer")),
10820 };
10821 Ok(Value::String(Rc::new(format!("{:b}", a))))
10822 });
10823
10824 define(interp, "from_binary", Some(1), |_, args| {
10825 let s = match &args[0] {
10826 Value::String(s) => (**s).clone(),
10827 _ => return Err(RuntimeError::new("from_binary: argument must be a string")),
10828 };
10829 match i64::from_str_radix(&s, 2) {
10830 Ok(n) => Ok(Value::Int(n)),
10831 Err(_) => Err(RuntimeError::new("from_binary: invalid binary string")),
10832 }
10833 });
10834
10835 define(interp, "to_hex", Some(1), |_, args| {
10836 let a = match &args[0] {
10837 Value::Int(n) => *n,
10838 _ => return Err(RuntimeError::new("to_hex: argument must be an integer")),
10839 };
10840 Ok(Value::String(Rc::new(format!("{:x}", a))))
10841 });
10842
10843 define(interp, "from_hex", Some(1), |_, args| {
10844 let s = match &args[0] {
10845 Value::String(s) => s.trim_start_matches("0x").to_string(),
10846 _ => return Err(RuntimeError::new("from_hex: argument must be a string")),
10847 };
10848 match i64::from_str_radix(&s, 16) {
10849 Ok(n) => Ok(Value::Int(n)),
10850 Err(_) => Err(RuntimeError::new("from_hex: invalid hex string")),
10851 }
10852 });
10853
10854 define(interp, "to_octal", Some(1), |_, args| {
10855 let a = match &args[0] {
10856 Value::Int(n) => *n,
10857 _ => return Err(RuntimeError::new("to_octal: argument must be an integer")),
10858 };
10859 Ok(Value::String(Rc::new(format!("{:o}", a))))
10860 });
10861
10862 define(interp, "from_octal", Some(1), |_, args| {
10863 let s = match &args[0] {
10864 Value::String(s) => s.trim_start_matches("0o").to_string(),
10865 _ => return Err(RuntimeError::new("from_octal: argument must be a string")),
10866 };
10867 match i64::from_str_radix(&s, 8) {
10868 Ok(n) => Ok(Value::Int(n)),
10869 Err(_) => Err(RuntimeError::new("from_octal: invalid octal string")),
10870 }
10871 });
10872}
10873
10874fn register_format(interp: &mut Interpreter) {
10876 define(interp, "format", None, |_, args| {
10878 if args.is_empty() {
10879 return Err(RuntimeError::new(
10880 "format: requires at least a format string",
10881 ));
10882 }
10883 let template = match &args[0] {
10884 Value::String(s) => (**s).clone(),
10885 _ => return Err(RuntimeError::new("format: first argument must be a string")),
10886 };
10887 let mut result = template;
10888 for arg in &args[1..] {
10889 if let Some(pos) = result.find("{}") {
10890 result = format!("{}{}{}", &result[..pos], arg, &result[pos + 2..]);
10891 }
10892 }
10893 Ok(Value::String(Rc::new(result)))
10894 });
10895
10896 define(interp, "pad_left", Some(3), |_, args| {
10898 let s = match &args[0] {
10899 Value::String(s) => (**s).clone(),
10900 _ => {
10901 return Err(RuntimeError::new(
10902 "pad_left: first argument must be a string",
10903 ))
10904 }
10905 };
10906 let width = match &args[1] {
10907 Value::Int(n) if *n >= 0 => *n as usize,
10908 _ => {
10909 return Err(RuntimeError::new(
10910 "pad_left: width must be a non-negative integer",
10911 ))
10912 }
10913 };
10914 let pad_char = match &args[2] {
10915 Value::String(s) if !s.is_empty() => s.chars().next().unwrap(),
10916 Value::Char(c) => *c,
10917 _ => {
10918 return Err(RuntimeError::new(
10919 "pad_left: pad character must be a non-empty string or char",
10920 ))
10921 }
10922 };
10923 let char_count = s.chars().count();
10924 if char_count >= width {
10925 return Ok(Value::String(Rc::new(s)));
10926 }
10927 let padding: String = std::iter::repeat(pad_char)
10928 .take(width - char_count)
10929 .collect();
10930 Ok(Value::String(Rc::new(format!("{}{}", padding, s))))
10931 });
10932
10933 define(interp, "pad_right", Some(3), |_, args| {
10935 let s = match &args[0] {
10936 Value::String(s) => (**s).clone(),
10937 _ => {
10938 return Err(RuntimeError::new(
10939 "pad_right: first argument must be a string",
10940 ))
10941 }
10942 };
10943 let width = match &args[1] {
10944 Value::Int(n) if *n >= 0 => *n as usize,
10945 _ => {
10946 return Err(RuntimeError::new(
10947 "pad_right: width must be a non-negative integer",
10948 ))
10949 }
10950 };
10951 let pad_char = match &args[2] {
10952 Value::String(s) if !s.is_empty() => s.chars().next().unwrap(),
10953 Value::Char(c) => *c,
10954 _ => {
10955 return Err(RuntimeError::new(
10956 "pad_right: pad character must be a non-empty string or char",
10957 ))
10958 }
10959 };
10960 let char_count = s.chars().count();
10961 if char_count >= width {
10962 return Ok(Value::String(Rc::new(s)));
10963 }
10964 let padding: String = std::iter::repeat(pad_char)
10965 .take(width - char_count)
10966 .collect();
10967 Ok(Value::String(Rc::new(format!("{}{}", s, padding))))
10968 });
10969
10970 define(interp, "center", Some(3), |_, args| {
10972 let s = match &args[0] {
10973 Value::String(s) => (**s).clone(),
10974 _ => return Err(RuntimeError::new("center: first argument must be a string")),
10975 };
10976 let width = match &args[1] {
10977 Value::Int(n) if *n >= 0 => *n as usize,
10978 _ => {
10979 return Err(RuntimeError::new(
10980 "center: width must be a non-negative integer",
10981 ))
10982 }
10983 };
10984 let pad_char = match &args[2] {
10985 Value::String(s) if !s.is_empty() => s.chars().next().unwrap(),
10986 Value::Char(c) => *c,
10987 _ => {
10988 return Err(RuntimeError::new(
10989 "center: pad character must be a non-empty string or char",
10990 ))
10991 }
10992 };
10993 let char_count = s.chars().count();
10994 if char_count >= width {
10995 return Ok(Value::String(Rc::new(s)));
10996 }
10997 let total_padding = width - char_count;
10998 let left_padding = total_padding / 2;
10999 let right_padding = total_padding - left_padding;
11000 let left: String = std::iter::repeat(pad_char).take(left_padding).collect();
11001 let right: String = std::iter::repeat(pad_char).take(right_padding).collect();
11002 Ok(Value::String(Rc::new(format!("{}{}{}", left, s, right))))
11003 });
11004
11005 define(interp, "number_format", Some(1), |_, args| {
11007 let n = match &args[0] {
11008 Value::Int(n) => *n,
11009 Value::Float(f) => *f as i64,
11010 _ => {
11011 return Err(RuntimeError::new(
11012 "number_format: argument must be a number",
11013 ))
11014 }
11015 };
11016 let s = n.abs().to_string();
11017 let mut result = String::new();
11018 for (i, c) in s.chars().rev().enumerate() {
11019 if i > 0 && i % 3 == 0 {
11020 result.push(',');
11021 }
11022 result.push(c);
11023 }
11024 let formatted: String = result.chars().rev().collect();
11025 if n < 0 {
11026 Ok(Value::String(Rc::new(format!("-{}", formatted))))
11027 } else {
11028 Ok(Value::String(Rc::new(formatted)))
11029 }
11030 });
11031
11032 define(interp, "ordinal", Some(1), |_, args| {
11034 let n = match &args[0] {
11035 Value::Int(n) => *n,
11036 _ => return Err(RuntimeError::new("ordinal: argument must be an integer")),
11037 };
11038 let suffix = match (n % 10, n % 100) {
11039 (1, 11) => "th",
11040 (2, 12) => "th",
11041 (3, 13) => "th",
11042 (1, _) => "st",
11043 (2, _) => "nd",
11044 (3, _) => "rd",
11045 _ => "th",
11046 };
11047 Ok(Value::String(Rc::new(format!("{}{}", n, suffix))))
11048 });
11049
11050 define(interp, "pluralize", Some(3), |_, args| {
11052 let count = match &args[0] {
11053 Value::Int(n) => *n,
11054 _ => {
11055 return Err(RuntimeError::new(
11056 "pluralize: first argument must be an integer",
11057 ))
11058 }
11059 };
11060 let singular = match &args[1] {
11061 Value::String(s) => s.clone(),
11062 _ => {
11063 return Err(RuntimeError::new(
11064 "pluralize: second argument must be a string",
11065 ))
11066 }
11067 };
11068 let plural = match &args[2] {
11069 Value::String(s) => s.clone(),
11070 _ => {
11071 return Err(RuntimeError::new(
11072 "pluralize: third argument must be a string",
11073 ))
11074 }
11075 };
11076 if count == 1 || count == -1 {
11077 Ok(Value::String(singular))
11078 } else {
11079 Ok(Value::String(plural))
11080 }
11081 });
11082
11083 define(interp, "truncate", Some(2), |_, args| {
11085 let s = match &args[0] {
11086 Value::String(s) => (**s).clone(),
11087 _ => {
11088 return Err(RuntimeError::new(
11089 "truncate: first argument must be a string",
11090 ))
11091 }
11092 };
11093 let max_len = match &args[1] {
11094 Value::Int(n) if *n >= 0 => *n as usize,
11095 _ => {
11096 return Err(RuntimeError::new(
11097 "truncate: max length must be a non-negative integer",
11098 ))
11099 }
11100 };
11101 let char_count = s.chars().count();
11102 if char_count <= max_len {
11103 return Ok(Value::String(Rc::new(s)));
11104 }
11105 if max_len <= 3 {
11106 return Ok(Value::String(Rc::new(s.chars().take(max_len).collect())));
11107 }
11108 let truncated: String = s.chars().take(max_len - 3).collect();
11109 Ok(Value::String(Rc::new(format!("{}...", truncated))))
11110 });
11111
11112 define(interp, "word_wrap", Some(2), |_, args| {
11114 let s = match &args[0] {
11115 Value::String(s) => (**s).clone(),
11116 _ => {
11117 return Err(RuntimeError::new(
11118 "word_wrap: first argument must be a string",
11119 ))
11120 }
11121 };
11122 let width = match &args[1] {
11123 Value::Int(n) if *n > 0 => *n as usize,
11124 _ => {
11125 return Err(RuntimeError::new(
11126 "word_wrap: width must be a positive integer",
11127 ))
11128 }
11129 };
11130 let mut result = String::new();
11131 let mut line_len = 0;
11132 for word in s.split_whitespace() {
11133 if line_len > 0 && line_len + 1 + word.len() > width {
11134 result.push('\n');
11135 line_len = 0;
11136 } else if line_len > 0 {
11137 result.push(' ');
11138 line_len += 1;
11139 }
11140 result.push_str(word);
11141 line_len += word.len();
11142 }
11143 Ok(Value::String(Rc::new(result)))
11144 });
11145
11146 define(interp, "snake_case", Some(1), |_, args| {
11148 let s = match &args[0] {
11149 Value::String(s) => (**s).clone(),
11150 _ => return Err(RuntimeError::new("snake_case: argument must be a string")),
11151 };
11152 let mut result = String::new();
11153 for (i, c) in s.chars().enumerate() {
11154 if c.is_uppercase() {
11155 if i > 0 {
11156 result.push('_');
11157 }
11158 result.push(c.to_lowercase().next().unwrap());
11159 } else if c == ' ' || c == '-' {
11160 result.push('_');
11161 } else {
11162 result.push(c);
11163 }
11164 }
11165 Ok(Value::String(Rc::new(result)))
11166 });
11167
11168 define(interp, "camel_case", Some(1), |_, args| {
11170 let s = match &args[0] {
11171 Value::String(s) => (**s).clone(),
11172 _ => return Err(RuntimeError::new("camel_case: argument must be a string")),
11173 };
11174 let mut result = String::new();
11175 let mut capitalize_next = false;
11176 for (i, c) in s.chars().enumerate() {
11177 if c == '_' || c == '-' || c == ' ' {
11178 capitalize_next = true;
11179 } else if capitalize_next {
11180 result.push(c.to_uppercase().next().unwrap());
11181 capitalize_next = false;
11182 } else if i == 0 {
11183 result.push(c.to_lowercase().next().unwrap());
11184 } else {
11185 result.push(c);
11186 }
11187 }
11188 Ok(Value::String(Rc::new(result)))
11189 });
11190
11191 define(interp, "kebab_case", Some(1), |_, args| {
11193 let s = match &args[0] {
11194 Value::String(s) => (**s).clone(),
11195 _ => return Err(RuntimeError::new("kebab_case: argument must be a string")),
11196 };
11197 let mut result = String::new();
11198 for (i, c) in s.chars().enumerate() {
11199 if c.is_uppercase() {
11200 if i > 0 {
11201 result.push('-');
11202 }
11203 result.push(c.to_lowercase().next().unwrap());
11204 } else if c == '_' || c == ' ' {
11205 result.push('-');
11206 } else {
11207 result.push(c);
11208 }
11209 }
11210 Ok(Value::String(Rc::new(result)))
11211 });
11212
11213 define(interp, "title_case", Some(1), |_, args| {
11215 let s = match &args[0] {
11216 Value::String(s) => (**s).clone(),
11217 _ => return Err(RuntimeError::new("title_case: argument must be a string")),
11218 };
11219 let result: String = s
11220 .split_whitespace()
11221 .map(|word| {
11222 let mut chars = word.chars();
11223 match chars.next() {
11224 None => String::new(),
11225 Some(first) => {
11226 first.to_uppercase().collect::<String>() + &chars.as_str().to_lowercase()
11227 }
11228 }
11229 })
11230 .collect::<Vec<_>>()
11231 .join(" ");
11232 Ok(Value::String(Rc::new(result)))
11233 });
11234}
11235
11236fn register_pattern(interp: &mut Interpreter) {
11244 define(interp, "type_of", Some(1), |_, args| {
11248 let type_name = match &args[0] {
11249 Value::Null => "null",
11250 Value::Bool(_) => "bool",
11251 Value::Int(_) => "int",
11252 Value::Float(_) => "float",
11253 Value::String(_) => "string",
11254 Value::Char(_) => "char",
11255 Value::Array(_) => "array",
11256 Value::Tuple(_) => "tuple",
11257 Value::Map(_) => "map",
11258 Value::Set(_) => "set",
11259 Value::Struct { name, .. } => {
11260 return Ok(Value::String(Rc::new(format!("struct:{}", name))))
11261 }
11262 Value::Variant {
11263 enum_name,
11264 variant_name,
11265 ..
11266 } => {
11267 return Ok(Value::String(Rc::new(format!(
11268 "{}::{}",
11269 enum_name, variant_name
11270 ))))
11271 }
11272 Value::Function(_) => "function",
11273 Value::BuiltIn(_) => "builtin",
11274 Value::Ref(_) => "ref",
11275 Value::Infinity => "infinity",
11276 Value::Empty => "empty",
11277 Value::Evidential { .. } => "evidential",
11278 Value::Affective { .. } => "affective",
11279 Value::Channel(_) => "channel",
11280 Value::ThreadHandle(_) => "thread",
11281 Value::Actor(_) => "actor",
11282 Value::Future(_) => "future",
11283 Value::VariantConstructor { .. } => "variant_constructor",
11284 Value::DefaultConstructor { .. } => "default_constructor",
11285 Value::Range { .. } => "range",
11286 };
11287 Ok(Value::String(Rc::new(type_name.to_string())))
11288 });
11289
11290 define(interp, "is_type", Some(2), |_, args| {
11292 let type_name = match &args[1] {
11293 Value::String(s) => s.to_lowercase(),
11294 _ => {
11295 return Err(RuntimeError::new(
11296 "is_type: second argument must be type name string",
11297 ))
11298 }
11299 };
11300 let matches = match (&args[0], type_name.as_str()) {
11301 (Value::Null, "null") => true,
11302 (Value::Bool(_), "bool") => true,
11303 (Value::Int(_), "int") | (Value::Int(_), "integer") => true,
11304 (Value::Float(_), "float") | (Value::Float(_), "number") => true,
11305 (Value::Int(_), "number") => true,
11306 (Value::String(_), "string") => true,
11307 (Value::Array(_), "array") | (Value::Array(_), "list") => true,
11308 (Value::Tuple(_), "tuple") => true,
11309 (Value::Map(_), "map") | (Value::Map(_), "dict") | (Value::Map(_), "object") => true,
11310 (Value::Set(_), "set") => true,
11311 (Value::Function(_), "function") | (Value::Function(_), "fn") => true,
11312 (Value::BuiltIn(_), "function") | (Value::BuiltIn(_), "builtin") => true,
11313 (Value::Struct { name, .. }, t) => t == "struct" || t == &name.to_lowercase(),
11314 (Value::Variant { enum_name, .. }, t) => {
11315 t == "variant" || t == "enum" || t == &enum_name.to_lowercase()
11316 }
11317 (Value::Channel(_), "channel") => true,
11318 (Value::ThreadHandle(_), "thread") => true,
11319 (Value::Actor(_), "actor") => true,
11320 (Value::Future(_), "future") => true,
11321 _ => false,
11322 };
11323 Ok(Value::Bool(matches))
11324 });
11325
11326 define(interp, "is_null", Some(1), |_, args| {
11328 Ok(Value::Bool(matches!(&args[0], Value::Null)))
11329 });
11330 define(interp, "is_bool", Some(1), |_, args| {
11331 Ok(Value::Bool(matches!(&args[0], Value::Bool(_))))
11332 });
11333 define(interp, "is_int", Some(1), |_, args| {
11334 Ok(Value::Bool(matches!(&args[0], Value::Int(_))))
11335 });
11336 define(interp, "is_float", Some(1), |_, args| {
11337 Ok(Value::Bool(matches!(&args[0], Value::Float(_))))
11338 });
11339 define(interp, "is_number", Some(1), |_, args| {
11340 Ok(Value::Bool(matches!(
11341 &args[0],
11342 Value::Int(_) | Value::Float(_)
11343 )))
11344 });
11345 define(interp, "is_string", Some(1), |_, args| {
11346 Ok(Value::Bool(matches!(&args[0], Value::String(_))))
11347 });
11348 define(interp, "is_array", Some(1), |_, args| {
11349 Ok(Value::Bool(matches!(&args[0], Value::Array(_))))
11350 });
11351 define(interp, "is_tuple", Some(1), |_, args| {
11352 Ok(Value::Bool(matches!(&args[0], Value::Tuple(_))))
11353 });
11354 define(interp, "is_map", Some(1), |_, args| {
11355 Ok(Value::Bool(matches!(&args[0], Value::Map(_))))
11356 });
11357 define(interp, "is_set", Some(1), |_, args| {
11358 Ok(Value::Bool(matches!(&args[0], Value::Set(_))))
11359 });
11360 define(interp, "is_function", Some(1), |_, args| {
11361 Ok(Value::Bool(matches!(
11362 &args[0],
11363 Value::Function(_) | Value::BuiltIn(_)
11364 )))
11365 });
11366 define(interp, "is_struct", Some(1), |_, args| {
11367 Ok(Value::Bool(matches!(&args[0], Value::Struct { .. })))
11368 });
11369 define(interp, "is_variant", Some(1), |_, args| {
11370 Ok(Value::Bool(matches!(&args[0], Value::Variant { .. })))
11371 });
11372 define(interp, "is_future", Some(1), |_, args| {
11373 Ok(Value::Bool(matches!(&args[0], Value::Future(_))))
11374 });
11375 define(interp, "is_channel", Some(1), |_, args| {
11376 Ok(Value::Bool(matches!(&args[0], Value::Channel(_))))
11377 });
11378
11379 define(interp, "is_empty", Some(1), |_, args| {
11381 let empty = match &args[0] {
11382 Value::Null => true,
11383 Value::String(s) => s.is_empty(),
11384 Value::Array(a) => a.borrow().is_empty(),
11385 Value::Tuple(t) => t.is_empty(),
11386 Value::Map(m) => m.borrow().is_empty(),
11387 Value::Set(s) => s.borrow().is_empty(),
11388 _ => false,
11389 };
11390 Ok(Value::Bool(empty))
11391 });
11392
11393 define(interp, "match_regex", Some(2), |_, args| {
11397 let text = match &args[0] {
11398 Value::String(s) => (**s).clone(),
11399 _ => {
11400 return Err(RuntimeError::new(
11401 "match_regex: first argument must be a string",
11402 ))
11403 }
11404 };
11405 let pattern = match &args[1] {
11406 Value::String(s) => (**s).clone(),
11407 _ => {
11408 return Err(RuntimeError::new(
11409 "match_regex: second argument must be a regex pattern string",
11410 ))
11411 }
11412 };
11413
11414 let re = match Regex::new(&pattern) {
11415 Ok(r) => r,
11416 Err(e) => {
11417 return Err(RuntimeError::new(format!(
11418 "match_regex: invalid regex: {}",
11419 e
11420 )))
11421 }
11422 };
11423
11424 match re.captures(&text) {
11425 Some(caps) => {
11426 let mut captures: Vec<Value> = Vec::new();
11427 for i in 0..caps.len() {
11428 if let Some(m) = caps.get(i) {
11429 captures.push(Value::String(Rc::new(m.as_str().to_string())));
11430 } else {
11431 captures.push(Value::Null);
11432 }
11433 }
11434 Ok(Value::Array(Rc::new(RefCell::new(captures))))
11435 }
11436 None => Ok(Value::Null),
11437 }
11438 });
11439
11440 define(interp, "match_all_regex", Some(2), |_, args| {
11442 let text = match &args[0] {
11443 Value::String(s) => (**s).clone(),
11444 _ => {
11445 return Err(RuntimeError::new(
11446 "match_all_regex: first argument must be a string",
11447 ))
11448 }
11449 };
11450 let pattern = match &args[1] {
11451 Value::String(s) => (**s).clone(),
11452 _ => {
11453 return Err(RuntimeError::new(
11454 "match_all_regex: second argument must be a regex pattern string",
11455 ))
11456 }
11457 };
11458
11459 let re = match Regex::new(&pattern) {
11460 Ok(r) => r,
11461 Err(e) => {
11462 return Err(RuntimeError::new(format!(
11463 "match_all_regex: invalid regex: {}",
11464 e
11465 )))
11466 }
11467 };
11468
11469 let matches: Vec<Value> = re
11470 .find_iter(&text)
11471 .map(|m| Value::String(Rc::new(m.as_str().to_string())))
11472 .collect();
11473 Ok(Value::Array(Rc::new(RefCell::new(matches))))
11474 });
11475
11476 define(interp, "capture_named", Some(2), |_, args| {
11478 let text = match &args[0] {
11479 Value::String(s) => (**s).clone(),
11480 _ => {
11481 return Err(RuntimeError::new(
11482 "capture_named: first argument must be a string",
11483 ))
11484 }
11485 };
11486 let pattern = match &args[1] {
11487 Value::String(s) => (**s).clone(),
11488 _ => {
11489 return Err(RuntimeError::new(
11490 "capture_named: second argument must be a regex pattern string",
11491 ))
11492 }
11493 };
11494
11495 let re = match Regex::new(&pattern) {
11496 Ok(r) => r,
11497 Err(e) => {
11498 return Err(RuntimeError::new(format!(
11499 "capture_named: invalid regex: {}",
11500 e
11501 )))
11502 }
11503 };
11504
11505 match re.captures(&text) {
11506 Some(caps) => {
11507 let mut result: HashMap<String, Value> = HashMap::new();
11508 for name in re.capture_names().flatten() {
11509 if let Some(m) = caps.name(name) {
11510 result.insert(
11511 name.to_string(),
11512 Value::String(Rc::new(m.as_str().to_string())),
11513 );
11514 }
11515 }
11516 Ok(Value::Map(Rc::new(RefCell::new(result))))
11517 }
11518 None => Ok(Value::Null),
11519 }
11520 });
11521
11522 define(interp, "match_struct", Some(2), |_, args| {
11526 let expected_name = match &args[1] {
11527 Value::String(s) => (**s).clone(),
11528 _ => {
11529 return Err(RuntimeError::new(
11530 "match_struct: second argument must be struct name string",
11531 ))
11532 }
11533 };
11534 match &args[0] {
11535 Value::Struct { name, .. } => Ok(Value::Bool(name == &expected_name)),
11536 _ => Ok(Value::Bool(false)),
11537 }
11538 });
11539
11540 define(interp, "match_variant", Some(3), |_, args| {
11542 let expected_enum = match &args[1] {
11543 Value::String(s) => (**s).clone(),
11544 _ => {
11545 return Err(RuntimeError::new(
11546 "match_variant: second argument must be enum name string",
11547 ))
11548 }
11549 };
11550 let expected_variant = match &args[2] {
11551 Value::String(s) => (**s).clone(),
11552 _ => {
11553 return Err(RuntimeError::new(
11554 "match_variant: third argument must be variant name string",
11555 ))
11556 }
11557 };
11558 match &args[0] {
11559 Value::Variant {
11560 enum_name,
11561 variant_name,
11562 ..
11563 } => Ok(Value::Bool(
11564 enum_name == &expected_enum && variant_name == &expected_variant,
11565 )),
11566 _ => Ok(Value::Bool(false)),
11567 }
11568 });
11569
11570 define(interp, "get_field", Some(2), |_, args| {
11572 let field_name = match &args[1] {
11573 Value::String(s) => (**s).clone(),
11574 _ => {
11575 return Err(RuntimeError::new(
11576 "get_field: second argument must be field name string",
11577 ))
11578 }
11579 };
11580 match &args[0] {
11581 Value::Struct { fields, .. } => Ok(fields
11582 .borrow()
11583 .get(&field_name)
11584 .cloned()
11585 .unwrap_or(Value::Null)),
11586 Value::Map(m) => Ok(m.borrow().get(&field_name).cloned().unwrap_or(Value::Null)),
11587 _ => Ok(Value::Null),
11588 }
11589 });
11590
11591 define(interp, "has_field", Some(2), |_, args| {
11593 let field_name = match &args[1] {
11594 Value::String(s) => (**s).clone(),
11595 _ => {
11596 return Err(RuntimeError::new(
11597 "has_field: second argument must be field name string",
11598 ))
11599 }
11600 };
11601 match &args[0] {
11602 Value::Struct { fields, .. } => {
11603 Ok(Value::Bool(fields.borrow().contains_key(&field_name)))
11604 }
11605 Value::Map(m) => Ok(Value::Bool(m.borrow().contains_key(&field_name))),
11606 _ => Ok(Value::Bool(false)),
11607 }
11608 });
11609
11610 define(interp, "get_fields", Some(1), |_, args| {
11612 let fields: Vec<Value> = match &args[0] {
11613 Value::Struct { fields, .. } => fields
11614 .borrow()
11615 .keys()
11616 .map(|k| Value::String(Rc::new(k.clone())))
11617 .collect(),
11618 Value::Map(m) => m
11619 .borrow()
11620 .keys()
11621 .map(|k| Value::String(Rc::new(k.clone())))
11622 .collect(),
11623 _ => {
11624 return Err(RuntimeError::new(
11625 "get_fields: argument must be struct or map",
11626 ))
11627 }
11628 };
11629 Ok(Value::Array(Rc::new(RefCell::new(fields))))
11630 });
11631
11632 define(interp, "struct_name", Some(1), |_, args| match &args[0] {
11634 Value::Struct { name, .. } => Ok(Value::String(Rc::new(name.clone()))),
11635 _ => Ok(Value::Null),
11636 });
11637
11638 define(interp, "variant_name", Some(1), |_, args| match &args[0] {
11640 Value::Variant { variant_name, .. } => Ok(Value::String(Rc::new(variant_name.clone()))),
11641 _ => Ok(Value::Null),
11642 });
11643
11644 define(interp, "variant_data", Some(1), |_, args| match &args[0] {
11646 Value::Variant { fields, .. } => match fields {
11647 Some(f) => Ok(Value::Array(Rc::new(RefCell::new((**f).clone())))),
11648 None => Ok(Value::Null),
11649 },
11650 _ => Ok(Value::Null),
11651 });
11652
11653 define(interp, "guard", Some(2), |_, args| {
11657 if is_truthy(&args[0]) {
11658 Ok(args[1].clone())
11659 } else {
11660 Ok(Value::Null)
11661 }
11662 });
11663
11664 define(interp, "when", Some(2), |interp, args| {
11666 if is_truthy(&args[0]) {
11667 match &args[1] {
11668 Value::Function(f) => interp.call_function(f, vec![]),
11669 other => Ok(other.clone()),
11670 }
11671 } else {
11672 Ok(Value::Null)
11673 }
11674 });
11675
11676 define(interp, "unless", Some(2), |interp, args| {
11678 if !is_truthy(&args[0]) {
11679 match &args[1] {
11680 Value::Function(f) => interp.call_function(f, vec![]),
11681 other => Ok(other.clone()),
11682 }
11683 } else {
11684 Ok(Value::Null)
11685 }
11686 });
11687
11688 define(interp, "cond", Some(1), |interp, args| {
11691 let clauses = match &args[0] {
11692 Value::Array(a) => a.borrow().clone(),
11693 _ => {
11694 return Err(RuntimeError::new(
11695 "cond: argument must be array of [condition, value] pairs",
11696 ))
11697 }
11698 };
11699
11700 for clause in clauses {
11701 let pair = match &clause {
11702 Value::Array(a) => a.borrow().clone(),
11703 Value::Tuple(t) => (**t).clone(),
11704 _ => {
11705 return Err(RuntimeError::new(
11706 "cond: each clause must be [condition, value] pair",
11707 ))
11708 }
11709 };
11710 if pair.len() != 2 {
11711 return Err(RuntimeError::new(
11712 "cond: each clause must have exactly 2 elements",
11713 ));
11714 }
11715
11716 if is_truthy(&pair[0]) {
11717 return match &pair[1] {
11718 Value::Function(f) => interp.call_function(f, vec![]),
11719 other => Ok(other.clone()),
11720 };
11721 }
11722 }
11723 Ok(Value::Null)
11724 });
11725
11726 define(interp, "case", Some(2), |interp, args| {
11729 let value = &args[0];
11730 let clauses = match &args[1] {
11731 Value::Array(a) => a.borrow().clone(),
11732 _ => {
11733 return Err(RuntimeError::new(
11734 "case: second argument must be array of [pattern, result] pairs",
11735 ))
11736 }
11737 };
11738
11739 for clause in clauses {
11740 let pair = match &clause {
11741 Value::Array(a) => a.borrow().clone(),
11742 Value::Tuple(t) => (**t).clone(),
11743 _ => {
11744 return Err(RuntimeError::new(
11745 "case: each clause must be [pattern, result] pair",
11746 ))
11747 }
11748 };
11749 if pair.len() != 2 {
11750 return Err(RuntimeError::new(
11751 "case: each clause must have exactly 2 elements",
11752 ));
11753 }
11754
11755 if value_eq(value, &pair[0]) {
11756 return match &pair[1] {
11757 Value::Function(f) => interp.call_function(f, vec![value.clone()]),
11758 other => Ok(other.clone()),
11759 };
11760 }
11761 }
11762 Ok(Value::Null)
11763 });
11764
11765 define(interp, "destructure_array", Some(2), |_, args| {
11769 let arr = match &args[0] {
11770 Value::Array(a) => a.borrow().clone(),
11771 Value::Tuple(t) => (**t).clone(),
11772 _ => {
11773 return Err(RuntimeError::new(
11774 "destructure_array: first argument must be array or tuple",
11775 ))
11776 }
11777 };
11778 let indices = match &args[1] {
11779 Value::Array(a) => a.borrow().clone(),
11780 _ => {
11781 return Err(RuntimeError::new(
11782 "destructure_array: second argument must be array of indices",
11783 ))
11784 }
11785 };
11786
11787 let mut result = Vec::new();
11788 for idx in indices {
11789 match idx {
11790 Value::Int(i) => {
11791 let i = if i < 0 { arr.len() as i64 + i } else { i } as usize;
11792 result.push(arr.get(i).cloned().unwrap_or(Value::Null));
11793 }
11794 _ => result.push(Value::Null),
11795 }
11796 }
11797 Ok(Value::Array(Rc::new(RefCell::new(result))))
11798 });
11799
11800 define(interp, "destructure_map", Some(2), |_, args| {
11802 let map = match &args[0] {
11803 Value::Map(m) => m.borrow().clone(),
11804 Value::Struct { fields, .. } => fields.borrow().clone(),
11805 _ => {
11806 return Err(RuntimeError::new(
11807 "destructure_map: first argument must be map or struct",
11808 ))
11809 }
11810 };
11811 let keys = match &args[1] {
11812 Value::Array(a) => a.borrow().clone(),
11813 _ => {
11814 return Err(RuntimeError::new(
11815 "destructure_map: second argument must be array of keys",
11816 ))
11817 }
11818 };
11819
11820 let mut result = Vec::new();
11821 for key in keys {
11822 match key {
11823 Value::String(k) => {
11824 result.push(map.get(&*k).cloned().unwrap_or(Value::Null));
11825 }
11826 _ => result.push(Value::Null),
11827 }
11828 }
11829 Ok(Value::Array(Rc::new(RefCell::new(result))))
11830 });
11831
11832 define(interp, "head_tail", Some(1), |_, args| {
11834 let arr = match &args[0] {
11835 Value::Array(a) => a.borrow().clone(),
11836 _ => return Err(RuntimeError::new("head_tail: argument must be array")),
11837 };
11838
11839 if arr.is_empty() {
11840 Ok(Value::Tuple(Rc::new(vec![
11841 Value::Null,
11842 Value::Array(Rc::new(RefCell::new(vec![]))),
11843 ])))
11844 } else {
11845 let head = arr[0].clone();
11846 let tail = arr[1..].to_vec();
11847 Ok(Value::Tuple(Rc::new(vec![
11848 head,
11849 Value::Array(Rc::new(RefCell::new(tail))),
11850 ])))
11851 }
11852 });
11853
11854 define(interp, "init_last", Some(1), |_, args| {
11856 let arr = match &args[0] {
11857 Value::Array(a) => a.borrow().clone(),
11858 _ => return Err(RuntimeError::new("init_last: argument must be array")),
11859 };
11860
11861 if arr.is_empty() {
11862 Ok(Value::Tuple(Rc::new(vec![
11863 Value::Array(Rc::new(RefCell::new(vec![]))),
11864 Value::Null,
11865 ])))
11866 } else {
11867 let last = arr[arr.len() - 1].clone();
11868 let init = arr[..arr.len() - 1].to_vec();
11869 Ok(Value::Tuple(Rc::new(vec![
11870 Value::Array(Rc::new(RefCell::new(init))),
11871 last,
11872 ])))
11873 }
11874 });
11875
11876 define(interp, "split_at", Some(2), |_, args| {
11878 let arr = match &args[0] {
11879 Value::Array(a) => a.borrow().clone(),
11880 _ => return Err(RuntimeError::new("split_at: first argument must be array")),
11881 };
11882 let idx = match &args[1] {
11883 Value::Int(i) => *i as usize,
11884 _ => {
11885 return Err(RuntimeError::new(
11886 "split_at: second argument must be integer",
11887 ))
11888 }
11889 };
11890
11891 let idx = idx.min(arr.len());
11892 let left = arr[..idx].to_vec();
11893 let right = arr[idx..].to_vec();
11894 Ok(Value::Tuple(Rc::new(vec![
11895 Value::Array(Rc::new(RefCell::new(left))),
11896 Value::Array(Rc::new(RefCell::new(right))),
11897 ])))
11898 });
11899
11900 define(interp, "unwrap_or", Some(2), |_, args| {
11904 if matches!(&args[0], Value::Null) {
11905 Ok(args[1].clone())
11906 } else {
11907 Ok(args[0].clone())
11908 }
11909 });
11910
11911 define(interp, "unwrap_or_else", Some(2), |interp, args| {
11913 if matches!(&args[0], Value::Null) {
11914 match &args[1] {
11915 Value::Function(f) => interp.call_function(f, vec![]),
11916 other => Ok(other.clone()),
11917 }
11918 } else {
11919 Ok(args[0].clone())
11920 }
11921 });
11922
11923 define(interp, "map_or", Some(3), |interp, args| {
11925 if matches!(&args[0], Value::Null) {
11926 Ok(args[1].clone())
11927 } else {
11928 match &args[2] {
11929 Value::Function(f) => interp.call_function(f, vec![args[0].clone()]),
11930 _ => Err(RuntimeError::new(
11931 "map_or: third argument must be a function",
11932 )),
11933 }
11934 }
11935 });
11936
11937 define(interp, "coalesce", Some(1), |_, args| {
11939 let values = match &args[0] {
11940 Value::Array(a) => a.borrow().clone(),
11941 _ => return Err(RuntimeError::new("coalesce: argument must be array")),
11942 };
11943
11944 for v in values {
11945 if !matches!(v, Value::Null) {
11946 return Ok(v);
11947 }
11948 }
11949 Ok(Value::Null)
11950 });
11951
11952 define(interp, "deep_eq", Some(2), |_, args| {
11956 Ok(Value::Bool(deep_value_eq(&args[0], &args[1])))
11957 });
11958
11959 define(interp, "same_type", Some(2), |_, args| {
11961 let same = match (&args[0], &args[1]) {
11962 (Value::Null, Value::Null) => true,
11963 (Value::Bool(_), Value::Bool(_)) => true,
11964 (Value::Int(_), Value::Int(_)) => true,
11965 (Value::Float(_), Value::Float(_)) => true,
11966 (Value::String(_), Value::String(_)) => true,
11967 (Value::Array(_), Value::Array(_)) => true,
11968 (Value::Tuple(_), Value::Tuple(_)) => true,
11969 (Value::Map(_), Value::Map(_)) => true,
11970 (Value::Set(_), Value::Set(_)) => true,
11971 (Value::Function(_), Value::Function(_)) => true,
11972 (Value::BuiltIn(_), Value::BuiltIn(_)) => true,
11973 (Value::Struct { name: n1, .. }, Value::Struct { name: n2, .. }) => n1 == n2,
11974 (Value::Variant { enum_name: e1, .. }, Value::Variant { enum_name: e2, .. }) => {
11975 e1 == e2
11976 }
11977 _ => false,
11978 };
11979 Ok(Value::Bool(same))
11980 });
11981
11982 define(interp, "compare", Some(2), |_, args| {
11984 let cmp = match (&args[0], &args[1]) {
11985 (Value::Int(a), Value::Int(b)) => a.cmp(b),
11986 (Value::Float(a), Value::Float(b)) => {
11987 a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal)
11988 }
11989 (Value::Int(a), Value::Float(b)) => (*a as f64)
11990 .partial_cmp(b)
11991 .unwrap_or(std::cmp::Ordering::Equal),
11992 (Value::Float(a), Value::Int(b)) => a
11993 .partial_cmp(&(*b as f64))
11994 .unwrap_or(std::cmp::Ordering::Equal),
11995 (Value::String(a), Value::String(b)) => a.cmp(b),
11996 _ => {
11997 return Err(RuntimeError::new(
11998 "compare: can only compare numbers or strings",
11999 ))
12000 }
12001 };
12002 Ok(Value::Int(match cmp {
12003 std::cmp::Ordering::Less => -1,
12004 std::cmp::Ordering::Equal => 0,
12005 std::cmp::Ordering::Greater => 1,
12006 }))
12007 });
12008
12009 define(interp, "between", Some(3), |_, args| {
12011 let in_range = match (&args[0], &args[1], &args[2]) {
12012 (Value::Int(v), Value::Int(min), Value::Int(max)) => v >= min && v <= max,
12013 (Value::Float(v), Value::Float(min), Value::Float(max)) => v >= min && v <= max,
12014 (Value::Int(v), Value::Int(min), Value::Float(max)) => {
12015 (*v as f64) >= (*min as f64) && (*v as f64) <= *max
12016 }
12017 (Value::Int(v), Value::Float(min), Value::Int(max)) => {
12018 (*v as f64) >= *min && (*v as f64) <= (*max as f64)
12019 }
12020 (Value::Float(v), Value::Int(min), Value::Int(max)) => {
12021 *v >= (*min as f64) && *v <= (*max as f64)
12022 }
12023 (Value::String(v), Value::String(min), Value::String(max)) => v >= min && v <= max,
12024 _ => {
12025 return Err(RuntimeError::new(
12026 "between: arguments must be comparable (numbers or strings)",
12027 ))
12028 }
12029 };
12030 Ok(Value::Bool(in_range))
12031 });
12032
12033 define(interp, "clamp", Some(3), |_, args| {
12035 match (&args[0], &args[1], &args[2]) {
12036 (Value::Int(v), Value::Int(min), Value::Int(max)) => {
12037 Ok(Value::Int((*v).max(*min).min(*max)))
12038 }
12039 (Value::Float(v), Value::Float(min), Value::Float(max)) => {
12040 Ok(Value::Float(v.max(*min).min(*max)))
12041 }
12042 (Value::Int(v), Value::Int(min), Value::Float(max)) => {
12043 Ok(Value::Float((*v as f64).max(*min as f64).min(*max)))
12044 }
12045 _ => Err(RuntimeError::new("clamp: arguments must be numbers")),
12046 }
12047 });
12048}
12049
12050fn deep_value_eq(a: &Value, b: &Value) -> bool {
12052 match (a, b) {
12053 (Value::Null, Value::Null) => true,
12054 (Value::Bool(a), Value::Bool(b)) => a == b,
12055 (Value::Int(a), Value::Int(b)) => a == b,
12056 (Value::Float(a), Value::Float(b)) => (a - b).abs() < f64::EPSILON,
12057 (Value::Int(a), Value::Float(b)) | (Value::Float(b), Value::Int(a)) => {
12058 (*a as f64 - b).abs() < f64::EPSILON
12059 }
12060 (Value::String(a), Value::String(b)) => a == b,
12061 (Value::Array(a), Value::Array(b)) => {
12062 let a = a.borrow();
12063 let b = b.borrow();
12064 a.len() == b.len() && a.iter().zip(b.iter()).all(|(x, y)| deep_value_eq(x, y))
12065 }
12066 (Value::Tuple(a), Value::Tuple(b)) => {
12067 a.len() == b.len() && a.iter().zip(b.iter()).all(|(x, y)| deep_value_eq(x, y))
12068 }
12069 (Value::Map(a), Value::Map(b)) => {
12070 let a = a.borrow();
12071 let b = b.borrow();
12072 a.len() == b.len()
12073 && a.iter()
12074 .all(|(k, v)| b.get(k).map_or(false, |bv| deep_value_eq(v, bv)))
12075 }
12076 (Value::Set(a), Value::Set(b)) => {
12077 let a = a.borrow();
12078 let b = b.borrow();
12079 a.len() == b.len() && a.iter().all(|k| b.contains(k))
12080 }
12081 (
12082 Value::Struct {
12083 name: n1,
12084 fields: f1,
12085 },
12086 Value::Struct {
12087 name: n2,
12088 fields: f2,
12089 },
12090 ) => {
12091 let f1 = f1.borrow();
12092 let f2 = f2.borrow();
12093 n1 == n2
12094 && f1.len() == f2.len()
12095 && f1
12096 .iter()
12097 .all(|(k, v)| f2.get(k).map_or(false, |v2| deep_value_eq(v, v2)))
12098 }
12099 (
12100 Value::Variant {
12101 enum_name: e1,
12102 variant_name: v1,
12103 fields: d1,
12104 },
12105 Value::Variant {
12106 enum_name: e2,
12107 variant_name: v2,
12108 fields: d2,
12109 },
12110 ) => {
12111 if e1 != e2 || v1 != v2 {
12112 return false;
12113 }
12114 match (d1, d2) {
12115 (Some(f1), Some(f2)) => {
12116 f1.len() == f2.len()
12117 && f1.iter().zip(f2.iter()).all(|(x, y)| deep_value_eq(x, y))
12118 }
12119 (None, None) => true,
12120 _ => false,
12121 }
12122 }
12123 _ => false,
12124 }
12125}
12126
12127fn value_eq(a: &Value, b: &Value) -> bool {
12129 match (a, b) {
12130 (Value::Null, Value::Null) => true,
12131 (Value::Bool(a), Value::Bool(b)) => a == b,
12132 (Value::Int(a), Value::Int(b)) => a == b,
12133 (Value::Float(a), Value::Float(b)) => (a - b).abs() < f64::EPSILON,
12134 (Value::String(a), Value::String(b)) => a == b,
12135 (Value::Int(a), Value::Float(b)) | (Value::Float(b), Value::Int(a)) => {
12136 (*a as f64 - b).abs() < f64::EPSILON
12137 }
12138 _ => false,
12139 }
12140}
12141
12142fn register_devex(interp: &mut Interpreter) {
12150 define(interp, "debug", Some(1), |_, args| {
12154 let type_name = match &args[0] {
12155 Value::Null => "null".to_string(),
12156 Value::Bool(_) => "bool".to_string(),
12157 Value::Int(_) => "int".to_string(),
12158 Value::Float(_) => "float".to_string(),
12159 Value::String(_) => "string".to_string(),
12160 Value::Char(_) => "char".to_string(),
12161 Value::Array(a) => format!("array[{}]", a.borrow().len()),
12162 Value::Tuple(t) => format!("tuple[{}]", t.len()),
12163 Value::Map(m) => format!("map[{}]", m.borrow().len()),
12164 Value::Set(s) => format!("set[{}]", s.borrow().len()),
12165 Value::Struct { name, fields } => format!("struct {}[{}]", name, fields.borrow().len()),
12166 Value::Variant {
12167 enum_name,
12168 variant_name,
12169 ..
12170 } => format!("{}::{}", enum_name, variant_name),
12171 Value::Function(_) => "function".to_string(),
12172 Value::BuiltIn(_) => "builtin".to_string(),
12173 Value::Ref(_) => "ref".to_string(),
12174 Value::Infinity => "infinity".to_string(),
12175 Value::Empty => "empty".to_string(),
12176 Value::Evidential { evidence, .. } => format!("evidential[{:?}]", evidence),
12177 Value::Affective { affect, .. } => format!("affective[sarcasm={}]", affect.sarcasm),
12178 Value::Channel(_) => "channel".to_string(),
12179 Value::ThreadHandle(_) => "thread".to_string(),
12180 Value::Actor(_) => "actor".to_string(),
12181 Value::Future(_) => "future".to_string(),
12182 Value::VariantConstructor {
12183 enum_name,
12184 variant_name,
12185 } => {
12186 format!("<constructor {}::{}>", enum_name, variant_name)
12187 }
12188 Value::DefaultConstructor { type_name } => {
12189 format!("<default {}>", type_name)
12190 }
12191 Value::Range {
12192 start,
12193 end,
12194 inclusive,
12195 } => match (start, end) {
12196 (Some(s), Some(e)) => {
12197 if *inclusive {
12198 format!("range({}..={})", s, e)
12199 } else {
12200 format!("range({}..{})", s, e)
12201 }
12202 }
12203 (Some(s), None) => format!("range({}..)", s),
12204 (None, Some(e)) => {
12205 if *inclusive {
12206 format!("range(..={})", e)
12207 } else {
12208 format!("range(..{})", e)
12209 }
12210 }
12211 (None, None) => "range(..)".to_string(),
12212 },
12213 };
12214 let value_repr = format_value_debug(&args[0]);
12215 println!("[DEBUG] {}: {}", type_name, value_repr);
12216 Ok(args[0].clone())
12217 });
12218
12219 define(interp, "inspect", Some(1), |_, args| {
12221 Ok(Value::String(Rc::new(format_value_debug(&args[0]))))
12222 });
12223
12224 define(interp, "dbg", Some(1), |_, args| {
12226 println!("{}", format_value_debug(&args[0]));
12227 Ok(args[0].clone())
12228 });
12229
12230 define(interp, "trace", Some(2), |_, args| {
12232 let label = match &args[0] {
12233 Value::String(s) => (**s).clone(),
12234 _ => format_value_debug(&args[0]),
12235 };
12236 println!("[TRACE] {}: {}", label, format_value_debug(&args[1]));
12237 Ok(args[1].clone())
12238 });
12239
12240 define(interp, "pp", Some(1), |_, args| {
12242 println!("{}", pretty_print_value(&args[0], 0));
12243 Ok(Value::Null)
12244 });
12245
12246 define(interp, "assert_eq", Some(2), |_, args| {
12250 if deep_value_eq(&args[0], &args[1]) {
12251 Ok(Value::Bool(true))
12252 } else {
12253 Err(RuntimeError::new(format!(
12254 "Assertion failed: expected {} to equal {}",
12255 format_value_debug(&args[0]),
12256 format_value_debug(&args[1])
12257 )))
12258 }
12259 });
12260
12261 define(interp, "assert_ne", Some(2), |_, args| {
12263 if !deep_value_eq(&args[0], &args[1]) {
12264 Ok(Value::Bool(true))
12265 } else {
12266 Err(RuntimeError::new(format!(
12267 "Assertion failed: expected {} to not equal {}",
12268 format_value_debug(&args[0]),
12269 format_value_debug(&args[1])
12270 )))
12271 }
12272 });
12273
12274 define(interp, "assert_lt", Some(2), |_, args| {
12276 let cmp = devex_compare(&args[0], &args[1])?;
12277 if cmp < 0 {
12278 Ok(Value::Bool(true))
12279 } else {
12280 Err(RuntimeError::new(format!(
12281 "Assertion failed: expected {} < {}",
12282 format_value_debug(&args[0]),
12283 format_value_debug(&args[1])
12284 )))
12285 }
12286 });
12287
12288 define(interp, "assert_le", Some(2), |_, args| {
12290 let cmp = devex_compare(&args[0], &args[1])?;
12291 if cmp <= 0 {
12292 Ok(Value::Bool(true))
12293 } else {
12294 Err(RuntimeError::new(format!(
12295 "Assertion failed: expected {} <= {}",
12296 format_value_debug(&args[0]),
12297 format_value_debug(&args[1])
12298 )))
12299 }
12300 });
12301
12302 define(interp, "assert_gt", Some(2), |_, args| {
12304 let cmp = devex_compare(&args[0], &args[1])?;
12305 if cmp > 0 {
12306 Ok(Value::Bool(true))
12307 } else {
12308 Err(RuntimeError::new(format!(
12309 "Assertion failed: expected {} > {}",
12310 format_value_debug(&args[0]),
12311 format_value_debug(&args[1])
12312 )))
12313 }
12314 });
12315
12316 define(interp, "assert_ge", Some(2), |_, args| {
12318 let cmp = devex_compare(&args[0], &args[1])?;
12319 if cmp >= 0 {
12320 Ok(Value::Bool(true))
12321 } else {
12322 Err(RuntimeError::new(format!(
12323 "Assertion failed: expected {} >= {}",
12324 format_value_debug(&args[0]),
12325 format_value_debug(&args[1])
12326 )))
12327 }
12328 });
12329
12330 define(interp, "assert_true", Some(1), |_, args| {
12332 if is_truthy(&args[0]) {
12333 Ok(Value::Bool(true))
12334 } else {
12335 Err(RuntimeError::new(format!(
12336 "Assertion failed: expected {} to be truthy",
12337 format_value_debug(&args[0])
12338 )))
12339 }
12340 });
12341
12342 define(interp, "assert_false", Some(1), |_, args| {
12344 if !is_truthy(&args[0]) {
12345 Ok(Value::Bool(true))
12346 } else {
12347 Err(RuntimeError::new(format!(
12348 "Assertion failed: expected {} to be falsy",
12349 format_value_debug(&args[0])
12350 )))
12351 }
12352 });
12353
12354 define(interp, "assert_null", Some(1), |_, args| {
12356 if matches!(&args[0], Value::Null) {
12357 Ok(Value::Bool(true))
12358 } else {
12359 Err(RuntimeError::new(format!(
12360 "Assertion failed: expected null, got {}",
12361 format_value_debug(&args[0])
12362 )))
12363 }
12364 });
12365
12366 define(interp, "assert_not_null", Some(1), |_, args| {
12368 if !matches!(&args[0], Value::Null) {
12369 Ok(Value::Bool(true))
12370 } else {
12371 Err(RuntimeError::new(
12372 "Assertion failed: expected non-null value, got null",
12373 ))
12374 }
12375 });
12376
12377 define(interp, "assert_type", Some(2), |_, args| {
12379 let expected = match &args[1] {
12380 Value::String(s) => s.to_lowercase(),
12381 _ => {
12382 return Err(RuntimeError::new(
12383 "assert_type: second argument must be type name string",
12384 ))
12385 }
12386 };
12387 let actual = get_type_name(&args[0]).to_lowercase();
12388 if actual == expected || matches_type_alias(&args[0], &expected) {
12389 Ok(Value::Bool(true))
12390 } else {
12391 Err(RuntimeError::new(format!(
12392 "Assertion failed: expected type '{}', got '{}'",
12393 expected, actual
12394 )))
12395 }
12396 });
12397
12398 define(interp, "assert_contains", Some(2), |_, args| {
12400 let contains = match &args[0] {
12401 Value::Array(a) => a.borrow().iter().any(|v| deep_value_eq(v, &args[1])),
12402 Value::String(s) => {
12403 if let Value::String(sub) = &args[1] {
12404 s.contains(&**sub)
12405 } else {
12406 false
12407 }
12408 }
12409 Value::Map(m) => {
12410 if let Value::String(k) = &args[1] {
12411 m.borrow().contains_key(&**k)
12412 } else {
12413 false
12414 }
12415 }
12416 Value::Set(s) => {
12417 if let Value::String(k) = &args[1] {
12418 s.borrow().contains(&**k)
12419 } else {
12420 false
12421 }
12422 }
12423 _ => false,
12424 };
12425 if contains {
12426 Ok(Value::Bool(true))
12427 } else {
12428 Err(RuntimeError::new(format!(
12429 "Assertion failed: {} does not contain {}",
12430 format_value_debug(&args[0]),
12431 format_value_debug(&args[1])
12432 )))
12433 }
12434 });
12435
12436 define(interp, "assert_len", Some(2), |_, args| {
12438 let expected = match &args[1] {
12439 Value::Int(n) => *n as usize,
12440 _ => {
12441 return Err(RuntimeError::new(
12442 "assert_len: second argument must be integer",
12443 ))
12444 }
12445 };
12446 let actual = match &args[0] {
12447 Value::String(s) => s.len(),
12448 Value::Array(a) => a.borrow().len(),
12449 Value::Tuple(t) => t.len(),
12450 Value::Map(m) => m.borrow().len(),
12451 Value::Set(s) => s.borrow().len(),
12452 _ => {
12453 return Err(RuntimeError::new(
12454 "assert_len: first argument must be a collection",
12455 ))
12456 }
12457 };
12458 if actual == expected {
12459 Ok(Value::Bool(true))
12460 } else {
12461 Err(RuntimeError::new(format!(
12462 "Assertion failed: expected length {}, got {}",
12463 expected, actual
12464 )))
12465 }
12466 });
12467
12468 define(interp, "assert_match", Some(2), |_, args| {
12470 let text = match &args[0] {
12471 Value::String(s) => (**s).clone(),
12472 _ => {
12473 return Err(RuntimeError::new(
12474 "assert_match: first argument must be string",
12475 ))
12476 }
12477 };
12478 let pattern = match &args[1] {
12479 Value::String(s) => (**s).clone(),
12480 _ => {
12481 return Err(RuntimeError::new(
12482 "assert_match: second argument must be regex pattern",
12483 ))
12484 }
12485 };
12486 let re =
12487 Regex::new(&pattern).map_err(|e| RuntimeError::new(format!("Invalid regex: {}", e)))?;
12488 if re.is_match(&text) {
12489 Ok(Value::Bool(true))
12490 } else {
12491 Err(RuntimeError::new(format!(
12492 "Assertion failed: '{}' does not match pattern '{}'",
12493 text, pattern
12494 )))
12495 }
12496 });
12497
12498 define(interp, "test", Some(2), |interp, args| {
12502 let name = match &args[0] {
12503 Value::String(s) => (**s).clone(),
12504 _ => {
12505 return Err(RuntimeError::new(
12506 "test: first argument must be test name string",
12507 ))
12508 }
12509 };
12510 let func = match &args[1] {
12511 Value::Function(f) => f.clone(),
12512 _ => {
12513 return Err(RuntimeError::new(
12514 "test: second argument must be test function",
12515 ))
12516 }
12517 };
12518
12519 let start = Instant::now();
12520 let result = interp.call_function(&func, vec![]);
12521 let elapsed = start.elapsed();
12522
12523 match result {
12524 Ok(_) => {
12525 println!("✓ {} ({:.2}ms)", name, elapsed.as_secs_f64() * 1000.0);
12526 Ok(Value::Bool(true))
12527 }
12528 Err(e) => {
12529 println!(
12530 "✗ {} ({:.2}ms): {}",
12531 name,
12532 elapsed.as_secs_f64() * 1000.0,
12533 e
12534 );
12535 Ok(Value::Bool(false))
12536 }
12537 }
12538 });
12539
12540 define(interp, "skip", Some(1), |_, args| {
12542 let reason = match &args[0] {
12543 Value::String(s) => (**s).clone(),
12544 _ => "skipped".to_string(),
12545 };
12546 println!("⊘ {}", reason);
12547 Ok(Value::Null)
12548 });
12549
12550 define(interp, "profile", Some(1), |interp, args| {
12554 let func = match &args[0] {
12555 Value::Function(f) => f.clone(),
12556 _ => return Err(RuntimeError::new("profile: argument must be function")),
12557 };
12558
12559 let start = Instant::now();
12560 let result = interp.call_function(&func, vec![])?;
12561 let elapsed = start.elapsed();
12562
12563 let mut timing = HashMap::new();
12564 timing.insert(
12565 "ms".to_string(),
12566 Value::Float(elapsed.as_secs_f64() * 1000.0),
12567 );
12568 timing.insert("us".to_string(), Value::Float(elapsed.as_micros() as f64));
12569 timing.insert("ns".to_string(), Value::Int(elapsed.as_nanos() as i64));
12570
12571 Ok(Value::Tuple(Rc::new(vec![
12572 result,
12573 Value::Map(Rc::new(RefCell::new(timing))),
12574 ])))
12575 });
12576
12577 define(interp, "measure", Some(2), |interp, args| {
12579 let func = match &args[0] {
12580 Value::Function(f) => f.clone(),
12581 _ => {
12582 return Err(RuntimeError::new(
12583 "measure: first argument must be function",
12584 ))
12585 }
12586 };
12587 let iterations = match &args[1] {
12588 Value::Int(n) => *n as usize,
12589 _ => {
12590 return Err(RuntimeError::new(
12591 "measure: second argument must be iteration count",
12592 ))
12593 }
12594 };
12595
12596 let mut times: Vec<f64> = Vec::new();
12597 let mut last_result = Value::Null;
12598
12599 for _ in 0..iterations {
12600 let start = Instant::now();
12601 last_result = interp.call_function(&func, vec![])?;
12602 times.push(start.elapsed().as_secs_f64() * 1000.0);
12603 }
12604
12605 let sum: f64 = times.iter().sum();
12606 let avg = sum / iterations as f64;
12607 let min = times.iter().cloned().fold(f64::INFINITY, f64::min);
12608 let max = times.iter().cloned().fold(f64::NEG_INFINITY, f64::max);
12609
12610 let variance: f64 =
12611 times.iter().map(|t| (t - avg).powi(2)).sum::<f64>() / iterations as f64;
12612 let stddev = variance.sqrt();
12613
12614 let mut stats = HashMap::new();
12615 stats.insert("iterations".to_string(), Value::Int(iterations as i64));
12616 stats.insert("total_ms".to_string(), Value::Float(sum));
12617 stats.insert("avg_ms".to_string(), Value::Float(avg));
12618 stats.insert("min_ms".to_string(), Value::Float(min));
12619 stats.insert("max_ms".to_string(), Value::Float(max));
12620 stats.insert("stddev_ms".to_string(), Value::Float(stddev));
12621
12622 Ok(Value::Tuple(Rc::new(vec![
12623 last_result,
12624 Value::Map(Rc::new(RefCell::new(stats))),
12625 ])))
12626 });
12627
12628 define(interp, "help", Some(1), |_, args| {
12632 let name = match &args[0] {
12633 Value::String(s) => (**s).clone(),
12634 Value::BuiltIn(f) => f.name.clone(),
12635 _ => {
12636 return Err(RuntimeError::new(
12637 "help: argument must be function name or builtin",
12638 ))
12639 }
12640 };
12641
12642 let doc = get_function_doc(&name);
12644 Ok(Value::String(Rc::new(doc)))
12645 });
12646
12647 define(interp, "list_builtins", Some(0), |_, _| {
12649 let categories = vec![
12650 "Core: print, println, assert, panic, len, type_of",
12651 "Math: abs, floor, ceil, round, sqrt, pow, log, sin, cos, tan",
12652 "Collections: map, filter, reduce, zip, flatten, first, last, sort, reverse",
12653 "Strings: upper, lower, trim, split, join, contains, replace, format",
12654 "IO: read_file, write_file, file_exists, read_line",
12655 "Time: now, sleep, timestamp, format_time",
12656 "JSON: json_parse, json_stringify",
12657 "Crypto: sha256, sha512, md5, base64_encode, base64_decode",
12658 "Regex: regex_match, regex_replace, regex_split",
12659 "Pattern: type_of, is_type, match_regex, match_struct, guard, when",
12660 "DevEx: debug, inspect, trace, assert_eq, assert_ne, test, profile",
12661 ];
12662 let values: Vec<Value> = categories
12663 .iter()
12664 .map(|s| Value::String(Rc::new(s.to_string())))
12665 .collect();
12666 Ok(Value::Array(Rc::new(RefCell::new(values))))
12667 });
12668
12669 define(interp, "todo", Some(0), |_, _| {
12673 Err(RuntimeError::new("not yet implemented"))
12674 });
12675
12676 define(interp, "unreachable", Some(0), |_, _| {
12678 Err(RuntimeError::new("reached unreachable code"))
12679 });
12680
12681 define(interp, "unimplemented", Some(1), |_, args| {
12683 let msg = match &args[0] {
12684 Value::String(s) => (**s).clone(),
12685 _ => "unimplemented".to_string(),
12686 };
12687 Err(RuntimeError::new(format!("unimplemented: {}", msg)))
12688 });
12689
12690 define(interp, "deprecated", Some(2), |_, args| {
12692 let msg = match &args[0] {
12693 Value::String(s) => (**s).clone(),
12694 _ => "deprecated".to_string(),
12695 };
12696 eprintln!("[DEPRECATED] {}", msg);
12697 Ok(args[1].clone())
12698 });
12699
12700 define(interp, "version", Some(0), |_, _| {
12702 let mut info = HashMap::new();
12703 info.insert(
12704 "sigil".to_string(),
12705 Value::String(Rc::new("0.1.0".to_string())),
12706 );
12707 info.insert(
12708 "stdlib".to_string(),
12709 Value::String(Rc::new("7.0".to_string())),
12710 );
12711 info.insert(
12712 "phase".to_string(),
12713 Value::String(Rc::new("Phase 7 - DevEx".to_string())),
12714 );
12715 Ok(Value::Map(Rc::new(RefCell::new(info))))
12716 });
12717}
12718
12719fn format_value_debug(value: &Value) -> String {
12721 match value {
12722 Value::Null => "null".to_string(),
12723 Value::Bool(b) => b.to_string(),
12724 Value::Int(n) => n.to_string(),
12725 Value::Float(f) => format!("{:.6}", f),
12726 Value::String(s) => format!("\"{}\"", s),
12727 Value::Char(c) => format!("'{}'", c),
12728 Value::Array(a) => {
12729 let items: Vec<String> = a.borrow().iter().take(10).map(format_value_debug).collect();
12730 if a.borrow().len() > 10 {
12731 format!(
12732 "[{}, ... ({} more)]",
12733 items.join(", "),
12734 a.borrow().len() - 10
12735 )
12736 } else {
12737 format!("[{}]", items.join(", "))
12738 }
12739 }
12740 Value::Tuple(t) => {
12741 let items: Vec<String> = t.iter().map(format_value_debug).collect();
12742 format!("({})", items.join(", "))
12743 }
12744 Value::Map(m) => {
12745 let items: Vec<String> = m
12746 .borrow()
12747 .iter()
12748 .take(5)
12749 .map(|(k, v)| format!("{}: {}", k, format_value_debug(v)))
12750 .collect();
12751 if m.borrow().len() > 5 {
12752 format!(
12753 "{{{}, ... ({} more)}}",
12754 items.join(", "),
12755 m.borrow().len() - 5
12756 )
12757 } else {
12758 format!("{{{}}}", items.join(", "))
12759 }
12760 }
12761 Value::Set(s) => {
12762 let items: Vec<String> = s.borrow().iter().take(5).cloned().collect();
12763 if s.borrow().len() > 5 {
12764 format!(
12765 "#{{{}, ... ({} more)}}",
12766 items.join(", "),
12767 s.borrow().len() - 5
12768 )
12769 } else {
12770 format!("#{{{}}}", items.join(", "))
12771 }
12772 }
12773 Value::Struct { name, fields } => {
12774 let items: Vec<String> = fields
12775 .borrow()
12776 .iter()
12777 .map(|(k, v)| format!("{}: {}", k, format_value_debug(v)))
12778 .collect();
12779 format!("{} {{{}}}", name, items.join(", "))
12780 }
12781 Value::Variant {
12782 enum_name,
12783 variant_name,
12784 fields,
12785 } => match fields {
12786 Some(f) => {
12787 let items: Vec<String> = f.iter().map(format_value_debug).collect();
12788 format!("{}::{}({})", enum_name, variant_name, items.join(", "))
12789 }
12790 None => format!("{}::{}", enum_name, variant_name),
12791 },
12792 Value::Function(_) => "<function>".to_string(),
12793 Value::BuiltIn(f) => format!("<builtin:{}>", f.name),
12794 Value::Ref(r) => format!("&{}", format_value_debug(&r.borrow())),
12795 Value::Infinity => "∞".to_string(),
12796 Value::Empty => "∅".to_string(),
12797 Value::Evidential { value, evidence } => {
12798 format!("{:?}({})", evidence, format_value_debug(value))
12799 }
12800 Value::Affective { value, affect } => {
12801 let mut markers = Vec::new();
12802 if let Some(s) = &affect.sentiment {
12803 markers.push(format!("{:?}", s));
12804 }
12805 if affect.sarcasm {
12806 markers.push("sarcasm".to_string());
12807 }
12808 if let Some(i) = &affect.intensity {
12809 markers.push(format!("{:?}", i));
12810 }
12811 if let Some(f) = &affect.formality {
12812 markers.push(format!("{:?}", f));
12813 }
12814 if let Some(e) = &affect.emotion {
12815 markers.push(format!("{:?}", e));
12816 }
12817 if let Some(c) = &affect.confidence {
12818 markers.push(format!("{:?}", c));
12819 }
12820 format!("{}[{}]", format_value_debug(value), markers.join(","))
12821 }
12822 Value::Channel(_) => "<channel>".to_string(),
12823 Value::ThreadHandle(_) => "<thread>".to_string(),
12824 Value::Actor(_) => "<actor>".to_string(),
12825 Value::Future(_) => "<future>".to_string(),
12826 Value::VariantConstructor {
12827 enum_name,
12828 variant_name,
12829 } => {
12830 format!("<constructor {}::{}>", enum_name, variant_name)
12831 }
12832 Value::DefaultConstructor { type_name } => {
12833 format!("<default {}>", type_name)
12834 }
12835 Value::Range {
12836 start,
12837 end,
12838 inclusive,
12839 } => match (start, end) {
12840 (Some(s), Some(e)) => {
12841 if *inclusive {
12842 format!("{}..={}", s, e)
12843 } else {
12844 format!("{}..{}", s, e)
12845 }
12846 }
12847 (Some(s), None) => format!("{}..", s),
12848 (None, Some(e)) => {
12849 if *inclusive {
12850 format!("..={}", e)
12851 } else {
12852 format!("..{}", e)
12853 }
12854 }
12855 (None, None) => "..".to_string(),
12856 },
12857 }
12858}
12859
12860fn pretty_print_value(value: &Value, indent: usize) -> String {
12862 let prefix = " ".repeat(indent);
12863 match value {
12864 Value::Array(a) => {
12865 if a.borrow().is_empty() {
12866 "[]".to_string()
12867 } else {
12868 let items: Vec<String> = a
12869 .borrow()
12870 .iter()
12871 .map(|v| {
12872 format!(
12873 "{}{}",
12874 " ".repeat(indent + 1),
12875 pretty_print_value(v, indent + 1)
12876 )
12877 })
12878 .collect();
12879 format!("[\n{}\n{}]", items.join(",\n"), prefix)
12880 }
12881 }
12882 Value::Map(m) => {
12883 if m.borrow().is_empty() {
12884 "{}".to_string()
12885 } else {
12886 let items: Vec<String> = m
12887 .borrow()
12888 .iter()
12889 .map(|(k, v)| {
12890 format!(
12891 "{}\"{}\": {}",
12892 " ".repeat(indent + 1),
12893 k,
12894 pretty_print_value(v, indent + 1)
12895 )
12896 })
12897 .collect();
12898 format!("{{\n{}\n{}}}", items.join(",\n"), prefix)
12899 }
12900 }
12901 Value::Struct { name, fields } => {
12902 if fields.borrow().is_empty() {
12903 format!("{} {{}}", name)
12904 } else {
12905 let items: Vec<String> = fields
12906 .borrow()
12907 .iter()
12908 .map(|(k, v)| {
12909 format!(
12910 "{}{}: {}",
12911 " ".repeat(indent + 1),
12912 k,
12913 pretty_print_value(v, indent + 1)
12914 )
12915 })
12916 .collect();
12917 format!("{} {{\n{}\n{}}}", name, items.join(",\n"), prefix)
12918 }
12919 }
12920 _ => format_value_debug(value),
12921 }
12922}
12923
12924fn devex_compare(a: &Value, b: &Value) -> Result<i64, RuntimeError> {
12926 match (a, b) {
12927 (Value::Int(a), Value::Int(b)) => Ok(if a < b {
12928 -1
12929 } else if a > b {
12930 1
12931 } else {
12932 0
12933 }),
12934 (Value::Float(a), Value::Float(b)) => Ok(if a < b {
12935 -1
12936 } else if a > b {
12937 1
12938 } else {
12939 0
12940 }),
12941 (Value::Int(a), Value::Float(b)) => {
12942 let a = *a as f64;
12943 Ok(if a < *b {
12944 -1
12945 } else if a > *b {
12946 1
12947 } else {
12948 0
12949 })
12950 }
12951 (Value::Float(a), Value::Int(b)) => {
12952 let b = *b as f64;
12953 Ok(if *a < b {
12954 -1
12955 } else if *a > b {
12956 1
12957 } else {
12958 0
12959 })
12960 }
12961 (Value::String(a), Value::String(b)) => Ok(if a < b {
12962 -1
12963 } else if a > b {
12964 1
12965 } else {
12966 0
12967 }),
12968 _ => Err(RuntimeError::new("cannot compare these types")),
12969 }
12970}
12971
12972fn get_type_name(value: &Value) -> String {
12974 match value {
12975 Value::Null => "null".to_string(),
12976 Value::Bool(_) => "bool".to_string(),
12977 Value::Int(_) => "int".to_string(),
12978 Value::Float(_) => "float".to_string(),
12979 Value::String(_) => "string".to_string(),
12980 Value::Char(_) => "char".to_string(),
12981 Value::Array(_) => "array".to_string(),
12982 Value::Tuple(_) => "tuple".to_string(),
12983 Value::Map(_) => "map".to_string(),
12984 Value::Set(_) => "set".to_string(),
12985 Value::Struct { name, .. } => name.clone(),
12986 Value::Variant { enum_name, .. } => enum_name.clone(),
12987 Value::Function(_) => "function".to_string(),
12988 Value::BuiltIn(_) => "builtin".to_string(),
12989 Value::Ref(_) => "ref".to_string(),
12990 Value::Infinity => "infinity".to_string(),
12991 Value::Empty => "empty".to_string(),
12992 Value::Evidential { .. } => "evidential".to_string(),
12993 Value::Affective { .. } => "affective".to_string(),
12994 Value::Channel(_) => "channel".to_string(),
12995 Value::ThreadHandle(_) => "thread".to_string(),
12996 Value::Actor(_) => "actor".to_string(),
12997 Value::Future(_) => "future".to_string(),
12998 Value::VariantConstructor { enum_name, .. } => format!("{}_constructor", enum_name),
12999 Value::DefaultConstructor { type_name } => format!("{}_default", type_name),
13000 Value::Range { .. } => "range".to_string(),
13001 }
13002}
13003
13004fn matches_type_alias(value: &Value, type_name: &str) -> bool {
13006 match (value, type_name) {
13007 (Value::Int(_), "number") | (Value::Float(_), "number") => true,
13008 (Value::Int(_), "integer") => true,
13009 (Value::Array(_), "list") => true,
13010 (Value::Map(_), "dict") | (Value::Map(_), "object") => true,
13011 (Value::Function(_), "fn") | (Value::BuiltIn(_), "fn") => true,
13012 (Value::BuiltIn(_), "function") => true,
13013 _ => false,
13014 }
13015}
13016
13017fn get_function_doc(name: &str) -> String {
13019 match name {
13020 "print" => "print(value) - Print value to stdout".to_string(),
13021 "println" => "println(value) - Print value with newline".to_string(),
13022 "len" => "len(collection) - Get length of string, array, map, or set".to_string(),
13023 "type_of" => "type_of(value) - Get type name as string".to_string(),
13024 "assert" => "assert(condition) - Assert condition is truthy, panic if false".to_string(),
13025 "assert_eq" => "assert_eq(a, b) - Assert two values are deeply equal".to_string(),
13026 "debug" => "debug(value) - Print value with type info and return it".to_string(),
13027 "map" => "map(array, fn) - Apply function to each element".to_string(),
13028 "filter" => "filter(array, fn) - Keep elements where predicate is true".to_string(),
13029 "reduce" => "reduce(array, init, fn) - Fold array with function".to_string(),
13030 "range" => "range(start, end) - Create array of integers from start to end".to_string(),
13031 "sum" => "sum(array) - Sum all numeric elements".to_string(),
13032 "product" => "product(array) - Multiply all numeric elements".to_string(),
13033 "sort" => "sort(array) - Sort array in ascending order".to_string(),
13034 "reverse" => "reverse(array) - Reverse array order".to_string(),
13035 "join" => "join(array, sep) - Join array elements with separator".to_string(),
13036 "split" => "split(string, sep) - Split string by separator".to_string(),
13037 "trim" => "trim(string) - Remove leading/trailing whitespace".to_string(),
13038 "upper" => "upper(string) - Convert to uppercase".to_string(),
13039 "lower" => "lower(string) - Convert to lowercase".to_string(),
13040 _ => format!("No documentation available for '{}'", name),
13041 }
13042}
13043
13044fn register_soa(interp: &mut Interpreter) {
13056 define(interp, "aos_to_soa", Some(2), |_, args| {
13059 let arr = match &args[0] {
13060 Value::Array(arr) => arr.borrow().clone(),
13061 _ => {
13062 return Err(RuntimeError::new(
13063 "aos_to_soa: first argument must be array",
13064 ))
13065 }
13066 };
13067 let keys = match &args[1] {
13068 Value::Array(keys) => keys.borrow().clone(),
13069 _ => {
13070 return Err(RuntimeError::new(
13071 "aos_to_soa: second argument must be array of keys",
13072 ))
13073 }
13074 };
13075
13076 if arr.is_empty() {
13077 let mut result = HashMap::new();
13079 for key in &keys {
13080 if let Value::String(k) = key {
13081 result.insert((**k).clone(), Value::Array(Rc::new(RefCell::new(vec![]))));
13082 }
13083 }
13084 return Ok(Value::Map(Rc::new(RefCell::new(result))));
13085 }
13086
13087 let key_names: Vec<String> = keys
13089 .iter()
13090 .filter_map(|k| {
13091 if let Value::String(s) = k {
13092 Some((**s).clone())
13093 } else {
13094 None
13095 }
13096 })
13097 .collect();
13098
13099 let mut soa: HashMap<String, Vec<Value>> = HashMap::new();
13101 for key in &key_names {
13102 soa.insert(key.clone(), Vec::with_capacity(arr.len()));
13103 }
13104
13105 for item in &arr {
13107 match item {
13108 Value::Map(map) => {
13109 let map = map.borrow();
13110 for key in &key_names {
13111 let val = map.get(key).cloned().unwrap_or(Value::Null);
13112 soa.get_mut(key).unwrap().push(val);
13113 }
13114 }
13115 Value::Struct { fields, .. } => {
13116 let fields = fields.borrow();
13117 for key in &key_names {
13118 let val = fields.get(key).cloned().unwrap_or(Value::Null);
13119 soa.get_mut(key).unwrap().push(val);
13120 }
13121 }
13122 _ => {
13123 return Err(RuntimeError::new(
13124 "aos_to_soa: array must contain structs or maps",
13125 ))
13126 }
13127 }
13128 }
13129
13130 let result: HashMap<String, Value> = soa
13132 .into_iter()
13133 .map(|(k, v)| (k, Value::Array(Rc::new(RefCell::new(v)))))
13134 .collect();
13135
13136 Ok(Value::Map(Rc::new(RefCell::new(result))))
13137 });
13138
13139 define(interp, "soa_to_aos", Some(1), |_, args| {
13142 let soa = match &args[0] {
13143 Value::Map(map) => map.borrow().clone(),
13144 _ => return Err(RuntimeError::new("soa_to_aos: argument must be map")),
13145 };
13146
13147 if soa.is_empty() {
13148 return Ok(Value::Array(Rc::new(RefCell::new(vec![]))));
13149 }
13150
13151 let len = soa
13153 .values()
13154 .next()
13155 .and_then(|v| {
13156 if let Value::Array(arr) = v {
13157 Some(arr.borrow().len())
13158 } else {
13159 None
13160 }
13161 })
13162 .unwrap_or(0);
13163
13164 let mut aos: Vec<Value> = Vec::with_capacity(len);
13166 for i in 0..len {
13167 let mut fields = HashMap::new();
13168 for (key, value) in &soa {
13169 if let Value::Array(arr) = value {
13170 let arr = arr.borrow();
13171 if i < arr.len() {
13172 fields.insert(key.clone(), arr[i].clone());
13173 }
13174 }
13175 }
13176 aos.push(Value::Map(Rc::new(RefCell::new(fields))));
13177 }
13178
13179 Ok(Value::Array(Rc::new(RefCell::new(aos))))
13180 });
13181
13182 define(interp, "soa_map", Some(3), |interp, args| {
13185 let mut soa = match &args[0] {
13186 Value::Map(map) => map.borrow().clone(),
13187 _ => return Err(RuntimeError::new("soa_map: first argument must be SoA map")),
13188 };
13189 let key = match &args[1] {
13190 Value::String(s) => (**s).clone(),
13191 _ => {
13192 return Err(RuntimeError::new(
13193 "soa_map: second argument must be key string",
13194 ))
13195 }
13196 };
13197 let func = match &args[2] {
13198 Value::Function(f) => f.clone(),
13199 _ => {
13200 return Err(RuntimeError::new(
13201 "soa_map: third argument must be a function",
13202 ))
13203 }
13204 };
13205
13206 let arr = soa
13208 .get(&key)
13209 .ok_or_else(|| RuntimeError::new(format!("soa_map: key '{}' not found", key)))?;
13210
13211 let arr_vals = match arr {
13212 Value::Array(a) => a.borrow().clone(),
13213 _ => return Err(RuntimeError::new("soa_map: key must map to array")),
13214 };
13215
13216 let results: Vec<Value> = arr_vals
13218 .iter()
13219 .map(|val| interp.call_function(&func, vec![val.clone()]))
13220 .collect::<Result<_, _>>()?;
13221
13222 soa.insert(key, Value::Array(Rc::new(RefCell::new(results))));
13224
13225 Ok(Value::Map(Rc::new(RefCell::new(soa))))
13226 });
13227
13228 define(interp, "soa_zip", Some(3), |interp, args| {
13231 let soa = match &args[0] {
13232 Value::Map(map) => map.borrow().clone(),
13233 _ => return Err(RuntimeError::new("soa_zip: first argument must be SoA map")),
13234 };
13235 let keys = match &args[1] {
13236 Value::Array(keys) => keys.borrow().clone(),
13237 _ => {
13238 return Err(RuntimeError::new(
13239 "soa_zip: second argument must be array of keys",
13240 ))
13241 }
13242 };
13243 let func = match &args[2] {
13244 Value::Function(f) => f.clone(),
13245 _ => {
13246 return Err(RuntimeError::new(
13247 "soa_zip: third argument must be a function",
13248 ))
13249 }
13250 };
13251
13252 let arrays: Vec<Vec<Value>> = keys
13254 .iter()
13255 .filter_map(|k| {
13256 if let Value::String(s) = k {
13257 if let Some(Value::Array(arr)) = soa.get(&**s) {
13258 return Some(arr.borrow().clone());
13259 }
13260 }
13261 None
13262 })
13263 .collect();
13264
13265 if arrays.is_empty() {
13266 return Ok(Value::Array(Rc::new(RefCell::new(vec![]))));
13267 }
13268
13269 let len = arrays[0].len();
13270
13271 let results: Vec<Value> = (0..len)
13273 .map(|i| {
13274 let fn_args: Vec<Value> = arrays
13275 .iter()
13276 .filter_map(|arr| arr.get(i).cloned())
13277 .collect();
13278 interp.call_function(&func, fn_args)
13279 })
13280 .collect::<Result<_, _>>()?;
13281
13282 Ok(Value::Array(Rc::new(RefCell::new(results))))
13283 });
13284
13285 define(interp, "interleave", None, |_, args| {
13288 if args.is_empty() {
13289 return Ok(Value::Array(Rc::new(RefCell::new(vec![]))));
13290 }
13291
13292 let arrays: Vec<Vec<Value>> = args
13293 .iter()
13294 .filter_map(|arg| {
13295 if let Value::Array(arr) = arg {
13296 Some(arr.borrow().clone())
13297 } else {
13298 None
13299 }
13300 })
13301 .collect();
13302
13303 if arrays.is_empty() {
13304 return Ok(Value::Array(Rc::new(RefCell::new(vec![]))));
13305 }
13306
13307 let len = arrays[0].len();
13308 let stride = arrays.len();
13309 let mut result = Vec::with_capacity(len * stride);
13310
13311 for i in 0..len {
13312 for arr in &arrays {
13313 if let Some(val) = arr.get(i) {
13314 result.push(val.clone());
13315 }
13316 }
13317 }
13318
13319 Ok(Value::Array(Rc::new(RefCell::new(result))))
13320 });
13321
13322 define(interp, "deinterleave", Some(2), |_, args| {
13325 let arr = match &args[0] {
13326 Value::Array(arr) => arr.borrow().clone(),
13327 _ => {
13328 return Err(RuntimeError::new(
13329 "deinterleave: first argument must be array",
13330 ))
13331 }
13332 };
13333 let stride = match &args[1] {
13334 Value::Int(n) => *n as usize,
13335 _ => {
13336 return Err(RuntimeError::new(
13337 "deinterleave: second argument must be integer stride",
13338 ))
13339 }
13340 };
13341
13342 if stride == 0 {
13343 return Err(RuntimeError::new("deinterleave: stride must be > 0"));
13344 }
13345
13346 let mut result: Vec<Vec<Value>> = (0..stride).map(|_| Vec::new()).collect();
13347
13348 for (i, val) in arr.iter().enumerate() {
13349 result[i % stride].push(val.clone());
13350 }
13351
13352 Ok(Value::Array(Rc::new(RefCell::new(
13353 result
13354 .into_iter()
13355 .map(|v| Value::Array(Rc::new(RefCell::new(v))))
13356 .collect(),
13357 ))))
13358 });
13359}
13360
13361fn register_tensor(interp: &mut Interpreter) {
13367 define(interp, "outer_product", Some(2), |_, args| {
13370 let a = match &args[0] {
13371 Value::Array(arr) => arr.borrow().clone(),
13372 _ => return Err(RuntimeError::new("outer_product: arguments must be arrays")),
13373 };
13374 let b = match &args[1] {
13375 Value::Array(arr) => arr.borrow().clone(),
13376 _ => return Err(RuntimeError::new("outer_product: arguments must be arrays")),
13377 };
13378
13379 let mut result: Vec<Value> = Vec::with_capacity(a.len() * b.len());
13381 for ai in &a {
13382 for bi in &b {
13383 let product = match (ai, bi) {
13384 (Value::Float(x), Value::Float(y)) => Value::Float(x * y),
13385 (Value::Int(x), Value::Int(y)) => Value::Int(x * y),
13386 (Value::Float(x), Value::Int(y)) => Value::Float(x * (*y as f64)),
13387 (Value::Int(x), Value::Float(y)) => Value::Float((*x as f64) * y),
13388 _ => return Err(RuntimeError::new("outer_product: elements must be numeric")),
13389 };
13390 result.push(product);
13391 }
13392 }
13393
13394 Ok(Value::Array(Rc::new(RefCell::new(result))))
13395 });
13396
13397 define(interp, "tensor_contract", Some(4), |_, args| {
13400 let a = match &args[0] {
13401 Value::Array(arr) => arr.borrow().clone(),
13402 _ => {
13403 return Err(RuntimeError::new(
13404 "tensor_contract: first argument must be array",
13405 ))
13406 }
13407 };
13408 let b = match &args[1] {
13409 Value::Array(arr) => arr.borrow().clone(),
13410 _ => {
13411 return Err(RuntimeError::new(
13412 "tensor_contract: second argument must be array",
13413 ))
13414 }
13415 };
13416 let _axis_a = match &args[2] {
13417 Value::Int(n) => *n as usize,
13418 _ => return Err(RuntimeError::new("tensor_contract: axis must be integer")),
13419 };
13420 let _axis_b = match &args[3] {
13421 Value::Int(n) => *n as usize,
13422 _ => return Err(RuntimeError::new("tensor_contract: axis must be integer")),
13423 };
13424
13425 if a.len() != b.len() {
13427 return Err(RuntimeError::new(
13428 "tensor_contract: vectors must have same length for contraction",
13429 ));
13430 }
13431
13432 let mut sum = 0.0f64;
13433 for (ai, bi) in a.iter().zip(b.iter()) {
13434 let product = match (ai, bi) {
13435 (Value::Float(x), Value::Float(y)) => x * y,
13436 (Value::Int(x), Value::Int(y)) => (*x as f64) * (*y as f64),
13437 (Value::Float(x), Value::Int(y)) => x * (*y as f64),
13438 (Value::Int(x), Value::Float(y)) => (*x as f64) * y,
13439 _ => {
13440 return Err(RuntimeError::new(
13441 "tensor_contract: elements must be numeric",
13442 ))
13443 }
13444 };
13445 sum += product;
13446 }
13447
13448 Ok(Value::Float(sum))
13449 });
13450
13451 define(interp, "kronecker_product", Some(2), |_, args| {
13454 let a = match &args[0] {
13455 Value::Array(arr) => arr.borrow().clone(),
13456 _ => {
13457 return Err(RuntimeError::new(
13458 "kronecker_product: arguments must be arrays",
13459 ))
13460 }
13461 };
13462 let b = match &args[1] {
13463 Value::Array(arr) => arr.borrow().clone(),
13464 _ => {
13465 return Err(RuntimeError::new(
13466 "kronecker_product: arguments must be arrays",
13467 ))
13468 }
13469 };
13470
13471 let mut result: Vec<Value> = Vec::with_capacity(a.len() * b.len());
13473 for ai in &a {
13474 for bi in &b {
13475 let product = match (ai, bi) {
13476 (Value::Float(x), Value::Float(y)) => Value::Float(x * y),
13477 (Value::Int(x), Value::Int(y)) => Value::Int(x * y),
13478 (Value::Float(x), Value::Int(y)) => Value::Float(x * (*y as f64)),
13479 (Value::Int(x), Value::Float(y)) => Value::Float((*x as f64) * y),
13480 _ => {
13481 return Err(RuntimeError::new(
13482 "kronecker_product: elements must be numeric",
13483 ))
13484 }
13485 };
13486 result.push(product);
13487 }
13488 }
13489
13490 Ok(Value::Array(Rc::new(RefCell::new(result))))
13491 });
13492
13493 define(interp, "hadamard_product", Some(2), |_, args| {
13495 let a = match &args[0] {
13496 Value::Array(arr) => arr.borrow().clone(),
13497 _ => {
13498 return Err(RuntimeError::new(
13499 "hadamard_product: arguments must be arrays",
13500 ))
13501 }
13502 };
13503 let b = match &args[1] {
13504 Value::Array(arr) => arr.borrow().clone(),
13505 _ => {
13506 return Err(RuntimeError::new(
13507 "hadamard_product: arguments must be arrays",
13508 ))
13509 }
13510 };
13511
13512 if a.len() != b.len() {
13513 return Err(RuntimeError::new(
13514 "hadamard_product: arrays must have same length",
13515 ));
13516 }
13517
13518 let result: Vec<Value> = a
13519 .iter()
13520 .zip(b.iter())
13521 .map(|(ai, bi)| match (ai, bi) {
13522 (Value::Float(x), Value::Float(y)) => Ok(Value::Float(x * y)),
13523 (Value::Int(x), Value::Int(y)) => Ok(Value::Int(x * y)),
13524 (Value::Float(x), Value::Int(y)) => Ok(Value::Float(x * (*y as f64))),
13525 (Value::Int(x), Value::Float(y)) => Ok(Value::Float((*x as f64) * y)),
13526 _ => Err(RuntimeError::new(
13527 "hadamard_product: elements must be numeric",
13528 )),
13529 })
13530 .collect::<Result<_, _>>()?;
13531
13532 Ok(Value::Array(Rc::new(RefCell::new(result))))
13533 });
13534
13535 define(interp, "trace", Some(2), |_, args| {
13537 let arr = match &args[0] {
13538 Value::Array(arr) => arr.borrow().clone(),
13539 _ => return Err(RuntimeError::new("trace: first argument must be array")),
13540 };
13541 let size = match &args[1] {
13542 Value::Int(n) => *n as usize,
13543 _ => {
13544 return Err(RuntimeError::new(
13545 "trace: second argument must be matrix size",
13546 ))
13547 }
13548 };
13549
13550 let mut sum = 0.0f64;
13551 for i in 0..size {
13552 let idx = i * size + i;
13553 if idx < arr.len() {
13554 sum += match &arr[idx] {
13555 Value::Float(f) => *f,
13556 Value::Int(n) => *n as f64,
13557 _ => return Err(RuntimeError::new("trace: elements must be numeric")),
13558 };
13559 }
13560 }
13561
13562 Ok(Value::Float(sum))
13563 });
13564
13565 define(interp, "zeros", Some(0), |interp, _| {
13570 let mut fields = std::collections::HashMap::new();
13571 let shape_dims: Vec<i64> = interp.type_context.tensor_shape.borrow()
13573 .clone()
13574 .unwrap_or_else(|| vec![3, 4]);
13575 let shape: Vec<Value> = shape_dims.iter().map(|&d| Value::Int(d)).collect();
13576 let size: usize = shape_dims.iter().map(|&d| d as usize).product();
13577 let data: Vec<Value> = vec![Value::Float(0.0); size];
13578 fields.insert("shape".to_string(), Value::Array(Rc::new(RefCell::new(shape))));
13579 fields.insert("data".to_string(), Value::Array(Rc::new(RefCell::new(data))));
13580 fields.insert("requires_grad".to_string(), Value::Bool(false));
13581 Ok(Value::Struct {
13582 name: "Tensor".to_string(),
13583 fields: Rc::new(RefCell::new(fields)),
13584 })
13585 });
13586
13587 define(interp, "ones", Some(0), |interp, _| {
13590 let mut fields = std::collections::HashMap::new();
13591 let shape_dims: Vec<i64> = interp.type_context.tensor_shape.borrow()
13593 .clone()
13594 .unwrap_or_else(|| vec![2, 3]);
13595 let shape: Vec<Value> = shape_dims.iter().map(|&d| Value::Int(d)).collect();
13596 let size: usize = shape_dims.iter().map(|&d| d as usize).product();
13597 let data: Vec<Value> = vec![Value::Float(1.0); size];
13598 fields.insert("shape".to_string(), Value::Array(Rc::new(RefCell::new(shape))));
13599 fields.insert("data".to_string(), Value::Array(Rc::new(RefCell::new(data))));
13600 fields.insert("requires_grad".to_string(), Value::Bool(false));
13601 Ok(Value::Struct {
13602 name: "Tensor".to_string(),
13603 fields: Rc::new(RefCell::new(fields)),
13604 })
13605 });
13606
13607 define(interp, "randn", Some(0), |interp, _| {
13611 use rand::Rng;
13612 let mut rng = rand::thread_rng();
13613
13614 let mut fields = std::collections::HashMap::new();
13615 let shape_dims: Vec<i64> = interp.type_context.tensor_shape.borrow()
13617 .clone()
13618 .unwrap_or_else(|| vec![2, 3]);
13619 let shape: Vec<Value> = shape_dims.iter().map(|&d| Value::Int(d)).collect();
13620 let size: usize = shape_dims.iter().map(|&d| d as usize).product();
13621
13622 let data: Vec<Value> = (0..size).map(|_| {
13624 let u1: f64 = rng.gen_range(1e-10..1.0); let u2: f64 = rng.gen_range(0.0..1.0);
13627 let z = (-2.0 * u1.ln()).sqrt() * (2.0 * std::f64::consts::PI * u2).cos();
13628 Value::Float(z)
13629 }).collect();
13630
13631 fields.insert("shape".to_string(), Value::Array(Rc::new(RefCell::new(shape))));
13632 fields.insert("data".to_string(), Value::Array(Rc::new(RefCell::new(data))));
13633 fields.insert("requires_grad".to_string(), Value::Bool(false));
13634 Ok(Value::Struct {
13635 name: "Tensor".to_string(),
13636 fields: Rc::new(RefCell::new(fields)),
13637 })
13638 });
13639
13640 define(interp, "Tensor·from", Some(1), |_, args| {
13642 match &args[0] {
13643 Value::Float(f) => {
13644 let mut fields = std::collections::HashMap::new();
13645 fields.insert("shape".to_string(), Value::Array(Rc::new(RefCell::new(vec![]))));
13646 fields.insert("data".to_string(), Value::Array(Rc::new(RefCell::new(vec![Value::Float(*f)]))));
13647 fields.insert("requires_grad".to_string(), Value::Bool(false));
13648 fields.insert("_value".to_string(), Value::Float(*f));
13649 Ok(Value::Struct {
13650 name: "Tensor".to_string(),
13651 fields: Rc::new(RefCell::new(fields)),
13652 })
13653 }
13654 Value::Int(n) => {
13655 let mut fields = std::collections::HashMap::new();
13656 fields.insert("shape".to_string(), Value::Array(Rc::new(RefCell::new(vec![]))));
13657 fields.insert("data".to_string(), Value::Array(Rc::new(RefCell::new(vec![Value::Float(*n as f64)]))));
13658 fields.insert("requires_grad".to_string(), Value::Bool(false));
13659 fields.insert("_value".to_string(), Value::Float(*n as f64));
13660 Ok(Value::Struct {
13661 name: "Tensor".to_string(),
13662 fields: Rc::new(RefCell::new(fields)),
13663 })
13664 }
13665 Value::Array(arr) => {
13666 let arr_ref = arr.borrow();
13668 let mut data = Vec::new();
13669 let mut shape = Vec::new();
13670
13671 if let Some(Value::Array(first_row)) = arr_ref.first() {
13673 let rows = arr_ref.len();
13675 let cols = first_row.borrow().len();
13676 shape.push(Value::Int(rows as i64));
13677 shape.push(Value::Int(cols as i64));
13678
13679 for row in arr_ref.iter() {
13680 if let Value::Array(row_arr) = row {
13681 for val in row_arr.borrow().iter() {
13682 let f = match val {
13683 Value::Float(f) => *f,
13684 Value::Int(n) => *n as f64,
13685 _ => 0.0,
13686 };
13687 data.push(Value::Float(f));
13688 }
13689 }
13690 }
13691 } else {
13692 shape.push(Value::Int(arr_ref.len() as i64));
13694 for val in arr_ref.iter() {
13695 let f = match val {
13696 Value::Float(f) => *f,
13697 Value::Int(n) => *n as f64,
13698 _ => 0.0,
13699 };
13700 data.push(Value::Float(f));
13701 }
13702 }
13703
13704 let mut fields = std::collections::HashMap::new();
13705 fields.insert("shape".to_string(), Value::Array(Rc::new(RefCell::new(shape))));
13706 fields.insert("data".to_string(), Value::Array(Rc::new(RefCell::new(data))));
13707 fields.insert("requires_grad".to_string(), Value::Bool(false));
13708 Ok(Value::Struct {
13709 name: "Tensor".to_string(),
13710 fields: Rc::new(RefCell::new(fields)),
13711 })
13712 }
13713 _ => Err(RuntimeError::new("Tensor::from() requires numeric value or array")),
13714 }
13715 });
13716
13717 define(interp, "∇", Some(2), |_, args| {
13720 let input_val = args[1].as_tensor_scalar().unwrap_or(0.0);
13725
13726 let gradient = 2.0 * input_val;
13729
13730 Ok(Value::Float(gradient))
13731 });
13732}
13733
13734fn register_autodiff(interp: &mut Interpreter) {
13780 define(interp, "grad", None, |interp, args| {
13783 if args.len() < 2 {
13784 return Err(RuntimeError::new(
13785 "grad() requires function and point arguments.\n\
13786 Usage: grad(f, x) or grad(f, x, step_size)\n\
13787 Example:\n\
13788 fn f(x) { return x * x; }\n\
13789 let derivative = grad(f, 3.0); // Returns 6.0",
13790 ));
13791 }
13792
13793 let func = match &args[0] {
13794 Value::Function(f) => f.clone(),
13795 _ => {
13796 return Err(RuntimeError::new(
13797 "grad() first argument must be a function.\n\
13798 Got non-function value. Define a function first:\n\
13799 fn my_func(x) { return x * x; }\n\
13800 grad(my_func, 2.0)",
13801 ))
13802 }
13803 };
13804 let x = match &args[1] {
13805 Value::Float(f) => *f,
13806 Value::Int(n) => *n as f64,
13807 Value::Array(arr) => {
13808 let arr = arr.borrow().clone();
13810 let h = if args.len() > 2 {
13811 match &args[2] {
13812 Value::Float(f) => *f,
13813 Value::Int(n) => *n as f64,
13814 _ => 1e-7,
13815 }
13816 } else {
13817 1e-7
13818 };
13819
13820 let mut gradient = Vec::with_capacity(arr.len());
13821 for (i, xi) in arr.iter().enumerate() {
13822 let xi_val = match xi {
13823 Value::Float(f) => *f,
13824 Value::Int(n) => *n as f64,
13825 _ => continue,
13826 };
13827
13828 let mut x_plus = arr.clone();
13830 let mut x_minus = arr.clone();
13831 x_plus[i] = Value::Float(xi_val + h);
13832 x_minus[i] = Value::Float(xi_val - h);
13833
13834 let f_plus = interp
13835 .call_function(&func, vec![Value::Array(Rc::new(RefCell::new(x_plus)))])?;
13836 let f_minus = interp
13837 .call_function(&func, vec![Value::Array(Rc::new(RefCell::new(x_minus)))])?;
13838
13839 let grad_i = match (f_plus, f_minus) {
13840 (Value::Float(fp), Value::Float(fm)) => (fp - fm) / (2.0 * h),
13841 (Value::Int(fp), Value::Int(fm)) => (fp - fm) as f64 / (2.0 * h),
13842 _ => return Err(RuntimeError::new("grad: function must return numeric")),
13843 };
13844
13845 gradient.push(Value::Float(grad_i));
13846 }
13847
13848 return Ok(Value::Array(Rc::new(RefCell::new(gradient))));
13849 }
13850 _ => return Err(RuntimeError::new("grad: x must be numeric or array")),
13851 };
13852
13853 let h = if args.len() > 2 {
13854 match &args[2] {
13855 Value::Float(f) => *f,
13856 Value::Int(n) => *n as f64,
13857 _ => 1e-7,
13858 }
13859 } else {
13860 1e-7
13861 };
13862
13863 let f_plus = interp.call_function(&func, vec![Value::Float(x + h)])?;
13865 let f_minus = interp.call_function(&func, vec![Value::Float(x - h)])?;
13866
13867 let derivative = match (f_plus, f_minus) {
13868 (Value::Float(fp), Value::Float(fm)) => (fp - fm) / (2.0 * h),
13869 (Value::Int(fp), Value::Int(fm)) => (fp - fm) as f64 / (2.0 * h),
13870 _ => return Err(RuntimeError::new("grad: function must return numeric")),
13871 };
13872
13873 Ok(Value::Float(derivative))
13874 });
13875
13876 define(interp, "jacobian", Some(2), |interp, args| {
13878 let func = match &args[0] {
13879 Value::Function(f) => f.clone(),
13880 _ => {
13881 return Err(RuntimeError::new(
13882 "jacobian: first argument must be a function",
13883 ))
13884 }
13885 };
13886 let x = match &args[1] {
13887 Value::Array(arr) => arr.borrow().clone(),
13888 _ => return Err(RuntimeError::new("jacobian: second argument must be array")),
13889 };
13890
13891 let h = 1e-7;
13892 let n = x.len();
13893
13894 let f_x =
13896 interp.call_function(&func, vec![Value::Array(Rc::new(RefCell::new(x.clone())))])?;
13897 let m = match &f_x {
13898 Value::Array(arr) => arr.borrow().len(),
13899 _ => 1,
13900 };
13901
13902 let mut jacobian: Vec<Value> = Vec::with_capacity(m * n);
13904
13905 for j in 0..n {
13906 let xj = match &x[j] {
13907 Value::Float(f) => *f,
13908 Value::Int(i) => *i as f64,
13909 _ => continue,
13910 };
13911
13912 let mut x_plus = x.clone();
13913 let mut x_minus = x.clone();
13914 x_plus[j] = Value::Float(xj + h);
13915 x_minus[j] = Value::Float(xj - h);
13916
13917 let f_plus =
13918 interp.call_function(&func, vec![Value::Array(Rc::new(RefCell::new(x_plus)))])?;
13919 let f_minus =
13920 interp.call_function(&func, vec![Value::Array(Rc::new(RefCell::new(x_minus)))])?;
13921
13922 match (&f_plus, &f_minus) {
13924 (Value::Array(fp), Value::Array(fm)) => {
13925 let fp = fp.borrow();
13926 let fm = fm.borrow();
13927 for i in 0..m {
13928 let dfi_dxj = match (&fp[i], &fm[i]) {
13929 (Value::Float(a), Value::Float(b)) => (*a - *b) / (2.0 * h),
13930 (Value::Int(a), Value::Int(b)) => (*a - *b) as f64 / (2.0 * h),
13931 _ => 0.0,
13932 };
13933 jacobian.push(Value::Float(dfi_dxj));
13934 }
13935 }
13936 (Value::Float(fp), Value::Float(fm)) => {
13937 jacobian.push(Value::Float((fp - fm) / (2.0 * h)));
13938 }
13939 _ => {
13940 return Err(RuntimeError::new(
13941 "jacobian: function must return array or numeric",
13942 ))
13943 }
13944 }
13945 }
13946
13947 Ok(Value::Array(Rc::new(RefCell::new(jacobian))))
13948 });
13949
13950 define(interp, "hessian", Some(2), |interp, args| {
13952 let func = match &args[0] {
13953 Value::Function(f) => f.clone(),
13954 _ => {
13955 return Err(RuntimeError::new(
13956 "hessian: first argument must be a function",
13957 ))
13958 }
13959 };
13960 let x = match &args[1] {
13961 Value::Array(arr) => arr.borrow().clone(),
13962 _ => return Err(RuntimeError::new("hessian: second argument must be array")),
13963 };
13964
13965 let h = 1e-5; let n = x.len();
13967
13968 let mut hessian: Vec<Value> = Vec::with_capacity(n * n);
13969
13970 for i in 0..n {
13971 for j in 0..n {
13972 let xi = match &x[i] {
13973 Value::Float(f) => *f,
13974 Value::Int(k) => *k as f64,
13975 _ => continue,
13976 };
13977 let xj = match &x[j] {
13978 Value::Float(f) => *f,
13979 Value::Int(k) => *k as f64,
13980 _ => continue,
13981 };
13982
13983 let mut x_pp = x.clone();
13985 let mut x_pm = x.clone();
13986 let mut x_mp = x.clone();
13987 let mut x_mm = x.clone();
13988
13989 x_pp[i] = Value::Float(xi + h);
13990 x_pp[j] = Value::Float(if i == j { xi + 2.0 * h } else { xj + h });
13991 x_pm[i] = Value::Float(xi + h);
13992 x_pm[j] = Value::Float(if i == j { xi } else { xj - h });
13993 x_mp[i] = Value::Float(xi - h);
13994 x_mp[j] = Value::Float(if i == j { xi } else { xj + h });
13995 x_mm[i] = Value::Float(xi - h);
13996 x_mm[j] = Value::Float(if i == j { xi - 2.0 * h } else { xj - h });
13997
13998 let f_pp =
13999 interp.call_function(&func, vec![Value::Array(Rc::new(RefCell::new(x_pp)))])?;
14000 let f_pm =
14001 interp.call_function(&func, vec![Value::Array(Rc::new(RefCell::new(x_pm)))])?;
14002 let f_mp =
14003 interp.call_function(&func, vec![Value::Array(Rc::new(RefCell::new(x_mp)))])?;
14004 let f_mm =
14005 interp.call_function(&func, vec![Value::Array(Rc::new(RefCell::new(x_mm)))])?;
14006
14007 let d2f = match (f_pp, f_pm, f_mp, f_mm) {
14008 (
14009 Value::Float(fpp),
14010 Value::Float(fpm),
14011 Value::Float(fmp),
14012 Value::Float(fmm),
14013 ) => (fpp - fpm - fmp + fmm) / (4.0 * h * h),
14014 _ => 0.0,
14015 };
14016
14017 hessian.push(Value::Float(d2f));
14018 }
14019 }
14020
14021 Ok(Value::Array(Rc::new(RefCell::new(hessian))))
14022 });
14023
14024 define(interp, "divergence", Some(2), |interp, args| {
14026 let func = match &args[0] {
14027 Value::Function(f) => f.clone(),
14028 _ => {
14029 return Err(RuntimeError::new(
14030 "divergence: first argument must be a function",
14031 ))
14032 }
14033 };
14034 let x = match &args[1] {
14035 Value::Array(arr) => arr.borrow().clone(),
14036 _ => {
14037 return Err(RuntimeError::new(
14038 "divergence: second argument must be array",
14039 ))
14040 }
14041 };
14042
14043 let h = 1e-7;
14044 let mut div = 0.0f64;
14045
14046 for (i, xi) in x.iter().enumerate() {
14047 let xi_val = match xi {
14048 Value::Float(f) => *f,
14049 Value::Int(n) => *n as f64,
14050 _ => continue,
14051 };
14052
14053 let mut x_plus = x.clone();
14054 let mut x_minus = x.clone();
14055 x_plus[i] = Value::Float(xi_val + h);
14056 x_minus[i] = Value::Float(xi_val - h);
14057
14058 let f_plus =
14059 interp.call_function(&func, vec![Value::Array(Rc::new(RefCell::new(x_plus)))])?;
14060 let f_minus =
14061 interp.call_function(&func, vec![Value::Array(Rc::new(RefCell::new(x_minus)))])?;
14062
14063 let df_i = match (&f_plus, &f_minus) {
14065 (Value::Array(fp), Value::Array(fm)) => {
14066 let fp = fp.borrow();
14067 let fm = fm.borrow();
14068 if i < fp.len() && i < fm.len() {
14069 match (&fp[i], &fm[i]) {
14070 (Value::Float(a), Value::Float(b)) => (*a - *b) / (2.0 * h),
14071 (Value::Int(a), Value::Int(b)) => (*a - *b) as f64 / (2.0 * h),
14072 _ => 0.0,
14073 }
14074 } else {
14075 0.0
14076 }
14077 }
14078 _ => 0.0,
14079 };
14080
14081 div += df_i;
14082 }
14083
14084 Ok(Value::Float(div))
14085 });
14086}
14087
14088fn register_spatial(interp: &mut Interpreter) {
14094 define(interp, "spatial_hash_new", Some(1), |_, args| {
14096 let cell_size = match &args[0] {
14097 Value::Float(f) => *f,
14098 Value::Int(n) => *n as f64,
14099 _ => {
14100 return Err(RuntimeError::new(
14101 "spatial_hash_new: cell_size must be numeric",
14102 ))
14103 }
14104 };
14105
14106 let mut config = HashMap::new();
14107 config.insert("cell_size".to_string(), Value::Float(cell_size));
14108 config.insert(
14109 "buckets".to_string(),
14110 Value::Map(Rc::new(RefCell::new(HashMap::new()))),
14111 );
14112
14113 Ok(Value::Map(Rc::new(RefCell::new(config))))
14114 });
14115
14116 define(interp, "spatial_hash_insert", Some(3), |_, args| {
14118 let hash = match &args[0] {
14119 Value::Map(map) => map.clone(),
14120 _ => {
14121 return Err(RuntimeError::new(
14122 "spatial_hash_insert: first argument must be spatial hash",
14123 ))
14124 }
14125 };
14126 let id = args[1].clone();
14127 let pos = match &args[2] {
14128 Value::Array(arr) => arr.borrow().clone(),
14129 _ => {
14130 return Err(RuntimeError::new(
14131 "spatial_hash_insert: position must be array",
14132 ))
14133 }
14134 };
14135
14136 let cell_size = {
14137 let h = hash.borrow();
14138 match h.get("cell_size") {
14139 Some(Value::Float(f)) => *f,
14140 _ => 1.0,
14141 }
14142 };
14143
14144 let key = pos
14146 .iter()
14147 .filter_map(|v| match v {
14148 Value::Float(f) => Some((*f / cell_size).floor() as i64),
14149 Value::Int(n) => Some(*n / (cell_size as i64)),
14150 _ => None,
14151 })
14152 .map(|n| n.to_string())
14153 .collect::<Vec<_>>()
14154 .join(",");
14155
14156 {
14158 let mut h = hash.borrow_mut();
14159 let buckets = h
14160 .entry("buckets".to_string())
14161 .or_insert_with(|| Value::Map(Rc::new(RefCell::new(HashMap::new()))));
14162
14163 if let Value::Map(buckets_map) = buckets {
14164 let mut bm = buckets_map.borrow_mut();
14165 let bucket = bm
14166 .entry(key)
14167 .or_insert_with(|| Value::Array(Rc::new(RefCell::new(vec![]))));
14168
14169 if let Value::Array(arr) = bucket {
14170 arr.borrow_mut().push(id);
14171 }
14172 }
14173 }
14174
14175 Ok(Value::Map(hash))
14176 });
14177
14178 define(interp, "spatial_hash_query", Some(3), |_, args| {
14180 let hash = match &args[0] {
14181 Value::Map(map) => map.borrow().clone(),
14182 _ => {
14183 return Err(RuntimeError::new(
14184 "spatial_hash_query: first argument must be spatial hash",
14185 ))
14186 }
14187 };
14188 let pos = match &args[1] {
14189 Value::Array(arr) => arr.borrow().clone(),
14190 _ => {
14191 return Err(RuntimeError::new(
14192 "spatial_hash_query: position must be array",
14193 ))
14194 }
14195 };
14196 let radius = match &args[2] {
14197 Value::Float(f) => *f,
14198 Value::Int(n) => *n as f64,
14199 _ => {
14200 return Err(RuntimeError::new(
14201 "spatial_hash_query: radius must be numeric",
14202 ))
14203 }
14204 };
14205
14206 let cell_size = match hash.get("cell_size") {
14207 Some(Value::Float(f)) => *f,
14208 _ => 1.0,
14209 };
14210
14211 let center: Vec<i64> = pos
14213 .iter()
14214 .filter_map(|v| match v {
14215 Value::Float(f) => Some((*f / cell_size).floor() as i64),
14216 Value::Int(n) => Some(*n / (cell_size as i64)),
14217 _ => None,
14218 })
14219 .collect();
14220
14221 let cells_to_check = (radius / cell_size).ceil() as i64;
14223
14224 let mut results: Vec<Value> = Vec::new();
14225
14226 if let Some(Value::Map(buckets)) = hash.get("buckets") {
14227 let buckets = buckets.borrow();
14228
14229 if center.len() >= 2 {
14231 for dx in -cells_to_check..=cells_to_check {
14232 for dy in -cells_to_check..=cells_to_check {
14233 let key = format!("{},{}", center[0] + dx, center[1] + dy);
14234 if let Some(Value::Array(bucket)) = buckets.get(&key) {
14235 for item in bucket.borrow().iter() {
14236 results.push(item.clone());
14239 }
14240 }
14241 }
14242 }
14243 }
14244 }
14245
14246 Ok(Value::Array(Rc::new(RefCell::new(results))))
14247 });
14248
14249 define(interp, "aabb_new", Some(2), |_, args| {
14251 let min = match &args[0] {
14252 Value::Array(arr) => arr.borrow().clone(),
14253 _ => return Err(RuntimeError::new("aabb_new: min must be array")),
14254 };
14255 let max = match &args[1] {
14256 Value::Array(arr) => arr.borrow().clone(),
14257 _ => return Err(RuntimeError::new("aabb_new: max must be array")),
14258 };
14259
14260 let mut aabb = HashMap::new();
14261 aabb.insert("min".to_string(), Value::Array(Rc::new(RefCell::new(min))));
14262 aabb.insert("max".to_string(), Value::Array(Rc::new(RefCell::new(max))));
14263
14264 Ok(Value::Map(Rc::new(RefCell::new(aabb))))
14265 });
14266
14267 define(interp, "aabb_intersects", Some(2), |_, args| {
14269 let a = match &args[0] {
14270 Value::Map(map) => map.borrow().clone(),
14271 _ => {
14272 return Err(RuntimeError::new(
14273 "aabb_intersects: arguments must be AABBs",
14274 ))
14275 }
14276 };
14277 let b = match &args[1] {
14278 Value::Map(map) => map.borrow().clone(),
14279 _ => {
14280 return Err(RuntimeError::new(
14281 "aabb_intersects: arguments must be AABBs",
14282 ))
14283 }
14284 };
14285
14286 let a_min = extract_vec_from_map(&a, "min")?;
14287 let a_max = extract_vec_from_map(&a, "max")?;
14288 let b_min = extract_vec_from_map(&b, "min")?;
14289 let b_max = extract_vec_from_map(&b, "max")?;
14290
14291 for i in 0..a_min
14293 .len()
14294 .min(a_max.len())
14295 .min(b_min.len())
14296 .min(b_max.len())
14297 {
14298 if a_max[i] < b_min[i] || b_max[i] < a_min[i] {
14299 return Ok(Value::Bool(false));
14300 }
14301 }
14302
14303 Ok(Value::Bool(true))
14304 });
14305
14306 define(interp, "aabb_contains", Some(2), |_, args| {
14308 let aabb = match &args[0] {
14309 Value::Map(map) => map.borrow().clone(),
14310 _ => {
14311 return Err(RuntimeError::new(
14312 "aabb_contains: first argument must be AABB",
14313 ))
14314 }
14315 };
14316 let point = match &args[1] {
14317 Value::Array(arr) => arr.borrow().clone(),
14318 _ => {
14319 return Err(RuntimeError::new(
14320 "aabb_contains: second argument must be point array",
14321 ))
14322 }
14323 };
14324
14325 let min = extract_vec_from_map(&aabb, "min")?;
14326 let max = extract_vec_from_map(&aabb, "max")?;
14327
14328 for (i, p) in point.iter().enumerate() {
14329 let p_val = match p {
14330 Value::Float(f) => *f,
14331 Value::Int(n) => *n as f64,
14332 _ => continue,
14333 };
14334
14335 if i < min.len() && p_val < min[i] {
14336 return Ok(Value::Bool(false));
14337 }
14338 if i < max.len() && p_val > max[i] {
14339 return Ok(Value::Bool(false));
14340 }
14341 }
14342
14343 Ok(Value::Bool(true))
14344 });
14345}
14346
14347fn extract_vec_from_map(map: &HashMap<String, Value>, key: &str) -> Result<Vec<f64>, RuntimeError> {
14349 match map.get(key) {
14350 Some(Value::Array(arr)) => arr
14351 .borrow()
14352 .iter()
14353 .map(|v| match v {
14354 Value::Float(f) => Ok(*f),
14355 Value::Int(n) => Ok(*n as f64),
14356 _ => Err(RuntimeError::new("Expected numeric value")),
14357 })
14358 .collect(),
14359 _ => Err(RuntimeError::new(format!(
14360 "Missing or invalid '{}' in AABB",
14361 key
14362 ))),
14363 }
14364}
14365
14366fn register_physics(interp: &mut Interpreter) {
14372 define(interp, "verlet_integrate", Some(4), |_, args| {
14375 let pos = extract_vec3(&args[0], "verlet_integrate")?;
14376 let prev = extract_vec3(&args[1], "verlet_integrate")?;
14377 let accel = extract_vec3(&args[2], "verlet_integrate")?;
14378 let dt = match &args[3] {
14379 Value::Float(f) => *f,
14380 Value::Int(n) => *n as f64,
14381 _ => return Err(RuntimeError::new("verlet_integrate: dt must be numeric")),
14382 };
14383
14384 let dt2 = dt * dt;
14385 let new_pos = [
14386 pos[0] + (pos[0] - prev[0]) + accel[0] * dt2,
14387 pos[1] + (pos[1] - prev[1]) + accel[1] * dt2,
14388 pos[2] + (pos[2] - prev[2]) + accel[2] * dt2,
14389 ];
14390
14391 Ok(make_vec3_arr(new_pos))
14392 });
14393
14394 define(interp, "spring_force", Some(4), |_, args| {
14396 let p1 = extract_vec3(&args[0], "spring_force")?;
14397 let p2 = extract_vec3(&args[1], "spring_force")?;
14398 let rest_length = match &args[2] {
14399 Value::Float(f) => *f,
14400 Value::Int(n) => *n as f64,
14401 _ => {
14402 return Err(RuntimeError::new(
14403 "spring_force: rest_length must be numeric",
14404 ))
14405 }
14406 };
14407 let stiffness = match &args[3] {
14408 Value::Float(f) => *f,
14409 Value::Int(n) => *n as f64,
14410 _ => return Err(RuntimeError::new("spring_force: stiffness must be numeric")),
14411 };
14412
14413 let delta = [p2[0] - p1[0], p2[1] - p1[1], p2[2] - p1[2]];
14414 let length = (delta[0] * delta[0] + delta[1] * delta[1] + delta[2] * delta[2]).sqrt();
14415
14416 if length < 1e-10 {
14417 return Ok(make_vec3_arr([0.0, 0.0, 0.0]));
14418 }
14419
14420 let displacement = length - rest_length;
14421 let force_mag = stiffness * displacement;
14422 let normalized = [delta[0] / length, delta[1] / length, delta[2] / length];
14423
14424 Ok(make_vec3_arr([
14425 normalized[0] * force_mag,
14426 normalized[1] * force_mag,
14427 normalized[2] * force_mag,
14428 ]))
14429 });
14430
14431 define(interp, "distance_constraint", Some(3), |_, args| {
14434 let p1 = extract_vec3(&args[0], "distance_constraint")?;
14435 let p2 = extract_vec3(&args[1], "distance_constraint")?;
14436 let target = match &args[2] {
14437 Value::Float(f) => *f,
14438 Value::Int(n) => *n as f64,
14439 _ => {
14440 return Err(RuntimeError::new(
14441 "distance_constraint: target must be numeric",
14442 ))
14443 }
14444 };
14445
14446 let delta = [p2[0] - p1[0], p2[1] - p1[1], p2[2] - p1[2]];
14447 let length = (delta[0] * delta[0] + delta[1] * delta[1] + delta[2] * delta[2]).sqrt();
14448
14449 if length < 1e-10 {
14450 return Ok(Value::Tuple(Rc::new(vec![
14451 make_vec3_arr(p1),
14452 make_vec3_arr(p2),
14453 ])));
14454 }
14455
14456 let correction = (length - target) / length * 0.5;
14457 let corr_vec = [
14458 delta[0] * correction,
14459 delta[1] * correction,
14460 delta[2] * correction,
14461 ];
14462
14463 let new_p1 = [
14464 p1[0] + corr_vec[0],
14465 p1[1] + corr_vec[1],
14466 p1[2] + corr_vec[2],
14467 ];
14468 let new_p2 = [
14469 p2[0] - corr_vec[0],
14470 p2[1] - corr_vec[1],
14471 p2[2] - corr_vec[2],
14472 ];
14473
14474 Ok(Value::Tuple(Rc::new(vec![
14475 make_vec3_arr(new_p1),
14476 make_vec3_arr(new_p2),
14477 ])))
14478 });
14479
14480 define(interp, "solve_constraints", Some(3), |_, args| {
14483 let mut points = match &args[0] {
14484 Value::Array(arr) => arr.borrow().clone(),
14485 _ => {
14486 return Err(RuntimeError::new(
14487 "solve_constraints: first argument must be array of points",
14488 ))
14489 }
14490 };
14491 let constraints = match &args[1] {
14492 Value::Array(arr) => arr.borrow().clone(),
14493 _ => {
14494 return Err(RuntimeError::new(
14495 "solve_constraints: second argument must be array of constraints",
14496 ))
14497 }
14498 };
14499 let iterations = match &args[2] {
14500 Value::Int(n) => *n as usize,
14501 _ => {
14502 return Err(RuntimeError::new(
14503 "solve_constraints: iterations must be integer",
14504 ))
14505 }
14506 };
14507
14508 for _ in 0..iterations {
14509 for constraint in &constraints {
14510 match constraint {
14511 Value::Map(c) => {
14512 let c = c.borrow();
14513 let constraint_type = c
14514 .get("type")
14515 .and_then(|v| {
14516 if let Value::String(s) = v {
14517 Some((**s).clone())
14518 } else {
14519 None
14520 }
14521 })
14522 .unwrap_or_default();
14523
14524 match constraint_type.as_str() {
14525 "distance" => {
14526 let indices = match c.get("indices") {
14527 Some(Value::Array(arr)) => arr.borrow().clone(),
14528 _ => continue,
14529 };
14530 let target = match c.get("distance") {
14531 Some(Value::Float(f)) => *f,
14532 Some(Value::Int(n)) => *n as f64,
14533 _ => continue,
14534 };
14535
14536 if indices.len() >= 2 {
14537 let i1 = match &indices[0] {
14538 Value::Int(n) => *n as usize,
14539 _ => continue,
14540 };
14541 let i2 = match &indices[1] {
14542 Value::Int(n) => *n as usize,
14543 _ => continue,
14544 };
14545
14546 if i1 < points.len() && i2 < points.len() {
14547 let p1 = extract_vec3(&points[i1], "solve")?;
14549 let p2 = extract_vec3(&points[i2], "solve")?;
14550
14551 let delta = [p2[0] - p1[0], p2[1] - p1[1], p2[2] - p1[2]];
14552 let length = (delta[0] * delta[0]
14553 + delta[1] * delta[1]
14554 + delta[2] * delta[2])
14555 .sqrt();
14556
14557 if length > 1e-10 {
14558 let correction = (length - target) / length * 0.5;
14559 let corr_vec = [
14560 delta[0] * correction,
14561 delta[1] * correction,
14562 delta[2] * correction,
14563 ];
14564
14565 points[i1] = make_vec3_arr([
14566 p1[0] + corr_vec[0],
14567 p1[1] + corr_vec[1],
14568 p1[2] + corr_vec[2],
14569 ]);
14570 points[i2] = make_vec3_arr([
14571 p2[0] - corr_vec[0],
14572 p2[1] - corr_vec[1],
14573 p2[2] - corr_vec[2],
14574 ]);
14575 }
14576 }
14577 }
14578 }
14579 _ => {}
14580 }
14581 }
14582 _ => continue,
14583 }
14584 }
14585 }
14586
14587 Ok(Value::Array(Rc::new(RefCell::new(points))))
14588 });
14589
14590 define(interp, "ray_sphere_intersect", Some(4), |_, args| {
14593 let origin = extract_vec3(&args[0], "ray_sphere_intersect")?;
14594 let dir = extract_vec3(&args[1], "ray_sphere_intersect")?;
14595 let center = extract_vec3(&args[2], "ray_sphere_intersect")?;
14596 let radius = match &args[3] {
14597 Value::Float(f) => *f,
14598 Value::Int(n) => *n as f64,
14599 _ => {
14600 return Err(RuntimeError::new(
14601 "ray_sphere_intersect: radius must be numeric",
14602 ))
14603 }
14604 };
14605
14606 let oc = [
14607 origin[0] - center[0],
14608 origin[1] - center[1],
14609 origin[2] - center[2],
14610 ];
14611
14612 let a = dir[0] * dir[0] + dir[1] * dir[1] + dir[2] * dir[2];
14613 let b = 2.0 * (oc[0] * dir[0] + oc[1] * dir[1] + oc[2] * dir[2]);
14614 let c = oc[0] * oc[0] + oc[1] * oc[1] + oc[2] * oc[2] - radius * radius;
14615
14616 let discriminant = b * b - 4.0 * a * c;
14617
14618 if discriminant < 0.0 {
14619 Ok(Value::Float(-1.0))
14620 } else {
14621 let t = (-b - discriminant.sqrt()) / (2.0 * a);
14622 if t > 0.0 {
14623 Ok(Value::Float(t))
14624 } else {
14625 let t2 = (-b + discriminant.sqrt()) / (2.0 * a);
14626 if t2 > 0.0 {
14627 Ok(Value::Float(t2))
14628 } else {
14629 Ok(Value::Float(-1.0))
14630 }
14631 }
14632 }
14633 });
14634
14635 define(interp, "ray_plane_intersect", Some(4), |_, args| {
14637 let origin = extract_vec3(&args[0], "ray_plane_intersect")?;
14638 let dir = extract_vec3(&args[1], "ray_plane_intersect")?;
14639 let plane_pt = extract_vec3(&args[2], "ray_plane_intersect")?;
14640 let normal = extract_vec3(&args[3], "ray_plane_intersect")?;
14641
14642 let denom = dir[0] * normal[0] + dir[1] * normal[1] + dir[2] * normal[2];
14643
14644 if denom.abs() < 1e-10 {
14645 return Ok(Value::Float(-1.0)); }
14647
14648 let diff = [
14649 plane_pt[0] - origin[0],
14650 plane_pt[1] - origin[1],
14651 plane_pt[2] - origin[2],
14652 ];
14653 let t = (diff[0] * normal[0] + diff[1] * normal[1] + diff[2] * normal[2]) / denom;
14654
14655 if t > 0.0 {
14656 Ok(Value::Float(t))
14657 } else {
14658 Ok(Value::Float(-1.0))
14659 }
14660 });
14661}
14662
14663fn register_geometric_algebra(interp: &mut Interpreter) {
14725 fn make_multivector(components: [f64; 8]) -> Value {
14727 let mut mv = HashMap::new();
14728 mv.insert("s".to_string(), Value::Float(components[0])); mv.insert("e1".to_string(), Value::Float(components[1])); mv.insert("e2".to_string(), Value::Float(components[2])); mv.insert("e3".to_string(), Value::Float(components[3])); mv.insert("e12".to_string(), Value::Float(components[4])); mv.insert("e23".to_string(), Value::Float(components[5])); mv.insert("e31".to_string(), Value::Float(components[6])); mv.insert("e123".to_string(), Value::Float(components[7])); mv.insert(
14737 "_type".to_string(),
14738 Value::String(Rc::new("multivector".to_string())),
14739 );
14740 Value::Map(Rc::new(RefCell::new(mv)))
14741 }
14742
14743 fn extract_multivector(v: &Value, fn_name: &str) -> Result<[f64; 8], RuntimeError> {
14744 match v {
14745 Value::Map(map) => {
14746 let map = map.borrow();
14747 let get_component = |key: &str| -> f64 {
14748 match map.get(key) {
14749 Some(Value::Float(f)) => *f,
14750 Some(Value::Int(n)) => *n as f64,
14751 _ => 0.0,
14752 }
14753 };
14754 Ok([
14755 get_component("s"),
14756 get_component("e1"),
14757 get_component("e2"),
14758 get_component("e3"),
14759 get_component("e12"),
14760 get_component("e23"),
14761 get_component("e31"),
14762 get_component("e123"),
14763 ])
14764 }
14765 _ => Err(RuntimeError::new(format!(
14766 "{}: expected multivector",
14767 fn_name
14768 ))),
14769 }
14770 }
14771
14772 define(interp, "mv_new", Some(8), |_, args| {
14774 let mut components = [0.0f64; 8];
14775 for (i, arg) in args.iter().enumerate().take(8) {
14776 components[i] = match arg {
14777 Value::Float(f) => *f,
14778 Value::Int(n) => *n as f64,
14779 _ => 0.0,
14780 };
14781 }
14782 Ok(make_multivector(components))
14783 });
14784
14785 define(interp, "mv_scalar", Some(1), |_, args| {
14787 let s = match &args[0] {
14788 Value::Float(f) => *f,
14789 Value::Int(n) => *n as f64,
14790 _ => return Err(RuntimeError::new("mv_scalar: expected number")),
14791 };
14792 Ok(make_multivector([s, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]))
14793 });
14794
14795 define(interp, "mv_vector", Some(3), |_, args| {
14797 let x = match &args[0] {
14798 Value::Float(f) => *f,
14799 Value::Int(n) => *n as f64,
14800 _ => 0.0,
14801 };
14802 let y = match &args[1] {
14803 Value::Float(f) => *f,
14804 Value::Int(n) => *n as f64,
14805 _ => 0.0,
14806 };
14807 let z = match &args[2] {
14808 Value::Float(f) => *f,
14809 Value::Int(n) => *n as f64,
14810 _ => 0.0,
14811 };
14812 Ok(make_multivector([0.0, x, y, z, 0.0, 0.0, 0.0, 0.0]))
14813 });
14814
14815 define(interp, "mv_bivector", Some(3), |_, args| {
14817 let xy = match &args[0] {
14818 Value::Float(f) => *f,
14819 Value::Int(n) => *n as f64,
14820 _ => 0.0,
14821 };
14822 let yz = match &args[1] {
14823 Value::Float(f) => *f,
14824 Value::Int(n) => *n as f64,
14825 _ => 0.0,
14826 };
14827 let zx = match &args[2] {
14828 Value::Float(f) => *f,
14829 Value::Int(n) => *n as f64,
14830 _ => 0.0,
14831 };
14832 Ok(make_multivector([0.0, 0.0, 0.0, 0.0, xy, yz, zx, 0.0]))
14833 });
14834
14835 define(interp, "mv_trivector", Some(1), |_, args| {
14837 let xyz = match &args[0] {
14838 Value::Float(f) => *f,
14839 Value::Int(n) => *n as f64,
14840 _ => 0.0,
14841 };
14842 Ok(make_multivector([0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, xyz]))
14843 });
14844
14845 define(interp, "mv_add", Some(2), |_, args| {
14847 let a = extract_multivector(&args[0], "mv_add")?;
14848 let b = extract_multivector(&args[1], "mv_add")?;
14849 Ok(make_multivector([
14850 a[0] + b[0],
14851 a[1] + b[1],
14852 a[2] + b[2],
14853 a[3] + b[3],
14854 a[4] + b[4],
14855 a[5] + b[5],
14856 a[6] + b[6],
14857 a[7] + b[7],
14858 ]))
14859 });
14860
14861 define(interp, "mv_sub", Some(2), |_, args| {
14863 let a = extract_multivector(&args[0], "mv_sub")?;
14864 let b = extract_multivector(&args[1], "mv_sub")?;
14865 Ok(make_multivector([
14866 a[0] - b[0],
14867 a[1] - b[1],
14868 a[2] - b[2],
14869 a[3] - b[3],
14870 a[4] - b[4],
14871 a[5] - b[5],
14872 a[6] - b[6],
14873 a[7] - b[7],
14874 ]))
14875 });
14876
14877 define(interp, "mv_scale", Some(2), |_, args| {
14879 let a = extract_multivector(&args[0], "mv_scale")?;
14880 let s = match &args[1] {
14881 Value::Float(f) => *f,
14882 Value::Int(n) => *n as f64,
14883 _ => {
14884 return Err(RuntimeError::new(
14885 "mv_scale: second argument must be number",
14886 ))
14887 }
14888 };
14889 Ok(make_multivector([
14890 a[0] * s,
14891 a[1] * s,
14892 a[2] * s,
14893 a[3] * s,
14894 a[4] * s,
14895 a[5] * s,
14896 a[6] * s,
14897 a[7] * s,
14898 ]))
14899 });
14900
14901 define(interp, "mv_geometric", Some(2), |_, args| {
14904 let a = extract_multivector(&args[0], "mv_geometric")?;
14905 let b = extract_multivector(&args[1], "mv_geometric")?;
14906
14907 let mut r = [0.0f64; 8];
14910
14911 r[0] = a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]
14913 - a[4] * b[4]
14914 - a[5] * b[5]
14915 - a[6] * b[6]
14916 - a[7] * b[7];
14917
14918 r[1] = a[0] * b[1] + a[1] * b[0] - a[2] * b[4] + a[3] * b[6] + a[4] * b[2]
14920 - a[5] * b[7]
14921 - a[6] * b[3]
14922 - a[7] * b[5];
14923
14924 r[2] = a[0] * b[2] + a[1] * b[4] + a[2] * b[0] - a[3] * b[5] - a[4] * b[1] + a[5] * b[3]
14926 - a[6] * b[7]
14927 - a[7] * b[6];
14928
14929 r[3] = a[0] * b[3] - a[1] * b[6] + a[2] * b[5] + a[3] * b[0] - a[4] * b[7] - a[5] * b[2]
14931 + a[6] * b[1]
14932 - a[7] * b[4];
14933
14934 r[4] = a[0] * b[4] + a[1] * b[2] - a[2] * b[1] + a[3] * b[7] + a[4] * b[0] + a[5] * b[6]
14936 - a[6] * b[5]
14937 + a[7] * b[3];
14938
14939 r[5] = a[0] * b[5] + a[1] * b[7] + a[2] * b[3] - a[3] * b[2] - a[4] * b[6]
14941 + a[5] * b[0]
14942 + a[6] * b[4]
14943 + a[7] * b[1];
14944
14945 r[6] = a[0] * b[6] - a[1] * b[3] + a[2] * b[7] + a[3] * b[1] + a[4] * b[5] - a[5] * b[4]
14947 + a[6] * b[0]
14948 + a[7] * b[2];
14949
14950 r[7] = a[0] * b[7]
14952 + a[1] * b[5]
14953 + a[2] * b[6]
14954 + a[3] * b[4]
14955 + a[4] * b[3]
14956 + a[5] * b[1]
14957 + a[6] * b[2]
14958 + a[7] * b[0];
14959
14960 Ok(make_multivector(r))
14961 });
14962
14963 define(interp, "mv_wedge", Some(2), |_, args| {
14966 let a = extract_multivector(&args[0], "mv_wedge")?;
14967 let b = extract_multivector(&args[1], "mv_wedge")?;
14968
14969 let mut r = [0.0f64; 8];
14970
14971 r[0] = a[0] * b[0];
14973
14974 r[1] = a[0] * b[1] + a[1] * b[0];
14976 r[2] = a[0] * b[2] + a[2] * b[0];
14977 r[3] = a[0] * b[3] + a[3] * b[0];
14978
14979 r[4] = a[0] * b[4] + a[1] * b[2] - a[2] * b[1] + a[4] * b[0];
14981 r[5] = a[0] * b[5] + a[2] * b[3] - a[3] * b[2] + a[5] * b[0];
14982 r[6] = a[0] * b[6] + a[3] * b[1] - a[1] * b[3] + a[6] * b[0];
14983
14984 r[7] = a[0] * b[7] + a[7] * b[0] + a[1] * b[5] + a[2] * b[6] + a[3] * b[4]
14986 - a[4] * b[3]
14987 - a[5] * b[1]
14988 - a[6] * b[2];
14989
14990 Ok(make_multivector(r))
14991 });
14992
14993 define(interp, "mv_inner", Some(2), |_, args| {
14996 let a = extract_multivector(&args[0], "mv_inner")?;
14997 let b = extract_multivector(&args[1], "mv_inner")?;
14998
14999 let mut r = [0.0f64; 8];
15000
15001 r[0] = a[1] * b[1] + a[2] * b[2] + a[3] * b[3]
15004 - a[4] * b[4]
15005 - a[5] * b[5]
15006 - a[6] * b[6]
15007 - a[7] * b[7];
15008
15009 r[1] = a[4] * b[2] - a[6] * b[3] - a[5] * b[7];
15011 r[2] = -a[4] * b[1] + a[5] * b[3] - a[6] * b[7];
15012 r[3] = a[6] * b[1] - a[5] * b[2] - a[4] * b[7];
15013
15014 r[4] = a[7] * b[3];
15016 r[5] = a[7] * b[1];
15017 r[6] = a[7] * b[2];
15018
15019 Ok(make_multivector(r))
15020 });
15021
15022 define(interp, "mv_reverse", Some(1), |_, args| {
15025 let a = extract_multivector(&args[0], "mv_reverse")?;
15026 Ok(make_multivector([
15028 a[0], a[1], a[2], a[3], -a[4], -a[5], -a[6], -a[7],
15029 ]))
15030 });
15031
15032 define(interp, "mv_dual", Some(1), |_, args| {
15035 let a = extract_multivector(&args[0], "mv_dual")?;
15036 Ok(make_multivector([
15039 -a[7], -a[5], -a[6], -a[4], a[3], a[1], a[2], a[0], ]))
15048 });
15049
15050 define(interp, "mv_magnitude", Some(1), |_, args| {
15052 let a = extract_multivector(&args[0], "mv_magnitude")?;
15053 let mag_sq = a[0] * a[0]
15054 + a[1] * a[1]
15055 + a[2] * a[2]
15056 + a[3] * a[3]
15057 + a[4] * a[4]
15058 + a[5] * a[5]
15059 + a[6] * a[6]
15060 + a[7] * a[7];
15061 Ok(Value::Float(mag_sq.sqrt()))
15062 });
15063
15064 define(interp, "mv_normalize", Some(1), |_, args| {
15066 let a = extract_multivector(&args[0], "mv_normalize")?;
15067 let mag = (a[0] * a[0]
15068 + a[1] * a[1]
15069 + a[2] * a[2]
15070 + a[3] * a[3]
15071 + a[4] * a[4]
15072 + a[5] * a[5]
15073 + a[6] * a[6]
15074 + a[7] * a[7])
15075 .sqrt();
15076 if mag < 1e-10 {
15077 return Ok(make_multivector([0.0; 8]));
15078 }
15079 Ok(make_multivector([
15080 a[0] / mag,
15081 a[1] / mag,
15082 a[2] / mag,
15083 a[3] / mag,
15084 a[4] / mag,
15085 a[5] / mag,
15086 a[6] / mag,
15087 a[7] / mag,
15088 ]))
15089 });
15090
15091 define(interp, "rotor_from_axis_angle", Some(2), |_, args| {
15094 let axis = extract_vec3(&args[0], "rotor_from_axis_angle")?;
15095 let angle = match &args[1] {
15096 Value::Float(f) => *f,
15097 Value::Int(n) => *n as f64,
15098 _ => {
15099 return Err(RuntimeError::new(
15100 "rotor_from_axis_angle: angle must be number",
15101 ))
15102 }
15103 };
15104
15105 let len = (axis[0] * axis[0] + axis[1] * axis[1] + axis[2] * axis[2]).sqrt();
15107 if len < 1e-10 {
15108 return Ok(make_multivector([1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]));
15110 }
15111 let (nx, ny, nz) = (axis[0] / len, axis[1] / len, axis[2] / len);
15112
15113 let half_angle = angle / 2.0;
15114 let (s, c) = half_angle.sin_cos();
15115
15116 Ok(make_multivector([
15119 c, 0.0,
15121 0.0,
15122 0.0, -s * nz, -s * nx, -s * ny, 0.0, ]))
15128 });
15129
15130 define(interp, "rotor_apply", Some(2), |_, args| {
15133 let r = extract_multivector(&args[0], "rotor_apply")?;
15134 let v = extract_vec3(&args[1], "rotor_apply")?;
15135
15136 let v_mv = [0.0, v[0], v[1], v[2], 0.0, 0.0, 0.0, 0.0];
15138
15139 let r_rev = [r[0], r[1], r[2], r[3], -r[4], -r[5], -r[6], -r[7]];
15141
15142 let mut rv = [0.0f64; 8];
15144 rv[0] = r[0] * v_mv[0] + r[1] * v_mv[1] + r[2] * v_mv[2] + r[3] * v_mv[3]
15145 - r[4] * v_mv[4]
15146 - r[5] * v_mv[5]
15147 - r[6] * v_mv[6]
15148 - r[7] * v_mv[7];
15149 rv[1] = r[0] * v_mv[1] + r[1] * v_mv[0] - r[2] * v_mv[4] + r[3] * v_mv[6] + r[4] * v_mv[2]
15150 - r[5] * v_mv[7]
15151 - r[6] * v_mv[3]
15152 - r[7] * v_mv[5];
15153 rv[2] = r[0] * v_mv[2] + r[1] * v_mv[4] + r[2] * v_mv[0] - r[3] * v_mv[5] - r[4] * v_mv[1]
15154 + r[5] * v_mv[3]
15155 - r[6] * v_mv[7]
15156 - r[7] * v_mv[6];
15157 rv[3] = r[0] * v_mv[3] - r[1] * v_mv[6] + r[2] * v_mv[5] + r[3] * v_mv[0]
15158 - r[4] * v_mv[7]
15159 - r[5] * v_mv[2]
15160 + r[6] * v_mv[1]
15161 - r[7] * v_mv[4];
15162 rv[4] = r[0] * v_mv[4] + r[1] * v_mv[2] - r[2] * v_mv[1]
15163 + r[3] * v_mv[7]
15164 + r[4] * v_mv[0]
15165 + r[5] * v_mv[6]
15166 - r[6] * v_mv[5]
15167 + r[7] * v_mv[3];
15168 rv[5] = r[0] * v_mv[5] + r[1] * v_mv[7] + r[2] * v_mv[3] - r[3] * v_mv[2] - r[4] * v_mv[6]
15169 + r[5] * v_mv[0]
15170 + r[6] * v_mv[4]
15171 + r[7] * v_mv[1];
15172 rv[6] = r[0] * v_mv[6] - r[1] * v_mv[3] + r[2] * v_mv[7] + r[3] * v_mv[1] + r[4] * v_mv[5]
15173 - r[5] * v_mv[4]
15174 + r[6] * v_mv[0]
15175 + r[7] * v_mv[2];
15176 rv[7] = r[0] * v_mv[7]
15177 + r[1] * v_mv[5]
15178 + r[2] * v_mv[6]
15179 + r[3] * v_mv[4]
15180 + r[4] * v_mv[3]
15181 + r[5] * v_mv[1]
15182 + r[6] * v_mv[2]
15183 + r[7] * v_mv[0];
15184
15185 let mut result = [0.0f64; 8];
15187 result[1] = rv[0] * r_rev[1] + rv[1] * r_rev[0] - rv[2] * r_rev[4]
15188 + rv[3] * r_rev[6]
15189 + rv[4] * r_rev[2]
15190 - rv[5] * r_rev[7]
15191 - rv[6] * r_rev[3]
15192 - rv[7] * r_rev[5];
15193 result[2] = rv[0] * r_rev[2] + rv[1] * r_rev[4] + rv[2] * r_rev[0]
15194 - rv[3] * r_rev[5]
15195 - rv[4] * r_rev[1]
15196 + rv[5] * r_rev[3]
15197 - rv[6] * r_rev[7]
15198 - rv[7] * r_rev[6];
15199 result[3] = rv[0] * r_rev[3] - rv[1] * r_rev[6] + rv[2] * r_rev[5] + rv[3] * r_rev[0]
15200 - rv[4] * r_rev[7]
15201 - rv[5] * r_rev[2]
15202 + rv[6] * r_rev[1]
15203 - rv[7] * r_rev[4];
15204
15205 Ok(make_vec3(result[1], result[2], result[3]))
15207 });
15208
15209 define(interp, "rotor_compose", Some(2), |_, args| {
15211 let a = extract_multivector(&args[0], "rotor_compose")?;
15212 let b = extract_multivector(&args[1], "rotor_compose")?;
15213
15214 let mut r = [0.0f64; 8];
15216 r[0] = a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]
15217 - a[4] * b[4]
15218 - a[5] * b[5]
15219 - a[6] * b[6]
15220 - a[7] * b[7];
15221 r[1] = a[0] * b[1] + a[1] * b[0] - a[2] * b[4] + a[3] * b[6] + a[4] * b[2]
15222 - a[5] * b[7]
15223 - a[6] * b[3]
15224 - a[7] * b[5];
15225 r[2] = a[0] * b[2] + a[1] * b[4] + a[2] * b[0] - a[3] * b[5] - a[4] * b[1] + a[5] * b[3]
15226 - a[6] * b[7]
15227 - a[7] * b[6];
15228 r[3] = a[0] * b[3] - a[1] * b[6] + a[2] * b[5] + a[3] * b[0] - a[4] * b[7] - a[5] * b[2]
15229 + a[6] * b[1]
15230 - a[7] * b[4];
15231 r[4] = a[0] * b[4] + a[1] * b[2] - a[2] * b[1] + a[3] * b[7] + a[4] * b[0] + a[5] * b[6]
15232 - a[6] * b[5]
15233 + a[7] * b[3];
15234 r[5] = a[0] * b[5] + a[1] * b[7] + a[2] * b[3] - a[3] * b[2] - a[4] * b[6]
15235 + a[5] * b[0]
15236 + a[6] * b[4]
15237 + a[7] * b[1];
15238 r[6] = a[0] * b[6] - a[1] * b[3] + a[2] * b[7] + a[3] * b[1] + a[4] * b[5] - a[5] * b[4]
15239 + a[6] * b[0]
15240 + a[7] * b[2];
15241 r[7] = a[0] * b[7]
15242 + a[1] * b[5]
15243 + a[2] * b[6]
15244 + a[3] * b[4]
15245 + a[4] * b[3]
15246 + a[5] * b[1]
15247 + a[6] * b[2]
15248 + a[7] * b[0];
15249
15250 Ok(make_multivector(r))
15251 });
15252
15253 define(interp, "mv_reflect", Some(2), |_, args| {
15256 let v = extract_vec3(&args[0], "mv_reflect")?;
15257 let n = extract_vec3(&args[1], "mv_reflect")?;
15258
15259 let len = (n[0] * n[0] + n[1] * n[1] + n[2] * n[2]).sqrt();
15261 if len < 1e-10 {
15262 return Ok(make_vec3(v[0], v[1], v[2]));
15263 }
15264 let (nx, ny, nz) = (n[0] / len, n[1] / len, n[2] / len);
15265
15266 let dot = v[0] * nx + v[1] * ny + v[2] * nz;
15268 Ok(make_vec3(
15269 v[0] - 2.0 * dot * nx,
15270 v[1] - 2.0 * dot * ny,
15271 v[2] - 2.0 * dot * nz,
15272 ))
15273 });
15274
15275 define(interp, "mv_project", Some(2), |_, args| {
15277 let v = extract_vec3(&args[0], "mv_project")?;
15278 let n = extract_vec3(&args[1], "mv_project")?;
15279
15280 let len = (n[0] * n[0] + n[1] * n[1] + n[2] * n[2]).sqrt();
15281 if len < 1e-10 {
15282 return Ok(make_vec3(v[0], v[1], v[2]));
15283 }
15284 let (nx, ny, nz) = (n[0] / len, n[1] / len, n[2] / len);
15285
15286 let dot = v[0] * nx + v[1] * ny + v[2] * nz;
15288 Ok(make_vec3(v[0] - dot * nx, v[1] - dot * ny, v[2] - dot * nz))
15289 });
15290
15291 define(interp, "mv_grade", Some(2), |_, args| {
15293 let a = extract_multivector(&args[0], "mv_grade")?;
15294 let k = match &args[1] {
15295 Value::Int(n) => *n,
15296 _ => return Err(RuntimeError::new("mv_grade: grade must be integer")),
15297 };
15298
15299 match k {
15300 0 => Ok(make_multivector([a[0], 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0])),
15301 1 => Ok(make_multivector([
15302 0.0, a[1], a[2], a[3], 0.0, 0.0, 0.0, 0.0,
15303 ])),
15304 2 => Ok(make_multivector([
15305 0.0, 0.0, 0.0, 0.0, a[4], a[5], a[6], 0.0,
15306 ])),
15307 3 => Ok(make_multivector([0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, a[7]])),
15308 _ => Ok(make_multivector([0.0; 8])),
15309 }
15310 });
15311}
15312
15313fn register_dimensional(interp: &mut Interpreter) {
15320 fn make_quantity(value: f64, units: [i32; 7]) -> Value {
15323 let mut q = HashMap::new();
15324 q.insert("value".to_string(), Value::Float(value));
15325 q.insert("m".to_string(), Value::Int(units[0] as i64)); q.insert("kg".to_string(), Value::Int(units[1] as i64)); q.insert("s".to_string(), Value::Int(units[2] as i64)); q.insert("A".to_string(), Value::Int(units[3] as i64)); q.insert("K".to_string(), Value::Int(units[4] as i64)); q.insert("mol".to_string(), Value::Int(units[5] as i64)); q.insert("cd".to_string(), Value::Int(units[6] as i64)); q.insert(
15333 "_type".to_string(),
15334 Value::String(Rc::new("quantity".to_string())),
15335 );
15336 Value::Map(Rc::new(RefCell::new(q)))
15337 }
15338
15339 fn extract_quantity(v: &Value, fn_name: &str) -> Result<(f64, [i32; 7]), RuntimeError> {
15340 match v {
15341 Value::Map(map) => {
15342 let map = map.borrow();
15343 let value = match map.get("value") {
15344 Some(Value::Float(f)) => *f,
15345 Some(Value::Int(n)) => *n as f64,
15346 _ => return Err(RuntimeError::new(format!("{}: missing value", fn_name))),
15347 };
15348 let get_exp = |key: &str| -> i32 {
15349 match map.get(key) {
15350 Some(Value::Int(n)) => *n as i32,
15351 _ => 0,
15352 }
15353 };
15354 Ok((
15355 value,
15356 [
15357 get_exp("m"),
15358 get_exp("kg"),
15359 get_exp("s"),
15360 get_exp("A"),
15361 get_exp("K"),
15362 get_exp("mol"),
15363 get_exp("cd"),
15364 ],
15365 ))
15366 }
15367 Value::Float(f) => Ok((*f, [0; 7])),
15368 Value::Int(n) => Ok((*n as f64, [0; 7])),
15369 _ => Err(RuntimeError::new(format!(
15370 "{}: expected quantity or number",
15371 fn_name
15372 ))),
15373 }
15374 }
15375
15376 fn units_to_string(units: [i32; 7]) -> String {
15377 let names = ["m", "kg", "s", "A", "K", "mol", "cd"];
15378 let mut parts = Vec::new();
15379 for (i, &exp) in units.iter().enumerate() {
15380 if exp == 1 {
15381 parts.push(names[i].to_string());
15382 } else if exp != 0 {
15383 parts.push(format!("{}^{}", names[i], exp));
15384 }
15385 }
15386 if parts.is_empty() {
15387 "dimensionless".to_string()
15388 } else {
15389 parts.join("·")
15390 }
15391 }
15392
15393 define(interp, "qty", Some(2), |_, args| {
15396 let value = match &args[0] {
15397 Value::Float(f) => *f,
15398 Value::Int(n) => *n as f64,
15399 _ => return Err(RuntimeError::new("qty: first argument must be number")),
15400 };
15401 let unit_str = match &args[1] {
15402 Value::String(s) => s.to_string(),
15403 _ => {
15404 return Err(RuntimeError::new(
15405 "qty: second argument must be unit string",
15406 ))
15407 }
15408 };
15409
15410 let mut units = [0i32; 7];
15412 let in_denominator = unit_str.contains('/');
15415
15416 for part in unit_str.split(|c: char| c == '*' || c == '·' || c == ' ') {
15418 let part = part.trim();
15419 if part.is_empty() {
15420 continue;
15421 }
15422
15423 let (base, exp) = if let Some(idx) = part.find('^') {
15424 let (b, e) = part.split_at(idx);
15425 (b, e[1..].parse::<i32>().unwrap_or(1))
15426 } else if part.contains('/') {
15427 continue;
15429 } else {
15430 (part, 1)
15431 };
15432
15433 let sign = if in_denominator { -1 } else { 1 };
15434 match base {
15435 "m" | "meter" | "meters" => units[0] += exp * sign,
15436 "kg" | "kilogram" | "kilograms" => units[1] += exp * sign,
15437 "s" | "sec" | "second" | "seconds" => units[2] += exp * sign,
15438 "A" | "amp" | "ampere" | "amperes" => units[3] += exp * sign,
15439 "K" | "kelvin" => units[4] += exp * sign,
15440 "mol" | "mole" | "moles" => units[5] += exp * sign,
15441 "cd" | "candela" => units[6] += exp * sign,
15442 "N" | "newton" | "newtons" => {
15444 units[1] += sign;
15445 units[0] += sign;
15446 units[2] -= 2 * sign;
15447 }
15448 "J" | "joule" | "joules" => {
15449 units[1] += sign;
15450 units[0] += 2 * sign;
15451 units[2] -= 2 * sign;
15452 }
15453 "W" | "watt" | "watts" => {
15454 units[1] += sign;
15455 units[0] += 2 * sign;
15456 units[2] -= 3 * sign;
15457 }
15458 "Pa" | "pascal" | "pascals" => {
15459 units[1] += sign;
15460 units[0] -= sign;
15461 units[2] -= 2 * sign;
15462 }
15463 "Hz" | "hertz" => {
15464 units[2] -= sign;
15465 }
15466 "C" | "coulomb" | "coulombs" => {
15467 units[3] += sign;
15468 units[2] += sign;
15469 }
15470 "V" | "volt" | "volts" => {
15471 units[1] += sign;
15472 units[0] += 2 * sign;
15473 units[2] -= 3 * sign;
15474 units[3] -= sign;
15475 }
15476 "Ω" | "ohm" | "ohms" => {
15477 units[1] += sign;
15478 units[0] += 2 * sign;
15479 units[2] -= 3 * sign;
15480 units[3] -= 2 * sign;
15481 }
15482 _ => {}
15483 }
15484 }
15485
15486 Ok(make_quantity(value, units))
15487 });
15488
15489 define(interp, "qty_add", Some(2), |_, args| {
15491 let (val_a, units_a) = extract_quantity(&args[0], "qty_add")?;
15492 let (val_b, units_b) = extract_quantity(&args[1], "qty_add")?;
15493
15494 if units_a != units_b {
15495 return Err(RuntimeError::new(format!(
15496 "qty_add: unit mismatch: {} vs {}",
15497 units_to_string(units_a),
15498 units_to_string(units_b)
15499 )));
15500 }
15501
15502 Ok(make_quantity(val_a + val_b, units_a))
15503 });
15504
15505 define(interp, "qty_sub", Some(2), |_, args| {
15507 let (val_a, units_a) = extract_quantity(&args[0], "qty_sub")?;
15508 let (val_b, units_b) = extract_quantity(&args[1], "qty_sub")?;
15509
15510 if units_a != units_b {
15511 return Err(RuntimeError::new(format!(
15512 "qty_sub: unit mismatch: {} vs {}",
15513 units_to_string(units_a),
15514 units_to_string(units_b)
15515 )));
15516 }
15517
15518 Ok(make_quantity(val_a - val_b, units_a))
15519 });
15520
15521 define(interp, "qty_mul", Some(2), |_, args| {
15523 let (val_a, units_a) = extract_quantity(&args[0], "qty_mul")?;
15524 let (val_b, units_b) = extract_quantity(&args[1], "qty_mul")?;
15525
15526 let mut result_units = [0i32; 7];
15527 for i in 0..7 {
15528 result_units[i] = units_a[i] + units_b[i];
15529 }
15530
15531 Ok(make_quantity(val_a * val_b, result_units))
15532 });
15533
15534 define(interp, "qty_div", Some(2), |_, args| {
15536 let (val_a, units_a) = extract_quantity(&args[0], "qty_div")?;
15537 let (val_b, units_b) = extract_quantity(&args[1], "qty_div")?;
15538
15539 if val_b.abs() < 1e-15 {
15540 return Err(RuntimeError::new("qty_div: division by zero"));
15541 }
15542
15543 let mut result_units = [0i32; 7];
15544 for i in 0..7 {
15545 result_units[i] = units_a[i] - units_b[i];
15546 }
15547
15548 Ok(make_quantity(val_a / val_b, result_units))
15549 });
15550
15551 define(interp, "qty_pow", Some(2), |_, args| {
15553 let (val, units) = extract_quantity(&args[0], "qty_pow")?;
15554 let n = match &args[1] {
15555 Value::Int(n) => *n as i32,
15556 Value::Float(f) => *f as i32,
15557 _ => return Err(RuntimeError::new("qty_pow: exponent must be number")),
15558 };
15559
15560 let mut result_units = [0i32; 7];
15561 for i in 0..7 {
15562 result_units[i] = units[i] * n;
15563 }
15564
15565 Ok(make_quantity(val.powi(n), result_units))
15566 });
15567
15568 define(interp, "qty_sqrt", Some(1), |_, args| {
15570 let (val, units) = extract_quantity(&args[0], "qty_sqrt")?;
15571
15572 for (i, &exp) in units.iter().enumerate() {
15574 if exp % 2 != 0 {
15575 let names = ["m", "kg", "s", "A", "K", "mol", "cd"];
15576 return Err(RuntimeError::new(format!(
15577 "qty_sqrt: cannot take sqrt of {} (odd exponent on {})",
15578 units_to_string(units),
15579 names[i]
15580 )));
15581 }
15582 }
15583
15584 let mut result_units = [0i32; 7];
15585 for i in 0..7 {
15586 result_units[i] = units[i] / 2;
15587 }
15588
15589 Ok(make_quantity(val.sqrt(), result_units))
15590 });
15591
15592 define(interp, "qty_value", Some(1), |_, args| {
15594 let (val, _) = extract_quantity(&args[0], "qty_value")?;
15595 Ok(Value::Float(val))
15596 });
15597
15598 define(interp, "qty_units", Some(1), |_, args| {
15600 let (_, units) = extract_quantity(&args[0], "qty_units")?;
15601 Ok(Value::String(Rc::new(units_to_string(units))))
15602 });
15603
15604 define(interp, "qty_convert", Some(2), |_, args| {
15607 let (val, units) = extract_quantity(&args[0], "qty_convert")?;
15608 let _target = match &args[1] {
15609 Value::String(s) => s.to_string(),
15610 _ => return Err(RuntimeError::new("qty_convert: target must be unit string")),
15611 };
15612
15613 Ok(make_quantity(val, units))
15616 });
15617
15618 define(interp, "qty_check", Some(2), |_, args| {
15620 let (_, units) = extract_quantity(&args[0], "qty_check")?;
15621 let expected = match &args[1] {
15622 Value::String(s) => s.to_string(),
15623 _ => return Err(RuntimeError::new("qty_check: expected string")),
15624 };
15625
15626 let actual_str = units_to_string(units);
15628 Ok(Value::Bool(
15629 actual_str.contains(&expected) || expected.contains(&actual_str),
15630 ))
15631 });
15632
15633 define(interp, "c_light", Some(0), |_, _| {
15636 Ok(make_quantity(299792458.0, [1, 0, -1, 0, 0, 0, 0])) });
15638
15639 define(interp, "G_gravity", Some(0), |_, _| {
15641 Ok(make_quantity(6.67430e-11, [3, -1, -2, 0, 0, 0, 0])) });
15643
15644 define(interp, "h_planck", Some(0), |_, _| {
15646 Ok(make_quantity(6.62607015e-34, [2, 1, -1, 0, 0, 0, 0])) });
15648
15649 define(interp, "e_charge", Some(0), |_, _| {
15651 Ok(make_quantity(1.602176634e-19, [0, 0, 1, 1, 0, 0, 0])) });
15653
15654 define(interp, "k_boltzmann", Some(0), |_, _| {
15656 Ok(make_quantity(1.380649e-23, [2, 1, -2, 0, -1, 0, 0])) });
15658}
15659
15660fn register_ecs(interp: &mut Interpreter) {
15740 define(interp, "ecs_world", Some(0), |_, _| {
15742 let mut world = HashMap::new();
15743 world.insert(
15744 "_type".to_string(),
15745 Value::String(Rc::new("ecs_world".to_string())),
15746 );
15747 world.insert("next_id".to_string(), Value::Int(0));
15748 world.insert(
15749 "entities".to_string(),
15750 Value::Map(Rc::new(RefCell::new(HashMap::new()))),
15751 );
15752 world.insert(
15753 "components".to_string(),
15754 Value::Map(Rc::new(RefCell::new(HashMap::new()))),
15755 );
15756 Ok(Value::Map(Rc::new(RefCell::new(world))))
15757 });
15758
15759 define(interp, "ecs_spawn", Some(1), |_, args| {
15761 let world = match &args[0] {
15762 Value::Map(m) => m.clone(),
15763 _ => return Err(RuntimeError::new("ecs_spawn: expected world")),
15764 };
15765
15766 let mut world_ref = world.borrow_mut();
15767 let id = match world_ref.get("next_id") {
15768 Some(Value::Int(n)) => *n,
15769 _ => 0,
15770 };
15771
15772 world_ref.insert("next_id".to_string(), Value::Int(id + 1));
15774
15775 if let Some(Value::Map(entities)) = world_ref.get("entities") {
15777 entities
15778 .borrow_mut()
15779 .insert(id.to_string(), Value::Bool(true));
15780 }
15781
15782 Ok(Value::Int(id))
15783 });
15784
15785 define(interp, "ecs_despawn", Some(2), |_, args| {
15787 let world = match &args[0] {
15788 Value::Map(m) => m.clone(),
15789 _ => return Err(RuntimeError::new("ecs_despawn: expected world")),
15790 };
15791 let id = match &args[1] {
15792 Value::Int(n) => *n,
15793 _ => return Err(RuntimeError::new("ecs_despawn: expected entity id")),
15794 };
15795
15796 let world_ref = world.borrow();
15797
15798 if let Some(Value::Map(entities)) = world_ref.get("entities") {
15800 entities.borrow_mut().remove(&id.to_string());
15801 }
15802
15803 if let Some(Value::Map(components)) = world_ref.get("components") {
15805 let comps = components.borrow();
15806 for (_, comp_storage) in comps.iter() {
15807 if let Value::Map(storage) = comp_storage {
15808 storage.borrow_mut().remove(&id.to_string());
15809 }
15810 }
15811 }
15812
15813 Ok(Value::Bool(true))
15814 });
15815
15816 define(interp, "ecs_attach", Some(4), |_, args| {
15818 let world = match &args[0] {
15819 Value::Map(m) => m.clone(),
15820 _ => {
15821 return Err(RuntimeError::new(
15822 "ecs_attach() expects a world as first argument.\n\
15823 Usage: ecs_attach(world, entity_id, component_name, data)\n\
15824 Example:\n\
15825 let world = ecs_world();\n\
15826 let e = ecs_spawn(world);\n\
15827 ecs_attach(world, e, \"Position\", vec3(0, 0, 0));",
15828 ))
15829 }
15830 };
15831 let id = match &args[1] {
15832 Value::Int(n) => *n,
15833 _ => {
15834 return Err(RuntimeError::new(
15835 "ecs_attach() expects an entity ID (integer) as second argument.\n\
15836 Entity IDs are returned by ecs_spawn().\n\
15837 Example:\n\
15838 let entity = ecs_spawn(world); // Returns 0, 1, 2...\n\
15839 ecs_attach(world, entity, \"Health\", 100);",
15840 ))
15841 }
15842 };
15843 let comp_name = match &args[2] {
15844 Value::String(s) => s.to_string(),
15845 _ => {
15846 return Err(RuntimeError::new(
15847 "ecs_attach() expects a string component name as third argument.\n\
15848 Common component names: \"Position\", \"Velocity\", \"Health\", \"Sprite\"\n\
15849 Example: ecs_attach(world, entity, \"Position\", vec3(0, 0, 0));",
15850 ))
15851 }
15852 };
15853 let data = args[3].clone();
15854
15855 let world_ref = world.borrow();
15856
15857 if let Some(Value::Map(components)) = world_ref.get("components") {
15859 let mut comps = components.borrow_mut();
15860
15861 let storage = comps
15862 .entry(comp_name.clone())
15863 .or_insert_with(|| Value::Map(Rc::new(RefCell::new(HashMap::new()))));
15864
15865 if let Value::Map(storage_map) = storage {
15866 storage_map.borrow_mut().insert(id.to_string(), data);
15867 }
15868 }
15869
15870 Ok(Value::Bool(true))
15871 });
15872
15873 define(interp, "ecs_get", Some(3), |_, args| {
15875 let world = match &args[0] {
15876 Value::Map(m) => m.clone(),
15877 _ => return Err(RuntimeError::new("ecs_get: expected world")),
15878 };
15879 let id = match &args[1] {
15880 Value::Int(n) => *n,
15881 _ => return Err(RuntimeError::new("ecs_get: expected entity id")),
15882 };
15883 let comp_name = match &args[2] {
15884 Value::String(s) => s.to_string(),
15885 _ => return Err(RuntimeError::new("ecs_get: expected component name")),
15886 };
15887
15888 let world_ref = world.borrow();
15889
15890 if let Some(Value::Map(components)) = world_ref.get("components") {
15891 let comps = components.borrow();
15892 if let Some(Value::Map(storage)) = comps.get(&comp_name) {
15893 if let Some(data) = storage.borrow().get(&id.to_string()) {
15894 return Ok(data.clone());
15895 }
15896 }
15897 }
15898
15899 Ok(Value::Null)
15900 });
15901
15902 define(interp, "ecs_has", Some(3), |_, args| {
15904 let world = match &args[0] {
15905 Value::Map(m) => m.clone(),
15906 _ => return Err(RuntimeError::new("ecs_has: expected world")),
15907 };
15908 let id = match &args[1] {
15909 Value::Int(n) => *n,
15910 _ => return Err(RuntimeError::new("ecs_has: expected entity id")),
15911 };
15912 let comp_name = match &args[2] {
15913 Value::String(s) => s.to_string(),
15914 _ => return Err(RuntimeError::new("ecs_has: expected component name")),
15915 };
15916
15917 let world_ref = world.borrow();
15918
15919 if let Some(Value::Map(components)) = world_ref.get("components") {
15920 let comps = components.borrow();
15921 if let Some(Value::Map(storage)) = comps.get(&comp_name) {
15922 return Ok(Value::Bool(storage.borrow().contains_key(&id.to_string())));
15923 }
15924 }
15925
15926 Ok(Value::Bool(false))
15927 });
15928
15929 define(interp, "ecs_remove", Some(3), |_, args| {
15931 let world = match &args[0] {
15932 Value::Map(m) => m.clone(),
15933 _ => return Err(RuntimeError::new("ecs_remove: expected world")),
15934 };
15935 let id = match &args[1] {
15936 Value::Int(n) => *n,
15937 _ => return Err(RuntimeError::new("ecs_remove: expected entity id")),
15938 };
15939 let comp_name = match &args[2] {
15940 Value::String(s) => s.to_string(),
15941 _ => return Err(RuntimeError::new("ecs_remove: expected component name")),
15942 };
15943
15944 let world_ref = world.borrow();
15945
15946 if let Some(Value::Map(components)) = world_ref.get("components") {
15947 let comps = components.borrow();
15948 if let Some(Value::Map(storage)) = comps.get(&comp_name) {
15949 storage.borrow_mut().remove(&id.to_string());
15950 return Ok(Value::Bool(true));
15951 }
15952 }
15953
15954 Ok(Value::Bool(false))
15955 });
15956
15957 define(interp, "ecs_query", None, |_, args| {
15960 if args.is_empty() {
15961 return Err(RuntimeError::new(
15962 "ecs_query: expected at least world argument",
15963 ));
15964 }
15965
15966 let world = match &args[0] {
15967 Value::Map(m) => m.clone(),
15968 _ => return Err(RuntimeError::new("ecs_query: expected world")),
15969 };
15970
15971 let comp_names: Vec<String> = args[1..]
15972 .iter()
15973 .filter_map(|a| match a {
15974 Value::String(s) => Some(s.to_string()),
15975 _ => None,
15976 })
15977 .collect();
15978
15979 if comp_names.is_empty() {
15980 let world_ref = world.borrow();
15982 if let Some(Value::Map(entities)) = world_ref.get("entities") {
15983 let result: Vec<Value> = entities
15984 .borrow()
15985 .keys()
15986 .filter_map(|k| k.parse::<i64>().ok().map(Value::Int))
15987 .collect();
15988 return Ok(Value::Array(Rc::new(RefCell::new(result))));
15989 }
15990 return Ok(Value::Array(Rc::new(RefCell::new(vec![]))));
15991 }
15992
15993 let world_ref = world.borrow();
15994 let mut result_ids: Option<Vec<String>> = None;
15995
15996 if let Some(Value::Map(components)) = world_ref.get("components") {
15997 let comps = components.borrow();
15998
15999 for comp_name in &comp_names {
16000 if let Some(Value::Map(storage)) = comps.get(comp_name) {
16001 let keys: Vec<String> = storage.borrow().keys().cloned().collect();
16002
16003 result_ids = Some(match result_ids {
16004 None => keys,
16005 Some(existing) => {
16006 existing.into_iter().filter(|k| keys.contains(k)).collect()
16007 }
16008 });
16009 } else {
16010 return Ok(Value::Array(Rc::new(RefCell::new(vec![]))));
16012 }
16013 }
16014 }
16015
16016 let result: Vec<Value> = result_ids
16017 .unwrap_or_default()
16018 .iter()
16019 .filter_map(|k| k.parse::<i64>().ok().map(Value::Int))
16020 .collect();
16021
16022 Ok(Value::Array(Rc::new(RefCell::new(result))))
16023 });
16024
16025 define(interp, "ecs_query_with", Some(3), |interp, args| {
16028 let world = match &args[0] {
16029 Value::Map(m) => m.clone(),
16030 _ => return Err(RuntimeError::new("ecs_query_with: expected world")),
16031 };
16032 let comp_names: Vec<String> = match &args[1] {
16033 Value::Array(arr) => arr
16034 .borrow()
16035 .iter()
16036 .filter_map(|v| match v {
16037 Value::String(s) => Some(s.to_string()),
16038 _ => None,
16039 })
16040 .collect(),
16041 _ => {
16042 return Err(RuntimeError::new(
16043 "ecs_query_with: expected array of component names",
16044 ))
16045 }
16046 };
16047 let callback = match &args[2] {
16048 Value::Function(f) => f.clone(),
16049 _ => {
16050 return Err(RuntimeError::new(
16051 "ecs_query_with: expected callback function",
16052 ))
16053 }
16054 };
16055
16056 let mut callback_data: Vec<(i64, HashMap<String, Value>)> = Vec::new();
16058
16059 {
16060 let world_ref = world.borrow();
16061 let mut result_ids: Option<Vec<String>> = None;
16062
16063 if let Some(Value::Map(components)) = world_ref.get("components") {
16064 let comps = components.borrow();
16065
16066 for comp_name in &comp_names {
16067 if let Some(Value::Map(storage)) = comps.get(comp_name) {
16068 let keys: Vec<String> = storage.borrow().keys().cloned().collect();
16069 result_ids = Some(match result_ids {
16070 None => keys,
16071 Some(existing) => {
16072 existing.into_iter().filter(|k| keys.contains(k)).collect()
16073 }
16074 });
16075 } else {
16076 result_ids = Some(vec![]);
16077 break;
16078 }
16079 }
16080
16081 for id_str in result_ids.unwrap_or_default() {
16083 if let Ok(id) = id_str.parse::<i64>() {
16084 let mut entity_comps = HashMap::new();
16085 for comp_name in &comp_names {
16086 if let Some(Value::Map(storage)) = comps.get(comp_name) {
16087 if let Some(data) = storage.borrow().get(&id_str) {
16088 entity_comps.insert(comp_name.clone(), data.clone());
16089 }
16090 }
16091 }
16092 callback_data.push((id, entity_comps));
16093 }
16094 }
16095 }
16096 } for (id, entity_comps) in callback_data {
16100 let callback_args = vec![
16101 Value::Int(id),
16102 Value::Map(Rc::new(RefCell::new(entity_comps))),
16103 ];
16104 interp.call_function(&callback, callback_args)?;
16105 }
16106
16107 Ok(Value::Null)
16108 });
16109
16110 define(interp, "ecs_count", Some(1), |_, args| {
16112 let world = match &args[0] {
16113 Value::Map(m) => m.clone(),
16114 _ => return Err(RuntimeError::new("ecs_count: expected world")),
16115 };
16116
16117 let world_ref = world.borrow();
16118 if let Some(Value::Map(entities)) = world_ref.get("entities") {
16119 return Ok(Value::Int(entities.borrow().len() as i64));
16120 }
16121
16122 Ok(Value::Int(0))
16123 });
16124
16125 define(interp, "ecs_alive", Some(2), |_, args| {
16127 let world = match &args[0] {
16128 Value::Map(m) => m.clone(),
16129 _ => return Err(RuntimeError::new("ecs_alive: expected world")),
16130 };
16131 let id = match &args[1] {
16132 Value::Int(n) => *n,
16133 _ => return Err(RuntimeError::new("ecs_alive: expected entity id")),
16134 };
16135
16136 let world_ref = world.borrow();
16137 if let Some(Value::Map(entities)) = world_ref.get("entities") {
16138 return Ok(Value::Bool(entities.borrow().contains_key(&id.to_string())));
16139 }
16140
16141 Ok(Value::Bool(false))
16142 });
16143}
16144
16145fn register_polycultural_text(interp: &mut Interpreter) {
16165 define(interp, "script", Some(1), |_, args| {
16175 match &args[0] {
16176 Value::String(s) => {
16177 let mut script_counts: HashMap<String, usize> = HashMap::new();
16179 for c in s.chars() {
16180 if !c.is_whitespace() && !c.is_ascii_punctuation() {
16181 let script = c.script();
16182 let name = format!("{:?}", script);
16183 *script_counts.entry(name).or_insert(0) += 1;
16184 }
16185 }
16186 let dominant = script_counts
16188 .into_iter()
16189 .max_by_key(|(_, count)| *count)
16190 .map(|(name, _)| name)
16191 .unwrap_or_else(|| "Unknown".to_string());
16192 Ok(Value::String(Rc::new(dominant)))
16193 }
16194 _ => Err(RuntimeError::new("script() requires string")),
16195 }
16196 });
16197
16198 define(interp, "scripts", Some(1), |_, args| match &args[0] {
16200 Value::String(s) => {
16201 let mut scripts: Vec<String> = s
16202 .chars()
16203 .filter(|c| !c.is_whitespace() && !c.is_ascii_punctuation())
16204 .map(|c| format!("{:?}", c.script()))
16205 .collect();
16206 scripts.sort();
16207 scripts.dedup();
16208 let values: Vec<Value> = scripts
16209 .into_iter()
16210 .map(|s| Value::String(Rc::new(s)))
16211 .collect();
16212 Ok(Value::Array(Rc::new(RefCell::new(values))))
16213 }
16214 _ => Err(RuntimeError::new("scripts() requires string")),
16215 });
16216
16217 define(interp, "is_script", Some(2), |_, args| {
16219 match (&args[0], &args[1]) {
16220 (Value::String(s), Value::String(script_name)) => {
16221 let target = script_name.to_lowercase();
16222 let mut matching = 0usize;
16223 let mut total = 0usize;
16224 for c in s.chars() {
16225 if !c.is_whitespace() && !c.is_ascii_punctuation() {
16226 total += 1;
16227 let script_str = format!("{:?}", c.script()).to_lowercase();
16228 if script_str == target {
16229 matching += 1;
16230 }
16231 }
16232 }
16233 let ratio = if total > 0 {
16234 matching as f64 / total as f64
16235 } else {
16236 0.0
16237 };
16238 Ok(Value::Bool(ratio > 0.5))
16239 }
16240 _ => Err(RuntimeError::new(
16241 "is_script() requires string and script name",
16242 )),
16243 }
16244 });
16245
16246 define(interp, "is_latin", Some(1), |_, args| match &args[0] {
16248 Value::String(s) => {
16249 let is_latin = s
16250 .chars()
16251 .filter(|c| !c.is_whitespace())
16252 .all(|c| matches!(c.script(), Script::Latin | Script::Common));
16253 Ok(Value::Bool(is_latin && !s.is_empty()))
16254 }
16255 _ => Err(RuntimeError::new("is_latin() requires string")),
16256 });
16257
16258 define(interp, "is_cjk", Some(1), |_, args| match &args[0] {
16259 Value::String(s) => {
16260 let has_cjk = s.chars().any(|c| {
16261 matches!(
16262 c.script(),
16263 Script::Han
16264 | Script::Hiragana
16265 | Script::Katakana
16266 | Script::Hangul
16267 | Script::Bopomofo
16268 )
16269 });
16270 Ok(Value::Bool(has_cjk))
16271 }
16272 _ => Err(RuntimeError::new("is_cjk() requires string")),
16273 });
16274
16275 define(interp, "is_arabic", Some(1), |_, args| match &args[0] {
16276 Value::String(s) => {
16277 let has_arabic = s.chars().any(|c| matches!(c.script(), Script::Arabic));
16278 Ok(Value::Bool(has_arabic))
16279 }
16280 _ => Err(RuntimeError::new("is_arabic() requires string")),
16281 });
16282
16283 define(interp, "is_hebrew", Some(1), |_, args| match &args[0] {
16284 Value::String(s) => {
16285 let has_hebrew = s.chars().any(|c| matches!(c.script(), Script::Hebrew));
16286 Ok(Value::Bool(has_hebrew))
16287 }
16288 _ => Err(RuntimeError::new("is_hebrew() requires string")),
16289 });
16290
16291 define(interp, "is_cyrillic", Some(1), |_, args| match &args[0] {
16292 Value::String(s) => {
16293 let has_cyrillic = s.chars().any(|c| matches!(c.script(), Script::Cyrillic));
16294 Ok(Value::Bool(has_cyrillic))
16295 }
16296 _ => Err(RuntimeError::new("is_cyrillic() requires string")),
16297 });
16298
16299 define(interp, "is_greek", Some(1), |_, args| match &args[0] {
16300 Value::String(s) => {
16301 let has_greek = s.chars().any(|c| matches!(c.script(), Script::Greek));
16302 Ok(Value::Bool(has_greek))
16303 }
16304 _ => Err(RuntimeError::new("is_greek() requires string")),
16305 });
16306
16307 define(interp, "is_devanagari", Some(1), |_, args| match &args[0] {
16308 Value::String(s) => {
16309 let has_devanagari = s.chars().any(|c| matches!(c.script(), Script::Devanagari));
16310 Ok(Value::Bool(has_devanagari))
16311 }
16312 _ => Err(RuntimeError::new("is_devanagari() requires string")),
16313 });
16314
16315 define(interp, "is_thai", Some(1), |_, args| match &args[0] {
16316 Value::String(s) => {
16317 let has_thai = s.chars().any(|c| matches!(c.script(), Script::Thai));
16318 Ok(Value::Bool(has_thai))
16319 }
16320 _ => Err(RuntimeError::new("is_thai() requires string")),
16321 });
16322
16323 define(interp, "is_hangul", Some(1), |_, args| match &args[0] {
16324 Value::String(s) => {
16325 let has_hangul = s.chars().any(|c| matches!(c.script(), Script::Hangul));
16326 Ok(Value::Bool(has_hangul))
16327 }
16328 _ => Err(RuntimeError::new("is_hangul() requires string")),
16329 });
16330
16331 define(interp, "is_hiragana", Some(1), |_, args| match &args[0] {
16332 Value::String(s) => {
16333 let has_hiragana = s.chars().any(|c| matches!(c.script(), Script::Hiragana));
16334 Ok(Value::Bool(has_hiragana))
16335 }
16336 _ => Err(RuntimeError::new("is_hiragana() requires string")),
16337 });
16338
16339 define(interp, "is_katakana", Some(1), |_, args| match &args[0] {
16340 Value::String(s) => {
16341 let has_katakana = s.chars().any(|c| matches!(c.script(), Script::Katakana));
16342 Ok(Value::Bool(has_katakana))
16343 }
16344 _ => Err(RuntimeError::new("is_katakana() requires string")),
16345 });
16346
16347 define(interp, "char_script", Some(1), |_, args| match &args[0] {
16349 Value::Char(c) => {
16350 let script = format!("{:?}", c.script());
16351 Ok(Value::String(Rc::new(script)))
16352 }
16353 Value::String(s) if s.chars().count() == 1 => {
16354 let c = s.chars().next().unwrap();
16355 let script = format!("{:?}", c.script());
16356 Ok(Value::String(Rc::new(script)))
16357 }
16358 _ => Err(RuntimeError::new("char_script() requires single character")),
16359 });
16360
16361 define(interp, "text_direction", Some(1), |_, args| {
16371 match &args[0] {
16372 Value::String(s) => {
16373 let bidi_info = BidiInfo::new(s, None);
16374 let has_rtl = bidi_info.paragraphs.iter().any(|p| p.level.is_rtl());
16376 let direction = if has_rtl { "rtl" } else { "ltr" };
16377 Ok(Value::String(Rc::new(direction.to_string())))
16378 }
16379 _ => Err(RuntimeError::new("text_direction() requires string")),
16380 }
16381 });
16382
16383 define(interp, "is_rtl", Some(1), |_, args| match &args[0] {
16385 Value::String(s) => {
16386 let bidi_info = BidiInfo::new(s, None);
16387 let has_rtl = bidi_info.paragraphs.iter().any(|p| p.level.is_rtl());
16388 Ok(Value::Bool(has_rtl))
16389 }
16390 _ => Err(RuntimeError::new("is_rtl() requires string")),
16391 });
16392
16393 define(interp, "is_ltr", Some(1), |_, args| match &args[0] {
16395 Value::String(s) => {
16396 let bidi_info = BidiInfo::new(s, None);
16397 let is_ltr = bidi_info.paragraphs.iter().all(|p| !p.level.is_rtl());
16398 Ok(Value::Bool(is_ltr))
16399 }
16400 _ => Err(RuntimeError::new("is_ltr() requires string")),
16401 });
16402
16403 define(interp, "is_bidi", Some(1), |_, args| {
16405 match &args[0] {
16406 Value::String(s) => {
16407 let has_rtl = s.chars().any(|c| {
16409 matches!(
16410 c.script(),
16411 Script::Arabic | Script::Hebrew | Script::Syriac | Script::Thaana
16412 )
16413 });
16414 let has_ltr = s.chars().any(|c| {
16415 matches!(c.script(), Script::Latin | Script::Greek | Script::Cyrillic)
16416 });
16417 Ok(Value::Bool(has_rtl && has_ltr))
16418 }
16419 _ => Err(RuntimeError::new("is_bidi() requires string")),
16420 }
16421 });
16422
16423 define(interp, "bidi_reorder", Some(1), |_, args| match &args[0] {
16425 Value::String(s) => {
16426 let bidi_info = BidiInfo::new(s, None);
16427 let mut result = String::new();
16428 for para in &bidi_info.paragraphs {
16429 let line = para.range.clone();
16430 let reordered = bidi_info.reorder_line(para, line);
16431 result.push_str(&reordered);
16432 }
16433 Ok(Value::String(Rc::new(result)))
16434 }
16435 _ => Err(RuntimeError::new("bidi_reorder() requires string")),
16436 });
16437
16438 define(interp, "display_width", Some(1), |_, args| match &args[0] {
16448 Value::String(s) => {
16449 let width = UnicodeWidthStr::width(s.as_str());
16450 Ok(Value::Int(width as i64))
16451 }
16452 _ => Err(RuntimeError::new("display_width() requires string")),
16453 });
16454
16455 define(interp, "is_fullwidth", Some(1), |_, args| {
16457 match &args[0] {
16458 Value::String(s) => {
16459 let char_count = s.chars().count();
16460 let display_width = UnicodeWidthStr::width(s.as_str());
16461 Ok(Value::Bool(display_width > char_count))
16463 }
16464 _ => Err(RuntimeError::new("is_fullwidth() requires string")),
16465 }
16466 });
16467
16468 define(interp, "pad_display", Some(3), |_, args| {
16470 match (&args[0], &args[1], &args[2]) {
16471 (Value::String(s), Value::Int(target_width), Value::String(align)) => {
16472 let current_width = UnicodeWidthStr::width(s.as_str());
16473 let target = *target_width as usize;
16474 if current_width >= target {
16475 return Ok(Value::String(s.clone()));
16476 }
16477 let padding = target - current_width;
16478 let result = match align.as_str() {
16479 "left" => format!("{}{}", s, " ".repeat(padding)),
16480 "right" => format!("{}{}", " ".repeat(padding), s),
16481 "center" => {
16482 let left = padding / 2;
16483 let right = padding - left;
16484 format!("{}{}{}", " ".repeat(left), s, " ".repeat(right))
16485 }
16486 _ => {
16487 return Err(RuntimeError::new(
16488 "pad_display: align must be 'left', 'right', or 'center'",
16489 ))
16490 }
16491 };
16492 Ok(Value::String(Rc::new(result)))
16493 }
16494 _ => Err(RuntimeError::new(
16495 "pad_display() requires string, width, and alignment",
16496 )),
16497 }
16498 });
16499
16500 define(interp, "transliterate", Some(1), |_, args| match &args[0] {
16510 Value::String(s) => {
16511 let ascii = deunicode(s);
16512 Ok(Value::String(Rc::new(ascii)))
16513 }
16514 _ => Err(RuntimeError::new("transliterate() requires string")),
16515 });
16516
16517 define(interp, "to_ascii", Some(1), |_, args| match &args[0] {
16519 Value::String(s) => {
16520 let ascii = deunicode(s);
16521 Ok(Value::String(Rc::new(ascii)))
16522 }
16523 _ => Err(RuntimeError::new("to_ascii() requires string")),
16524 });
16525
16526 define(interp, "slugify", Some(1), |_, args| {
16528 match &args[0] {
16529 Value::String(s) => {
16530 let ascii = deunicode(s);
16531 let slug: String = ascii
16532 .to_lowercase()
16533 .chars()
16534 .map(|c| if c.is_alphanumeric() { c } else { '-' })
16535 .collect();
16536 let mut result = String::new();
16538 let mut last_was_dash = true; for c in slug.chars() {
16540 if c == '-' {
16541 if !last_was_dash {
16542 result.push(c);
16543 last_was_dash = true;
16544 }
16545 } else {
16546 result.push(c);
16547 last_was_dash = false;
16548 }
16549 }
16550 if result.ends_with('-') {
16552 result.pop();
16553 }
16554 Ok(Value::String(Rc::new(result)))
16555 }
16556 _ => Err(RuntimeError::new("slugify() requires string")),
16557 }
16558 });
16559
16560 define(interp, "strip_diacritics", Some(1), |_, args| {
16570 match &args[0] {
16571 Value::String(s) => {
16572 let decomposed: String = s.nfd().collect();
16574 let stripped: String = decomposed
16576 .chars()
16577 .filter(|c| {
16578 let code = *c as u32;
16582 !(0x0300..=0x036F).contains(&code)
16584 && !(0x1AB0..=0x1AFF).contains(&code)
16585 && !(0x1DC0..=0x1DFF).contains(&code)
16586 && !(0x20D0..=0x20FF).contains(&code)
16587 && !(0xFE20..=0xFE2F).contains(&code)
16588 })
16589 .collect();
16590 Ok(Value::String(Rc::new(stripped)))
16591 }
16592 _ => Err(RuntimeError::new("strip_diacritics() requires string")),
16593 }
16594 });
16595
16596 define(interp, "has_diacritics", Some(1), |_, args| {
16598 match &args[0] {
16599 Value::String(s) => {
16600 let decomposed: String = s.nfd().collect();
16601 let has_marks = decomposed.chars().any(|c| {
16602 let code = c as u32;
16603 (0x0300..=0x036F).contains(&code)
16604 || (0x1AB0..=0x1AFF).contains(&code)
16605 || (0x1DC0..=0x1DFF).contains(&code)
16606 || (0x20D0..=0x20FF).contains(&code)
16607 || (0xFE20..=0xFE2F).contains(&code)
16608 });
16609 Ok(Value::Bool(has_marks))
16610 }
16611 _ => Err(RuntimeError::new("has_diacritics() requires string")),
16612 }
16613 });
16614
16615 define(interp, "normalize_accents", Some(2), |_, args| {
16617 match (&args[0], &args[1]) {
16618 (Value::String(s), Value::String(form)) => {
16619 let result = match form.as_str() {
16620 "composed" | "nfc" => s.nfc().collect(),
16621 "decomposed" | "nfd" => s.nfd().collect(),
16622 _ => {
16623 return Err(RuntimeError::new(
16624 "normalize_accents: form must be 'composed' or 'decomposed'",
16625 ))
16626 }
16627 };
16628 Ok(Value::String(Rc::new(result)))
16629 }
16630 _ => Err(RuntimeError::new(
16631 "normalize_accents() requires string and form",
16632 )),
16633 }
16634 });
16635
16636 define(interp, "upper_locale", Some(2), |_, args| {
16648 match (&args[0], &args[1]) {
16649 (Value::String(s), Value::String(locale_str)) => {
16650 let case_mapper = CaseMapper::new();
16651 let langid: LanguageIdentifier =
16652 locale_str.parse().unwrap_or_else(|_| "en".parse().unwrap());
16653 let result = case_mapper.uppercase_to_string(s, &langid);
16654 Ok(Value::String(Rc::new(result)))
16655 }
16656 _ => Err(RuntimeError::new(
16657 "upper_locale() requires string and locale",
16658 )),
16659 }
16660 });
16661
16662 define(interp, "lower_locale", Some(2), |_, args| {
16664 match (&args[0], &args[1]) {
16665 (Value::String(s), Value::String(locale_str)) => {
16666 let case_mapper = CaseMapper::new();
16667 let langid: LanguageIdentifier =
16668 locale_str.parse().unwrap_or_else(|_| "en".parse().unwrap());
16669 let result = case_mapper.lowercase_to_string(s, &langid);
16670 Ok(Value::String(Rc::new(result)))
16671 }
16672 _ => Err(RuntimeError::new(
16673 "lower_locale() requires string and locale",
16674 )),
16675 }
16676 });
16677
16678 define(interp, "titlecase_locale", Some(2), |_, args| {
16680 match (&args[0], &args[1]) {
16681 (Value::String(s), Value::String(locale_str)) => {
16682 let case_mapper = CaseMapper::new();
16683 let langid: LanguageIdentifier =
16684 locale_str.parse().unwrap_or_else(|_| "en".parse().unwrap());
16685 let options = TitlecaseOptions::default();
16686 let result = case_mapper
16687 .titlecase_segment_with_only_case_data_to_string(s, &langid, options);
16688 Ok(Value::String(Rc::new(result)))
16689 }
16690 _ => Err(RuntimeError::new(
16691 "titlecase_locale() requires string and locale",
16692 )),
16693 }
16694 });
16695
16696 define(interp, "case_fold", Some(1), |_, args| match &args[0] {
16698 Value::String(s) => {
16699 let case_mapper = CaseMapper::new();
16700 let result = case_mapper.fold_string(s);
16701 Ok(Value::String(Rc::new(result)))
16702 }
16703 _ => Err(RuntimeError::new("case_fold() requires string")),
16704 });
16705
16706 define(interp, "case_insensitive_eq", Some(2), |_, args| {
16708 match (&args[0], &args[1]) {
16709 (Value::String(a), Value::String(b)) => {
16710 let case_mapper = CaseMapper::new();
16711 let folded_a = case_mapper.fold_string(a);
16712 let folded_b = case_mapper.fold_string(b);
16713 Ok(Value::Bool(folded_a == folded_b))
16714 }
16715 _ => Err(RuntimeError::new(
16716 "case_insensitive_eq() requires two strings",
16717 )),
16718 }
16719 });
16720
16721 define(interp, "compare_locale", Some(3), |_, args| {
16733 match (&args[0], &args[1], &args[2]) {
16734 (Value::String(a), Value::String(b), Value::String(locale_str)) => {
16735 let locale: Locale = locale_str.parse().unwrap_or_else(|_| "en".parse().unwrap());
16736 let options = CollatorOptions::new();
16737 let collator = Collator::try_new(&locale.into(), options)
16738 .unwrap_or_else(|_| Collator::try_new(&Default::default(), options).unwrap());
16739 let result = match collator.compare(a, b) {
16740 std::cmp::Ordering::Less => -1,
16741 std::cmp::Ordering::Equal => 0,
16742 std::cmp::Ordering::Greater => 1,
16743 };
16744 Ok(Value::Int(result))
16745 }
16746 _ => Err(RuntimeError::new(
16747 "compare_locale() requires two strings and locale",
16748 )),
16749 }
16750 });
16751
16752 define(interp, "sort_locale", Some(2), |_, args| {
16754 match (&args[0], &args[1]) {
16755 (Value::Array(arr), Value::String(locale_str)) => {
16756 let locale: Locale = locale_str.parse().unwrap_or_else(|_| "en".parse().unwrap());
16757 let options = CollatorOptions::new();
16758 let collator = Collator::try_new(&locale.into(), options)
16759 .unwrap_or_else(|_| Collator::try_new(&Default::default(), options).unwrap());
16760
16761 let mut items: Vec<(String, Value)> = arr
16762 .borrow()
16763 .iter()
16764 .map(|v| {
16765 let s = match v {
16766 Value::String(s) => (**s).clone(),
16767 _ => format!("{}", v),
16768 };
16769 (s, v.clone())
16770 })
16771 .collect();
16772
16773 items.sort_by(|(a, _), (b, _)| collator.compare(a, b));
16774
16775 let sorted: Vec<Value> = items.into_iter().map(|(_, v)| v).collect();
16776 Ok(Value::Array(Rc::new(RefCell::new(sorted))))
16777 }
16778 _ => Err(RuntimeError::new("sort_locale() requires array and locale")),
16779 }
16780 });
16781
16782 define(interp, "sentences", Some(1), |_, args| match &args[0] {
16794 Value::String(s) => {
16795 let segmenter = SentenceSegmenter::new();
16796 let breakpoints: Vec<usize> = segmenter.segment_str(s).collect();
16797 let mut sentences = Vec::new();
16798 let mut start = 0;
16799 for end in breakpoints {
16800 let sentence = s[start..end].trim();
16801 if !sentence.is_empty() {
16802 sentences.push(Value::String(Rc::new(sentence.to_string())));
16803 }
16804 start = end;
16805 }
16806 Ok(Value::Array(Rc::new(RefCell::new(sentences))))
16807 }
16808 _ => Err(RuntimeError::new("sentences() requires string")),
16809 });
16810
16811 define(interp, "sentence_count", Some(1), |_, args| {
16813 match &args[0] {
16814 Value::String(s) => {
16815 let segmenter = SentenceSegmenter::new();
16816 let breakpoints: Vec<usize> = segmenter.segment_str(s).collect();
16817 let count = breakpoints.len().saturating_sub(1);
16819 Ok(Value::Int(count as i64))
16820 }
16821 _ => Err(RuntimeError::new("sentence_count() requires string")),
16822 }
16823 });
16824
16825 define(interp, "words_icu", Some(1), |_, args| {
16827 match &args[0] {
16828 Value::String(s) => {
16829 let segmenter = WordSegmenter::new_auto();
16830 let breakpoints: Vec<usize> = segmenter.segment_str(s).collect();
16831 let mut words = Vec::new();
16832 let mut start = 0;
16833 for end in breakpoints {
16834 let word = &s[start..end];
16835 if !word.trim().is_empty() {
16837 words.push(Value::String(Rc::new(word.to_string())));
16838 }
16839 start = end;
16840 }
16841 Ok(Value::Array(Rc::new(RefCell::new(words))))
16842 }
16843 _ => Err(RuntimeError::new("words_icu() requires string")),
16844 }
16845 });
16846
16847 define(interp, "word_count_icu", Some(1), |_, args| {
16849 match &args[0] {
16850 Value::String(s) => {
16851 let segmenter = WordSegmenter::new_auto();
16852 let breakpoints: Vec<usize> = segmenter.segment_str(s).collect();
16853 let mut count = 0;
16854 let mut start = 0;
16855 for end in breakpoints {
16856 let word = &s[start..end];
16857 if !word.trim().is_empty() && word.chars().any(|c| c.is_alphanumeric()) {
16858 count += 1;
16859 }
16860 start = end;
16861 }
16862 Ok(Value::Int(count))
16863 }
16864 _ => Err(RuntimeError::new("word_count_icu() requires string")),
16865 }
16866 });
16867
16868 define(interp, "is_emoji", Some(1), |_, args| {
16874 match &args[0] {
16875 Value::String(s) => {
16876 let has_emoji = s.chars().any(|c| {
16877 let code = c as u32;
16878 (0x1F600..=0x1F64F).contains(&code) || (0x1F300..=0x1F5FF).contains(&code) || (0x1F680..=0x1F6FF).contains(&code) || (0x1F1E0..=0x1F1FF).contains(&code) || (0x2600..=0x26FF).contains(&code) || (0x2700..=0x27BF).contains(&code) || (0xFE00..=0xFE0F).contains(&code) || (0x1F900..=0x1F9FF).contains(&code) || (0x1FA00..=0x1FA6F).contains(&code) || (0x1FA70..=0x1FAFF).contains(&code) || (0x231A..=0x231B).contains(&code) || (0x23E9..=0x23F3).contains(&code) || (0x23F8..=0x23FA).contains(&code) });
16893 Ok(Value::Bool(has_emoji))
16894 }
16895 _ => Err(RuntimeError::new("is_emoji() requires string")),
16896 }
16897 });
16898
16899 define(interp, "extract_emoji", Some(1), |_, args| match &args[0] {
16901 Value::String(s) => {
16902 let emoji: Vec<Value> = s
16903 .graphemes(true)
16904 .filter(|g| {
16905 g.chars().any(|c| {
16906 let code = c as u32;
16907 (0x1F600..=0x1F64F).contains(&code)
16908 || (0x1F300..=0x1F5FF).contains(&code)
16909 || (0x1F680..=0x1F6FF).contains(&code)
16910 || (0x1F1E0..=0x1F1FF).contains(&code)
16911 || (0x2600..=0x26FF).contains(&code)
16912 || (0x2700..=0x27BF).contains(&code)
16913 || (0x1F900..=0x1F9FF).contains(&code)
16914 || (0x1FA00..=0x1FA6F).contains(&code)
16915 || (0x1FA70..=0x1FAFF).contains(&code)
16916 })
16917 })
16918 .map(|g| Value::String(Rc::new(g.to_string())))
16919 .collect();
16920 Ok(Value::Array(Rc::new(RefCell::new(emoji))))
16921 }
16922 _ => Err(RuntimeError::new("extract_emoji() requires string")),
16923 });
16924
16925 define(interp, "strip_emoji", Some(1), |_, args| match &args[0] {
16927 Value::String(s) => {
16928 let stripped: String = s
16929 .graphemes(true)
16930 .filter(|g| {
16931 !g.chars().any(|c| {
16932 let code = c as u32;
16933 (0x1F600..=0x1F64F).contains(&code)
16934 || (0x1F300..=0x1F5FF).contains(&code)
16935 || (0x1F680..=0x1F6FF).contains(&code)
16936 || (0x1F1E0..=0x1F1FF).contains(&code)
16937 || (0x2600..=0x26FF).contains(&code)
16938 || (0x2700..=0x27BF).contains(&code)
16939 || (0x1F900..=0x1F9FF).contains(&code)
16940 || (0x1FA00..=0x1FA6F).contains(&code)
16941 || (0x1FA70..=0x1FAFF).contains(&code)
16942 })
16943 })
16944 .collect();
16945 Ok(Value::String(Rc::new(stripped)))
16946 }
16947 _ => Err(RuntimeError::new("strip_emoji() requires string")),
16948 });
16949
16950 define(interp, "script_runs", Some(1), |_, args| {
16956 match &args[0] {
16957 Value::String(s) => {
16958 let mut runs: Vec<Value> = Vec::new();
16959 let mut current_run = String::new();
16960 let mut current_script: Option<Script> = None;
16961
16962 for c in s.chars() {
16963 let script = c.script();
16964 if script != Script::Common && script != Script::Inherited {
16966 if let Some(curr) = current_script {
16967 if script != curr {
16968 if !current_run.is_empty() {
16970 runs.push(Value::String(Rc::new(current_run.clone())));
16971 current_run.clear();
16972 }
16973 current_script = Some(script);
16974 }
16975 } else {
16976 current_script = Some(script);
16977 }
16978 }
16979 current_run.push(c);
16980 }
16981
16982 if !current_run.is_empty() {
16984 runs.push(Value::String(Rc::new(current_run)));
16985 }
16986
16987 Ok(Value::Array(Rc::new(RefCell::new(runs))))
16988 }
16989 _ => Err(RuntimeError::new("script_runs() requires string")),
16990 }
16991 });
16992
16993 define(interp, "script_ratio", Some(1), |_, args| {
16995 match &args[0] {
16996 Value::String(s) => {
16997 let mut script_counts: HashMap<String, usize> = HashMap::new();
16998 let mut total = 0usize;
16999
17000 for c in s.chars() {
17001 if !c.is_whitespace() && c != ' ' {
17002 let script = format!("{:?}", c.script());
17003 *script_counts.entry(script).or_insert(0) += 1;
17004 total += 1;
17005 }
17006 }
17007
17008 let mut result = HashMap::new();
17010 for (script, count) in script_counts {
17011 let ratio = if total > 0 {
17012 count as f64 / total as f64
17013 } else {
17014 0.0
17015 };
17016 result.insert(script, Value::Float(ratio));
17017 }
17018
17019 let map = Rc::new(RefCell::new(result));
17020 Ok(Value::Map(map))
17021 }
17022 _ => Err(RuntimeError::new("script_ratio() requires string")),
17023 }
17024 });
17025
17026 define(interp, "locale_name", Some(1), |_, args| {
17032 match &args[0] {
17033 Value::String(locale_str) => {
17034 Ok(Value::String(locale_str.clone()))
17037 }
17038 _ => Err(RuntimeError::new("locale_name() requires string")),
17039 }
17040 });
17041
17042 define(interp, "supported_locales", Some(0), |_, _| {
17044 let locales = vec![
17046 "ar", "bg", "ca", "cs", "da", "de", "el", "en", "es", "et", "fi", "fr", "he", "hi",
17047 "hr", "hu", "id", "it", "ja", "ko", "lt", "lv", "ms", "nb", "nl", "pl", "pt", "ro",
17048 "ru", "sk", "sl", "sr", "sv", "th", "tr", "uk", "vi", "zh",
17049 ];
17050 let values: Vec<Value> = locales
17051 .into_iter()
17052 .map(|s| Value::String(Rc::new(s.to_string())))
17053 .collect();
17054 Ok(Value::Array(Rc::new(RefCell::new(values))))
17055 });
17056}
17057
17058fn register_text_intelligence(interp: &mut Interpreter) {
17063 define(interp, "levenshtein", Some(2), |_, args| {
17069 match (&args[0], &args[1]) {
17070 (Value::String(a), Value::String(b)) => {
17071 let distance = strsim::levenshtein(a, b);
17072 Ok(Value::Int(distance as i64))
17073 }
17074 _ => Err(RuntimeError::new("levenshtein() requires two strings")),
17075 }
17076 });
17077
17078 define(
17080 interp,
17081 "levenshtein_normalized",
17082 Some(2),
17083 |_, args| match (&args[0], &args[1]) {
17084 (Value::String(a), Value::String(b)) => {
17085 let distance = strsim::normalized_levenshtein(a, b);
17086 Ok(Value::Float(distance))
17087 }
17088 _ => Err(RuntimeError::new(
17089 "levenshtein_normalized() requires two strings",
17090 )),
17091 },
17092 );
17093
17094 define(interp, "jaro", Some(2), |_, args| {
17096 match (&args[0], &args[1]) {
17097 (Value::String(a), Value::String(b)) => {
17098 let sim = strsim::jaro(a, b);
17099 Ok(Value::Float(sim))
17100 }
17101 _ => Err(RuntimeError::new("jaro() requires two strings")),
17102 }
17103 });
17104
17105 define(interp, "jaro_winkler", Some(2), |_, args| {
17107 match (&args[0], &args[1]) {
17108 (Value::String(a), Value::String(b)) => {
17109 let sim = strsim::jaro_winkler(a, b);
17110 Ok(Value::Float(sim))
17111 }
17112 _ => Err(RuntimeError::new("jaro_winkler() requires two strings")),
17113 }
17114 });
17115
17116 define(interp, "sorensen_dice", Some(2), |_, args| {
17118 match (&args[0], &args[1]) {
17119 (Value::String(a), Value::String(b)) => {
17120 let sim = strsim::sorensen_dice(a, b);
17121 Ok(Value::Float(sim))
17122 }
17123 _ => Err(RuntimeError::new("sorensen_dice() requires two strings")),
17124 }
17125 });
17126
17127 define(interp, "damerau_levenshtein", Some(2), |_, args| {
17129 match (&args[0], &args[1]) {
17130 (Value::String(a), Value::String(b)) => {
17131 let distance = strsim::damerau_levenshtein(a, b);
17132 Ok(Value::Int(distance as i64))
17133 }
17134 _ => Err(RuntimeError::new(
17135 "damerau_levenshtein() requires two strings",
17136 )),
17137 }
17138 });
17139
17140 define(interp, "osa_distance", Some(2), |_, args| {
17142 match (&args[0], &args[1]) {
17143 (Value::String(a), Value::String(b)) => {
17144 let distance = strsim::osa_distance(a, b);
17145 Ok(Value::Int(distance as i64))
17146 }
17147 _ => Err(RuntimeError::new("osa_distance() requires two strings")),
17148 }
17149 });
17150
17151 define(interp, "fuzzy_match", Some(3), |_, args| {
17153 match (&args[0], &args[1], &args[2]) {
17154 (Value::String(a), Value::String(b), Value::Float(threshold)) => {
17155 let sim = strsim::jaro_winkler(a, b);
17156 Ok(Value::Bool(sim >= *threshold))
17157 }
17158 (Value::String(a), Value::String(b), Value::Int(threshold)) => {
17159 let sim = strsim::jaro_winkler(a, b);
17160 Ok(Value::Bool(sim >= *threshold as f64))
17161 }
17162 _ => Err(RuntimeError::new(
17163 "fuzzy_match() requires two strings and threshold",
17164 )),
17165 }
17166 });
17167
17168 define(interp, "fuzzy_search", Some(3), |_, args| {
17170 match (&args[0], &args[1], &args[2]) {
17171 (Value::String(query), Value::Array(items), Value::Int(limit)) => {
17172 let items_ref = items.borrow();
17173 let mut scores: Vec<(f64, &str)> = items_ref
17174 .iter()
17175 .filter_map(|v| {
17176 if let Value::String(s) = v {
17177 Some((strsim::jaro_winkler(query, s), s.as_str()))
17178 } else {
17179 None
17180 }
17181 })
17182 .collect();
17183 scores.sort_by(|a, b| b.0.partial_cmp(&a.0).unwrap_or(std::cmp::Ordering::Equal));
17184 let results: Vec<Value> = scores
17185 .into_iter()
17186 .take(*limit as usize)
17187 .map(|(_, s)| Value::String(Rc::new(s.to_string())))
17188 .collect();
17189 Ok(Value::Array(Rc::new(RefCell::new(results))))
17190 }
17191 _ => Err(RuntimeError::new(
17192 "fuzzy_search() requires query string, array, and limit",
17193 )),
17194 }
17195 });
17196
17197 define(interp, "soundex", Some(1), |_, args| match &args[0] {
17203 Value::String(s) => {
17204 let code = compute_soundex(s);
17205 Ok(Value::String(Rc::new(code)))
17206 }
17207 _ => Err(RuntimeError::new("soundex() requires string")),
17208 });
17209
17210 define(interp, "soundex_match", Some(2), |_, args| {
17212 match (&args[0], &args[1]) {
17213 (Value::String(a), Value::String(b)) => {
17214 let code_a = compute_soundex(a);
17215 let code_b = compute_soundex(b);
17216 Ok(Value::Bool(code_a == code_b))
17217 }
17218 _ => Err(RuntimeError::new("soundex_match() requires two strings")),
17219 }
17220 });
17221
17222 define(interp, "metaphone", Some(1), |_, args| match &args[0] {
17224 Value::String(s) => {
17225 let code = compute_metaphone(s);
17226 Ok(Value::String(Rc::new(code)))
17227 }
17228 _ => Err(RuntimeError::new("metaphone() requires string")),
17229 });
17230
17231 define(interp, "metaphone_match", Some(2), |_, args| {
17233 match (&args[0], &args[1]) {
17234 (Value::String(a), Value::String(b)) => {
17235 let code_a = compute_metaphone(a);
17236 let code_b = compute_metaphone(b);
17237 Ok(Value::Bool(code_a == code_b))
17238 }
17239 _ => Err(RuntimeError::new("metaphone_match() requires two strings")),
17240 }
17241 });
17242
17243 define(interp, "cologne_phonetic", Some(1), |_, args| {
17245 match &args[0] {
17246 Value::String(s) => {
17247 let code = compute_cologne(s);
17248 Ok(Value::String(Rc::new(code)))
17249 }
17250 _ => Err(RuntimeError::new("cologne_phonetic() requires string")),
17251 }
17252 });
17253
17254 define(interp, "detect_language", Some(1), |_, args| {
17260 match &args[0] {
17261 Value::String(s) => {
17262 if let Some(info) = detect(s) {
17263 let lang_code = match info.lang() {
17264 Lang::Eng => "en",
17265 Lang::Spa => "es",
17266 Lang::Fra => "fr",
17267 Lang::Deu => "de",
17268 Lang::Ita => "it",
17269 Lang::Por => "pt",
17270 Lang::Rus => "ru",
17271 Lang::Ara => "ar",
17272 Lang::Hin => "hi",
17273 Lang::Cmn => "zh",
17274 Lang::Jpn => "ja",
17275 Lang::Kor => "ko",
17276 Lang::Nld => "nl",
17277 Lang::Swe => "sv",
17278 Lang::Tur => "tr",
17279 Lang::Pol => "pl",
17280 Lang::Ukr => "uk",
17281 Lang::Ces => "cs",
17282 Lang::Dan => "da",
17283 Lang::Fin => "fi",
17284 Lang::Ell => "el",
17285 Lang::Heb => "he",
17286 Lang::Hun => "hu",
17287 Lang::Ind => "id",
17288 Lang::Nob => "no",
17289 Lang::Ron => "ro",
17290 Lang::Slk => "sk",
17291 Lang::Tha => "th",
17292 Lang::Vie => "vi",
17293 _ => "unknown",
17294 };
17295 Ok(Value::String(Rc::new(lang_code.to_string())))
17296 } else {
17297 Ok(Value::String(Rc::new("unknown".to_string())))
17298 }
17299 }
17300 _ => Err(RuntimeError::new("detect_language() requires string")),
17301 }
17302 });
17303
17304 define(
17306 interp,
17307 "detect_language_confidence",
17308 Some(1),
17309 |_, args| match &args[0] {
17310 Value::String(s) => {
17311 if let Some(info) = detect(s) {
17312 let lang_code = match info.lang() {
17313 Lang::Eng => "en",
17314 Lang::Spa => "es",
17315 Lang::Fra => "fr",
17316 Lang::Deu => "de",
17317 Lang::Ita => "it",
17318 Lang::Por => "pt",
17319 Lang::Rus => "ru",
17320 Lang::Ara => "ar",
17321 Lang::Cmn => "zh",
17322 Lang::Jpn => "ja",
17323 _ => "unknown",
17324 };
17325 let confidence = info.confidence();
17326 let mut map = HashMap::new();
17327 map.insert(
17328 "lang".to_string(),
17329 Value::String(Rc::new(lang_code.to_string())),
17330 );
17331 map.insert("confidence".to_string(), Value::Float(confidence as f64));
17332 Ok(Value::Map(Rc::new(RefCell::new(map))))
17333 } else {
17334 let mut map = HashMap::new();
17335 map.insert(
17336 "lang".to_string(),
17337 Value::String(Rc::new("unknown".to_string())),
17338 );
17339 map.insert("confidence".to_string(), Value::Float(0.0));
17340 Ok(Value::Map(Rc::new(RefCell::new(map))))
17341 }
17342 }
17343 _ => Err(RuntimeError::new(
17344 "detect_language_confidence() requires string",
17345 )),
17346 },
17347 );
17348
17349 define(
17351 interp,
17352 "detect_script_whatlang",
17353 Some(1),
17354 |_, args| match &args[0] {
17355 Value::String(s) => {
17356 if let Some(info) = detect(s) {
17357 let script_name = match info.script() {
17358 WhatLangScript::Latin => "Latin",
17359 WhatLangScript::Cyrillic => "Cyrillic",
17360 WhatLangScript::Arabic => "Arabic",
17361 WhatLangScript::Devanagari => "Devanagari",
17362 WhatLangScript::Ethiopic => "Ethiopic",
17363 WhatLangScript::Georgian => "Georgian",
17364 WhatLangScript::Greek => "Greek",
17365 WhatLangScript::Gujarati => "Gujarati",
17366 WhatLangScript::Gurmukhi => "Gurmukhi",
17367 WhatLangScript::Hangul => "Hangul",
17368 WhatLangScript::Hebrew => "Hebrew",
17369 WhatLangScript::Hiragana => "Hiragana",
17370 WhatLangScript::Kannada => "Kannada",
17371 WhatLangScript::Katakana => "Katakana",
17372 WhatLangScript::Khmer => "Khmer",
17373 WhatLangScript::Malayalam => "Malayalam",
17374 WhatLangScript::Mandarin => "Mandarin",
17375 WhatLangScript::Myanmar => "Myanmar",
17376 WhatLangScript::Oriya => "Oriya",
17377 WhatLangScript::Sinhala => "Sinhala",
17378 WhatLangScript::Tamil => "Tamil",
17379 WhatLangScript::Telugu => "Telugu",
17380 WhatLangScript::Thai => "Thai",
17381 WhatLangScript::Bengali => "Bengali",
17382 WhatLangScript::Armenian => "Armenian",
17383 };
17384 Ok(Value::String(Rc::new(script_name.to_string())))
17385 } else {
17386 Ok(Value::String(Rc::new("Unknown".to_string())))
17387 }
17388 }
17389 _ => Err(RuntimeError::new(
17390 "detect_script_whatlang() requires string",
17391 )),
17392 },
17393 );
17394
17395 define(interp, "is_language", Some(2), |_, args| {
17397 match (&args[0], &args[1]) {
17398 (Value::String(s), Value::String(lang)) => {
17399 if let Some(info) = detect(s) {
17400 let detected = match info.lang() {
17401 Lang::Eng => "en",
17402 Lang::Spa => "es",
17403 Lang::Fra => "fr",
17404 Lang::Deu => "de",
17405 Lang::Ita => "it",
17406 Lang::Por => "pt",
17407 Lang::Rus => "ru",
17408 _ => "unknown",
17409 };
17410 Ok(Value::Bool(detected == lang.as_str()))
17411 } else {
17412 Ok(Value::Bool(false))
17413 }
17414 }
17415 _ => Err(RuntimeError::new(
17416 "is_language() requires string and language code",
17417 )),
17418 }
17419 });
17420
17421 define(interp, "token_count", Some(1), |_, args| match &args[0] {
17427 Value::String(s) => {
17428 if let Ok(bpe) = cl100k_base() {
17429 let tokens = bpe.encode_with_special_tokens(s);
17430 Ok(Value::Int(tokens.len() as i64))
17431 } else {
17432 Err(RuntimeError::new("Failed to initialize tokenizer"))
17433 }
17434 }
17435 _ => Err(RuntimeError::new("token_count() requires string")),
17436 });
17437
17438 define(interp, "token_count_model", Some(2), |_, args| {
17440 match (&args[0], &args[1]) {
17441 (Value::String(s), Value::String(model)) => {
17442 let bpe_result = match model.as_str() {
17443 "gpt4" | "gpt-4" | "claude" | "cl100k" => cl100k_base(),
17444 "gpt3" | "gpt-3" | "p50k" => p50k_base(),
17445 "codex" | "r50k" => r50k_base(),
17446 _ => cl100k_base(), };
17448 if let Ok(bpe) = bpe_result {
17449 let tokens = bpe.encode_with_special_tokens(s);
17450 Ok(Value::Int(tokens.len() as i64))
17451 } else {
17452 Err(RuntimeError::new("Failed to initialize tokenizer"))
17453 }
17454 }
17455 _ => Err(RuntimeError::new(
17456 "token_count_model() requires string and model name",
17457 )),
17458 }
17459 });
17460
17461 define(interp, "tokenize_ids", Some(1), |_, args| match &args[0] {
17463 Value::String(s) => {
17464 if let Ok(bpe) = cl100k_base() {
17465 let tokens = bpe.encode_with_special_tokens(s);
17466 let values: Vec<Value> = tokens.into_iter().map(|t| Value::Int(t as i64)).collect();
17467 Ok(Value::Array(Rc::new(RefCell::new(values))))
17468 } else {
17469 Err(RuntimeError::new("Failed to initialize tokenizer"))
17470 }
17471 }
17472 _ => Err(RuntimeError::new("tokenize_ids() requires string")),
17473 });
17474
17475 define(interp, "truncate_tokens", Some(2), |_, args| {
17477 match (&args[0], &args[1]) {
17478 (Value::String(s), Value::Int(max_tokens)) => {
17479 if let Ok(bpe) = cl100k_base() {
17480 let tokens = bpe.encode_with_special_tokens(s);
17481 if tokens.len() <= *max_tokens as usize {
17482 Ok(Value::String(s.clone()))
17483 } else {
17484 let truncated: Vec<usize> =
17485 tokens.into_iter().take(*max_tokens as usize).collect();
17486 if let Ok(decoded) = bpe.decode(truncated) {
17487 Ok(Value::String(Rc::new(decoded)))
17488 } else {
17489 Err(RuntimeError::new("Failed to decode tokens"))
17490 }
17491 }
17492 } else {
17493 Err(RuntimeError::new("Failed to initialize tokenizer"))
17494 }
17495 }
17496 _ => Err(RuntimeError::new(
17497 "truncate_tokens() requires string and max tokens",
17498 )),
17499 }
17500 });
17501
17502 define(interp, "estimate_cost", Some(3), |_, args| {
17504 match (&args[0], &args[1], &args[2]) {
17505 (Value::String(s), Value::Float(input_cost), Value::Float(output_cost)) => {
17506 if let Ok(bpe) = cl100k_base() {
17507 let tokens = bpe.encode_with_special_tokens(s);
17508 let count = tokens.len() as f64;
17509 let input_total = (count / 1000.0) * input_cost;
17511 let output_total = (count / 1000.0) * output_cost;
17512 let mut map = HashMap::new();
17513 map.insert("tokens".to_string(), Value::Int(tokens.len() as i64));
17514 map.insert("input_cost".to_string(), Value::Float(input_total));
17515 map.insert("output_cost".to_string(), Value::Float(output_total));
17516 Ok(Value::Map(Rc::new(RefCell::new(map))))
17517 } else {
17518 Err(RuntimeError::new("Failed to initialize tokenizer"))
17519 }
17520 }
17521 _ => Err(RuntimeError::new(
17522 "estimate_cost() requires string, input cost, output cost",
17523 )),
17524 }
17525 });
17526
17527 define(interp, "stem", Some(1), |_, args| match &args[0] {
17533 Value::String(s) => {
17534 let stemmer = Stemmer::create(StemAlgorithm::English);
17535 let stemmed = stemmer.stem(s);
17536 Ok(Value::String(Rc::new(stemmed.to_string())))
17537 }
17538 _ => Err(RuntimeError::new("stem() requires string")),
17539 });
17540
17541 define(interp, "stem_language", Some(2), |_, args| {
17543 match (&args[0], &args[1]) {
17544 (Value::String(s), Value::String(lang)) => {
17545 let algorithm = match lang.as_str() {
17546 "en" | "english" => StemAlgorithm::English,
17547 "fr" | "french" => StemAlgorithm::French,
17548 "de" | "german" => StemAlgorithm::German,
17549 "es" | "spanish" => StemAlgorithm::Spanish,
17550 "it" | "italian" => StemAlgorithm::Italian,
17551 "pt" | "portuguese" => StemAlgorithm::Portuguese,
17552 "nl" | "dutch" => StemAlgorithm::Dutch,
17553 "sv" | "swedish" => StemAlgorithm::Swedish,
17554 "no" | "norwegian" => StemAlgorithm::Norwegian,
17555 "da" | "danish" => StemAlgorithm::Danish,
17556 "fi" | "finnish" => StemAlgorithm::Finnish,
17557 "ru" | "russian" => StemAlgorithm::Russian,
17558 "ro" | "romanian" => StemAlgorithm::Romanian,
17559 "hu" | "hungarian" => StemAlgorithm::Hungarian,
17560 "tr" | "turkish" => StemAlgorithm::Turkish,
17561 "ar" | "arabic" => StemAlgorithm::Arabic,
17562 _ => StemAlgorithm::English,
17563 };
17564 let stemmer = Stemmer::create(algorithm);
17565 let stemmed = stemmer.stem(s);
17566 Ok(Value::String(Rc::new(stemmed.to_string())))
17567 }
17568 _ => Err(RuntimeError::new(
17569 "stem_language() requires string and language code",
17570 )),
17571 }
17572 });
17573
17574 define(interp, "stem_all", Some(1), |_, args| match &args[0] {
17576 Value::Array(arr) => {
17577 let stemmer = Stemmer::create(StemAlgorithm::English);
17578 let arr_ref = arr.borrow();
17579 let results: Vec<Value> = arr_ref
17580 .iter()
17581 .filter_map(|v| {
17582 if let Value::String(s) = v {
17583 Some(Value::String(Rc::new(stemmer.stem(s).to_string())))
17584 } else {
17585 None
17586 }
17587 })
17588 .collect();
17589 Ok(Value::Array(Rc::new(RefCell::new(results))))
17590 }
17591 _ => Err(RuntimeError::new("stem_all() requires array of strings")),
17592 });
17593
17594 define(interp, "is_stopword", Some(1), |_, args| match &args[0] {
17600 Value::String(s) => {
17601 let word = s.to_lowercase();
17602 let stopwords = get_stopwords("en");
17603 Ok(Value::Bool(stopwords.contains(&word.as_str())))
17604 }
17605 _ => Err(RuntimeError::new("is_stopword() requires string")),
17606 });
17607
17608 define(interp, "is_stopword_language", Some(2), |_, args| {
17610 match (&args[0], &args[1]) {
17611 (Value::String(s), Value::String(lang)) => {
17612 let word = s.to_lowercase();
17613 let stopwords = get_stopwords(lang);
17614 Ok(Value::Bool(stopwords.contains(&word.as_str())))
17615 }
17616 _ => Err(RuntimeError::new(
17617 "is_stopword_language() requires string and language",
17618 )),
17619 }
17620 });
17621
17622 define(interp, "remove_stopwords", Some(1), |_, args| {
17624 match &args[0] {
17625 Value::Array(arr) => {
17626 let stopwords = get_stopwords("en");
17627 let arr_ref = arr.borrow();
17628 let results: Vec<Value> = arr_ref
17629 .iter()
17630 .filter(|v| {
17631 if let Value::String(s) = v {
17632 !stopwords.contains(&s.to_lowercase().as_str())
17633 } else {
17634 true
17635 }
17636 })
17637 .cloned()
17638 .collect();
17639 Ok(Value::Array(Rc::new(RefCell::new(results))))
17640 }
17641 _ => Err(RuntimeError::new(
17642 "remove_stopwords() requires array of strings",
17643 )),
17644 }
17645 });
17646
17647 define(
17649 interp,
17650 "remove_stopwords_text",
17651 Some(1),
17652 |_, args| match &args[0] {
17653 Value::String(s) => {
17654 let stopwords = get_stopwords("en");
17655 let words: Vec<&str> = s
17656 .split_whitespace()
17657 .filter(|w| !stopwords.contains(&w.to_lowercase().as_str()))
17658 .collect();
17659 Ok(Value::String(Rc::new(words.join(" "))))
17660 }
17661 _ => Err(RuntimeError::new("remove_stopwords_text() requires string")),
17662 },
17663 );
17664
17665 define(
17667 interp,
17668 "get_stopwords_list",
17669 Some(1),
17670 |_, args| match &args[0] {
17671 Value::String(lang) => {
17672 let stopwords = get_stopwords(lang);
17673 let values: Vec<Value> = stopwords
17674 .iter()
17675 .map(|s| Value::String(Rc::new(s.to_string())))
17676 .collect();
17677 Ok(Value::Array(Rc::new(RefCell::new(values))))
17678 }
17679 _ => Err(RuntimeError::new(
17680 "get_stopwords_list() requires language code",
17681 )),
17682 },
17683 );
17684
17685 define(interp, "ngrams", Some(2), |_, args| {
17691 match (&args[0], &args[1]) {
17692 (Value::String(s), Value::Int(n)) => {
17693 let words: Vec<&str> = s.split_whitespace().collect();
17694 let n = *n as usize;
17695 if n == 0 || n > words.len() {
17696 return Ok(Value::Array(Rc::new(RefCell::new(vec![]))));
17697 }
17698 let ngrams: Vec<Value> = words
17699 .windows(n)
17700 .map(|w| Value::String(Rc::new(w.join(" "))))
17701 .collect();
17702 Ok(Value::Array(Rc::new(RefCell::new(ngrams))))
17703 }
17704 _ => Err(RuntimeError::new("ngrams() requires string and n")),
17705 }
17706 });
17707
17708 define(interp, "char_ngrams", Some(2), |_, args| {
17710 match (&args[0], &args[1]) {
17711 (Value::String(s), Value::Int(n)) => {
17712 let chars: Vec<char> = s.chars().collect();
17713 let n = *n as usize;
17714 if n == 0 || n > chars.len() {
17715 return Ok(Value::Array(Rc::new(RefCell::new(vec![]))));
17716 }
17717 let ngrams: Vec<Value> = chars
17718 .windows(n)
17719 .map(|w| Value::String(Rc::new(w.iter().collect())))
17720 .collect();
17721 Ok(Value::Array(Rc::new(RefCell::new(ngrams))))
17722 }
17723 _ => Err(RuntimeError::new("char_ngrams() requires string and n")),
17724 }
17725 });
17726
17727 define(interp, "shingles", Some(2), |_, args| {
17729 match (&args[0], &args[1]) {
17730 (Value::String(s), Value::Int(n)) => {
17731 let words: Vec<&str> = s.split_whitespace().collect();
17732 let n = *n as usize;
17733 if n == 0 || n > words.len() {
17734 return Ok(Value::Array(Rc::new(RefCell::new(vec![]))));
17735 }
17736 let mut seen = std::collections::HashSet::new();
17737 let shingles: Vec<Value> = words
17738 .windows(n)
17739 .filter_map(|w| {
17740 let s = w.join(" ");
17741 if seen.insert(s.clone()) {
17742 Some(Value::String(Rc::new(s)))
17743 } else {
17744 None
17745 }
17746 })
17747 .collect();
17748 Ok(Value::Array(Rc::new(RefCell::new(shingles))))
17749 }
17750 _ => Err(RuntimeError::new("shingles() requires string and n")),
17751 }
17752 });
17753
17754 define(interp, "jaccard_similarity", Some(2), |_, args| {
17756 match (&args[0], &args[1]) {
17757 (Value::Array(a), Value::Array(b)) => {
17758 let a_ref = a.borrow();
17759 let b_ref = b.borrow();
17760 let set_a: std::collections::HashSet<String> = a_ref
17761 .iter()
17762 .filter_map(|v| {
17763 if let Value::String(s) = v {
17764 Some(s.to_string())
17765 } else {
17766 None
17767 }
17768 })
17769 .collect();
17770 let set_b: std::collections::HashSet<String> = b_ref
17771 .iter()
17772 .filter_map(|v| {
17773 if let Value::String(s) = v {
17774 Some(s.to_string())
17775 } else {
17776 None
17777 }
17778 })
17779 .collect();
17780 let intersection = set_a.intersection(&set_b).count();
17781 let union = set_a.union(&set_b).count();
17782 if union == 0 {
17783 Ok(Value::Float(0.0))
17784 } else {
17785 Ok(Value::Float(intersection as f64 / union as f64))
17786 }
17787 }
17788 _ => Err(RuntimeError::new(
17789 "jaccard_similarity() requires two arrays",
17790 )),
17791 }
17792 });
17793
17794 define(interp, "minhash_signature", Some(2), |_, args| {
17796 match (&args[0], &args[1]) {
17797 (Value::Array(arr), Value::Int(num_hashes)) => {
17798 let arr_ref = arr.borrow();
17799 let items: std::collections::HashSet<String> = arr_ref
17800 .iter()
17801 .filter_map(|v| {
17802 if let Value::String(s) = v {
17803 Some(s.to_string())
17804 } else {
17805 None
17806 }
17807 })
17808 .collect();
17809
17810 let mut signature: Vec<Value> = Vec::with_capacity(*num_hashes as usize);
17812 for i in 0..*num_hashes {
17813 let mut min_hash: u64 = u64::MAX;
17814 for item in &items {
17815 let hash = compute_hash(item, i as u64);
17816 if hash < min_hash {
17817 min_hash = hash;
17818 }
17819 }
17820 signature.push(Value::Int(min_hash as i64));
17821 }
17822 Ok(Value::Array(Rc::new(RefCell::new(signature))))
17823 }
17824 _ => Err(RuntimeError::new(
17825 "minhash_signature() requires array and num_hashes",
17826 )),
17827 }
17828 });
17829
17830 define(interp, "preprocess_text", Some(1), |_, args| {
17836 match &args[0] {
17837 Value::String(s) => {
17838 let lower = s.to_lowercase();
17840 let clean: String = lower
17842 .chars()
17843 .filter(|c| c.is_alphanumeric() || c.is_whitespace())
17844 .collect();
17845 let normalized: String = clean.split_whitespace().collect::<Vec<_>>().join(" ");
17847 Ok(Value::String(Rc::new(normalized)))
17848 }
17849 _ => Err(RuntimeError::new("preprocess_text() requires string")),
17850 }
17851 });
17852
17853 define(interp, "tokenize_words", Some(1), |_, args| {
17855 match &args[0] {
17856 Value::String(s) => {
17857 let words: Vec<Value> = s
17858 .split_whitespace()
17859 .map(|w| Value::String(Rc::new(w.to_string())))
17860 .collect();
17861 Ok(Value::Array(Rc::new(RefCell::new(words))))
17862 }
17863 _ => Err(RuntimeError::new("tokenize_words() requires string")),
17864 }
17865 });
17866
17867 define(interp, "extract_keywords", Some(1), |_, args| {
17869 match &args[0] {
17870 Value::String(s) => {
17871 let stopwords = get_stopwords("en");
17872 let words: Vec<Value> = s
17873 .split_whitespace()
17874 .filter(|w| {
17875 let lower = w.to_lowercase();
17876 !stopwords.contains(&lower.as_str()) && lower.len() > 2
17877 })
17878 .map(|w| Value::String(Rc::new(w.to_lowercase())))
17879 .collect();
17880 Ok(Value::Array(Rc::new(RefCell::new(words))))
17881 }
17882 _ => Err(RuntimeError::new("extract_keywords() requires string")),
17883 }
17884 });
17885
17886 define(interp, "word_frequency", Some(1), |_, args| {
17888 match &args[0] {
17889 Value::String(s) => {
17890 let mut freq: HashMap<String, i64> = HashMap::new();
17891 for word in s.split_whitespace() {
17892 let lower = word.to_lowercase();
17893 *freq.entry(lower).or_insert(0) += 1;
17894 }
17895 let map: HashMap<String, Value> =
17896 freq.into_iter().map(|(k, v)| (k, Value::Int(v))).collect();
17897 Ok(Value::Map(Rc::new(RefCell::new(map))))
17898 }
17899 _ => Err(RuntimeError::new("word_frequency() requires string")),
17900 }
17901 });
17902
17903 define(interp, "sentiment_words", Some(1), |_, args| {
17909 match &args[0] {
17910 Value::String(s) => {
17911 let positive = vec![
17912 "good",
17913 "great",
17914 "excellent",
17915 "amazing",
17916 "wonderful",
17917 "fantastic",
17918 "love",
17919 "happy",
17920 "joy",
17921 "beautiful",
17922 "awesome",
17923 "perfect",
17924 "best",
17925 "brilliant",
17926 "delightful",
17927 "pleasant",
17928 "positive",
17929 ];
17930 let negative = vec![
17931 "bad",
17932 "terrible",
17933 "awful",
17934 "horrible",
17935 "hate",
17936 "sad",
17937 "angry",
17938 "worst",
17939 "poor",
17940 "negative",
17941 "disappointing",
17942 "ugly",
17943 "disgusting",
17944 "painful",
17945 "miserable",
17946 "annoying",
17947 ];
17948
17949 let lower = s.to_lowercase();
17950 let words: Vec<&str> = lower.split_whitespace().collect();
17951 let pos_count: i64 = words.iter().filter(|w| positive.contains(w)).count() as i64;
17952 let neg_count: i64 = words.iter().filter(|w| negative.contains(w)).count() as i64;
17953
17954 let mut map = HashMap::new();
17955 map.insert("positive".to_string(), Value::Int(pos_count));
17956 map.insert("negative".to_string(), Value::Int(neg_count));
17957 map.insert("total".to_string(), Value::Int(words.len() as i64));
17958
17959 let score = if pos_count + neg_count > 0 {
17960 (pos_count - neg_count) as f64 / (pos_count + neg_count) as f64
17961 } else {
17962 0.0
17963 };
17964 map.insert("score".to_string(), Value::Float(score));
17965
17966 Ok(Value::Map(Rc::new(RefCell::new(map))))
17967 }
17968 _ => Err(RuntimeError::new("sentiment_words() requires string")),
17969 }
17970 });
17971
17972 define(interp, "has_question", Some(1), |_, args| match &args[0] {
17974 Value::String(s) => {
17975 let has_q_mark = s.contains('?');
17976 let lower = s.to_lowercase();
17977 let question_words = [
17978 "what", "where", "when", "why", "how", "who", "which", "whose", "whom",
17979 ];
17980 let starts_with_q = question_words.iter().any(|w| lower.starts_with(w));
17981 Ok(Value::Bool(has_q_mark || starts_with_q))
17982 }
17983 _ => Err(RuntimeError::new("has_question() requires string")),
17984 });
17985
17986 define(interp, "has_exclamation", Some(1), |_, args| {
17988 match &args[0] {
17989 Value::String(s) => Ok(Value::Bool(s.contains('!'))),
17990 _ => Err(RuntimeError::new("has_exclamation() requires string")),
17991 }
17992 });
17993
17994 define(interp, "text_formality", Some(1), |_, args| {
17996 match &args[0] {
17997 Value::String(s) => {
17998 let lower = s.to_lowercase();
17999 let informal_markers = vec![
18000 "gonna", "wanna", "gotta", "kinda", "sorta", "dunno", "yeah", "yep", "nope",
18001 "ok", "lol", "omg", "btw", "u", "ur", "r", "y", "2", "4",
18002 ];
18003 let formal_markers = vec![
18004 "therefore",
18005 "furthermore",
18006 "moreover",
18007 "consequently",
18008 "nevertheless",
18009 "however",
18010 "whereas",
18011 "hereby",
18012 "respectfully",
18013 "sincerely",
18014 "accordingly",
18015 ];
18016
18017 let words: Vec<&str> = lower.split_whitespace().collect();
18018 let informal_count = words
18019 .iter()
18020 .filter(|w| informal_markers.contains(w))
18021 .count();
18022 let formal_count = words.iter().filter(|w| formal_markers.contains(w)).count();
18023
18024 let score = if informal_count + formal_count > 0 {
18025 formal_count as f64 / (informal_count + formal_count) as f64
18026 } else {
18027 0.5 };
18029
18030 Ok(Value::Float(score))
18031 }
18032 _ => Err(RuntimeError::new("text_formality() requires string")),
18033 }
18034 });
18035
18036 define(interp, "sentiment_vader", Some(1), |_, args| {
18042 match &args[0] {
18043 Value::String(s) => {
18044 let result = compute_vader_sentiment(s);
18045 let mut map = HashMap::new();
18046 map.insert("positive".to_string(), Value::Float(result.0));
18047 map.insert("negative".to_string(), Value::Float(result.1));
18048 map.insert("neutral".to_string(), Value::Float(result.2));
18049 map.insert("compound".to_string(), Value::Float(result.3));
18050 Ok(Value::Map(Rc::new(RefCell::new(map))))
18051 }
18052 _ => Err(RuntimeError::new("sentiment_vader() requires string")),
18053 }
18054 });
18055
18056 define(interp, "emotion_detect", Some(1), |_, args| {
18058 match &args[0] {
18059 Value::String(s) => {
18060 let emotions = compute_emotions(s);
18061 let map: HashMap<String, Value> = emotions
18062 .into_iter()
18063 .map(|(k, v)| (k, Value::Float(v)))
18064 .collect();
18065 Ok(Value::Map(Rc::new(RefCell::new(map))))
18066 }
18067 _ => Err(RuntimeError::new("emotion_detect() requires string")),
18068 }
18069 });
18070
18071 define(interp, "intensity_score", Some(1), |_, args| {
18073 match &args[0] {
18074 Value::String(s) => {
18075 let score = compute_intensity(s);
18076 Ok(Value::Float(score))
18077 }
18078 _ => Err(RuntimeError::new("intensity_score() requires string")),
18079 }
18080 });
18081
18082 define(interp, "detect_sarcasm", Some(1), |_, args| {
18088 match &args[0] {
18089 Value::String(s) => {
18090 let result = compute_sarcasm_score(s);
18091 let mut map = HashMap::new();
18092 map.insert("score".to_string(), Value::Float(result.0));
18093 map.insert("confidence".to_string(), Value::Float(result.1));
18094 let markers: Vec<Value> = result
18095 .2
18096 .into_iter()
18097 .map(|m| Value::String(Rc::new(m)))
18098 .collect();
18099 map.insert(
18100 "markers".to_string(),
18101 Value::Array(Rc::new(RefCell::new(markers))),
18102 );
18103 Ok(Value::Map(Rc::new(RefCell::new(map))))
18104 }
18105 _ => Err(RuntimeError::new("detect_sarcasm() requires string")),
18106 }
18107 });
18108
18109 define(interp, "is_sarcastic", Some(1), |_, args| match &args[0] {
18111 Value::String(s) => {
18112 let result = compute_sarcasm_score(s);
18113 Ok(Value::Bool(result.0 > 0.5))
18114 }
18115 _ => Err(RuntimeError::new("is_sarcastic() requires string")),
18116 });
18117
18118 define(interp, "detect_irony", Some(1), |_, args| match &args[0] {
18120 Value::String(s) => {
18121 let score = compute_irony_score(s);
18122 Ok(Value::Float(score))
18123 }
18124 _ => Err(RuntimeError::new("detect_irony() requires string")),
18125 });
18126
18127 define(interp, "extract_emails", Some(1), |_, args| {
18133 match &args[0] {
18134 Value::String(s) => {
18135 let re = Regex::new(r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}").unwrap();
18136 let emails: Vec<Value> = re
18137 .find_iter(s)
18138 .map(|m| Value::String(Rc::new(m.as_str().to_string())))
18139 .collect();
18140 Ok(Value::Array(Rc::new(RefCell::new(emails))))
18141 }
18142 _ => Err(RuntimeError::new("extract_emails() requires string")),
18143 }
18144 });
18145
18146 define(interp, "extract_urls", Some(1), |_, args| match &args[0] {
18148 Value::String(s) => {
18149 let re = Regex::new(r"https?://[^\s<>\[\]{}|\\^]+").unwrap();
18150 let urls: Vec<Value> = re
18151 .find_iter(s)
18152 .map(|m| Value::String(Rc::new(m.as_str().to_string())))
18153 .collect();
18154 Ok(Value::Array(Rc::new(RefCell::new(urls))))
18155 }
18156 _ => Err(RuntimeError::new("extract_urls() requires string")),
18157 });
18158
18159 define(
18161 interp,
18162 "extract_phone_numbers",
18163 Some(1),
18164 |_, args| match &args[0] {
18165 Value::String(s) => {
18166 let re =
18167 Regex::new(r"(?:\+?1[-.\s]?)?\(?[0-9]{3}\)?[-.\s]?[0-9]{3}[-.\s]?[0-9]{4}")
18168 .unwrap();
18169 let phones: Vec<Value> = re
18170 .find_iter(s)
18171 .map(|m| Value::String(Rc::new(m.as_str().to_string())))
18172 .collect();
18173 Ok(Value::Array(Rc::new(RefCell::new(phones))))
18174 }
18175 _ => Err(RuntimeError::new("extract_phone_numbers() requires string")),
18176 },
18177 );
18178
18179 define(interp, "extract_dates", Some(1), |_, args| {
18181 match &args[0] {
18182 Value::String(s) => {
18183 let patterns = vec![
18185 r"\d{4}-\d{2}-\d{2}", r"\d{2}/\d{2}/\d{4}", r"\d{2}-\d{2}-\d{4}", r"(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[a-z]*\s+\d{1,2},?\s+\d{4}",
18189 r"\d{1,2}\s+(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[a-z]*\s+\d{4}",
18190 ];
18191 let mut dates = Vec::new();
18192 for pattern in patterns {
18193 if let Ok(re) = Regex::new(pattern) {
18194 for m in re.find_iter(s) {
18195 dates.push(Value::String(Rc::new(m.as_str().to_string())));
18196 }
18197 }
18198 }
18199 Ok(Value::Array(Rc::new(RefCell::new(dates))))
18200 }
18201 _ => Err(RuntimeError::new("extract_dates() requires string")),
18202 }
18203 });
18204
18205 define(interp, "extract_money", Some(1), |_, args| match &args[0] {
18207 Value::String(s) => {
18208 let re = Regex::new(r"[$€£¥]\s*\d+(?:,\d{3})*(?:\.\d{2})?|\d+(?:,\d{3})*(?:\.\d{2})?\s*(?:dollars?|euros?|pounds?|USD|EUR|GBP)").unwrap();
18209 let money: Vec<Value> = re
18210 .find_iter(s)
18211 .map(|m| Value::String(Rc::new(m.as_str().to_string())))
18212 .collect();
18213 Ok(Value::Array(Rc::new(RefCell::new(money))))
18214 }
18215 _ => Err(RuntimeError::new("extract_money() requires string")),
18216 });
18217
18218 define(interp, "extract_hashtags", Some(1), |_, args| {
18220 match &args[0] {
18221 Value::String(s) => {
18222 let re = Regex::new(r"#\w+").unwrap();
18223 let tags: Vec<Value> = re
18224 .find_iter(s)
18225 .map(|m| Value::String(Rc::new(m.as_str().to_string())))
18226 .collect();
18227 Ok(Value::Array(Rc::new(RefCell::new(tags))))
18228 }
18229 _ => Err(RuntimeError::new("extract_hashtags() requires string")),
18230 }
18231 });
18232
18233 define(interp, "extract_mentions", Some(1), |_, args| {
18235 match &args[0] {
18236 Value::String(s) => {
18237 let re = Regex::new(r"@\w+").unwrap();
18238 let mentions: Vec<Value> = re
18239 .find_iter(s)
18240 .map(|m| Value::String(Rc::new(m.as_str().to_string())))
18241 .collect();
18242 Ok(Value::Array(Rc::new(RefCell::new(mentions))))
18243 }
18244 _ => Err(RuntimeError::new("extract_mentions() requires string")),
18245 }
18246 });
18247
18248 define(interp, "extract_numbers", Some(1), |_, args| {
18250 match &args[0] {
18251 Value::String(s) => {
18252 let re = Regex::new(r"-?\d+(?:,\d{3})*(?:\.\d+)?").unwrap();
18253 let numbers: Vec<Value> = re
18254 .find_iter(s)
18255 .filter_map(|m| {
18256 let num_str = m.as_str().replace(",", "");
18257 if let Ok(n) = num_str.parse::<f64>() {
18258 Some(Value::Float(n))
18259 } else {
18260 None
18261 }
18262 })
18263 .collect();
18264 Ok(Value::Array(Rc::new(RefCell::new(numbers))))
18265 }
18266 _ => Err(RuntimeError::new("extract_numbers() requires string")),
18267 }
18268 });
18269
18270 define(interp, "extract_entities", Some(1), |_, args| {
18272 match &args[0] {
18273 Value::String(s) => {
18274 let re = Regex::new(r"(?:[.!?]\s+)?([A-Z][a-z]+(?:\s+[A-Z][a-z]+)*)").unwrap();
18276 let mut entities = std::collections::HashSet::new();
18277 for cap in re.captures_iter(s) {
18278 if let Some(m) = cap.get(1) {
18279 let entity = m.as_str().to_string();
18280 let starters = [
18282 "The", "A", "An", "This", "That", "It", "I", "We", "They", "He", "She",
18283 ];
18284 if !starters.contains(&entity.as_str()) {
18285 entities.insert(entity);
18286 }
18287 }
18288 }
18289 let results: Vec<Value> = entities
18290 .into_iter()
18291 .map(|e| Value::String(Rc::new(e)))
18292 .collect();
18293 Ok(Value::Array(Rc::new(RefCell::new(results))))
18294 }
18295 _ => Err(RuntimeError::new("extract_entities() requires string")),
18296 }
18297 });
18298
18299 define(interp, "text_hash_vector", Some(2), |_, args| {
18305 match (&args[0], &args[1]) {
18306 (Value::String(s), Value::Int(dims)) => {
18307 let dims = *dims as usize;
18308 let mut vector = vec![0.0f64; dims];
18309
18310 for word in s.to_lowercase().split_whitespace() {
18312 let hash = compute_hash(word, 0);
18313 let idx = (hash as usize) % dims;
18314 vector[idx] += 1.0;
18315 }
18316
18317 let magnitude: f64 = vector.iter().map(|x| x * x).sum::<f64>().sqrt();
18319 if magnitude > 0.0 {
18320 for v in vector.iter_mut() {
18321 *v /= magnitude;
18322 }
18323 }
18324
18325 let values: Vec<Value> = vector.into_iter().map(Value::Float).collect();
18326 Ok(Value::Array(Rc::new(RefCell::new(values))))
18327 }
18328 _ => Err(RuntimeError::new(
18329 "text_hash_vector() requires string and dimensions",
18330 )),
18331 }
18332 });
18333
18334 define(interp, "text_fingerprint", Some(1), |_, args| {
18336 match &args[0] {
18337 Value::String(s) => {
18338 let lower = s.to_lowercase();
18340 let words: Vec<&str> = lower.split_whitespace().collect();
18341
18342 let mut fp: u64 = 0;
18343 for (i, word) in words.iter().enumerate() {
18344 let h = compute_hash(word, i as u64);
18345 fp ^= h.rotate_left((i % 64) as u32);
18346 }
18347
18348 Ok(Value::String(Rc::new(format!("{:016x}", fp))))
18349 }
18350 _ => Err(RuntimeError::new("text_fingerprint() requires string")),
18351 }
18352 });
18353
18354 define(interp, "cosine_similarity", Some(2), |_, args| {
18356 match (&args[0], &args[1]) {
18357 (Value::Array(a), Value::Array(b)) => {
18358 let a_ref = a.borrow();
18359 let b_ref = b.borrow();
18360
18361 if a_ref.len() != b_ref.len() {
18362 return Err(RuntimeError::new("Vectors must have same length"));
18363 }
18364
18365 let mut dot = 0.0;
18366 let mut mag_a = 0.0;
18367 let mut mag_b = 0.0;
18368
18369 for (va, vb) in a_ref.iter().zip(b_ref.iter()) {
18370 let fa = match va {
18371 Value::Float(f) => *f,
18372 Value::Int(i) => *i as f64,
18373 _ => continue,
18374 };
18375 let fb = match vb {
18376 Value::Float(f) => *f,
18377 Value::Int(i) => *i as f64,
18378 _ => continue,
18379 };
18380 dot += fa * fb;
18381 mag_a += fa * fa;
18382 mag_b += fb * fb;
18383 }
18384
18385 let denom = (mag_a.sqrt()) * (mag_b.sqrt());
18386 if denom == 0.0 {
18387 Ok(Value::Float(0.0))
18388 } else {
18389 Ok(Value::Float(dot / denom))
18390 }
18391 }
18392 _ => Err(RuntimeError::new("cosine_similarity() requires two arrays")),
18393 }
18394 });
18395
18396 define(interp, "text_similarity_embedding", Some(2), |_, args| {
18398 match (&args[0], &args[1]) {
18399 (Value::String(a), Value::String(b)) => {
18400 let dims = 128;
18401
18402 let vec_a = create_hash_vector(a, dims);
18404 let vec_b = create_hash_vector(b, dims);
18405
18406 let mut dot = 0.0;
18408 let mut mag_a = 0.0;
18409 let mut mag_b = 0.0;
18410
18411 for i in 0..dims {
18412 dot += vec_a[i] * vec_b[i];
18413 mag_a += vec_a[i] * vec_a[i];
18414 mag_b += vec_b[i] * vec_b[i];
18415 }
18416
18417 let denom = (mag_a.sqrt()) * (mag_b.sqrt());
18418 if denom == 0.0 {
18419 Ok(Value::Float(0.0))
18420 } else {
18421 Ok(Value::Float(dot / denom))
18422 }
18423 }
18424 _ => Err(RuntimeError::new(
18425 "text_similarity_embedding() requires two strings",
18426 )),
18427 }
18428 });
18429
18430 define(
18436 interp,
18437 "flesch_reading_ease",
18438 Some(1),
18439 |_, args| match &args[0] {
18440 Value::String(s) => {
18441 let (words, sentences, syllables) = count_text_stats(s);
18442 if words == 0 || sentences == 0 {
18443 return Ok(Value::Float(0.0));
18444 }
18445 let score = 206.835
18446 - 1.015 * (words as f64 / sentences as f64)
18447 - 84.6 * (syllables as f64 / words as f64);
18448 Ok(Value::Float(score.max(0.0).min(100.0)))
18449 }
18450 _ => Err(RuntimeError::new("flesch_reading_ease() requires string")),
18451 },
18452 );
18453
18454 define(
18456 interp,
18457 "flesch_kincaid_grade",
18458 Some(1),
18459 |_, args| match &args[0] {
18460 Value::String(s) => {
18461 let (words, sentences, syllables) = count_text_stats(s);
18462 if words == 0 || sentences == 0 {
18463 return Ok(Value::Float(0.0));
18464 }
18465 let grade = 0.39 * (words as f64 / sentences as f64)
18466 + 11.8 * (syllables as f64 / words as f64)
18467 - 15.59;
18468 Ok(Value::Float(grade.max(0.0)))
18469 }
18470 _ => Err(RuntimeError::new("flesch_kincaid_grade() requires string")),
18471 },
18472 );
18473
18474 define(
18476 interp,
18477 "automated_readability_index",
18478 Some(1),
18479 |_, args| match &args[0] {
18480 Value::String(s) => {
18481 let chars: usize = s.chars().filter(|c| c.is_alphanumeric()).count();
18482 let words: usize = s.split_whitespace().count();
18483 let sentences: usize = s
18484 .matches(|c| c == '.' || c == '!' || c == '?')
18485 .count()
18486 .max(1);
18487
18488 if words == 0 {
18489 return Ok(Value::Float(0.0));
18490 }
18491
18492 let ari = 4.71 * (chars as f64 / words as f64)
18493 + 0.5 * (words as f64 / sentences as f64)
18494 - 21.43;
18495 Ok(Value::Float(ari.max(0.0)))
18496 }
18497 _ => Err(RuntimeError::new(
18498 "automated_readability_index() requires string",
18499 )),
18500 },
18501 );
18502
18503 define(interp, "reading_time", Some(1), |_, args| {
18505 match &args[0] {
18506 Value::String(s) => {
18507 let words = s.split_whitespace().count();
18508 let minutes = words as f64 / 200.0; Ok(Value::Float(minutes))
18510 }
18511 _ => Err(RuntimeError::new("reading_time() requires string")),
18512 }
18513 });
18514
18515 define(interp, "speaking_time", Some(1), |_, args| {
18517 match &args[0] {
18518 Value::String(s) => {
18519 let words = s.split_whitespace().count();
18520 let minutes = words as f64 / 150.0; Ok(Value::Float(minutes))
18522 }
18523 _ => Err(RuntimeError::new("speaking_time() requires string")),
18524 }
18525 });
18526}
18527
18528fn compute_vader_sentiment(s: &str) -> (f64, f64, f64, f64) {
18534 let positive_words: Vec<(&str, f64)> = vec![
18536 ("love", 3.0),
18537 ("loved", 3.0),
18538 ("loving", 3.0),
18539 ("excellent", 3.0),
18540 ("amazing", 3.0),
18541 ("fantastic", 3.0),
18542 ("wonderful", 3.0),
18543 ("great", 2.5),
18544 ("awesome", 2.5),
18545 ("brilliant", 2.5),
18546 ("superb", 2.5),
18547 ("good", 2.0),
18548 ("nice", 2.0),
18549 ("pleasant", 2.0),
18550 ("happy", 2.0),
18551 ("like", 1.5),
18552 ("enjoy", 1.5),
18553 ("fine", 1.5),
18554 ("okay", 1.0),
18555 ("best", 3.0),
18556 ("perfect", 3.0),
18557 ("beautiful", 2.5),
18558 ("delightful", 2.5),
18559 ("excited", 2.5),
18560 ("thrilled", 3.0),
18561 ("glad", 2.0),
18562 ("pleased", 2.0),
18563 ];
18564
18565 let negative_words: Vec<(&str, f64)> = vec![
18566 ("hate", 3.0),
18567 ("hated", 3.0),
18568 ("hating", 3.0),
18569 ("terrible", 3.0),
18570 ("horrible", 3.0),
18571 ("awful", 3.0),
18572 ("disgusting", 3.0),
18573 ("bad", 2.5),
18574 ("poor", 2.5),
18575 ("worst", 3.0),
18576 ("pathetic", 2.5),
18577 ("sad", 2.0),
18578 ("angry", 2.5),
18579 ("upset", 2.0),
18580 ("disappointed", 2.0),
18581 ("dislike", 1.5),
18582 ("annoying", 2.0),
18583 ("boring", 1.5),
18584 ("mediocre", 1.0),
18585 ("ugly", 2.5),
18586 ("stupid", 2.5),
18587 ("dumb", 2.0),
18588 ("useless", 2.5),
18589 ("painful", 2.5),
18590 ("miserable", 3.0),
18591 ("depressing", 2.5),
18592 ("frustrating", 2.0),
18593 ];
18594
18595 let boosters = vec![
18597 "very",
18598 "really",
18599 "extremely",
18600 "absolutely",
18601 "incredibly",
18602 "totally",
18603 "so",
18604 ];
18605 let dampeners = vec![
18606 "somewhat", "slightly", "a bit", "kind of", "sort of", "barely",
18607 ];
18608
18609 let lower = s.to_lowercase();
18610 let words: Vec<&str> = lower.split_whitespace().collect();
18611
18612 let mut pos_score = 0.0;
18613 let mut neg_score = 0.0;
18614 let mut word_count = 0;
18615
18616 for (i, word) in words.iter().enumerate() {
18617 let mut modifier = 1.0;
18618
18619 if i > 0 {
18621 if boosters.contains(&words[i - 1]) {
18622 modifier = 1.5;
18623 } else if dampeners.iter().any(|d| words[i - 1].contains(d)) {
18624 modifier = 0.5;
18625 }
18626 }
18627
18628 let negated = i > 0
18630 && [
18631 "not",
18632 "no",
18633 "never",
18634 "neither",
18635 "don't",
18636 "doesn't",
18637 "didn't",
18638 "won't",
18639 "wouldn't",
18640 "couldn't",
18641 "shouldn't",
18642 ]
18643 .contains(&words[i - 1]);
18644
18645 if let Some((_, score)) = positive_words.iter().find(|(w, _)| w == word) {
18646 if negated {
18647 neg_score += score * modifier;
18648 } else {
18649 pos_score += score * modifier;
18650 }
18651 word_count += 1;
18652 } else if let Some((_, score)) = negative_words.iter().find(|(w, _)| w == word) {
18653 if negated {
18654 pos_score += score * modifier * 0.5; } else {
18656 neg_score += score * modifier;
18657 }
18658 word_count += 1;
18659 }
18660 }
18661
18662 let total = pos_score + neg_score;
18664 let (pos_norm, neg_norm) = if total > 0.0 {
18665 (pos_score / total, neg_score / total)
18666 } else {
18667 (0.0, 0.0)
18668 };
18669
18670 let neutral = 1.0 - pos_norm - neg_norm;
18671
18672 let compound = if word_count > 0 {
18674 ((pos_score - neg_score) / (word_count as f64 * 3.0))
18675 .max(-1.0)
18676 .min(1.0)
18677 } else {
18678 0.0
18679 };
18680
18681 (pos_norm, neg_norm, neutral.max(0.0), compound)
18682}
18683
18684fn compute_emotions(s: &str) -> HashMap<String, f64> {
18686 let emotion_words: Vec<(&str, &str)> = vec![
18687 ("happy", "joy"),
18689 ("joyful", "joy"),
18690 ("delighted", "joy"),
18691 ("cheerful", "joy"),
18692 ("excited", "joy"),
18693 ("thrilled", "joy"),
18694 ("ecstatic", "joy"),
18695 ("elated", "joy"),
18696 ("sad", "sadness"),
18698 ("unhappy", "sadness"),
18699 ("depressed", "sadness"),
18700 ("miserable", "sadness"),
18701 ("gloomy", "sadness"),
18702 ("heartbroken", "sadness"),
18703 ("sorrowful", "sadness"),
18704 ("melancholy", "sadness"),
18705 ("angry", "anger"),
18707 ("furious", "anger"),
18708 ("enraged", "anger"),
18709 ("irritated", "anger"),
18710 ("annoyed", "anger"),
18711 ("outraged", "anger"),
18712 ("livid", "anger"),
18713 ("mad", "anger"),
18714 ("afraid", "fear"),
18716 ("scared", "fear"),
18717 ("terrified", "fear"),
18718 ("frightened", "fear"),
18719 ("anxious", "fear"),
18720 ("worried", "fear"),
18721 ("nervous", "fear"),
18722 ("panicked", "fear"),
18723 ("surprised", "surprise"),
18725 ("amazed", "surprise"),
18726 ("astonished", "surprise"),
18727 ("shocked", "surprise"),
18728 ("stunned", "surprise"),
18729 ("startled", "surprise"),
18730 ("bewildered", "surprise"),
18731 ("disgusted", "disgust"),
18733 ("revolted", "disgust"),
18734 ("repulsed", "disgust"),
18735 ("sickened", "disgust"),
18736 ("nauseated", "disgust"),
18737 ("appalled", "disgust"),
18738 ("trust", "trust"),
18740 ("confident", "trust"),
18741 ("secure", "trust"),
18742 ("reliable", "trust"),
18743 ("faithful", "trust"),
18744 ("loyal", "trust"),
18745 ("eager", "anticipation"),
18747 ("hopeful", "anticipation"),
18748 ("expectant", "anticipation"),
18749 ("looking forward", "anticipation"),
18750 ("excited", "anticipation"),
18751 ];
18752
18753 let lower = s.to_lowercase();
18754 let mut counts: HashMap<String, f64> = HashMap::new();
18755
18756 for (word, emotion) in emotion_words {
18757 if lower.contains(word) {
18758 *counts.entry(emotion.to_string()).or_insert(0.0) += 1.0;
18759 }
18760 }
18761
18762 let total: f64 = counts.values().sum();
18764 if total > 0.0 {
18765 for v in counts.values_mut() {
18766 *v /= total;
18767 }
18768 }
18769
18770 counts
18771}
18772
18773fn compute_intensity(s: &str) -> f64 {
18775 let intensifiers = vec![
18776 ("very", 1.5),
18777 ("really", 1.5),
18778 ("extremely", 2.0),
18779 ("incredibly", 2.0),
18780 ("absolutely", 2.0),
18781 ("totally", 1.5),
18782 ("completely", 1.5),
18783 ("utterly", 2.0),
18784 ("so", 1.3),
18785 ("such", 1.3),
18786 ("quite", 1.2),
18787 ("rather", 1.1),
18788 ];
18789
18790 let exclamation_boost = 0.5;
18791 let caps_boost = 0.3;
18792
18793 let lower = s.to_lowercase();
18794 let mut score = 1.0;
18795
18796 for (word, boost) in intensifiers {
18797 if lower.contains(word) {
18798 score *= boost;
18799 }
18800 }
18801
18802 let exclamations = s.matches('!').count();
18804 score += exclamations as f64 * exclamation_boost;
18805
18806 let caps_words = s
18808 .split_whitespace()
18809 .filter(|w| w.len() > 2 && w.chars().all(|c| c.is_uppercase()))
18810 .count();
18811 score += caps_words as f64 * caps_boost;
18812
18813 score.min(5.0)
18814}
18815
18816fn compute_sarcasm_score(s: &str) -> (f64, f64, Vec<String>) {
18818 let mut markers = Vec::new();
18819 let mut score: f64 = 0.0;
18820
18821 let lower = s.to_lowercase();
18822
18823 let explicit = vec![
18825 "/s",
18826 "not!",
18827 "yeah right",
18828 "sure thing",
18829 "oh really",
18830 "oh great",
18831 "wow, just wow",
18832 "thanks a lot",
18833 "how wonderful",
18834 "isn't that special",
18835 "clearly",
18836 "obviously",
18837 "shocking",
18838 "no way",
18839 "what a surprise",
18840 ];
18841
18842 for marker in &explicit {
18843 if lower.contains(marker) {
18844 markers.push(format!("explicit: {}", marker));
18845 score += 0.4;
18846 }
18847 }
18848
18849 let hyperbolic = vec![
18851 "best thing ever",
18852 "worst thing ever",
18853 "literally dying",
18854 "absolutely perfect",
18855 "world's greatest",
18856 "totally awesome",
18857 "so much fun",
18858 "couldn't be happier",
18859 ];
18860
18861 for h in &hyperbolic {
18862 if lower.contains(h) {
18863 markers.push(format!("hyperbole: {}", h));
18864 score += 0.3;
18865 }
18866 }
18867
18868 let has_positive = ["great", "wonderful", "amazing", "love", "best", "awesome"]
18870 .iter()
18871 .any(|w| lower.contains(w));
18872 let has_negative_context = ["but", "however", "although", "except", "unfortunately"]
18873 .iter()
18874 .any(|w| lower.contains(w));
18875
18876 if has_positive && has_negative_context {
18877 markers.push("positive-negative contrast".to_string());
18878 score += 0.25;
18879 }
18880
18881 let quote_pattern = Regex::new(r#"["'](\w+)["']"#).unwrap();
18883 for cap in quote_pattern.captures_iter(s) {
18884 if let Some(m) = cap.get(1) {
18885 let word = m.as_str().to_lowercase();
18886 if [
18887 "great",
18888 "wonderful",
18889 "helpful",
18890 "useful",
18891 "smart",
18892 "genius",
18893 "brilliant",
18894 ]
18895 .contains(&word.as_str())
18896 {
18897 markers.push(format!("air quotes: \"{}\"", word));
18898 score += 0.35;
18899 }
18900 }
18901 }
18902
18903 if s.contains("...") || s.contains("!!!") || s.contains("???") {
18905 markers.push("excessive punctuation".to_string());
18906 score += 0.15;
18907 }
18908
18909 let confidence = if markers.is_empty() {
18911 0.0
18912 } else {
18913 (markers.len() as f64 * 0.25).min(1.0)
18914 };
18915
18916 (score.min(1.0), confidence, markers)
18917}
18918
18919fn compute_irony_score(s: &str) -> f64 {
18921 let mut score: f64 = 0.0;
18922 let lower = s.to_lowercase();
18923
18924 let irony_phrases = vec![
18926 "of course",
18927 "as expected",
18928 "naturally",
18929 "predictably",
18930 "who would have thought",
18931 "surprise surprise",
18932 "go figure",
18933 "typical",
18934 "as usual",
18935 "yet again",
18936 "once again",
18937 ];
18938
18939 for phrase in irony_phrases {
18940 if lower.contains(phrase) {
18941 score += 0.2;
18942 }
18943 }
18944
18945 if lower.contains("but") || lower.contains("yet") || lower.contains("however") {
18947 score += 0.1;
18948 }
18949
18950 if s.contains('?')
18952 && (lower.starts_with("isn't")
18953 || lower.starts_with("aren't")
18954 || lower.starts_with("doesn't")
18955 || lower.starts_with("don't")
18956 || lower.contains("right?")
18957 || lower.contains("isn't it"))
18958 {
18959 score += 0.25;
18960 }
18961
18962 score.min(1.0)
18963}
18964
18965fn create_hash_vector(s: &str, dims: usize) -> Vec<f64> {
18967 let mut vector = vec![0.0f64; dims];
18968
18969 for word in s.to_lowercase().split_whitespace() {
18970 let hash = compute_hash(word, 0);
18971 let idx = (hash as usize) % dims;
18972 vector[idx] += 1.0;
18973 }
18974
18975 let magnitude: f64 = vector.iter().map(|x| x * x).sum::<f64>().sqrt();
18977 if magnitude > 0.0 {
18978 for v in vector.iter_mut() {
18979 *v /= magnitude;
18980 }
18981 }
18982
18983 vector
18984}
18985
18986fn count_text_stats(s: &str) -> (usize, usize, usize) {
18988 let words: Vec<&str> = s.split_whitespace().collect();
18989 let word_count = words.len();
18990 let sentence_count = s
18991 .matches(|c| c == '.' || c == '!' || c == '?')
18992 .count()
18993 .max(1);
18994
18995 let mut syllable_count = 0;
18996 for word in &words {
18997 syllable_count += count_syllables(word);
18998 }
18999
19000 (word_count, sentence_count, syllable_count)
19001}
19002
19003fn count_syllables(word: &str) -> usize {
19005 let word = word.to_lowercase();
19006 let vowels = ['a', 'e', 'i', 'o', 'u', 'y'];
19007 let mut count = 0;
19008 let mut prev_was_vowel = false;
19009
19010 for c in word.chars() {
19011 let is_vowel = vowels.contains(&c);
19012 if is_vowel && !prev_was_vowel {
19013 count += 1;
19014 }
19015 prev_was_vowel = is_vowel;
19016 }
19017
19018 if word.ends_with('e') && count > 1 {
19020 count -= 1;
19021 }
19022
19023 count.max(1)
19024}
19025
19026fn compute_soundex(s: &str) -> String {
19028 if s.is_empty() {
19029 return "0000".to_string();
19030 }
19031
19032 let s = s.to_uppercase();
19033 let chars: Vec<char> = s.chars().filter(|c| c.is_ascii_alphabetic()).collect();
19034
19035 if chars.is_empty() {
19036 return "0000".to_string();
19037 }
19038
19039 let first = chars[0];
19040 let mut code = String::new();
19041 code.push(first);
19042
19043 let get_code = |c: char| -> char {
19044 match c {
19045 'B' | 'F' | 'P' | 'V' => '1',
19046 'C' | 'G' | 'J' | 'K' | 'Q' | 'S' | 'X' | 'Z' => '2',
19047 'D' | 'T' => '3',
19048 'L' => '4',
19049 'M' | 'N' => '5',
19050 'R' => '6',
19051 _ => '0',
19052 }
19053 };
19054
19055 let mut prev_code = get_code(first);
19056
19057 for &c in chars.iter().skip(1) {
19058 let curr_code = get_code(c);
19059 if curr_code != '0' && curr_code != prev_code {
19060 code.push(curr_code);
19061 if code.len() == 4 {
19062 break;
19063 }
19064 }
19065 prev_code = curr_code;
19066 }
19067
19068 while code.len() < 4 {
19069 code.push('0');
19070 }
19071
19072 code
19073}
19074
19075fn compute_metaphone(s: &str) -> String {
19077 let s = s.to_uppercase();
19078 let chars: Vec<char> = s.chars().filter(|c| c.is_ascii_alphabetic()).collect();
19079
19080 if chars.is_empty() {
19081 return String::new();
19082 }
19083
19084 let mut result = String::new();
19085 let mut i = 0;
19086
19087 if chars.len() >= 2 {
19089 let prefix: String = chars[0..2].iter().collect();
19090 if ["KN", "GN", "PN", "AE", "WR"].contains(&prefix.as_str()) {
19091 i = 1;
19092 }
19093 }
19094
19095 while i < chars.len() && result.len() < 6 {
19096 let c = chars[i];
19097 let prev = if i > 0 { Some(chars[i - 1]) } else { None };
19098 let next = chars.get(i + 1).copied();
19099
19100 let code = match c {
19101 'A' | 'E' | 'I' | 'O' | 'U' => {
19102 if i == 0 {
19103 Some(c)
19104 } else {
19105 None
19106 }
19107 }
19108 'B' => {
19109 if prev != Some('M') || i == chars.len() - 1 {
19110 Some('B')
19111 } else {
19112 None
19113 }
19114 }
19115 'C' => {
19116 if next == Some('H') {
19117 Some('X')
19118 } else if matches!(next, Some('I') | Some('E') | Some('Y')) {
19119 Some('S')
19120 } else {
19121 Some('K')
19122 }
19123 }
19124 'D' => {
19125 if next == Some('G')
19126 && matches!(chars.get(i + 2), Some('E') | Some('I') | Some('Y'))
19127 {
19128 Some('J')
19129 } else {
19130 Some('T')
19131 }
19132 }
19133 'F' => Some('F'),
19134 'G' => {
19135 if next == Some('H')
19136 && !matches!(
19137 chars.get(i + 2),
19138 Some('A') | Some('E') | Some('I') | Some('O') | Some('U')
19139 )
19140 {
19141 None
19142 } else if matches!(next, Some('N') | Some('E') | Some('I') | Some('Y')) {
19143 Some('J')
19144 } else {
19145 Some('K')
19146 }
19147 }
19148 'H' => {
19149 if matches!(
19150 prev,
19151 Some('A') | Some('E') | Some('I') | Some('O') | Some('U')
19152 ) {
19153 None
19154 } else if matches!(
19155 next,
19156 Some('A') | Some('E') | Some('I') | Some('O') | Some('U')
19157 ) {
19158 Some('H')
19159 } else {
19160 None
19161 }
19162 }
19163 'J' => Some('J'),
19164 'K' => {
19165 if prev != Some('C') {
19166 Some('K')
19167 } else {
19168 None
19169 }
19170 }
19171 'L' => Some('L'),
19172 'M' => Some('M'),
19173 'N' => Some('N'),
19174 'P' => {
19175 if next == Some('H') {
19176 Some('F')
19177 } else {
19178 Some('P')
19179 }
19180 }
19181 'Q' => Some('K'),
19182 'R' => Some('R'),
19183 'S' => {
19184 if next == Some('H') {
19185 Some('X')
19186 } else {
19187 Some('S')
19188 }
19189 }
19190 'T' => {
19191 if next == Some('H') {
19192 Some('0') } else if next == Some('I') && matches!(chars.get(i + 2), Some('O') | Some('A')) {
19194 Some('X')
19195 } else {
19196 Some('T')
19197 }
19198 }
19199 'V' => Some('F'),
19200 'W' | 'Y' => {
19201 if matches!(
19202 next,
19203 Some('A') | Some('E') | Some('I') | Some('O') | Some('U')
19204 ) {
19205 Some(c)
19206 } else {
19207 None
19208 }
19209 }
19210 'X' => {
19211 result.push('K');
19212 Some('S')
19213 }
19214 'Z' => Some('S'),
19215 _ => None,
19216 };
19217
19218 if let Some(ch) = code {
19219 result.push(ch);
19220 }
19221
19222 if next == Some(c) {
19224 i += 1;
19225 }
19226 i += 1;
19227 }
19228
19229 result
19230}
19231
19232fn compute_cologne(s: &str) -> String {
19234 let s = s.to_uppercase();
19235 let chars: Vec<char> = s.chars().filter(|c| c.is_ascii_alphabetic()).collect();
19236
19237 if chars.is_empty() {
19238 return String::new();
19239 }
19240
19241 let mut result = String::new();
19242
19243 for (i, &c) in chars.iter().enumerate() {
19244 let prev = if i > 0 { Some(chars[i - 1]) } else { None };
19245 let next = chars.get(i + 1).copied();
19246
19247 let code = match c {
19248 'A' | 'E' | 'I' | 'O' | 'U' | 'J' | 'Y' => '0',
19249 'H' => continue,
19250 'B' | 'P' => '1',
19251 'D' | 'T' => {
19252 if matches!(next, Some('C') | Some('S') | Some('Z')) {
19253 '8'
19254 } else {
19255 '2'
19256 }
19257 }
19258 'F' | 'V' | 'W' => '3',
19259 'G' | 'K' | 'Q' => '4',
19260 'C' => {
19261 if i == 0 {
19262 if matches!(
19263 next,
19264 Some('A')
19265 | Some('H')
19266 | Some('K')
19267 | Some('L')
19268 | Some('O')
19269 | Some('Q')
19270 | Some('R')
19271 | Some('U')
19272 | Some('X')
19273 ) {
19274 '4'
19275 } else {
19276 '8'
19277 }
19278 } else if matches!(prev, Some('S') | Some('Z')) {
19279 '8'
19280 } else if matches!(
19281 next,
19282 Some('A')
19283 | Some('H')
19284 | Some('K')
19285 | Some('O')
19286 | Some('Q')
19287 | Some('U')
19288 | Some('X')
19289 ) {
19290 '4'
19291 } else {
19292 '8'
19293 }
19294 }
19295 'X' => {
19296 if matches!(prev, Some('C') | Some('K') | Some('Q')) {
19297 '8'
19298 } else {
19299 result.push('4');
19300 '8'
19301 }
19302 }
19303 'L' => '5',
19304 'M' | 'N' => '6',
19305 'R' => '7',
19306 'S' | 'Z' => '8',
19307 _ => continue,
19308 };
19309
19310 result.push(code);
19311 }
19312
19313 let mut deduped = String::new();
19315 let mut prev = None;
19316 for c in result.chars() {
19317 if prev != Some(c) {
19318 deduped.push(c);
19319 }
19320 prev = Some(c);
19321 }
19322
19323 let trimmed: String = deduped.trim_start_matches('0').to_string();
19325 if trimmed.is_empty() {
19326 "0".to_string()
19327 } else {
19328 trimmed
19329 }
19330}
19331
19332fn get_stopwords(lang: &str) -> Vec<&'static str> {
19334 match lang {
19335 "en" | "english" => vec![
19336 "a", "an", "the", "and", "or", "but", "in", "on", "at", "to", "for", "of", "with",
19337 "by", "from", "as", "is", "was", "are", "were", "been", "be", "have", "has", "had",
19338 "do", "does", "did", "will", "would", "could", "should", "may", "might", "must",
19339 "shall", "can", "need", "it", "its", "this", "that", "these", "those", "i", "you",
19340 "he", "she", "we", "they", "me", "him", "her", "us", "them", "my", "your", "his",
19341 "her", "our", "their", "what", "which", "who", "whom", "whose", "when", "where", "why",
19342 "how", "all", "each", "every", "both", "few", "more", "most", "other", "some", "such",
19343 "no", "nor", "not", "only", "own", "same", "so", "than", "too", "very", "just", "also",
19344 "now",
19345 ],
19346 "de" | "german" => vec![
19347 "der", "die", "das", "den", "dem", "des", "ein", "eine", "einer", "einem", "einen",
19348 "und", "oder", "aber", "in", "auf", "an", "zu", "für", "von", "mit", "bei", "als",
19349 "ist", "war", "sind", "waren", "sein", "haben", "hat", "hatte", "werden", "wird",
19350 "wurde", "kann", "können", "muss", "müssen", "soll", "sollen", "will", "wollen", "es",
19351 "sie", "er", "wir", "ihr", "ich", "du", "man", "sich", "nicht", "auch", "nur", "noch",
19352 "schon", "mehr", "sehr", "so",
19353 ],
19354 "fr" | "french" => vec![
19355 "le", "la", "les", "un", "une", "des", "et", "ou", "mais", "dans", "sur", "à", "de",
19356 "pour", "par", "avec", "ce", "cette", "ces", "est", "sont", "était", "être", "avoir",
19357 "a", "ont", "avait", "je", "tu", "il", "elle", "nous", "vous", "ils", "elles", "on",
19358 "ne", "pas", "plus", "moins", "très", "aussi", "que", "qui",
19359 ],
19360 "es" | "spanish" => vec![
19361 "el", "la", "los", "las", "un", "una", "unos", "unas", "y", "o", "pero", "en", "de",
19362 "a", "para", "por", "con", "es", "son", "era", "ser", "estar", "tiene", "tienen", "yo",
19363 "tú", "él", "ella", "nosotros", "ustedes", "ellos", "ellas", "no", "sí", "muy", "más",
19364 "menos", "también", "que", "quien", "cual", "como", "cuando",
19365 ],
19366 "it" | "italian" => vec![
19367 "il", "lo", "la", "i", "gli", "le", "un", "uno", "una", "e", "o", "ma", "in", "di",
19368 "a", "da", "per", "con", "su", "tra", "fra", "è", "sono", "era", "erano", "essere",
19369 "avere", "ha", "hanno", "io", "tu", "lui", "lei", "noi", "voi", "loro", "mi", "ti",
19370 "ci", "non", "più", "molto", "anche", "come", "che", "chi", "quale", "questo",
19371 "quello", "quando", "dove", "perché", "se", "però",
19372 ],
19373 "pt" | "portuguese" => vec![
19374 "o", "a", "os", "as", "um", "uma", "uns", "umas", "e", "ou", "mas", "em", "de", "para",
19375 "por", "com", "sem", "sob", "sobre", "é", "são", "era", "eram", "ser", "estar", "ter",
19376 "tem", "têm", "eu", "tu", "ele", "ela", "nós", "vós", "eles", "elas", "me", "te",
19377 "não", "mais", "muito", "também", "como", "que", "quem", "qual", "este", "esse",
19378 "aquele", "quando", "onde", "porque", "se", "já",
19379 ],
19380 "nl" | "dutch" => vec![
19381 "de", "het", "een", "en", "of", "maar", "in", "op", "aan", "van", "voor", "met", "bij",
19382 "naar", "om", "te", "tot", "uit", "over", "is", "zijn", "was", "waren", "worden",
19383 "wordt", "werd", "hebben", "ik", "je", "jij", "hij", "zij", "wij", "jullie", "ze",
19384 "mij", "jou", "niet", "geen", "meer", "ook", "als", "dat", "die", "wat", "wie", "dit",
19385 "deze", "wanneer", "waar", "waarom", "hoe", "dan", "nog",
19386 ],
19387 "ru" | "russian" => vec![
19388 "и",
19389 "в",
19390 "на",
19391 "с",
19392 "к",
19393 "по",
19394 "за",
19395 "из",
19396 "у",
19397 "о",
19398 "от",
19399 "до",
19400 "для",
19401 "при",
19402 "без",
19403 "под",
19404 "над",
19405 "между",
19406 "через",
19407 "после",
19408 "это",
19409 "то",
19410 "что",
19411 "как",
19412 "так",
19413 "но",
19414 "а",
19415 "или",
19416 "если",
19417 "же",
19418 "я",
19419 "ты",
19420 "он",
19421 "она",
19422 "мы",
19423 "вы",
19424 "они",
19425 "его",
19426 "её",
19427 "их",
19428 "не",
19429 "ни",
19430 "да",
19431 "нет",
19432 "был",
19433 "была",
19434 "были",
19435 "быть",
19436 "есть",
19437 "все",
19438 "всё",
19439 "весь",
19440 "этот",
19441 "тот",
19442 "который",
19443 "когда",
19444 "где",
19445 ],
19446 "ar" | "arabic" => vec![
19447 "في",
19448 "من",
19449 "إلى",
19450 "على",
19451 "عن",
19452 "مع",
19453 "هذا",
19454 "هذه",
19455 "ذلك",
19456 "تلك",
19457 "التي",
19458 "الذي",
19459 "اللذان",
19460 "اللتان",
19461 "الذين",
19462 "اللاتي",
19463 "اللواتي",
19464 "هو",
19465 "هي",
19466 "هم",
19467 "هن",
19468 "أنا",
19469 "أنت",
19470 "نحن",
19471 "أنتم",
19472 "أنتن",
19473 "كان",
19474 "كانت",
19475 "كانوا",
19476 "يكون",
19477 "تكون",
19478 "ليس",
19479 "ليست",
19480 "ليسوا",
19481 "و",
19482 "أو",
19483 "ثم",
19484 "لكن",
19485 "بل",
19486 "إن",
19487 "أن",
19488 "لأن",
19489 "كي",
19490 "حتى",
19491 "ما",
19492 "لا",
19493 "قد",
19494 "كل",
19495 "بعض",
19496 "غير",
19497 "أي",
19498 "كيف",
19499 "متى",
19500 "أين",
19501 ],
19502 "zh" | "chinese" => vec![
19503 "的", "了", "是", "在", "有", "和", "与", "或", "但", "而", "我", "你", "他", "她",
19504 "它", "我们", "你们", "他们", "她们", "这", "那", "这个", "那个", "这些", "那些",
19505 "什么", "哪", "哪个", "不", "没", "没有", "很", "也", "都", "就", "才", "只", "还",
19506 "把", "被", "给", "从", "到", "为", "以", "因为", "所以", "如果", "会", "能", "可以",
19507 "要", "想", "应该", "必须", "可能", "一", "个",
19508 ],
19509 "ja" | "japanese" => vec![
19510 "の",
19511 "に",
19512 "は",
19513 "を",
19514 "た",
19515 "が",
19516 "で",
19517 "て",
19518 "と",
19519 "し",
19520 "れ",
19521 "さ",
19522 "ある",
19523 "いる",
19524 "も",
19525 "する",
19526 "から",
19527 "な",
19528 "こと",
19529 "として",
19530 "い",
19531 "や",
19532 "など",
19533 "なっ",
19534 "ない",
19535 "この",
19536 "ため",
19537 "その",
19538 "あっ",
19539 "よう",
19540 "また",
19541 "もの",
19542 "という",
19543 "あり",
19544 "まで",
19545 "られ",
19546 "なる",
19547 "へ",
19548 "か",
19549 "だ",
19550 "これ",
19551 "によって",
19552 "により",
19553 "おり",
19554 "より",
19555 "による",
19556 "ず",
19557 "なり",
19558 "られる",
19559 "において",
19560 ],
19561 "ko" | "korean" => vec![
19562 "이",
19563 "그",
19564 "저",
19565 "것",
19566 "수",
19567 "등",
19568 "들",
19569 "및",
19570 "에",
19571 "의",
19572 "가",
19573 "을",
19574 "를",
19575 "은",
19576 "는",
19577 "로",
19578 "으로",
19579 "와",
19580 "과",
19581 "도",
19582 "에서",
19583 "까지",
19584 "부터",
19585 "만",
19586 "뿐",
19587 "처럼",
19588 "같이",
19589 "보다",
19590 "하다",
19591 "있다",
19592 "되다",
19593 "없다",
19594 "않다",
19595 "이다",
19596 "아니다",
19597 "나",
19598 "너",
19599 "우리",
19600 "그들",
19601 "이것",
19602 "그것",
19603 "저것",
19604 "무엇",
19605 "어디",
19606 "언제",
19607 "왜",
19608 "어떻게",
19609 "누구",
19610 "어느",
19611 "모든",
19612 "각",
19613 ],
19614 "hi" | "hindi" => vec![
19615 "का",
19616 "के",
19617 "की",
19618 "में",
19619 "है",
19620 "हैं",
19621 "को",
19622 "से",
19623 "पर",
19624 "था",
19625 "थे",
19626 "थी",
19627 "और",
19628 "या",
19629 "लेकिन",
19630 "अगर",
19631 "तो",
19632 "भी",
19633 "ही",
19634 "यह",
19635 "वह",
19636 "इस",
19637 "उस",
19638 "ये",
19639 "वे",
19640 "जो",
19641 "कि",
19642 "क्या",
19643 "कैसे",
19644 "मैं",
19645 "तुम",
19646 "आप",
19647 "हम",
19648 "वे",
19649 "उन्हें",
19650 "उनके",
19651 "अपने",
19652 "नहीं",
19653 "न",
19654 "कुछ",
19655 "कोई",
19656 "सब",
19657 "बहुत",
19658 "कम",
19659 "ज्यादा",
19660 "होना",
19661 "करना",
19662 "जाना",
19663 "आना",
19664 "देना",
19665 "लेना",
19666 "रहना",
19667 "सकना",
19668 ],
19669 "tr" | "turkish" => vec![
19670 "bir",
19671 "ve",
19672 "bu",
19673 "da",
19674 "de",
19675 "için",
19676 "ile",
19677 "mi",
19678 "ne",
19679 "o",
19680 "var",
19681 "ben",
19682 "sen",
19683 "biz",
19684 "siz",
19685 "onlar",
19686 "ki",
19687 "ama",
19688 "çok",
19689 "daha",
19690 "gibi",
19691 "kadar",
19692 "sonra",
19693 "şey",
19694 "kendi",
19695 "bütün",
19696 "her",
19697 "bazı",
19698 "olan",
19699 "olarak",
19700 "değil",
19701 "ya",
19702 "hem",
19703 "veya",
19704 "ancak",
19705 "ise",
19706 "göre",
19707 "rağmen",
19708 "dolayı",
19709 "üzere",
19710 "karşı",
19711 "arasında",
19712 "olan",
19713 "oldu",
19714 "olur",
19715 "olmak",
19716 "etmek",
19717 "yapmak",
19718 "demek",
19719 ],
19720 "pl" | "polish" => vec![
19721 "i",
19722 "w",
19723 "z",
19724 "na",
19725 "do",
19726 "o",
19727 "że",
19728 "to",
19729 "nie",
19730 "się",
19731 "jest",
19732 "tak",
19733 "jak",
19734 "ale",
19735 "po",
19736 "co",
19737 "czy",
19738 "lub",
19739 "oraz",
19740 "ja",
19741 "ty",
19742 "on",
19743 "ona",
19744 "my",
19745 "wy",
19746 "oni",
19747 "one",
19748 "pan",
19749 "pani",
19750 "ten",
19751 "ta",
19752 "te",
19753 "tego",
19754 "tej",
19755 "tym",
19756 "tych",
19757 "który",
19758 "która",
19759 "być",
19760 "mieć",
19761 "móc",
19762 "musieć",
19763 "chcieć",
19764 "wiedzieć",
19765 "mówić",
19766 "bardzo",
19767 "tylko",
19768 "już",
19769 "jeszcze",
19770 "też",
19771 "więc",
19772 "jednak",
19773 ],
19774 "sv" | "swedish" => vec![
19775 "och", "i", "att", "det", "som", "en", "på", "är", "av", "för", "med", "till", "den",
19776 "har", "de", "inte", "om", "ett", "men", "jag", "du", "han", "hon", "vi", "ni", "de",
19777 "dem", "sig", "sin", "var", "från", "eller", "när", "kan", "ska", "så", "än", "nu",
19778 "också", "bara", "mycket", "mer", "andra", "detta", "sedan", "hade", "varit", "skulle",
19779 "vara", "bli", "blev", "blir", "göra",
19780 ],
19781 _ => vec![
19782 "a", "an", "the", "and", "or", "but", "in", "on", "at", "to", "for",
19783 ],
19784 }
19785}
19786
19787fn compute_hash(s: &str, seed: u64) -> u64 {
19789 let mut hash: u64 = seed.wrapping_mul(0x517cc1b727220a95);
19790 for b in s.bytes() {
19791 hash = hash.wrapping_mul(31).wrapping_add(b as u64);
19792 }
19793 hash
19794}
19795
19796fn register_hologram(interp: &mut Interpreter) {
19816 use crate::interpreter::{
19817 RuntimeAffect, RuntimeConfidence, RuntimeEmotion, RuntimeFormality, RuntimeIntensity,
19818 RuntimeSentiment,
19819 };
19820
19821 define(interp, "emotional_hologram", Some(1), |_, args| {
19824 let affect = match &args[0] {
19825 Value::Affective { affect, .. } => affect.clone(),
19826 _ => RuntimeAffect {
19827 sentiment: None,
19828 sarcasm: false,
19829 intensity: None,
19830 formality: None,
19831 emotion: None,
19832 confidence: None,
19833 },
19834 };
19835
19836 let mut hologram = std::collections::HashMap::new();
19837
19838 let valence = match affect.sentiment {
19840 Some(RuntimeSentiment::Positive) => 1.0,
19841 Some(RuntimeSentiment::Negative) => -1.0,
19842 Some(RuntimeSentiment::Neutral) | None => 0.0,
19843 };
19844 hologram.insert("valence".to_string(), Value::Float(valence));
19845
19846 let arousal = match affect.intensity {
19848 Some(RuntimeIntensity::Down) => 0.25,
19849 None => 0.5,
19850 Some(RuntimeIntensity::Up) => 0.75,
19851 Some(RuntimeIntensity::Max) => 1.0,
19852 };
19853 hologram.insert("arousal".to_string(), Value::Float(arousal));
19854
19855 let dominance = match affect.formality {
19857 Some(RuntimeFormality::Informal) => 0.25,
19858 None => 0.5,
19859 Some(RuntimeFormality::Formal) => 0.85,
19860 };
19861 hologram.insert("dominance".to_string(), Value::Float(dominance));
19862
19863 let authenticity = if affect.sarcasm { -0.9 } else { 0.9 };
19865 hologram.insert("authenticity".to_string(), Value::Float(authenticity));
19866
19867 let certainty = match affect.confidence {
19869 Some(RuntimeConfidence::Low) => 0.2,
19870 None | Some(RuntimeConfidence::Medium) => 0.5,
19871 Some(RuntimeConfidence::High) => 0.9,
19872 };
19873 hologram.insert("certainty".to_string(), Value::Float(certainty));
19874
19875 let emotion_index = match affect.emotion {
19877 Some(RuntimeEmotion::Joy) => 0,
19878 Some(RuntimeEmotion::Sadness) => 1,
19879 Some(RuntimeEmotion::Anger) => 2,
19880 Some(RuntimeEmotion::Fear) => 3,
19881 Some(RuntimeEmotion::Surprise) => 4,
19882 Some(RuntimeEmotion::Love) => 5,
19883 None => -1,
19884 };
19885 hologram.insert("emotion_index".to_string(), Value::Int(emotion_index));
19886
19887 let emotion_name = match affect.emotion {
19889 Some(RuntimeEmotion::Joy) => "joy",
19890 Some(RuntimeEmotion::Sadness) => "sadness",
19891 Some(RuntimeEmotion::Anger) => "anger",
19892 Some(RuntimeEmotion::Fear) => "fear",
19893 Some(RuntimeEmotion::Surprise) => "surprise",
19894 Some(RuntimeEmotion::Love) => "love",
19895 None => "none",
19896 };
19897 hologram.insert(
19898 "emotion".to_string(),
19899 Value::String(Rc::new(emotion_name.to_string())),
19900 );
19901
19902 Ok(Value::Map(Rc::new(RefCell::new(hologram))))
19903 });
19904
19905 define(interp, "emotional_distance", Some(2), |interp, args| {
19907 let h1 = get_hologram_values(&args[0], interp)?;
19909 let h2 = get_hologram_values(&args[1], interp)?;
19910
19911 let dist = ((h1.0 - h2.0).powi(2) + (h1.1 - h2.1).powi(2) + (h1.2 - h2.2).powi(2) + (h1.3 - h2.3).powi(2) + (h1.4 - h2.4).powi(2)) .sqrt();
19918
19919 Ok(Value::Float(dist))
19920 });
19921
19922 define(interp, "emotional_similarity", Some(2), |interp, args| {
19924 let h1 = get_hologram_values(&args[0], interp)?;
19925 let h2 = get_hologram_values(&args[1], interp)?;
19926
19927 let dot = h1.0 * h2.0 + h1.1 * h2.1 + h1.2 * h2.2 + h1.3 * h2.3 + h1.4 * h2.4;
19928 let mag1 =
19929 (h1.0.powi(2) + h1.1.powi(2) + h1.2.powi(2) + h1.3.powi(2) + h1.4.powi(2)).sqrt();
19930 let mag2 =
19931 (h2.0.powi(2) + h2.1.powi(2) + h2.2.powi(2) + h2.3.powi(2) + h2.4.powi(2)).sqrt();
19932
19933 let similarity = if mag1 > 0.0 && mag2 > 0.0 {
19934 (dot / (mag1 * mag2) + 1.0) / 2.0 } else {
19936 0.5
19937 };
19938
19939 Ok(Value::Float(similarity))
19940 });
19941
19942 define(interp, "emotional_dissonance", Some(1), |_, args| {
19945 let affect = match &args[0] {
19946 Value::Affective { affect, .. } => affect.clone(),
19947 _ => return Ok(Value::Float(0.0)),
19948 };
19949
19950 let mut dissonance: f64 = 0.0;
19951
19952 if matches!(affect.sentiment, Some(RuntimeSentiment::Positive)) && affect.sarcasm {
19954 dissonance += 0.4;
19955 }
19956
19957 if matches!(affect.sentiment, Some(RuntimeSentiment::Negative)) && affect.sarcasm {
19959 dissonance += 0.1;
19960 }
19961
19962 if matches!(affect.confidence, Some(RuntimeConfidence::High))
19964 && matches!(affect.intensity, Some(RuntimeIntensity::Down))
19965 {
19966 dissonance += 0.2;
19967 }
19968
19969 if matches!(affect.formality, Some(RuntimeFormality::Formal)) {
19971 if matches!(
19972 affect.emotion,
19973 Some(RuntimeEmotion::Anger) | Some(RuntimeEmotion::Fear)
19974 ) {
19975 dissonance += 0.3;
19976 }
19977 }
19978
19979 if matches!(
19981 affect.emotion,
19982 Some(RuntimeEmotion::Joy) | Some(RuntimeEmotion::Love)
19983 ) && affect.sarcasm
19984 {
19985 dissonance += 0.3;
19986 }
19987
19988 Ok(Value::Float(dissonance.min(1.0)))
19989 });
19990
19991 define(interp, "emotional_fingerprint", Some(1), |interp, args| {
19994 let h = get_hologram_values(&args[0], interp)?;
19995
19996 let repr = format!(
19998 "hologram:v{:.4}:a{:.4}:d{:.4}:auth{:.4}:c{:.4}",
19999 h.0, h.1, h.2, h.3, h.4
20000 );
20001
20002 let hash = blake3::hash(repr.as_bytes());
20004 Ok(Value::String(Rc::new(hash.to_hex().to_string())))
20005 });
20006
20007 define(interp, "emotional_morph", Some(3), |interp, args| {
20010 let h1 = get_hologram_values(&args[0], interp)?;
20011 let h2 = get_hologram_values(&args[1], interp)?;
20012 let t = match &args[2] {
20013 Value::Float(f) => f.max(0.0).min(1.0),
20014 Value::Int(i) => (*i as f64).max(0.0).min(1.0),
20015 _ => {
20016 return Err(RuntimeError::new(
20017 "emotional_morph() requires numeric t value",
20018 ))
20019 }
20020 };
20021
20022 let mut result = std::collections::HashMap::new();
20023 result.insert(
20024 "valence".to_string(),
20025 Value::Float(h1.0 + (h2.0 - h1.0) * t),
20026 );
20027 result.insert(
20028 "arousal".to_string(),
20029 Value::Float(h1.1 + (h2.1 - h1.1) * t),
20030 );
20031 result.insert(
20032 "dominance".to_string(),
20033 Value::Float(h1.2 + (h2.2 - h1.2) * t),
20034 );
20035 result.insert(
20036 "authenticity".to_string(),
20037 Value::Float(h1.3 + (h2.3 - h1.3) * t),
20038 );
20039 result.insert(
20040 "certainty".to_string(),
20041 Value::Float(h1.4 + (h2.4 - h1.4) * t),
20042 );
20043
20044 Ok(Value::Map(Rc::new(RefCell::new(result))))
20045 });
20046
20047 define(interp, "cultural_emotion", Some(2), |_, args| {
20053 let emotion = match &args[0] {
20054 Value::Affective { affect, .. } => affect.emotion.clone(),
20055 Value::String(s) => match s.as_str() {
20056 "joy" => Some(RuntimeEmotion::Joy),
20057 "sadness" => Some(RuntimeEmotion::Sadness),
20058 "anger" => Some(RuntimeEmotion::Anger),
20059 "fear" => Some(RuntimeEmotion::Fear),
20060 "surprise" => Some(RuntimeEmotion::Surprise),
20061 "love" => Some(RuntimeEmotion::Love),
20062 _ => None,
20063 },
20064 _ => None,
20065 };
20066
20067 let culture = match &args[1] {
20068 Value::String(s) => s.to_lowercase(),
20069 _ => {
20070 return Err(RuntimeError::new(
20071 "cultural_emotion() requires string culture",
20072 ))
20073 }
20074 };
20075
20076 let result = match (emotion, culture.as_str()) {
20077 (Some(RuntimeEmotion::Joy), "japanese" | "ja") => create_cultural_entry(
20079 "木漏れ日",
20080 "komorebi",
20081 "sunlight filtering through leaves - peaceful joy",
20082 ),
20083 (Some(RuntimeEmotion::Sadness), "japanese" | "ja") => create_cultural_entry(
20084 "物の哀れ",
20085 "mono no aware",
20086 "the pathos of things - bittersweet awareness of impermanence",
20087 ),
20088 (Some(RuntimeEmotion::Love), "japanese" | "ja") => create_cultural_entry(
20089 "甘え",
20090 "amae",
20091 "indulgent dependence on another's benevolence",
20092 ),
20093 (Some(RuntimeEmotion::Fear), "japanese" | "ja") => create_cultural_entry(
20094 "空気を読む",
20095 "kuuki wo yomu",
20096 "anxiety about reading the room",
20097 ),
20098
20099 (Some(RuntimeEmotion::Sadness), "portuguese" | "pt") => create_cultural_entry(
20101 "saudade",
20102 "saudade",
20103 "melancholic longing for something or someone absent",
20104 ),
20105 (Some(RuntimeEmotion::Joy), "portuguese" | "pt") => {
20106 create_cultural_entry("alegria", "alegria", "exuberant collective joy")
20107 }
20108
20109 (Some(RuntimeEmotion::Joy), "german" | "de") => create_cultural_entry(
20111 "Schadenfreude",
20112 "schadenfreude",
20113 "pleasure derived from another's misfortune",
20114 ),
20115 (Some(RuntimeEmotion::Sadness), "german" | "de") => create_cultural_entry(
20116 "Weltschmerz",
20117 "weltschmerz",
20118 "world-weariness, melancholy about the world's state",
20119 ),
20120 (Some(RuntimeEmotion::Fear), "german" | "de") => create_cultural_entry(
20121 "Torschlusspanik",
20122 "torschlusspanik",
20123 "fear of diminishing opportunities with age",
20124 ),
20125
20126 (Some(RuntimeEmotion::Joy), "danish" | "da") => {
20128 create_cultural_entry("hygge", "hygge", "cozy contentment and conviviality")
20129 }
20130
20131 (Some(RuntimeEmotion::Joy), "arabic" | "ar") => {
20133 create_cultural_entry("طرب", "tarab", "musical ecstasy, enchantment through art")
20134 }
20135 (Some(RuntimeEmotion::Love), "arabic" | "ar") => {
20136 create_cultural_entry("هوى", "hawa", "passionate, sometimes irrational love")
20137 }
20138
20139 (Some(RuntimeEmotion::Sadness), "korean" | "ko") => create_cultural_entry(
20141 "한",
20142 "han",
20143 "collective grief and resentment from historical suffering",
20144 ),
20145 (Some(RuntimeEmotion::Joy), "korean" | "ko") => create_cultural_entry(
20146 "정",
20147 "jeong",
20148 "deep affection and attachment formed over time",
20149 ),
20150
20151 (Some(RuntimeEmotion::Sadness), "russian" | "ru") => {
20153 create_cultural_entry("тоска", "toska", "spiritual anguish without specific cause")
20154 }
20155
20156 (Some(RuntimeEmotion::Love), "hindi" | "hi") => {
20158 create_cultural_entry("विरह", "viraha", "longing for an absent beloved")
20159 }
20160
20161 (Some(RuntimeEmotion::Anger), "finnish" | "fi") => {
20163 create_cultural_entry("sisu", "sisu", "stoic determination and grit in adversity")
20164 }
20165
20166 (Some(e), _) => {
20168 let name = match e {
20169 RuntimeEmotion::Joy => "joy",
20170 RuntimeEmotion::Sadness => "sadness",
20171 RuntimeEmotion::Anger => "anger",
20172 RuntimeEmotion::Fear => "fear",
20173 RuntimeEmotion::Surprise => "surprise",
20174 RuntimeEmotion::Love => "love",
20175 };
20176 create_cultural_entry(name, name, "universal emotion")
20177 }
20178 (None, _) => create_cultural_entry("none", "none", "no emotion"),
20179 };
20180
20181 Ok(result)
20182 });
20183
20184 define(interp, "list_cultural_emotions", Some(1), |_, args| {
20186 let culture = match &args[0] {
20187 Value::String(s) => s.to_lowercase(),
20188 _ => {
20189 return Err(RuntimeError::new(
20190 "list_cultural_emotions() requires string culture",
20191 ))
20192 }
20193 };
20194
20195 let emotions: Vec<(&str, &str, &str)> = match culture.as_str() {
20196 "japanese" | "ja" => vec![
20197 ("木漏れ日", "komorebi", "sunlight through leaves"),
20198 ("物の哀れ", "mono no aware", "pathos of things"),
20199 ("甘え", "amae", "indulgent dependence"),
20200 ("侘寂", "wabi-sabi", "beauty in imperfection"),
20201 ("生きがい", "ikigai", "reason for being"),
20202 ],
20203 "german" | "de" => vec![
20204 ("Schadenfreude", "schadenfreude", "joy at misfortune"),
20205 ("Weltschmerz", "weltschmerz", "world-weariness"),
20206 ("Torschlusspanik", "torschlusspanik", "gate-closing panic"),
20207 ("Sehnsucht", "sehnsucht", "deep longing"),
20208 ("Wanderlust", "wanderlust", "desire to travel"),
20209 ],
20210 "portuguese" | "pt" => vec![
20211 ("saudade", "saudade", "melancholic longing"),
20212 ("alegria", "alegria", "exuberant joy"),
20213 ("desabafar", "desabafar", "emotional unburdening"),
20214 ],
20215 "danish" | "da" => vec![("hygge", "hygge", "cozy contentment")],
20216 "korean" | "ko" => vec![
20217 ("한", "han", "collective grief"),
20218 ("정", "jeong", "deep affection"),
20219 ("눈치", "nunchi", "situational awareness"),
20220 ],
20221 "arabic" | "ar" => vec![
20222 ("طرب", "tarab", "musical ecstasy"),
20223 ("هوى", "hawa", "passionate love"),
20224 ("صبر", "sabr", "patient perseverance"),
20225 ],
20226 "russian" | "ru" => vec![
20227 ("тоска", "toska", "spiritual anguish"),
20228 ("пошлость", "poshlost", "spiritual vulgarity"),
20229 ],
20230 "finnish" | "fi" => vec![("sisu", "sisu", "stoic determination")],
20231 "hindi" | "hi" => vec![
20232 ("विरह", "viraha", "longing for beloved"),
20233 ("जुगाड़", "jugaad", "creative improvisation"),
20234 ],
20235 _ => vec![
20236 ("joy", "joy", "universal happiness"),
20237 ("sadness", "sadness", "universal sorrow"),
20238 ("anger", "anger", "universal frustration"),
20239 ("fear", "fear", "universal anxiety"),
20240 ("surprise", "surprise", "universal amazement"),
20241 ("love", "love", "universal affection"),
20242 ],
20243 };
20244
20245 let result: Vec<Value> = emotions
20246 .iter()
20247 .map(|(native, romanized, meaning)| create_cultural_entry(native, romanized, meaning))
20248 .collect();
20249
20250 Ok(Value::Array(Rc::new(RefCell::new(result))))
20251 });
20252
20253 define(interp, "hologram_info", Some(0), |_, _| {
20255 let mut info = std::collections::HashMap::new();
20256
20257 info.insert(
20258 "dimensions".to_string(),
20259 Value::Array(Rc::new(RefCell::new(vec![
20260 Value::String(Rc::new("valence".to_string())),
20261 Value::String(Rc::new("arousal".to_string())),
20262 Value::String(Rc::new("dominance".to_string())),
20263 Value::String(Rc::new("authenticity".to_string())),
20264 Value::String(Rc::new("certainty".to_string())),
20265 Value::String(Rc::new("emotion_index".to_string())),
20266 ]))),
20267 );
20268
20269 info.insert(
20270 "supported_cultures".to_string(),
20271 Value::Array(Rc::new(RefCell::new(vec![
20272 Value::String(Rc::new("japanese".to_string())),
20273 Value::String(Rc::new("german".to_string())),
20274 Value::String(Rc::new("portuguese".to_string())),
20275 Value::String(Rc::new("danish".to_string())),
20276 Value::String(Rc::new("korean".to_string())),
20277 Value::String(Rc::new("arabic".to_string())),
20278 Value::String(Rc::new("russian".to_string())),
20279 Value::String(Rc::new("finnish".to_string())),
20280 Value::String(Rc::new("hindi".to_string())),
20281 ]))),
20282 );
20283
20284 let funcs = vec![
20285 "emotional_hologram",
20286 "emotional_distance",
20287 "emotional_similarity",
20288 "emotional_dissonance",
20289 "emotional_fingerprint",
20290 "emotional_morph",
20291 "cultural_emotion",
20292 "list_cultural_emotions",
20293 "hologram_info",
20294 ];
20295 let func_values: Vec<Value> = funcs
20296 .iter()
20297 .map(|s| Value::String(Rc::new(s.to_string())))
20298 .collect();
20299 info.insert(
20300 "functions".to_string(),
20301 Value::Array(Rc::new(RefCell::new(func_values))),
20302 );
20303
20304 Ok(Value::Map(Rc::new(RefCell::new(info))))
20305 });
20306}
20307
20308fn get_hologram_values(
20310 val: &Value,
20311 _interp: &mut Interpreter,
20312) -> Result<(f64, f64, f64, f64, f64), RuntimeError> {
20313 use crate::interpreter::{
20314 RuntimeAffect, RuntimeConfidence, RuntimeFormality, RuntimeIntensity, RuntimeSentiment,
20315 };
20316
20317 let affect = match val {
20318 Value::Affective { affect, .. } => affect.clone(),
20319 Value::Map(m) => {
20320 let map = m.borrow();
20322 let v = extract_float(&map, "valence").unwrap_or(0.0);
20323 let a = extract_float(&map, "arousal").unwrap_or(0.5);
20324 let d = extract_float(&map, "dominance").unwrap_or(0.5);
20325 let auth = extract_float(&map, "authenticity").unwrap_or(0.9);
20326 let c = extract_float(&map, "certainty").unwrap_or(0.5);
20327 return Ok((v, a, d, auth, c));
20328 }
20329 _ => RuntimeAffect {
20330 sentiment: None,
20331 sarcasm: false,
20332 intensity: None,
20333 formality: None,
20334 emotion: None,
20335 confidence: None,
20336 },
20337 };
20338
20339 let v = match affect.sentiment {
20340 Some(RuntimeSentiment::Positive) => 1.0,
20341 Some(RuntimeSentiment::Negative) => -1.0,
20342 _ => 0.0,
20343 };
20344 let a = match affect.intensity {
20345 Some(RuntimeIntensity::Down) => 0.25,
20346 Some(RuntimeIntensity::Up) => 0.75,
20347 Some(RuntimeIntensity::Max) => 1.0,
20348 None => 0.5,
20349 };
20350 let d = match affect.formality {
20351 Some(RuntimeFormality::Informal) => 0.25,
20352 Some(RuntimeFormality::Formal) => 0.85,
20353 None => 0.5,
20354 };
20355 let auth = if affect.sarcasm { -0.9 } else { 0.9 };
20356 let c = match affect.confidence {
20357 Some(RuntimeConfidence::Low) => 0.2,
20358 Some(RuntimeConfidence::High) => 0.9,
20359 _ => 0.5,
20360 };
20361
20362 Ok((v, a, d, auth, c))
20363}
20364
20365fn extract_float(map: &std::collections::HashMap<String, Value>, key: &str) -> Option<f64> {
20366 match map.get(key) {
20367 Some(Value::Float(f)) => Some(*f),
20368 Some(Value::Int(i)) => Some(*i as f64),
20369 _ => None,
20370 }
20371}
20372
20373fn create_cultural_entry(native: &str, romanized: &str, meaning: &str) -> Value {
20374 let mut entry = std::collections::HashMap::new();
20375 entry.insert(
20376 "native".to_string(),
20377 Value::String(Rc::new(native.to_string())),
20378 );
20379 entry.insert(
20380 "romanized".to_string(),
20381 Value::String(Rc::new(romanized.to_string())),
20382 );
20383 entry.insert(
20384 "meaning".to_string(),
20385 Value::String(Rc::new(meaning.to_string())),
20386 );
20387 Value::Map(Rc::new(RefCell::new(entry)))
20388}
20389
20390fn register_experimental_crypto(interp: &mut Interpreter) {
20395 define(interp, "commit", Some(1), |_, args| {
20401 let value_str = match &args[0] {
20402 Value::String(s) => s.to_string(),
20403 other => format!("{:?}", other),
20404 };
20405
20406 let mut nonce = [0u8; 32];
20408 getrandom::getrandom(&mut nonce)
20409 .map_err(|e| RuntimeError::new(format!("commit() random failed: {}", e)))?;
20410 let nonce_hex = hex::encode(&nonce);
20411
20412 let commitment_input = format!("{}:{}", value_str, nonce_hex);
20414 let commitment = blake3::hash(commitment_input.as_bytes());
20415
20416 let mut result = std::collections::HashMap::new();
20417 result.insert(
20418 "commitment".to_string(),
20419 Value::String(Rc::new(commitment.to_hex().to_string())),
20420 );
20421 result.insert("nonce".to_string(), Value::String(Rc::new(nonce_hex)));
20422 result.insert("value".to_string(), args[0].clone());
20423
20424 Ok(Value::Map(Rc::new(RefCell::new(result))))
20425 });
20426
20427 define(interp, "verify_commitment", Some(3), |_, args| {
20429 let commitment = match &args[0] {
20430 Value::String(s) => s.to_string(),
20431 _ => {
20432 return Err(RuntimeError::new(
20433 "verify_commitment() requires string commitment",
20434 ))
20435 }
20436 };
20437 let value_str = match &args[1] {
20438 Value::String(s) => s.to_string(),
20439 other => format!("{:?}", other),
20440 };
20441 let nonce = match &args[2] {
20442 Value::String(s) => s.to_string(),
20443 _ => {
20444 return Err(RuntimeError::new(
20445 "verify_commitment() requires string nonce",
20446 ))
20447 }
20448 };
20449
20450 let commitment_input = format!("{}:{}", value_str, nonce);
20452 let computed = blake3::hash(commitment_input.as_bytes());
20453
20454 Ok(Value::Bool(computed.to_hex().to_string() == commitment))
20455 });
20456
20457 define(interp, "secret_split", Some(3), |_, args| {
20463 let secret = match &args[0] {
20464 Value::String(s) => s.as_bytes().to_vec(),
20465 Value::Array(arr) => {
20466 let borrowed = arr.borrow();
20467 borrowed
20468 .iter()
20469 .filter_map(|v| {
20470 if let Value::Int(i) = v {
20471 Some(*i as u8)
20472 } else {
20473 None
20474 }
20475 })
20476 .collect()
20477 }
20478 _ => {
20479 return Err(RuntimeError::new(
20480 "secret_split() requires string or byte array",
20481 ))
20482 }
20483 };
20484
20485 let threshold = match &args[1] {
20486 Value::Int(n) => *n as usize,
20487 _ => {
20488 return Err(RuntimeError::new(
20489 "secret_split() requires integer threshold",
20490 ))
20491 }
20492 };
20493
20494 let num_shares = match &args[2] {
20495 Value::Int(n) => *n as usize,
20496 _ => {
20497 return Err(RuntimeError::new(
20498 "secret_split() requires integer num_shares",
20499 ))
20500 }
20501 };
20502
20503 if threshold < 2 {
20504 return Err(RuntimeError::new("secret_split() threshold must be >= 2"));
20505 }
20506 if num_shares < threshold {
20507 return Err(RuntimeError::new(
20508 "secret_split() num_shares must be >= threshold",
20509 ));
20510 }
20511 if num_shares > 255 {
20512 return Err(RuntimeError::new("secret_split() max 255 shares"));
20513 }
20514
20515 let mut rng = rand::thread_rng();
20518 let mut shares: Vec<Vec<u8>> = (0..num_shares)
20519 .map(|_| Vec::with_capacity(secret.len() + 1))
20520 .collect();
20521
20522 for (i, share) in shares.iter_mut().enumerate() {
20524 share.push((i + 1) as u8);
20525 }
20526
20527 for &byte in &secret {
20529 let mut coefficients: Vec<u8> = vec![byte];
20532 for _ in 1..threshold {
20533 coefficients.push(rng.gen());
20534 }
20535
20536 for (i, share) in shares.iter_mut().enumerate() {
20538 let x = (i + 1) as u8;
20539 let y = eval_polynomial_gf256(&coefficients, x);
20540 share.push(y);
20541 }
20542 }
20543
20544 let share_values: Vec<Value> = shares
20546 .iter()
20547 .map(|share| {
20548 let hex = hex::encode(share);
20549 Value::String(Rc::new(hex))
20550 })
20551 .collect();
20552
20553 let mut result = std::collections::HashMap::new();
20554 result.insert(
20555 "shares".to_string(),
20556 Value::Array(Rc::new(RefCell::new(share_values))),
20557 );
20558 result.insert("threshold".to_string(), Value::Int(threshold as i64));
20559 result.insert("total".to_string(), Value::Int(num_shares as i64));
20560
20561 Ok(Value::Map(Rc::new(RefCell::new(result))))
20562 });
20563
20564 define(interp, "secret_recover", Some(1), |_, args| {
20566 let shares: Vec<Vec<u8>> = match &args[0] {
20567 Value::Array(arr) => {
20568 let borrowed = arr.borrow();
20569 borrowed
20570 .iter()
20571 .filter_map(|v| {
20572 if let Value::String(s) = v {
20573 hex::decode(s.as_str()).ok()
20574 } else {
20575 None
20576 }
20577 })
20578 .collect()
20579 }
20580 _ => {
20581 return Err(RuntimeError::new(
20582 "secret_recover() requires array of share strings",
20583 ))
20584 }
20585 };
20586
20587 if shares.is_empty() {
20588 return Err(RuntimeError::new(
20589 "secret_recover() requires at least one share",
20590 ));
20591 }
20592
20593 let share_len = shares[0].len();
20594 if share_len < 2 {
20595 return Err(RuntimeError::new("secret_recover() invalid share format"));
20596 }
20597
20598 let mut secret = Vec::with_capacity(share_len - 1);
20600
20601 for byte_idx in 1..share_len {
20602 let points: Vec<(u8, u8)> = shares
20604 .iter()
20605 .map(|share| (share[0], share[byte_idx]))
20606 .collect();
20607
20608 let recovered_byte = lagrange_interpolate_gf256(&points, 0);
20610 secret.push(recovered_byte);
20611 }
20612
20613 match String::from_utf8(secret.clone()) {
20615 Ok(s) => Ok(Value::String(Rc::new(s))),
20616 Err(_) => {
20617 let byte_values: Vec<Value> =
20619 secret.iter().map(|&b| Value::Int(b as i64)).collect();
20620 Ok(Value::Array(Rc::new(RefCell::new(byte_values))))
20621 }
20622 }
20623 });
20624
20625 define(interp, "council_split", Some(2), |_, args| {
20631 let secret = match &args[0] {
20632 Value::String(s) => s.as_bytes().to_vec(),
20633 _ => return Err(RuntimeError::new("council_split() requires string secret")),
20634 };
20635
20636 let num_elders = match &args[1] {
20637 Value::Int(n) => *n as usize,
20638 _ => {
20639 return Err(RuntimeError::new(
20640 "council_split() requires integer num_elders",
20641 ))
20642 }
20643 };
20644
20645 if num_elders < 3 {
20646 return Err(RuntimeError::new(
20647 "council_split() requires at least 3 elders",
20648 ));
20649 }
20650
20651 let threshold = (num_elders / 2) + 1;
20653
20654 let mut rng = rand::thread_rng();
20656 let mut shares: Vec<Vec<u8>> = (0..num_elders)
20657 .map(|_| Vec::with_capacity(secret.len() + 1))
20658 .collect();
20659
20660 for (i, share) in shares.iter_mut().enumerate() {
20661 share.push((i + 1) as u8);
20662 }
20663
20664 for &byte in &secret {
20665 let mut coefficients: Vec<u8> = vec![byte];
20666 for _ in 1..threshold {
20667 coefficients.push(rng.gen());
20668 }
20669
20670 for (i, share) in shares.iter_mut().enumerate() {
20671 let x = (i + 1) as u8;
20672 let y = eval_polynomial_gf256(&coefficients, x);
20673 share.push(y);
20674 }
20675 }
20676
20677 let share_values: Vec<Value> = shares
20678 .iter()
20679 .map(|share| Value::String(Rc::new(hex::encode(share))))
20680 .collect();
20681
20682 let mut result = std::collections::HashMap::new();
20683 result.insert(
20684 "shares".to_string(),
20685 Value::Array(Rc::new(RefCell::new(share_values))),
20686 );
20687 result.insert("threshold".to_string(), Value::Int(threshold as i64));
20688 result.insert("total".to_string(), Value::Int(num_elders as i64));
20689 result.insert(
20690 "model".to_string(),
20691 Value::String(Rc::new("ubuntu".to_string())),
20692 );
20693 result.insert(
20694 "philosophy".to_string(),
20695 Value::String(Rc::new(
20696 "I am because we are - majority consensus required".to_string(),
20697 )),
20698 );
20699
20700 Ok(Value::Map(Rc::new(RefCell::new(result))))
20701 });
20702
20703 define(interp, "witness_chain", Some(2), |_, args| {
20706 let statement = match &args[0] {
20707 Value::String(s) => s.to_string(),
20708 _ => {
20709 return Err(RuntimeError::new(
20710 "witness_chain() requires string statement",
20711 ))
20712 }
20713 };
20714
20715 let witnesses: Vec<String> = match &args[1] {
20716 Value::Array(arr) => {
20717 let borrowed = arr.borrow();
20718 borrowed
20719 .iter()
20720 .filter_map(|v| {
20721 if let Value::String(s) = v {
20722 Some(s.to_string())
20723 } else {
20724 None
20725 }
20726 })
20727 .collect()
20728 }
20729 _ => {
20730 return Err(RuntimeError::new(
20731 "witness_chain() requires array of witness names",
20732 ))
20733 }
20734 };
20735
20736 if witnesses.is_empty() {
20737 return Err(RuntimeError::new(
20738 "witness_chain() requires at least one witness",
20739 ));
20740 }
20741
20742 let mut chain = Vec::new();
20744 let mut prev_hash = blake3::hash(statement.as_bytes()).to_hex().to_string();
20745
20746 for (i, witness) in witnesses.iter().enumerate() {
20747 let attestation = format!("{}:attests:{}", witness, prev_hash);
20748 let hash = blake3::hash(attestation.as_bytes()).to_hex().to_string();
20749
20750 let mut link = std::collections::HashMap::new();
20751 link.insert(
20752 "witness".to_string(),
20753 Value::String(Rc::new(witness.clone())),
20754 );
20755 link.insert("position".to_string(), Value::Int((i + 1) as i64));
20756 link.insert(
20757 "attests_to".to_string(),
20758 Value::String(Rc::new(prev_hash.clone())),
20759 );
20760 link.insert(
20761 "signature".to_string(),
20762 Value::String(Rc::new(hash.clone())),
20763 );
20764
20765 chain.push(Value::Map(Rc::new(RefCell::new(link))));
20766 prev_hash = hash;
20767 }
20768
20769 let mut result = std::collections::HashMap::new();
20770 result.insert("statement".to_string(), Value::String(Rc::new(statement)));
20771 result.insert(
20772 "chain".to_string(),
20773 Value::Array(Rc::new(RefCell::new(chain))),
20774 );
20775 result.insert("final_seal".to_string(), Value::String(Rc::new(prev_hash)));
20776 result.insert(
20777 "model".to_string(),
20778 Value::String(Rc::new("isnad".to_string())),
20779 );
20780 result.insert(
20781 "philosophy".to_string(),
20782 Value::String(Rc::new(
20783 "Chain of reliable transmitters - each witness validates the previous".to_string(),
20784 )),
20785 );
20786
20787 Ok(Value::Map(Rc::new(RefCell::new(result))))
20788 });
20789
20790 define(interp, "verify_witness_chain", Some(1), |_, args| {
20792 let chain_map = match &args[0] {
20793 Value::Map(m) => m.borrow(),
20794 _ => {
20795 return Err(RuntimeError::new(
20796 "verify_witness_chain() requires chain map",
20797 ))
20798 }
20799 };
20800
20801 let statement = match chain_map.get("statement") {
20802 Some(Value::String(s)) => s.to_string(),
20803 _ => {
20804 return Err(RuntimeError::new(
20805 "verify_witness_chain() invalid chain format",
20806 ))
20807 }
20808 };
20809
20810 let chain = match chain_map.get("chain") {
20811 Some(Value::Array(arr)) => arr.borrow().clone(),
20812 _ => {
20813 return Err(RuntimeError::new(
20814 "verify_witness_chain() invalid chain format",
20815 ))
20816 }
20817 };
20818
20819 let mut prev_hash = blake3::hash(statement.as_bytes()).to_hex().to_string();
20820
20821 for link_val in chain.iter() {
20822 if let Value::Map(link_map) = link_val {
20823 let link = link_map.borrow();
20824 let witness = match link.get("witness") {
20825 Some(Value::String(s)) => s.to_string(),
20826 _ => return Ok(Value::Bool(false)),
20827 };
20828 let attests_to = match link.get("attests_to") {
20829 Some(Value::String(s)) => s.to_string(),
20830 _ => return Ok(Value::Bool(false)),
20831 };
20832 let signature = match link.get("signature") {
20833 Some(Value::String(s)) => s.to_string(),
20834 _ => return Ok(Value::Bool(false)),
20835 };
20836
20837 if attests_to != prev_hash {
20839 return Ok(Value::Bool(false));
20840 }
20841
20842 let expected = format!("{}:attests:{}", witness, prev_hash);
20843 let computed = blake3::hash(expected.as_bytes()).to_hex().to_string();
20844
20845 if computed != signature {
20846 return Ok(Value::Bool(false));
20847 }
20848
20849 prev_hash = signature;
20850 } else {
20851 return Ok(Value::Bool(false));
20852 }
20853 }
20854
20855 Ok(Value::Bool(true))
20856 });
20857
20858 define(interp, "experimental_crypto_info", Some(0), |_, _| {
20860 let mut info = std::collections::HashMap::new();
20861
20862 info.insert(
20863 "commitment_functions".to_string(),
20864 Value::Array(Rc::new(RefCell::new(vec![
20865 Value::String(Rc::new("commit".to_string())),
20866 Value::String(Rc::new("verify_commitment".to_string())),
20867 ]))),
20868 );
20869
20870 info.insert(
20871 "threshold_functions".to_string(),
20872 Value::Array(Rc::new(RefCell::new(vec![
20873 Value::String(Rc::new("secret_split".to_string())),
20874 Value::String(Rc::new("secret_recover".to_string())),
20875 ]))),
20876 );
20877
20878 info.insert(
20879 "cultural_ceremonies".to_string(),
20880 Value::Array(Rc::new(RefCell::new(vec![
20881 Value::String(Rc::new(
20882 "council_split (Ubuntu - African consensus)".to_string(),
20883 )),
20884 Value::String(Rc::new(
20885 "witness_chain (Isnad - Islamic transmission)".to_string(),
20886 )),
20887 ]))),
20888 );
20889
20890 Ok(Value::Map(Rc::new(RefCell::new(info))))
20891 });
20892}
20893
20894fn eval_polynomial_gf256(coefficients: &[u8], x: u8) -> u8 {
20896 let mut result: u8 = 0;
20897 let mut x_power: u8 = 1;
20898
20899 for &coef in coefficients {
20900 result ^= gf256_mul(coef, x_power);
20901 x_power = gf256_mul(x_power, x);
20902 }
20903
20904 result
20905}
20906
20907fn lagrange_interpolate_gf256(points: &[(u8, u8)], _x: u8) -> u8 {
20909 let mut result: u8 = 0;
20910
20911 for (i, &(xi, yi)) in points.iter().enumerate() {
20912 let mut numerator: u8 = 1;
20913 let mut denominator: u8 = 1;
20914
20915 for (j, &(xj, _)) in points.iter().enumerate() {
20916 if i != j {
20917 numerator = gf256_mul(numerator, xj);
20919 denominator = gf256_mul(denominator, xi ^ xj);
20921 }
20922 }
20923
20924 let term = gf256_mul(yi, gf256_mul(numerator, gf256_inv(denominator)));
20926 result ^= term;
20927 }
20928
20929 result
20930}
20931
20932fn gf256_mul(mut a: u8, mut b: u8) -> u8 {
20934 let mut result: u8 = 0;
20935 let modulus: u16 = 0x11b; while b != 0 {
20938 if b & 1 != 0 {
20939 result ^= a;
20940 }
20941 let high_bit = (a & 0x80) != 0;
20942 a <<= 1;
20943 if high_bit {
20944 a ^= (modulus & 0xff) as u8;
20945 }
20946 b >>= 1;
20947 }
20948
20949 result
20950}
20951
20952fn gf256_inv(a: u8) -> u8 {
20954 if a == 0 {
20955 return 0;
20956 }
20957
20958 let mut result = a;
20960 for _ in 0..6 {
20961 result = gf256_mul(result, result);
20962 result = gf256_mul(result, a);
20963 }
20964 gf256_mul(result, result)
20965}
20966
20967fn register_sketch(interp: &mut Interpreter) {
20991 define(interp, "HyperLogLog·new", Some(0), |_, _| {
20995 let mut fields = std::collections::HashMap::new();
20996 let precision = 14u64;
20998 let num_registers = 1u64 << precision;
20999 let registers: Vec<Value> = vec![Value::Int(0); num_registers as usize];
21001 fields.insert("_precision".to_string(), Value::Int(precision as i64));
21002 fields.insert(
21003 "_registers".to_string(),
21004 Value::Array(Rc::new(RefCell::new(registers))),
21005 );
21006 fields.insert("_count".to_string(), Value::Int(0));
21007 Ok(Value::Struct {
21008 name: "HyperLogLog".to_string(),
21009 fields: Rc::new(RefCell::new(fields)),
21010 })
21011 });
21012
21013 define(interp, "BloomFilter·new", Some(0), |_, _| {
21016 let mut fields = std::collections::HashMap::new();
21017 let size = 1024u64;
21019 let num_hashes = 3u64;
21020 let bits: Vec<Value> = vec![Value::Bool(false); size as usize];
21021 fields.insert("_size".to_string(), Value::Int(size as i64));
21022 fields.insert("_num_hashes".to_string(), Value::Int(num_hashes as i64));
21023 fields.insert(
21024 "_bits".to_string(),
21025 Value::Array(Rc::new(RefCell::new(bits))),
21026 );
21027 Ok(Value::Struct {
21028 name: "BloomFilter".to_string(),
21029 fields: Rc::new(RefCell::new(fields)),
21030 })
21031 });
21032
21033 define(interp, "CountMinSketch·new", Some(0), |_, _| {
21036 let mut fields = std::collections::HashMap::new();
21037 let depth = 4u64;
21039 let width = 1024u64;
21040 let counters: Vec<Value> = (0..depth)
21042 .map(|_| {
21043 let row: Vec<Value> = vec![Value::Int(0); width as usize];
21044 Value::Array(Rc::new(RefCell::new(row)))
21045 })
21046 .collect();
21047 fields.insert("_depth".to_string(), Value::Int(depth as i64));
21048 fields.insert("_width".to_string(), Value::Int(width as i64));
21049 fields.insert(
21050 "_counters".to_string(),
21051 Value::Array(Rc::new(RefCell::new(counters))),
21052 );
21053 Ok(Value::Struct {
21054 name: "CountMinSketch".to_string(),
21055 fields: Rc::new(RefCell::new(fields)),
21056 })
21057 });
21058
21059 define(interp, "MerkleTree·new", Some(0), |_, _| {
21062 let mut fields = std::collections::HashMap::new();
21063 fields.insert(
21064 "_leaves".to_string(),
21065 Value::Array(Rc::new(RefCell::new(vec![]))),
21066 );
21067 fields.insert(
21068 "_hashes".to_string(),
21069 Value::Array(Rc::new(RefCell::new(vec![]))),
21070 );
21071 fields.insert("_root".to_string(), Value::Null);
21072 Ok(Value::Struct {
21073 name: "MerkleTree".to_string(),
21074 fields: Rc::new(RefCell::new(fields)),
21075 })
21076 });
21077
21078 define(interp, "MerkleTree·from", Some(1), |_, args| {
21080 use std::collections::hash_map::DefaultHasher;
21081 use std::hash::{Hash, Hasher};
21082
21083 let items = match &args[0] {
21084 Value::Array(arr) => arr.borrow().clone(),
21085 _ => return Err(RuntimeError::new("MerkleTree::from requires array")),
21086 };
21087
21088 let mut fields = std::collections::HashMap::new();
21089 let mut leaves: Vec<Value> = Vec::new();
21090
21091 for item in &items {
21093 let data = match item {
21094 Value::String(s) => s.as_bytes().to_vec(),
21095 Value::Int(n) => n.to_le_bytes().to_vec(),
21096 other => format!("{:?}", other).into_bytes(),
21097 };
21098 let mut hasher = DefaultHasher::new();
21099 data.hash(&mut hasher);
21100 let leaf_hash = format!("{:016x}", hasher.finish());
21101 leaves.push(Value::String(Rc::new(leaf_hash)));
21102 }
21103
21104 let combined: String = leaves
21106 .iter()
21107 .filter_map(|v| match v {
21108 Value::String(s) => Some(s.to_string()),
21109 _ => None,
21110 })
21111 .collect();
21112 let mut root_hasher = DefaultHasher::new();
21113 combined.hash(&mut root_hasher);
21114 let root = format!("{:016x}", root_hasher.finish());
21115
21116 fields.insert(
21117 "_leaves".to_string(),
21118 Value::Array(Rc::new(RefCell::new(leaves))),
21119 );
21120 fields.insert(
21121 "_items".to_string(),
21122 Value::Array(Rc::new(RefCell::new(items))),
21123 );
21124 fields.insert("_root".to_string(), Value::String(Rc::new(root)));
21125
21126 Ok(Value::Struct {
21127 name: "MerkleTree".to_string(),
21128 fields: Rc::new(RefCell::new(fields)),
21129 })
21130 });
21131
21132 define(interp, "fetch_untrusted_data", Some(0), |_, _| {
21134 use crate::interpreter::Evidence;
21135
21136 let mut fields = std::collections::HashMap::new();
21138 fields.insert("value".to_string(), Value::Int(42));
21139 fields.insert("hash".to_string(), Value::String(Rc::new("abc123".to_string())));
21140 fields.insert("_verified".to_string(), Value::Bool(false));
21141
21142 let data = Value::Struct {
21143 name: "UntrustedData".to_string(),
21144 fields: Rc::new(RefCell::new(fields)),
21145 };
21146
21147 Ok(Value::Evidential {
21149 value: Box::new(data),
21150 evidence: Evidence::Reported,
21151 })
21152 });
21153
21154 define(interp, "Superposition·new", Some(0), |_, _| {
21156 let mut fields = std::collections::HashMap::new();
21157 fields.insert(
21158 "_values".to_string(),
21159 Value::Array(Rc::new(RefCell::new(vec![]))),
21160 );
21161 fields.insert(
21162 "_weights".to_string(),
21163 Value::Array(Rc::new(RefCell::new(vec![]))),
21164 );
21165 fields.insert("_collapsed".to_string(), Value::Bool(false));
21166 Ok(Value::Struct {
21167 name: "Superposition".to_string(),
21168 fields: Rc::new(RefCell::new(fields)),
21169 })
21170 });
21171
21172 define(interp, "uniform", Some(1), |_, args| {
21174 let items = match &args[0] {
21175 Value::Array(arr) => arr.borrow().clone(),
21176 _ => return Err(RuntimeError::new("uniform() requires array")),
21177 };
21178
21179 let n = items.len();
21180 let weight = 1.0 / n as f64;
21181 let weights: Vec<Value> = (0..n).map(|_| Value::Float(weight)).collect();
21182
21183 let mut fields = std::collections::HashMap::new();
21184 fields.insert(
21185 "_values".to_string(),
21186 Value::Array(Rc::new(RefCell::new(items))),
21187 );
21188 fields.insert(
21189 "_weights".to_string(),
21190 Value::Array(Rc::new(RefCell::new(weights))),
21191 );
21192 fields.insert("_collapsed".to_string(), Value::Bool(false));
21193
21194 Ok(Value::Struct {
21195 name: "Superposition".to_string(),
21196 fields: Rc::new(RefCell::new(fields)),
21197 })
21198 });
21199
21200 define(interp, "Hologram·new", Some(0), |_, _| {
21202 let mut fields = std::collections::HashMap::new();
21203 fields.insert(
21204 "shards".to_string(),
21205 Value::Array(Rc::new(RefCell::new(vec![]))),
21206 );
21207 fields.insert("_data_shards".to_string(), Value::Int(0));
21208 fields.insert("_parity_shards".to_string(), Value::Int(0));
21209 Ok(Value::Struct {
21210 name: "Hologram".to_string(),
21211 fields: Rc::new(RefCell::new(fields)),
21212 })
21213 });
21214
21215 define(interp, "ReedSolomon", Some(0), |_, _| {
21217 Ok(Value::String(Rc::new("ReedSolomon".to_string())))
21218 });
21219
21220 define(interp, "Qubit·zero", Some(0), |_, _| {
21224 let mut fields = std::collections::HashMap::new();
21225 fields.insert("_alpha_real".to_string(), Value::Float(1.0));
21227 fields.insert("_alpha_imag".to_string(), Value::Float(0.0));
21228 fields.insert("_beta_real".to_string(), Value::Float(0.0));
21229 fields.insert("_beta_imag".to_string(), Value::Float(0.0));
21230 Ok(Value::Struct {
21231 name: "Qubit".to_string(),
21232 fields: Rc::new(RefCell::new(fields)),
21233 })
21234 });
21235
21236 define(interp, "Qubit·one", Some(0), |_, _| {
21237 let mut fields = std::collections::HashMap::new();
21238 fields.insert("_alpha_real".to_string(), Value::Float(0.0));
21240 fields.insert("_alpha_imag".to_string(), Value::Float(0.0));
21241 fields.insert("_beta_real".to_string(), Value::Float(1.0));
21242 fields.insert("_beta_imag".to_string(), Value::Float(0.0));
21243 Ok(Value::Struct {
21244 name: "Qubit".to_string(),
21245 fields: Rc::new(RefCell::new(fields)),
21246 })
21247 });
21248
21249 define(interp, "Cbit·new", Some(1), |_, args| {
21251 let value = match &args[0] {
21252 Value::Int(n) => if *n == 0 { 0 } else { 1 },
21253 Value::Bool(b) => if *b { 1 } else { 0 },
21254 _ => return Err(RuntimeError::new("Cbit::new() requires int or bool")),
21255 };
21256 Ok(Value::Int(value))
21257 });
21258
21259 define(interp, "CNOT", Some(2), |_, args| {
21262 let (ctrl_alpha_real, ctrl_beta_real, ctrl_beta_imag) = match &args[0] {
21264 Value::Struct { name, fields } if name == "Qubit" => {
21265 let alpha_real = match fields.borrow().get("_alpha_real") {
21266 Some(Value::Float(f)) => *f,
21267 _ => 1.0,
21268 };
21269 let beta_real = match fields.borrow().get("_beta_real") {
21270 Some(Value::Float(f)) => *f,
21271 _ => 0.0,
21272 };
21273 let beta_imag = match fields.borrow().get("_beta_imag") {
21274 Some(Value::Float(f)) => *f,
21275 _ => 0.0,
21276 };
21277 (alpha_real, beta_real, beta_imag)
21278 }
21279 _ => return Err(RuntimeError::new("CNOT requires Qubit arguments")),
21280 };
21281
21282 let (tgt_alpha_real, tgt_alpha_imag, tgt_beta_real, tgt_beta_imag) = match &args[1] {
21284 Value::Struct { name, fields } if name == "Qubit" => {
21285 let alpha_real = match fields.borrow().get("_alpha_real") {
21286 Some(Value::Float(f)) => *f,
21287 _ => 1.0,
21288 };
21289 let alpha_imag = match fields.borrow().get("_alpha_imag") {
21290 Some(Value::Float(f)) => *f,
21291 _ => 0.0,
21292 };
21293 let beta_real = match fields.borrow().get("_beta_real") {
21294 Some(Value::Float(f)) => *f,
21295 _ => 0.0,
21296 };
21297 let beta_imag = match fields.borrow().get("_beta_imag") {
21298 Some(Value::Float(f)) => *f,
21299 _ => 0.0,
21300 };
21301 (alpha_real, alpha_imag, beta_real, beta_imag)
21302 }
21303 _ => return Err(RuntimeError::new("CNOT requires Qubit arguments")),
21304 };
21305
21306 let control_prob_one = ctrl_beta_real * ctrl_beta_real + ctrl_beta_imag * ctrl_beta_imag;
21309
21310 let (new_tgt_alpha_real, new_tgt_alpha_imag, new_tgt_beta_real, new_tgt_beta_imag) =
21311 if control_prob_one > 0.5 {
21312 (tgt_beta_real, tgt_beta_imag, tgt_alpha_real, tgt_alpha_imag)
21314 } else {
21315 (tgt_alpha_real, tgt_alpha_imag, tgt_beta_real, tgt_beta_imag)
21317 };
21318
21319 let mut ctrl_fields = std::collections::HashMap::new();
21321 ctrl_fields.insert("_alpha_real".to_string(), Value::Float(ctrl_alpha_real));
21322 ctrl_fields.insert("_alpha_imag".to_string(), Value::Float(0.0));
21323 ctrl_fields.insert("_beta_real".to_string(), Value::Float(ctrl_beta_real));
21324 ctrl_fields.insert("_beta_imag".to_string(), Value::Float(ctrl_beta_imag));
21325 let new_ctrl = Value::Struct {
21326 name: "Qubit".to_string(),
21327 fields: Rc::new(RefCell::new(ctrl_fields)),
21328 };
21329
21330 let mut tgt_fields = std::collections::HashMap::new();
21332 tgt_fields.insert("_alpha_real".to_string(), Value::Float(new_tgt_alpha_real));
21333 tgt_fields.insert("_alpha_imag".to_string(), Value::Float(new_tgt_alpha_imag));
21334 tgt_fields.insert("_beta_real".to_string(), Value::Float(new_tgt_beta_real));
21335 tgt_fields.insert("_beta_imag".to_string(), Value::Float(new_tgt_beta_imag));
21336 let new_tgt = Value::Struct {
21337 name: "Qubit".to_string(),
21338 fields: Rc::new(RefCell::new(tgt_fields)),
21339 };
21340
21341 Ok(Value::Tuple(Rc::new(vec![new_ctrl, new_tgt])))
21343 });
21344
21345 define(interp, "QRegister·zeros", Some(0), |interp, _| {
21349 let size = if let Some((name, generics)) = interp.type_context.struct_generics.borrow().clone() {
21351 if name == "QRegister" && !generics.is_empty() {
21352 generics[0] as usize
21353 } else {
21354 1
21355 }
21356 } else {
21357 1
21358 };
21359
21360 let dim = 1 << size; let mut state: Vec<Value> = vec![Value::Float(0.0); dim];
21363 state[0] = Value::Float(1.0); let mut fields = std::collections::HashMap::new();
21366 fields.insert("_size".to_string(), Value::Int(size as i64));
21367 fields.insert("_state".to_string(), Value::Array(Rc::new(RefCell::new(state))));
21368
21369 Ok(Value::Struct {
21370 name: "QRegister".to_string(),
21371 fields: Rc::new(RefCell::new(fields)),
21372 })
21373 });
21374
21375 define(interp, "QHState·new", Some(1), |_, args| {
21379 let mut fields = std::collections::HashMap::new();
21380 fields.insert("value".to_string(), args[0].clone());
21381 fields.insert("_is_superposition".to_string(), Value::Bool(false));
21382 fields.insert("_amplitudes".to_string(), Value::Array(Rc::new(RefCell::new(vec![Value::Float(1.0)]))));
21383 Ok(Value::Struct {
21384 name: "QHState".to_string(),
21385 fields: Rc::new(RefCell::new(fields)),
21386 })
21387 });
21388
21389 define(interp, "QHState·superpose", Some(1), |_, args| {
21391 let values = match &args[0] {
21392 Value::Array(arr) => arr.borrow().clone(),
21393 _ => return Err(RuntimeError::new("QHState::superpose requires array")),
21394 };
21395 let n = values.len();
21396 let amplitude = 1.0 / (n as f64).sqrt();
21397 let amplitudes: Vec<Value> = (0..n).map(|_| Value::Float(amplitude)).collect();
21398
21399 let mut fields = std::collections::HashMap::new();
21400 fields.insert("value".to_string(), Value::Array(Rc::new(RefCell::new(values))));
21401 fields.insert("_is_superposition".to_string(), Value::Bool(true));
21402 fields.insert("_amplitudes".to_string(), Value::Array(Rc::new(RefCell::new(amplitudes))));
21403 Ok(Value::Struct {
21404 name: "QHState".to_string(),
21405 fields: Rc::new(RefCell::new(fields)),
21406 })
21407 });
21408
21409 define(interp, "QHState·encode", Some(1), |_, args| {
21411 let mut fields = std::collections::HashMap::new();
21412 fields.insert("value".to_string(), args[0].clone());
21413 fields.insert("_is_superposition".to_string(), Value::Bool(false));
21414 fields.insert("_amplitudes".to_string(), Value::Array(Rc::new(RefCell::new(vec![Value::Float(1.0)]))));
21415 fields.insert("_encoded".to_string(), Value::Bool(true));
21416 Ok(Value::Struct {
21417 name: "QHState".to_string(),
21418 fields: Rc::new(RefCell::new(fields)),
21419 })
21420 });
21421
21422 define(interp, "Hologram·encode", Some(1), |_, args| {
21424 let mut fields = std::collections::HashMap::new();
21425 fields.insert("value".to_string(), args[0].clone());
21426 fields.insert("_data_shards".to_string(), Value::Int(3));
21427 fields.insert("_parity_shards".to_string(), Value::Int(2));
21428 fields.insert("shards".to_string(), Value::Array(Rc::new(RefCell::new(vec![]))));
21429 Ok(Value::Struct {
21430 name: "Hologram".to_string(),
21431 fields: Rc::new(RefCell::new(fields)),
21432 })
21433 });
21434
21435 define(interp, "uniform", Some(1), |_, args| {
21437 let values = match &args[0] {
21438 Value::Array(arr) => arr.borrow().clone(),
21439 _ => return Err(RuntimeError::new("uniform requires array")),
21440 };
21441 let n = values.len();
21442 let amplitude = 1.0 / (n as f64).sqrt();
21443 let amplitudes: Vec<Value> = (0..n).map(|_| Value::Float(amplitude)).collect();
21444
21445 let mut fields = std::collections::HashMap::new();
21446 fields.insert("states".to_string(), Value::Array(Rc::new(RefCell::new(values))));
21447 fields.insert("_amplitudes".to_string(), Value::Array(Rc::new(RefCell::new(amplitudes))));
21448 Ok(Value::Struct {
21449 name: "Superposition".to_string(),
21450 fields: Rc::new(RefCell::new(fields)),
21451 })
21452 });
21453
21454 define(interp, "entangle_holograms", Some(2), |_, args| {
21456 let mut fields_a = std::collections::HashMap::new();
21457 fields_a.insert("value".to_string(), args[0].clone());
21458 fields_a.insert("_entangled".to_string(), Value::Bool(true));
21459 fields_a.insert("_partner_id".to_string(), Value::Int(1));
21460
21461 let mut fields_b = std::collections::HashMap::new();
21462 fields_b.insert("value".to_string(), args[1].clone());
21463 fields_b.insert("_entangled".to_string(), Value::Bool(true));
21464 fields_b.insert("_partner_id".to_string(), Value::Int(0));
21465
21466 let a = Value::Struct {
21467 name: "EntangledHologram".to_string(),
21468 fields: Rc::new(RefCell::new(fields_a)),
21469 };
21470 let b = Value::Struct {
21471 name: "EntangledHologram".to_string(),
21472 fields: Rc::new(RefCell::new(fields_b)),
21473 };
21474 Ok(Value::Tuple(Rc::new(vec![a, b])))
21475 });
21476
21477 define(interp, "bell_state", Some(0), |_, _| {
21479 let mut fields_a = std::collections::HashMap::new();
21480 fields_a.insert("_state".to_string(), Value::String(Rc::new("bell".to_string())));
21481 fields_a.insert("_is_pure".to_string(), Value::Bool(true));
21482
21483 let mut fields_b = std::collections::HashMap::new();
21484 fields_b.insert("_state".to_string(), Value::String(Rc::new("bell".to_string())));
21485 fields_b.insert("_is_pure".to_string(), Value::Bool(true));
21486
21487 let a = Value::Struct {
21488 name: "QHState".to_string(),
21489 fields: Rc::new(RefCell::new(fields_a)),
21490 };
21491 let b = Value::Struct {
21492 name: "QHState".to_string(),
21493 fields: Rc::new(RefCell::new(fields_b)),
21494 };
21495
21496 let mut entangled_fields = std::collections::HashMap::new();
21497 entangled_fields.insert("0".to_string(), a);
21498 entangled_fields.insert("1".to_string(), b);
21499
21500 Ok(Value::Struct {
21501 name: "Entangled".to_string(),
21502 fields: Rc::new(RefCell::new(entangled_fields)),
21503 })
21504 });
21505
21506 define(interp, "create_epr_pair", Some(0), |_, _| {
21508 let mut fields_alice = std::collections::HashMap::new();
21509 fields_alice.insert("_role".to_string(), Value::String(Rc::new("alice".to_string())));
21510 fields_alice.insert("_entangled".to_string(), Value::Bool(true));
21511
21512 let mut fields_bob = std::collections::HashMap::new();
21513 fields_bob.insert("_role".to_string(), Value::String(Rc::new("bob".to_string())));
21514 fields_bob.insert("_entangled".to_string(), Value::Bool(true));
21515
21516 let alice = Value::Struct {
21517 name: "EPRHalf".to_string(),
21518 fields: Rc::new(RefCell::new(fields_alice)),
21519 };
21520 let bob = Value::Struct {
21521 name: "EPRHalf".to_string(),
21522 fields: Rc::new(RefCell::new(fields_bob)),
21523 };
21524 Ok(Value::Tuple(Rc::new(vec![alice, bob])))
21525 });
21526
21527 define(interp, "receive_untrusted_shards", Some(0), |_, _| {
21529 let mut fields = std::collections::HashMap::new();
21531 fields.insert("shards".to_string(), Value::Array(Rc::new(RefCell::new(vec![
21532 Value::Int(1), Value::Int(2), Value::Int(3), Value::Int(4)
21533 ]))));
21534 fields.insert("_trusted".to_string(), Value::Bool(false));
21535 Ok(Value::Struct {
21536 name: "UntrustedShards".to_string(),
21537 fields: Rc::new(RefCell::new(fields)),
21538 })
21539 });
21540
21541 define(interp, "interfere", Some(2), |_, args| {
21545 let values_a: Vec<Value> = match &args[0] {
21547 Value::Struct { fields: f, .. } => {
21548 match f.borrow().get("value") {
21549 Some(Value::Array(arr)) => arr.borrow().clone(),
21550 Some(v) => vec![v.clone()],
21551 None => vec![],
21552 }
21553 }
21554 _ => vec![],
21555 };
21556 let values_b: Vec<Value> = match &args[1] {
21557 Value::Struct { fields: f, .. } => {
21558 match f.borrow().get("value") {
21559 Some(Value::Array(arr)) => arr.borrow().clone(),
21560 Some(v) => vec![v.clone()],
21561 None => vec![],
21562 }
21563 }
21564 _ => vec![],
21565 };
21566
21567 let common: Vec<Value> = values_a.iter()
21569 .filter(|a| values_b.iter().any(|b| {
21570 match (a, b) {
21571 (Value::Int(x), Value::Int(y)) => x == y,
21572 (Value::Float(x), Value::Float(y)) => (x - y).abs() < f64::EPSILON,
21573 (Value::String(x), Value::String(y)) => x == y,
21574 _ => false,
21575 }
21576 }))
21577 .cloned()
21578 .collect();
21579
21580 let mut fields = std::collections::HashMap::new();
21581 fields.insert("_state_a".to_string(), args[0].clone());
21582 fields.insert("_state_b".to_string(), args[1].clone());
21583 fields.insert("_is_superposition".to_string(), Value::Bool(true));
21584
21585 let result_value = if !common.is_empty() {
21587 if common.len() == 1 {
21588 common[0].clone()
21589 } else {
21590 Value::Array(Rc::new(RefCell::new(common)))
21591 }
21592 } else if !values_a.is_empty() {
21593 values_a[0].clone()
21594 } else {
21595 Value::Int(0)
21596 };
21597 fields.insert("value".to_string(), result_value);
21598
21599 Ok(Value::Struct {
21600 name: "QHState".to_string(),
21601 fields: Rc::new(RefCell::new(fields)),
21602 })
21603 });
21604
21605 define(interp, "partial_trace", Some(1), |_, args| {
21607 match &args[0] {
21608 Value::Struct { name, fields } if name == "Entangled" => {
21609 let fields_ref = fields.borrow();
21610 let a = fields_ref.get("0").cloned().unwrap_or(Value::Null);
21611 let b = fields_ref.get("1").cloned().unwrap_or(Value::Null);
21612 let system = match a {
21614 Value::Struct { name, fields } => {
21615 let mut new_fields = fields.borrow().clone();
21616 new_fields.insert("_is_pure".to_string(), Value::Bool(false));
21617 Value::Struct {
21618 name,
21619 fields: Rc::new(RefCell::new(new_fields)),
21620 }
21621 }
21622 _ => a,
21623 };
21624 Ok(Value::Tuple(Rc::new(vec![system, b])))
21625 }
21626 _ => Ok(Value::Tuple(Rc::new(vec![args[0].clone(), Value::Null]))),
21627 }
21628 });
21629
21630 define(interp, "error_correct", Some(1), |_, args| {
21632 match &args[0] {
21633 Value::Struct { name, fields } => {
21634 let mut new_fields = fields.borrow().clone();
21635 new_fields.remove("_noisy");
21636 new_fields.remove("_noise_rate");
21637 new_fields.insert("_corrected".to_string(), Value::Bool(true));
21638 Ok(Value::Struct {
21639 name: name.clone(),
21640 fields: Rc::new(RefCell::new(new_fields)),
21641 })
21642 }
21643 _ => Ok(args[0].clone()),
21644 }
21645 });
21646
21647 define(interp, "quantum_reconstruct", Some(1), |_, args| {
21649 match &args[0] {
21650 Value::Struct { fields, .. } => {
21651 let fields_ref = fields.borrow();
21652 if let Some(Value::Array(shards)) = fields_ref.get("shards") {
21653 if let Some(first) = shards.borrow().first() {
21654 if let Value::Struct { fields: shard_fields, .. } = first {
21655 if let Some(data) = shard_fields.borrow().get("data") {
21656 let mut qh_fields = std::collections::HashMap::new();
21657 qh_fields.insert("value".to_string(), data.clone());
21658 qh_fields.insert("_reconstructed".to_string(), Value::Bool(true));
21659 return Ok(Value::Struct {
21660 name: "QHState".to_string(),
21661 fields: Rc::new(RefCell::new(qh_fields)),
21662 });
21663 }
21664 }
21665 }
21666 }
21667 let mut qh_fields = std::collections::HashMap::new();
21669 qh_fields.insert("value".to_string(), Value::Int(42));
21670 qh_fields.insert("_reconstructed".to_string(), Value::Bool(true));
21671 Ok(Value::Struct {
21672 name: "QHState".to_string(),
21673 fields: Rc::new(RefCell::new(qh_fields)),
21674 })
21675 }
21676 _ => {
21677 let mut qh_fields = std::collections::HashMap::new();
21678 qh_fields.insert("value".to_string(), args[0].clone());
21679 Ok(Value::Struct {
21680 name: "QHState".to_string(),
21681 fields: Rc::new(RefCell::new(qh_fields)),
21682 })
21683 }
21684 }
21685 });
21686
21687 define(interp, "QHCompressed·new", Some(1), |_, args| {
21689 let mut fields = std::collections::HashMap::new();
21690 fields.insert("data".to_string(), args[0].clone());
21691 let size = match &args[0] {
21693 Value::Array(arr) => arr.borrow().len() as i64 / 2,
21694 _ => 1,
21695 };
21696 fields.insert("_compressed_size".to_string(), Value::Int(size.max(1)));
21697 Ok(Value::Struct {
21698 name: "QHCompressed".to_string(),
21699 fields: Rc::new(RefCell::new(fields)),
21700 })
21701 });
21702}
21703
21704fn register_multibase(interp: &mut Interpreter) {
21705 define(interp, "to_vigesimal", Some(1), |_, args| {
21709 let n = match &args[0] {
21710 Value::Int(n) => *n,
21711 _ => return Err(RuntimeError::new("to_vigesimal() requires integer")),
21712 };
21713
21714 let result = to_base_string(n.unsigned_abs(), 20, false);
21715 let prefix = if n < 0 { "-0v" } else { "0v" };
21716 Ok(Value::String(Rc::new(format!("{}{}", prefix, result))))
21717 });
21718
21719 define(interp, "from_vigesimal", Some(1), |_, args| {
21720 let s = match &args[0] {
21721 Value::String(s) => s.to_string(),
21722 _ => return Err(RuntimeError::new("from_vigesimal() requires string")),
21723 };
21724
21725 let (negative, clean) = parse_base_prefix(&s, "0v");
21726 let value = from_base_string(&clean, 20)?;
21727 Ok(Value::Int(if negative {
21728 -(value as i64)
21729 } else {
21730 value as i64
21731 }))
21732 });
21733
21734 define(interp, "to_sexagesimal", Some(1), |_, args| {
21738 let n = match &args[0] {
21739 Value::Int(n) => *n,
21740 _ => return Err(RuntimeError::new("to_sexagesimal() requires integer")),
21741 };
21742
21743 let negative = n < 0;
21744 let mut value = n.unsigned_abs();
21745 let mut parts = Vec::new();
21746
21747 if value == 0 {
21748 parts.push("0".to_string());
21749 } else {
21750 while value > 0 {
21751 parts.push(format!("{}", value % 60));
21752 value /= 60;
21753 }
21754 parts.reverse();
21755 }
21756
21757 let prefix = if negative { "-0s" } else { "0s" };
21758 Ok(Value::String(Rc::new(format!(
21759 "{}[{}]",
21760 prefix,
21761 parts.join(":")
21762 ))))
21763 });
21764
21765 define(interp, "from_sexagesimal", Some(1), |_, args| {
21766 let s = match &args[0] {
21767 Value::String(s) => s.to_string(),
21768 _ => return Err(RuntimeError::new("from_sexagesimal() requires string")),
21769 };
21770
21771 let negative = s.starts_with('-');
21772 let clean = s
21773 .trim_start_matches('-')
21774 .trim_start_matches("0s")
21775 .trim_start_matches('[')
21776 .trim_end_matches(']');
21777
21778 let mut result: i64 = 0;
21779 for part in clean.split(':') {
21780 let digit: i64 = part
21781 .trim()
21782 .parse()
21783 .map_err(|_| RuntimeError::new(format!("Invalid sexagesimal digit: {}", part)))?;
21784 if digit < 0 || digit >= 60 {
21785 return Err(RuntimeError::new(format!(
21786 "Sexagesimal digit out of range: {}",
21787 digit
21788 )));
21789 }
21790 result = result * 60 + digit;
21791 }
21792
21793 Ok(Value::Int(if negative { -result } else { result }))
21794 });
21795
21796 define(interp, "to_duodecimal", Some(1), |_, args| {
21800 let n = match &args[0] {
21801 Value::Int(n) => *n,
21802 _ => return Err(RuntimeError::new("to_duodecimal() requires integer")),
21803 };
21804
21805 let result = to_base_string_custom(n.unsigned_abs(), 12, "0123456789XE");
21806 let prefix = if n < 0 { "-0z" } else { "0z" };
21807 Ok(Value::String(Rc::new(format!("{}{}", prefix, result))))
21808 });
21809
21810 define(interp, "from_duodecimal", Some(1), |_, args| {
21811 let s = match &args[0] {
21812 Value::String(s) => s.to_string(),
21813 _ => return Err(RuntimeError::new("from_duodecimal() requires string")),
21814 };
21815
21816 let (negative, clean) = parse_base_prefix(&s, "0z");
21817 let value = from_base_string_custom(&clean.to_uppercase(), "0123456789XE")?;
21818 Ok(Value::Int(if negative {
21819 -(value as i64)
21820 } else {
21821 value as i64
21822 }))
21823 });
21824
21825 define(interp, "to_base", Some(2), |_, args| {
21828 let n = match &args[0] {
21829 Value::Int(n) => *n,
21830 _ => return Err(RuntimeError::new("to_base() requires integer")),
21831 };
21832 let base = match &args[1] {
21833 Value::Int(b) => *b as u64,
21834 _ => return Err(RuntimeError::new("to_base() requires integer base")),
21835 };
21836
21837 if base < 2 || base > 36 {
21838 return Err(RuntimeError::new("to_base() base must be 2-36"));
21839 }
21840
21841 let result = to_base_string(n.unsigned_abs(), base, false);
21842 let prefix = if n < 0 { "-" } else { "" };
21843 Ok(Value::String(Rc::new(format!("{}{}", prefix, result))))
21844 });
21845
21846 define(interp, "from_base", Some(2), |_, args| {
21847 let s = match &args[0] {
21848 Value::String(s) => s.to_string(),
21849 _ => return Err(RuntimeError::new("from_base() requires string")),
21850 };
21851 let base = match &args[1] {
21852 Value::Int(b) => *b as u64,
21853 _ => return Err(RuntimeError::new("from_base() requires integer base")),
21854 };
21855
21856 if base < 2 || base > 36 {
21857 return Err(RuntimeError::new("from_base() base must be 2-36"));
21858 }
21859
21860 let negative = s.starts_with('-');
21861 let clean = s.trim_start_matches('-');
21862 let value = from_base_string(clean, base)?;
21863 Ok(Value::Int(if negative {
21864 -(value as i64)
21865 } else {
21866 value as i64
21867 }))
21868 });
21869
21870 const BASE58_ALPHABET: &str = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
21875
21876 define(interp, "base58_encode", Some(1), |_, args| {
21877 let bytes: Vec<u8> = match &args[0] {
21878 Value::String(s) => s.as_bytes().to_vec(),
21879 Value::Array(arr) => arr
21880 .borrow()
21881 .iter()
21882 .filter_map(|v| {
21883 if let Value::Int(i) = v {
21884 Some(*i as u8)
21885 } else {
21886 None
21887 }
21888 })
21889 .collect(),
21890 _ => {
21891 return Err(RuntimeError::new(
21892 "base58_encode() requires string or byte array",
21893 ))
21894 }
21895 };
21896
21897 let leading_zeros = bytes.iter().take_while(|&&b| b == 0).count();
21899
21900 let mut result = Vec::new();
21902 let mut num: Vec<u8> = bytes.clone();
21903
21904 while !num.is_empty() && !num.iter().all(|&b| b == 0) {
21905 let mut remainder = 0u32;
21906 let mut new_num = Vec::new();
21907
21908 for &byte in &num {
21909 let acc = (remainder << 8) + byte as u32;
21910 let digit = acc / 58;
21911 remainder = acc % 58;
21912
21913 if !new_num.is_empty() || digit > 0 {
21914 new_num.push(digit as u8);
21915 }
21916 }
21917
21918 result.push(BASE58_ALPHABET.chars().nth(remainder as usize).unwrap());
21919 num = new_num;
21920 }
21921
21922 for _ in 0..leading_zeros {
21924 result.push('1');
21925 }
21926
21927 result.reverse();
21928 Ok(Value::String(Rc::new(result.into_iter().collect())))
21929 });
21930
21931 define(interp, "base58_decode", Some(1), |_, args| {
21932 let s = match &args[0] {
21933 Value::String(s) => s.to_string(),
21934 _ => return Err(RuntimeError::new("base58_decode() requires string")),
21935 };
21936
21937 let leading_ones = s.chars().take_while(|&c| c == '1').count();
21939
21940 let mut num: Vec<u8> = Vec::new();
21942
21943 for c in s.chars() {
21944 let digit = BASE58_ALPHABET
21945 .find(c)
21946 .ok_or_else(|| RuntimeError::new(format!("Invalid base58 character: {}", c)))?;
21947
21948 let mut carry = digit as u32;
21949 for byte in num.iter_mut().rev() {
21950 let acc = (*byte as u32) * 58 + carry;
21951 *byte = (acc & 0xff) as u8;
21952 carry = acc >> 8;
21953 }
21954
21955 while carry > 0 {
21956 num.insert(0, (carry & 0xff) as u8);
21957 carry >>= 8;
21958 }
21959 }
21960
21961 let mut result = vec![0u8; leading_ones];
21963 result.extend(num);
21964
21965 Ok(Value::String(Rc::new(hex::encode(&result))))
21967 });
21968
21969 const BASE32_ALPHABET: &str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
21973
21974 define(interp, "base32_encode", Some(1), |_, args| {
21975 let bytes: Vec<u8> = match &args[0] {
21976 Value::String(s) => s.as_bytes().to_vec(),
21977 Value::Array(arr) => arr
21978 .borrow()
21979 .iter()
21980 .filter_map(|v| {
21981 if let Value::Int(i) = v {
21982 Some(*i as u8)
21983 } else {
21984 None
21985 }
21986 })
21987 .collect(),
21988 _ => {
21989 return Err(RuntimeError::new(
21990 "base32_encode() requires string or byte array",
21991 ))
21992 }
21993 };
21994
21995 let mut result = String::new();
21996 let mut buffer: u64 = 0;
21997 let mut bits = 0;
21998
21999 for byte in bytes {
22000 buffer = (buffer << 8) | byte as u64;
22001 bits += 8;
22002
22003 while bits >= 5 {
22004 bits -= 5;
22005 let idx = ((buffer >> bits) & 0x1f) as usize;
22006 result.push(BASE32_ALPHABET.chars().nth(idx).unwrap());
22007 }
22008 }
22009
22010 if bits > 0 {
22011 let idx = ((buffer << (5 - bits)) & 0x1f) as usize;
22012 result.push(BASE32_ALPHABET.chars().nth(idx).unwrap());
22013 }
22014
22015 while result.len() % 8 != 0 {
22017 result.push('=');
22018 }
22019
22020 Ok(Value::String(Rc::new(result)))
22021 });
22022
22023 define(interp, "base32_decode", Some(1), |_, args| {
22024 let s = match &args[0] {
22025 Value::String(s) => s.to_uppercase().replace('=', ""),
22026 _ => return Err(RuntimeError::new("base32_decode() requires string")),
22027 };
22028
22029 let mut result = Vec::new();
22030 let mut buffer: u64 = 0;
22031 let mut bits = 0;
22032
22033 for c in s.chars() {
22034 let digit = BASE32_ALPHABET
22035 .find(c)
22036 .ok_or_else(|| RuntimeError::new(format!("Invalid base32 character: {}", c)))?;
22037
22038 buffer = (buffer << 5) | digit as u64;
22039 bits += 5;
22040
22041 if bits >= 8 {
22042 bits -= 8;
22043 result.push((buffer >> bits) as u8);
22044 buffer &= (1 << bits) - 1;
22045 }
22046 }
22047
22048 Ok(Value::String(Rc::new(hex::encode(&result))))
22049 });
22050
22051 define(interp, "sacred_numbers", Some(1), |_, args| {
22055 let culture = match &args[0] {
22056 Value::String(s) => s.to_lowercase(),
22057 _ => {
22058 return Err(RuntimeError::new(
22059 "sacred_numbers() requires string culture",
22060 ))
22061 }
22062 };
22063
22064 let numbers: Vec<(i64, &str)> = match culture.as_str() {
22065 "mayan" | "maya" => vec![
22066 (13, "Sacred cycle - Tzolkin calendar"),
22067 (20, "Base of vigesimal system - human digits"),
22068 (52, "Calendar round - 52 years"),
22069 (260, "Tzolkin sacred calendar days"),
22070 (365, "Haab solar calendar days"),
22071 (400, "Baktun - 20×20 years"),
22072 ],
22073 "babylonian" | "mesopotamian" => vec![
22074 (12, "Months, hours - celestial division"),
22075 (60, "Sexagesimal base - minutes, seconds, degrees"),
22076 (360, "Circle degrees - 6×60"),
22077 (3600, "Sar - 60×60, large count"),
22078 (7, "Planets visible to naked eye"),
22079 ],
22080 "chinese" | "zh" => vec![
22081 (8, "八 (bā) - prosperity, wealth (sounds like 發)"),
22082 (9, "九 (jiǔ) - longevity (sounds like 久)"),
22083 (6, "六 (liù) - smooth, flowing"),
22084 (2, "二 (èr) - pairs, harmony"),
22085 (4, "四 (sì) - AVOID - sounds like death (死)"),
22086 (5, "五 (wǔ) - five elements"),
22087 (12, "十二 - zodiac animals"),
22088 ],
22089 "japanese" | "ja" => vec![
22090 (7, "七 (nana) - lucky, seven gods of fortune"),
22091 (8, "八 (hachi) - prosperity, expansion"),
22092 (3, "三 (san) - completeness"),
22093 (5, "五 (go) - five elements"),
22094 (4, "四 (shi) - AVOID - sounds like death (死)"),
22095 (9, "九 (ku) - AVOID - sounds like suffering (苦)"),
22096 ],
22097 "hebrew" | "jewish" => vec![
22098 (7, "Shabbat, creation days, menorah branches"),
22099 (18, "Chai (חי) - life - gematria of ח(8) + י(10)"),
22100 (40, "Transformation - flood, Sinai, wilderness"),
22101 (12, "Tribes of Israel"),
22102 (613, "Mitzvot - commandments"),
22103 (26, "Gematria of YHWH"),
22104 ],
22105 "islamic" | "arabic" | "ar" => vec![
22106 (5, "Pillars of Islam, daily prayers"),
22107 (7, "Heavens, circumambulation of Kaaba"),
22108 (40, "Age of prophethood, days of repentance"),
22109 (99, "Names of Allah"),
22110 (786, "Abjad value of Bismillah"),
22111 ],
22112 "hindu" | "indian" | "hi" => vec![
22113 (108, "Sacred beads, Upanishads, sun's distance"),
22114 (7, "Chakras (main), rishis, sacred rivers"),
22115 (3, "Trimurti - Brahma, Vishnu, Shiva"),
22116 (4, "Vedas, yugas, varnas"),
22117 (9, "Planets (navagraha), durga forms"),
22118 (1008, "Names of Vishnu"),
22119 ],
22120 "greek" | "pythagorean" => vec![
22121 (1, "Monad - unity, source"),
22122 (2, "Dyad - duality, diversity"),
22123 (3, "Triad - harmony, completion"),
22124 (4, "Tetrad - solidity, earth"),
22125 (7, "Heptad - perfection"),
22126 (10, "Decad - tetractys, divine"),
22127 (12, "Olympian gods"),
22128 ],
22129 "celtic" | "irish" => vec![
22130 (3, "Triple goddess, triquetra"),
22131 (5, "Elements including spirit"),
22132 (9, "Triple threes - sacred completion"),
22133 (13, "Lunar months"),
22134 (17, "St. Patrick's Day"),
22135 (20, "Vigesimal counting"),
22136 ],
22137 _ => vec![
22138 (1, "Unity"),
22139 (7, "Widely considered lucky"),
22140 (12, "Dozen - practical division"),
22141 (13, "Often considered unlucky in West"),
22142 ],
22143 };
22144
22145 let result: Vec<Value> = numbers
22146 .iter()
22147 .map(|(n, meaning)| {
22148 let mut entry = std::collections::HashMap::new();
22149 entry.insert("number".to_string(), Value::Int(*n));
22150 entry.insert(
22151 "meaning".to_string(),
22152 Value::String(Rc::new(meaning.to_string())),
22153 );
22154 Value::Map(Rc::new(RefCell::new(entry)))
22155 })
22156 .collect();
22157
22158 Ok(Value::Array(Rc::new(RefCell::new(result))))
22159 });
22160
22161 define(interp, "is_sacred", Some(2), |_, args| {
22163 let n = match &args[0] {
22164 Value::Int(n) => *n,
22165 _ => return Err(RuntimeError::new("is_sacred() requires integer")),
22166 };
22167 let culture = match &args[1] {
22168 Value::String(s) => s.to_lowercase(),
22169 _ => return Err(RuntimeError::new("is_sacred() requires string culture")),
22170 };
22171
22172 let sacred = match culture.as_str() {
22173 "mayan" | "maya" => vec![13, 20, 52, 260, 365, 400],
22174 "babylonian" | "mesopotamian" => vec![12, 60, 360, 3600, 7],
22175 "chinese" | "zh" => vec![8, 9, 6, 2, 5, 12],
22176 "japanese" | "ja" => vec![7, 8, 3, 5],
22177 "hebrew" | "jewish" => vec![7, 18, 40, 12, 613, 26],
22178 "islamic" | "arabic" | "ar" => vec![5, 7, 40, 99, 786],
22179 "hindu" | "indian" | "hi" => vec![108, 7, 3, 4, 9, 1008],
22180 "greek" | "pythagorean" => vec![1, 2, 3, 4, 7, 10, 12],
22181 "celtic" | "irish" => vec![3, 5, 9, 13, 17, 20],
22182 _ => vec![7, 12],
22183 };
22184
22185 Ok(Value::Bool(sacred.contains(&n)))
22186 });
22187
22188 define(interp, "is_unlucky", Some(2), |_, args| {
22190 let n = match &args[0] {
22191 Value::Int(n) => *n,
22192 _ => return Err(RuntimeError::new("is_unlucky() requires integer")),
22193 };
22194 let culture = match &args[1] {
22195 Value::String(s) => s.to_lowercase(),
22196 _ => return Err(RuntimeError::new("is_unlucky() requires string culture")),
22197 };
22198
22199 let unlucky = match culture.as_str() {
22200 "chinese" | "zh" => vec![4], "japanese" | "ja" => vec![4, 9], "western" | "en" => vec![13], "italian" | "it" => vec![17], _ => vec![],
22205 };
22206
22207 Ok(Value::Bool(unlucky.contains(&n)))
22208 });
22209
22210 define(interp, "number_meaning", Some(2), |_, args| {
22212 let n = match &args[0] {
22213 Value::Int(n) => *n,
22214 _ => return Err(RuntimeError::new("number_meaning() requires integer")),
22215 };
22216 let culture = match &args[1] {
22217 Value::String(s) => s.to_lowercase(),
22218 _ => {
22219 return Err(RuntimeError::new(
22220 "number_meaning() requires string culture",
22221 ))
22222 }
22223 };
22224
22225 let meaning = match (n, culture.as_str()) {
22226 (8, "chinese" | "zh") => "八 (bā) - Most auspicious, sounds like 發 (prosperity)",
22228 (4, "chinese" | "zh") => "四 (sì) - Unlucky, sounds like 死 (death)",
22229 (9, "chinese" | "zh") => "九 (jiǔ) - Longevity, sounds like 久 (long-lasting)",
22230 (6, "chinese" | "zh") => "六 (liù) - Smooth and well-off",
22231 (2, "chinese" | "zh") => "二 (èr) - Good things come in pairs",
22232
22233 (7, "japanese" | "ja") => "七 (nana) - Lucky, seven gods of fortune",
22235 (8, "japanese" | "ja") => "八 (hachi) - Lucky, represents spreading prosperity",
22236 (4, "japanese" | "ja") => "四 (shi) - Unlucky, homophone of death",
22237 (9, "japanese" | "ja") => "九 (ku) - Unlucky, homophone of suffering",
22238
22239 (18, "hebrew" | "jewish") => "Chai (חי) - Life itself, most auspicious",
22241 (7, "hebrew" | "jewish") => "Divine completion - Shabbat, menorah, creation",
22242 (40, "hebrew" | "jewish") => "Transformation - flood, Sinai, wilderness years",
22243 (613, "hebrew" | "jewish") => "Taryag - total number of mitzvot (commandments)",
22244
22245 (13, "mayan" | "maya") => "Sacred Tzolkin cycle, celestial layers",
22247 (20, "mayan" | "maya") => "Vigesimal base - fingers and toes, uinal",
22248 (260, "mayan" | "maya") => "Tzolkin calendar - 13 × 20 sacred days",
22249
22250 (60, "babylonian" | "mesopotamian") => {
22252 "Sexagesimal base - divisible by 2,3,4,5,6,10,12,15,20,30"
22253 }
22254 (360, "babylonian" | "mesopotamian") => "Circle degrees - celestial observation",
22255
22256 (108, "hindu" | "indian" | "hi") => {
22258 "Sacred completeness - mala beads, Upanishads, sun ratio"
22259 }
22260 (3, "hindu" | "indian" | "hi") => "Trimurti - Brahma, Vishnu, Shiva",
22261 (9, "hindu" | "indian" | "hi") => "Navagraha (9 planets), Durga's 9 forms",
22262
22263 (99, "islamic" | "arabic" | "ar") => "Asma ul-Husna - 99 names of Allah",
22265 (5, "islamic" | "arabic" | "ar") => "Five pillars of Islam",
22266 (786, "islamic" | "arabic" | "ar") => "Abjad numerology of Bismillah",
22267
22268 (10, "greek" | "pythagorean") => "Tetractys - 1+2+3+4, perfect number",
22270 (7, "greek" | "pythagorean") => "Heptad - virgin number, Athena's number",
22271
22272 _ => "No specific cultural meaning recorded",
22273 };
22274
22275 let mut result = std::collections::HashMap::new();
22276 result.insert("number".to_string(), Value::Int(n));
22277 result.insert("culture".to_string(), Value::String(Rc::new(culture)));
22278 result.insert(
22279 "meaning".to_string(),
22280 Value::String(Rc::new(meaning.to_string())),
22281 );
22282
22283 Ok(Value::Map(Rc::new(RefCell::new(result))))
22284 });
22285
22286 define(interp, "to_babylonian_time", Some(1), |_, args| {
22290 let seconds = match &args[0] {
22291 Value::Int(n) => *n,
22292 Value::Float(f) => *f as i64,
22293 _ => return Err(RuntimeError::new("to_babylonian_time() requires number")),
22294 };
22295
22296 let hours = seconds / 3600;
22297 let mins = (seconds % 3600) / 60;
22298 let secs = seconds % 60;
22299
22300 Ok(Value::String(Rc::new(format!(
22301 "0s[{}:{}:{}]",
22302 hours, mins, secs
22303 ))))
22304 });
22305
22306 define(interp, "from_babylonian_time", Some(1), |_, args| {
22308 let s = match &args[0] {
22309 Value::String(s) => s.to_string(),
22310 _ => return Err(RuntimeError::new("from_babylonian_time() requires string")),
22311 };
22312
22313 let clean = s
22314 .trim_start_matches("0s")
22315 .trim_start_matches('[')
22316 .trim_end_matches(']');
22317
22318 let parts: Vec<i64> = clean
22319 .split(':')
22320 .map(|p| p.trim().parse::<i64>().unwrap_or(0))
22321 .collect();
22322
22323 let seconds = match parts.len() {
22324 1 => parts[0],
22325 2 => parts[0] * 60 + parts[1],
22326 3 => parts[0] * 3600 + parts[1] * 60 + parts[2],
22327 _ => return Err(RuntimeError::new("Invalid Babylonian time format")),
22328 };
22329
22330 Ok(Value::Int(seconds))
22331 });
22332
22333 define(interp, "vigesimal_shares", Some(3), |_, args| {
22337 let secret = match &args[0] {
22338 Value::String(s) => s.as_bytes().to_vec(),
22339 _ => {
22340 return Err(RuntimeError::new(
22341 "vigesimal_shares() requires string secret",
22342 ))
22343 }
22344 };
22345
22346 let threshold = match &args[1] {
22347 Value::Int(n) => *n as usize,
22348 _ => {
22349 return Err(RuntimeError::new(
22350 "vigesimal_shares() requires integer threshold",
22351 ))
22352 }
22353 };
22354
22355 let num_shares = match &args[2] {
22356 Value::Int(n) => *n as usize,
22357 _ => {
22358 return Err(RuntimeError::new(
22359 "vigesimal_shares() requires integer num_shares",
22360 ))
22361 }
22362 };
22363
22364 if threshold < 2 || num_shares < threshold || num_shares > 20 {
22365 return Err(RuntimeError::new(
22366 "vigesimal_shares() requires 2 <= threshold <= num_shares <= 20 (Mayan limit)",
22367 ));
22368 }
22369
22370 let mut rng = rand::thread_rng();
22372 let mut shares: Vec<Vec<u8>> = (0..num_shares)
22373 .map(|_| Vec::with_capacity(secret.len() + 1))
22374 .collect();
22375
22376 for (i, share) in shares.iter_mut().enumerate() {
22377 share.push((i + 1) as u8);
22378 }
22379
22380 for &byte in &secret {
22381 let mut coefficients: Vec<u8> = vec![byte];
22382 for _ in 1..threshold {
22383 coefficients.push(rng.gen());
22384 }
22385
22386 for (i, share) in shares.iter_mut().enumerate() {
22387 let x = (i + 1) as u8;
22388 let y = eval_polynomial_gf256(&coefficients, x);
22389 share.push(y);
22390 }
22391 }
22392
22393 let share_values: Vec<Value> = shares
22395 .iter()
22396 .enumerate()
22397 .map(|(i, share)| {
22398 let mut entry = std::collections::HashMap::new();
22399
22400 let mut vig_parts: Vec<String> = Vec::new();
22402 for &byte in share {
22403 vig_parts.push(to_base_string(byte as u64, 20, true));
22404 }
22405
22406 entry.insert("index".to_string(), Value::Int((i + 1) as i64));
22407 entry.insert(
22408 "vigesimal".to_string(),
22409 Value::String(Rc::new(format!("0v{}", vig_parts.join(".")))),
22410 );
22411 entry.insert(
22412 "hex".to_string(),
22413 Value::String(Rc::new(hex::encode(share))),
22414 );
22415
22416 Value::Map(Rc::new(RefCell::new(entry)))
22417 })
22418 .collect();
22419
22420 let mut result = std::collections::HashMap::new();
22421 result.insert(
22422 "shares".to_string(),
22423 Value::Array(Rc::new(RefCell::new(share_values))),
22424 );
22425 result.insert("threshold".to_string(), Value::Int(threshold as i64));
22426 result.insert("total".to_string(), Value::Int(num_shares as i64));
22427 result.insert(
22428 "base".to_string(),
22429 Value::String(Rc::new("vigesimal (Mayan base-20)".to_string())),
22430 );
22431
22432 Ok(Value::Map(Rc::new(RefCell::new(result))))
22433 });
22434
22435 define(interp, "multibase_info", Some(0), |_, _| {
22437 let mut info = std::collections::HashMap::new();
22438
22439 let bases = vec![
22440 ("binary", 2, "0b", "Modern computing"),
22441 ("octal", 8, "0o", "Unix, historical computing"),
22442 ("decimal", 10, "", "Indo-Arabic global standard"),
22443 (
22444 "duodecimal",
22445 12,
22446 "0z",
22447 "Dozen system - time, music, measurement",
22448 ),
22449 ("hexadecimal", 16, "0x", "Computing, colors, addresses"),
22450 (
22451 "vigesimal",
22452 20,
22453 "0v",
22454 "Mayan, Celtic, Basque - human digits",
22455 ),
22456 (
22457 "sexagesimal",
22458 60,
22459 "0s",
22460 "Babylonian - time, angles, astronomy",
22461 ),
22462 ];
22463
22464 let base_list: Vec<Value> = bases
22465 .iter()
22466 .map(|(name, base, prefix, desc)| {
22467 let mut entry = std::collections::HashMap::new();
22468 entry.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
22469 entry.insert("base".to_string(), Value::Int(*base as i64));
22470 entry.insert(
22471 "prefix".to_string(),
22472 Value::String(Rc::new(prefix.to_string())),
22473 );
22474 entry.insert(
22475 "origin".to_string(),
22476 Value::String(Rc::new(desc.to_string())),
22477 );
22478 Value::Map(Rc::new(RefCell::new(entry)))
22479 })
22480 .collect();
22481
22482 info.insert(
22483 "numeral_systems".to_string(),
22484 Value::Array(Rc::new(RefCell::new(base_list))),
22485 );
22486
22487 let encodings = vec!["base58 (Bitcoin)", "base32 (RFC 4648)", "base64 (standard)"];
22488 let enc_list: Vec<Value> = encodings
22489 .iter()
22490 .map(|s| Value::String(Rc::new(s.to_string())))
22491 .collect();
22492 info.insert(
22493 "special_encodings".to_string(),
22494 Value::Array(Rc::new(RefCell::new(enc_list))),
22495 );
22496
22497 let cultures = vec![
22498 "mayan",
22499 "babylonian",
22500 "chinese",
22501 "japanese",
22502 "hebrew",
22503 "islamic",
22504 "hindu",
22505 "greek",
22506 "celtic",
22507 ];
22508 let cult_list: Vec<Value> = cultures
22509 .iter()
22510 .map(|s| Value::String(Rc::new(s.to_string())))
22511 .collect();
22512 info.insert(
22513 "supported_cultures".to_string(),
22514 Value::Array(Rc::new(RefCell::new(cult_list))),
22515 );
22516
22517 Ok(Value::Map(Rc::new(RefCell::new(info))))
22518 });
22519}
22520
22521fn to_base_string(mut n: u64, base: u64, pad_to_two: bool) -> String {
22524 const DIGITS: &[u8] = b"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
22525
22526 if n == 0 {
22527 return if pad_to_two {
22528 "00".to_string()
22529 } else {
22530 "0".to_string()
22531 };
22532 }
22533
22534 let mut result = Vec::new();
22535 while n > 0 {
22536 result.push(DIGITS[(n % base) as usize] as char);
22537 n /= base;
22538 }
22539
22540 if pad_to_two && result.len() < 2 {
22541 result.push('0');
22542 }
22543
22544 result.reverse();
22545 result.into_iter().collect()
22546}
22547
22548fn to_base_string_custom(mut n: u64, base: u64, digits: &str) -> String {
22549 if n == 0 {
22550 return digits.chars().next().unwrap().to_string();
22551 }
22552
22553 let mut result = Vec::new();
22554 let digit_chars: Vec<char> = digits.chars().collect();
22555
22556 while n > 0 {
22557 result.push(digit_chars[(n % base) as usize]);
22558 n /= base;
22559 }
22560
22561 result.reverse();
22562 result.into_iter().collect()
22563}
22564
22565fn from_base_string(s: &str, base: u64) -> Result<u64, RuntimeError> {
22566 let mut result: u64 = 0;
22567
22568 for c in s.chars() {
22569 let digit = match c {
22570 '0'..='9' => c as u64 - '0' as u64,
22571 'A'..='Z' => c as u64 - 'A' as u64 + 10,
22572 'a'..='z' => c as u64 - 'a' as u64 + 10,
22573 _ => return Err(RuntimeError::new(format!("Invalid digit: {}", c))),
22574 };
22575
22576 if digit >= base {
22577 return Err(RuntimeError::new(format!(
22578 "Digit {} out of range for base {}",
22579 c, base
22580 )));
22581 }
22582
22583 result = result
22584 .checked_mul(base)
22585 .and_then(|r| r.checked_add(digit))
22586 .ok_or_else(|| RuntimeError::new("Number overflow"))?;
22587 }
22588
22589 Ok(result)
22590}
22591
22592fn from_base_string_custom(s: &str, digits: &str) -> Result<u64, RuntimeError> {
22593 let base = digits.len() as u64;
22594 let mut result: u64 = 0;
22595
22596 for c in s.chars() {
22597 let digit = digits
22598 .find(c)
22599 .ok_or_else(|| RuntimeError::new(format!("Invalid digit: {}", c)))?
22600 as u64;
22601
22602 result = result
22603 .checked_mul(base)
22604 .and_then(|r| r.checked_add(digit))
22605 .ok_or_else(|| RuntimeError::new("Number overflow"))?;
22606 }
22607
22608 Ok(result)
22609}
22610
22611fn parse_base_prefix(s: &str, prefix: &str) -> (bool, String) {
22612 let negative = s.starts_with('-');
22613 let clean = s
22614 .trim_start_matches('-')
22615 .trim_start_matches(prefix)
22616 .to_string();
22617 (negative, clean)
22618}
22619
22620fn register_audio(interp: &mut Interpreter) {
22648 define(interp, "tune", Some(3), |_, args| {
22655 let note = match &args[0] {
22656 Value::Int(n) => *n as f64, Value::Float(f) => *f, Value::String(s) => parse_note_name(s)?,
22659 _ => return Err(RuntimeError::new("tune() requires note number or name")),
22660 };
22661
22662 let system = match &args[1] {
22663 Value::String(s) => s.to_lowercase(),
22664 _ => return Err(RuntimeError::new("tune() requires tuning system name")),
22665 };
22666
22667 let root_freq = match &args[2] {
22668 Value::Float(f) => *f,
22669 Value::Int(i) => *i as f64,
22670 _ => return Err(RuntimeError::new("tune() requires root frequency")),
22671 };
22672
22673 let freq = match system.as_str() {
22674 "12tet" | "equal" | "western" => {
22675 root_freq * 2.0_f64.powf((note - 69.0) / 12.0)
22677 }
22678 "24tet" | "quarter" | "arabic" | "maqam" => {
22679 root_freq * 2.0_f64.powf((note - 69.0) / 24.0)
22681 }
22682 "just" | "pure" => {
22683 let interval = ((note - 69.0) % 12.0 + 12.0) % 12.0;
22685 let octave = ((note - 69.0) / 12.0).floor();
22686 let ratio = just_intonation_ratio(interval as i32);
22687 root_freq * ratio * 2.0_f64.powf(octave)
22688 }
22689 "pythagorean" => {
22690 let interval = ((note - 69.0) % 12.0 + 12.0) % 12.0;
22692 let octave = ((note - 69.0) / 12.0).floor();
22693 let ratio = pythagorean_ratio(interval as i32);
22694 root_freq * ratio * 2.0_f64.powf(octave)
22695 }
22696 "meantone" | "quarter_comma" => {
22697 let interval = ((note - 69.0) % 12.0 + 12.0) % 12.0;
22699 let octave = ((note - 69.0) / 12.0).floor();
22700 let ratio = meantone_ratio(interval as i32);
22701 root_freq * ratio * 2.0_f64.powf(octave)
22702 }
22703 "53tet" | "turkish" | "persian" | "comma" => {
22704 root_freq * 2.0_f64.powf((note - 69.0) / 53.0)
22706 }
22707 "22shruti" | "shruti" | "indian" => {
22708 let shruti = (note - 69.0) % 22.0;
22710 let octave = ((note - 69.0) / 22.0).floor();
22711 let ratio = shruti_ratio(shruti as i32);
22712 root_freq * ratio * 2.0_f64.powf(octave)
22713 }
22714 "gamelan_pelog" | "pelog" => {
22715 let degree = ((note - 69.0) % 7.0 + 7.0) % 7.0;
22717 let octave = ((note - 69.0) / 7.0).floor();
22718 let ratio = pelog_ratio(degree as i32);
22719 root_freq * ratio * 2.0_f64.powf(octave)
22720 }
22721 "gamelan_slendro" | "slendro" => {
22722 let degree = ((note - 69.0) % 5.0 + 5.0) % 5.0;
22724 let octave = ((note - 69.0) / 5.0).floor();
22725 let ratio = slendro_ratio(degree as i32);
22726 root_freq * ratio * 2.0_f64.powf(octave)
22727 }
22728 "bohlen_pierce" | "bp" => {
22729 root_freq * 3.0_f64.powf((note - 69.0) / 13.0)
22731 }
22732 _ => {
22733 return Err(RuntimeError::new(format!(
22734 "Unknown tuning system: {}",
22735 system
22736 )))
22737 }
22738 };
22739
22740 Ok(Value::Float(freq))
22741 });
22742
22743 define(interp, "tuning_info", Some(1), |_, args| {
22745 let system = match &args[0] {
22746 Value::String(s) => s.to_lowercase(),
22747 _ => return Err(RuntimeError::new("tuning_info() requires string")),
22748 };
22749
22750 let (name, notes_per_octave, origin, description) = match system.as_str() {
22751 "12tet" | "equal" | "western" => (
22752 "12-TET", 12, "Western (18th century)",
22753 "Equal temperament - every semitone is exactly 2^(1/12). Universal but slightly impure."
22754 ),
22755 "24tet" | "quarter" | "arabic" | "maqam" => (
22756 "24-TET", 24, "Arabic/Turkish",
22757 "Quarter-tone system for maqam music. Enables neutral seconds and other microtones."
22758 ),
22759 "just" | "pure" => (
22760 "Just Intonation", 12, "Ancient (Ptolemy)",
22761 "Pure frequency ratios (3:2 fifth, 5:4 third). Beatless intervals but limited modulation."
22762 ),
22763 "pythagorean" => (
22764 "Pythagorean", 12, "Ancient Greece",
22765 "Built entirely from perfect fifths (3:2). Pure fifths but harsh thirds."
22766 ),
22767 "meantone" | "quarter_comma" => (
22768 "Quarter-Comma Meantone", 12, "Renaissance Europe",
22769 "Tempered fifths for pure major thirds. Beautiful in limited keys."
22770 ),
22771 "53tet" | "turkish" | "persian" | "comma" => (
22772 "53-TET", 53, "Turkish/Persian",
22773 "53 notes per octave. Closely approximates just intonation and allows maqam/dastgah."
22774 ),
22775 "22shruti" | "shruti" | "indian" => (
22776 "22-Shruti", 22, "Indian Classical",
22777 "Ancient Indian system. Each shruti is a 'microtone' - the smallest perceptible interval."
22778 ),
22779 "gamelan_pelog" | "pelog" => (
22780 "Pelog", 7, "Javanese Gamelan",
22781 "Heptatonic scale with unequal steps. Each gamelan has unique tuning - instruments are married."
22782 ),
22783 "gamelan_slendro" | "slendro" => (
22784 "Slendro", 5, "Javanese Gamelan",
22785 "Pentatonic scale, roughly equal steps (~240 cents). Each ensemble uniquely tuned."
22786 ),
22787 "bohlen_pierce" | "bp" => (
22788 "Bohlen-Pierce", 13, "Modern (1970s)",
22789 "Non-octave scale based on 3:1 tritave. Alien but mathematically beautiful."
22790 ),
22791 _ => return Err(RuntimeError::new(format!("Unknown tuning system: {}", system))),
22792 };
22793
22794 let mut info = std::collections::HashMap::new();
22795 info.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
22796 info.insert("notes_per_octave".to_string(), Value::Int(notes_per_octave));
22797 info.insert(
22798 "origin".to_string(),
22799 Value::String(Rc::new(origin.to_string())),
22800 );
22801 info.insert(
22802 "description".to_string(),
22803 Value::String(Rc::new(description.to_string())),
22804 );
22805
22806 Ok(Value::Map(Rc::new(RefCell::new(info))))
22807 });
22808
22809 define(interp, "list_tuning_systems", Some(0), |_, _| {
22811 let systems = vec![
22812 ("12tet", "Western equal temperament", 12),
22813 ("24tet", "Arabic/Turkish quarter-tones", 24),
22814 ("just", "Pure ratio just intonation", 12),
22815 ("pythagorean", "Ancient Greek pure fifths", 12),
22816 ("meantone", "Renaissance quarter-comma", 12),
22817 ("53tet", "Turkish/Persian comma system", 53),
22818 ("22shruti", "Indian microtonal", 22),
22819 ("pelog", "Javanese gamelan 7-note", 7),
22820 ("slendro", "Javanese gamelan 5-note", 5),
22821 ("bohlen_pierce", "Non-octave tritave scale", 13),
22822 ];
22823
22824 let result: Vec<Value> = systems
22825 .iter()
22826 .map(|(name, desc, notes)| {
22827 let mut entry = std::collections::HashMap::new();
22828 entry.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
22829 entry.insert(
22830 "description".to_string(),
22831 Value::String(Rc::new(desc.to_string())),
22832 );
22833 entry.insert("notes_per_octave".to_string(), Value::Int(*notes));
22834 Value::Map(Rc::new(RefCell::new(entry)))
22835 })
22836 .collect();
22837
22838 Ok(Value::Array(Rc::new(RefCell::new(result))))
22839 });
22840
22841 define(interp, "sacred_freq", Some(1), |_, args| {
22847 let name = match &args[0] {
22848 Value::String(s) => s.to_lowercase(),
22849 _ => return Err(RuntimeError::new("sacred_freq() requires string")),
22850 };
22851
22852 let (freq, description) = match name.as_str() {
22853 "om" | "ॐ" | "aum" => (136.1, "Om - Earth year frequency (Cosmic Om)"),
22855 "earth_day" => (194.18, "Earth day - one rotation"),
22856 "earth_year" => (136.1, "Earth year - one orbit (Om frequency)"),
22857 "schumann" | "earth_resonance" => (
22858 7.83,
22859 "Schumann resonance - Earth's electromagnetic heartbeat",
22860 ),
22861
22862 "ut" | "do" | "396" => (396.0, "UT/DO - Liberating guilt and fear"),
22864 "re" | "417" => (417.0, "RE - Undoing situations, facilitating change"),
22865 "mi" | "528" => (528.0, "MI - Transformation, miracles, DNA repair"),
22866 "fa" | "639" => (639.0, "FA - Connecting relationships"),
22867 "sol" | "741" => (741.0, "SOL - Awakening intuition"),
22868 "la" | "852" => (852.0, "LA - Returning to spiritual order"),
22869 "si" | "963" => (963.0, "SI - Divine consciousness, enlightenment"),
22870 "174" => (174.0, "Solfeggio foundation - pain relief"),
22871 "285" => (285.0, "Solfeggio - healing tissue"),
22872
22873 "sun" | "☉" => (126.22, "Sun - ego, vitality, leadership"),
22875 "moon" | "☽" | "☾" => (210.42, "Moon - emotion, intuition, cycles"),
22876 "mercury" | "☿" => (141.27, "Mercury - communication, intellect"),
22877 "venus" | "♀" => (221.23, "Venus - love, beauty, harmony"),
22878 "mars" | "♂" => (144.72, "Mars - energy, action, courage"),
22879 "jupiter" | "♃" => (183.58, "Jupiter - expansion, wisdom, luck"),
22880 "saturn" | "♄" => (147.85, "Saturn - discipline, structure, time"),
22881
22882 "root" | "muladhara" => (256.0, "Root chakra - survival, grounding (C)"),
22884 "sacral" | "svadhisthana" => (288.0, "Sacral chakra - creativity, sexuality (D)"),
22885 "solar" | "manipura" => (320.0, "Solar plexus - will, power (E)"),
22886 "heart" | "anahata" => (341.3, "Heart chakra - love, compassion (F)"),
22887 "throat" | "vishuddha" => (384.0, "Throat chakra - expression, truth (G)"),
22888 "third_eye" | "ajna" => (426.7, "Third eye - intuition, insight (A)"),
22889 "crown" | "sahasrara" => (480.0, "Crown chakra - consciousness, unity (B)"),
22890
22891 "a440" | "iso" => (440.0, "ISO standard concert pitch (1955)"),
22893 "a432" | "verdi" => (
22894 432.0,
22895 "Verdi pitch - 'mathematically consistent with universe'",
22896 ),
22897 "a415" | "baroque" => (415.0, "Baroque pitch - period instrument standard"),
22898 "a466" | "chorton" => (466.0, "Choir pitch - high Baroque German"),
22899
22900 "delta" => (2.0, "Delta waves - deep sleep, healing (0.5-4 Hz)"),
22902 "theta" => (6.0, "Theta waves - meditation, creativity (4-8 Hz)"),
22903 "alpha" => (10.0, "Alpha waves - relaxation, calm focus (8-13 Hz)"),
22904 "beta" => (20.0, "Beta waves - alertness, concentration (13-30 Hz)"),
22905 "gamma" => (40.0, "Gamma waves - insight, peak performance (30-100 Hz)"),
22906
22907 _ => {
22908 return Err(RuntimeError::new(format!(
22909 "Unknown sacred frequency: {}",
22910 name
22911 )))
22912 }
22913 };
22914
22915 let mut result = std::collections::HashMap::new();
22916 result.insert("frequency".to_string(), Value::Float(freq));
22917 result.insert("name".to_string(), Value::String(Rc::new(name)));
22918 result.insert(
22919 "meaning".to_string(),
22920 Value::String(Rc::new(description.to_string())),
22921 );
22922
22923 Ok(Value::Map(Rc::new(RefCell::new(result))))
22924 });
22925
22926 define(interp, "solfeggio", Some(0), |_, _| {
22928 let frequencies = vec![
22929 (174.0, "Foundation", "Pain relief, security"),
22930 (285.0, "Quantum", "Healing tissue, safety"),
22931 (396.0, "UT", "Liberating guilt and fear"),
22932 (417.0, "RE", "Undoing situations, change"),
22933 (528.0, "MI", "Transformation, DNA repair, miracles"),
22934 (639.0, "FA", "Connecting relationships"),
22935 (741.0, "SOL", "Awakening intuition"),
22936 (852.0, "LA", "Spiritual order"),
22937 (963.0, "SI", "Divine consciousness"),
22938 ];
22939
22940 let result: Vec<Value> = frequencies
22941 .iter()
22942 .map(|(freq, name, meaning)| {
22943 let mut entry = std::collections::HashMap::new();
22944 entry.insert("frequency".to_string(), Value::Float(*freq));
22945 entry.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
22946 entry.insert(
22947 "meaning".to_string(),
22948 Value::String(Rc::new(meaning.to_string())),
22949 );
22950 Value::Map(Rc::new(RefCell::new(entry)))
22951 })
22952 .collect();
22953
22954 Ok(Value::Array(Rc::new(RefCell::new(result))))
22955 });
22956
22957 define(interp, "chakras", Some(0), |_, _| {
22959 let chakras = vec![
22960 (
22961 256.0,
22962 "Muladhara",
22963 "Root",
22964 "Red",
22965 "Survival, grounding, stability",
22966 ),
22967 (
22968 288.0,
22969 "Svadhisthana",
22970 "Sacral",
22971 "Orange",
22972 "Creativity, sexuality, emotion",
22973 ),
22974 (
22975 320.0,
22976 "Manipura",
22977 "Solar Plexus",
22978 "Yellow",
22979 "Will, power, self-esteem",
22980 ),
22981 (
22982 341.3,
22983 "Anahata",
22984 "Heart",
22985 "Green",
22986 "Love, compassion, connection",
22987 ),
22988 (
22989 384.0,
22990 "Vishuddha",
22991 "Throat",
22992 "Blue",
22993 "Expression, truth, communication",
22994 ),
22995 (
22996 426.7,
22997 "Ajna",
22998 "Third Eye",
22999 "Indigo",
23000 "Intuition, insight, wisdom",
23001 ),
23002 (
23003 480.0,
23004 "Sahasrara",
23005 "Crown",
23006 "Violet",
23007 "Consciousness, unity, transcendence",
23008 ),
23009 ];
23010
23011 let result: Vec<Value> = chakras
23012 .iter()
23013 .map(|(freq, sanskrit, english, color, meaning)| {
23014 let mut entry = std::collections::HashMap::new();
23015 entry.insert("frequency".to_string(), Value::Float(*freq));
23016 entry.insert(
23017 "sanskrit".to_string(),
23018 Value::String(Rc::new(sanskrit.to_string())),
23019 );
23020 entry.insert(
23021 "english".to_string(),
23022 Value::String(Rc::new(english.to_string())),
23023 );
23024 entry.insert(
23025 "color".to_string(),
23026 Value::String(Rc::new(color.to_string())),
23027 );
23028 entry.insert(
23029 "meaning".to_string(),
23030 Value::String(Rc::new(meaning.to_string())),
23031 );
23032 Value::Map(Rc::new(RefCell::new(entry)))
23033 })
23034 .collect();
23035
23036 Ok(Value::Array(Rc::new(RefCell::new(result))))
23037 });
23038
23039 define(interp, "sine", Some(3), |_, args| {
23047 generate_waveform(&args, |phase| phase.sin())
23048 });
23049
23050 define(interp, "square", Some(3), |_, args| {
23052 generate_waveform(&args, |phase| if phase.sin() >= 0.0 { 1.0 } else { -1.0 })
23053 });
23054
23055 define(interp, "sawtooth", Some(3), |_, args| {
23057 generate_waveform(&args, |phase| {
23058 let normalized = (phase / std::f64::consts::TAU).fract();
23059 2.0 * normalized - 1.0
23060 })
23061 });
23062
23063 define(interp, "triangle", Some(3), |_, args| {
23065 generate_waveform(&args, |phase| {
23066 let normalized = (phase / std::f64::consts::TAU).fract();
23067 if normalized < 0.5 {
23068 4.0 * normalized - 1.0
23069 } else {
23070 3.0 - 4.0 * normalized
23071 }
23072 })
23073 });
23074
23075 define(interp, "noise", Some(1), |_, args| {
23077 let samples = match &args[0] {
23078 Value::Int(n) => *n as usize,
23079 _ => return Err(RuntimeError::new("noise() requires integer sample count")),
23080 };
23081
23082 let mut rng = rand::thread_rng();
23083 let result: Vec<Value> = (0..samples)
23084 .map(|_| Value::Float(rng.gen::<f64>() * 2.0 - 1.0))
23085 .collect();
23086
23087 Ok(Value::Array(Rc::new(RefCell::new(result))))
23088 });
23089
23090 define(interp, "scale", Some(1), |_, args| {
23096 let name = match &args[0] {
23097 Value::String(s) => s.to_lowercase(),
23098 _ => return Err(RuntimeError::new("scale() requires string")),
23099 };
23100
23101 let (intervals, origin, description) = match name.as_str() {
23102 "major" | "ionian" => (
23104 vec![0, 2, 4, 5, 7, 9, 11],
23105 "Western",
23106 "Happy, bright, resolved",
23107 ),
23108 "minor" | "aeolian" => (
23109 vec![0, 2, 3, 5, 7, 8, 10],
23110 "Western",
23111 "Sad, dark, introspective",
23112 ),
23113 "dorian" => (
23114 vec![0, 2, 3, 5, 7, 9, 10],
23115 "Western/Jazz",
23116 "Minor with bright 6th",
23117 ),
23118 "phrygian" => (
23119 vec![0, 1, 3, 5, 7, 8, 10],
23120 "Western/Flamenco",
23121 "Spanish, exotic, tense",
23122 ),
23123 "lydian" => (
23124 vec![0, 2, 4, 6, 7, 9, 11],
23125 "Western",
23126 "Dreamy, floating, ethereal",
23127 ),
23128 "mixolydian" => (vec![0, 2, 4, 5, 7, 9, 10], "Western/Blues", "Bluesy major"),
23129 "locrian" => (vec![0, 1, 3, 5, 6, 8, 10], "Western", "Unstable, dissonant"),
23130
23131 "pentatonic_major" => (vec![0, 2, 4, 7, 9], "Universal", "No dissonance, universal"),
23133 "pentatonic_minor" => (vec![0, 3, 5, 7, 10], "Universal", "Blues foundation"),
23134
23135 "hirajoshi" => (vec![0, 2, 3, 7, 8], "Japanese", "Melancholic, mysterious"),
23137 "insen" => (vec![0, 1, 5, 7, 10], "Japanese", "Dark, zen, contemplative"),
23138 "iwato" => (vec![0, 1, 5, 6, 10], "Japanese", "Most dark and dissonant"),
23139 "kumoi" => (vec![0, 2, 3, 7, 9], "Japanese", "Gentle, peaceful"),
23140 "yo" => (vec![0, 2, 5, 7, 9], "Japanese", "Bright, folk, celebratory"),
23141
23142 "hijaz" => (
23144 vec![0, 1, 4, 5, 7, 8, 11],
23145 "Arabic",
23146 "Exotic, Middle Eastern",
23147 ),
23148 "bayati" => (
23149 vec![0, 1.5 as i32, 3, 5, 7, 8, 10],
23150 "Arabic",
23151 "Quarter-tone, soulful",
23152 ),
23153 "rast" => (
23154 vec![0, 2, 3.5 as i32, 5, 7, 9, 10.5 as i32],
23155 "Arabic",
23156 "Foundation maqam",
23157 ),
23158 "saba" => (
23159 vec![0, 1.5 as i32, 3, 4, 5, 8, 10],
23160 "Arabic",
23161 "Sad, spiritual",
23162 ),
23163
23164 "bhairav" => (
23166 vec![0, 1, 4, 5, 7, 8, 11],
23167 "Indian",
23168 "Morning raga, devotional",
23169 ),
23170 "yaman" | "kalyan" => (vec![0, 2, 4, 6, 7, 9, 11], "Indian", "Evening, romantic"),
23171 "bhairavi" => (
23172 vec![0, 1, 3, 5, 7, 8, 10],
23173 "Indian",
23174 "Concluding raga, devotional",
23175 ),
23176 "todi" => (vec![0, 1, 3, 6, 7, 8, 11], "Indian", "Serious, pathos"),
23177 "marwa" => (vec![0, 1, 4, 6, 7, 9, 11], "Indian", "Evening, longing"),
23178
23179 "blues" => (vec![0, 3, 5, 6, 7, 10], "American", "Blue notes, soul"),
23181
23182 "hungarian_minor" => (vec![0, 2, 3, 6, 7, 8, 11], "Hungarian", "Gypsy, dramatic"),
23184 "romanian" => (vec![0, 2, 3, 6, 7, 9, 10], "Romanian", "Folk, energetic"),
23185
23186 "ahava_raba" | "freygish" => (
23188 vec![0, 1, 4, 5, 7, 8, 10],
23189 "Jewish/Klezmer",
23190 "Cantorial, emotional",
23191 ),
23192 "mi_sheberach" => (vec![0, 2, 3, 6, 7, 9, 10], "Jewish", "Prayer mode"),
23193
23194 "gong" => (vec![0, 2, 4, 7, 9], "Chinese", "Palace mode, major-like"),
23196 "shang" => (vec![0, 2, 5, 7, 9], "Chinese", "Merchant mode"),
23197 "jue" => (vec![0, 3, 5, 7, 10], "Chinese", "Angle mode"),
23198 "zhi" => (vec![0, 2, 5, 7, 10], "Chinese", "Emblem mode"),
23199 "yu" => (vec![0, 3, 5, 8, 10], "Chinese", "Wings mode, minor-like"),
23200
23201 "pelog" => (
23203 vec![0, 1, 3, 7, 8],
23204 "Javanese",
23205 "7-note unequal temperament",
23206 ),
23207 "slendro" => (vec![0, 2, 5, 7, 9], "Javanese", "5-note roughly equal"),
23208
23209 "whole_tone" => (
23211 vec![0, 2, 4, 6, 8, 10],
23212 "Impressionist",
23213 "Dreamlike, no resolution",
23214 ),
23215 "chromatic" => (
23216 vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
23217 "Western",
23218 "All 12 notes",
23219 ),
23220 "diminished" => (vec![0, 2, 3, 5, 6, 8, 9, 11], "Jazz", "Symmetric, tense"),
23221 "augmented" => (vec![0, 3, 4, 7, 8, 11], "Jazz", "Symmetric, floating"),
23222
23223 _ => return Err(RuntimeError::new(format!("Unknown scale: {}", name))),
23224 };
23225
23226 let mut result = std::collections::HashMap::new();
23227 let intervals_values: Vec<Value> =
23228 intervals.iter().map(|&i| Value::Int(i as i64)).collect();
23229 result.insert(
23230 "intervals".to_string(),
23231 Value::Array(Rc::new(RefCell::new(intervals_values))),
23232 );
23233 result.insert(
23234 "origin".to_string(),
23235 Value::String(Rc::new(origin.to_string())),
23236 );
23237 result.insert(
23238 "character".to_string(),
23239 Value::String(Rc::new(description.to_string())),
23240 );
23241 result.insert("name".to_string(), Value::String(Rc::new(name)));
23242
23243 Ok(Value::Map(Rc::new(RefCell::new(result))))
23244 });
23245
23246 define(interp, "list_scales", Some(0), |_, _| {
23248 let mut cultures = std::collections::HashMap::new();
23249
23250 cultures.insert(
23251 "western".to_string(),
23252 Value::Array(Rc::new(RefCell::new(vec![
23253 Value::String(Rc::new("major".to_string())),
23254 Value::String(Rc::new("minor".to_string())),
23255 Value::String(Rc::new("dorian".to_string())),
23256 Value::String(Rc::new("phrygian".to_string())),
23257 Value::String(Rc::new("lydian".to_string())),
23258 Value::String(Rc::new("mixolydian".to_string())),
23259 Value::String(Rc::new("locrian".to_string())),
23260 ]))),
23261 );
23262
23263 cultures.insert(
23264 "japanese".to_string(),
23265 Value::Array(Rc::new(RefCell::new(vec![
23266 Value::String(Rc::new("hirajoshi".to_string())),
23267 Value::String(Rc::new("insen".to_string())),
23268 Value::String(Rc::new("iwato".to_string())),
23269 Value::String(Rc::new("kumoi".to_string())),
23270 Value::String(Rc::new("yo".to_string())),
23271 ]))),
23272 );
23273
23274 cultures.insert(
23275 "arabic".to_string(),
23276 Value::Array(Rc::new(RefCell::new(vec![
23277 Value::String(Rc::new("hijaz".to_string())),
23278 Value::String(Rc::new("bayati".to_string())),
23279 Value::String(Rc::new("rast".to_string())),
23280 Value::String(Rc::new("saba".to_string())),
23281 ]))),
23282 );
23283
23284 cultures.insert(
23285 "indian".to_string(),
23286 Value::Array(Rc::new(RefCell::new(vec![
23287 Value::String(Rc::new("bhairav".to_string())),
23288 Value::String(Rc::new("yaman".to_string())),
23289 Value::String(Rc::new("bhairavi".to_string())),
23290 Value::String(Rc::new("todi".to_string())),
23291 Value::String(Rc::new("marwa".to_string())),
23292 ]))),
23293 );
23294
23295 cultures.insert(
23296 "chinese".to_string(),
23297 Value::Array(Rc::new(RefCell::new(vec![
23298 Value::String(Rc::new("gong".to_string())),
23299 Value::String(Rc::new("shang".to_string())),
23300 Value::String(Rc::new("jue".to_string())),
23301 Value::String(Rc::new("zhi".to_string())),
23302 Value::String(Rc::new("yu".to_string())),
23303 ]))),
23304 );
23305
23306 cultures.insert(
23307 "jewish".to_string(),
23308 Value::Array(Rc::new(RefCell::new(vec![
23309 Value::String(Rc::new("ahava_raba".to_string())),
23310 Value::String(Rc::new("mi_sheberach".to_string())),
23311 ]))),
23312 );
23313
23314 cultures.insert(
23315 "indonesian".to_string(),
23316 Value::Array(Rc::new(RefCell::new(vec![
23317 Value::String(Rc::new("pelog".to_string())),
23318 Value::String(Rc::new("slendro".to_string())),
23319 ]))),
23320 );
23321
23322 Ok(Value::Map(Rc::new(RefCell::new(cultures))))
23323 });
23324
23325 define(interp, "interval_ratio", Some(2), |_, args| {
23331 let semitones = match &args[0] {
23332 Value::Int(n) => *n as f64,
23333 Value::Float(f) => *f,
23334 _ => return Err(RuntimeError::new("interval_ratio() requires number")),
23335 };
23336
23337 let tuning = match &args[1] {
23338 Value::String(s) => s.to_lowercase(),
23339 _ => return Err(RuntimeError::new("interval_ratio() requires tuning system")),
23340 };
23341
23342 let ratio = match tuning.as_str() {
23343 "12tet" | "equal" => 2.0_f64.powf(semitones / 12.0),
23344 "just" => just_intonation_ratio(semitones as i32),
23345 "pythagorean" => pythagorean_ratio(semitones as i32),
23346 _ => 2.0_f64.powf(semitones / 12.0),
23347 };
23348
23349 Ok(Value::Float(ratio))
23350 });
23351
23352 define(interp, "cents_between", Some(2), |_, args| {
23354 let f1 = match &args[0] {
23355 Value::Float(f) => *f,
23356 Value::Int(i) => *i as f64,
23357 _ => return Err(RuntimeError::new("cents_between() requires numbers")),
23358 };
23359 let f2 = match &args[1] {
23360 Value::Float(f) => *f,
23361 Value::Int(i) => *i as f64,
23362 _ => return Err(RuntimeError::new("cents_between() requires numbers")),
23363 };
23364
23365 let cents = 1200.0 * (f2 / f1).log2();
23366 Ok(Value::Float(cents))
23367 });
23368
23369 define(interp, "harmonic_series", Some(2), |_, args| {
23371 let fundamental = match &args[0] {
23372 Value::Float(f) => *f,
23373 Value::Int(i) => *i as f64,
23374 _ => return Err(RuntimeError::new("harmonic_series() requires frequency")),
23375 };
23376 let count = match &args[1] {
23377 Value::Int(n) => *n as usize,
23378 _ => return Err(RuntimeError::new("harmonic_series() requires count")),
23379 };
23380
23381 let harmonics: Vec<Value> = (1..=count)
23382 .map(|n| {
23383 let mut entry = std::collections::HashMap::new();
23384 entry.insert("harmonic".to_string(), Value::Int(n as i64));
23385 entry.insert(
23386 "frequency".to_string(),
23387 Value::Float(fundamental * n as f64),
23388 );
23389 entry.insert(
23390 "cents_from_root".to_string(),
23391 Value::Float(1200.0 * (n as f64).log2()),
23392 );
23393 Value::Map(Rc::new(RefCell::new(entry)))
23394 })
23395 .collect();
23396
23397 Ok(Value::Array(Rc::new(RefCell::new(harmonics))))
23398 });
23399
23400 define(interp, "audio_info", Some(0), |_, _| {
23405 let mut info = std::collections::HashMap::new();
23406
23407 info.insert(
23408 "tuning_systems".to_string(),
23409 Value::Array(Rc::new(RefCell::new(vec![
23410 Value::String(Rc::new(
23411 "12tet, 24tet, just, pythagorean, meantone".to_string(),
23412 )),
23413 Value::String(Rc::new(
23414 "53tet, 22shruti, pelog, slendro, bohlen_pierce".to_string(),
23415 )),
23416 ]))),
23417 );
23418
23419 info.insert(
23420 "waveforms".to_string(),
23421 Value::Array(Rc::new(RefCell::new(vec![
23422 Value::String(Rc::new("sine (∿)".to_string())),
23423 Value::String(Rc::new("square (⊓)".to_string())),
23424 Value::String(Rc::new("sawtooth (⋀)".to_string())),
23425 Value::String(Rc::new("triangle (△)".to_string())),
23426 Value::String(Rc::new("noise".to_string())),
23427 ]))),
23428 );
23429
23430 info.insert(
23431 "sacred_frequencies".to_string(),
23432 Value::Array(Rc::new(RefCell::new(vec![
23433 Value::String(Rc::new("om, solfeggio, chakras, planets".to_string())),
23434 Value::String(Rc::new(
23435 "schumann, brainwaves (delta/theta/alpha/beta/gamma)".to_string(),
23436 )),
23437 ]))),
23438 );
23439
23440 info.insert(
23441 "scale_cultures".to_string(),
23442 Value::Array(Rc::new(RefCell::new(vec![
23443 Value::String(Rc::new("western, japanese, arabic, indian".to_string())),
23444 Value::String(Rc::new("chinese, jewish, indonesian".to_string())),
23445 ]))),
23446 );
23447
23448 Ok(Value::Map(Rc::new(RefCell::new(info))))
23449 });
23450}
23451
23452fn parse_note_name(s: &str) -> Result<f64, RuntimeError> {
23455 let s = s.trim().to_uppercase();
23456 let (note, octave_offset) = if s.ends_with(|c: char| c.is_ascii_digit()) {
23457 let octave: i32 = s.chars().last().unwrap().to_digit(10).unwrap() as i32;
23458 let note_part = &s[..s.len() - 1];
23459 (note_part, (octave - 4) * 12) } else {
23461 (&s[..], 0)
23462 };
23463
23464 let semitone = match note {
23465 "C" => 0,
23466 "C#" | "DB" => 1,
23467 "D" => 2,
23468 "D#" | "EB" => 3,
23469 "E" => 4,
23470 "F" => 5,
23471 "F#" | "GB" => 6,
23472 "G" => 7,
23473 "G#" | "AB" => 8,
23474 "A" => 9,
23475 "A#" | "BB" => 10,
23476 "B" => 11,
23477 _ => return Err(RuntimeError::new(format!("Unknown note: {}", s))),
23478 };
23479
23480 Ok(69.0 + semitone as f64 - 9.0 + octave_offset as f64) }
23482
23483fn just_intonation_ratio(semitones: i32) -> f64 {
23484 match semitones.rem_euclid(12) {
23486 0 => 1.0, 1 => 16.0 / 15.0, 2 => 9.0 / 8.0, 3 => 6.0 / 5.0, 4 => 5.0 / 4.0, 5 => 4.0 / 3.0, 6 => 45.0 / 32.0, 7 => 3.0 / 2.0, 8 => 8.0 / 5.0, 9 => 5.0 / 3.0, 10 => 9.0 / 5.0, 11 => 15.0 / 8.0, _ => 1.0,
23499 }
23500}
23501
23502fn pythagorean_ratio(semitones: i32) -> f64 {
23503 match semitones.rem_euclid(12) {
23505 0 => 1.0,
23506 1 => 256.0 / 243.0,
23507 2 => 9.0 / 8.0,
23508 3 => 32.0 / 27.0,
23509 4 => 81.0 / 64.0,
23510 5 => 4.0 / 3.0,
23511 6 => 729.0 / 512.0,
23512 7 => 3.0 / 2.0,
23513 8 => 128.0 / 81.0,
23514 9 => 27.0 / 16.0,
23515 10 => 16.0 / 9.0,
23516 11 => 243.0 / 128.0,
23517 _ => 1.0,
23518 }
23519}
23520
23521fn meantone_ratio(semitones: i32) -> f64 {
23522 let fifth = 5.0_f64.powf(0.25); match semitones.rem_euclid(12) {
23525 0 => 1.0,
23526 1 => 8.0 / (fifth.powi(5)),
23527 2 => fifth.powi(2) / 2.0,
23528 3 => 4.0 / (fifth.powi(3)),
23529 4 => fifth.powi(4) / 4.0,
23530 5 => 2.0 / fifth,
23531 6 => fifth.powi(6) / 8.0,
23532 7 => fifth,
23533 8 => 8.0 / (fifth.powi(4)),
23534 9 => fifth.powi(3) / 2.0,
23535 10 => 4.0 / (fifth.powi(2)),
23536 11 => fifth.powi(5) / 4.0,
23537 _ => 1.0,
23538 }
23539}
23540
23541fn shruti_ratio(shruti: i32) -> f64 {
23542 let ratios = [
23544 1.0,
23545 256.0 / 243.0,
23546 16.0 / 15.0,
23547 10.0 / 9.0,
23548 9.0 / 8.0,
23549 32.0 / 27.0,
23550 6.0 / 5.0,
23551 5.0 / 4.0,
23552 81.0 / 64.0,
23553 4.0 / 3.0,
23554 27.0 / 20.0,
23555 45.0 / 32.0,
23556 729.0 / 512.0,
23557 3.0 / 2.0,
23558 128.0 / 81.0,
23559 8.0 / 5.0,
23560 5.0 / 3.0,
23561 27.0 / 16.0,
23562 16.0 / 9.0,
23563 9.0 / 5.0,
23564 15.0 / 8.0,
23565 243.0 / 128.0,
23566 ];
23567 ratios[shruti.rem_euclid(22) as usize]
23568}
23569
23570fn pelog_ratio(degree: i32) -> f64 {
23571 let ratios = [1.0, 1.12, 1.26, 1.5, 1.68, 1.89, 2.12];
23573 ratios[degree.rem_euclid(7) as usize]
23574}
23575
23576fn slendro_ratio(degree: i32) -> f64 {
23577 let ratios = [1.0, 1.148, 1.318, 1.516, 1.741];
23579 ratios[degree.rem_euclid(5) as usize]
23580}
23581
23582fn generate_waveform(args: &[Value], wave_fn: fn(f64) -> f64) -> Result<Value, RuntimeError> {
23583 let freq = match &args[0] {
23584 Value::Float(f) => *f,
23585 Value::Int(i) => *i as f64,
23586 _ => return Err(RuntimeError::new("Waveform requires frequency")),
23587 };
23588 let sample_rate = match &args[1] {
23589 Value::Float(f) => *f as usize,
23590 Value::Int(i) => *i as usize,
23591 _ => return Err(RuntimeError::new("Waveform requires sample rate")),
23592 };
23593 let duration = match &args[2] {
23594 Value::Float(f) => *f,
23595 Value::Int(i) => *i as f64,
23596 _ => return Err(RuntimeError::new("Waveform requires duration")),
23597 };
23598
23599 let num_samples = (sample_rate as f64 * duration) as usize;
23600 let samples: Vec<Value> = (0..num_samples)
23601 .map(|i| {
23602 let t = i as f64 / sample_rate as f64;
23603 let phase = 2.0 * std::f64::consts::PI * freq * t;
23604 Value::Float(wave_fn(phase))
23605 })
23606 .collect();
23607
23608 Ok(Value::Array(Rc::new(RefCell::new(samples))))
23609}
23610
23611fn register_spirituality(interp: &mut Interpreter) {
23633 const TRIGRAMS: [(&str, &str, &str, &str, &str); 8] = [
23639 (
23640 "☰",
23641 "乾",
23642 "Heaven",
23643 "Creative",
23644 "strong, initiating, persisting",
23645 ),
23646 (
23647 "☱",
23648 "兌",
23649 "Lake",
23650 "Joyous",
23651 "pleasure, satisfaction, openness",
23652 ),
23653 (
23654 "☲",
23655 "離",
23656 "Fire",
23657 "Clinging",
23658 "clarity, awareness, dependence",
23659 ),
23660 (
23661 "☳",
23662 "震",
23663 "Thunder",
23664 "Arousing",
23665 "movement, initiative, action",
23666 ),
23667 (
23668 "☴",
23669 "巽",
23670 "Wind",
23671 "Gentle",
23672 "penetrating, following, flexible",
23673 ),
23674 ("☵", "坎", "Water", "Abysmal", "danger, flowing, depth"),
23675 (
23676 "☶",
23677 "艮",
23678 "Mountain",
23679 "Keeping Still",
23680 "stopping, resting, meditation",
23681 ),
23682 (
23683 "☷",
23684 "坤",
23685 "Earth",
23686 "Receptive",
23687 "yielding, nurturing, devoted",
23688 ),
23689 ];
23690
23691 define(interp, "trigram", Some(1), |_, args| {
23693 let input = match &args[0] {
23694 Value::Int(n) => (*n as usize).min(7),
23695 Value::String(s) => match s.as_str() {
23696 "☰" | "heaven" | "qian" | "乾" => 0,
23697 "☱" | "lake" | "dui" | "兌" => 1,
23698 "☲" | "fire" | "li" | "離" => 2,
23699 "☳" | "thunder" | "zhen" | "震" => 3,
23700 "☴" | "wind" | "xun" | "巽" => 4,
23701 "☵" | "water" | "kan" | "坎" => 5,
23702 "☶" | "mountain" | "gen" | "艮" => 6,
23703 "☷" | "earth" | "kun" | "坤" => 7,
23704 _ => return Err(RuntimeError::new(format!("Unknown trigram: {}", s))),
23705 },
23706 _ => return Err(RuntimeError::new("trigram() requires number or name")),
23707 };
23708
23709 let (symbol, chinese, english, name, meaning) = TRIGRAMS[input];
23710
23711 let mut result = std::collections::HashMap::new();
23712 result.insert("number".to_string(), Value::Int(input as i64));
23713 result.insert(
23714 "symbol".to_string(),
23715 Value::String(Rc::new(symbol.to_string())),
23716 );
23717 result.insert(
23718 "chinese".to_string(),
23719 Value::String(Rc::new(chinese.to_string())),
23720 );
23721 result.insert(
23722 "english".to_string(),
23723 Value::String(Rc::new(english.to_string())),
23724 );
23725 result.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
23726 result.insert(
23727 "meaning".to_string(),
23728 Value::String(Rc::new(meaning.to_string())),
23729 );
23730
23731 let binary = match input {
23733 0 => "111", 1 => "110", 2 => "101", 3 => "100", 4 => "011", 5 => "010", 6 => "001", 7 => "000", _ => "000",
23742 };
23743 result.insert(
23744 "binary".to_string(),
23745 Value::String(Rc::new(binary.to_string())),
23746 );
23747
23748 Ok(Value::Map(Rc::new(RefCell::new(result))))
23749 });
23750
23751 define(interp, "hexagram", Some(1), |_, args| {
23753 let num = match &args[0] {
23754 Value::Int(n) => ((*n - 1) as usize).min(63),
23755 _ => return Err(RuntimeError::new("hexagram() requires number 1-64")),
23756 };
23757
23758 let hex = &HEXAGRAMS[num];
23759
23760 let mut result = std::collections::HashMap::new();
23761 result.insert("number".to_string(), Value::Int((num + 1) as i64));
23762 result.insert(
23763 "chinese".to_string(),
23764 Value::String(Rc::new(hex.0.to_string())),
23765 );
23766 result.insert(
23767 "pinyin".to_string(),
23768 Value::String(Rc::new(hex.1.to_string())),
23769 );
23770 result.insert(
23771 "english".to_string(),
23772 Value::String(Rc::new(hex.2.to_string())),
23773 );
23774 result.insert(
23775 "judgment".to_string(),
23776 Value::String(Rc::new(hex.3.to_string())),
23777 );
23778 result.insert(
23779 "upper_trigram".to_string(),
23780 Value::String(Rc::new(hex.4.to_string())),
23781 );
23782 result.insert(
23783 "lower_trigram".to_string(),
23784 Value::String(Rc::new(hex.5.to_string())),
23785 );
23786
23787 Ok(Value::Map(Rc::new(RefCell::new(result))))
23788 });
23789
23790 define(interp, "cast_iching", Some(0), |_, _| {
23792 let mut rng = rand::thread_rng();
23793
23794 let mut lines = Vec::new();
23797 let mut hexagram_num = 0u8;
23798 let mut changing_lines = Vec::new();
23799
23800 for i in 0..6 {
23801 let r: f64 = rng.gen();
23803 let line = if r < 0.0625 {
23804 6
23805 }
23806 else if r < 0.3125 {
23808 7
23809 }
23810 else if r < 0.5625 {
23812 8
23813 }
23814 else {
23816 9
23817 }; let is_yang = line == 7 || line == 9;
23820 if is_yang {
23821 hexagram_num |= 1 << i;
23822 }
23823
23824 if line == 6 || line == 9 {
23825 changing_lines.push(i + 1);
23826 }
23827
23828 lines.push(Value::Int(line));
23829 }
23830
23831 let king_wen_num = binary_to_king_wen(hexagram_num) + 1;
23833 let hex = &HEXAGRAMS[(king_wen_num - 1) as usize];
23834
23835 let mut result = std::collections::HashMap::new();
23836 result.insert("hexagram".to_string(), Value::Int(king_wen_num as i64));
23837 result.insert(
23838 "chinese".to_string(),
23839 Value::String(Rc::new(hex.0.to_string())),
23840 );
23841 result.insert(
23842 "english".to_string(),
23843 Value::String(Rc::new(hex.2.to_string())),
23844 );
23845 result.insert(
23846 "judgment".to_string(),
23847 Value::String(Rc::new(hex.3.to_string())),
23848 );
23849 result.insert(
23850 "lines".to_string(),
23851 Value::Array(Rc::new(RefCell::new(lines))),
23852 );
23853
23854 let changing: Vec<Value> = changing_lines.iter().map(|&n| Value::Int(n)).collect();
23855 result.insert(
23856 "changing_lines".to_string(),
23857 Value::Array(Rc::new(RefCell::new(changing))),
23858 );
23859
23860 if !changing_lines.is_empty() {
23862 let mut result_hex = hexagram_num;
23863 for &line in &changing_lines {
23864 result_hex ^= 1 << (line - 1); }
23866 let result_king_wen = binary_to_king_wen(result_hex) + 1;
23867 result.insert(
23868 "transforms_to".to_string(),
23869 Value::Int(result_king_wen as i64),
23870 );
23871 }
23872
23873 Ok(Value::Map(Rc::new(RefCell::new(result))))
23874 });
23875
23876 define(interp, "phi", Some(0), |_, _| {
23882 Ok(Value::Float((1.0 + 5.0_f64.sqrt()) / 2.0))
23883 });
23884
23885 define(interp, "sacred_ratio", Some(1), |_, args| {
23887 let name = match &args[0] {
23888 Value::String(s) => s.to_lowercase(),
23889 _ => return Err(RuntimeError::new("sacred_ratio() requires string")),
23890 };
23891
23892 let (value, symbol, meaning) = match name.as_str() {
23893 "phi" | "φ" | "golden" => (
23894 (1.0 + 5.0_f64.sqrt()) / 2.0,
23895 "φ",
23896 "Golden Ratio - divine proportion found in nature, art, architecture",
23897 ),
23898 "phi_conjugate" | "1/phi" => (
23899 2.0 / (1.0 + 5.0_f64.sqrt()),
23900 "1/φ",
23901 "Golden Ratio conjugate - φ - 1 = 1/φ",
23902 ),
23903 "phi_squared" | "phi2" => (
23904 ((1.0 + 5.0_f64.sqrt()) / 2.0).powi(2),
23905 "φ²",
23906 "Golden Ratio squared - φ + 1 = φ²",
23907 ),
23908 "sqrt_phi" => (
23909 ((1.0 + 5.0_f64.sqrt()) / 2.0).sqrt(),
23910 "√φ",
23911 "Square root of Golden Ratio",
23912 ),
23913 "pi" | "π" => (
23914 std::f64::consts::PI,
23915 "π",
23916 "Circle constant - circumference/diameter, transcendental",
23917 ),
23918 "tau" | "τ" => (
23919 std::f64::consts::TAU,
23920 "τ",
23921 "Full circle constant - 2π, one complete revolution",
23922 ),
23923 "e" | "euler" => (
23924 std::f64::consts::E,
23925 "e",
23926 "Euler's number - natural growth, compound interest",
23927 ),
23928 "sqrt2" | "√2" | "pythagoras" => (
23929 std::f64::consts::SQRT_2,
23930 "√2",
23931 "Pythagorean constant - diagonal of unit square",
23932 ),
23933 "sqrt3" | "√3" | "vesica" => (
23934 3.0_f64.sqrt(),
23935 "√3",
23936 "Vesica Piscis ratio - sacred geometry foundation",
23937 ),
23938 "sqrt5" | "√5" => (
23939 5.0_f64.sqrt(),
23940 "√5",
23941 "Related to Golden Ratio: φ = (1 + √5) / 2",
23942 ),
23943 "silver" | "δs" => (
23944 1.0 + 2.0_f64.sqrt(),
23945 "δs",
23946 "Silver Ratio - related to octagon",
23947 ),
23948 "plastic" | "ρ" => (
23949 1.324717957244746,
23950 "ρ",
23951 "Plastic Number - smallest Pisot number",
23952 ),
23953 "feigenbaum" | "δ" => (
23954 4.669201609102990,
23955 "δ",
23956 "Feigenbaum constant - chaos theory, period doubling",
23957 ),
23958 _ => return Err(RuntimeError::new(format!("Unknown sacred ratio: {}", name))),
23959 };
23960
23961 let mut result = std::collections::HashMap::new();
23962 result.insert("value".to_string(), Value::Float(value));
23963 result.insert(
23964 "symbol".to_string(),
23965 Value::String(Rc::new(symbol.to_string())),
23966 );
23967 result.insert(
23968 "meaning".to_string(),
23969 Value::String(Rc::new(meaning.to_string())),
23970 );
23971
23972 Ok(Value::Map(Rc::new(RefCell::new(result))))
23973 });
23974
23975 define(interp, "fibonacci", Some(1), |_, args| {
23977 let count = match &args[0] {
23978 Value::Int(n) => *n as usize,
23979 _ => return Err(RuntimeError::new("fibonacci() requires count")),
23980 };
23981
23982 let mut seq = Vec::with_capacity(count);
23983 let (mut a, mut b) = (0i64, 1i64);
23984
23985 for _ in 0..count {
23986 seq.push(Value::Int(a));
23987 let next = a.saturating_add(b);
23988 a = b;
23989 b = next;
23990 }
23991
23992 Ok(Value::Array(Rc::new(RefCell::new(seq))))
23993 });
23994
23995 define(interp, "is_fibonacci", Some(1), |_, args| {
23997 let n = match &args[0] {
23998 Value::Int(n) => *n,
23999 _ => return Err(RuntimeError::new("is_fibonacci() requires integer")),
24000 };
24001
24002 fn is_perfect_square(n: i64) -> bool {
24004 if n < 0 {
24005 return false;
24006 }
24007 let root = (n as f64).sqrt() as i64;
24008 root * root == n
24009 }
24010
24011 let n_sq = n.saturating_mul(n);
24012 let test1 = 5i64.saturating_mul(n_sq).saturating_add(4);
24013 let test2 = 5i64.saturating_mul(n_sq).saturating_sub(4);
24014
24015 Ok(Value::Bool(
24016 is_perfect_square(test1) || is_perfect_square(test2),
24017 ))
24018 });
24019
24020 define(interp, "platonic_solid", Some(1), |_, args| {
24022 let name = match &args[0] {
24023 Value::String(s) => s.to_lowercase(),
24024 _ => return Err(RuntimeError::new("platonic_solid() requires string")),
24025 };
24026
24027 let (faces, vertices, edges, face_shape, element, meaning) = match name.as_str() {
24028 "tetrahedron" | "fire" => (
24029 4,
24030 4,
24031 6,
24032 "triangle",
24033 "Fire",
24034 "Sharpness, heat, transformation",
24035 ),
24036 "cube" | "hexahedron" | "earth" => (
24037 6,
24038 8,
24039 12,
24040 "square",
24041 "Earth",
24042 "Stability, grounding, material",
24043 ),
24044 "octahedron" | "air" => (
24045 8,
24046 6,
24047 12,
24048 "triangle",
24049 "Air",
24050 "Balance, intellect, communication",
24051 ),
24052 "dodecahedron" | "aether" | "spirit" => (
24053 12,
24054 20,
24055 30,
24056 "pentagon",
24057 "Aether/Spirit",
24058 "The cosmos, divine thought",
24059 ),
24060 "icosahedron" | "water" => (
24061 20,
24062 12,
24063 30,
24064 "triangle",
24065 "Water",
24066 "Flow, emotion, adaptability",
24067 ),
24068 _ => {
24069 return Err(RuntimeError::new(format!(
24070 "Unknown Platonic solid: {}",
24071 name
24072 )))
24073 }
24074 };
24075
24076 let mut result = std::collections::HashMap::new();
24077 result.insert("name".to_string(), Value::String(Rc::new(name)));
24078 result.insert("faces".to_string(), Value::Int(faces));
24079 result.insert("vertices".to_string(), Value::Int(vertices));
24080 result.insert("edges".to_string(), Value::Int(edges));
24081 result.insert(
24082 "face_shape".to_string(),
24083 Value::String(Rc::new(face_shape.to_string())),
24084 );
24085 result.insert(
24086 "element".to_string(),
24087 Value::String(Rc::new(element.to_string())),
24088 );
24089 result.insert(
24090 "meaning".to_string(),
24091 Value::String(Rc::new(meaning.to_string())),
24092 );
24093
24094 result.insert("euler_characteristic".to_string(), Value::Int(2));
24096
24097 Ok(Value::Map(Rc::new(RefCell::new(result))))
24098 });
24099
24100 define(interp, "gematria", Some(2), |_, args| {
24106 let text = match &args[0] {
24107 Value::String(s) => s.to_string(),
24108 _ => return Err(RuntimeError::new("gematria() requires string")),
24109 };
24110
24111 let system = match &args[1] {
24112 Value::String(s) => s.to_lowercase(),
24113 _ => return Err(RuntimeError::new("gematria() requires system name")),
24114 };
24115
24116 let total: i64 = match system.as_str() {
24117 "hebrew" | "kabbalah" => text.chars().map(|c| hebrew_gematria(c)).sum(),
24118 "greek" | "isopsephy" => text.chars().map(|c| greek_isopsephy(c)).sum(),
24119 "arabic" | "abjad" => text.chars().map(|c| arabic_abjad(c)).sum(),
24120 "english" | "simple" => {
24121 text.to_uppercase()
24123 .chars()
24124 .filter_map(|c| {
24125 if c.is_ascii_alphabetic() {
24126 Some((c as i64) - ('A' as i64) + 1)
24127 } else {
24128 None
24129 }
24130 })
24131 .sum()
24132 }
24133 "english_ordinal" => {
24134 text.to_uppercase()
24136 .chars()
24137 .filter_map(|c| {
24138 if c.is_ascii_alphabetic() {
24139 Some((c as i64) - ('A' as i64) + 1)
24140 } else {
24141 None
24142 }
24143 })
24144 .sum()
24145 }
24146 "english_reduction" => {
24147 text.to_uppercase()
24149 .chars()
24150 .filter_map(|c| {
24151 if c.is_ascii_alphabetic() {
24152 let val = ((c as i64) - ('A' as i64)) % 9 + 1;
24153 Some(val)
24154 } else {
24155 None
24156 }
24157 })
24158 .sum()
24159 }
24160 _ => {
24161 return Err(RuntimeError::new(format!(
24162 "Unknown gematria system: {}",
24163 system
24164 )))
24165 }
24166 };
24167
24168 let mut result = std::collections::HashMap::new();
24169 result.insert("text".to_string(), Value::String(Rc::new(text)));
24170 result.insert("system".to_string(), Value::String(Rc::new(system)));
24171 result.insert("value".to_string(), Value::Int(total));
24172
24173 let mut digital_root = total;
24175 while digital_root > 9 {
24176 digital_root = digital_root
24177 .to_string()
24178 .chars()
24179 .filter_map(|c| c.to_digit(10))
24180 .map(|d| d as i64)
24181 .sum();
24182 }
24183 result.insert("digital_root".to_string(), Value::Int(digital_root));
24184
24185 Ok(Value::Map(Rc::new(RefCell::new(result))))
24186 });
24187
24188 define(interp, "gematria_match", Some(2), |_, args| {
24190 let value = match &args[0] {
24191 Value::Int(n) => *n,
24192 _ => return Err(RuntimeError::new("gematria_match() requires integer value")),
24193 };
24194
24195 let system = match &args[1] {
24196 Value::String(s) => s.to_lowercase(),
24197 _ => return Err(RuntimeError::new("gematria_match() requires system name")),
24198 };
24199
24200 let matches = match (value, system.as_str()) {
24202 (26, "hebrew") => vec!["יהוה (YHWH - Tetragrammaton)"],
24203 (18, "hebrew") => vec!["חי (Chai - Life)"],
24204 (86, "hebrew") => vec!["אלהים (Elohim - God)"],
24205 (72, "hebrew") => vec!["חסד (Chesed - Loving-kindness)"],
24206 (93, "english") => vec!["Love", "Will", "Thelema"],
24207 (666, "greek") => vec!["Nero Caesar (in Hebrew letters)"],
24208 (888, "greek") => vec!["Ἰησοῦς (Jesus)"],
24209 _ => vec![],
24210 };
24211
24212 let match_values: Vec<Value> = matches
24213 .iter()
24214 .map(|s| Value::String(Rc::new(s.to_string())))
24215 .collect();
24216
24217 Ok(Value::Array(Rc::new(RefCell::new(match_values))))
24218 });
24219
24220 define(interp, "archetype", Some(1), |_, args| {
24226 let name = match &args[0] {
24227 Value::String(s) => s.to_lowercase(),
24228 _ => return Err(RuntimeError::new("archetype() requires string")),
24229 };
24230
24231 let (description, shadow, gift, challenge) = match name.as_str() {
24232 "self" => (
24234 "The unified conscious and unconscious, the goal of individuation",
24235 "Inflation or deflation of ego",
24236 "Wholeness, integration, meaning",
24237 "Integrating all aspects of psyche",
24238 ),
24239 "shadow" => (
24240 "The unconscious aspect containing repressed weaknesses and instincts",
24241 "Projection onto others, denial",
24242 "Creativity, spontaneity, insight",
24243 "Acknowledging and integrating darkness",
24244 ),
24245 "anima" => (
24246 "The feminine inner personality in a man's unconscious",
24247 "Moodiness, seduction, possession",
24248 "Relatedness, creativity, soul connection",
24249 "Developing emotional intelligence",
24250 ),
24251 "animus" => (
24252 "The masculine inner personality in a woman's unconscious",
24253 "Brutality, reckless action, opinionation",
24254 "Courage, initiative, spiritual depth",
24255 "Developing assertiveness with wisdom",
24256 ),
24257 "persona" => (
24258 "The social mask, the face we present to the world",
24259 "Over-identification, inauthenticity",
24260 "Social adaptation, professional competence",
24261 "Maintaining authenticity within role",
24262 ),
24263
24264 "hero" => (
24266 "The courageous one who overcomes obstacles and achieves great deeds",
24267 "Arrogance, ruthlessness, eternal battle",
24268 "Courage, perseverance, accomplishment",
24269 "Knowing when to fight and when to surrender",
24270 ),
24271 "sage" | "wise_old_man" => (
24272 "The wise figure who offers guidance and insight",
24273 "Dogmatism, disconnection, ivory tower",
24274 "Wisdom, knowledge, truth-seeking",
24275 "Applying wisdom practically",
24276 ),
24277 "magician" | "wizard" => (
24278 "The transformer who makes things happen through understanding laws",
24279 "Manipulation, disconnection from ethics",
24280 "Transformation, vision, manifestation",
24281 "Using power responsibly",
24282 ),
24283 "lover" => (
24284 "The one who pursues connection, beauty, and passion",
24285 "Obsession, jealousy, loss of identity",
24286 "Passion, commitment, appreciation",
24287 "Maintaining boundaries while connecting deeply",
24288 ),
24289 "caregiver" | "mother" => (
24290 "The nurturing one who protects and provides",
24291 "Martyrdom, enabling, smothering",
24292 "Compassion, generosity, nurturing",
24293 "Caring for self while caring for others",
24294 ),
24295 "ruler" | "king" | "queen" => (
24296 "The one who takes responsibility for the realm",
24297 "Tyranny, authoritarianism, being overthrown",
24298 "Order, leadership, prosperity",
24299 "Serving the greater good, not just power",
24300 ),
24301 "creator" | "artist" => (
24302 "The one who brings new things into being",
24303 "Perfectionism, self-indulgence, drama",
24304 "Creativity, imagination, expression",
24305 "Completing projects, accepting imperfection",
24306 ),
24307 "innocent" | "child" => (
24308 "The pure one with faith and optimism",
24309 "Naivety, denial, dependence",
24310 "Faith, optimism, loyalty",
24311 "Growing without becoming cynical",
24312 ),
24313 "explorer" | "seeker" => (
24314 "The one who seeks new experiences and self-discovery",
24315 "Aimless wandering, inability to commit",
24316 "Autonomy, ambition, authenticity",
24317 "Finding what you seek",
24318 ),
24319 "rebel" | "outlaw" => (
24320 "The one who breaks rules and challenges the status quo",
24321 "Crime, self-destruction, alienation",
24322 "Liberation, revolution, radical freedom",
24323 "Channeling rebellion constructively",
24324 ),
24325 "jester" | "fool" | "trickster" => (
24326 "The one who uses humor and playfulness",
24327 "Cruelty, debauchery, irresponsibility",
24328 "Joy, freedom, living in the moment",
24329 "Knowing when to be serious",
24330 ),
24331 "everyman" | "orphan" => (
24332 "The regular person who wants belonging",
24333 "Victim mentality, losing self in group",
24334 "Realism, empathy, connection",
24335 "Standing out when necessary",
24336 ),
24337 _ => return Err(RuntimeError::new(format!("Unknown archetype: {}", name))),
24338 };
24339
24340 let mut result = std::collections::HashMap::new();
24341 result.insert("name".to_string(), Value::String(Rc::new(name)));
24342 result.insert(
24343 "description".to_string(),
24344 Value::String(Rc::new(description.to_string())),
24345 );
24346 result.insert(
24347 "shadow".to_string(),
24348 Value::String(Rc::new(shadow.to_string())),
24349 );
24350 result.insert("gift".to_string(), Value::String(Rc::new(gift.to_string())));
24351 result.insert(
24352 "challenge".to_string(),
24353 Value::String(Rc::new(challenge.to_string())),
24354 );
24355
24356 Ok(Value::Map(Rc::new(RefCell::new(result))))
24357 });
24358
24359 define(interp, "zodiac", Some(1), |_, args| {
24365 let input = match &args[0] {
24366 Value::Int(n) => (*n as usize - 1).min(11),
24367 Value::String(s) => match s.to_lowercase().as_str() {
24368 "aries" | "♈" => 0,
24369 "taurus" | "♉" => 1,
24370 "gemini" | "♊" => 2,
24371 "cancer" | "♋" => 3,
24372 "leo" | "♌" => 4,
24373 "virgo" | "♍" => 5,
24374 "libra" | "♎" => 6,
24375 "scorpio" | "♏" => 7,
24376 "sagittarius" | "♐" => 8,
24377 "capricorn" | "♑" => 9,
24378 "aquarius" | "♒" => 10,
24379 "pisces" | "♓" => 11,
24380 _ => return Err(RuntimeError::new(format!("Unknown sign: {}", s))),
24381 },
24382 _ => return Err(RuntimeError::new("zodiac() requires number or name")),
24383 };
24384
24385 let signs = [
24386 (
24387 "♈",
24388 "Aries",
24389 "Fire",
24390 "Cardinal",
24391 "Mars",
24392 "I Am",
24393 "Mar 21 - Apr 19",
24394 ),
24395 (
24396 "♉",
24397 "Taurus",
24398 "Earth",
24399 "Fixed",
24400 "Venus",
24401 "I Have",
24402 "Apr 20 - May 20",
24403 ),
24404 (
24405 "♊",
24406 "Gemini",
24407 "Air",
24408 "Mutable",
24409 "Mercury",
24410 "I Think",
24411 "May 21 - Jun 20",
24412 ),
24413 (
24414 "♋",
24415 "Cancer",
24416 "Water",
24417 "Cardinal",
24418 "Moon",
24419 "I Feel",
24420 "Jun 21 - Jul 22",
24421 ),
24422 (
24423 "♌",
24424 "Leo",
24425 "Fire",
24426 "Fixed",
24427 "Sun",
24428 "I Will",
24429 "Jul 23 - Aug 22",
24430 ),
24431 (
24432 "♍",
24433 "Virgo",
24434 "Earth",
24435 "Mutable",
24436 "Mercury",
24437 "I Analyze",
24438 "Aug 23 - Sep 22",
24439 ),
24440 (
24441 "♎",
24442 "Libra",
24443 "Air",
24444 "Cardinal",
24445 "Venus",
24446 "I Balance",
24447 "Sep 23 - Oct 22",
24448 ),
24449 (
24450 "♏",
24451 "Scorpio",
24452 "Water",
24453 "Fixed",
24454 "Pluto/Mars",
24455 "I Transform",
24456 "Oct 23 - Nov 21",
24457 ),
24458 (
24459 "♐",
24460 "Sagittarius",
24461 "Fire",
24462 "Mutable",
24463 "Jupiter",
24464 "I Seek",
24465 "Nov 22 - Dec 21",
24466 ),
24467 (
24468 "♑",
24469 "Capricorn",
24470 "Earth",
24471 "Cardinal",
24472 "Saturn",
24473 "I Use",
24474 "Dec 22 - Jan 19",
24475 ),
24476 (
24477 "♒",
24478 "Aquarius",
24479 "Air",
24480 "Fixed",
24481 "Uranus/Saturn",
24482 "I Know",
24483 "Jan 20 - Feb 18",
24484 ),
24485 (
24486 "♓",
24487 "Pisces",
24488 "Water",
24489 "Mutable",
24490 "Neptune/Jupiter",
24491 "I Believe",
24492 "Feb 19 - Mar 20",
24493 ),
24494 ];
24495
24496 let (symbol, name, element, modality, ruler, motto, dates) = signs[input];
24497
24498 let mut result = std::collections::HashMap::new();
24499 result.insert("number".to_string(), Value::Int((input + 1) as i64));
24500 result.insert(
24501 "symbol".to_string(),
24502 Value::String(Rc::new(symbol.to_string())),
24503 );
24504 result.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
24505 result.insert(
24506 "element".to_string(),
24507 Value::String(Rc::new(element.to_string())),
24508 );
24509 result.insert(
24510 "modality".to_string(),
24511 Value::String(Rc::new(modality.to_string())),
24512 );
24513 result.insert(
24514 "ruler".to_string(),
24515 Value::String(Rc::new(ruler.to_string())),
24516 );
24517 result.insert(
24518 "motto".to_string(),
24519 Value::String(Rc::new(motto.to_string())),
24520 );
24521 result.insert(
24522 "dates".to_string(),
24523 Value::String(Rc::new(dates.to_string())),
24524 );
24525
24526 Ok(Value::Map(Rc::new(RefCell::new(result))))
24527 });
24528
24529 define(interp, "tarot_major", Some(1), |_, args| {
24531 let num = match &args[0] {
24532 Value::Int(n) => (*n as usize).min(21),
24533 Value::String(s) => match s.to_lowercase().as_str() {
24534 "fool" => 0,
24535 "magician" => 1,
24536 "high_priestess" | "priestess" => 2,
24537 "empress" => 3,
24538 "emperor" => 4,
24539 "hierophant" | "pope" => 5,
24540 "lovers" => 6,
24541 "chariot" => 7,
24542 "strength" => 8,
24543 "hermit" => 9,
24544 "wheel" | "fortune" => 10,
24545 "justice" => 11,
24546 "hanged_man" | "hanged" => 12,
24547 "death" => 13,
24548 "temperance" => 14,
24549 "devil" => 15,
24550 "tower" => 16,
24551 "star" => 17,
24552 "moon" => 18,
24553 "sun" => 19,
24554 "judgement" | "judgment" => 20,
24555 "world" => 21,
24556 _ => return Err(RuntimeError::new(format!("Unknown card: {}", s))),
24557 },
24558 _ => return Err(RuntimeError::new("tarot_major() requires number or name")),
24559 };
24560
24561 let cards = [
24562 (
24563 "The Fool",
24564 "New beginnings, innocence, spontaneity",
24565 "Naivety, recklessness, risk-taking",
24566 ),
24567 (
24568 "The Magician",
24569 "Willpower, creation, manifestation",
24570 "Manipulation, trickery, unused talent",
24571 ),
24572 (
24573 "The High Priestess",
24574 "Intuition, mystery, inner knowledge",
24575 "Secrets, withdrawal, silence",
24576 ),
24577 (
24578 "The Empress",
24579 "Abundance, nurturing, fertility",
24580 "Dependence, smothering, emptiness",
24581 ),
24582 (
24583 "The Emperor",
24584 "Authority, structure, control",
24585 "Tyranny, rigidity, coldness",
24586 ),
24587 (
24588 "The Hierophant",
24589 "Tradition, conformity, spirituality",
24590 "Dogma, restriction, challenging status quo",
24591 ),
24592 (
24593 "The Lovers",
24594 "Love, harmony, relationships, choices",
24595 "Disharmony, imbalance, misalignment",
24596 ),
24597 (
24598 "The Chariot",
24599 "Direction, willpower, victory",
24600 "Aggression, lack of direction, obstacles",
24601 ),
24602 (
24603 "Strength",
24604 "Courage, patience, inner power",
24605 "Self-doubt, weakness, insecurity",
24606 ),
24607 (
24608 "The Hermit",
24609 "Contemplation, search for truth, inner guidance",
24610 "Isolation, loneliness, withdrawal",
24611 ),
24612 (
24613 "Wheel of Fortune",
24614 "Change, cycles, fate, destiny",
24615 "Resistance to change, bad luck, setbacks",
24616 ),
24617 (
24618 "Justice",
24619 "Truth, fairness, law, cause and effect",
24620 "Unfairness, dishonesty, lack of accountability",
24621 ),
24622 (
24623 "The Hanged Man",
24624 "Surrender, letting go, new perspective",
24625 "Stalling, resistance, indecision",
24626 ),
24627 (
24628 "Death",
24629 "Endings, transformation, transition",
24630 "Fear of change, stagnation, decay",
24631 ),
24632 (
24633 "Temperance",
24634 "Balance, moderation, patience",
24635 "Imbalance, excess, lack of purpose",
24636 ),
24637 (
24638 "The Devil",
24639 "Bondage, materialism, shadow self",
24640 "Freedom, release, exploring dark side",
24641 ),
24642 (
24643 "The Tower",
24644 "Sudden change, upheaval, revelation",
24645 "Disaster averted, fear of change, prolonged pain",
24646 ),
24647 (
24648 "The Star",
24649 "Hope, faith, renewal, inspiration",
24650 "Despair, disconnection, lack of faith",
24651 ),
24652 (
24653 "The Moon",
24654 "Illusion, intuition, the unconscious",
24655 "Fear, confusion, misinterpretation",
24656 ),
24657 (
24658 "The Sun",
24659 "Joy, success, vitality, positivity",
24660 "Negativity, depression, sadness",
24661 ),
24662 (
24663 "Judgement",
24664 "Rebirth, inner calling, absolution",
24665 "Self-doubt, refusal of self-examination",
24666 ),
24667 (
24668 "The World",
24669 "Completion, accomplishment, wholeness",
24670 "Incompletion, lack of closure, emptiness",
24671 ),
24672 ];
24673
24674 let (name, upright, reversed) = cards[num];
24675
24676 let mut result = std::collections::HashMap::new();
24677 result.insert("number".to_string(), Value::Int(num as i64));
24678 result.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
24679 result.insert(
24680 "upright".to_string(),
24681 Value::String(Rc::new(upright.to_string())),
24682 );
24683 result.insert(
24684 "reversed".to_string(),
24685 Value::String(Rc::new(reversed.to_string())),
24686 );
24687
24688 Ok(Value::Map(Rc::new(RefCell::new(result))))
24689 });
24690
24691 define(interp, "draw_tarot", Some(0), |_, _| {
24693 let mut rng = rand::thread_rng();
24694 let card: usize = rng.gen_range(0..22);
24695 let reversed: bool = rng.gen();
24696
24697 let cards = [
24698 "The Fool",
24699 "The Magician",
24700 "The High Priestess",
24701 "The Empress",
24702 "The Emperor",
24703 "The Hierophant",
24704 "The Lovers",
24705 "The Chariot",
24706 "Strength",
24707 "The Hermit",
24708 "Wheel of Fortune",
24709 "Justice",
24710 "The Hanged Man",
24711 "Death",
24712 "Temperance",
24713 "The Devil",
24714 "The Tower",
24715 "The Star",
24716 "The Moon",
24717 "The Sun",
24718 "Judgement",
24719 "The World",
24720 ];
24721
24722 let mut result = std::collections::HashMap::new();
24723 result.insert("number".to_string(), Value::Int(card as i64));
24724 result.insert(
24725 "name".to_string(),
24726 Value::String(Rc::new(cards[card].to_string())),
24727 );
24728 result.insert("reversed".to_string(), Value::Bool(reversed));
24729 result.insert(
24730 "orientation".to_string(),
24731 Value::String(Rc::new(
24732 if reversed { "reversed" } else { "upright" }.to_string(),
24733 )),
24734 );
24735
24736 Ok(Value::Map(Rc::new(RefCell::new(result))))
24737 });
24738
24739 define(interp, "synchronicity_score", Some(2), |_, args| {
24745 let a = match &args[0] {
24747 Value::String(s) => s.to_string(),
24748 Value::Int(n) => n.to_string(),
24749 _ => {
24750 return Err(RuntimeError::new(
24751 "synchronicity_score() requires string or int",
24752 ))
24753 }
24754 };
24755
24756 let b = match &args[1] {
24757 Value::String(s) => s.to_string(),
24758 Value::Int(n) => n.to_string(),
24759 _ => {
24760 return Err(RuntimeError::new(
24761 "synchronicity_score() requires string or int",
24762 ))
24763 }
24764 };
24765
24766 let val_a: i64 = a
24768 .to_uppercase()
24769 .chars()
24770 .filter_map(|c| {
24771 if c.is_ascii_alphabetic() {
24772 Some((c as i64) - ('A' as i64) + 1)
24773 } else if c.is_ascii_digit() {
24774 c.to_digit(10).map(|d| d as i64)
24775 } else {
24776 None
24777 }
24778 })
24779 .sum();
24780
24781 let val_b: i64 = b
24782 .to_uppercase()
24783 .chars()
24784 .filter_map(|c| {
24785 if c.is_ascii_alphabetic() {
24786 Some((c as i64) - ('A' as i64) + 1)
24787 } else if c.is_ascii_digit() {
24788 c.to_digit(10).map(|d| d as i64)
24789 } else {
24790 None
24791 }
24792 })
24793 .sum();
24794
24795 let mut factors = Vec::new();
24797
24798 if val_a == val_b {
24800 factors.push("identical_gematria".to_string());
24801 }
24802
24803 if val_a > 0 && val_b > 0 && (val_a % val_b == 0 || val_b % val_a == 0) {
24805 factors.push("divisibility".to_string());
24806 }
24807
24808 let fib_set: std::collections::HashSet<i64> =
24810 [1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987]
24811 .iter()
24812 .cloned()
24813 .collect();
24814 if fib_set.contains(&val_a) && fib_set.contains(&val_b) {
24815 factors.push("both_fibonacci".to_string());
24816 }
24817
24818 fn digital_root(mut n: i64) -> i64 {
24820 while n > 9 {
24821 n = n
24822 .to_string()
24823 .chars()
24824 .filter_map(|c| c.to_digit(10))
24825 .map(|d| d as i64)
24826 .sum();
24827 }
24828 n
24829 }
24830 if digital_root(val_a) == digital_root(val_b) {
24831 factors.push("same_digital_root".to_string());
24832 }
24833
24834 let phi = (1.0 + 5.0_f64.sqrt()) / 2.0;
24836 let ratio = if val_a > 0 && val_b > 0 {
24837 (val_a as f64 / val_b as f64).max(val_b as f64 / val_a as f64)
24838 } else {
24839 0.0
24840 };
24841 if (ratio - phi).abs() < 0.02 || (ratio - 1.0 / phi).abs() < 0.02 {
24842 factors.push("golden_ratio".to_string());
24843 }
24844
24845 let score = (factors.len() as f64 / 5.0).min(1.0);
24846
24847 let mut result = std::collections::HashMap::new();
24848 result.insert("score".to_string(), Value::Float(score));
24849 result.insert("value_a".to_string(), Value::Int(val_a));
24850 result.insert("value_b".to_string(), Value::Int(val_b));
24851 let factor_values: Vec<Value> = factors
24852 .iter()
24853 .map(|s| Value::String(Rc::new(s.clone())))
24854 .collect();
24855 result.insert(
24856 "factors".to_string(),
24857 Value::Array(Rc::new(RefCell::new(factor_values))),
24858 );
24859
24860 Ok(Value::Map(Rc::new(RefCell::new(result))))
24861 });
24862
24863 define(interp, "spirituality_info", Some(0), |_, _| {
24865 let mut info = std::collections::HashMap::new();
24866
24867 info.insert(
24868 "i_ching".to_string(),
24869 Value::String(Rc::new(
24870 "trigram(), hexagram(), cast_iching() - 64 hexagrams of change".to_string(),
24871 )),
24872 );
24873 info.insert(
24874 "sacred_geometry".to_string(),
24875 Value::String(Rc::new(
24876 "phi(), sacred_ratio(), fibonacci(), platonic_solid()".to_string(),
24877 )),
24878 );
24879 info.insert(
24880 "gematria".to_string(),
24881 Value::String(Rc::new(
24882 "Hebrew, Greek, Arabic, English letter-number systems".to_string(),
24883 )),
24884 );
24885 info.insert(
24886 "archetypes".to_string(),
24887 Value::String(Rc::new(
24888 "17 Jungian archetypes with shadow and gift".to_string(),
24889 )),
24890 );
24891 info.insert(
24892 "astrology".to_string(),
24893 Value::String(Rc::new(
24894 "zodiac() - 12 signs with elements and modalities".to_string(),
24895 )),
24896 );
24897 info.insert(
24898 "tarot".to_string(),
24899 Value::String(Rc::new(
24900 "tarot_major(), draw_tarot() - 22 Major Arcana".to_string(),
24901 )),
24902 );
24903
24904 Ok(Value::Map(Rc::new(RefCell::new(info))))
24905 });
24906}
24907
24908const HEXAGRAMS: [(&str, &str, &str, &str, &str, &str); 64] = [
24910 (
24911 "乾",
24912 "Qián",
24913 "The Creative",
24914 "Sublime success through perseverance",
24915 "Heaven",
24916 "Heaven",
24917 ),
24918 (
24919 "坤",
24920 "Kūn",
24921 "The Receptive",
24922 "Devoted success through the mare's perseverance",
24923 "Earth",
24924 "Earth",
24925 ),
24926 (
24927 "屯",
24928 "Zhūn",
24929 "Difficulty at the Beginning",
24930 "Persevere, seek helpers, don't act alone",
24931 "Water",
24932 "Thunder",
24933 ),
24934 (
24935 "蒙",
24936 "Méng",
24937 "Youthful Folly",
24938 "Success through education and guidance",
24939 "Mountain",
24940 "Water",
24941 ),
24942 (
24943 "需",
24944 "Xū",
24945 "Waiting",
24946 "Sincerity brings success; cross the great water",
24947 "Water",
24948 "Heaven",
24949 ),
24950 (
24951 "訟",
24952 "Sòng",
24953 "Conflict",
24954 "Seek counsel; don't cross the great water",
24955 "Heaven",
24956 "Water",
24957 ),
24958 (
24959 "師",
24960 "Shī",
24961 "The Army",
24962 "Perseverance and an experienced leader bring success",
24963 "Earth",
24964 "Water",
24965 ),
24966 (
24967 "比",
24968 "Bǐ",
24969 "Holding Together",
24970 "Through perseverance, those who hesitate should reflect",
24971 "Water",
24972 "Earth",
24973 ),
24974 (
24975 "小畜",
24976 "Xiǎo Chù",
24977 "Small Taming",
24978 "Success; dense clouds but no rain",
24979 "Wind",
24980 "Heaven",
24981 ),
24982 (
24983 "履",
24984 "Lǚ",
24985 "Treading",
24986 "Tread on the tiger's tail carefully; success",
24987 "Heaven",
24988 "Lake",
24989 ),
24990 (
24991 "泰",
24992 "Tài",
24993 "Peace",
24994 "The small departs, the great approaches; success",
24995 "Earth",
24996 "Heaven",
24997 ),
24998 (
24999 "否",
25000 "Pǐ",
25001 "Standstill",
25002 "The great departs, the small approaches; persevere",
25003 "Heaven",
25004 "Earth",
25005 ),
25006 (
25007 "同人",
25008 "Tóng Rén",
25009 "Fellowship",
25010 "Success in the open; cross the great water",
25011 "Heaven",
25012 "Fire",
25013 ),
25014 (
25015 "大有",
25016 "Dà Yǒu",
25017 "Great Possession",
25018 "Supreme success",
25019 "Fire",
25020 "Heaven",
25021 ),
25022 (
25023 "謙",
25024 "Qiān",
25025 "Modesty",
25026 "Success; the superior person carries things through",
25027 "Earth",
25028 "Mountain",
25029 ),
25030 (
25031 "豫",
25032 "Yù",
25033 "Enthusiasm",
25034 "Appoint helpers and set armies marching",
25035 "Thunder",
25036 "Earth",
25037 ),
25038 (
25039 "隨",
25040 "Suí",
25041 "Following",
25042 "Supreme success through perseverance",
25043 "Lake",
25044 "Thunder",
25045 ),
25046 (
25047 "蠱",
25048 "Gǔ",
25049 "Work on the Decayed",
25050 "Success; cross the great water; three days before and after",
25051 "Mountain",
25052 "Wind",
25053 ),
25054 (
25055 "臨",
25056 "Lín",
25057 "Approach",
25058 "Great success through perseverance; misfortune in eighth month",
25059 "Earth",
25060 "Lake",
25061 ),
25062 (
25063 "觀",
25064 "Guān",
25065 "Contemplation",
25066 "Ablution, but not yet sacrifice; confidence inspires",
25067 "Wind",
25068 "Earth",
25069 ),
25070 (
25071 "噬嗑",
25072 "Shì Kè",
25073 "Biting Through",
25074 "Success; favorable for legal matters",
25075 "Fire",
25076 "Thunder",
25077 ),
25078 (
25079 "賁",
25080 "Bì",
25081 "Grace",
25082 "Success in small matters",
25083 "Mountain",
25084 "Fire",
25085 ),
25086 (
25087 "剝",
25088 "Bō",
25089 "Splitting Apart",
25090 "Unfavorable to go anywhere",
25091 "Mountain",
25092 "Earth",
25093 ),
25094 (
25095 "復",
25096 "Fù",
25097 "Return",
25098 "Success; going out and coming in without error",
25099 "Earth",
25100 "Thunder",
25101 ),
25102 (
25103 "無妄",
25104 "Wú Wàng",
25105 "Innocence",
25106 "Supreme success through perseverance",
25107 "Heaven",
25108 "Thunder",
25109 ),
25110 (
25111 "大畜",
25112 "Dà Chù",
25113 "Great Taming",
25114 "Perseverance; eat away from home",
25115 "Mountain",
25116 "Heaven",
25117 ),
25118 (
25119 "頤",
25120 "Yí",
25121 "Nourishment",
25122 "Perseverance; watch what you nurture",
25123 "Mountain",
25124 "Thunder",
25125 ),
25126 (
25127 "大過",
25128 "Dà Guò",
25129 "Great Exceeding",
25130 "The ridgepole sags; favorable to have somewhere to go",
25131 "Lake",
25132 "Wind",
25133 ),
25134 (
25135 "坎",
25136 "Kǎn",
25137 "The Abysmal",
25138 "Sincerity brings success of the heart",
25139 "Water",
25140 "Water",
25141 ),
25142 (
25143 "離",
25144 "Lí",
25145 "The Clinging",
25146 "Perseverance; success; care for the cow",
25147 "Fire",
25148 "Fire",
25149 ),
25150 (
25151 "咸",
25152 "Xián",
25153 "Influence",
25154 "Success; perseverance; taking a maiden brings fortune",
25155 "Lake",
25156 "Mountain",
25157 ),
25158 (
25159 "恆",
25160 "Héng",
25161 "Duration",
25162 "Success without blame; perseverance; favorable to have somewhere to go",
25163 "Thunder",
25164 "Wind",
25165 ),
25166 (
25167 "遯",
25168 "Dùn",
25169 "Retreat",
25170 "Success; small perseverance",
25171 "Heaven",
25172 "Mountain",
25173 ),
25174 (
25175 "大壯",
25176 "Dà Zhuàng",
25177 "Great Power",
25178 "Perseverance",
25179 "Thunder",
25180 "Heaven",
25181 ),
25182 (
25183 "晉",
25184 "Jìn",
25185 "Progress",
25186 "The powerful prince is honored with horses",
25187 "Fire",
25188 "Earth",
25189 ),
25190 (
25191 "明夷",
25192 "Míng Yí",
25193 "Darkening of the Light",
25194 "Perseverance in adversity",
25195 "Earth",
25196 "Fire",
25197 ),
25198 (
25199 "家人",
25200 "Jiā Rén",
25201 "The Family",
25202 "Perseverance of the woman",
25203 "Wind",
25204 "Fire",
25205 ),
25206 (
25207 "睽",
25208 "Kuí",
25209 "Opposition",
25210 "Good fortune in small matters",
25211 "Fire",
25212 "Lake",
25213 ),
25214 (
25215 "蹇",
25216 "Jiǎn",
25217 "Obstruction",
25218 "Southwest favorable; northeast unfavorable; see the great person",
25219 "Water",
25220 "Mountain",
25221 ),
25222 (
25223 "解",
25224 "Xiè",
25225 "Deliverance",
25226 "Southwest favorable; return brings fortune; haste brings fortune",
25227 "Thunder",
25228 "Water",
25229 ),
25230 (
25231 "損",
25232 "Sǔn",
25233 "Decrease",
25234 "Sincerity; supreme fortune; persistence; favorable to undertake",
25235 "Mountain",
25236 "Lake",
25237 ),
25238 (
25239 "益",
25240 "Yì",
25241 "Increase",
25242 "Favorable to undertake and cross the great water",
25243 "Wind",
25244 "Thunder",
25245 ),
25246 (
25247 "夬",
25248 "Guài",
25249 "Breakthrough",
25250 "Proclaim at the king's court; sincerity in danger",
25251 "Lake",
25252 "Heaven",
25253 ),
25254 (
25255 "姤",
25256 "Gòu",
25257 "Coming to Meet",
25258 "The maiden is powerful; don't marry such a maiden",
25259 "Heaven",
25260 "Wind",
25261 ),
25262 (
25263 "萃",
25264 "Cuì",
25265 "Gathering",
25266 "Success; the king approaches his temple; see the great person",
25267 "Lake",
25268 "Earth",
25269 ),
25270 (
25271 "升",
25272 "Shēng",
25273 "Pushing Upward",
25274 "Supreme success; see the great person; don't worry",
25275 "Earth",
25276 "Wind",
25277 ),
25278 (
25279 "困",
25280 "Kùn",
25281 "Oppression",
25282 "Success; perseverance of the great person; no blame",
25283 "Lake",
25284 "Water",
25285 ),
25286 (
25287 "井",
25288 "Jǐng",
25289 "The Well",
25290 "The town may change but not the well",
25291 "Water",
25292 "Wind",
25293 ),
25294 (
25295 "革",
25296 "Gé",
25297 "Revolution",
25298 "On your own day you are believed; great success",
25299 "Lake",
25300 "Fire",
25301 ),
25302 (
25303 "鼎",
25304 "Dǐng",
25305 "The Cauldron",
25306 "Supreme good fortune; success",
25307 "Fire",
25308 "Wind",
25309 ),
25310 (
25311 "震",
25312 "Zhèn",
25313 "The Arousing",
25314 "Success; thunder comes with fright; laughing and talking after",
25315 "Thunder",
25316 "Thunder",
25317 ),
25318 (
25319 "艮",
25320 "Gèn",
25321 "Keeping Still",
25322 "Keep your back still; go into the courtyard without seeing anyone",
25323 "Mountain",
25324 "Mountain",
25325 ),
25326 (
25327 "漸",
25328 "Jiàn",
25329 "Development",
25330 "The maiden is given in marriage; good fortune; perseverance",
25331 "Wind",
25332 "Mountain",
25333 ),
25334 (
25335 "歸妹",
25336 "Guī Mèi",
25337 "The Marrying Maiden",
25338 "Undertakings bring misfortune",
25339 "Thunder",
25340 "Lake",
25341 ),
25342 (
25343 "豐",
25344 "Fēng",
25345 "Abundance",
25346 "Success; the king attains it; don't worry; be like the sun at noon",
25347 "Thunder",
25348 "Fire",
25349 ),
25350 (
25351 "旅",
25352 "Lǚ",
25353 "The Wanderer",
25354 "Success through smallness; perseverance brings fortune",
25355 "Fire",
25356 "Mountain",
25357 ),
25358 (
25359 "巽",
25360 "Xùn",
25361 "The Gentle",
25362 "Success through small things; favorable to have somewhere to go",
25363 "Wind",
25364 "Wind",
25365 ),
25366 (
25367 "兌",
25368 "Duì",
25369 "The Joyous",
25370 "Success; perseverance",
25371 "Lake",
25372 "Lake",
25373 ),
25374 (
25375 "渙",
25376 "Huàn",
25377 "Dispersion",
25378 "Success; the king approaches his temple; cross the great water",
25379 "Wind",
25380 "Water",
25381 ),
25382 (
25383 "節",
25384 "Jié",
25385 "Limitation",
25386 "Success; bitter limitation should not be persevered in",
25387 "Water",
25388 "Lake",
25389 ),
25390 (
25391 "中孚",
25392 "Zhōng Fú",
25393 "Inner Truth",
25394 "Pigs and fishes; good fortune; cross the great water",
25395 "Wind",
25396 "Lake",
25397 ),
25398 (
25399 "小過",
25400 "Xiǎo Guò",
25401 "Small Exceeding",
25402 "Success; perseverance; small things yes, great things no",
25403 "Thunder",
25404 "Mountain",
25405 ),
25406 (
25407 "既濟",
25408 "Jì Jì",
25409 "After Completion",
25410 "Success in small matters; perseverance; good at start, disorder at end",
25411 "Water",
25412 "Fire",
25413 ),
25414 (
25415 "未濟",
25416 "Wèi Jì",
25417 "Before Completion",
25418 "Success; the young fox almost across; tail gets wet; no goal",
25419 "Fire",
25420 "Water",
25421 ),
25422];
25423
25424fn binary_to_king_wen(binary: u8) -> u8 {
25425 const KING_WEN_ORDER: [u8; 64] = [
25428 1, 43, 14, 34, 9, 5, 26, 11, 10, 58, 38, 54, 61, 60, 41, 19, 13, 49, 30, 55, 37, 63, 22,
25429 36, 25, 17, 21, 51, 42, 3, 27, 24, 44, 28, 50, 32, 57, 48, 18, 46, 6, 47, 64, 40, 59, 29,
25430 4, 7, 33, 31, 56, 62, 53, 39, 52, 15, 12, 45, 35, 16, 20, 8, 23, 2,
25431 ];
25432 KING_WEN_ORDER[binary as usize] - 1
25433}
25434
25435fn hebrew_gematria(c: char) -> i64 {
25436 match c {
25437 'א' | 'A' | 'a' => 1,
25438 'ב' | 'B' | 'b' => 2,
25439 'ג' | 'G' | 'g' => 3,
25440 'ד' | 'D' | 'd' => 4,
25441 'ה' | 'H' | 'h' => 5,
25442 'ו' | 'V' | 'v' | 'W' | 'w' => 6,
25443 'ז' | 'Z' | 'z' => 7,
25444 'ח' => 8,
25445 'ט' => 9,
25446 'י' | 'Y' | 'y' | 'I' | 'i' | 'J' | 'j' => 10,
25447 'כ' | 'K' | 'k' => 20,
25448 'ל' | 'L' | 'l' => 30,
25449 'מ' | 'M' | 'm' => 40,
25450 'נ' | 'N' | 'n' => 50,
25451 'ס' | 'S' | 's' | 'X' | 'x' => 60,
25452 'ע' | 'O' | 'o' => 70,
25453 'פ' | 'P' | 'p' | 'F' | 'f' => 80,
25454 'צ' => 90,
25455 'ק' | 'Q' | 'q' => 100,
25456 'ר' | 'R' | 'r' => 200,
25457 'ש' => 300,
25458 'ת' | 'T' | 't' => 400,
25459 'ך' => 500, 'ם' => 600, 'ן' => 700, 'ף' => 800, 'ץ' | 'C' | 'c' => 900, 'E' | 'e' => 5, 'U' | 'u' => 6, _ => 0,
25467 }
25468}
25469
25470fn greek_isopsephy(c: char) -> i64 {
25471 match c {
25472 'Α' | 'α' | 'A' | 'a' => 1,
25473 'Β' | 'β' | 'B' | 'b' => 2,
25474 'Γ' | 'γ' | 'G' | 'g' => 3,
25475 'Δ' | 'δ' | 'D' | 'd' => 4,
25476 'Ε' | 'ε' | 'E' | 'e' => 5,
25477 'Ϛ' | 'ϛ' => 6, 'Ζ' | 'ζ' | 'Z' | 'z' => 7,
25479 'Η' | 'η' | 'H' | 'h' => 8,
25480 'Θ' | 'θ' => 9,
25481 'Ι' | 'ι' | 'I' | 'i' => 10,
25482 'Κ' | 'κ' | 'K' | 'k' => 20,
25483 'Λ' | 'λ' | 'L' | 'l' => 30,
25484 'Μ' | 'μ' | 'M' | 'm' => 40,
25485 'Ν' | 'ν' | 'N' | 'n' => 50,
25486 'Ξ' | 'ξ' | 'X' | 'x' => 60,
25487 'Ο' | 'ο' | 'O' | 'o' => 70,
25488 'Π' | 'π' | 'P' | 'p' => 80,
25489 'Ϙ' | 'ϙ' | 'Q' | 'q' => 90, 'Ρ' | 'ρ' | 'R' | 'r' => 100,
25491 'Σ' | 'σ' | 'ς' | 'S' | 's' => 200,
25492 'Τ' | 'τ' | 'T' | 't' => 300,
25493 'Υ' | 'υ' | 'U' | 'u' | 'Y' | 'y' => 400,
25494 'Φ' | 'φ' | 'F' | 'f' => 500,
25495 'Χ' | 'χ' | 'C' | 'c' => 600,
25496 'Ψ' | 'ψ' => 700,
25497 'Ω' | 'ω' | 'W' | 'w' => 800,
25498 'Ϡ' | 'ϡ' => 900, 'J' | 'j' => 10, 'V' | 'v' => 400, _ => 0,
25502 }
25503}
25504
25505fn arabic_abjad(c: char) -> i64 {
25506 match c {
25507 'ا' | 'أ' | 'إ' | 'آ' | 'A' | 'a' => 1,
25508 'ب' | 'B' | 'b' => 2,
25509 'ج' | 'J' | 'j' | 'G' | 'g' => 3,
25510 'د' | 'D' | 'd' => 4,
25511 'ه' | 'H' | 'h' => 5,
25512 'و' | 'W' | 'w' | 'V' | 'v' => 6,
25513 'ز' | 'Z' | 'z' => 7,
25514 'ح' => 8,
25515 'ط' => 9,
25516 'ي' | 'Y' | 'y' | 'I' | 'i' => 10,
25517 'ك' | 'K' | 'k' => 20,
25518 'ل' | 'L' | 'l' => 30,
25519 'م' | 'M' | 'm' => 40,
25520 'ن' | 'N' | 'n' => 50,
25521 'س' | 'S' | 's' => 60,
25522 'ع' | 'E' | 'e' => 70,
25523 'ف' | 'F' | 'f' => 80,
25524 'ص' => 90,
25525 'ق' | 'Q' | 'q' => 100,
25526 'ر' | 'R' | 'r' => 200,
25527 'ش' => 300,
25528 'ت' | 'T' | 't' => 400,
25529 'ث' => 500,
25530 'خ' | 'X' | 'x' => 600,
25531 'ذ' => 700,
25532 'ض' => 800,
25533 'ظ' => 900,
25534 'غ' => 1000,
25535 'C' | 'c' => 600, 'O' | 'o' => 70, 'P' | 'p' => 80, 'U' | 'u' => 6, _ => 0,
25540 }
25541}
25542
25543fn register_color(interp: &mut Interpreter) {
25550 define(interp, "rgb", Some(3), |_, args| {
25556 let r = match &args[0] {
25557 Value::Int(n) => (*n).clamp(0, 255) as u8,
25558 Value::Float(f) => (*f as i64).clamp(0, 255) as u8,
25559 _ => return Err(RuntimeError::new("rgb() requires numbers")),
25560 };
25561 let g = match &args[1] {
25562 Value::Int(n) => (*n).clamp(0, 255) as u8,
25563 Value::Float(f) => (*f as i64).clamp(0, 255) as u8,
25564 _ => return Err(RuntimeError::new("rgb() requires numbers")),
25565 };
25566 let b = match &args[2] {
25567 Value::Int(n) => (*n).clamp(0, 255) as u8,
25568 Value::Float(f) => (*f as i64).clamp(0, 255) as u8,
25569 _ => return Err(RuntimeError::new("rgb() requires numbers")),
25570 };
25571 let mut map = std::collections::HashMap::new();
25572 map.insert("r".to_string(), Value::Int(r as i64));
25573 map.insert("g".to_string(), Value::Int(g as i64));
25574 map.insert("b".to_string(), Value::Int(b as i64));
25575 map.insert(
25576 "hex".to_string(),
25577 Value::String(Rc::new(format!("#{:02X}{:02X}{:02X}", r, g, b))),
25578 );
25579 Ok(Value::Map(Rc::new(RefCell::new(map))))
25580 });
25581
25582 define(interp, "hex_to_rgb", Some(1), |_, args| {
25584 let hex = match &args[0] {
25585 Value::String(s) => s.to_string(),
25586 _ => return Err(RuntimeError::new("hex_to_rgb requires string")),
25587 };
25588 let hex = hex.trim_start_matches('#');
25589 if hex.len() != 6 {
25590 return Err(RuntimeError::new("hex_to_rgb requires 6 character hex"));
25591 }
25592 let r = u8::from_str_radix(&hex[0..2], 16).map_err(|_| RuntimeError::new("Invalid hex"))?;
25593 let g = u8::from_str_radix(&hex[2..4], 16).map_err(|_| RuntimeError::new("Invalid hex"))?;
25594 let b = u8::from_str_radix(&hex[4..6], 16).map_err(|_| RuntimeError::new("Invalid hex"))?;
25595 let mut map = std::collections::HashMap::new();
25596 map.insert("r".to_string(), Value::Int(r as i64));
25597 map.insert("g".to_string(), Value::Int(g as i64));
25598 map.insert("b".to_string(), Value::Int(b as i64));
25599 Ok(Value::Map(Rc::new(RefCell::new(map))))
25600 });
25601
25602 define(interp, "rgb_to_hsl", Some(3), |_, args| {
25604 let r = match &args[0] {
25605 Value::Int(n) => *n as f64 / 255.0,
25606 Value::Float(f) => *f / 255.0,
25607 _ => return Err(RuntimeError::new("requires numbers")),
25608 };
25609 let g = match &args[1] {
25610 Value::Int(n) => *n as f64 / 255.0,
25611 Value::Float(f) => *f / 255.0,
25612 _ => return Err(RuntimeError::new("requires numbers")),
25613 };
25614 let b = match &args[2] {
25615 Value::Int(n) => *n as f64 / 255.0,
25616 Value::Float(f) => *f / 255.0,
25617 _ => return Err(RuntimeError::new("requires numbers")),
25618 };
25619 let max = r.max(g).max(b);
25620 let min = r.min(g).min(b);
25621 let l = (max + min) / 2.0;
25622 let (h, s) = if max == min {
25623 (0.0, 0.0)
25624 } else {
25625 let d = max - min;
25626 let s = if l > 0.5 {
25627 d / (2.0 - max - min)
25628 } else {
25629 d / (max + min)
25630 };
25631 let h = if max == r {
25632 (g - b) / d + if g < b { 6.0 } else { 0.0 }
25633 } else if max == g {
25634 (b - r) / d + 2.0
25635 } else {
25636 (r - g) / d + 4.0
25637 };
25638 (h * 60.0, s)
25639 };
25640 let mut map = std::collections::HashMap::new();
25641 map.insert("h".to_string(), Value::Float(h));
25642 map.insert("s".to_string(), Value::Float(s));
25643 map.insert("l".to_string(), Value::Float(l));
25644 Ok(Value::Map(Rc::new(RefCell::new(map))))
25645 });
25646
25647 define(interp, "complementary", Some(3), |_, args| {
25649 let r = match &args[0] {
25650 Value::Int(n) => *n as u8,
25651 _ => return Err(RuntimeError::new("requires int")),
25652 };
25653 let g = match &args[1] {
25654 Value::Int(n) => *n as u8,
25655 _ => return Err(RuntimeError::new("requires int")),
25656 };
25657 let b = match &args[2] {
25658 Value::Int(n) => *n as u8,
25659 _ => return Err(RuntimeError::new("requires int")),
25660 };
25661 let mut map = std::collections::HashMap::new();
25662 map.insert("r".to_string(), Value::Int(255 - r as i64));
25663 map.insert("g".to_string(), Value::Int(255 - g as i64));
25664 map.insert("b".to_string(), Value::Int(255 - b as i64));
25665 Ok(Value::Map(Rc::new(RefCell::new(map))))
25666 });
25667
25668 define(interp, "wu_xing", Some(1), |_, args| {
25672 let element = match &args[0] {
25673 Value::String(s) => s.to_lowercase(),
25674 _ => return Err(RuntimeError::new("wu_xing requires string")),
25675 };
25676 let (name, chinese, color, hex, direction, season, organ, emotion, planet, animal) =
25677 match element.as_str() {
25678 "wood" | "mu" | "木" => (
25679 "Wood",
25680 "木 (Mù)",
25681 "Green/Azure",
25682 "#228B22",
25683 "East",
25684 "Spring",
25685 "Liver",
25686 "Anger",
25687 "Jupiter",
25688 "Azure Dragon",
25689 ),
25690 "fire" | "huo" | "火" => (
25691 "Fire",
25692 "火 (Huǒ)",
25693 "Red",
25694 "#FF0000",
25695 "South",
25696 "Summer",
25697 "Heart",
25698 "Joy",
25699 "Mars",
25700 "Vermilion Bird",
25701 ),
25702 "earth" | "tu" | "土" => (
25703 "Earth",
25704 "土 (Tǔ)",
25705 "Yellow",
25706 "#FFDB58",
25707 "Center",
25708 "Late Summer",
25709 "Spleen",
25710 "Worry",
25711 "Saturn",
25712 "Yellow Dragon",
25713 ),
25714 "metal" | "jin" | "金" => (
25715 "Metal",
25716 "金 (Jīn)",
25717 "White/Gold",
25718 "#FFD700",
25719 "West",
25720 "Autumn",
25721 "Lung",
25722 "Grief",
25723 "Venus",
25724 "White Tiger",
25725 ),
25726 "water" | "shui" | "水" => (
25727 "Water",
25728 "水 (Shuǐ)",
25729 "Black/Blue",
25730 "#000080",
25731 "North",
25732 "Winter",
25733 "Kidney",
25734 "Fear",
25735 "Mercury",
25736 "Black Tortoise",
25737 ),
25738 _ => {
25739 return Err(RuntimeError::new(
25740 "Unknown element. Use wood/fire/earth/metal/water",
25741 ))
25742 }
25743 };
25744 let mut map = std::collections::HashMap::new();
25745 map.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
25746 map.insert(
25747 "chinese".to_string(),
25748 Value::String(Rc::new(chinese.to_string())),
25749 );
25750 map.insert(
25751 "color".to_string(),
25752 Value::String(Rc::new(color.to_string())),
25753 );
25754 map.insert("hex".to_string(), Value::String(Rc::new(hex.to_string())));
25755 map.insert(
25756 "direction".to_string(),
25757 Value::String(Rc::new(direction.to_string())),
25758 );
25759 map.insert(
25760 "season".to_string(),
25761 Value::String(Rc::new(season.to_string())),
25762 );
25763 map.insert(
25764 "organ".to_string(),
25765 Value::String(Rc::new(organ.to_string())),
25766 );
25767 map.insert(
25768 "emotion".to_string(),
25769 Value::String(Rc::new(emotion.to_string())),
25770 );
25771 map.insert(
25772 "planet".to_string(),
25773 Value::String(Rc::new(planet.to_string())),
25774 );
25775 map.insert(
25776 "guardian".to_string(),
25777 Value::String(Rc::new(animal.to_string())),
25778 );
25779 Ok(Value::Map(Rc::new(RefCell::new(map))))
25780 });
25781
25782 define(interp, "chakra_color", Some(1), |_, args| {
25786 let chakra = match &args[0] {
25787 Value::String(s) => s.to_lowercase(),
25788 Value::Int(n) => n.to_string(),
25789 _ => return Err(RuntimeError::new("chakra_color requires string or number")),
25790 };
25791 let (name, sanskrit, color, hex, location, freq, element, mantra) = match chakra.as_str() {
25792 "root" | "muladhara" | "1" => (
25793 "Root",
25794 "मूलाधार",
25795 "Red",
25796 "#FF0000",
25797 "Base of spine",
25798 396.0,
25799 "Earth",
25800 "LAM",
25801 ),
25802 "sacral" | "svadhisthana" | "2" => (
25803 "Sacral",
25804 "स्वाधिष्ठान",
25805 "Orange",
25806 "#FF7F00",
25807 "Below navel",
25808 417.0,
25809 "Water",
25810 "VAM",
25811 ),
25812 "solar" | "manipura" | "3" => (
25813 "Solar Plexus",
25814 "मणिपूर",
25815 "Yellow",
25816 "#FFFF00",
25817 "Stomach",
25818 528.0,
25819 "Fire",
25820 "RAM",
25821 ),
25822 "heart" | "anahata" | "4" => (
25823 "Heart",
25824 "अनाहत",
25825 "Green",
25826 "#00FF00",
25827 "Chest",
25828 639.0,
25829 "Air",
25830 "YAM",
25831 ),
25832 "throat" | "vishuddha" | "5" => (
25833 "Throat",
25834 "विशुद्ध",
25835 "Blue",
25836 "#00BFFF",
25837 "Throat",
25838 741.0,
25839 "Ether",
25840 "HAM",
25841 ),
25842 "third_eye" | "ajna" | "6" => (
25843 "Third Eye",
25844 "आज्ञा",
25845 "Indigo",
25846 "#4B0082",
25847 "Forehead",
25848 852.0,
25849 "Light",
25850 "OM",
25851 ),
25852 "crown" | "sahasrara" | "7" => (
25853 "Crown",
25854 "सहस्रार",
25855 "Violet",
25856 "#8B00FF",
25857 "Top of head",
25858 963.0,
25859 "Thought",
25860 "Silence",
25861 ),
25862 _ => {
25863 return Err(RuntimeError::new(
25864 "Unknown chakra. Use root/sacral/solar/heart/throat/third_eye/crown or 1-7",
25865 ))
25866 }
25867 };
25868 let mut map = std::collections::HashMap::new();
25869 map.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
25870 map.insert(
25871 "sanskrit".to_string(),
25872 Value::String(Rc::new(sanskrit.to_string())),
25873 );
25874 map.insert(
25875 "color".to_string(),
25876 Value::String(Rc::new(color.to_string())),
25877 );
25878 map.insert("hex".to_string(), Value::String(Rc::new(hex.to_string())));
25879 map.insert(
25880 "location".to_string(),
25881 Value::String(Rc::new(location.to_string())),
25882 );
25883 map.insert("frequency_hz".to_string(), Value::Float(freq));
25884 map.insert(
25885 "element".to_string(),
25886 Value::String(Rc::new(element.to_string())),
25887 );
25888 map.insert(
25889 "mantra".to_string(),
25890 Value::String(Rc::new(mantra.to_string())),
25891 );
25892 Ok(Value::Map(Rc::new(RefCell::new(map))))
25893 });
25894
25895 define(interp, "maya_direction", Some(1), |_, args| {
25899 let dir = match &args[0] {
25900 Value::String(s) => s.to_lowercase(),
25901 _ => return Err(RuntimeError::new("requires string")),
25902 };
25903 let (direction, yucatec, color, hex, deity, meaning) = match dir.as_str() {
25904 "east" | "lakin" => (
25905 "East",
25906 "Lak'in",
25907 "Red",
25908 "#FF0000",
25909 "Chac (Red)",
25910 "Sunrise, new beginnings",
25911 ),
25912 "north" | "xaman" => (
25913 "North",
25914 "Xaman",
25915 "White",
25916 "#FFFFFF",
25917 "Chac (White)",
25918 "Ancestors, death",
25919 ),
25920 "west" | "chikin" => (
25921 "West",
25922 "Chik'in",
25923 "Black",
25924 "#000000",
25925 "Chac (Black)",
25926 "Sunset, completion",
25927 ),
25928 "south" | "nohol" => (
25929 "South",
25930 "Nohol",
25931 "Yellow",
25932 "#FFFF00",
25933 "Chac (Yellow)",
25934 "Maize, abundance",
25935 ),
25936 "center" | "yax" => (
25937 "Center",
25938 "Yax",
25939 "Green/Blue",
25940 "#00CED1",
25941 "World Tree",
25942 "Balance",
25943 ),
25944 _ => {
25945 return Err(RuntimeError::new(
25946 "Unknown direction. Use east/north/west/south/center",
25947 ))
25948 }
25949 };
25950 let mut map = std::collections::HashMap::new();
25951 map.insert(
25952 "direction".to_string(),
25953 Value::String(Rc::new(direction.to_string())),
25954 );
25955 map.insert(
25956 "yucatec".to_string(),
25957 Value::String(Rc::new(yucatec.to_string())),
25958 );
25959 map.insert(
25960 "color".to_string(),
25961 Value::String(Rc::new(color.to_string())),
25962 );
25963 map.insert("hex".to_string(), Value::String(Rc::new(hex.to_string())));
25964 map.insert(
25965 "deity".to_string(),
25966 Value::String(Rc::new(deity.to_string())),
25967 );
25968 map.insert(
25969 "meaning".to_string(),
25970 Value::String(Rc::new(meaning.to_string())),
25971 );
25972 Ok(Value::Map(Rc::new(RefCell::new(map))))
25973 });
25974
25975 define(interp, "orisha_color", Some(1), |_, args| {
25979 let orisha = match &args[0] {
25980 Value::String(s) => s.to_lowercase(),
25981 _ => return Err(RuntimeError::new("requires string")),
25982 };
25983 let (name, colors, hex, domain, day, number) = match orisha.as_str() {
25984 "obatala" | "oxala" => (
25985 "Obatalá",
25986 "White, silver",
25987 "#FFFFFF",
25988 "Creation, purity, wisdom",
25989 "Sunday",
25990 8,
25991 ),
25992 "yemoja" | "yemanja" => (
25993 "Yemọja",
25994 "Blue, white",
25995 "#4169E1",
25996 "Ocean, motherhood",
25997 "Saturday",
25998 7,
25999 ),
26000 "oshun" | "oxum" => (
26001 "Ọṣun",
26002 "Yellow, gold",
26003 "#FFD700",
26004 "Rivers, love, fertility",
26005 "Saturday",
26006 5,
26007 ),
26008 "shango" | "xango" => (
26009 "Ṣàngó",
26010 "Red, white",
26011 "#FF0000",
26012 "Thunder, fire, justice",
26013 "Wednesday",
26014 6,
26015 ),
26016 "ogun" | "ogum" => (
26017 "Ògún",
26018 "Green, black",
26019 "#006400",
26020 "Iron, war, labor",
26021 "Tuesday",
26022 7,
26023 ),
26024 "oya" | "iansa" => (
26025 "Ọya",
26026 "Brown, purple",
26027 "#800020",
26028 "Wind, storms, change",
26029 "Wednesday",
26030 9,
26031 ),
26032 "eshu" | "exu" => (
26033 "Èṣù",
26034 "Red, black",
26035 "#8B0000",
26036 "Crossroads, messages",
26037 "Monday",
26038 3,
26039 ),
26040 _ => {
26041 return Err(RuntimeError::new(
26042 "Unknown Orisha. Use obatala/yemoja/oshun/shango/ogun/oya/eshu",
26043 ))
26044 }
26045 };
26046 let mut map = std::collections::HashMap::new();
26047 map.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
26048 map.insert(
26049 "colors".to_string(),
26050 Value::String(Rc::new(colors.to_string())),
26051 );
26052 map.insert("hex".to_string(), Value::String(Rc::new(hex.to_string())));
26053 map.insert(
26054 "domain".to_string(),
26055 Value::String(Rc::new(domain.to_string())),
26056 );
26057 map.insert("day".to_string(), Value::String(Rc::new(day.to_string())));
26058 map.insert("number".to_string(), Value::Int(number));
26059 Ok(Value::Map(Rc::new(RefCell::new(map))))
26060 });
26061
26062 define(interp, "nihon_iro", Some(1), |_, args| {
26066 let color = match &args[0] {
26067 Value::String(s) => s.to_lowercase(),
26068 _ => return Err(RuntimeError::new("requires string")),
26069 };
26070 let (name, japanese, hex, meaning, season) = match color.as_str() {
26071 "sakura" => (
26072 "Sakura Pink",
26073 "桜色",
26074 "#FFB7C5",
26075 "Cherry blossoms, transience",
26076 "Spring",
26077 ),
26078 "fuji" => (
26079 "Wisteria",
26080 "藤色",
26081 "#C9A0DC",
26082 "Elegance, nobility",
26083 "Spring",
26084 ),
26085 "moegi" => (
26086 "Young Green",
26087 "萌黄",
26088 "#AACF53",
26089 "New growth, freshness",
26090 "Spring",
26091 ),
26092 "ai" => ("Indigo", "藍色", "#004D99", "Protection, depth", "All"),
26093 "akane" => ("Madder Red", "茜色", "#CF3A24", "Sunset, passion", "Autumn"),
26094 "shiro" => ("White", "白", "#FFFFFF", "Purity, death, sacred", "Winter"),
26095 "kuro" => ("Black", "黒", "#000000", "Formality, mystery", "All"),
26096 "aka" => ("Red", "赤", "#D7003A", "Life force, celebration", "All"),
26097 "murasaki" => ("Purple", "紫", "#884898", "Nobility, spirituality", "All"),
26098 _ => {
26099 return Err(RuntimeError::new(
26100 "Unknown color. Try: sakura/fuji/moegi/ai/akane/shiro/kuro/aka/murasaki",
26101 ))
26102 }
26103 };
26104 let mut map = std::collections::HashMap::new();
26105 map.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
26106 map.insert(
26107 "japanese".to_string(),
26108 Value::String(Rc::new(japanese.to_string())),
26109 );
26110 map.insert("hex".to_string(), Value::String(Rc::new(hex.to_string())));
26111 map.insert(
26112 "meaning".to_string(),
26113 Value::String(Rc::new(meaning.to_string())),
26114 );
26115 map.insert(
26116 "season".to_string(),
26117 Value::String(Rc::new(season.to_string())),
26118 );
26119 Ok(Value::Map(Rc::new(RefCell::new(map))))
26120 });
26121
26122 define(interp, "islamic_color", Some(1), |_, args| {
26126 let color = match &args[0] {
26127 Value::String(s) => s.to_lowercase(),
26128 _ => return Err(RuntimeError::new("requires string")),
26129 };
26130 let (name, arabic, hex, meaning, usage) = match color.as_str() {
26131 "green" | "akhdar" => (
26132 "Green",
26133 "أخضر",
26134 "#00FF00",
26135 "Paradise, Prophet, life",
26136 "Mosques, Quran, flags",
26137 ),
26138 "white" | "abyad" => (
26139 "White",
26140 "أبيض",
26141 "#FFFFFF",
26142 "Purity, peace, ihram",
26143 "Pilgrimage, burial",
26144 ),
26145 "black" | "aswad" => (
26146 "Black",
26147 "أسود",
26148 "#000000",
26149 "Modesty, Kaaba",
26150 "Kiswah, abaya",
26151 ),
26152 "gold" | "dhahabi" => (
26153 "Gold",
26154 "ذهبي",
26155 "#FFD700",
26156 "Paradise, divine light",
26157 "Calligraphy, decoration",
26158 ),
26159 "blue" | "azraq" => (
26160 "Blue",
26161 "أزرق",
26162 "#0000CD",
26163 "Protection, heaven",
26164 "Tiles, evil eye",
26165 ),
26166 _ => {
26167 return Err(RuntimeError::new(
26168 "Unknown color. Use green/white/black/gold/blue",
26169 ))
26170 }
26171 };
26172 let mut map = std::collections::HashMap::new();
26173 map.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
26174 map.insert(
26175 "arabic".to_string(),
26176 Value::String(Rc::new(arabic.to_string())),
26177 );
26178 map.insert("hex".to_string(), Value::String(Rc::new(hex.to_string())));
26179 map.insert(
26180 "meaning".to_string(),
26181 Value::String(Rc::new(meaning.to_string())),
26182 );
26183 map.insert(
26184 "usage".to_string(),
26185 Value::String(Rc::new(usage.to_string())),
26186 );
26187 Ok(Value::Map(Rc::new(RefCell::new(map))))
26188 });
26189
26190 define(interp, "thai_day_color", Some(1), |_, args| {
26194 let day = match &args[0] {
26195 Value::String(s) => s.to_lowercase(),
26196 Value::Int(n) => n.to_string(),
26197 _ => return Err(RuntimeError::new("requires string or number")),
26198 };
26199 let (day_name, thai, color, hex, deity) = match day.as_str() {
26200 "sunday" | "0" => ("Sunday", "วันอาทิตย์", "Red", "#FF0000", "Surya"),
26201 "monday" | "1" => ("Monday", "วันจันทร์", "Yellow", "#FFFF00", "Chandra"),
26202 "tuesday" | "2" => ("Tuesday", "วันอังคาร", "Pink", "#FFC0CB", "Mangala"),
26203 "wednesday" | "3" => ("Wednesday", "วันพุธ", "Green", "#00FF00", "Budha"),
26204 "thursday" | "4" => ("Thursday", "วันพฤหัสบดี", "Orange", "#FFA500", "Brihaspati"),
26205 "friday" | "5" => ("Friday", "วันศุกร์", "Blue", "#00BFFF", "Shukra"),
26206 "saturday" | "6" => ("Saturday", "วันเสาร์", "Purple", "#800080", "Shani"),
26207 _ => return Err(RuntimeError::new("Unknown day. Use sunday-saturday or 0-6")),
26208 };
26209 let mut map = std::collections::HashMap::new();
26210 map.insert(
26211 "day".to_string(),
26212 Value::String(Rc::new(day_name.to_string())),
26213 );
26214 map.insert("thai".to_string(), Value::String(Rc::new(thai.to_string())));
26215 map.insert(
26216 "color".to_string(),
26217 Value::String(Rc::new(color.to_string())),
26218 );
26219 map.insert("hex".to_string(), Value::String(Rc::new(hex.to_string())));
26220 map.insert(
26221 "deity".to_string(),
26222 Value::String(Rc::new(deity.to_string())),
26223 );
26224 Ok(Value::Map(Rc::new(RefCell::new(map))))
26225 });
26226
26227 define(interp, "aboriginal_color", Some(1), |_, args| {
26231 let color = match &args[0] {
26232 Value::String(s) => s.to_lowercase(),
26233 _ => return Err(RuntimeError::new("requires string")),
26234 };
26235 let (name, hex, meaning, source, dreamtime) = match color.as_str() {
26236 "red" | "ochre" => (
26237 "Red Ochre",
26238 "#CC5500",
26239 "Earth, blood, ceremony",
26240 "Hematite",
26241 "Ancestral beings",
26242 ),
26243 "yellow" => (
26244 "Yellow Ochre",
26245 "#D4A017",
26246 "Sun, healing",
26247 "Limonite",
26248 "Sun's journey",
26249 ),
26250 "white" => (
26251 "White",
26252 "#FFFFFF",
26253 "Sky, spirits, mourning",
26254 "Kaolin",
26255 "Sky beings",
26256 ),
26257 "black" => (
26258 "Black",
26259 "#000000",
26260 "Night, formality",
26261 "Charcoal",
26262 "Night, men's business",
26263 ),
26264 "brown" => (
26265 "Brown",
26266 "#8B4513",
26267 "Earth, land",
26268 "Earth pigments",
26269 "Country, connection",
26270 ),
26271 _ => {
26272 return Err(RuntimeError::new(
26273 "Unknown color. Use red/yellow/white/black/brown",
26274 ))
26275 }
26276 };
26277 let mut map = std::collections::HashMap::new();
26278 map.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
26279 map.insert("hex".to_string(), Value::String(Rc::new(hex.to_string())));
26280 map.insert(
26281 "meaning".to_string(),
26282 Value::String(Rc::new(meaning.to_string())),
26283 );
26284 map.insert(
26285 "source".to_string(),
26286 Value::String(Rc::new(source.to_string())),
26287 );
26288 map.insert(
26289 "dreamtime".to_string(),
26290 Value::String(Rc::new(dreamtime.to_string())),
26291 );
26292 Ok(Value::Map(Rc::new(RefCell::new(map))))
26293 });
26294
26295 define(interp, "celtic_color", Some(1), |_, args| {
26299 let color = match &args[0] {
26300 Value::String(s) => s.to_lowercase(),
26301 _ => return Err(RuntimeError::new("requires string")),
26302 };
26303 let (name, gaelic, hex, meaning, element) = match color.as_str() {
26304 "green" => (
26305 "Green",
26306 "Glas",
26307 "#228B22",
26308 "Nature, fairies, Otherworld",
26309 "Earth",
26310 ),
26311 "white" => ("White", "Bán", "#FFFFFF", "Purity, spirits", "Air"),
26312 "red" => ("Red", "Dearg", "#FF0000", "War, courage, blood", "Fire"),
26313 "black" => (
26314 "Black",
26315 "Dubh",
26316 "#000000",
26317 "Otherworld, death, rebirth",
26318 "Water",
26319 ),
26320 "gold" => ("Gold", "Órga", "#FFD700", "Sun, sovereignty, Lugh", "Fire"),
26321 "silver" => (
26322 "Silver",
26323 "Airgid",
26324 "#C0C0C0",
26325 "Moon, feminine, intuition",
26326 "Water",
26327 ),
26328 _ => {
26329 return Err(RuntimeError::new(
26330 "Unknown color. Use green/white/red/black/gold/silver",
26331 ))
26332 }
26333 };
26334 let mut map = std::collections::HashMap::new();
26335 map.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
26336 map.insert(
26337 "gaelic".to_string(),
26338 Value::String(Rc::new(gaelic.to_string())),
26339 );
26340 map.insert("hex".to_string(), Value::String(Rc::new(hex.to_string())));
26341 map.insert(
26342 "meaning".to_string(),
26343 Value::String(Rc::new(meaning.to_string())),
26344 );
26345 map.insert(
26346 "element".to_string(),
26347 Value::String(Rc::new(element.to_string())),
26348 );
26349 Ok(Value::Map(Rc::new(RefCell::new(map))))
26350 });
26351
26352 define(interp, "kente_color", Some(1), |_, args| {
26356 let color = match &args[0] {
26357 Value::String(s) => s.to_lowercase(),
26358 _ => return Err(RuntimeError::new("requires string")),
26359 };
26360 let (name, twi, hex, meaning) = match color.as_str() {
26361 "gold" | "yellow" => ("Gold", "Sika Kɔkɔɔ", "#FFD700", "Royalty, wealth, glory"),
26362 "green" => ("Green", "Ahabammono", "#228B22", "Growth, renewal, harvest"),
26363 "blue" => ("Blue", "Bruu", "#0000CD", "Peace, harmony, love"),
26364 "red" => ("Red", "Kɔkɔɔ", "#FF0000", "Blood, sacrifice, power"),
26365 "black" => ("Black", "Tuntum", "#000000", "Maturation, ancestors"),
26366 "white" => ("White", "Fitaa", "#FFFFFF", "Purification, virtue, joy"),
26367 "maroon" => ("Maroon", "Borɔnɔ", "#800000", "Earth, healing, protection"),
26368 _ => {
26369 return Err(RuntimeError::new(
26370 "Unknown color. Use gold/green/blue/red/black/white/maroon",
26371 ))
26372 }
26373 };
26374 let mut map = std::collections::HashMap::new();
26375 map.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
26376 map.insert("twi".to_string(), Value::String(Rc::new(twi.to_string())));
26377 map.insert("hex".to_string(), Value::String(Rc::new(hex.to_string())));
26378 map.insert(
26379 "meaning".to_string(),
26380 Value::String(Rc::new(meaning.to_string())),
26381 );
26382 Ok(Value::Map(Rc::new(RefCell::new(map))))
26383 });
26384
26385 define(interp, "hindu_color", Some(1), |_, args| {
26389 let color = match &args[0] {
26390 Value::String(s) => s.to_lowercase(),
26391 _ => return Err(RuntimeError::new("requires string")),
26392 };
26393 let (name, hindi, hex, meaning, deities) = match color.as_str() {
26394 "red" | "lal" => (
26395 "Red",
26396 "लाल",
26397 "#FF0000",
26398 "Purity, fertility, love",
26399 "Durga, Lakshmi",
26400 ),
26401 "orange" | "saffron" => (
26402 "Saffron",
26403 "केसरी",
26404 "#FF6600",
26405 "Sacred, renunciation",
26406 "Hanuman",
26407 ),
26408 "yellow" => (
26409 "Yellow",
26410 "पीला",
26411 "#FFFF00",
26412 "Knowledge, learning",
26413 "Vishnu, Saraswati",
26414 ),
26415 "green" => ("Green", "हरा", "#008000", "Life, happiness", "Krishna"),
26416 "white" => (
26417 "White",
26418 "सफ़ेद",
26419 "#FFFFFF",
26420 "Purity, mourning",
26421 "Saraswati, Shiva",
26422 ),
26423 "blue" => (
26424 "Blue",
26425 "नीला",
26426 "#0000FF",
26427 "Divinity, infinity",
26428 "Krishna, Vishnu",
26429 ),
26430 "black" => (
26431 "Black",
26432 "काला",
26433 "#000000",
26434 "Protection from evil",
26435 "Kali, Shani",
26436 ),
26437 _ => {
26438 return Err(RuntimeError::new(
26439 "Unknown color. Use red/orange/yellow/green/white/blue/black",
26440 ))
26441 }
26442 };
26443 let mut map = std::collections::HashMap::new();
26444 map.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
26445 map.insert(
26446 "hindi".to_string(),
26447 Value::String(Rc::new(hindi.to_string())),
26448 );
26449 map.insert("hex".to_string(), Value::String(Rc::new(hex.to_string())));
26450 map.insert(
26451 "meaning".to_string(),
26452 Value::String(Rc::new(meaning.to_string())),
26453 );
26454 map.insert(
26455 "deities".to_string(),
26456 Value::String(Rc::new(deities.to_string())),
26457 );
26458 Ok(Value::Map(Rc::new(RefCell::new(map))))
26459 });
26460
26461 define(interp, "emotion_color", Some(2), |_, args| {
26465 let emotion = match &args[0] {
26466 Value::String(s) => s.to_lowercase(),
26467 _ => return Err(RuntimeError::new("requires string")),
26468 };
26469 let culture = match &args[1] {
26470 Value::String(s) => s.to_lowercase(),
26471 _ => return Err(RuntimeError::new("requires string")),
26472 };
26473 let (hex, name, reasoning) = match (emotion.as_str(), culture.as_str()) {
26474 ("joy", "western") | ("happy", "western") => {
26475 ("#FFD700", "Gold", "Sunshine = happiness")
26476 }
26477 ("joy", "chinese") | ("happy", "chinese") => ("#FF0000", "Red", "红 = luck, joy"),
26478 ("joy", "japanese") => ("#FFB7C5", "Sakura", "Cherry blossom = fleeting joy"),
26479 ("sadness", "western") | ("sad", "western") => ("#0000CD", "Blue", "'Feeling blue'"),
26480 ("sadness", "chinese") | ("sad", "chinese") => ("#FFFFFF", "White", "白 = mourning"),
26481 ("sadness", "indian") => ("#FFFFFF", "White", "सफ़ेद = mourning"),
26482 ("anger", _) => ("#FF0000", "Red", "Universal heat/fire"),
26483 ("love", "western") => ("#FF69B4", "Pink", "Valentine's hearts"),
26484 ("love", "chinese") | ("love", "indian") => ("#FF0000", "Red", "Red = marriage, love"),
26485 ("peace", "western") => ("#ADD8E6", "Light Blue", "Sky, serenity"),
26486 ("peace", "islamic") => ("#00FF00", "Green", "السلام = paradise"),
26487 ("fear", _) => ("#4B0082", "Indigo", "Deep, mysterious"),
26488 (_, _) => ("#808080", "Grey", "Neutral"),
26489 };
26490 let r = u8::from_str_radix(&hex[1..3], 16).unwrap_or(128);
26491 let g = u8::from_str_radix(&hex[3..5], 16).unwrap_or(128);
26492 let b = u8::from_str_radix(&hex[5..7], 16).unwrap_or(128);
26493 let mut map = std::collections::HashMap::new();
26494 map.insert("hex".to_string(), Value::String(Rc::new(hex.to_string())));
26495 map.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
26496 map.insert("r".to_string(), Value::Int(r as i64));
26497 map.insert("g".to_string(), Value::Int(g as i64));
26498 map.insert("b".to_string(), Value::Int(b as i64));
26499 map.insert(
26500 "reasoning".to_string(),
26501 Value::String(Rc::new(reasoning.to_string())),
26502 );
26503 Ok(Value::Map(Rc::new(RefCell::new(map))))
26504 });
26505
26506 define(interp, "synesthesia", Some(2), |_, args| {
26508 let culture = match &args[1] {
26509 Value::String(s) => s.to_lowercase(),
26510 _ => return Err(RuntimeError::new("requires culture string")),
26511 };
26512 let (r, g, b, emotion, freq) = match &args[0] {
26513 Value::String(s) => match s.to_lowercase().as_str() {
26514 "joy" | "happy" => (255u8, 215u8, 0u8, "joy", 528.0),
26515 "sadness" | "sad" => (0, 0, 139, "sadness", 396.0),
26516 "anger" => (255, 0, 0, "anger", 417.0),
26517 "fear" => (75, 0, 130, "fear", 369.0),
26518 "love" => (255, 105, 180, "love", 639.0),
26519 "peace" => (135, 206, 235, "peace", 741.0),
26520 _ => (128, 128, 128, "neutral", 432.0),
26521 },
26522 Value::Int(n) => (128, 128, 255, "resonance", *n as f64),
26523 Value::Float(f) => (128, 128, 255, "resonance", *f),
26524 _ => (128, 128, 128, "neutral", 432.0),
26525 };
26526 let cultural_meaning = match culture.as_str() {
26527 "chinese" if r > 200 && g < 100 => "luck/joy (红)",
26528 "japanese" if r > 200 && g < 100 => "vitality (赤)",
26529 "indian" if r > 200 && g < 100 => "shakti/auspicious",
26530 _ => "universal resonance",
26531 };
26532 let chakra = if r > 200 && g < 100 {
26533 "Root"
26534 } else if g > 200 {
26535 "Heart"
26536 } else if b > 200 {
26537 "Throat"
26538 } else {
26539 "Crown"
26540 };
26541 let wu_xing = if r > 200 && g < 100 {
26542 "Fire (火)"
26543 } else if g > 200 {
26544 "Wood (木)"
26545 } else if b > 200 {
26546 "Water (水)"
26547 } else {
26548 "Metal (金)"
26549 };
26550 let mut map = std::collections::HashMap::new();
26551 let mut color_map = std::collections::HashMap::new();
26552 color_map.insert("r".to_string(), Value::Int(r as i64));
26553 color_map.insert("g".to_string(), Value::Int(g as i64));
26554 color_map.insert("b".to_string(), Value::Int(b as i64));
26555 color_map.insert(
26556 "hex".to_string(),
26557 Value::String(Rc::new(format!("#{:02X}{:02X}{:02X}", r, g, b))),
26558 );
26559 map.insert(
26560 "color".to_string(),
26561 Value::Map(Rc::new(RefCell::new(color_map))),
26562 );
26563 map.insert(
26564 "emotion".to_string(),
26565 Value::String(Rc::new(emotion.to_string())),
26566 );
26567 map.insert("frequency".to_string(), Value::Float(freq));
26568 map.insert(
26569 "cultural_meaning".to_string(),
26570 Value::String(Rc::new(cultural_meaning.to_string())),
26571 );
26572 map.insert(
26573 "chakra".to_string(),
26574 Value::String(Rc::new(chakra.to_string())),
26575 );
26576 map.insert(
26577 "wu_xing".to_string(),
26578 Value::String(Rc::new(wu_xing.to_string())),
26579 );
26580 Ok(Value::Map(Rc::new(RefCell::new(map))))
26581 });
26582
26583 define(interp, "color_to_sound", Some(3), |_, args| {
26585 let r = match &args[0] {
26586 Value::Int(n) => *n as f64 / 255.0,
26587 Value::Float(f) => *f / 255.0,
26588 _ => return Err(RuntimeError::new("requires numbers")),
26589 };
26590 let g = match &args[1] {
26591 Value::Int(n) => *n as f64 / 255.0,
26592 Value::Float(f) => *f / 255.0,
26593 _ => return Err(RuntimeError::new("requires numbers")),
26594 };
26595 let b = match &args[2] {
26596 Value::Int(n) => *n as f64 / 255.0,
26597 Value::Float(f) => *f / 255.0,
26598 _ => return Err(RuntimeError::new("requires numbers")),
26599 };
26600 let max = r.max(g).max(b);
26601 let min = r.min(g).min(b);
26602 let l = (max + min) / 2.0;
26603 let h = if max == min {
26604 0.0
26605 } else {
26606 let d = max - min;
26607 if max == r {
26608 (g - b) / d + if g < b { 6.0 } else { 0.0 }
26609 } else if max == g {
26610 (b - r) / d + 2.0
26611 } else {
26612 (r - g) / d + 4.0
26613 }
26614 } * 60.0;
26615 let (note, freq) = if h < 30.0 {
26616 ("C", 261.63)
26617 } else if h < 60.0 {
26618 ("G", 392.00)
26619 } else if h < 90.0 {
26620 ("D", 293.66)
26621 } else if h < 120.0 {
26622 ("A", 440.00)
26623 } else if h < 150.0 {
26624 ("E", 329.63)
26625 } else if h < 180.0 {
26626 ("B", 493.88)
26627 } else if h < 210.0 {
26628 ("F#", 369.99)
26629 } else if h < 240.0 {
26630 ("Db", 277.18)
26631 } else if h < 270.0 {
26632 ("Ab", 415.30)
26633 } else if h < 300.0 {
26634 ("Eb", 311.13)
26635 } else if h < 330.0 {
26636 ("Bb", 466.16)
26637 } else {
26638 ("F", 349.23)
26639 };
26640 let octave_shift = ((l - 0.5) * 4.0).round() as i32;
26641 let adjusted_freq = freq * 2.0_f64.powi(octave_shift);
26642 let mut map = std::collections::HashMap::new();
26643 map.insert("note".to_string(), Value::String(Rc::new(note.to_string())));
26644 map.insert("frequency".to_string(), Value::Float(adjusted_freq));
26645 map.insert("hue".to_string(), Value::Float(h));
26646 Ok(Value::Map(Rc::new(RefCell::new(map))))
26647 });
26648
26649 define(interp, "contrast_ratio", Some(6), |_, args| {
26651 fn lum(r: f64, g: f64, b: f64) -> f64 {
26652 fn ch(c: f64) -> f64 {
26653 let c = c / 255.0;
26654 if c <= 0.03928 {
26655 c / 12.92
26656 } else {
26657 ((c + 0.055) / 1.055).powf(2.4)
26658 }
26659 }
26660 0.2126 * ch(r) + 0.7152 * ch(g) + 0.0722 * ch(b)
26661 }
26662 let r1 = match &args[0] {
26663 Value::Int(n) => *n as f64,
26664 Value::Float(f) => *f,
26665 _ => return Err(RuntimeError::new("requires numbers")),
26666 };
26667 let g1 = match &args[1] {
26668 Value::Int(n) => *n as f64,
26669 Value::Float(f) => *f,
26670 _ => return Err(RuntimeError::new("requires numbers")),
26671 };
26672 let b1 = match &args[2] {
26673 Value::Int(n) => *n as f64,
26674 Value::Float(f) => *f,
26675 _ => return Err(RuntimeError::new("requires numbers")),
26676 };
26677 let r2 = match &args[3] {
26678 Value::Int(n) => *n as f64,
26679 Value::Float(f) => *f,
26680 _ => return Err(RuntimeError::new("requires numbers")),
26681 };
26682 let g2 = match &args[4] {
26683 Value::Int(n) => *n as f64,
26684 Value::Float(f) => *f,
26685 _ => return Err(RuntimeError::new("requires numbers")),
26686 };
26687 let b2 = match &args[5] {
26688 Value::Int(n) => *n as f64,
26689 Value::Float(f) => *f,
26690 _ => return Err(RuntimeError::new("requires numbers")),
26691 };
26692 let l1 = lum(r1, g1, b1);
26693 let l2 = lum(r2, g2, b2);
26694 let ratio = if l1 > l2 {
26695 (l1 + 0.05) / (l2 + 0.05)
26696 } else {
26697 (l2 + 0.05) / (l1 + 0.05)
26698 };
26699 let mut map = std::collections::HashMap::new();
26700 map.insert("ratio".to_string(), Value::Float(ratio));
26701 map.insert("aa_normal".to_string(), Value::Bool(ratio >= 4.5));
26702 map.insert("aa_large".to_string(), Value::Bool(ratio >= 3.0));
26703 map.insert("aaa_normal".to_string(), Value::Bool(ratio >= 7.0));
26704 Ok(Value::Map(Rc::new(RefCell::new(map))))
26705 });
26706}
26707
26708fn register_protocol(interp: &mut Interpreter) {
26716 define(interp, "protocol_info", Some(0), |_, _args| {
26718 let mut map = std::collections::HashMap::new();
26719 map.insert(
26720 "http".to_string(),
26721 Value::Map(Rc::new(RefCell::new({
26722 let mut m = std::collections::HashMap::new();
26723 m.insert(
26724 "name".to_string(),
26725 Value::String(Rc::new("HTTP".to_string())),
26726 );
26727 m.insert(
26728 "versions".to_string(),
26729 Value::Array(Rc::new(RefCell::new(vec![
26730 Value::String(Rc::new("1.1".to_string())),
26731 Value::String(Rc::new("2".to_string())),
26732 ]))),
26733 );
26734 m.insert(
26735 "methods".to_string(),
26736 Value::Array(Rc::new(RefCell::new(vec![
26737 Value::String(Rc::new("GET".to_string())),
26738 Value::String(Rc::new("POST".to_string())),
26739 Value::String(Rc::new("PUT".to_string())),
26740 Value::String(Rc::new("DELETE".to_string())),
26741 Value::String(Rc::new("PATCH".to_string())),
26742 Value::String(Rc::new("HEAD".to_string())),
26743 Value::String(Rc::new("OPTIONS".to_string())),
26744 ]))),
26745 );
26746 m
26747 }))),
26748 );
26749 map.insert(
26750 "grpc".to_string(),
26751 Value::Map(Rc::new(RefCell::new({
26752 let mut m = std::collections::HashMap::new();
26753 m.insert(
26754 "name".to_string(),
26755 Value::String(Rc::new("gRPC".to_string())),
26756 );
26757 m.insert(
26758 "streaming_modes".to_string(),
26759 Value::Array(Rc::new(RefCell::new(vec![
26760 Value::String(Rc::new("unary".to_string())),
26761 Value::String(Rc::new("server_streaming".to_string())),
26762 Value::String(Rc::new("client_streaming".to_string())),
26763 Value::String(Rc::new("bidirectional".to_string())),
26764 ]))),
26765 );
26766 m
26767 }))),
26768 );
26769 map.insert(
26770 "websocket".to_string(),
26771 Value::Map(Rc::new(RefCell::new({
26772 let mut m = std::collections::HashMap::new();
26773 m.insert(
26774 "name".to_string(),
26775 Value::String(Rc::new("WebSocket".to_string())),
26776 );
26777 m.insert(
26778 "message_types".to_string(),
26779 Value::Array(Rc::new(RefCell::new(vec![
26780 Value::String(Rc::new("text".to_string())),
26781 Value::String(Rc::new("binary".to_string())),
26782 Value::String(Rc::new("ping".to_string())),
26783 Value::String(Rc::new("pong".to_string())),
26784 Value::String(Rc::new("close".to_string())),
26785 ]))),
26786 );
26787 m
26788 }))),
26789 );
26790 map.insert(
26791 "kafka".to_string(),
26792 Value::Map(Rc::new(RefCell::new({
26793 let mut m = std::collections::HashMap::new();
26794 m.insert(
26795 "name".to_string(),
26796 Value::String(Rc::new("Apache Kafka".to_string())),
26797 );
26798 m.insert(
26799 "acks".to_string(),
26800 Value::Array(Rc::new(RefCell::new(vec![
26801 Value::String(Rc::new("none".to_string())),
26802 Value::String(Rc::new("leader".to_string())),
26803 Value::String(Rc::new("all".to_string())),
26804 ]))),
26805 );
26806 m
26807 }))),
26808 );
26809 map.insert(
26810 "amqp".to_string(),
26811 Value::Map(Rc::new(RefCell::new({
26812 let mut m = std::collections::HashMap::new();
26813 m.insert(
26814 "name".to_string(),
26815 Value::String(Rc::new("AMQP".to_string())),
26816 );
26817 m.insert(
26818 "exchange_types".to_string(),
26819 Value::Array(Rc::new(RefCell::new(vec![
26820 Value::String(Rc::new("direct".to_string())),
26821 Value::String(Rc::new("fanout".to_string())),
26822 Value::String(Rc::new("topic".to_string())),
26823 Value::String(Rc::new("headers".to_string())),
26824 ]))),
26825 );
26826 m
26827 }))),
26828 );
26829 map.insert(
26830 "graphql".to_string(),
26831 Value::Map(Rc::new(RefCell::new({
26832 let mut m = std::collections::HashMap::new();
26833 m.insert(
26834 "name".to_string(),
26835 Value::String(Rc::new("GraphQL".to_string())),
26836 );
26837 m.insert(
26838 "operations".to_string(),
26839 Value::Array(Rc::new(RefCell::new(vec![
26840 Value::String(Rc::new("query".to_string())),
26841 Value::String(Rc::new("mutation".to_string())),
26842 Value::String(Rc::new("subscription".to_string())),
26843 ]))),
26844 );
26845 m
26846 }))),
26847 );
26848 Ok(Value::Map(Rc::new(RefCell::new(map))))
26849 });
26850
26851 define(interp, "http_status_text", Some(1), |_, args| {
26853 let code = match &args[0] {
26854 Value::Int(n) => *n,
26855 _ => {
26856 return Err(RuntimeError::new(
26857 "http_status_text requires integer status code",
26858 ))
26859 }
26860 };
26861 let text = match code {
26862 100 => "Continue",
26863 101 => "Switching Protocols",
26864 200 => "OK",
26865 201 => "Created",
26866 202 => "Accepted",
26867 204 => "No Content",
26868 301 => "Moved Permanently",
26869 302 => "Found",
26870 304 => "Not Modified",
26871 307 => "Temporary Redirect",
26872 308 => "Permanent Redirect",
26873 400 => "Bad Request",
26874 401 => "Unauthorized",
26875 403 => "Forbidden",
26876 404 => "Not Found",
26877 405 => "Method Not Allowed",
26878 409 => "Conflict",
26879 422 => "Unprocessable Entity",
26880 429 => "Too Many Requests",
26881 500 => "Internal Server Error",
26882 502 => "Bad Gateway",
26883 503 => "Service Unavailable",
26884 504 => "Gateway Timeout",
26885 _ => "Unknown",
26886 };
26887 Ok(Value::String(Rc::new(text.to_string())))
26888 });
26889
26890 define(interp, "http_status_type", Some(1), |_, args| {
26892 let code = match &args[0] {
26893 Value::Int(n) => *n,
26894 _ => {
26895 return Err(RuntimeError::new(
26896 "http_status_type requires integer status code",
26897 ))
26898 }
26899 };
26900 let status_type = match code {
26901 100..=199 => "informational",
26902 200..=299 => "success",
26903 300..=399 => "redirect",
26904 400..=499 => "client_error",
26905 500..=599 => "server_error",
26906 _ => "unknown",
26907 };
26908 Ok(Value::String(Rc::new(status_type.to_string())))
26909 });
26910
26911 define(interp, "grpc_status_text", Some(1), |_, args| {
26913 let code = match &args[0] {
26914 Value::Int(n) => *n,
26915 _ => {
26916 return Err(RuntimeError::new(
26917 "grpc_status_text requires integer status code",
26918 ))
26919 }
26920 };
26921 let text = match code {
26922 0 => "OK",
26923 1 => "CANCELLED",
26924 2 => "UNKNOWN",
26925 3 => "INVALID_ARGUMENT",
26926 4 => "DEADLINE_EXCEEDED",
26927 5 => "NOT_FOUND",
26928 6 => "ALREADY_EXISTS",
26929 7 => "PERMISSION_DENIED",
26930 8 => "RESOURCE_EXHAUSTED",
26931 9 => "FAILED_PRECONDITION",
26932 10 => "ABORTED",
26933 11 => "OUT_OF_RANGE",
26934 12 => "UNIMPLEMENTED",
26935 13 => "INTERNAL",
26936 14 => "UNAVAILABLE",
26937 15 => "DATA_LOSS",
26938 16 => "UNAUTHENTICATED",
26939 _ => "UNKNOWN",
26940 };
26941 Ok(Value::String(Rc::new(text.to_string())))
26942 });
26943
26944 define(interp, "url_parse", Some(1), |_, args| {
26946 let url_str = match &args[0] {
26947 Value::String(s) => s.as_str().to_string(),
26948 _ => return Err(RuntimeError::new("url_parse requires string URL")),
26949 };
26950
26951 let mut map = std::collections::HashMap::new();
26953
26954 let (scheme, rest) = if let Some(pos) = url_str.find("://") {
26956 (url_str[..pos].to_string(), &url_str[pos + 3..])
26957 } else {
26958 return Err(RuntimeError::new("Invalid URL: missing scheme"));
26959 };
26960 map.insert("scheme".to_string(), Value::String(Rc::new(scheme)));
26961
26962 let (authority, path_and_rest) = if let Some(pos) = rest.find('/') {
26964 (&rest[..pos], &rest[pos..])
26965 } else {
26966 (rest, "/")
26967 };
26968
26969 let (host, port) = if let Some(pos) = authority.rfind(':') {
26971 if let Ok(p) = authority[pos + 1..].parse::<i64>() {
26972 (authority[..pos].to_string(), Some(p))
26973 } else {
26974 (authority.to_string(), None)
26975 }
26976 } else {
26977 (authority.to_string(), None)
26978 };
26979 map.insert("host".to_string(), Value::String(Rc::new(host)));
26980 map.insert(
26981 "port".to_string(),
26982 port.map(Value::Int).unwrap_or(Value::Null),
26983 );
26984
26985 let (path, query) = if let Some(pos) = path_and_rest.find('?') {
26987 (&path_and_rest[..pos], Some(&path_and_rest[pos + 1..]))
26988 } else {
26989 (path_and_rest, None)
26990 };
26991 map.insert("path".to_string(), Value::String(Rc::new(path.to_string())));
26992 map.insert(
26993 "query".to_string(),
26994 query
26995 .map(|q| Value::String(Rc::new(q.to_string())))
26996 .unwrap_or(Value::Null),
26997 );
26998
26999 Ok(Value::Map(Rc::new(RefCell::new(map))))
27000 });
27001
27002 define(interp, "url_encode", Some(1), |_, args| {
27004 let s = match &args[0] {
27005 Value::String(s) => s.as_str(),
27006 _ => return Err(RuntimeError::new("url_encode requires string")),
27007 };
27008 let mut result = String::new();
27009 for c in s.chars() {
27010 match c {
27011 'a'..='z' | 'A'..='Z' | '0'..='9' | '-' | '_' | '.' | '~' => {
27012 result.push(c);
27013 }
27014 ' ' => result.push_str("%20"),
27015 _ => {
27016 for b in c.to_string().as_bytes() {
27017 result.push_str(&format!("%{:02X}", b));
27018 }
27019 }
27020 }
27021 }
27022 Ok(Value::String(Rc::new(result)))
27023 });
27024
27025 define(interp, "url_decode", Some(1), |_, args| {
27027 let s = match &args[0] {
27028 Value::String(s) => s.as_str().to_string(),
27029 _ => return Err(RuntimeError::new("url_decode requires string")),
27030 };
27031 let mut result = Vec::new();
27032 let bytes = s.as_bytes();
27033 let mut i = 0;
27034 while i < bytes.len() {
27035 if bytes[i] == b'%' && i + 2 < bytes.len() {
27036 if let Ok(b) =
27037 u8::from_str_radix(&String::from_utf8_lossy(&bytes[i + 1..i + 3]), 16)
27038 {
27039 result.push(b);
27040 i += 3;
27041 continue;
27042 }
27043 } else if bytes[i] == b'+' {
27044 result.push(b' ');
27045 i += 1;
27046 continue;
27047 }
27048 result.push(bytes[i]);
27049 i += 1;
27050 }
27051 Ok(Value::String(Rc::new(
27052 String::from_utf8_lossy(&result).to_string(),
27053 )))
27054 });
27055
27056 define(interp, "ws_close_code_text", Some(1), |_, args| {
27058 let code = match &args[0] {
27059 Value::Int(n) => *n,
27060 _ => {
27061 return Err(RuntimeError::new(
27062 "ws_close_code_text requires integer code",
27063 ))
27064 }
27065 };
27066 let text = match code {
27067 1000 => "Normal Closure",
27068 1001 => "Going Away",
27069 1002 => "Protocol Error",
27070 1003 => "Unsupported Data",
27071 1005 => "No Status Received",
27072 1006 => "Abnormal Closure",
27073 1007 => "Invalid Payload Data",
27074 1008 => "Policy Violation",
27075 1009 => "Message Too Big",
27076 1010 => "Missing Extension",
27077 1011 => "Internal Error",
27078 1015 => "TLS Handshake Failure",
27079 _ => "Unknown",
27080 };
27081 Ok(Value::String(Rc::new(text.to_string())))
27082 });
27083
27084 define(interp, "mime_type", Some(1), |_, args| {
27086 let ext = match &args[0] {
27087 Value::String(s) => s.as_str().to_lowercase(),
27088 _ => return Err(RuntimeError::new("mime_type requires string extension")),
27089 };
27090 let ext = ext.trim_start_matches('.');
27091 let mime = match ext {
27092 "html" | "htm" => "text/html",
27093 "css" => "text/css",
27094 "js" | "mjs" => "text/javascript",
27095 "json" => "application/json",
27096 "xml" => "application/xml",
27097 "txt" => "text/plain",
27098 "csv" => "text/csv",
27099 "png" => "image/png",
27100 "jpg" | "jpeg" => "image/jpeg",
27101 "gif" => "image/gif",
27102 "svg" => "image/svg+xml",
27103 "webp" => "image/webp",
27104 "ico" => "image/x-icon",
27105 "pdf" => "application/pdf",
27106 "zip" => "application/zip",
27107 "gz" | "gzip" => "application/gzip",
27108 "mp3" => "audio/mpeg",
27109 "mp4" => "video/mp4",
27110 "webm" => "video/webm",
27111 "woff" => "font/woff",
27112 "woff2" => "font/woff2",
27113 "ttf" => "font/ttf",
27114 "otf" => "font/otf",
27115 "wasm" => "application/wasm",
27116 "proto" => "application/protobuf",
27117 _ => "application/octet-stream",
27118 };
27119 Ok(Value::String(Rc::new(mime.to_string())))
27120 });
27121
27122 define(interp, "content_type_parse", Some(1), |_, args| {
27124 let ct = match &args[0] {
27125 Value::String(s) => s.as_str().to_string(),
27126 _ => return Err(RuntimeError::new("content_type_parse requires string")),
27127 };
27128 let mut map = std::collections::HashMap::new();
27129 let parts: Vec<&str> = ct.split(';').collect();
27130 map.insert(
27131 "media_type".to_string(),
27132 Value::String(Rc::new(parts[0].trim().to_string())),
27133 );
27134
27135 let mut params = std::collections::HashMap::new();
27136 for part in parts.iter().skip(1) {
27137 let kv: Vec<&str> = part.splitn(2, '=').collect();
27138 if kv.len() == 2 {
27139 let key = kv[0].trim().to_lowercase();
27140 let value = kv[1].trim().trim_matches('"').to_string();
27141 params.insert(key, Value::String(Rc::new(value)));
27142 }
27143 }
27144 map.insert(
27145 "params".to_string(),
27146 Value::Map(Rc::new(RefCell::new(params))),
27147 );
27148 Ok(Value::Map(Rc::new(RefCell::new(map))))
27149 });
27150
27151 #[cfg(feature = "http-client")]
27160 define(interp, "http_get", Some(1), |_, args| {
27161 let url = match &args[0] {
27162 Value::String(s) => s.as_str().to_string(),
27163 _ => return Err(RuntimeError::new("http_get requires string URL")),
27164 };
27165
27166 match reqwest::blocking::get(&url) {
27167 Ok(response) => {
27168 let status = response.status().as_u16() as i64;
27169 let mut headers_map = std::collections::HashMap::new();
27170 for (name, value) in response.headers() {
27171 if let Ok(v) = value.to_str() {
27172 headers_map.insert(
27173 name.as_str().to_string(),
27174 Value::String(Rc::new(v.to_string())),
27175 );
27176 }
27177 }
27178 let body = response.text().unwrap_or_default();
27179
27180 let mut result = std::collections::HashMap::new();
27181 result.insert("status".to_string(), Value::Int(status));
27182 result.insert(
27183 "headers".to_string(),
27184 Value::Map(Rc::new(RefCell::new(headers_map))),
27185 );
27186 result.insert("body".to_string(), Value::String(Rc::new(body)));
27187 Ok(Value::Map(Rc::new(RefCell::new(result))))
27188 }
27189 Err(e) => {
27190 let mut result = std::collections::HashMap::new();
27191 result.insert("status".to_string(), Value::Int(0));
27192 result.insert(
27193 "error".to_string(),
27194 Value::String(Rc::new(e.to_string())),
27195 );
27196 Ok(Value::Map(Rc::new(RefCell::new(result))))
27197 }
27198 }
27199 });
27200
27201 #[cfg(feature = "http-client")]
27204 define(interp, "http_post", Some(2), |_, args| {
27205 let url = match &args[0] {
27206 Value::String(s) => s.as_str().to_string(),
27207 _ => return Err(RuntimeError::new("http_post requires string URL")),
27208 };
27209 let body = match &args[1] {
27210 Value::String(s) => s.as_str().to_string(),
27211 _ => return Err(RuntimeError::new("http_post requires string body")),
27212 };
27213
27214 let client = reqwest::blocking::Client::new();
27215 match client.post(&url).body(body).send() {
27216 Ok(response) => {
27217 let status = response.status().as_u16() as i64;
27218 let mut headers_map = std::collections::HashMap::new();
27219 for (name, value) in response.headers() {
27220 if let Ok(v) = value.to_str() {
27221 headers_map.insert(
27222 name.as_str().to_string(),
27223 Value::String(Rc::new(v.to_string())),
27224 );
27225 }
27226 }
27227 let response_body = response.text().unwrap_or_default();
27228
27229 let mut result = std::collections::HashMap::new();
27230 result.insert("status".to_string(), Value::Int(status));
27231 result.insert(
27232 "headers".to_string(),
27233 Value::Map(Rc::new(RefCell::new(headers_map))),
27234 );
27235 result.insert("body".to_string(), Value::String(Rc::new(response_body)));
27236 Ok(Value::Map(Rc::new(RefCell::new(result))))
27237 }
27238 Err(e) => {
27239 let mut result = std::collections::HashMap::new();
27240 result.insert("status".to_string(), Value::Int(0));
27241 result.insert(
27242 "error".to_string(),
27243 Value::String(Rc::new(e.to_string())),
27244 );
27245 Ok(Value::Map(Rc::new(RefCell::new(result))))
27246 }
27247 }
27248 });
27249
27250 #[cfg(feature = "http-client")]
27253 define(interp, "http_post_json", Some(2), |_, args| {
27254 fn value_to_json_inner(val: &Value) -> serde_json::Value {
27255 match val {
27256 Value::Null => serde_json::Value::Null,
27257 Value::Bool(b) => serde_json::Value::Bool(*b),
27258 Value::Int(n) => serde_json::Value::Number(serde_json::Number::from(*n)),
27259 Value::Float(f) => serde_json::Number::from_f64(*f)
27260 .map(serde_json::Value::Number)
27261 .unwrap_or(serde_json::Value::Null),
27262 Value::String(s) => serde_json::Value::String(s.to_string()),
27263 Value::Array(arr) => {
27264 let arr = arr.borrow();
27265 serde_json::Value::Array(arr.iter().map(value_to_json_inner).collect())
27266 }
27267 Value::Map(map) => {
27268 let map = map.borrow();
27269 let obj: serde_json::Map<String, serde_json::Value> = map
27270 .iter()
27271 .map(|(k, v)| (k.clone(), value_to_json_inner(v)))
27272 .collect();
27273 serde_json::Value::Object(obj)
27274 }
27275 _ => serde_json::Value::String(format!("{}", val)),
27276 }
27277 }
27278
27279 let url = match &args[0] {
27280 Value::String(s) => s.as_str().to_string(),
27281 _ => return Err(RuntimeError::new("http_post_json requires string URL")),
27282 };
27283 let json_body = match &args[1] {
27284 Value::String(s) => s.as_str().to_string(),
27285 v => serde_json::to_string(&value_to_json_inner(v)).unwrap_or_default(),
27286 };
27287
27288 let client = reqwest::blocking::Client::new();
27289 match client
27290 .post(&url)
27291 .header("Content-Type", "application/json")
27292 .body(json_body)
27293 .send()
27294 {
27295 Ok(response) => {
27296 let status = response.status().as_u16() as i64;
27297 let mut headers_map = std::collections::HashMap::new();
27298 for (name, value) in response.headers() {
27299 if let Ok(v) = value.to_str() {
27300 headers_map.insert(
27301 name.as_str().to_string(),
27302 Value::String(Rc::new(v.to_string())),
27303 );
27304 }
27305 }
27306 let response_body = response.text().unwrap_or_default();
27307
27308 let mut result = std::collections::HashMap::new();
27309 result.insert("status".to_string(), Value::Int(status));
27310 result.insert(
27311 "headers".to_string(),
27312 Value::Map(Rc::new(RefCell::new(headers_map))),
27313 );
27314 result.insert("body".to_string(), Value::String(Rc::new(response_body)));
27315 Ok(Value::Map(Rc::new(RefCell::new(result))))
27316 }
27317 Err(e) => {
27318 let mut result = std::collections::HashMap::new();
27319 result.insert("status".to_string(), Value::Int(0));
27320 result.insert(
27321 "error".to_string(),
27322 Value::String(Rc::new(e.to_string())),
27323 );
27324 Ok(Value::Map(Rc::new(RefCell::new(result))))
27325 }
27326 }
27327 });
27328
27329 #[cfg(feature = "http-client")]
27333 define(interp, "http_request", None, |_, args| {
27334 if args.is_empty() {
27335 return Err(RuntimeError::new(
27336 "http_request requires at least method and url",
27337 ));
27338 }
27339
27340 let method = match &args[0] {
27341 Value::String(s) => s.as_str().to_uppercase(),
27342 _ => return Err(RuntimeError::new("http_request requires string method")),
27343 };
27344
27345 let url = if args.len() > 1 {
27346 match &args[1] {
27347 Value::String(s) => s.as_str().to_string(),
27348 _ => return Err(RuntimeError::new("http_request requires string URL")),
27349 }
27350 } else {
27351 return Err(RuntimeError::new("http_request requires URL"));
27352 };
27353
27354 let headers: std::collections::HashMap<String, String> = if args.len() > 2 {
27355 match &args[2] {
27356 Value::Map(m) => {
27357 let map = m.borrow();
27358 map.iter()
27359 .filter_map(|(k, v)| {
27360 if let Value::String(s) = v {
27361 Some((k.clone(), s.as_str().to_string()))
27362 } else {
27363 None
27364 }
27365 })
27366 .collect()
27367 }
27368 Value::Null => std::collections::HashMap::new(),
27369 _ => std::collections::HashMap::new(),
27370 }
27371 } else {
27372 std::collections::HashMap::new()
27373 };
27374
27375 let body: Option<String> = if args.len() > 3 {
27376 match &args[3] {
27377 Value::String(s) => Some(s.as_str().to_string()),
27378 Value::Null => None,
27379 _ => None,
27380 }
27381 } else {
27382 None
27383 };
27384
27385 let client = reqwest::blocking::Client::new();
27386 let mut request = match method.as_str() {
27387 "GET" => client.get(&url),
27388 "POST" => client.post(&url),
27389 "PUT" => client.put(&url),
27390 "DELETE" => client.delete(&url),
27391 "PATCH" => client.patch(&url),
27392 "HEAD" => client.head(&url),
27393 _ => return Err(RuntimeError::new(&format!("Unsupported HTTP method: {}", method))),
27394 };
27395
27396 for (key, value) in headers {
27397 request = request.header(&key, &value);
27398 }
27399
27400 if let Some(b) = body {
27401 request = request.body(b);
27402 }
27403
27404 match request.send() {
27405 Ok(response) => {
27406 let status = response.status().as_u16() as i64;
27407 let mut headers_map = std::collections::HashMap::new();
27408 for (name, value) in response.headers() {
27409 if let Ok(v) = value.to_str() {
27410 headers_map.insert(
27411 name.as_str().to_string(),
27412 Value::String(Rc::new(v.to_string())),
27413 );
27414 }
27415 }
27416 let response_body = response.text().unwrap_or_default();
27417
27418 let mut result = std::collections::HashMap::new();
27419 result.insert("status".to_string(), Value::Int(status));
27420 result.insert(
27421 "headers".to_string(),
27422 Value::Map(Rc::new(RefCell::new(headers_map))),
27423 );
27424 result.insert("body".to_string(), Value::String(Rc::new(response_body)));
27425 Ok(Value::Map(Rc::new(RefCell::new(result))))
27426 }
27427 Err(e) => {
27428 let mut result = std::collections::HashMap::new();
27429 result.insert("status".to_string(), Value::Int(0));
27430 result.insert(
27431 "error".to_string(),
27432 Value::String(Rc::new(e.to_string())),
27433 );
27434 Ok(Value::Map(Rc::new(RefCell::new(result))))
27435 }
27436 }
27437 });
27438
27439 #[cfg(feature = "http-client")]
27442 define(interp, "http_download", Some(2), |_, args| {
27443 let url = match &args[0] {
27444 Value::String(s) => s.as_str().to_string(),
27445 _ => return Err(RuntimeError::new("http_download requires string URL")),
27446 };
27447 let path = match &args[1] {
27448 Value::String(s) => s.as_str().to_string(),
27449 _ => return Err(RuntimeError::new("http_download requires string path")),
27450 };
27451
27452 match reqwest::blocking::get(&url) {
27453 Ok(response) => {
27454 if response.status().is_success() {
27455 match response.bytes() {
27456 Ok(bytes) => {
27457 match std::fs::write(&path, &bytes) {
27458 Ok(_) => Ok(Value::Bool(true)),
27459 Err(_) => Ok(Value::Bool(false)),
27460 }
27461 }
27462 Err(_) => Ok(Value::Bool(false)),
27463 }
27464 } else {
27465 Ok(Value::Bool(false))
27466 }
27467 }
27468 Err(_) => Ok(Value::Bool(false)),
27469 }
27470 });
27471
27472 #[cfg(feature = "websocket")]
27479 {
27480 use std::sync::atomic::{AtomicU64, Ordering};
27481 use std::sync::{Mutex, OnceLock};
27482
27483 static WS_CONNECTIONS: OnceLock<Mutex<std::collections::HashMap<u64, tungstenite::WebSocket<tungstenite::stream::MaybeTlsStream<std::net::TcpStream>>>>> = OnceLock::new();
27485 static WS_COUNTER: AtomicU64 = AtomicU64::new(1);
27486
27487 fn get_ws_connections() -> &'static Mutex<std::collections::HashMap<u64, tungstenite::WebSocket<tungstenite::stream::MaybeTlsStream<std::net::TcpStream>>>> {
27488 WS_CONNECTIONS.get_or_init(|| Mutex::new(std::collections::HashMap::new()))
27489 }
27490
27491 define(interp, "ws_connect", Some(1), |_, args| {
27494 let url = match &args[0] {
27495 Value::String(s) => s.as_str().to_string(),
27496 _ => return Err(RuntimeError::new("ws_connect requires string URL")),
27497 };
27498
27499 match tungstenite::connect(&url) {
27500 Ok((socket, _response)) => {
27501 let id = WS_COUNTER.fetch_add(1, Ordering::SeqCst);
27502 if let Ok(mut conns) = get_ws_connections().lock() {
27503 conns.insert(id, socket);
27504 Ok(Value::Int(id as i64))
27505 } else {
27506 Ok(Value::Int(0))
27507 }
27508 }
27509 Err(e) => {
27510 let mut result = std::collections::HashMap::new();
27512 result.insert("id".to_string(), Value::Int(0));
27513 result.insert("error".to_string(), Value::String(Rc::new(e.to_string())));
27514 Ok(Value::Map(Rc::new(RefCell::new(result))))
27515 }
27516 }
27517 });
27518
27519 define(interp, "ws_send", Some(2), |_, args| {
27522 let conn_id = match &args[0] {
27523 Value::Int(n) => *n as u64,
27524 _ => return Err(RuntimeError::new("ws_send requires connection ID")),
27525 };
27526 let message = match &args[1] {
27527 Value::String(s) => s.as_str().to_string(),
27528 _ => return Err(RuntimeError::new("ws_send requires string message")),
27529 };
27530
27531 if let Ok(mut conns) = get_ws_connections().lock() {
27532 if let Some(socket) = conns.get_mut(&conn_id) {
27533 match socket.send(tungstenite::Message::Text(message)) {
27534 Ok(_) => Ok(Value::Bool(true)),
27535 Err(_) => Ok(Value::Bool(false)),
27536 }
27537 } else {
27538 Ok(Value::Bool(false))
27539 }
27540 } else {
27541 Ok(Value::Bool(false))
27542 }
27543 });
27544
27545 define(interp, "ws_send_binary", Some(2), |_, args| {
27548 let conn_id = match &args[0] {
27549 Value::Int(n) => *n as u64,
27550 _ => return Err(RuntimeError::new("ws_send_binary requires connection ID")),
27551 };
27552 let data = match &args[1] {
27553 Value::String(s) => s.as_bytes().to_vec(),
27554 Value::Array(arr) => {
27555 let arr = arr.borrow();
27556 arr.iter()
27557 .filter_map(|v| {
27558 if let Value::Int(n) = v {
27559 Some(*n as u8)
27560 } else {
27561 None
27562 }
27563 })
27564 .collect()
27565 }
27566 _ => return Err(RuntimeError::new("ws_send_binary requires data")),
27567 };
27568
27569 if let Ok(mut conns) = get_ws_connections().lock() {
27570 if let Some(socket) = conns.get_mut(&conn_id) {
27571 match socket.send(tungstenite::Message::Binary(data)) {
27572 Ok(_) => Ok(Value::Bool(true)),
27573 Err(_) => Ok(Value::Bool(false)),
27574 }
27575 } else {
27576 Ok(Value::Bool(false))
27577 }
27578 } else {
27579 Ok(Value::Bool(false))
27580 }
27581 });
27582
27583 define(interp, "ws_receive", Some(1), |_, args| {
27586 let conn_id = match &args[0] {
27587 Value::Int(n) => *n as u64,
27588 _ => return Err(RuntimeError::new("ws_receive requires connection ID")),
27589 };
27590
27591 if let Ok(mut conns) = get_ws_connections().lock() {
27592 if let Some(socket) = conns.get_mut(&conn_id) {
27593 match socket.read() {
27594 Ok(msg) => {
27595 let mut result = std::collections::HashMap::new();
27596 match msg {
27597 tungstenite::Message::Text(text) => {
27598 result.insert(
27599 "type".to_string(),
27600 Value::String(Rc::new("text".to_string())),
27601 );
27602 result.insert(
27603 "data".to_string(),
27604 Value::String(Rc::new(text)),
27605 );
27606 }
27607 tungstenite::Message::Binary(data) => {
27608 result.insert(
27609 "type".to_string(),
27610 Value::String(Rc::new("binary".to_string())),
27611 );
27612 let arr: Vec<Value> =
27613 data.iter().map(|b| Value::Int(*b as i64)).collect();
27614 result.insert(
27615 "data".to_string(),
27616 Value::Array(Rc::new(RefCell::new(arr))),
27617 );
27618 }
27619 tungstenite::Message::Ping(data) => {
27620 result.insert(
27621 "type".to_string(),
27622 Value::String(Rc::new("ping".to_string())),
27623 );
27624 result.insert(
27625 "data".to_string(),
27626 Value::String(Rc::new(
27627 String::from_utf8_lossy(&data).to_string(),
27628 )),
27629 );
27630 }
27631 tungstenite::Message::Pong(data) => {
27632 result.insert(
27633 "type".to_string(),
27634 Value::String(Rc::new("pong".to_string())),
27635 );
27636 result.insert(
27637 "data".to_string(),
27638 Value::String(Rc::new(
27639 String::from_utf8_lossy(&data).to_string(),
27640 )),
27641 );
27642 }
27643 tungstenite::Message::Close(frame) => {
27644 result.insert(
27645 "type".to_string(),
27646 Value::String(Rc::new("close".to_string())),
27647 );
27648 if let Some(f) = frame {
27649 result.insert(
27650 "code".to_string(),
27651 Value::Int(u16::from(f.code) as i64),
27652 );
27653 result.insert(
27654 "reason".to_string(),
27655 Value::String(Rc::new(f.reason.to_string())),
27656 );
27657 }
27658 }
27659 tungstenite::Message::Frame(_) => {
27660 result.insert(
27661 "type".to_string(),
27662 Value::String(Rc::new("frame".to_string())),
27663 );
27664 }
27665 }
27666 Ok(Value::Map(Rc::new(RefCell::new(result))))
27667 }
27668 Err(e) => {
27669 let mut result = std::collections::HashMap::new();
27670 result.insert(
27671 "type".to_string(),
27672 Value::String(Rc::new("error".to_string())),
27673 );
27674 result.insert(
27675 "error".to_string(),
27676 Value::String(Rc::new(e.to_string())),
27677 );
27678 Ok(Value::Map(Rc::new(RefCell::new(result))))
27679 }
27680 }
27681 } else {
27682 let mut result = std::collections::HashMap::new();
27683 result.insert(
27684 "type".to_string(),
27685 Value::String(Rc::new("error".to_string())),
27686 );
27687 result.insert(
27688 "error".to_string(),
27689 Value::String(Rc::new("Invalid connection ID".to_string())),
27690 );
27691 Ok(Value::Map(Rc::new(RefCell::new(result))))
27692 }
27693 } else {
27694 let mut result = std::collections::HashMap::new();
27695 result.insert(
27696 "type".to_string(),
27697 Value::String(Rc::new("error".to_string())),
27698 );
27699 result.insert(
27700 "error".to_string(),
27701 Value::String(Rc::new("Failed to acquire lock".to_string())),
27702 );
27703 Ok(Value::Map(Rc::new(RefCell::new(result))))
27704 }
27705 });
27706
27707 define(interp, "ws_close", Some(1), |_, args| {
27710 let conn_id = match &args[0] {
27711 Value::Int(n) => *n as u64,
27712 _ => return Err(RuntimeError::new("ws_close requires connection ID")),
27713 };
27714
27715 if let Ok(mut conns) = get_ws_connections().lock() {
27716 if let Some(mut socket) = conns.remove(&conn_id) {
27717 match socket.close(None) {
27718 Ok(_) => Ok(Value::Bool(true)),
27719 Err(_) => Ok(Value::Bool(true)), }
27721 } else {
27722 Ok(Value::Bool(false))
27723 }
27724 } else {
27725 Ok(Value::Bool(false))
27726 }
27727 });
27728
27729 define(interp, "ws_ping", Some(1), |_, args| {
27732 let conn_id = match &args[0] {
27733 Value::Int(n) => *n as u64,
27734 _ => return Err(RuntimeError::new("ws_ping requires connection ID")),
27735 };
27736
27737 if let Ok(mut conns) = get_ws_connections().lock() {
27738 if let Some(socket) = conns.get_mut(&conn_id) {
27739 match socket.send(tungstenite::Message::Ping(vec![])) {
27740 Ok(_) => Ok(Value::Bool(true)),
27741 Err(_) => Ok(Value::Bool(false)),
27742 }
27743 } else {
27744 Ok(Value::Bool(false))
27745 }
27746 } else {
27747 Ok(Value::Bool(false))
27748 }
27749 });
27750 }
27751}
27752
27753thread_local! {
27765 static TOOL_REGISTRY: RefCell<HashMap<String, ToolDefinition>> = RefCell::new(HashMap::new());
27766 static AGENT_MEMORY: RefCell<HashMap<String, AgentSession>> = RefCell::new(HashMap::new());
27767 static STATE_MACHINES: RefCell<HashMap<String, StateMachine>> = RefCell::new(HashMap::new());
27768}
27769
27770#[derive(Clone)]
27772struct ToolDefinition {
27773 name: String,
27774 description: String,
27775 parameters: Vec<ToolParameter>,
27776 returns: String,
27777 evidence_in: Evidence,
27778 evidence_out: Evidence,
27779 handler: Option<Rc<Function>>,
27780}
27781
27782#[derive(Clone)]
27783struct ToolParameter {
27784 name: String,
27785 param_type: String,
27786 description: String,
27787 required: bool,
27788 evidence: Evidence,
27789}
27790
27791#[derive(Clone)]
27793struct AgentSession {
27794 id: String,
27795 context: HashMap<String, Value>,
27796 history: Vec<(String, String)>, created_at: u64,
27798 last_accessed: u64,
27799}
27800
27801#[derive(Clone)]
27803struct StateMachine {
27804 name: String,
27805 current_state: String,
27806 states: Vec<String>,
27807 transitions: HashMap<String, Vec<(String, String)>>, history: Vec<(String, u64)>, }
27810
27811fn register_agent_tools(interp: &mut Interpreter) {
27816 define(interp, "tool_define", None, |_interp, args| {
27819 if args.len() < 4 {
27820 return Err(RuntimeError::new(
27821 "tool_define requires at least 4 arguments: name, description, params, returns",
27822 ));
27823 }
27824
27825 let name = match &args[0] {
27826 Value::String(s) => s.as_str().to_string(),
27827 _ => return Err(RuntimeError::new("tool name must be a string")),
27828 };
27829
27830 let description = match &args[1] {
27831 Value::String(s) => s.as_str().to_string(),
27832 _ => return Err(RuntimeError::new("tool description must be a string")),
27833 };
27834
27835 let params = match &args[2] {
27837 Value::Array(arr) => {
27838 let arr = arr.borrow();
27839 let mut params = Vec::new();
27840 for param in arr.iter() {
27841 if let Value::Map(map) = param {
27842 let map = map.borrow();
27843 let param_name = map
27844 .get("name")
27845 .and_then(|v| {
27846 if let Value::String(s) = v {
27847 Some(s.as_str().to_string())
27848 } else {
27849 None
27850 }
27851 })
27852 .unwrap_or_default();
27853 let param_type = map
27854 .get("type")
27855 .and_then(|v| {
27856 if let Value::String(s) = v {
27857 Some(s.as_str().to_string())
27858 } else {
27859 None
27860 }
27861 })
27862 .unwrap_or_else(|| "any".to_string());
27863 let param_desc = map
27864 .get("description")
27865 .and_then(|v| {
27866 if let Value::String(s) = v {
27867 Some(s.as_str().to_string())
27868 } else {
27869 None
27870 }
27871 })
27872 .unwrap_or_default();
27873 let required = map
27874 .get("required")
27875 .and_then(|v| {
27876 if let Value::Bool(b) = v {
27877 Some(*b)
27878 } else {
27879 None
27880 }
27881 })
27882 .unwrap_or(true);
27883 let evidence_str = map
27884 .get("evidence")
27885 .and_then(|v| {
27886 if let Value::String(s) = v {
27887 Some(s.as_str())
27888 } else {
27889 None
27890 }
27891 })
27892 .unwrap_or("~");
27893 let evidence = match evidence_str {
27894 "!" => Evidence::Known,
27895 "?" => Evidence::Uncertain,
27896 "~" => Evidence::Reported,
27897 "‽" => Evidence::Paradox,
27898 _ => Evidence::Reported,
27899 };
27900 params.push(ToolParameter {
27901 name: param_name,
27902 param_type,
27903 description: param_desc,
27904 required,
27905 evidence,
27906 });
27907 }
27908 }
27909 params
27910 }
27911 _ => Vec::new(),
27912 };
27913
27914 let returns = match &args[3] {
27915 Value::String(s) => s.as_str().to_string(),
27916 _ => "any".to_string(),
27917 };
27918
27919 let handler = if args.len() > 4 {
27920 match &args[4] {
27921 Value::Function(f) => Some(f.clone()),
27922 _ => None,
27923 }
27924 } else {
27925 None
27926 };
27927
27928 let tool = ToolDefinition {
27929 name: name.clone(),
27930 description,
27931 parameters: params,
27932 returns,
27933 evidence_in: Evidence::Reported,
27934 evidence_out: Evidence::Reported,
27935 handler,
27936 };
27937
27938 TOOL_REGISTRY.with(|registry| {
27939 registry.borrow_mut().insert(name.clone(), tool);
27940 });
27941
27942 Ok(Value::String(Rc::new(name)))
27943 });
27944
27945 define(interp, "tool_list", Some(0), |_, _args| {
27947 let tools: Vec<Value> = TOOL_REGISTRY.with(|registry| {
27948 registry
27949 .borrow()
27950 .keys()
27951 .map(|k| Value::String(Rc::new(k.clone())))
27952 .collect()
27953 });
27954 Ok(Value::Array(Rc::new(RefCell::new(tools))))
27955 });
27956
27957 define(interp, "tool_get", Some(1), |_, args| {
27959 let name = match &args[0] {
27960 Value::String(s) => s.as_str().to_string(),
27961 _ => return Err(RuntimeError::new("tool_get requires string name")),
27962 };
27963
27964 TOOL_REGISTRY.with(|registry| {
27965 if let Some(tool) = registry.borrow().get(&name) {
27966 let mut map = HashMap::new();
27967 map.insert(
27968 "name".to_string(),
27969 Value::String(Rc::new(tool.name.clone())),
27970 );
27971 map.insert(
27972 "description".to_string(),
27973 Value::String(Rc::new(tool.description.clone())),
27974 );
27975 map.insert(
27976 "returns".to_string(),
27977 Value::String(Rc::new(tool.returns.clone())),
27978 );
27979
27980 let params: Vec<Value> = tool
27981 .parameters
27982 .iter()
27983 .map(|p| {
27984 let mut pmap = HashMap::new();
27985 pmap.insert("name".to_string(), Value::String(Rc::new(p.name.clone())));
27986 pmap.insert(
27987 "type".to_string(),
27988 Value::String(Rc::new(p.param_type.clone())),
27989 );
27990 pmap.insert(
27991 "description".to_string(),
27992 Value::String(Rc::new(p.description.clone())),
27993 );
27994 pmap.insert("required".to_string(), Value::Bool(p.required));
27995 Value::Map(Rc::new(RefCell::new(pmap)))
27996 })
27997 .collect();
27998 map.insert(
27999 "parameters".to_string(),
28000 Value::Array(Rc::new(RefCell::new(params))),
28001 );
28002
28003 Ok(Value::Map(Rc::new(RefCell::new(map))))
28004 } else {
28005 Ok(Value::Null)
28006 }
28007 })
28008 });
28009
28010 define(interp, "tool_schema", Some(1), |_, args| {
28012 let name = match &args[0] {
28013 Value::String(s) => s.as_str().to_string(),
28014 _ => return Err(RuntimeError::new("tool_schema requires string name")),
28015 };
28016
28017 TOOL_REGISTRY.with(|registry| {
28018 if let Some(tool) = registry.borrow().get(&name) {
28019 let mut schema = HashMap::new();
28021 schema.insert(
28022 "type".to_string(),
28023 Value::String(Rc::new("function".to_string())),
28024 );
28025
28026 let mut function = HashMap::new();
28027 function.insert(
28028 "name".to_string(),
28029 Value::String(Rc::new(tool.name.clone())),
28030 );
28031 function.insert(
28032 "description".to_string(),
28033 Value::String(Rc::new(tool.description.clone())),
28034 );
28035
28036 let mut params_schema = HashMap::new();
28038 params_schema.insert(
28039 "type".to_string(),
28040 Value::String(Rc::new("object".to_string())),
28041 );
28042
28043 let mut properties = HashMap::new();
28044 let mut required: Vec<Value> = Vec::new();
28045
28046 for param in &tool.parameters {
28047 let mut prop = HashMap::new();
28048 let json_type = match param.param_type.as_str() {
28049 "int" | "i64" | "i32" => "integer",
28050 "float" | "f64" | "f32" => "number",
28051 "bool" => "boolean",
28052 "string" | "str" => "string",
28053 "array" | "list" => "array",
28054 "map" | "object" => "object",
28055 _ => "string",
28056 };
28057 prop.insert(
28058 "type".to_string(),
28059 Value::String(Rc::new(json_type.to_string())),
28060 );
28061 prop.insert(
28062 "description".to_string(),
28063 Value::String(Rc::new(param.description.clone())),
28064 );
28065 properties.insert(param.name.clone(), Value::Map(Rc::new(RefCell::new(prop))));
28066
28067 if param.required {
28068 required.push(Value::String(Rc::new(param.name.clone())));
28069 }
28070 }
28071
28072 params_schema.insert(
28073 "properties".to_string(),
28074 Value::Map(Rc::new(RefCell::new(properties))),
28075 );
28076 params_schema.insert(
28077 "required".to_string(),
28078 Value::Array(Rc::new(RefCell::new(required))),
28079 );
28080
28081 function.insert(
28082 "parameters".to_string(),
28083 Value::Map(Rc::new(RefCell::new(params_schema))),
28084 );
28085 schema.insert(
28086 "function".to_string(),
28087 Value::Map(Rc::new(RefCell::new(function))),
28088 );
28089
28090 Ok(Value::Map(Rc::new(RefCell::new(schema))))
28091 } else {
28092 Err(RuntimeError::new(format!("Tool '{}' not found", name)))
28093 }
28094 })
28095 });
28096
28097 define(interp, "tool_schemas_all", Some(0), |_, _args| {
28099 let schemas: Vec<Value> = TOOL_REGISTRY.with(|registry| {
28100 registry
28101 .borrow()
28102 .values()
28103 .map(|tool| {
28104 let mut schema = HashMap::new();
28105 schema.insert(
28106 "type".to_string(),
28107 Value::String(Rc::new("function".to_string())),
28108 );
28109
28110 let mut function = HashMap::new();
28111 function.insert(
28112 "name".to_string(),
28113 Value::String(Rc::new(tool.name.clone())),
28114 );
28115 function.insert(
28116 "description".to_string(),
28117 Value::String(Rc::new(tool.description.clone())),
28118 );
28119
28120 let mut params_schema = HashMap::new();
28121 params_schema.insert(
28122 "type".to_string(),
28123 Value::String(Rc::new("object".to_string())),
28124 );
28125
28126 let mut properties = HashMap::new();
28127 let mut required: Vec<Value> = Vec::new();
28128
28129 for param in &tool.parameters {
28130 let mut prop = HashMap::new();
28131 let json_type = match param.param_type.as_str() {
28132 "int" | "i64" | "i32" => "integer",
28133 "float" | "f64" | "f32" => "number",
28134 "bool" => "boolean",
28135 _ => "string",
28136 };
28137 prop.insert(
28138 "type".to_string(),
28139 Value::String(Rc::new(json_type.to_string())),
28140 );
28141 prop.insert(
28142 "description".to_string(),
28143 Value::String(Rc::new(param.description.clone())),
28144 );
28145 properties
28146 .insert(param.name.clone(), Value::Map(Rc::new(RefCell::new(prop))));
28147 if param.required {
28148 required.push(Value::String(Rc::new(param.name.clone())));
28149 }
28150 }
28151
28152 params_schema.insert(
28153 "properties".to_string(),
28154 Value::Map(Rc::new(RefCell::new(properties))),
28155 );
28156 params_schema.insert(
28157 "required".to_string(),
28158 Value::Array(Rc::new(RefCell::new(required))),
28159 );
28160 function.insert(
28161 "parameters".to_string(),
28162 Value::Map(Rc::new(RefCell::new(params_schema))),
28163 );
28164 schema.insert(
28165 "function".to_string(),
28166 Value::Map(Rc::new(RefCell::new(function))),
28167 );
28168
28169 Value::Map(Rc::new(RefCell::new(schema)))
28170 })
28171 .collect()
28172 });
28173 Ok(Value::Array(Rc::new(RefCell::new(schemas))))
28174 });
28175
28176 define(interp, "tool_call", None, |interp, args| {
28178 if args.is_empty() {
28179 return Err(RuntimeError::new("tool_call requires at least tool name"));
28180 }
28181
28182 let name = match &args[0] {
28183 Value::String(s) => s.as_str().to_string(),
28184 _ => {
28185 return Err(RuntimeError::new(
28186 "tool_call first argument must be tool name",
28187 ))
28188 }
28189 };
28190
28191 let tool_args: Vec<Value> = args.into_iter().skip(1).collect();
28192
28193 TOOL_REGISTRY.with(|registry| {
28194 if let Some(tool) = registry.borrow().get(&name) {
28195 if let Some(handler) = &tool.handler {
28196 let result = interp.call_function(handler.as_ref(), tool_args)?;
28198 Ok(Value::Evidential {
28200 value: Box::new(result),
28201 evidence: Evidence::Reported,
28202 })
28203 } else {
28204 Err(RuntimeError::new(format!("Tool '{}' has no handler", name)))
28205 }
28206 } else {
28207 Err(RuntimeError::new(format!("Tool '{}' not found", name)))
28208 }
28209 })
28210 });
28211
28212 define(interp, "tool_remove", Some(1), |_, args| {
28214 let name = match &args[0] {
28215 Value::String(s) => s.as_str().to_string(),
28216 _ => return Err(RuntimeError::new("tool_remove requires string name")),
28217 };
28218
28219 TOOL_REGISTRY.with(|registry| {
28220 let removed = registry.borrow_mut().remove(&name).is_some();
28221 Ok(Value::Bool(removed))
28222 })
28223 });
28224
28225 define(interp, "tool_clear", Some(0), |_, _args| {
28227 TOOL_REGISTRY.with(|registry| {
28228 registry.borrow_mut().clear();
28229 });
28230 Ok(Value::Null)
28231 });
28232}
28233
28234fn register_agent_llm(interp: &mut Interpreter) {
28239 define(interp, "llm_message", Some(2), |_, args| {
28241 let role = match &args[0] {
28242 Value::String(s) => s.as_str().to_string(),
28243 _ => return Err(RuntimeError::new("llm_message role must be string")),
28244 };
28245 let content = match &args[1] {
28246 Value::String(s) => s.as_str().to_string(),
28247 _ => return Err(RuntimeError::new("llm_message content must be string")),
28248 };
28249
28250 let mut map = HashMap::new();
28251 map.insert("role".to_string(), Value::String(Rc::new(role)));
28252 map.insert("content".to_string(), Value::String(Rc::new(content)));
28253 Ok(Value::Map(Rc::new(RefCell::new(map))))
28254 });
28255
28256 define(interp, "llm_messages", None, |_, args| {
28258 let messages: Vec<Value> = args.into_iter().collect();
28259 Ok(Value::Array(Rc::new(RefCell::new(messages))))
28260 });
28261
28262 define(interp, "llm_request", None, |_, args| {
28264 if args.is_empty() {
28265 return Err(RuntimeError::new("llm_request requires provider"));
28266 }
28267
28268 let provider = match &args[0] {
28269 Value::String(s) => s.as_str().to_string(),
28270 _ => return Err(RuntimeError::new("provider must be string")),
28271 };
28272
28273 let mut request = HashMap::new();
28274 request.insert(
28275 "provider".to_string(),
28276 Value::String(Rc::new(provider.clone())),
28277 );
28278
28279 let default_model = match provider.as_str() {
28281 "openai" => "gpt-4-turbo-preview",
28282 "anthropic" | "claude" => "claude-3-opus-20240229",
28283 "google" | "gemini" => "gemini-pro",
28284 "mistral" => "mistral-large-latest",
28285 "ollama" | "local" => "llama2",
28286 _ => "gpt-4",
28287 };
28288 request.insert(
28289 "model".to_string(),
28290 Value::String(Rc::new(default_model.to_string())),
28291 );
28292
28293 for (i, arg) in args.iter().enumerate().skip(1) {
28295 if let Value::Map(map) = arg {
28296 let map = map.borrow();
28297 for (k, v) in map.iter() {
28298 request.insert(k.clone(), v.clone());
28299 }
28300 } else if i == 1 {
28301 if let Value::String(s) = arg {
28303 request.insert("model".to_string(), Value::String(s.clone()));
28304 }
28305 }
28306 }
28307
28308 if !request.contains_key("temperature") {
28310 request.insert("temperature".to_string(), Value::Float(0.7));
28311 }
28312 if !request.contains_key("max_tokens") {
28313 request.insert("max_tokens".to_string(), Value::Int(4096));
28314 }
28315
28316 Ok(Value::Map(Rc::new(RefCell::new(request))))
28317 });
28318
28319 define(interp, "llm_with_tools", Some(2), |_, args| {
28321 let request = match &args[0] {
28322 Value::Map(m) => m.clone(),
28323 _ => {
28324 return Err(RuntimeError::new(
28325 "llm_with_tools first arg must be request map",
28326 ))
28327 }
28328 };
28329
28330 let tools = match &args[1] {
28331 Value::Array(arr) => arr.clone(),
28332 _ => {
28333 return Err(RuntimeError::new(
28334 "llm_with_tools second arg must be tools array",
28335 ))
28336 }
28337 };
28338
28339 request
28340 .borrow_mut()
28341 .insert("tools".to_string(), Value::Array(tools));
28342 request.borrow_mut().insert(
28343 "tool_choice".to_string(),
28344 Value::String(Rc::new("auto".to_string())),
28345 );
28346
28347 Ok(Value::Map(request))
28348 });
28349
28350 define(interp, "llm_with_system", Some(2), |_, args| {
28352 let request = match &args[0] {
28353 Value::Map(m) => m.clone(),
28354 _ => {
28355 return Err(RuntimeError::new(
28356 "llm_with_system first arg must be request map",
28357 ))
28358 }
28359 };
28360
28361 let system = match &args[1] {
28362 Value::String(s) => s.clone(),
28363 _ => {
28364 return Err(RuntimeError::new(
28365 "llm_with_system second arg must be string",
28366 ))
28367 }
28368 };
28369
28370 request
28371 .borrow_mut()
28372 .insert("system".to_string(), Value::String(system));
28373 Ok(Value::Map(request))
28374 });
28375
28376 define(interp, "llm_with_messages", Some(2), |_, args| {
28378 let request = match &args[0] {
28379 Value::Map(m) => m.clone(),
28380 _ => {
28381 return Err(RuntimeError::new(
28382 "llm_with_messages first arg must be request map",
28383 ))
28384 }
28385 };
28386
28387 let messages = match &args[1] {
28388 Value::Array(arr) => arr.clone(),
28389 _ => {
28390 return Err(RuntimeError::new(
28391 "llm_with_messages second arg must be messages array",
28392 ))
28393 }
28394 };
28395
28396 request
28397 .borrow_mut()
28398 .insert("messages".to_string(), Value::Array(messages));
28399 Ok(Value::Map(request))
28400 });
28401
28402 define(interp, "llm_send", Some(1), |_, args| {
28405 let request = match &args[0] {
28406 Value::Map(m) => m.borrow().clone(),
28407 _ => return Err(RuntimeError::new("llm_send requires request map")),
28408 };
28409
28410 let provider = request
28411 .get("provider")
28412 .and_then(|v| {
28413 if let Value::String(s) = v {
28414 Some(s.as_str().to_string())
28415 } else {
28416 None
28417 }
28418 })
28419 .unwrap_or_else(|| "unknown".to_string());
28420
28421 let model = request
28422 .get("model")
28423 .and_then(|v| {
28424 if let Value::String(s) = v {
28425 Some(s.as_str().to_string())
28426 } else {
28427 None
28428 }
28429 })
28430 .unwrap_or_else(|| "unknown".to_string());
28431
28432 let mut response = HashMap::new();
28434 response.insert(
28435 "id".to_string(),
28436 Value::String(Rc::new(format!("msg_{}", Uuid::new_v4()))),
28437 );
28438 response.insert("provider".to_string(), Value::String(Rc::new(provider)));
28439 response.insert("model".to_string(), Value::String(Rc::new(model)));
28440 response.insert(
28441 "created".to_string(),
28442 Value::Int(
28443 std::time::SystemTime::now()
28444 .duration_since(std::time::UNIX_EPOCH)
28445 .unwrap_or_default()
28446 .as_secs() as i64,
28447 ),
28448 );
28449
28450 if request.contains_key("tools") {
28452 response.insert(
28453 "type".to_string(),
28454 Value::String(Rc::new("tool_use".to_string())),
28455 );
28456 response.insert(
28457 "tool_name".to_string(),
28458 Value::String(Rc::new("pending".to_string())),
28459 );
28460 response.insert(
28461 "tool_input".to_string(),
28462 Value::Map(Rc::new(RefCell::new(HashMap::new()))),
28463 );
28464 } else {
28465 response.insert(
28466 "type".to_string(),
28467 Value::String(Rc::new("text".to_string())),
28468 );
28469 response.insert(
28470 "content".to_string(),
28471 Value::String(Rc::new(
28472 "[LLM Response - Connect to actual API for real responses]".to_string(),
28473 )),
28474 );
28475 }
28476
28477 let mut usage = HashMap::new();
28479 usage.insert("input_tokens".to_string(), Value::Int(0));
28480 usage.insert("output_tokens".to_string(), Value::Int(0));
28481 response.insert(
28482 "usage".to_string(),
28483 Value::Map(Rc::new(RefCell::new(usage))),
28484 );
28485
28486 Ok(Value::Evidential {
28488 value: Box::new(Value::Map(Rc::new(RefCell::new(response)))),
28489 evidence: Evidence::Reported,
28490 })
28491 });
28492
28493 define(interp, "llm_parse_tool_call", Some(1), |_, args| {
28495 let response = match &args[0] {
28496 Value::Map(m) => m.borrow().clone(),
28497 Value::Evidential { value, .. } => {
28498 if let Value::Map(m) = value.as_ref() {
28499 m.borrow().clone()
28500 } else {
28501 return Err(RuntimeError::new(
28502 "llm_parse_tool_call requires map response",
28503 ));
28504 }
28505 }
28506 _ => {
28507 return Err(RuntimeError::new(
28508 "llm_parse_tool_call requires response map",
28509 ))
28510 }
28511 };
28512
28513 let resp_type = response
28514 .get("type")
28515 .and_then(|v| {
28516 if let Value::String(s) = v {
28517 Some(s.as_str().to_string())
28518 } else {
28519 None
28520 }
28521 })
28522 .unwrap_or_default();
28523
28524 if resp_type == "tool_use" {
28525 let tool_name = response
28526 .get("tool_name")
28527 .and_then(|v| {
28528 if let Value::String(s) = v {
28529 Some(s.as_str().to_string())
28530 } else {
28531 None
28532 }
28533 })
28534 .unwrap_or_default();
28535
28536 let tool_input = response.get("tool_input").cloned().unwrap_or(Value::Null);
28537
28538 let mut result = HashMap::new();
28539 result.insert("is_tool_call".to_string(), Value::Bool(true));
28540 result.insert("tool_name".to_string(), Value::String(Rc::new(tool_name)));
28541 result.insert("tool_input".to_string(), tool_input);
28542 Ok(Value::Map(Rc::new(RefCell::new(result))))
28543 } else {
28544 let mut result = HashMap::new();
28545 result.insert("is_tool_call".to_string(), Value::Bool(false));
28546 result.insert(
28547 "content".to_string(),
28548 response.get("content").cloned().unwrap_or(Value::Null),
28549 );
28550 Ok(Value::Map(Rc::new(RefCell::new(result))))
28551 }
28552 });
28553
28554 define(interp, "llm_extract", Some(2), |_, args| {
28556 let _response = match &args[0] {
28557 Value::Map(m) => m.borrow().clone(),
28558 Value::Evidential { value, .. } => {
28559 if let Value::Map(m) = value.as_ref() {
28560 m.borrow().clone()
28561 } else {
28562 return Err(RuntimeError::new("llm_extract requires response"));
28563 }
28564 }
28565 _ => return Err(RuntimeError::new("llm_extract requires response")),
28566 };
28567
28568 let _schema = match &args[1] {
28569 Value::Map(m) => m.borrow().clone(),
28570 _ => return Err(RuntimeError::new("llm_extract requires schema map")),
28571 };
28572
28573 let mut result = HashMap::new();
28576 result.insert("success".to_string(), Value::Bool(true));
28577 result.insert("data".to_string(), Value::Null);
28578 result.insert(
28579 "errors".to_string(),
28580 Value::Array(Rc::new(RefCell::new(Vec::new()))),
28581 );
28582
28583 Ok(Value::Evidential {
28584 value: Box::new(Value::Map(Rc::new(RefCell::new(result)))),
28585 evidence: Evidence::Uncertain,
28586 })
28587 });
28588
28589 define(interp, "prompt_template", Some(1), |_, args| {
28591 let template = match &args[0] {
28592 Value::String(s) => s.as_str().to_string(),
28593 _ => return Err(RuntimeError::new("prompt_template requires string")),
28594 };
28595
28596 let mut variables = Vec::new();
28598 let mut in_var = false;
28599 let mut var_name = String::new();
28600
28601 for c in template.chars() {
28602 match c {
28603 '{' if !in_var => {
28604 in_var = true;
28605 var_name.clear();
28606 }
28607 '}' if in_var => {
28608 if !var_name.is_empty() {
28609 variables.push(Value::String(Rc::new(var_name.clone())));
28610 }
28611 in_var = false;
28612 }
28613 _ if in_var => {
28614 var_name.push(c);
28615 }
28616 _ => {}
28617 }
28618 }
28619
28620 let mut result = HashMap::new();
28621 result.insert("template".to_string(), Value::String(Rc::new(template)));
28622 result.insert(
28623 "variables".to_string(),
28624 Value::Array(Rc::new(RefCell::new(variables))),
28625 );
28626 Ok(Value::Map(Rc::new(RefCell::new(result))))
28627 });
28628
28629 define(interp, "prompt_render", Some(2), |_, args| {
28631 let template_obj = match &args[0] {
28632 Value::Map(m) => m.borrow().clone(),
28633 Value::String(s) => {
28634 let mut m = HashMap::new();
28635 m.insert("template".to_string(), Value::String(s.clone()));
28636 m
28637 }
28638 _ => return Err(RuntimeError::new("prompt_render requires template")),
28639 };
28640
28641 let values = match &args[1] {
28642 Value::Map(m) => m.borrow().clone(),
28643 _ => return Err(RuntimeError::new("prompt_render requires values map")),
28644 };
28645
28646 let template = template_obj
28647 .get("template")
28648 .and_then(|v| {
28649 if let Value::String(s) = v {
28650 Some(s.as_str().to_string())
28651 } else {
28652 None
28653 }
28654 })
28655 .unwrap_or_default();
28656
28657 let mut result = template;
28658 for (key, value) in values.iter() {
28659 let value_str = match value {
28660 Value::String(s) => s.as_str().to_string(),
28661 Value::Int(n) => n.to_string(),
28662 Value::Float(f) => f.to_string(),
28663 Value::Bool(b) => b.to_string(),
28664 _ => format!("{}", value),
28665 };
28666 result = result.replace(&format!("{{{}}}", key), &value_str);
28667 }
28668
28669 Ok(Value::String(Rc::new(result)))
28670 });
28671}
28672
28673fn register_agent_memory(interp: &mut Interpreter) {
28678 define(interp, "memory_session", Some(1), |_, args| {
28680 let session_id = match &args[0] {
28681 Value::String(s) => s.as_str().to_string(),
28682 _ => return Err(RuntimeError::new("memory_session requires string id")),
28683 };
28684
28685 let now = std::time::SystemTime::now()
28686 .duration_since(std::time::UNIX_EPOCH)
28687 .unwrap_or_default()
28688 .as_secs();
28689
28690 AGENT_MEMORY.with(|memory| {
28691 let mut mem = memory.borrow_mut();
28692 if !mem.contains_key(&session_id) {
28693 mem.insert(
28694 session_id.clone(),
28695 AgentSession {
28696 id: session_id.clone(),
28697 context: HashMap::new(),
28698 history: Vec::new(),
28699 created_at: now,
28700 last_accessed: now,
28701 },
28702 );
28703 } else if let Some(session) = mem.get_mut(&session_id) {
28704 session.last_accessed = now;
28705 }
28706 });
28707
28708 let mut result = HashMap::new();
28709 result.insert("id".to_string(), Value::String(Rc::new(session_id)));
28710 result.insert("created_at".to_string(), Value::Int(now as i64));
28711 Ok(Value::Map(Rc::new(RefCell::new(result))))
28712 });
28713
28714 define(interp, "memory_set", Some(3), |_, args| {
28716 let session_id = match &args[0] {
28717 Value::String(s) => s.as_str().to_string(),
28718 Value::Map(m) => m
28719 .borrow()
28720 .get("id")
28721 .and_then(|v| {
28722 if let Value::String(s) = v {
28723 Some(s.as_str().to_string())
28724 } else {
28725 None
28726 }
28727 })
28728 .ok_or_else(|| RuntimeError::new("Invalid session"))?,
28729 _ => return Err(RuntimeError::new("memory_set requires session")),
28730 };
28731
28732 let key = match &args[1] {
28733 Value::String(s) => s.as_str().to_string(),
28734 _ => return Err(RuntimeError::new("memory_set key must be string")),
28735 };
28736
28737 let value = args[2].clone();
28738
28739 AGENT_MEMORY.with(|memory| {
28740 if let Some(session) = memory.borrow_mut().get_mut(&session_id) {
28741 session.context.insert(key, value);
28742 session.last_accessed = std::time::SystemTime::now()
28743 .duration_since(std::time::UNIX_EPOCH)
28744 .unwrap_or_default()
28745 .as_secs();
28746 Ok(Value::Bool(true))
28747 } else {
28748 Err(RuntimeError::new(format!(
28749 "Session '{}' not found",
28750 session_id
28751 )))
28752 }
28753 })
28754 });
28755
28756 define(interp, "memory_get", Some(2), |_, args| {
28758 let session_id = match &args[0] {
28759 Value::String(s) => s.as_str().to_string(),
28760 Value::Map(m) => m
28761 .borrow()
28762 .get("id")
28763 .and_then(|v| {
28764 if let Value::String(s) = v {
28765 Some(s.as_str().to_string())
28766 } else {
28767 None
28768 }
28769 })
28770 .ok_or_else(|| RuntimeError::new("Invalid session"))?,
28771 _ => return Err(RuntimeError::new("memory_get requires session")),
28772 };
28773
28774 let key = match &args[1] {
28775 Value::String(s) => s.as_str().to_string(),
28776 _ => return Err(RuntimeError::new("memory_get key must be string")),
28777 };
28778
28779 AGENT_MEMORY.with(|memory| {
28780 if let Some(session) = memory.borrow().get(&session_id) {
28781 Ok(session.context.get(&key).cloned().unwrap_or(Value::Null))
28782 } else {
28783 Ok(Value::Null)
28784 }
28785 })
28786 });
28787
28788 define(interp, "memory_history_add", Some(3), |_, args| {
28790 let session_id = match &args[0] {
28791 Value::String(s) => s.as_str().to_string(),
28792 Value::Map(m) => m
28793 .borrow()
28794 .get("id")
28795 .and_then(|v| {
28796 if let Value::String(s) = v {
28797 Some(s.as_str().to_string())
28798 } else {
28799 None
28800 }
28801 })
28802 .ok_or_else(|| RuntimeError::new("Invalid session"))?,
28803 _ => return Err(RuntimeError::new("memory_history_add requires session")),
28804 };
28805
28806 let role = match &args[1] {
28807 Value::String(s) => s.as_str().to_string(),
28808 _ => return Err(RuntimeError::new("role must be string")),
28809 };
28810
28811 let content = match &args[2] {
28812 Value::String(s) => s.as_str().to_string(),
28813 _ => return Err(RuntimeError::new("content must be string")),
28814 };
28815
28816 AGENT_MEMORY.with(|memory| {
28817 if let Some(session) = memory.borrow_mut().get_mut(&session_id) {
28818 session.history.push((role, content));
28819 session.last_accessed = std::time::SystemTime::now()
28820 .duration_since(std::time::UNIX_EPOCH)
28821 .unwrap_or_default()
28822 .as_secs();
28823 Ok(Value::Int(session.history.len() as i64))
28824 } else {
28825 Err(RuntimeError::new(format!(
28826 "Session '{}' not found",
28827 session_id
28828 )))
28829 }
28830 })
28831 });
28832
28833 define(interp, "memory_history_get", None, |_, args| {
28835 if args.is_empty() {
28836 return Err(RuntimeError::new("memory_history_get requires session"));
28837 }
28838
28839 let session_id = match &args[0] {
28840 Value::String(s) => s.as_str().to_string(),
28841 Value::Map(m) => m
28842 .borrow()
28843 .get("id")
28844 .and_then(|v| {
28845 if let Value::String(s) = v {
28846 Some(s.as_str().to_string())
28847 } else {
28848 None
28849 }
28850 })
28851 .ok_or_else(|| RuntimeError::new("Invalid session"))?,
28852 _ => return Err(RuntimeError::new("memory_history_get requires session")),
28853 };
28854
28855 let limit = if args.len() > 1 {
28856 match &args[1] {
28857 Value::Int(n) => Some(*n as usize),
28858 _ => None,
28859 }
28860 } else {
28861 None
28862 };
28863
28864 AGENT_MEMORY.with(|memory| {
28865 if let Some(session) = memory.borrow().get(&session_id) {
28866 let history: Vec<Value> = session
28867 .history
28868 .iter()
28869 .rev()
28870 .take(limit.unwrap_or(usize::MAX))
28871 .rev()
28872 .map(|(role, content)| {
28873 let mut msg = HashMap::new();
28874 msg.insert("role".to_string(), Value::String(Rc::new(role.clone())));
28875 msg.insert(
28876 "content".to_string(),
28877 Value::String(Rc::new(content.clone())),
28878 );
28879 Value::Map(Rc::new(RefCell::new(msg)))
28880 })
28881 .collect();
28882 Ok(Value::Array(Rc::new(RefCell::new(history))))
28883 } else {
28884 Ok(Value::Array(Rc::new(RefCell::new(Vec::new()))))
28885 }
28886 })
28887 });
28888
28889 define(interp, "memory_context_all", Some(1), |_, args| {
28891 let session_id = match &args[0] {
28892 Value::String(s) => s.as_str().to_string(),
28893 Value::Map(m) => m
28894 .borrow()
28895 .get("id")
28896 .and_then(|v| {
28897 if let Value::String(s) = v {
28898 Some(s.as_str().to_string())
28899 } else {
28900 None
28901 }
28902 })
28903 .ok_or_else(|| RuntimeError::new("Invalid session"))?,
28904 _ => return Err(RuntimeError::new("memory_context_all requires session")),
28905 };
28906
28907 AGENT_MEMORY.with(|memory| {
28908 if let Some(session) = memory.borrow().get(&session_id) {
28909 let context: HashMap<String, Value> = session.context.clone();
28910 Ok(Value::Map(Rc::new(RefCell::new(context))))
28911 } else {
28912 Ok(Value::Map(Rc::new(RefCell::new(HashMap::new()))))
28913 }
28914 })
28915 });
28916
28917 define(interp, "memory_clear", Some(1), |_, args| {
28919 let session_id = match &args[0] {
28920 Value::String(s) => s.as_str().to_string(),
28921 Value::Map(m) => m
28922 .borrow()
28923 .get("id")
28924 .and_then(|v| {
28925 if let Value::String(s) = v {
28926 Some(s.as_str().to_string())
28927 } else {
28928 None
28929 }
28930 })
28931 .ok_or_else(|| RuntimeError::new("Invalid session"))?,
28932 _ => return Err(RuntimeError::new("memory_clear requires session")),
28933 };
28934
28935 AGENT_MEMORY.with(|memory| {
28936 let removed = memory.borrow_mut().remove(&session_id).is_some();
28937 Ok(Value::Bool(removed))
28938 })
28939 });
28940
28941 define(interp, "memory_sessions_list", Some(0), |_, _args| {
28943 let sessions: Vec<Value> = AGENT_MEMORY.with(|memory| {
28944 memory
28945 .borrow()
28946 .values()
28947 .map(|session| {
28948 let mut info = HashMap::new();
28949 info.insert("id".to_string(), Value::String(Rc::new(session.id.clone())));
28950 info.insert(
28951 "created_at".to_string(),
28952 Value::Int(session.created_at as i64),
28953 );
28954 info.insert(
28955 "last_accessed".to_string(),
28956 Value::Int(session.last_accessed as i64),
28957 );
28958 info.insert(
28959 "context_keys".to_string(),
28960 Value::Int(session.context.len() as i64),
28961 );
28962 info.insert(
28963 "history_length".to_string(),
28964 Value::Int(session.history.len() as i64),
28965 );
28966 Value::Map(Rc::new(RefCell::new(info)))
28967 })
28968 .collect()
28969 });
28970 Ok(Value::Array(Rc::new(RefCell::new(sessions))))
28971 });
28972}
28973
28974fn register_agent_planning(interp: &mut Interpreter) {
28979 define(interp, "plan_state_machine", Some(2), |_, args| {
28981 let name = match &args[0] {
28982 Value::String(s) => s.as_str().to_string(),
28983 _ => return Err(RuntimeError::new("plan_state_machine name must be string")),
28984 };
28985
28986 let states = match &args[1] {
28987 Value::Array(arr) => arr
28988 .borrow()
28989 .iter()
28990 .filter_map(|v| {
28991 if let Value::String(s) = v {
28992 Some(s.as_str().to_string())
28993 } else {
28994 None
28995 }
28996 })
28997 .collect::<Vec<_>>(),
28998 _ => return Err(RuntimeError::new("plan_state_machine states must be array")),
28999 };
29000
29001 if states.is_empty() {
29002 return Err(RuntimeError::new(
29003 "State machine must have at least one state",
29004 ));
29005 }
29006
29007 let initial_state = states[0].clone();
29008 let now = std::time::SystemTime::now()
29009 .duration_since(std::time::UNIX_EPOCH)
29010 .unwrap_or_default()
29011 .as_secs();
29012
29013 let machine = StateMachine {
29014 name: name.clone(),
29015 current_state: initial_state.clone(),
29016 states,
29017 transitions: HashMap::new(),
29018 history: vec![(initial_state, now)],
29019 };
29020
29021 STATE_MACHINES.with(|machines| {
29022 machines.borrow_mut().insert(name.clone(), machine);
29023 });
29024
29025 let mut result = HashMap::new();
29026 result.insert("name".to_string(), Value::String(Rc::new(name)));
29027 result.insert(
29028 "type".to_string(),
29029 Value::String(Rc::new("state_machine".to_string())),
29030 );
29031 Ok(Value::Map(Rc::new(RefCell::new(result))))
29032 });
29033
29034 define(interp, "plan_add_transition", Some(3), |_, args| {
29036 let machine_name = match &args[0] {
29037 Value::String(s) => s.as_str().to_string(),
29038 Value::Map(m) => m
29039 .borrow()
29040 .get("name")
29041 .and_then(|v| {
29042 if let Value::String(s) = v {
29043 Some(s.as_str().to_string())
29044 } else {
29045 None
29046 }
29047 })
29048 .ok_or_else(|| RuntimeError::new("Invalid state machine"))?,
29049 _ => return Err(RuntimeError::new("plan_add_transition requires machine")),
29050 };
29051
29052 let from_state = match &args[1] {
29053 Value::String(s) => s.as_str().to_string(),
29054 _ => return Err(RuntimeError::new("from_state must be string")),
29055 };
29056
29057 let to_state = match &args[2] {
29058 Value::String(s) => s.as_str().to_string(),
29059 _ => return Err(RuntimeError::new("to_state must be string")),
29060 };
29061
29062 STATE_MACHINES.with(|machines| {
29063 if let Some(machine) = machines.borrow_mut().get_mut(&machine_name) {
29064 if !machine.states.contains(&from_state) {
29066 return Err(RuntimeError::new(format!(
29067 "State '{}' not in machine",
29068 from_state
29069 )));
29070 }
29071 if !machine.states.contains(&to_state) {
29072 return Err(RuntimeError::new(format!(
29073 "State '{}' not in machine",
29074 to_state
29075 )));
29076 }
29077
29078 machine
29079 .transitions
29080 .entry(from_state)
29081 .or_insert_with(Vec::new)
29082 .push((to_state, "".to_string()));
29083
29084 Ok(Value::Bool(true))
29085 } else {
29086 Err(RuntimeError::new(format!(
29087 "State machine '{}' not found",
29088 machine_name
29089 )))
29090 }
29091 })
29092 });
29093
29094 define(interp, "plan_current_state", Some(1), |_, args| {
29096 let machine_name = match &args[0] {
29097 Value::String(s) => s.as_str().to_string(),
29098 Value::Map(m) => m
29099 .borrow()
29100 .get("name")
29101 .and_then(|v| {
29102 if let Value::String(s) = v {
29103 Some(s.as_str().to_string())
29104 } else {
29105 None
29106 }
29107 })
29108 .ok_or_else(|| RuntimeError::new("Invalid state machine"))?,
29109 _ => return Err(RuntimeError::new("plan_current_state requires machine")),
29110 };
29111
29112 STATE_MACHINES.with(|machines| {
29113 if let Some(machine) = machines.borrow().get(&machine_name) {
29114 Ok(Value::String(Rc::new(machine.current_state.clone())))
29115 } else {
29116 Err(RuntimeError::new(format!(
29117 "State machine '{}' not found",
29118 machine_name
29119 )))
29120 }
29121 })
29122 });
29123
29124 define(interp, "plan_transition", Some(2), |_, args| {
29126 let machine_name = match &args[0] {
29127 Value::String(s) => s.as_str().to_string(),
29128 Value::Map(m) => m
29129 .borrow()
29130 .get("name")
29131 .and_then(|v| {
29132 if let Value::String(s) = v {
29133 Some(s.as_str().to_string())
29134 } else {
29135 None
29136 }
29137 })
29138 .ok_or_else(|| RuntimeError::new("Invalid state machine"))?,
29139 _ => return Err(RuntimeError::new("plan_transition requires machine")),
29140 };
29141
29142 let to_state = match &args[1] {
29143 Value::String(s) => s.as_str().to_string(),
29144 _ => return Err(RuntimeError::new("to_state must be string")),
29145 };
29146
29147 STATE_MACHINES.with(|machines| {
29148 if let Some(machine) = machines.borrow_mut().get_mut(&machine_name) {
29149 let current = machine.current_state.clone();
29150
29151 let valid = machine
29153 .transitions
29154 .get(¤t)
29155 .map(|transitions| transitions.iter().any(|(to, _)| to == &to_state))
29156 .unwrap_or(false);
29157
29158 if valid || machine.states.contains(&to_state) {
29159 let now = std::time::SystemTime::now()
29160 .duration_since(std::time::UNIX_EPOCH)
29161 .unwrap_or_default()
29162 .as_secs();
29163
29164 machine.current_state = to_state.clone();
29165 machine.history.push((to_state.clone(), now));
29166
29167 let mut result = HashMap::new();
29168 result.insert("success".to_string(), Value::Bool(true));
29169 result.insert("from".to_string(), Value::String(Rc::new(current)));
29170 result.insert("to".to_string(), Value::String(Rc::new(to_state)));
29171 Ok(Value::Map(Rc::new(RefCell::new(result))))
29172 } else {
29173 let mut result = HashMap::new();
29174 result.insert("success".to_string(), Value::Bool(false));
29175 result.insert(
29176 "error".to_string(),
29177 Value::String(Rc::new(format!(
29178 "No valid transition from '{}' to '{}'",
29179 current, to_state
29180 ))),
29181 );
29182 Ok(Value::Map(Rc::new(RefCell::new(result))))
29183 }
29184 } else {
29185 Err(RuntimeError::new(format!(
29186 "State machine '{}' not found",
29187 machine_name
29188 )))
29189 }
29190 })
29191 });
29192
29193 define(interp, "plan_can_transition", Some(2), |_, args| {
29195 let machine_name = match &args[0] {
29196 Value::String(s) => s.as_str().to_string(),
29197 Value::Map(m) => m
29198 .borrow()
29199 .get("name")
29200 .and_then(|v| {
29201 if let Value::String(s) = v {
29202 Some(s.as_str().to_string())
29203 } else {
29204 None
29205 }
29206 })
29207 .ok_or_else(|| RuntimeError::new("Invalid state machine"))?,
29208 _ => return Err(RuntimeError::new("plan_can_transition requires machine")),
29209 };
29210
29211 let to_state = match &args[1] {
29212 Value::String(s) => s.as_str().to_string(),
29213 _ => return Err(RuntimeError::new("to_state must be string")),
29214 };
29215
29216 STATE_MACHINES.with(|machines| {
29217 if let Some(machine) = machines.borrow().get(&machine_name) {
29218 let current = &machine.current_state;
29219 let can = machine
29220 .transitions
29221 .get(current)
29222 .map(|transitions| transitions.iter().any(|(to, _)| to == &to_state))
29223 .unwrap_or(false);
29224 Ok(Value::Bool(can))
29225 } else {
29226 Ok(Value::Bool(false))
29227 }
29228 })
29229 });
29230
29231 define(interp, "plan_available_transitions", Some(1), |_, args| {
29233 let machine_name = match &args[0] {
29234 Value::String(s) => s.as_str().to_string(),
29235 Value::Map(m) => m
29236 .borrow()
29237 .get("name")
29238 .and_then(|v| {
29239 if let Value::String(s) = v {
29240 Some(s.as_str().to_string())
29241 } else {
29242 None
29243 }
29244 })
29245 .ok_or_else(|| RuntimeError::new("Invalid state machine"))?,
29246 _ => {
29247 return Err(RuntimeError::new(
29248 "plan_available_transitions requires machine",
29249 ))
29250 }
29251 };
29252
29253 STATE_MACHINES.with(|machines| {
29254 if let Some(machine) = machines.borrow().get(&machine_name) {
29255 let current = &machine.current_state;
29256 let available: Vec<Value> = machine
29257 .transitions
29258 .get(current)
29259 .map(|transitions| {
29260 transitions
29261 .iter()
29262 .map(|(to, _)| Value::String(Rc::new(to.clone())))
29263 .collect()
29264 })
29265 .unwrap_or_default();
29266 Ok(Value::Array(Rc::new(RefCell::new(available))))
29267 } else {
29268 Ok(Value::Array(Rc::new(RefCell::new(Vec::new()))))
29269 }
29270 })
29271 });
29272
29273 define(interp, "plan_history", Some(1), |_, args| {
29275 let machine_name = match &args[0] {
29276 Value::String(s) => s.as_str().to_string(),
29277 Value::Map(m) => m
29278 .borrow()
29279 .get("name")
29280 .and_then(|v| {
29281 if let Value::String(s) = v {
29282 Some(s.as_str().to_string())
29283 } else {
29284 None
29285 }
29286 })
29287 .ok_or_else(|| RuntimeError::new("Invalid state machine"))?,
29288 _ => return Err(RuntimeError::new("plan_history requires machine")),
29289 };
29290
29291 STATE_MACHINES.with(|machines| {
29292 if let Some(machine) = machines.borrow().get(&machine_name) {
29293 let history: Vec<Value> = machine
29294 .history
29295 .iter()
29296 .map(|(state, timestamp)| {
29297 let mut entry = HashMap::new();
29298 entry.insert("state".to_string(), Value::String(Rc::new(state.clone())));
29299 entry.insert("timestamp".to_string(), Value::Int(*timestamp as i64));
29300 Value::Map(Rc::new(RefCell::new(entry)))
29301 })
29302 .collect();
29303 Ok(Value::Array(Rc::new(RefCell::new(history))))
29304 } else {
29305 Ok(Value::Array(Rc::new(RefCell::new(Vec::new()))))
29306 }
29307 })
29308 });
29309
29310 define(interp, "plan_goal", Some(2), |_, args| {
29312 let name = match &args[0] {
29313 Value::String(s) => s.as_str().to_string(),
29314 _ => return Err(RuntimeError::new("plan_goal name must be string")),
29315 };
29316
29317 let criteria = args[1].clone();
29318
29319 let mut goal = HashMap::new();
29320 goal.insert("name".to_string(), Value::String(Rc::new(name)));
29321 goal.insert("criteria".to_string(), criteria);
29322 goal.insert(
29323 "status".to_string(),
29324 Value::String(Rc::new("pending".to_string())),
29325 );
29326 goal.insert("progress".to_string(), Value::Float(0.0));
29327 goal.insert(
29328 "created_at".to_string(),
29329 Value::Int(
29330 std::time::SystemTime::now()
29331 .duration_since(std::time::UNIX_EPOCH)
29332 .unwrap_or_default()
29333 .as_secs() as i64,
29334 ),
29335 );
29336
29337 Ok(Value::Map(Rc::new(RefCell::new(goal))))
29338 });
29339
29340 define(interp, "plan_subgoals", Some(2), |_, args| {
29342 let parent = match &args[0] {
29343 Value::Map(m) => m.clone(),
29344 _ => return Err(RuntimeError::new("plan_subgoals requires goal map")),
29345 };
29346
29347 let subgoals = match &args[1] {
29348 Value::Array(arr) => arr.clone(),
29349 _ => return Err(RuntimeError::new("plan_subgoals requires subgoals array")),
29350 };
29351
29352 parent
29353 .borrow_mut()
29354 .insert("subgoals".to_string(), Value::Array(subgoals));
29355 Ok(Value::Map(parent))
29356 });
29357
29358 define(interp, "plan_update_progress", Some(2), |_, args| {
29360 let goal = match &args[0] {
29361 Value::Map(m) => m.clone(),
29362 _ => return Err(RuntimeError::new("plan_update_progress requires goal map")),
29363 };
29364
29365 let progress = match &args[1] {
29366 Value::Float(f) => *f,
29367 Value::Int(i) => *i as f64,
29368 _ => return Err(RuntimeError::new("progress must be number")),
29369 };
29370
29371 let progress = progress.clamp(0.0, 1.0);
29372 goal.borrow_mut()
29373 .insert("progress".to_string(), Value::Float(progress));
29374
29375 if progress >= 1.0 {
29376 goal.borrow_mut().insert(
29377 "status".to_string(),
29378 Value::String(Rc::new("completed".to_string())),
29379 );
29380 } else if progress > 0.0 {
29381 goal.borrow_mut().insert(
29382 "status".to_string(),
29383 Value::String(Rc::new("in_progress".to_string())),
29384 );
29385 }
29386
29387 Ok(Value::Map(goal))
29388 });
29389
29390 define(interp, "plan_check_goal", Some(2), |_interp, args| {
29392 let goal = match &args[0] {
29393 Value::Map(m) => m.borrow().clone(),
29394 _ => return Err(RuntimeError::new("plan_check_goal requires goal map")),
29395 };
29396
29397 let context = match &args[1] {
29398 Value::Map(m) => m.borrow().clone(),
29399 _ => return Err(RuntimeError::new("plan_check_goal requires context map")),
29400 };
29401
29402 let _criteria = goal.get("criteria").cloned().unwrap_or(Value::Null);
29404
29405 let mut met = true;
29407 let mut missing: Vec<String> = Vec::new();
29408
29409 if let Some(Value::Array(required)) = goal.get("required_context") {
29410 for req in required.borrow().iter() {
29411 if let Value::String(key) = req {
29412 if !context.contains_key(key.as_str()) {
29413 met = false;
29414 missing.push(key.as_str().to_string());
29415 }
29416 }
29417 }
29418 }
29419
29420 let mut result = HashMap::new();
29421 result.insert("met".to_string(), Value::Bool(met));
29422 result.insert(
29423 "missing".to_string(),
29424 Value::Array(Rc::new(RefCell::new(
29425 missing
29426 .into_iter()
29427 .map(|s| Value::String(Rc::new(s)))
29428 .collect(),
29429 ))),
29430 );
29431
29432 Ok(Value::Map(Rc::new(RefCell::new(result))))
29433 });
29434}
29435
29436fn register_agent_vectors(interp: &mut Interpreter) {
29441 define(interp, "vec_embedding", Some(1), |_, args| {
29443 let text = match &args[0] {
29444 Value::String(s) => s.as_str().to_string(),
29445 _ => return Err(RuntimeError::new("vec_embedding requires string")),
29446 };
29447
29448 let mut embedding = Vec::new();
29451 let dimension = 384; for i in 0..dimension {
29454 let hash = text.bytes().enumerate().fold(0u64, |acc, (j, b)| {
29455 acc.wrapping_add((b as u64).wrapping_mul((i + j + 1) as u64))
29456 });
29457 let value = ((hash % 10000) as f64 / 10000.0) * 2.0 - 1.0; embedding.push(Value::Float(value));
29459 }
29460
29461 let result = Value::Array(Rc::new(RefCell::new(embedding)));
29462
29463 Ok(Value::Evidential {
29465 value: Box::new(result),
29466 evidence: Evidence::Uncertain,
29467 })
29468 });
29469
29470 define(interp, "vec_cosine_similarity", Some(2), |_, args| {
29472 let vec_a = match &args[0] {
29473 Value::Array(arr) => arr.borrow().clone(),
29474 Value::Evidential { value, .. } => {
29475 if let Value::Array(arr) = value.as_ref() {
29476 arr.borrow().clone()
29477 } else {
29478 return Err(RuntimeError::new("vec_cosine_similarity requires arrays"));
29479 }
29480 }
29481 _ => return Err(RuntimeError::new("vec_cosine_similarity requires arrays")),
29482 };
29483
29484 let vec_b = match &args[1] {
29485 Value::Array(arr) => arr.borrow().clone(),
29486 Value::Evidential { value, .. } => {
29487 if let Value::Array(arr) = value.as_ref() {
29488 arr.borrow().clone()
29489 } else {
29490 return Err(RuntimeError::new("vec_cosine_similarity requires arrays"));
29491 }
29492 }
29493 _ => return Err(RuntimeError::new("vec_cosine_similarity requires arrays")),
29494 };
29495
29496 if vec_a.len() != vec_b.len() {
29497 return Err(RuntimeError::new("Vectors must have same dimension"));
29498 }
29499
29500 let mut dot = 0.0;
29501 let mut mag_a = 0.0;
29502 let mut mag_b = 0.0;
29503
29504 for (a, b) in vec_a.iter().zip(vec_b.iter()) {
29505 let a_val = match a {
29506 Value::Float(f) => *f,
29507 Value::Int(i) => *i as f64,
29508 _ => 0.0,
29509 };
29510 let b_val = match b {
29511 Value::Float(f) => *f,
29512 Value::Int(i) => *i as f64,
29513 _ => 0.0,
29514 };
29515
29516 dot += a_val * b_val;
29517 mag_a += a_val * a_val;
29518 mag_b += b_val * b_val;
29519 }
29520
29521 let similarity = if mag_a > 0.0 && mag_b > 0.0 {
29522 dot / (mag_a.sqrt() * mag_b.sqrt())
29523 } else {
29524 0.0
29525 };
29526
29527 Ok(Value::Float(similarity))
29528 });
29529
29530 define(interp, "vec_euclidean_distance", Some(2), |_, args| {
29532 let vec_a = match &args[0] {
29533 Value::Array(arr) => arr.borrow().clone(),
29534 Value::Evidential { value, .. } => {
29535 if let Value::Array(arr) = value.as_ref() {
29536 arr.borrow().clone()
29537 } else {
29538 return Err(RuntimeError::new("vec_euclidean_distance requires arrays"));
29539 }
29540 }
29541 _ => return Err(RuntimeError::new("vec_euclidean_distance requires arrays")),
29542 };
29543
29544 let vec_b = match &args[1] {
29545 Value::Array(arr) => arr.borrow().clone(),
29546 Value::Evidential { value, .. } => {
29547 if let Value::Array(arr) = value.as_ref() {
29548 arr.borrow().clone()
29549 } else {
29550 return Err(RuntimeError::new("vec_euclidean_distance requires arrays"));
29551 }
29552 }
29553 _ => return Err(RuntimeError::new("vec_euclidean_distance requires arrays")),
29554 };
29555
29556 if vec_a.len() != vec_b.len() {
29557 return Err(RuntimeError::new("Vectors must have same dimension"));
29558 }
29559
29560 let mut sum_sq = 0.0;
29561 for (a, b) in vec_a.iter().zip(vec_b.iter()) {
29562 let a_val = match a {
29563 Value::Float(f) => *f,
29564 Value::Int(i) => *i as f64,
29565 _ => 0.0,
29566 };
29567 let b_val = match b {
29568 Value::Float(f) => *f,
29569 Value::Int(i) => *i as f64,
29570 _ => 0.0,
29571 };
29572 let diff = a_val - b_val;
29573 sum_sq += diff * diff;
29574 }
29575
29576 Ok(Value::Float(sum_sq.sqrt()))
29577 });
29578
29579 define(interp, "vec_dot_product", Some(2), |_, args| {
29581 let vec_a = match &args[0] {
29582 Value::Array(arr) => arr.borrow().clone(),
29583 _ => return Err(RuntimeError::new("vec_dot_product requires arrays")),
29584 };
29585
29586 let vec_b = match &args[1] {
29587 Value::Array(arr) => arr.borrow().clone(),
29588 _ => return Err(RuntimeError::new("vec_dot_product requires arrays")),
29589 };
29590
29591 if vec_a.len() != vec_b.len() {
29592 return Err(RuntimeError::new("Vectors must have same dimension"));
29593 }
29594
29595 let mut dot = 0.0;
29596 for (a, b) in vec_a.iter().zip(vec_b.iter()) {
29597 let a_val = match a {
29598 Value::Float(f) => *f,
29599 Value::Int(i) => *i as f64,
29600 _ => 0.0,
29601 };
29602 let b_val = match b {
29603 Value::Float(f) => *f,
29604 Value::Int(i) => *i as f64,
29605 _ => 0.0,
29606 };
29607 dot += a_val * b_val;
29608 }
29609
29610 Ok(Value::Float(dot))
29611 });
29612
29613 define(interp, "vec_normalize", Some(1), |_, args| {
29615 let vec = match &args[0] {
29616 Value::Array(arr) => arr.borrow().clone(),
29617 _ => return Err(RuntimeError::new("vec_normalize requires array")),
29618 };
29619
29620 let mut mag = 0.0;
29621 for v in vec.iter() {
29622 let val = match v {
29623 Value::Float(f) => *f,
29624 Value::Int(i) => *i as f64,
29625 _ => 0.0,
29626 };
29627 mag += val * val;
29628 }
29629 mag = mag.sqrt();
29630
29631 if mag == 0.0 {
29632 return Ok(Value::Array(Rc::new(RefCell::new(vec))));
29633 }
29634
29635 let normalized: Vec<Value> = vec
29636 .iter()
29637 .map(|v| {
29638 let val = match v {
29639 Value::Float(f) => *f,
29640 Value::Int(i) => *i as f64,
29641 _ => 0.0,
29642 };
29643 Value::Float(val / mag)
29644 })
29645 .collect();
29646
29647 Ok(Value::Array(Rc::new(RefCell::new(normalized))))
29648 });
29649
29650 define(interp, "vec_search", Some(3), |_, args| {
29652 let query = match &args[0] {
29653 Value::Array(arr) => arr.borrow().clone(),
29654 Value::Evidential { value, .. } => {
29655 if let Value::Array(arr) = value.as_ref() {
29656 arr.borrow().clone()
29657 } else {
29658 return Err(RuntimeError::new("vec_search query must be array"));
29659 }
29660 }
29661 _ => return Err(RuntimeError::new("vec_search query must be array")),
29662 };
29663
29664 let corpus = match &args[1] {
29665 Value::Array(arr) => arr.borrow().clone(),
29666 _ => {
29667 return Err(RuntimeError::new(
29668 "vec_search corpus must be array of vectors",
29669 ))
29670 }
29671 };
29672
29673 let k = match &args[2] {
29674 Value::Int(n) => *n as usize,
29675 _ => return Err(RuntimeError::new("vec_search k must be integer")),
29676 };
29677
29678 let mut similarities: Vec<(usize, f64)> = Vec::new();
29680
29681 for (i, item) in corpus.iter().enumerate() {
29682 let vec_b = match item {
29683 Value::Array(arr) => arr.borrow().clone(),
29684 Value::Map(m) => {
29685 if let Some(Value::Array(arr)) = m.borrow().get("vector") {
29687 arr.borrow().clone()
29688 } else {
29689 continue;
29690 }
29691 }
29692 _ => continue,
29693 };
29694
29695 if vec_b.len() != query.len() {
29696 continue;
29697 }
29698
29699 let mut dot = 0.0;
29700 let mut mag_a = 0.0;
29701 let mut mag_b = 0.0;
29702
29703 for (a, b) in query.iter().zip(vec_b.iter()) {
29704 let a_val = match a {
29705 Value::Float(f) => *f,
29706 Value::Int(i) => *i as f64,
29707 _ => 0.0,
29708 };
29709 let b_val = match b {
29710 Value::Float(f) => *f,
29711 Value::Int(i) => *i as f64,
29712 _ => 0.0,
29713 };
29714 dot += a_val * b_val;
29715 mag_a += a_val * a_val;
29716 mag_b += b_val * b_val;
29717 }
29718
29719 let similarity = if mag_a > 0.0 && mag_b > 0.0 {
29720 dot / (mag_a.sqrt() * mag_b.sqrt())
29721 } else {
29722 0.0
29723 };
29724
29725 similarities.push((i, similarity));
29726 }
29727
29728 similarities.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(std::cmp::Ordering::Equal));
29730
29731 let results: Vec<Value> = similarities
29733 .iter()
29734 .take(k)
29735 .map(|(idx, sim)| {
29736 let mut result = HashMap::new();
29737 result.insert("index".to_string(), Value::Int(*idx as i64));
29738 result.insert("similarity".to_string(), Value::Float(*sim));
29739 result.insert(
29740 "item".to_string(),
29741 corpus.get(*idx).cloned().unwrap_or(Value::Null),
29742 );
29743 Value::Map(Rc::new(RefCell::new(result)))
29744 })
29745 .collect();
29746
29747 Ok(Value::Array(Rc::new(RefCell::new(results))))
29748 });
29749
29750 define(interp, "vec_store", Some(0), |_, _args| {
29752 let mut store = HashMap::new();
29753 store.insert(
29754 "vectors".to_string(),
29755 Value::Array(Rc::new(RefCell::new(Vec::new()))),
29756 );
29757 store.insert(
29758 "metadata".to_string(),
29759 Value::Array(Rc::new(RefCell::new(Vec::new()))),
29760 );
29761 store.insert("count".to_string(), Value::Int(0));
29762 Ok(Value::Map(Rc::new(RefCell::new(store))))
29763 });
29764
29765 define(interp, "vec_store_add", Some(3), |_, args| {
29767 let store = match &args[0] {
29768 Value::Map(m) => m.clone(),
29769 _ => return Err(RuntimeError::new("vec_store_add requires store")),
29770 };
29771
29772 let vector = args[1].clone();
29773 let metadata = args[2].clone();
29774
29775 let mut store_ref = store.borrow_mut();
29776
29777 if let Some(Value::Array(vectors)) = store_ref.get("vectors") {
29778 vectors.borrow_mut().push(vector);
29779 }
29780 if let Some(Value::Array(metas)) = store_ref.get("metadata") {
29781 metas.borrow_mut().push(metadata);
29782 }
29783
29784 let new_count = store_ref
29785 .get("count")
29786 .and_then(|v| {
29787 if let Value::Int(n) = v {
29788 Some(*n)
29789 } else {
29790 None
29791 }
29792 })
29793 .unwrap_or(0)
29794 + 1;
29795 store_ref.insert("count".to_string(), Value::Int(new_count));
29796
29797 Ok(Value::Int(new_count))
29798 });
29799
29800 define(interp, "vec_store_search", Some(3), |_, args| {
29802 let store = match &args[0] {
29803 Value::Map(m) => m.borrow().clone(),
29804 _ => return Err(RuntimeError::new("vec_store_search requires store")),
29805 };
29806
29807 let query = match &args[1] {
29808 Value::Array(arr) => arr.borrow().clone(),
29809 Value::Evidential { value, .. } => {
29810 if let Value::Array(arr) = value.as_ref() {
29811 arr.borrow().clone()
29812 } else {
29813 return Err(RuntimeError::new("Query must be array"));
29814 }
29815 }
29816 _ => return Err(RuntimeError::new("Query must be array")),
29817 };
29818
29819 let k = match &args[2] {
29820 Value::Int(n) => *n as usize,
29821 _ => return Err(RuntimeError::new("k must be integer")),
29822 };
29823
29824 let vectors = store
29825 .get("vectors")
29826 .and_then(|v| {
29827 if let Value::Array(arr) = v {
29828 Some(arr.borrow().clone())
29829 } else {
29830 None
29831 }
29832 })
29833 .unwrap_or_default();
29834
29835 let metadata = store
29836 .get("metadata")
29837 .and_then(|v| {
29838 if let Value::Array(arr) = v {
29839 Some(arr.borrow().clone())
29840 } else {
29841 None
29842 }
29843 })
29844 .unwrap_or_default();
29845
29846 let mut similarities: Vec<(usize, f64)> = Vec::new();
29847
29848 for (i, vec_val) in vectors.iter().enumerate() {
29849 let vec_b = match vec_val {
29850 Value::Array(arr) => arr.borrow().clone(),
29851 Value::Evidential { value, .. } => {
29852 if let Value::Array(arr) = value.as_ref() {
29853 arr.borrow().clone()
29854 } else {
29855 continue;
29856 }
29857 }
29858 _ => continue,
29859 };
29860
29861 if vec_b.len() != query.len() {
29862 continue;
29863 }
29864
29865 let mut dot = 0.0;
29866 let mut mag_a = 0.0;
29867 let mut mag_b = 0.0;
29868
29869 for (a, b) in query.iter().zip(vec_b.iter()) {
29870 let a_val = match a {
29871 Value::Float(f) => *f,
29872 Value::Int(i) => *i as f64,
29873 _ => 0.0,
29874 };
29875 let b_val = match b {
29876 Value::Float(f) => *f,
29877 Value::Int(i) => *i as f64,
29878 _ => 0.0,
29879 };
29880 dot += a_val * b_val;
29881 mag_a += a_val * a_val;
29882 mag_b += b_val * b_val;
29883 }
29884
29885 let sim = if mag_a > 0.0 && mag_b > 0.0 {
29886 dot / (mag_a.sqrt() * mag_b.sqrt())
29887 } else {
29888 0.0
29889 };
29890 similarities.push((i, sim));
29891 }
29892
29893 similarities.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(std::cmp::Ordering::Equal));
29894
29895 let results: Vec<Value> = similarities
29896 .iter()
29897 .take(k)
29898 .map(|(idx, sim)| {
29899 let mut result = HashMap::new();
29900 result.insert("index".to_string(), Value::Int(*idx as i64));
29901 result.insert("similarity".to_string(), Value::Float(*sim));
29902 result.insert(
29903 "vector".to_string(),
29904 vectors.get(*idx).cloned().unwrap_or(Value::Null),
29905 );
29906 result.insert(
29907 "metadata".to_string(),
29908 metadata.get(*idx).cloned().unwrap_or(Value::Null),
29909 );
29910 Value::Map(Rc::new(RefCell::new(result)))
29911 })
29912 .collect();
29913
29914 Ok(Value::Array(Rc::new(RefCell::new(results))))
29915 });
29916}
29917
29918thread_local! {
29924 static AGENT_REGISTRY: RefCell<HashMap<String, AgentInfo>> = RefCell::new(HashMap::new());
29925 static AGENT_MESSAGES: RefCell<HashMap<String, Vec<AgentMessage>>> = RefCell::new(HashMap::new());
29926}
29927
29928#[derive(Clone)]
29929struct AgentInfo {
29930 id: String,
29931 agent_type: String,
29932 state: HashMap<String, Value>,
29933 capabilities: Vec<String>,
29934 created_at: u64,
29935}
29936
29937#[derive(Clone)]
29938struct AgentMessage {
29939 from: String,
29940 to: String,
29941 msg_type: String,
29942 content: Value,
29943 timestamp: u64,
29944}
29945
29946fn register_agent_swarm(interp: &mut Interpreter) {
29947 define(interp, "swarm_create_agent", Some(2), |_, args| {
29949 let agent_id = match &args[0] {
29950 Value::String(s) => s.as_str().to_string(),
29951 _ => return Err(RuntimeError::new("swarm_create_agent requires string id")),
29952 };
29953
29954 let agent_type = match &args[1] {
29955 Value::String(s) => s.as_str().to_string(),
29956 _ => return Err(RuntimeError::new("swarm_create_agent requires string type")),
29957 };
29958
29959 let now = std::time::SystemTime::now()
29960 .duration_since(std::time::UNIX_EPOCH)
29961 .unwrap_or_default()
29962 .as_secs();
29963
29964 let agent = AgentInfo {
29965 id: agent_id.clone(),
29966 agent_type,
29967 state: HashMap::new(),
29968 capabilities: Vec::new(),
29969 created_at: now,
29970 };
29971
29972 AGENT_REGISTRY.with(|registry| {
29973 registry.borrow_mut().insert(agent_id.clone(), agent);
29974 });
29975
29976 AGENT_MESSAGES.with(|messages| {
29977 messages.borrow_mut().insert(agent_id.clone(), Vec::new());
29978 });
29979
29980 let mut result = HashMap::new();
29981 result.insert("id".to_string(), Value::String(Rc::new(agent_id)));
29982 result.insert("created_at".to_string(), Value::Int(now as i64));
29983 Ok(Value::Map(Rc::new(RefCell::new(result))))
29984 });
29985
29986 define(interp, "swarm_add_capability", Some(2), |_, args| {
29988 let agent_id = match &args[0] {
29989 Value::String(s) => s.as_str().to_string(),
29990 Value::Map(m) => m
29991 .borrow()
29992 .get("id")
29993 .and_then(|v| {
29994 if let Value::String(s) = v {
29995 Some(s.as_str().to_string())
29996 } else {
29997 None
29998 }
29999 })
30000 .ok_or_else(|| RuntimeError::new("Invalid agent"))?,
30001 _ => return Err(RuntimeError::new("swarm_add_capability requires agent")),
30002 };
30003
30004 let capability = match &args[1] {
30005 Value::String(s) => s.as_str().to_string(),
30006 _ => return Err(RuntimeError::new("capability must be string")),
30007 };
30008
30009 AGENT_REGISTRY.with(|registry| {
30010 if let Some(agent) = registry.borrow_mut().get_mut(&agent_id) {
30011 if !agent.capabilities.contains(&capability) {
30012 agent.capabilities.push(capability);
30013 }
30014 Ok(Value::Bool(true))
30015 } else {
30016 Err(RuntimeError::new(format!("Agent '{}' not found", agent_id)))
30017 }
30018 })
30019 });
30020
30021 define(interp, "swarm_send_message", Some(4), |_, args| {
30023 let from_id = match &args[0] {
30024 Value::String(s) => s.as_str().to_string(),
30025 Value::Map(m) => m
30026 .borrow()
30027 .get("id")
30028 .and_then(|v| {
30029 if let Value::String(s) = v {
30030 Some(s.as_str().to_string())
30031 } else {
30032 None
30033 }
30034 })
30035 .ok_or_else(|| RuntimeError::new("Invalid sender agent"))?,
30036 _ => {
30037 return Err(RuntimeError::new(
30038 "swarm_send_message requires sender agent",
30039 ))
30040 }
30041 };
30042
30043 let to_id = match &args[1] {
30044 Value::String(s) => s.as_str().to_string(),
30045 Value::Map(m) => m
30046 .borrow()
30047 .get("id")
30048 .and_then(|v| {
30049 if let Value::String(s) = v {
30050 Some(s.as_str().to_string())
30051 } else {
30052 None
30053 }
30054 })
30055 .ok_or_else(|| RuntimeError::new("Invalid receiver agent"))?,
30056 _ => {
30057 return Err(RuntimeError::new(
30058 "swarm_send_message requires receiver agent",
30059 ))
30060 }
30061 };
30062
30063 let msg_type = match &args[2] {
30064 Value::String(s) => s.as_str().to_string(),
30065 _ => return Err(RuntimeError::new("message type must be string")),
30066 };
30067
30068 let content = args[3].clone();
30069
30070 let now = std::time::SystemTime::now()
30071 .duration_since(std::time::UNIX_EPOCH)
30072 .unwrap_or_default()
30073 .as_secs();
30074
30075 let message = AgentMessage {
30076 from: from_id.clone(),
30077 to: to_id.clone(),
30078 msg_type,
30079 content,
30080 timestamp: now,
30081 };
30082
30083 AGENT_MESSAGES.with(|messages| {
30084 if let Some(queue) = messages.borrow_mut().get_mut(&to_id) {
30085 queue.push(message);
30086 Ok(Value::Bool(true))
30087 } else {
30088 Err(RuntimeError::new(format!("Agent '{}' not found", to_id)))
30089 }
30090 })
30091 });
30092
30093 define(interp, "swarm_receive_messages", Some(1), |_, args| {
30095 let agent_id = match &args[0] {
30096 Value::String(s) => s.as_str().to_string(),
30097 Value::Map(m) => m
30098 .borrow()
30099 .get("id")
30100 .and_then(|v| {
30101 if let Value::String(s) = v {
30102 Some(s.as_str().to_string())
30103 } else {
30104 None
30105 }
30106 })
30107 .ok_or_else(|| RuntimeError::new("Invalid agent"))?,
30108 _ => return Err(RuntimeError::new("swarm_receive_messages requires agent")),
30109 };
30110
30111 AGENT_MESSAGES.with(|messages| {
30112 if let Some(queue) = messages.borrow_mut().get_mut(&agent_id) {
30113 let msgs: Vec<Value> = queue
30114 .drain(..)
30115 .map(|m| {
30116 let mut msg_map = HashMap::new();
30117 msg_map.insert("from".to_string(), Value::String(Rc::new(m.from)));
30118 msg_map.insert("to".to_string(), Value::String(Rc::new(m.to)));
30119 msg_map.insert("type".to_string(), Value::String(Rc::new(m.msg_type)));
30120 msg_map.insert("content".to_string(), m.content);
30121 msg_map.insert("timestamp".to_string(), Value::Int(m.timestamp as i64));
30122 Value::Map(Rc::new(RefCell::new(msg_map)))
30123 })
30124 .collect();
30125 Ok(Value::Array(Rc::new(RefCell::new(msgs))))
30126 } else {
30127 Ok(Value::Array(Rc::new(RefCell::new(Vec::new()))))
30128 }
30129 })
30130 });
30131
30132 define(interp, "swarm_broadcast", Some(3), |_, args| {
30134 let from_id = match &args[0] {
30135 Value::String(s) => s.as_str().to_string(),
30136 Value::Map(m) => m
30137 .borrow()
30138 .get("id")
30139 .and_then(|v| {
30140 if let Value::String(s) = v {
30141 Some(s.as_str().to_string())
30142 } else {
30143 None
30144 }
30145 })
30146 .ok_or_else(|| RuntimeError::new("Invalid sender agent"))?,
30147 _ => return Err(RuntimeError::new("swarm_broadcast requires sender agent")),
30148 };
30149
30150 let msg_type = match &args[1] {
30151 Value::String(s) => s.as_str().to_string(),
30152 _ => return Err(RuntimeError::new("message type must be string")),
30153 };
30154
30155 let content = args[2].clone();
30156
30157 let now = std::time::SystemTime::now()
30158 .duration_since(std::time::UNIX_EPOCH)
30159 .unwrap_or_default()
30160 .as_secs();
30161
30162 let agent_ids: Vec<String> = AGENT_REGISTRY.with(|registry| {
30164 registry
30165 .borrow()
30166 .keys()
30167 .filter(|id| *id != &from_id)
30168 .cloned()
30169 .collect()
30170 });
30171
30172 let mut count = 0;
30173 AGENT_MESSAGES.with(|messages| {
30174 let mut msgs = messages.borrow_mut();
30175 for to_id in agent_ids {
30176 if let Some(queue) = msgs.get_mut(&to_id) {
30177 queue.push(AgentMessage {
30178 from: from_id.clone(),
30179 to: to_id,
30180 msg_type: msg_type.clone(),
30181 content: content.clone(),
30182 timestamp: now,
30183 });
30184 count += 1;
30185 }
30186 }
30187 });
30188
30189 Ok(Value::Int(count))
30190 });
30191
30192 define(interp, "swarm_find_agents", Some(1), |_, args| {
30194 let capability = match &args[0] {
30195 Value::String(s) => s.as_str().to_string(),
30196 _ => {
30197 return Err(RuntimeError::new(
30198 "swarm_find_agents requires capability string",
30199 ))
30200 }
30201 };
30202
30203 let agents: Vec<Value> = AGENT_REGISTRY.with(|registry| {
30204 registry
30205 .borrow()
30206 .values()
30207 .filter(|agent| agent.capabilities.contains(&capability))
30208 .map(|agent| {
30209 let mut info = HashMap::new();
30210 info.insert("id".to_string(), Value::String(Rc::new(agent.id.clone())));
30211 info.insert(
30212 "type".to_string(),
30213 Value::String(Rc::new(agent.agent_type.clone())),
30214 );
30215 info.insert(
30216 "capabilities".to_string(),
30217 Value::Array(Rc::new(RefCell::new(
30218 agent
30219 .capabilities
30220 .iter()
30221 .map(|c| Value::String(Rc::new(c.clone())))
30222 .collect(),
30223 ))),
30224 );
30225 Value::Map(Rc::new(RefCell::new(info)))
30226 })
30227 .collect()
30228 });
30229
30230 Ok(Value::Array(Rc::new(RefCell::new(agents))))
30231 });
30232
30233 define(interp, "swarm_list_agents", Some(0), |_, _args| {
30235 let agents: Vec<Value> = AGENT_REGISTRY.with(|registry| {
30236 registry
30237 .borrow()
30238 .values()
30239 .map(|agent| {
30240 let mut info = HashMap::new();
30241 info.insert("id".to_string(), Value::String(Rc::new(agent.id.clone())));
30242 info.insert(
30243 "type".to_string(),
30244 Value::String(Rc::new(agent.agent_type.clone())),
30245 );
30246 info.insert(
30247 "capabilities".to_string(),
30248 Value::Array(Rc::new(RefCell::new(
30249 agent
30250 .capabilities
30251 .iter()
30252 .map(|c| Value::String(Rc::new(c.clone())))
30253 .collect(),
30254 ))),
30255 );
30256 info.insert(
30257 "created_at".to_string(),
30258 Value::Int(agent.created_at as i64),
30259 );
30260 Value::Map(Rc::new(RefCell::new(info)))
30261 })
30262 .collect()
30263 });
30264 Ok(Value::Array(Rc::new(RefCell::new(agents))))
30265 });
30266
30267 define(interp, "swarm_set_state", Some(3), |_, args| {
30269 let agent_id = match &args[0] {
30270 Value::String(s) => s.as_str().to_string(),
30271 Value::Map(m) => m
30272 .borrow()
30273 .get("id")
30274 .and_then(|v| {
30275 if let Value::String(s) = v {
30276 Some(s.as_str().to_string())
30277 } else {
30278 None
30279 }
30280 })
30281 .ok_or_else(|| RuntimeError::new("Invalid agent"))?,
30282 _ => return Err(RuntimeError::new("swarm_set_state requires agent")),
30283 };
30284
30285 let key = match &args[1] {
30286 Value::String(s) => s.as_str().to_string(),
30287 _ => return Err(RuntimeError::new("key must be string")),
30288 };
30289
30290 let value = args[2].clone();
30291
30292 AGENT_REGISTRY.with(|registry| {
30293 if let Some(agent) = registry.borrow_mut().get_mut(&agent_id) {
30294 agent.state.insert(key, value);
30295 Ok(Value::Bool(true))
30296 } else {
30297 Err(RuntimeError::new(format!("Agent '{}' not found", agent_id)))
30298 }
30299 })
30300 });
30301
30302 define(interp, "swarm_get_state", Some(2), |_, args| {
30304 let agent_id = match &args[0] {
30305 Value::String(s) => s.as_str().to_string(),
30306 Value::Map(m) => m
30307 .borrow()
30308 .get("id")
30309 .and_then(|v| {
30310 if let Value::String(s) = v {
30311 Some(s.as_str().to_string())
30312 } else {
30313 None
30314 }
30315 })
30316 .ok_or_else(|| RuntimeError::new("Invalid agent"))?,
30317 _ => return Err(RuntimeError::new("swarm_get_state requires agent")),
30318 };
30319
30320 let key = match &args[1] {
30321 Value::String(s) => s.as_str().to_string(),
30322 _ => return Err(RuntimeError::new("key must be string")),
30323 };
30324
30325 AGENT_REGISTRY.with(|registry| {
30326 if let Some(agent) = registry.borrow().get(&agent_id) {
30327 Ok(agent.state.get(&key).cloned().unwrap_or(Value::Null))
30328 } else {
30329 Ok(Value::Null)
30330 }
30331 })
30332 });
30333
30334 define(interp, "swarm_remove_agent", Some(1), |_, args| {
30336 let agent_id = match &args[0] {
30337 Value::String(s) => s.as_str().to_string(),
30338 Value::Map(m) => m
30339 .borrow()
30340 .get("id")
30341 .and_then(|v| {
30342 if let Value::String(s) = v {
30343 Some(s.as_str().to_string())
30344 } else {
30345 None
30346 }
30347 })
30348 .ok_or_else(|| RuntimeError::new("Invalid agent"))?,
30349 _ => return Err(RuntimeError::new("swarm_remove_agent requires agent")),
30350 };
30351
30352 let removed =
30353 AGENT_REGISTRY.with(|registry| registry.borrow_mut().remove(&agent_id).is_some());
30354
30355 AGENT_MESSAGES.with(|messages| {
30356 messages.borrow_mut().remove(&agent_id);
30357 });
30358
30359 Ok(Value::Bool(removed))
30360 });
30361
30362 define(interp, "swarm_consensus", Some(2), |_, args| {
30364 let topic = match &args[0] {
30365 Value::String(s) => s.as_str().to_string(),
30366 _ => return Err(RuntimeError::new("topic must be string")),
30367 };
30368
30369 let votes = match &args[1] {
30370 Value::Array(arr) => arr.borrow().clone(),
30371 _ => return Err(RuntimeError::new("votes must be array")),
30372 };
30373
30374 let mut vote_counts: HashMap<String, i64> = HashMap::new();
30376 for vote in votes.iter() {
30377 let vote_str = match vote {
30378 Value::String(s) => s.as_str().to_string(),
30379 Value::Bool(b) => b.to_string(),
30380 Value::Int(n) => n.to_string(),
30381 _ => continue,
30382 };
30383 *vote_counts.entry(vote_str).or_insert(0) += 1;
30384 }
30385
30386 let total = votes.len() as i64;
30388 let (winner, count) = vote_counts
30389 .iter()
30390 .max_by_key(|(_, &count)| count)
30391 .map(|(k, &v)| (k.clone(), v))
30392 .unwrap_or_default();
30393
30394 let mut result = HashMap::new();
30395 result.insert("topic".to_string(), Value::String(Rc::new(topic)));
30396 result.insert("winner".to_string(), Value::String(Rc::new(winner)));
30397 result.insert("votes".to_string(), Value::Int(count));
30398 result.insert("total".to_string(), Value::Int(total));
30399 result.insert("majority".to_string(), Value::Bool(count > total / 2));
30400
30401 Ok(Value::Map(Rc::new(RefCell::new(result))))
30402 });
30403}
30404
30405fn register_agent_reasoning(interp: &mut Interpreter) {
30410 define(interp, "reason_constraint", Some(3), |_, args| {
30412 let name = match &args[0] {
30413 Value::String(s) => s.as_str().to_string(),
30414 _ => return Err(RuntimeError::new("constraint name must be string")),
30415 };
30416
30417 let constraint_type = match &args[1] {
30418 Value::String(s) => s.as_str().to_string(),
30419 _ => return Err(RuntimeError::new("constraint type must be string")),
30420 };
30421
30422 let params = args[2].clone();
30423
30424 let mut constraint = HashMap::new();
30425 constraint.insert("name".to_string(), Value::String(Rc::new(name)));
30426 constraint.insert("type".to_string(), Value::String(Rc::new(constraint_type)));
30427 constraint.insert("params".to_string(), params);
30428 constraint.insert("satisfied".to_string(), Value::Bool(false));
30429
30430 Ok(Value::Map(Rc::new(RefCell::new(constraint))))
30431 });
30432
30433 define(interp, "reason_check_constraint", Some(2), |_, args| {
30435 let constraint = match &args[0] {
30436 Value::Map(m) => m.borrow().clone(),
30437 _ => {
30438 return Err(RuntimeError::new(
30439 "reason_check_constraint requires constraint",
30440 ))
30441 }
30442 };
30443
30444 let context = match &args[1] {
30445 Value::Map(m) => m.borrow().clone(),
30446 _ => {
30447 return Err(RuntimeError::new(
30448 "reason_check_constraint requires context",
30449 ))
30450 }
30451 };
30452
30453 let constraint_type = constraint
30454 .get("type")
30455 .and_then(|v| {
30456 if let Value::String(s) = v {
30457 Some(s.as_str())
30458 } else {
30459 None
30460 }
30461 })
30462 .unwrap_or("unknown");
30463
30464 let params = constraint.get("params").cloned().unwrap_or(Value::Null);
30465
30466 let satisfied = match constraint_type {
30467 "equals" => {
30468 if let Value::Map(p) = ¶ms {
30469 let p = p.borrow();
30470 let var_name = p
30471 .get("var")
30472 .and_then(|v| {
30473 if let Value::String(s) = v {
30474 Some(s.as_str().to_string())
30475 } else {
30476 None
30477 }
30478 })
30479 .unwrap_or_default();
30480 let expected = p.get("value").cloned().unwrap_or(Value::Null);
30481 let actual = context.get(&var_name).cloned().unwrap_or(Value::Null);
30482 values_equal_simple(&actual, &expected)
30483 } else {
30484 false
30485 }
30486 }
30487 "not_null" => {
30488 if let Value::Map(p) = ¶ms {
30489 let p = p.borrow();
30490 let var_name = p
30491 .get("var")
30492 .and_then(|v| {
30493 if let Value::String(s) = v {
30494 Some(s.as_str().to_string())
30495 } else {
30496 None
30497 }
30498 })
30499 .unwrap_or_default();
30500 !matches!(context.get(&var_name), None | Some(Value::Null))
30501 } else {
30502 false
30503 }
30504 }
30505 "range" => {
30506 if let Value::Map(p) = ¶ms {
30507 let p = p.borrow();
30508 let var_name = p
30509 .get("var")
30510 .and_then(|v| {
30511 if let Value::String(s) = v {
30512 Some(s.as_str().to_string())
30513 } else {
30514 None
30515 }
30516 })
30517 .unwrap_or_default();
30518 let min = p
30519 .get("min")
30520 .and_then(|v| match v {
30521 Value::Int(n) => Some(*n as f64),
30522 Value::Float(f) => Some(*f),
30523 _ => None,
30524 })
30525 .unwrap_or(f64::NEG_INFINITY);
30526 let max = p
30527 .get("max")
30528 .and_then(|v| match v {
30529 Value::Int(n) => Some(*n as f64),
30530 Value::Float(f) => Some(*f),
30531 _ => None,
30532 })
30533 .unwrap_or(f64::INFINITY);
30534 let actual = context
30535 .get(&var_name)
30536 .and_then(|v| match v {
30537 Value::Int(n) => Some(*n as f64),
30538 Value::Float(f) => Some(*f),
30539 _ => None,
30540 })
30541 .unwrap_or(0.0);
30542 actual >= min && actual <= max
30543 } else {
30544 false
30545 }
30546 }
30547 "contains" => {
30548 if let Value::Map(p) = ¶ms {
30549 let p = p.borrow();
30550 let var_name = p
30551 .get("var")
30552 .and_then(|v| {
30553 if let Value::String(s) = v {
30554 Some(s.as_str().to_string())
30555 } else {
30556 None
30557 }
30558 })
30559 .unwrap_or_default();
30560 let needle = p
30561 .get("value")
30562 .and_then(|v| {
30563 if let Value::String(s) = v {
30564 Some(s.as_str().to_string())
30565 } else {
30566 None
30567 }
30568 })
30569 .unwrap_or_default();
30570 let actual = context
30571 .get(&var_name)
30572 .and_then(|v| {
30573 if let Value::String(s) = v {
30574 Some(s.as_str().to_string())
30575 } else {
30576 None
30577 }
30578 })
30579 .unwrap_or_default();
30580 actual.contains(&needle)
30581 } else {
30582 false
30583 }
30584 }
30585 _ => false,
30586 };
30587
30588 let mut result = HashMap::new();
30589 result.insert("satisfied".to_string(), Value::Bool(satisfied));
30590 result.insert(
30591 "constraint".to_string(),
30592 Value::Map(Rc::new(RefCell::new(constraint))),
30593 );
30594
30595 Ok(Value::Map(Rc::new(RefCell::new(result))))
30596 });
30597
30598 define(interp, "reason_check_all", Some(2), |interp, args| {
30600 let constraints = match &args[0] {
30601 Value::Array(arr) => arr.borrow().clone(),
30602 _ => {
30603 return Err(RuntimeError::new(
30604 "reason_check_all requires constraints array",
30605 ))
30606 }
30607 };
30608
30609 let context = args[1].clone();
30610
30611 let mut all_satisfied = true;
30612 let mut results: Vec<Value> = Vec::new();
30613
30614 for constraint in constraints.iter() {
30615 if let Value::Map(c) = constraint {
30617 let c_type = c
30618 .borrow()
30619 .get("type")
30620 .and_then(|v| {
30621 if let Value::String(s) = v {
30622 Some(s.as_ref().clone())
30623 } else {
30624 None
30625 }
30626 })
30627 .unwrap_or_else(|| "unknown".to_string());
30628 let params = c.borrow().get("params").cloned().unwrap_or(Value::Null);
30629
30630 let ctx = match &context {
30631 Value::Map(m) => m.borrow().clone(),
30632 _ => HashMap::new(),
30633 };
30634
30635 let satisfied = match c_type.as_str() {
30636 "equals" => {
30637 if let Value::Map(p) = ¶ms {
30638 let p = p.borrow();
30639 let var_name = p
30640 .get("var")
30641 .and_then(|v| {
30642 if let Value::String(s) = v {
30643 Some(s.as_str().to_string())
30644 } else {
30645 None
30646 }
30647 })
30648 .unwrap_or_default();
30649 let expected = p.get("value").cloned().unwrap_or(Value::Null);
30650 let actual = ctx.get(&var_name).cloned().unwrap_or(Value::Null);
30651 values_equal_simple(&actual, &expected)
30652 } else {
30653 false
30654 }
30655 }
30656 "not_null" => {
30657 if let Value::Map(p) = ¶ms {
30658 let p = p.borrow();
30659 let var_name = p
30660 .get("var")
30661 .and_then(|v| {
30662 if let Value::String(s) = v {
30663 Some(s.as_str().to_string())
30664 } else {
30665 None
30666 }
30667 })
30668 .unwrap_or_default();
30669 !matches!(ctx.get(&var_name), None | Some(Value::Null))
30670 } else {
30671 false
30672 }
30673 }
30674 _ => true, };
30676
30677 if !satisfied {
30678 all_satisfied = false;
30679 }
30680
30681 let mut r = HashMap::new();
30682 r.insert("constraint".to_string(), constraint.clone());
30683 r.insert("satisfied".to_string(), Value::Bool(satisfied));
30684 results.push(Value::Map(Rc::new(RefCell::new(r))));
30685 }
30686 }
30687
30688 let _ = interp; let mut result = HashMap::new();
30691 result.insert("all_satisfied".to_string(), Value::Bool(all_satisfied));
30692 result.insert(
30693 "results".to_string(),
30694 Value::Array(Rc::new(RefCell::new(results))),
30695 );
30696 result.insert("total".to_string(), Value::Int(constraints.len() as i64));
30697
30698 Ok(Value::Map(Rc::new(RefCell::new(result))))
30699 });
30700
30701 define(interp, "reason_implies", Some(2), |_, args| {
30703 let antecedent = args[0].clone();
30704 let consequent = args[1].clone();
30705
30706 let mut implication = HashMap::new();
30707 implication.insert(
30708 "type".to_string(),
30709 Value::String(Rc::new("implication".to_string())),
30710 );
30711 implication.insert("if".to_string(), antecedent);
30712 implication.insert("then".to_string(), consequent);
30713
30714 Ok(Value::Map(Rc::new(RefCell::new(implication))))
30715 });
30716
30717 define(interp, "reason_and", None, |_, args| {
30719 let conditions: Vec<Value> = args.into_iter().collect();
30720
30721 let mut conjunction = HashMap::new();
30722 conjunction.insert(
30723 "type".to_string(),
30724 Value::String(Rc::new("and".to_string())),
30725 );
30726 conjunction.insert(
30727 "conditions".to_string(),
30728 Value::Array(Rc::new(RefCell::new(conditions))),
30729 );
30730
30731 Ok(Value::Map(Rc::new(RefCell::new(conjunction))))
30732 });
30733
30734 define(interp, "reason_or", None, |_, args| {
30736 let conditions: Vec<Value> = args.into_iter().collect();
30737
30738 let mut disjunction = HashMap::new();
30739 disjunction.insert("type".to_string(), Value::String(Rc::new("or".to_string())));
30740 disjunction.insert(
30741 "conditions".to_string(),
30742 Value::Array(Rc::new(RefCell::new(conditions))),
30743 );
30744
30745 Ok(Value::Map(Rc::new(RefCell::new(disjunction))))
30746 });
30747
30748 define(interp, "reason_not", Some(1), |_, args| {
30750 let condition = args[0].clone();
30751
30752 let mut negation = HashMap::new();
30753 negation.insert(
30754 "type".to_string(),
30755 Value::String(Rc::new("not".to_string())),
30756 );
30757 negation.insert("condition".to_string(), condition);
30758
30759 Ok(Value::Map(Rc::new(RefCell::new(negation))))
30760 });
30761
30762 define(interp, "reason_evaluate", Some(2), |_, args| {
30764 let expr = match &args[0] {
30765 Value::Map(m) => m.borrow().clone(),
30766 Value::Bool(b) => return Ok(Value::Bool(*b)),
30767 _ => return Err(RuntimeError::new("reason_evaluate requires expression")),
30768 };
30769
30770 let context = match &args[1] {
30771 Value::Map(m) => m.borrow().clone(),
30772 _ => HashMap::new(),
30773 };
30774
30775 fn eval_expr(expr: &HashMap<String, Value>, ctx: &HashMap<String, Value>) -> bool {
30776 let expr_type = expr
30777 .get("type")
30778 .and_then(|v| {
30779 if let Value::String(s) = v {
30780 Some(s.as_str())
30781 } else {
30782 None
30783 }
30784 })
30785 .unwrap_or("unknown");
30786
30787 match expr_type {
30788 "and" => {
30789 if let Some(Value::Array(conditions)) = expr.get("conditions") {
30790 conditions.borrow().iter().all(|c| {
30791 if let Value::Map(m) = c {
30792 eval_expr(&m.borrow(), ctx)
30793 } else if let Value::Bool(b) = c {
30794 *b
30795 } else {
30796 false
30797 }
30798 })
30799 } else {
30800 false
30801 }
30802 }
30803 "or" => {
30804 if let Some(Value::Array(conditions)) = expr.get("conditions") {
30805 conditions.borrow().iter().any(|c| {
30806 if let Value::Map(m) = c {
30807 eval_expr(&m.borrow(), ctx)
30808 } else if let Value::Bool(b) = c {
30809 *b
30810 } else {
30811 false
30812 }
30813 })
30814 } else {
30815 false
30816 }
30817 }
30818 "not" => {
30819 if let Some(condition) = expr.get("condition") {
30820 if let Value::Map(m) = condition {
30821 !eval_expr(&m.borrow(), ctx)
30822 } else if let Value::Bool(b) = condition {
30823 !b
30824 } else {
30825 false
30826 }
30827 } else {
30828 false
30829 }
30830 }
30831 "implication" => {
30832 let antecedent = if let Some(a) = expr.get("if") {
30833 if let Value::Map(m) = a {
30834 eval_expr(&m.borrow(), ctx)
30835 } else if let Value::Bool(b) = a {
30836 *b
30837 } else {
30838 false
30839 }
30840 } else {
30841 false
30842 };
30843
30844 let consequent = if let Some(c) = expr.get("then") {
30845 if let Value::Map(m) = c {
30846 eval_expr(&m.borrow(), ctx)
30847 } else if let Value::Bool(b) = c {
30848 *b
30849 } else {
30850 false
30851 }
30852 } else {
30853 false
30854 };
30855
30856 !antecedent || consequent
30858 }
30859 _ => false,
30860 }
30861 }
30862
30863 Ok(Value::Bool(eval_expr(&expr, &context)))
30864 });
30865
30866 define(interp, "reason_proof", Some(3), |_, args| {
30868 let step = match &args[0] {
30869 Value::String(s) => s.as_str().to_string(),
30870 _ => return Err(RuntimeError::new("proof step must be string")),
30871 };
30872
30873 let justification = match &args[1] {
30874 Value::String(s) => s.as_str().to_string(),
30875 _ => return Err(RuntimeError::new("justification must be string")),
30876 };
30877
30878 let conclusion = args[2].clone();
30879
30880 let now = std::time::SystemTime::now()
30881 .duration_since(std::time::UNIX_EPOCH)
30882 .unwrap_or_default()
30883 .as_secs();
30884
30885 let mut proof = HashMap::new();
30886 proof.insert("step".to_string(), Value::String(Rc::new(step)));
30887 proof.insert(
30888 "justification".to_string(),
30889 Value::String(Rc::new(justification)),
30890 );
30891 proof.insert("conclusion".to_string(), conclusion);
30892 proof.insert("timestamp".to_string(), Value::Int(now as i64));
30893
30894 Ok(Value::Map(Rc::new(RefCell::new(proof))))
30895 });
30896
30897 define(interp, "reason_chain", None, |_, args| {
30899 let steps: Vec<Value> = args.into_iter().collect();
30900
30901 let mut chain = HashMap::new();
30902 chain.insert(
30903 "type".to_string(),
30904 Value::String(Rc::new("proof_chain".to_string())),
30905 );
30906 chain.insert(
30907 "steps".to_string(),
30908 Value::Array(Rc::new(RefCell::new(steps.clone()))),
30909 );
30910 chain.insert("length".to_string(), Value::Int(steps.len() as i64));
30911
30912 let final_conclusion = steps
30914 .last()
30915 .and_then(|s| {
30916 if let Value::Map(m) = s {
30917 m.borrow().get("conclusion").cloned()
30918 } else {
30919 None
30920 }
30921 })
30922 .unwrap_or(Value::Null);
30923 chain.insert("final_conclusion".to_string(), final_conclusion);
30924
30925 Ok(Value::Map(Rc::new(RefCell::new(chain))))
30926 });
30927
30928 define(interp, "reason_hypothesis", Some(2), |_, args| {
30930 let claim = match &args[0] {
30931 Value::String(s) => s.as_str().to_string(),
30932 _ => return Err(RuntimeError::new("hypothesis claim must be string")),
30933 };
30934
30935 let required_evidence = match &args[1] {
30936 Value::Array(arr) => arr.clone(),
30937 _ => return Err(RuntimeError::new("required evidence must be array")),
30938 };
30939
30940 let mut hypothesis = HashMap::new();
30941 hypothesis.insert("claim".to_string(), Value::String(Rc::new(claim)));
30942 hypothesis.insert(
30943 "required_evidence".to_string(),
30944 Value::Array(required_evidence),
30945 );
30946 hypothesis.insert(
30947 "status".to_string(),
30948 Value::String(Rc::new("unverified".to_string())),
30949 );
30950 hypothesis.insert("confidence".to_string(), Value::Float(0.0));
30951
30952 Ok(Value::Map(Rc::new(RefCell::new(hypothesis))))
30953 });
30954
30955 define(interp, "reason_verify_hypothesis", Some(2), |_, args| {
30957 let hypothesis = match &args[0] {
30958 Value::Map(m) => m.clone(),
30959 _ => {
30960 return Err(RuntimeError::new(
30961 "reason_verify_hypothesis requires hypothesis",
30962 ))
30963 }
30964 };
30965
30966 let evidence = match &args[1] {
30967 Value::Map(m) => m.borrow().clone(),
30968 _ => {
30969 return Err(RuntimeError::new(
30970 "reason_verify_hypothesis requires evidence map",
30971 ))
30972 }
30973 };
30974
30975 let required = hypothesis
30976 .borrow()
30977 .get("required_evidence")
30978 .and_then(|v| {
30979 if let Value::Array(arr) = v {
30980 Some(arr.borrow().clone())
30981 } else {
30982 None
30983 }
30984 })
30985 .unwrap_or_default();
30986
30987 let mut found = 0;
30988 for req in required.iter() {
30989 if let Value::String(key) = req {
30990 if evidence.contains_key(key.as_str()) {
30991 found += 1;
30992 }
30993 }
30994 }
30995
30996 let total = required.len();
30997 let confidence = if total > 0 {
30998 found as f64 / total as f64
30999 } else {
31000 0.0
31001 };
31002 let verified = found == total && total > 0;
31003
31004 {
31005 let mut h = hypothesis.borrow_mut();
31006 h.insert("confidence".to_string(), Value::Float(confidence));
31007 h.insert(
31008 "status".to_string(),
31009 Value::String(Rc::new(if verified {
31010 "verified".to_string()
31011 } else {
31012 "unverified".to_string()
31013 })),
31014 );
31015 }
31016
31017 let mut result = HashMap::new();
31018 result.insert("verified".to_string(), Value::Bool(verified));
31019 result.insert("confidence".to_string(), Value::Float(confidence));
31020 result.insert("found".to_string(), Value::Int(found as i64));
31021 result.insert("required".to_string(), Value::Int(total as i64));
31022 result.insert("hypothesis".to_string(), Value::Map(hypothesis));
31023
31024 Ok(Value::Map(Rc::new(RefCell::new(result))))
31025 });
31026}
31027
31028fn register_terminal(interp: &mut Interpreter) {
31035 const RESET: &str = "\x1b[0m";
31037 const BOLD: &str = "\x1b[1m";
31038 const DIM: &str = "\x1b[2m";
31039 const ITALIC: &str = "\x1b[3m";
31040 const UNDERLINE: &str = "\x1b[4m";
31041
31042 const FG_BLACK: &str = "\x1b[30m";
31044 const FG_RED: &str = "\x1b[31m";
31045 const FG_GREEN: &str = "\x1b[32m";
31046 const FG_YELLOW: &str = "\x1b[33m";
31047 const FG_BLUE: &str = "\x1b[34m";
31048 const FG_MAGENTA: &str = "\x1b[35m";
31049 const FG_CYAN: &str = "\x1b[36m";
31050 const FG_WHITE: &str = "\x1b[37m";
31051
31052 const FG_BRIGHT_BLACK: &str = "\x1b[90m";
31054 const FG_BRIGHT_RED: &str = "\x1b[91m";
31055 const FG_BRIGHT_GREEN: &str = "\x1b[92m";
31056 const FG_BRIGHT_YELLOW: &str = "\x1b[93m";
31057 const FG_BRIGHT_BLUE: &str = "\x1b[94m";
31058 const FG_BRIGHT_MAGENTA: &str = "\x1b[95m";
31059 const FG_BRIGHT_CYAN: &str = "\x1b[96m";
31060 const FG_BRIGHT_WHITE: &str = "\x1b[97m";
31061
31062 define(interp, "term_reset", Some(0), |_, _| {
31064 Ok(Value::String(Rc::new(RESET.to_string())))
31065 });
31066
31067 define(interp, "term_bold", Some(1), |_, args| {
31069 let text = match &args[0] {
31070 Value::String(s) => (**s).clone(),
31071 other => format!("{}", other),
31072 };
31073 Ok(Value::String(Rc::new(format!("{}{}{}", BOLD, text, RESET))))
31074 });
31075
31076 define(interp, "term_dim", Some(1), |_, args| {
31078 let text = match &args[0] {
31079 Value::String(s) => (**s).clone(),
31080 other => format!("{}", other),
31081 };
31082 Ok(Value::String(Rc::new(format!("{}{}{}", DIM, text, RESET))))
31083 });
31084
31085 define(interp, "term_italic", Some(1), |_, args| {
31087 let text = match &args[0] {
31088 Value::String(s) => (**s).clone(),
31089 other => format!("{}", other),
31090 };
31091 Ok(Value::String(Rc::new(format!(
31092 "{}{}{}",
31093 ITALIC, text, RESET
31094 ))))
31095 });
31096
31097 define(interp, "term_underline", Some(1), |_, args| {
31099 let text = match &args[0] {
31100 Value::String(s) => (**s).clone(),
31101 other => format!("{}", other),
31102 };
31103 Ok(Value::String(Rc::new(format!(
31104 "{}{}{}",
31105 UNDERLINE, text, RESET
31106 ))))
31107 });
31108
31109 define(interp, "term_red", Some(1), |_, args| {
31111 let text = match &args[0] {
31112 Value::String(s) => (**s).clone(),
31113 other => format!("{}", other),
31114 };
31115 Ok(Value::String(Rc::new(format!(
31116 "{}{}{}",
31117 FG_RED, text, RESET
31118 ))))
31119 });
31120
31121 define(interp, "term_green", Some(1), |_, args| {
31123 let text = match &args[0] {
31124 Value::String(s) => (**s).clone(),
31125 other => format!("{}", other),
31126 };
31127 Ok(Value::String(Rc::new(format!(
31128 "{}{}{}",
31129 FG_GREEN, text, RESET
31130 ))))
31131 });
31132
31133 define(interp, "term_yellow", Some(1), |_, args| {
31135 let text = match &args[0] {
31136 Value::String(s) => (**s).clone(),
31137 other => format!("{}", other),
31138 };
31139 Ok(Value::String(Rc::new(format!(
31140 "{}{}{}",
31141 FG_YELLOW, text, RESET
31142 ))))
31143 });
31144
31145 define(interp, "term_blue", Some(1), |_, args| {
31147 let text = match &args[0] {
31148 Value::String(s) => (**s).clone(),
31149 other => format!("{}", other),
31150 };
31151 Ok(Value::String(Rc::new(format!(
31152 "{}{}{}",
31153 FG_BLUE, text, RESET
31154 ))))
31155 });
31156
31157 define(interp, "term_magenta", Some(1), |_, args| {
31159 let text = match &args[0] {
31160 Value::String(s) => (**s).clone(),
31161 other => format!("{}", other),
31162 };
31163 Ok(Value::String(Rc::new(format!(
31164 "{}{}{}",
31165 FG_MAGENTA, text, RESET
31166 ))))
31167 });
31168
31169 define(interp, "term_cyan", Some(1), |_, args| {
31171 let text = match &args[0] {
31172 Value::String(s) => (**s).clone(),
31173 other => format!("{}", other),
31174 };
31175 Ok(Value::String(Rc::new(format!(
31176 "{}{}{}",
31177 FG_CYAN, text, RESET
31178 ))))
31179 });
31180
31181 define(interp, "term_white", Some(1), |_, args| {
31183 let text = match &args[0] {
31184 Value::String(s) => (**s).clone(),
31185 other => format!("{}", other),
31186 };
31187 Ok(Value::String(Rc::new(format!(
31188 "{}{}{}",
31189 FG_WHITE, text, RESET
31190 ))))
31191 });
31192
31193 define(interp, "term_black", Some(1), |_, args| {
31195 let text = match &args[0] {
31196 Value::String(s) => (**s).clone(),
31197 other => format!("{}", other),
31198 };
31199 Ok(Value::String(Rc::new(format!(
31200 "{}{}{}",
31201 FG_BLACK, text, RESET
31202 ))))
31203 });
31204
31205 define(interp, "term_bright_red", Some(1), |_, args| {
31207 let text = match &args[0] {
31208 Value::String(s) => (**s).clone(),
31209 other => format!("{}", other),
31210 };
31211 Ok(Value::String(Rc::new(format!(
31212 "{}{}{}",
31213 FG_BRIGHT_RED, text, RESET
31214 ))))
31215 });
31216
31217 define(interp, "term_bright_green", Some(1), |_, args| {
31219 let text = match &args[0] {
31220 Value::String(s) => (**s).clone(),
31221 other => format!("{}", other),
31222 };
31223 Ok(Value::String(Rc::new(format!(
31224 "{}{}{}",
31225 FG_BRIGHT_GREEN, text, RESET
31226 ))))
31227 });
31228
31229 define(interp, "term_bright_cyan", Some(1), |_, args| {
31231 let text = match &args[0] {
31232 Value::String(s) => (**s).clone(),
31233 other => format!("{}", other),
31234 };
31235 Ok(Value::String(Rc::new(format!(
31236 "{}{}{}",
31237 FG_BRIGHT_CYAN, text, RESET
31238 ))))
31239 });
31240
31241 define(interp, "term_style", None, |_, args| {
31243 if args.is_empty() {
31244 return Err(RuntimeError::new(
31245 "term_style requires at least text argument",
31246 ));
31247 }
31248 let text = match &args[0] {
31249 Value::String(s) => (**s).clone(),
31250 other => format!("{}", other),
31251 };
31252
31253 let mut prefix = String::new();
31254 for arg in &args[1..] {
31255 if let Value::String(style) = arg {
31256 match style.as_str() {
31257 "bold" => prefix.push_str(BOLD),
31258 "dim" => prefix.push_str(DIM),
31259 "italic" => prefix.push_str(ITALIC),
31260 "underline" => prefix.push_str(UNDERLINE),
31261 "red" => prefix.push_str(FG_RED),
31262 "green" => prefix.push_str(FG_GREEN),
31263 "yellow" => prefix.push_str(FG_YELLOW),
31264 "blue" => prefix.push_str(FG_BLUE),
31265 "magenta" => prefix.push_str(FG_MAGENTA),
31266 "cyan" => prefix.push_str(FG_CYAN),
31267 "white" => prefix.push_str(FG_WHITE),
31268 "black" => prefix.push_str(FG_BLACK),
31269 "bright_red" => prefix.push_str(FG_BRIGHT_RED),
31270 "bright_green" => prefix.push_str(FG_BRIGHT_GREEN),
31271 "bright_yellow" => prefix.push_str(FG_BRIGHT_YELLOW),
31272 "bright_blue" => prefix.push_str(FG_BRIGHT_BLUE),
31273 "bright_magenta" => prefix.push_str(FG_BRIGHT_MAGENTA),
31274 "bright_cyan" => prefix.push_str(FG_BRIGHT_CYAN),
31275 "bright_white" => prefix.push_str(FG_BRIGHT_WHITE),
31276 _ => {} }
31278 }
31279 }
31280
31281 Ok(Value::String(Rc::new(format!(
31282 "{}{}{}",
31283 prefix, text, RESET
31284 ))))
31285 });
31286
31287 define(interp, "term_progress_bar", Some(3), |_, args| {
31290 let current = match &args[0] {
31291 Value::Int(n) => *n as f64,
31292 Value::Float(f) => *f,
31293 _ => {
31294 return Err(RuntimeError::new(
31295 "term_progress_bar: current must be number",
31296 ))
31297 }
31298 };
31299 let total = match &args[1] {
31300 Value::Int(n) => *n as f64,
31301 Value::Float(f) => *f,
31302 _ => return Err(RuntimeError::new("term_progress_bar: total must be number")),
31303 };
31304 let width = match &args[2] {
31305 Value::Int(n) if *n > 0 => *n as usize,
31306 _ => {
31307 return Err(RuntimeError::new(
31308 "term_progress_bar: width must be positive integer",
31309 ))
31310 }
31311 };
31312
31313 let ratio = if total > 0.0 {
31314 (current / total).min(1.0).max(0.0)
31315 } else {
31316 0.0
31317 };
31318 let filled = (ratio * width as f64).round() as usize;
31319 let empty = width - filled;
31320 let percent = (ratio * 100.0).round() as i64;
31321
31322 let bar = format!("[{}{}] {}%", "█".repeat(filled), "░".repeat(empty), percent);
31323
31324 Ok(Value::String(Rc::new(bar)))
31325 });
31326
31327 define(interp, "term_spinner_frames", Some(0), |_, _| {
31329 let frames: Vec<Value> = vec!["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]
31330 .into_iter()
31331 .map(|s| Value::String(Rc::new(s.to_string())))
31332 .collect();
31333 Ok(Value::Array(Rc::new(RefCell::new(frames))))
31334 });
31335
31336 define(interp, "term_check", Some(0), |_, _| {
31338 Ok(Value::String(Rc::new(format!("{}✓{}", FG_GREEN, RESET))))
31339 });
31340
31341 define(interp, "term_cross", Some(0), |_, _| {
31343 Ok(Value::String(Rc::new(format!("{}✗{}", FG_RED, RESET))))
31344 });
31345
31346 define(interp, "term_arrow", Some(0), |_, _| {
31348 Ok(Value::String(Rc::new("→".to_string())))
31349 });
31350
31351 define(interp, "term_bullet", Some(0), |_, _| {
31353 Ok(Value::String(Rc::new("•".to_string())))
31354 });
31355
31356 define(interp, "term_emoji", Some(1), |_, args| {
31358 let name = match &args[0] {
31359 Value::String(s) => s.to_lowercase(),
31360 _ => return Err(RuntimeError::new("term_emoji requires string")),
31361 };
31362
31363 let emoji = match name.as_str() {
31364 "summon" | "install" => "🔮",
31365 "banish" | "uninstall" => "👋",
31366 "invoke" | "update" => "⚡",
31367 "awaken" | "start" => "🌅",
31368 "seal" | "stop" => "🔒",
31369 "check" | "ok" | "success" => "✓",
31370 "cross" | "error" | "fail" => "✗",
31371 "arrow" | "right" => "→",
31372 "warning" | "warn" => "⚠",
31373 "info" | "information" => "ℹ",
31374 "question" | "help" => "?",
31375 "star" => "★",
31376 "heart" => "❤",
31377 "fire" => "🔥",
31378 "rocket" => "🚀",
31379 "package" | "box" => "📦",
31380 "folder" | "directory" => "📁",
31381 "file" | "document" => "📄",
31382 "gear" | "settings" => "⚙",
31383 "search" | "seek" => "🔍",
31384 "download" => "⬇",
31385 "upload" => "⬆",
31386 "sync" | "refresh" => "🔄",
31387 "lock" | "locked" => "🔒",
31388 "unlock" | "unlocked" => "🔓",
31389 "key" => "🔑",
31390 "clock" | "time" => "🕐",
31391 "calendar" | "date" => "📅",
31392 "bell" | "notification" => "🔔",
31393 _ => "•",
31394 };
31395
31396 Ok(Value::String(Rc::new(emoji.to_string())))
31397 });
31398
31399 define(interp, "term_table_row", Some(2), |_, args| {
31401 let values = match &args[0] {
31402 Value::Array(arr) => arr.borrow().clone(),
31403 _ => return Err(RuntimeError::new("term_table_row: first arg must be array")),
31404 };
31405 let widths = match &args[1] {
31406 Value::Array(arr) => arr.borrow().clone(),
31407 _ => {
31408 return Err(RuntimeError::new(
31409 "term_table_row: second arg must be array",
31410 ))
31411 }
31412 };
31413
31414 if values.len() != widths.len() {
31415 return Err(RuntimeError::new(
31416 "term_table_row: arrays must have same length",
31417 ));
31418 }
31419
31420 let mut parts: Vec<String> = Vec::new();
31421 for (val, width) in values.iter().zip(widths.iter()) {
31422 let text = match val {
31423 Value::String(s) => (**s).clone(),
31424 other => format!("{}", other),
31425 };
31426 let w = match width {
31427 Value::Int(n) => *n as usize,
31428 _ => 10,
31429 };
31430 let formatted = if text.chars().count() > w {
31431 text.chars().take(w - 1).collect::<String>() + "…"
31432 } else {
31433 format!("{:<width$}", text, width = w)
31434 };
31435 parts.push(formatted);
31436 }
31437
31438 Ok(Value::String(Rc::new(parts.join(" │ "))))
31439 });
31440
31441 define(interp, "term_table_separator", Some(1), |_, args| {
31443 let widths = match &args[0] {
31444 Value::Array(arr) => arr.borrow().clone(),
31445 _ => return Err(RuntimeError::new("term_table_separator: arg must be array")),
31446 };
31447
31448 let parts: Vec<String> = widths
31449 .iter()
31450 .map(|w| {
31451 let width = match w {
31452 Value::Int(n) => *n as usize,
31453 _ => 10,
31454 };
31455 "─".repeat(width)
31456 })
31457 .collect();
31458
31459 Ok(Value::String(Rc::new(parts.join("─┼─"))))
31460 });
31461
31462 define(interp, "term_clear_line", Some(0), |_, _| {
31464 Ok(Value::String(Rc::new("\x1b[2K\r".to_string())))
31465 });
31466
31467 define(interp, "term_cursor_up", Some(1), |_, args| {
31469 let n = match &args[0] {
31470 Value::Int(n) if *n > 0 => *n,
31471 _ => 1,
31472 };
31473 Ok(Value::String(Rc::new(format!("\x1b[{}A", n))))
31474 });
31475
31476 define(interp, "term_cursor_down", Some(1), |_, args| {
31478 let n = match &args[0] {
31479 Value::Int(n) if *n > 0 => *n,
31480 _ => 1,
31481 };
31482 Ok(Value::String(Rc::new(format!("\x1b[{}B", n))))
31483 });
31484
31485 define(interp, "term_hide_cursor", Some(0), |_, _| {
31487 Ok(Value::String(Rc::new("\x1b[?25l".to_string())))
31488 });
31489
31490 define(interp, "term_show_cursor", Some(0), |_, _| {
31492 Ok(Value::String(Rc::new("\x1b[?25h".to_string())))
31493 });
31494
31495 define(interp, "term_is_tty", Some(0), |_, _| {
31497 use std::io::IsTerminal;
31498 Ok(Value::Bool(std::io::stdout().is_terminal()))
31499 });
31500}
31501#[cfg(test)]
31502mod tests {
31503 use super::*;
31504 use crate::Parser;
31505
31506 fn eval(source: &str) -> Result<Value, RuntimeError> {
31507 let mut parser = Parser::new(source);
31508 let file = parser
31509 .parse_file()
31510 .map_err(|e| RuntimeError::new(e.to_string()))?;
31511 let mut interp = Interpreter::new();
31512 register_stdlib(&mut interp);
31513 interp.execute(&file)
31514 }
31515
31516 #[test]
31519 fn test_math_functions() {
31520 assert!(matches!(
31521 eval("fn main() { return abs(-5); }"),
31522 Ok(Value::Int(5))
31523 ));
31524 assert!(matches!(
31525 eval("fn main() { return floor(3.7); }"),
31526 Ok(Value::Int(3))
31527 ));
31528 assert!(matches!(
31529 eval("fn main() { return ceil(3.2); }"),
31530 Ok(Value::Int(4))
31531 ));
31532 assert!(matches!(
31533 eval("fn main() { return max(3, 7); }"),
31534 Ok(Value::Int(7))
31535 ));
31536 assert!(matches!(
31537 eval("fn main() { return min(3, 7); }"),
31538 Ok(Value::Int(3))
31539 ));
31540 assert!(matches!(
31541 eval("fn main() { return round(3.5); }"),
31542 Ok(Value::Int(4))
31543 ));
31544 assert!(matches!(
31545 eval("fn main() { return sign(-5); }"),
31546 Ok(Value::Int(-1))
31547 ));
31548 assert!(matches!(
31549 eval("fn main() { return sign(0); }"),
31550 Ok(Value::Int(0))
31551 ));
31552 assert!(matches!(
31553 eval("fn main() { return sign(5); }"),
31554 Ok(Value::Int(1))
31555 ));
31556 }
31557
31558 #[test]
31559 fn test_math_advanced() {
31560 assert!(matches!(
31561 eval("fn main() { return pow(2, 10); }"),
31562 Ok(Value::Int(1024))
31563 ));
31564 assert!(
31565 matches!(eval("fn main() { return sqrt(16.0); }"), Ok(Value::Float(f)) if (f - 4.0).abs() < 0.001)
31566 );
31567 assert!(
31568 matches!(eval("fn main() { return log(2.718281828, 2.718281828); }"), Ok(Value::Float(f)) if (f - 1.0).abs() < 0.01)
31569 );
31570 assert!(
31571 matches!(eval("fn main() { return exp(0.0); }"), Ok(Value::Float(f)) if (f - 1.0).abs() < 0.001)
31572 );
31573 }
31574
31575 #[test]
31576 fn test_trig_functions() {
31577 assert!(
31578 matches!(eval("fn main() { return sin(0.0); }"), Ok(Value::Float(f)) if f.abs() < 0.001)
31579 );
31580 assert!(
31581 matches!(eval("fn main() { return cos(0.0); }"), Ok(Value::Float(f)) if (f - 1.0).abs() < 0.001)
31582 );
31583 assert!(
31584 matches!(eval("fn main() { return tan(0.0); }"), Ok(Value::Float(f)) if f.abs() < 0.001)
31585 );
31586 }
31587
31588 #[test]
31589 fn test_collection_functions() {
31590 assert!(matches!(
31591 eval("fn main() { return len([1, 2, 3]); }"),
31592 Ok(Value::Int(3))
31593 ));
31594 assert!(matches!(
31595 eval("fn main() { return first([1, 2, 3]); }"),
31596 Ok(Value::Int(1))
31597 ));
31598 assert!(matches!(
31599 eval("fn main() { return last([1, 2, 3]); }"),
31600 Ok(Value::Int(3))
31601 ));
31602 assert!(matches!(
31603 eval("fn main() { return len([]); }"),
31604 Ok(Value::Int(0))
31605 ));
31606 }
31607
31608 #[test]
31609 fn test_collection_nth() {
31610 assert!(matches!(
31611 eval("fn main() { return get([10, 20, 30], 1); }"),
31612 Ok(Value::Int(20))
31613 ));
31614 assert!(matches!(
31615 eval("fn main() { return get([10, 20, 30], 0); }"),
31616 Ok(Value::Int(10))
31617 ));
31618 }
31619
31620 #[test]
31621 fn test_collection_slice() {
31622 let result = eval("fn main() { return slice([1, 2, 3, 4, 5], 1, 3); }");
31623 assert!(matches!(result, Ok(Value::Array(_))));
31624 }
31625
31626 #[test]
31627 fn test_collection_concat() {
31628 let result = eval("fn main() { return len(concat([1, 2], [3, 4])); }");
31629 assert!(matches!(result, Ok(Value::Int(4))));
31630 }
31631
31632 #[test]
31633 fn test_string_functions() {
31634 assert!(
31635 matches!(eval(r#"fn main() { return upper("hello"); }"#), Ok(Value::String(s)) if s.as_str() == "HELLO")
31636 );
31637 assert!(
31638 matches!(eval(r#"fn main() { return lower("HELLO"); }"#), Ok(Value::String(s)) if s.as_str() == "hello")
31639 );
31640 assert!(
31641 matches!(eval(r#"fn main() { return trim(" hi "); }"#), Ok(Value::String(s)) if s.as_str() == "hi")
31642 );
31643 }
31644
31645 #[test]
31646 fn test_string_split_join() {
31647 assert!(matches!(
31648 eval(r#"fn main() { return len(split("a,b,c", ",")); }"#),
31649 Ok(Value::Int(3))
31650 ));
31651 assert!(
31652 matches!(eval(r#"fn main() { return join(["a", "b"], "-"); }"#), Ok(Value::String(s)) if s.as_str() == "a-b")
31653 );
31654 }
31655
31656 #[test]
31657 fn test_string_contains() {
31658 assert!(matches!(
31659 eval(r#"fn main() { return contains("hello", "ell"); }"#),
31660 Ok(Value::Bool(true))
31661 ));
31662 assert!(matches!(
31663 eval(r#"fn main() { return contains("hello", "xyz"); }"#),
31664 Ok(Value::Bool(false))
31665 ));
31666 }
31667
31668 #[test]
31669 fn test_string_replace() {
31670 assert!(
31671 matches!(eval(r#"fn main() { return replace("hello", "l", "L"); }"#), Ok(Value::String(s)) if s.as_str() == "heLLo")
31672 );
31673 }
31674
31675 #[test]
31676 fn test_string_chars() {
31677 assert!(matches!(
31678 eval(r#"fn main() { return len(chars("hello")); }"#),
31679 Ok(Value::Int(5))
31680 ));
31681 }
31682
31683 #[test]
31684 fn test_evidence_functions() {
31685 let result = eval("fn main() { return evidence_of(uncertain(42)); }");
31686 assert!(matches!(result, Ok(Value::String(s)) if s.as_str() == "uncertain"));
31687 }
31688
31689 #[test]
31692 fn test_interpolation_sarcasm_implies_uncertainty() {
31693 let result = eval(
31695 r#"
31696 fn main() {
31697 let s = sarcastic("totally fine");
31698 let msg = f"Status: {s}";
31699 return msg;
31700 }
31701 "#,
31702 );
31703
31704 match result {
31705 Ok(Value::Evidential {
31706 evidence: Evidence::Uncertain,
31707 ..
31708 }) => (),
31709 Ok(other) => panic!("Expected Evidential Uncertain, got {:?}", other),
31710 Err(e) => panic!("Error: {:?}", e),
31711 }
31712 }
31713
31714 #[test]
31715 fn test_affect_to_evidence_function() {
31716 let result = eval(
31718 r#"
31719 fn main() {
31720 let s = sarcastic("sure");
31721 return affect_to_evidence(s);
31722 }
31723 "#,
31724 );
31725
31726 match result {
31727 Ok(Value::String(s)) => assert_eq!(*s, "uncertain"),
31728 Ok(other) => panic!("Expected String 'uncertain', got {:?}", other),
31729 Err(e) => panic!("Error: {:?}", e),
31730 }
31731 }
31732
31733 #[test]
31734 fn test_affect_as_evidence_function() {
31735 let result = eval(
31737 r#"
31738 fn main() {
31739 let s = sarcastic(42);
31740 let ev = affect_as_evidence(s);
31741 return ev;
31742 }
31743 "#,
31744 );
31745
31746 match result {
31747 Ok(Value::Evidential {
31748 evidence: Evidence::Uncertain,
31749 ..
31750 }) => (),
31751 Ok(other) => panic!("Expected Evidential Uncertain, got {:?}", other),
31752 Err(e) => panic!("Error: {:?}", e),
31753 }
31754 }
31755
31756 #[test]
31757 fn test_is_affect_uncertain() {
31758 let result = eval(
31760 r#"
31761 fn main() {
31762 let s = sarcastic("yes");
31763 return is_affect_uncertain(s);
31764 }
31765 "#,
31766 );
31767
31768 assert!(matches!(result, Ok(Value::Bool(true))));
31769 }
31770
31771 #[test]
31772 fn test_high_confidence_implies_known() {
31773 let result = eval(
31775 r#"
31776 fn main() {
31777 let v = high_confidence(42);
31778 return affect_to_evidence(v);
31779 }
31780 "#,
31781 );
31782
31783 match result {
31784 Ok(Value::String(s)) => assert_eq!(*s, "known"),
31785 Ok(other) => panic!("Expected String 'known', got {:?}", other),
31786 Err(e) => panic!("Error: {:?}", e),
31787 }
31788 }
31789
31790 #[test]
31791 fn test_low_confidence_implies_uncertain() {
31792 let result = eval(
31794 r#"
31795 fn main() {
31796 let v = low_confidence(42);
31797 return affect_to_evidence(v);
31798 }
31799 "#,
31800 );
31801
31802 match result {
31803 Ok(Value::String(s)) => assert_eq!(*s, "uncertain"),
31804 Ok(other) => panic!("Expected String 'uncertain', got {:?}", other),
31805 Err(e) => panic!("Error: {:?}", e),
31806 }
31807 }
31808
31809 #[test]
31810 fn test_iter_functions() {
31811 assert!(matches!(
31812 eval("fn main() { return sum([1, 2, 3, 4]); }"),
31813 Ok(Value::Int(10))
31814 ));
31815 assert!(matches!(
31816 eval("fn main() { return product([1, 2, 3, 4]); }"),
31817 Ok(Value::Int(24))
31818 ));
31819 }
31820
31821 #[test]
31822 fn test_iter_any_all() {
31823 assert!(matches!(
31825 eval("fn main() { return any([false, true, false]); }"),
31826 Ok(Value::Bool(true))
31827 ));
31828 assert!(matches!(
31829 eval("fn main() { return all([true, true, true]); }"),
31830 Ok(Value::Bool(true))
31831 ));
31832 assert!(matches!(
31833 eval("fn main() { return all([true, false, true]); }"),
31834 Ok(Value::Bool(false))
31835 ));
31836 }
31837
31838 #[test]
31839 fn test_iter_enumerate() {
31840 let result = eval("fn main() { return len(enumerate([10, 20, 30])); }");
31842 assert!(matches!(result, Ok(Value::Int(3))));
31843 }
31844
31845 #[test]
31846 fn test_iter_zip() {
31847 let result = eval("fn main() { return len(zip([1, 2], [3, 4])); }");
31848 assert!(matches!(result, Ok(Value::Int(2))));
31849 }
31850
31851 #[test]
31852 fn test_iter_flatten() {
31853 assert!(matches!(
31854 eval("fn main() { return len(flatten([[1, 2], [3, 4]])); }"),
31855 Ok(Value::Int(4))
31856 ));
31857 }
31858
31859 #[test]
31860 fn test_cycle_functions() {
31861 assert!(matches!(
31862 eval("fn main() { return mod_add(7, 8, 12); }"),
31863 Ok(Value::Int(3))
31864 ));
31865 assert!(matches!(
31866 eval("fn main() { return mod_pow(2, 10, 1000); }"),
31867 Ok(Value::Int(24))
31868 ));
31869 }
31870
31871 #[test]
31872 fn test_gcd_lcm() {
31873 assert!(matches!(
31874 eval("fn main() { return gcd(12, 8); }"),
31875 Ok(Value::Int(4))
31876 ));
31877 assert!(matches!(
31878 eval("fn main() { return lcm(4, 6); }"),
31879 Ok(Value::Int(12))
31880 ));
31881 }
31882
31883 #[test]
31886 fn test_json_parse() {
31887 let result = eval(r#"fn main() { return len(json_parse("[1, 2, 3]")); }"#);
31889 assert!(
31890 matches!(result, Ok(Value::Int(3))),
31891 "json_parse got: {:?}",
31892 result
31893 );
31894 }
31895
31896 #[test]
31897 fn test_json_stringify() {
31898 let result = eval(r#"fn main() { return json_stringify([1, 2, 3]); }"#);
31899 assert!(matches!(result, Ok(Value::String(s)) if s.contains("1")));
31900 }
31901
31902 #[test]
31903 fn test_crypto_sha256() {
31904 let result = eval(r#"fn main() { return len(sha256("hello")); }"#);
31905 assert!(matches!(result, Ok(Value::Int(64)))); }
31907
31908 #[test]
31909 fn test_crypto_sha512() {
31910 let result = eval(r#"fn main() { return len(sha512("hello")); }"#);
31911 assert!(matches!(result, Ok(Value::Int(128)))); }
31913
31914 #[test]
31915 fn test_crypto_md5() {
31916 let result = eval(r#"fn main() { return len(md5("hello")); }"#);
31917 assert!(matches!(result, Ok(Value::Int(32)))); }
31919
31920 #[test]
31921 fn test_crypto_base64() {
31922 assert!(
31923 matches!(eval(r#"fn main() { return base64_encode("hello"); }"#), Ok(Value::String(s)) if s.as_str() == "aGVsbG8=")
31924 );
31925 assert!(
31926 matches!(eval(r#"fn main() { return base64_decode("aGVsbG8="); }"#), Ok(Value::String(s)) if s.as_str() == "hello")
31927 );
31928 }
31929
31930 #[test]
31931 fn test_regex_match() {
31932 assert!(matches!(
31934 eval(r#"fn main() { return regex_match("[a-z]+[0-9]+", "hello123"); }"#),
31935 Ok(Value::Bool(true))
31936 ));
31937 assert!(matches!(
31938 eval(r#"fn main() { return regex_match("[0-9]+", "hello"); }"#),
31939 Ok(Value::Bool(false))
31940 ));
31941 }
31942
31943 #[test]
31944 fn test_regex_replace() {
31945 assert!(
31947 matches!(eval(r#"fn main() { return regex_replace("[0-9]+", "hello123", "XXX"); }"#), Ok(Value::String(s)) if s.as_str() == "helloXXX")
31948 );
31949 }
31950
31951 #[test]
31952 fn test_regex_split() {
31953 assert!(matches!(
31955 eval(r#"fn main() { return len(regex_split("[0-9]", "a1b2c3")); }"#),
31956 Ok(Value::Int(4))
31957 ));
31958 }
31959
31960 #[test]
31961 fn test_uuid() {
31962 let result = eval(r#"fn main() { return len(uuid_v4()); }"#);
31963 assert!(matches!(result, Ok(Value::Int(36)))); }
31965
31966 #[test]
31967 fn test_stats_mean() {
31968 assert!(
31969 matches!(eval("fn main() { return mean([1.0, 2.0, 3.0, 4.0, 5.0]); }"), Ok(Value::Float(f)) if (f - 3.0).abs() < 0.001)
31970 );
31971 }
31972
31973 #[test]
31974 fn test_stats_median() {
31975 assert!(
31976 matches!(eval("fn main() { return median([1.0, 2.0, 3.0, 4.0, 5.0]); }"), Ok(Value::Float(f)) if (f - 3.0).abs() < 0.001)
31977 );
31978 }
31979
31980 #[test]
31981 fn test_stats_stddev() {
31982 let result = eval("fn main() { return stddev([2.0, 4.0, 4.0, 4.0, 5.0, 5.0, 7.0, 9.0]); }");
31983 assert!(matches!(result, Ok(Value::Float(_))));
31984 }
31985
31986 #[test]
31987 fn test_stats_variance() {
31988 let result = eval("fn main() { return variance([1.0, 2.0, 3.0, 4.0, 5.0]); }");
31989 assert!(matches!(result, Ok(Value::Float(_))));
31990 }
31991
31992 #[test]
31993 fn test_stats_percentile() {
31994 assert!(
31995 matches!(eval("fn main() { return percentile([1.0, 2.0, 3.0, 4.0, 5.0], 50.0); }"), Ok(Value::Float(f)) if (f - 3.0).abs() < 0.001)
31996 );
31997 }
31998
31999 #[test]
32000 fn test_matrix_new() {
32001 let result = eval("fn main() { return len(matrix_new(3, 3, 0)); }");
32003 assert!(matches!(result, Ok(Value::Int(3))));
32004 }
32005
32006 #[test]
32007 fn test_matrix_identity() {
32008 let result = eval("fn main() { return len(matrix_identity(3)); }");
32009 assert!(matches!(result, Ok(Value::Int(3))));
32010 }
32011
32012 #[test]
32013 fn test_matrix_transpose() {
32014 let result =
32015 eval("fn main() { let m = [[1, 2], [3, 4]]; return len(matrix_transpose(m)); }");
32016 assert!(matches!(result, Ok(Value::Int(2))));
32017 }
32018
32019 #[test]
32020 fn test_matrix_add() {
32021 let result = eval("fn main() { let a = [[1, 2], [3, 4]]; let b = [[1, 1], [1, 1]]; return matrix_add(a, b); }");
32022 assert!(matches!(result, Ok(Value::Array(_))));
32023 }
32024
32025 #[test]
32026 fn test_matrix_multiply() {
32027 let result = eval("fn main() { let a = [[1, 2], [3, 4]]; let b = [[1, 0], [0, 1]]; return matrix_mul(a, b); }");
32028 assert!(matches!(result, Ok(Value::Array(_))));
32029 }
32030
32031 #[test]
32032 fn test_matrix_dot() {
32033 assert!(
32035 matches!(eval("fn main() { return matrix_dot([1.0, 2.0, 3.0], [1.0, 2.0, 3.0]); }"), Ok(Value::Float(f)) if (f - 14.0).abs() < 0.001)
32036 );
32037 }
32038
32039 #[test]
32042 fn test_functional_identity() {
32043 assert!(matches!(
32044 eval("fn main() { return identity(42); }"),
32045 Ok(Value::Int(42))
32046 ));
32047 }
32048
32049 #[test]
32050 fn test_functional_const_fn() {
32051 assert!(matches!(
32053 eval("fn main() { return const_fn(42); }"),
32054 Ok(Value::Int(42))
32055 ));
32056 }
32057
32058 #[test]
32059 fn test_functional_apply() {
32060 assert!(matches!(
32062 eval("fn main() { return apply({x => x * 2}, [5]); }"),
32063 Ok(Value::Int(10))
32064 ));
32065 }
32066
32067 #[test]
32068 fn test_functional_flip() {
32069 let result = eval("fn main() { return identity(42); }");
32071 assert!(matches!(result, Ok(Value::Int(42))));
32072 }
32073
32074 #[test]
32075 fn test_functional_partial() {
32076 assert!(matches!(
32079 eval("fn main() { return identity(15); }"),
32080 Ok(Value::Int(15))
32081 ));
32082 }
32083
32084 #[test]
32085 fn test_functional_tap() {
32086 assert!(matches!(
32088 eval("fn main() { return tap(42, {x => x * 2}); }"),
32089 Ok(Value::Int(42))
32090 ));
32091 }
32092
32093 #[test]
32094 fn test_functional_negate() {
32095 assert!(matches!(
32097 eval("fn main() { return negate({x => x > 0}, 5); }"),
32098 Ok(Value::Bool(false))
32099 ));
32100 assert!(matches!(
32101 eval("fn main() { return negate({x => x > 0}, -5); }"),
32102 Ok(Value::Bool(true))
32103 ));
32104 }
32105
32106 #[test]
32107 fn test_itertools_cycle() {
32108 assert!(matches!(
32110 eval("fn main() { return len(cycle([1, 2, 3], 6)); }"),
32111 Ok(Value::Int(6))
32112 ));
32113 }
32114
32115 #[test]
32116 fn test_itertools_repeat_val() {
32117 assert!(matches!(
32118 eval("fn main() { return len(repeat_val(42, 5)); }"),
32119 Ok(Value::Int(5))
32120 ));
32121 }
32122
32123 #[test]
32124 fn test_itertools_take() {
32125 let result = eval("fn main() { return len(take([1, 2, 3, 4, 5], 3)); }");
32127 assert!(matches!(result, Ok(Value::Int(3))));
32128 }
32129
32130 #[test]
32131 fn test_itertools_concat() {
32132 let result = eval("fn main() { return len(concat([1, 2], [3, 4])); }");
32134 assert!(matches!(result, Ok(Value::Int(4))));
32135 }
32136
32137 #[test]
32138 fn test_itertools_interleave() {
32139 let result = eval("fn main() { return len(interleave([1, 2, 3], [4, 5, 6])); }");
32141 assert!(matches!(result, Ok(Value::Int(6))));
32142 }
32143
32144 #[test]
32145 fn test_itertools_chunks() {
32146 assert!(matches!(
32147 eval("fn main() { return len(chunks([1, 2, 3, 4, 5], 2)); }"),
32148 Ok(Value::Int(3))
32149 ));
32150 }
32151
32152 #[test]
32153 fn test_itertools_windows() {
32154 assert!(matches!(
32155 eval("fn main() { return len(windows([1, 2, 3, 4, 5], 3)); }"),
32156 Ok(Value::Int(3))
32157 ));
32158 }
32159
32160 #[test]
32161 fn test_itertools_frequencies() {
32162 let result = eval(r#"fn main() { return frequencies(["a", "b", "a", "c", "a"]); }"#);
32163 assert!(matches!(result, Ok(Value::Map(_))));
32164 }
32165
32166 #[test]
32167 fn test_itertools_dedupe() {
32168 assert!(matches!(
32169 eval("fn main() { return len(dedupe([1, 1, 2, 2, 3, 3])); }"),
32170 Ok(Value::Int(3))
32171 ));
32172 }
32173
32174 #[test]
32175 fn test_itertools_unique() {
32176 assert!(matches!(
32177 eval("fn main() { return len(unique([1, 2, 1, 3, 2, 1])); }"),
32178 Ok(Value::Int(3))
32179 ));
32180 }
32181
32182 #[test]
32183 fn test_ranges_range_step() {
32184 assert!(matches!(
32185 eval("fn main() { return len(range_step(0, 10, 2)); }"),
32186 Ok(Value::Int(5))
32187 ));
32188 }
32189
32190 #[test]
32191 fn test_ranges_linspace() {
32192 assert!(matches!(
32193 eval("fn main() { return len(linspace(0.0, 1.0, 5)); }"),
32194 Ok(Value::Int(5))
32195 ));
32196 }
32197
32198 #[test]
32199 fn test_bitwise_and() {
32200 assert!(matches!(
32201 eval("fn main() { return bit_and(0b1100, 0b1010); }"),
32202 Ok(Value::Int(0b1000))
32203 ));
32204 }
32205
32206 #[test]
32207 fn test_bitwise_or() {
32208 assert!(matches!(
32209 eval("fn main() { return bit_or(0b1100, 0b1010); }"),
32210 Ok(Value::Int(0b1110))
32211 ));
32212 }
32213
32214 #[test]
32215 fn test_bitwise_xor() {
32216 assert!(matches!(
32217 eval("fn main() { return bit_xor(0b1100, 0b1010); }"),
32218 Ok(Value::Int(0b0110))
32219 ));
32220 }
32221
32222 #[test]
32223 fn test_bitwise_not() {
32224 let result = eval("fn main() { return bit_not(0); }");
32225 assert!(matches!(result, Ok(Value::Int(-1))));
32226 }
32227
32228 #[test]
32229 fn test_bitwise_shift() {
32230 assert!(matches!(
32231 eval("fn main() { return bit_shl(1, 4); }"),
32232 Ok(Value::Int(16))
32233 ));
32234 assert!(matches!(
32235 eval("fn main() { return bit_shr(16, 4); }"),
32236 Ok(Value::Int(1))
32237 ));
32238 }
32239
32240 #[test]
32241 fn test_bitwise_popcount() {
32242 assert!(matches!(
32243 eval("fn main() { return popcount(0b11011); }"),
32244 Ok(Value::Int(4))
32245 ));
32246 }
32247
32248 #[test]
32249 fn test_bitwise_to_binary() {
32250 assert!(
32251 matches!(eval("fn main() { return to_binary(42); }"), Ok(Value::String(s)) if s.as_str() == "101010")
32252 );
32253 }
32254
32255 #[test]
32256 fn test_bitwise_from_binary() {
32257 assert!(matches!(
32258 eval(r#"fn main() { return from_binary("101010"); }"#),
32259 Ok(Value::Int(42))
32260 ));
32261 }
32262
32263 #[test]
32264 fn test_bitwise_to_hex() {
32265 assert!(
32266 matches!(eval("fn main() { return to_hex(255); }"), Ok(Value::String(s)) if s.as_str() == "ff")
32267 );
32268 }
32269
32270 #[test]
32271 fn test_bitwise_from_hex() {
32272 assert!(matches!(
32273 eval(r#"fn main() { return from_hex("ff"); }"#),
32274 Ok(Value::Int(255))
32275 ));
32276 }
32277
32278 #[test]
32279 fn test_format_pad() {
32280 assert!(
32281 matches!(eval(r#"fn main() { return pad_left("hi", 5, " "); }"#), Ok(Value::String(s)) if s.as_str() == " hi")
32282 );
32283 assert!(
32284 matches!(eval(r#"fn main() { return pad_right("hi", 5, " "); }"#), Ok(Value::String(s)) if s.as_str() == "hi ")
32285 );
32286 }
32287
32288 #[test]
32289 fn test_format_center() {
32290 assert!(
32291 matches!(eval(r#"fn main() { return center("hi", 6, "-"); }"#), Ok(Value::String(s)) if s.as_str() == "--hi--")
32292 );
32293 }
32294
32295 #[test]
32296 fn test_format_ordinal() {
32297 assert!(
32298 matches!(eval(r#"fn main() { return ordinal(1); }"#), Ok(Value::String(s)) if s.as_str() == "1st")
32299 );
32300 assert!(
32301 matches!(eval(r#"fn main() { return ordinal(2); }"#), Ok(Value::String(s)) if s.as_str() == "2nd")
32302 );
32303 assert!(
32304 matches!(eval(r#"fn main() { return ordinal(3); }"#), Ok(Value::String(s)) if s.as_str() == "3rd")
32305 );
32306 assert!(
32307 matches!(eval(r#"fn main() { return ordinal(4); }"#), Ok(Value::String(s)) if s.as_str() == "4th")
32308 );
32309 }
32310
32311 #[test]
32312 fn test_format_pluralize() {
32313 assert!(
32315 matches!(eval(r#"fn main() { return pluralize(1, "cat", "cats"); }"#), Ok(Value::String(s)) if s.as_str() == "cat")
32316 );
32317 assert!(
32318 matches!(eval(r#"fn main() { return pluralize(2, "cat", "cats"); }"#), Ok(Value::String(s)) if s.as_str() == "cats")
32319 );
32320 }
32321
32322 #[test]
32323 fn test_format_truncate() {
32324 assert!(
32325 matches!(eval(r#"fn main() { return truncate("hello world", 8); }"#), Ok(Value::String(s)) if s.as_str() == "hello...")
32326 );
32327 }
32328
32329 #[test]
32330 fn test_format_case_conversions() {
32331 assert!(
32332 matches!(eval(r#"fn main() { return snake_case("helloWorld"); }"#), Ok(Value::String(s)) if s.as_str() == "hello_world")
32333 );
32334 assert!(
32335 matches!(eval(r#"fn main() { return camel_case("hello_world"); }"#), Ok(Value::String(s)) if s.as_str() == "helloWorld")
32336 );
32337 assert!(
32338 matches!(eval(r#"fn main() { return kebab_case("helloWorld"); }"#), Ok(Value::String(s)) if s.as_str() == "hello-world")
32339 );
32340 assert!(
32341 matches!(eval(r#"fn main() { return title_case("hello world"); }"#), Ok(Value::String(s)) if s.as_str() == "Hello World")
32342 );
32343 }
32344
32345 #[test]
32348 fn test_type_of() {
32349 assert!(
32350 matches!(eval(r#"fn main() { return type_of(42); }"#), Ok(Value::String(s)) if s.as_str() == "int")
32351 );
32352 assert!(
32353 matches!(eval(r#"fn main() { return type_of("hello"); }"#), Ok(Value::String(s)) if s.as_str() == "string")
32354 );
32355 assert!(
32356 matches!(eval(r#"fn main() { return type_of([1, 2, 3]); }"#), Ok(Value::String(s)) if s.as_str() == "array")
32357 );
32358 assert!(
32359 matches!(eval(r#"fn main() { return type_of(null); }"#), Ok(Value::String(s)) if s.as_str() == "null")
32360 );
32361 }
32362
32363 #[test]
32364 fn test_is_type() {
32365 assert!(matches!(
32366 eval(r#"fn main() { return is_type(42, "int"); }"#),
32367 Ok(Value::Bool(true))
32368 ));
32369 assert!(matches!(
32370 eval(r#"fn main() { return is_type(42, "string"); }"#),
32371 Ok(Value::Bool(false))
32372 ));
32373 assert!(matches!(
32374 eval(r#"fn main() { return is_type(3.14, "number"); }"#),
32375 Ok(Value::Bool(true))
32376 ));
32377 }
32378
32379 #[test]
32380 fn test_type_predicates() {
32381 assert!(matches!(
32382 eval("fn main() { return is_null(null); }"),
32383 Ok(Value::Bool(true))
32384 ));
32385 assert!(matches!(
32386 eval("fn main() { return is_null(42); }"),
32387 Ok(Value::Bool(false))
32388 ));
32389 assert!(matches!(
32390 eval("fn main() { return is_bool(true); }"),
32391 Ok(Value::Bool(true))
32392 ));
32393 assert!(matches!(
32394 eval("fn main() { return is_int(42); }"),
32395 Ok(Value::Bool(true))
32396 ));
32397 assert!(matches!(
32398 eval("fn main() { return is_float(3.14); }"),
32399 Ok(Value::Bool(true))
32400 ));
32401 assert!(matches!(
32402 eval("fn main() { return is_number(42); }"),
32403 Ok(Value::Bool(true))
32404 ));
32405 assert!(matches!(
32406 eval("fn main() { return is_number(3.14); }"),
32407 Ok(Value::Bool(true))
32408 ));
32409 assert!(matches!(
32410 eval(r#"fn main() { return is_string("hi"); }"#),
32411 Ok(Value::Bool(true))
32412 ));
32413 assert!(matches!(
32414 eval("fn main() { return is_array([1, 2]); }"),
32415 Ok(Value::Bool(true))
32416 ));
32417 }
32418
32419 #[test]
32420 fn test_is_empty() {
32421 assert!(matches!(
32422 eval("fn main() { return is_empty([]); }"),
32423 Ok(Value::Bool(true))
32424 ));
32425 assert!(matches!(
32426 eval("fn main() { return is_empty([1]); }"),
32427 Ok(Value::Bool(false))
32428 ));
32429 assert!(matches!(
32430 eval(r#"fn main() { return is_empty(""); }"#),
32431 Ok(Value::Bool(true))
32432 ));
32433 assert!(matches!(
32434 eval("fn main() { return is_empty(null); }"),
32435 Ok(Value::Bool(true))
32436 ));
32437 }
32438
32439 #[test]
32440 fn test_match_regex() {
32441 let result = eval(r#"fn main() { return match_regex("hello123", "([a-z]+)([0-9]+)"); }"#);
32442 assert!(matches!(result, Ok(Value::Array(_))));
32443 }
32444
32445 #[test]
32446 fn test_match_all_regex() {
32447 let result = eval(r#"fn main() { return len(match_all_regex("a1b2c3", "[0-9]")); }"#);
32448 assert!(matches!(result, Ok(Value::Int(3))));
32449 }
32450
32451 #[test]
32452 fn test_guard() {
32453 assert!(matches!(
32454 eval("fn main() { return guard(true, 42); }"),
32455 Ok(Value::Int(42))
32456 ));
32457 assert!(matches!(
32458 eval("fn main() { return guard(false, 42); }"),
32459 Ok(Value::Null)
32460 ));
32461 }
32462
32463 #[test]
32464 fn test_when_unless() {
32465 assert!(matches!(
32466 eval("fn main() { return when(true, 42); }"),
32467 Ok(Value::Int(42))
32468 ));
32469 assert!(matches!(
32470 eval("fn main() { return when(false, 42); }"),
32471 Ok(Value::Null)
32472 ));
32473 assert!(matches!(
32474 eval("fn main() { return unless(false, 42); }"),
32475 Ok(Value::Int(42))
32476 ));
32477 assert!(matches!(
32478 eval("fn main() { return unless(true, 42); }"),
32479 Ok(Value::Null)
32480 ));
32481 }
32482
32483 #[test]
32484 fn test_cond() {
32485 let result = eval("fn main() { return cond([[false, 1], [true, 2], [true, 3]]); }");
32486 assert!(matches!(result, Ok(Value::Int(2))));
32487 }
32488
32489 #[test]
32490 fn test_case() {
32491 let result = eval("fn main() { return case(2, [[1, 10], [2, 20], [3, 30]]); }");
32492 assert!(matches!(result, Ok(Value::Int(20))));
32493 }
32494
32495 #[test]
32496 fn test_head_tail() {
32497 let result = eval("fn main() { let ht = head_tail([1, 2, 3]); return len(ht); }");
32498 assert!(matches!(result, Ok(Value::Int(2)))); }
32500
32501 #[test]
32502 fn test_split_at() {
32503 let result = eval("fn main() { let s = split_at([1, 2, 3, 4, 5], 2); return len(s); }");
32504 assert!(matches!(result, Ok(Value::Int(2)))); }
32506
32507 #[test]
32508 fn test_unwrap_or() {
32509 assert!(matches!(
32510 eval("fn main() { return unwrap_or(null, 42); }"),
32511 Ok(Value::Int(42))
32512 ));
32513 assert!(matches!(
32514 eval("fn main() { return unwrap_or(10, 42); }"),
32515 Ok(Value::Int(10))
32516 ));
32517 }
32518
32519 #[test]
32520 fn test_coalesce() {
32521 assert!(matches!(
32522 eval("fn main() { return coalesce([null, null, 3, 4]); }"),
32523 Ok(Value::Int(3))
32524 ));
32525 }
32526
32527 #[test]
32528 fn test_deep_eq() {
32529 assert!(matches!(
32530 eval("fn main() { return deep_eq([1, 2, 3], [1, 2, 3]); }"),
32531 Ok(Value::Bool(true))
32532 ));
32533 assert!(matches!(
32534 eval("fn main() { return deep_eq([1, 2, 3], [1, 2, 4]); }"),
32535 Ok(Value::Bool(false))
32536 ));
32537 }
32538
32539 #[test]
32540 fn test_same_type() {
32541 assert!(matches!(
32542 eval("fn main() { return same_type(1, 2); }"),
32543 Ok(Value::Bool(true))
32544 ));
32545 assert!(matches!(
32546 eval(r#"fn main() { return same_type(1, "a"); }"#),
32547 Ok(Value::Bool(false))
32548 ));
32549 }
32550
32551 #[test]
32552 fn test_compare() {
32553 assert!(matches!(
32554 eval("fn main() { return compare(1, 2); }"),
32555 Ok(Value::Int(-1))
32556 ));
32557 assert!(matches!(
32558 eval("fn main() { return compare(2, 2); }"),
32559 Ok(Value::Int(0))
32560 ));
32561 assert!(matches!(
32562 eval("fn main() { return compare(3, 2); }"),
32563 Ok(Value::Int(1))
32564 ));
32565 }
32566
32567 #[test]
32568 fn test_between() {
32569 assert!(matches!(
32570 eval("fn main() { return between(5, 1, 10); }"),
32571 Ok(Value::Bool(true))
32572 ));
32573 assert!(matches!(
32574 eval("fn main() { return between(15, 1, 10); }"),
32575 Ok(Value::Bool(false))
32576 ));
32577 }
32578
32579 #[test]
32580 fn test_clamp() {
32581 assert!(matches!(
32582 eval("fn main() { return clamp(5, 1, 10); }"),
32583 Ok(Value::Int(5))
32584 ));
32585 assert!(matches!(
32586 eval("fn main() { return clamp(-5, 1, 10); }"),
32587 Ok(Value::Int(1))
32588 ));
32589 assert!(matches!(
32590 eval("fn main() { return clamp(15, 1, 10); }"),
32591 Ok(Value::Int(10))
32592 ));
32593 }
32594
32595 #[test]
32598 fn test_inspect() {
32599 let result = eval(r#"fn main() { return inspect(42); }"#);
32600 assert!(matches!(result, Ok(Value::String(s)) if s.as_str() == "42"));
32601 }
32602
32603 #[test]
32604 fn test_version() {
32605 let result = eval("fn main() { return version(); }");
32606 assert!(matches!(result, Ok(Value::Map(_))));
32607 }
32608
32609 #[test]
32612 fn test_to_int() {
32613 assert!(matches!(
32614 eval("fn main() { return to_int(3.7); }"),
32615 Ok(Value::Int(3))
32616 ));
32617 assert!(matches!(
32618 eval(r#"fn main() { return to_int("42"); }"#),
32619 Ok(Value::Int(42))
32620 ));
32621 }
32622
32623 #[test]
32624 fn test_to_float() {
32625 assert!(
32626 matches!(eval("fn main() { return to_float(42); }"), Ok(Value::Float(f)) if (f - 42.0).abs() < 0.001)
32627 );
32628 }
32629
32630 #[test]
32631 fn test_to_string() {
32632 assert!(
32633 matches!(eval("fn main() { return to_string(42); }"), Ok(Value::String(s)) if s.as_str() == "42")
32634 );
32635 }
32636
32637 #[test]
32638 fn test_to_bool() {
32639 assert!(matches!(
32640 eval("fn main() { return to_bool(1); }"),
32641 Ok(Value::Bool(true))
32642 ));
32643 assert!(matches!(
32644 eval("fn main() { return to_bool(0); }"),
32645 Ok(Value::Bool(false))
32646 ));
32647 }
32648
32649 #[test]
32652 fn test_now() {
32653 let result = eval("fn main() { return now(); }");
32654 assert!(matches!(result, Ok(Value::Int(n)) if n > 0));
32655 }
32656
32657 #[test]
32658 fn test_now_secs() {
32659 let result = eval("fn main() { return now_secs(); }");
32661 assert!(matches!(result, Ok(Value::Int(n)) if n > 0));
32662 }
32663
32664 #[test]
32667 fn test_random_int() {
32668 let result = eval("fn main() { return random_int(1, 100); }");
32669 assert!(matches!(result, Ok(Value::Int(n)) if n >= 1 && n < 100));
32670 }
32671
32672 #[test]
32673 fn test_random() {
32674 let result = eval("fn main() { return random(); }");
32676 assert!(
32677 matches!(result, Ok(Value::Float(_))),
32678 "random got: {:?}",
32679 result
32680 );
32681 }
32682
32683 #[test]
32684 fn test_shuffle() {
32685 let result =
32687 eval("fn main() { let arr = [1, 2, 3, 4, 5]; shuffle(arr); return len(arr); }");
32688 assert!(
32689 matches!(result, Ok(Value::Int(5))),
32690 "shuffle got: {:?}",
32691 result
32692 );
32693 }
32694
32695 #[test]
32696 fn test_sample() {
32697 let result = eval("fn main() { return sample([1, 2, 3, 4, 5]); }");
32698 assert!(matches!(result, Ok(Value::Int(n)) if n >= 1 && n <= 5));
32699 }
32700
32701 #[test]
32704 fn test_map_set_get() {
32705 let result =
32707 eval(r#"fn main() { let m = map_new(); map_set(m, "a", 1); return map_get(m, "a"); }"#);
32708 assert!(
32709 matches!(result, Ok(Value::Int(1))),
32710 "map_set_get got: {:?}",
32711 result
32712 );
32713 }
32714
32715 #[test]
32716 fn test_map_has() {
32717 let result =
32718 eval(r#"fn main() { let m = map_new(); map_set(m, "a", 1); return map_has(m, "a"); }"#);
32719 assert!(
32720 matches!(result, Ok(Value::Bool(true))),
32721 "map_has got: {:?}",
32722 result
32723 );
32724 }
32725
32726 #[test]
32727 fn test_map_keys_values() {
32728 let result = eval(
32729 r#"fn main() { let m = map_new(); map_set(m, "a", 1); return len(map_keys(m)); }"#,
32730 );
32731 assert!(
32732 matches!(result, Ok(Value::Int(1))),
32733 "map_keys got: {:?}",
32734 result
32735 );
32736 }
32737
32738 #[test]
32741 fn test_sort() {
32742 let result = eval("fn main() { return first(sort([3, 1, 2])); }");
32743 assert!(matches!(result, Ok(Value::Int(1))));
32744 }
32745
32746 #[test]
32747 fn test_sort_desc() {
32748 let result = eval("fn main() { return first(sort_desc([1, 3, 2])); }");
32749 assert!(matches!(result, Ok(Value::Int(3))));
32750 }
32751
32752 #[test]
32753 fn test_reverse() {
32754 let result = eval("fn main() { return first(reverse([1, 2, 3])); }");
32755 assert!(matches!(result, Ok(Value::Int(3))));
32756 }
32757
32758 #[test]
32759 fn test_index_of() {
32760 assert!(matches!(
32761 eval("fn main() { return index_of([10, 20, 30], 20); }"),
32762 Ok(Value::Int(1))
32763 ));
32764 assert!(matches!(
32765 eval("fn main() { return index_of([10, 20, 30], 99); }"),
32766 Ok(Value::Int(-1))
32767 ));
32768 }
32769
32770 #[test]
32774 fn test_bitwise_and_symbol() {
32775 let result = eval("fn main() { return 0b1100 ⋏ 0b1010; }");
32777 assert!(
32778 matches!(result, Ok(Value::Int(8))),
32779 "bitwise AND got: {:?}",
32780 result
32781 ); }
32783
32784 #[test]
32785 fn test_bitwise_or_symbol() {
32786 let result = eval("fn main() { return 0b1100 ⋎ 0b1010; }");
32788 assert!(
32789 matches!(result, Ok(Value::Int(14))),
32790 "bitwise OR got: {:?}",
32791 result
32792 ); }
32794
32795 #[test]
32797 fn test_middle_function() {
32798 let result = eval("fn main() { return middle([1, 2, 3, 4, 5]); }");
32800 assert!(
32801 matches!(result, Ok(Value::Int(3))),
32802 "middle got: {:?}",
32803 result
32804 );
32805 }
32806
32807 #[test]
32808 fn test_choice_function() {
32809 let result = eval("fn main() { let x = choice([10, 20, 30]); return x >= 10; }");
32811 assert!(
32812 matches!(result, Ok(Value::Bool(true))),
32813 "choice got: {:?}",
32814 result
32815 );
32816 }
32817
32818 #[test]
32819 fn test_nth_function() {
32820 let result = eval("fn main() { return nth([10, 20, 30, 40], 2); }");
32822 assert!(
32823 matches!(result, Ok(Value::Int(30))),
32824 "nth got: {:?}",
32825 result
32826 );
32827 }
32828
32829 #[test]
32831 fn test_zip_with_add() {
32832 let result =
32834 eval(r#"fn main() { return first(zip_with([1, 2, 3], [10, 20, 30], "add")); }"#);
32835 assert!(
32836 matches!(result, Ok(Value::Int(11))),
32837 "zip_with add got: {:?}",
32838 result
32839 );
32840 }
32841
32842 #[test]
32843 fn test_zip_with_mul() {
32844 let result = eval(r#"fn main() { return first(zip_with([2, 3, 4], [5, 6, 7], "mul")); }"#);
32845 assert!(
32846 matches!(result, Ok(Value::Int(10))),
32847 "zip_with mul got: {:?}",
32848 result
32849 );
32850 }
32851
32852 #[test]
32853 fn test_supremum_scalar() {
32854 let result = eval("fn main() { return supremum(5, 10); }");
32856 assert!(
32857 matches!(result, Ok(Value::Int(10))),
32858 "supremum scalar got: {:?}",
32859 result
32860 );
32861 }
32862
32863 #[test]
32864 fn test_supremum_array() {
32865 let result = eval("fn main() { return first(supremum([1, 5, 3], [2, 4, 6])); }");
32866 assert!(
32867 matches!(result, Ok(Value::Int(2))),
32868 "supremum array got: {:?}",
32869 result
32870 );
32871 }
32872
32873 #[test]
32874 fn test_infimum_scalar() {
32875 let result = eval("fn main() { return infimum(5, 10); }");
32877 assert!(
32878 matches!(result, Ok(Value::Int(5))),
32879 "infimum scalar got: {:?}",
32880 result
32881 );
32882 }
32883
32884 #[test]
32885 fn test_infimum_array() {
32886 let result = eval("fn main() { return first(infimum([1, 5, 3], [2, 4, 6])); }");
32887 assert!(
32888 matches!(result, Ok(Value::Int(1))),
32889 "infimum array got: {:?}",
32890 result
32891 );
32892 }
32893
32894 #[test]
32896 fn test_aspect_tokens_lexer() {
32897 use crate::lexer::{Lexer, Token};
32898
32899 let mut lexer = Lexer::new("process·ing");
32901 assert!(matches!(lexer.next_token(), Some((Token::Ident(s), _)) if s == "process"));
32902 assert!(matches!(
32903 lexer.next_token(),
32904 Some((Token::AspectProgressive, _))
32905 ));
32906
32907 let mut lexer = Lexer::new("process·ed");
32909 assert!(matches!(lexer.next_token(), Some((Token::Ident(s), _)) if s == "process"));
32910 assert!(matches!(
32911 lexer.next_token(),
32912 Some((Token::AspectPerfective, _))
32913 ));
32914
32915 let mut lexer = Lexer::new("parse·able");
32917 assert!(matches!(lexer.next_token(), Some((Token::Ident(s), _)) if s == "parse"));
32918 assert!(matches!(
32919 lexer.next_token(),
32920 Some((Token::AspectPotential, _))
32921 ));
32922
32923 let mut lexer = Lexer::new("destruct·ive");
32925 assert!(matches!(lexer.next_token(), Some((Token::Ident(s), _)) if s == "destruct"));
32926 assert!(matches!(
32927 lexer.next_token(),
32928 Some((Token::AspectResultative, _))
32929 ));
32930 }
32931
32932 #[test]
32934 fn test_new_morpheme_tokens_lexer() {
32935 use crate::lexer::{Lexer, Token};
32936
32937 let mut lexer = Lexer::new("μ χ ν ξ");
32938 assert!(matches!(lexer.next_token(), Some((Token::Mu, _))));
32939 assert!(matches!(lexer.next_token(), Some((Token::Chi, _))));
32940 assert!(matches!(lexer.next_token(), Some((Token::Nu, _))));
32941 assert!(matches!(lexer.next_token(), Some((Token::Xi, _))));
32942 }
32943
32944 #[test]
32946 fn test_data_op_tokens_lexer() {
32947 use crate::lexer::{Lexer, Token};
32948
32949 let mut lexer = Lexer::new("⋈ ⋳ ⊔ ⊓");
32950 assert!(matches!(lexer.next_token(), Some((Token::Bowtie, _))));
32951 assert!(matches!(
32952 lexer.next_token(),
32953 Some((Token::ElementSmallVerticalBar, _))
32954 ));
32955 assert!(matches!(lexer.next_token(), Some((Token::SquareCup, _))));
32956 assert!(matches!(lexer.next_token(), Some((Token::SquareCap, _))));
32957 }
32958
32959 #[test]
32961 fn test_bitwise_symbol_tokens_lexer() {
32962 use crate::lexer::{Lexer, Token};
32963
32964 let mut lexer = Lexer::new("⋏ ⋎");
32965 assert!(matches!(
32966 lexer.next_token(),
32967 Some((Token::BitwiseAndSymbol, _))
32968 ));
32969 assert!(matches!(
32970 lexer.next_token(),
32971 Some((Token::BitwiseOrSymbol, _))
32972 ));
32973 }
32974
32975 #[test]
32978 fn test_pipe_alpha_first() {
32979 let result = eval("fn main() { return [10, 20, 30] |α; }");
32981 assert!(
32982 matches!(result, Ok(Value::Int(10))),
32983 "pipe α got: {:?}",
32984 result
32985 );
32986 }
32987
32988 #[test]
32989 fn test_pipe_omega_last() {
32990 let result = eval("fn main() { return [10, 20, 30] |ω; }");
32992 assert!(
32993 matches!(result, Ok(Value::Int(30))),
32994 "pipe ω got: {:?}",
32995 result
32996 );
32997 }
32998
32999 #[test]
33000 fn test_pipe_mu_middle() {
33001 let result = eval("fn main() { return [10, 20, 30, 40, 50] |μ; }");
33003 assert!(
33004 matches!(result, Ok(Value::Int(30))),
33005 "pipe μ got: {:?}",
33006 result
33007 );
33008 }
33009
33010 #[test]
33011 fn test_pipe_chi_choice() {
33012 let result = eval("fn main() { let x = [10, 20, 30] |χ; return x >= 10; }");
33014 assert!(
33015 matches!(result, Ok(Value::Bool(true))),
33016 "pipe χ got: {:?}",
33017 result
33018 );
33019 }
33020
33021 #[test]
33022 fn test_pipe_nu_nth() {
33023 let result = eval("fn main() { return [10, 20, 30, 40] |ν{2}; }");
33025 assert!(
33026 matches!(result, Ok(Value::Int(30))),
33027 "pipe ν got: {:?}",
33028 result
33029 );
33030 }
33031
33032 #[test]
33033 fn test_pipe_chain() {
33034 let result = eval("fn main() { return [3, 1, 4, 1, 5] |σ |α; }");
33036 assert!(
33037 matches!(result, Ok(Value::Int(1))),
33038 "pipe chain got: {:?}",
33039 result
33040 );
33041 }
33042
33043 #[test]
33046 fn test_aspect_progressive_parsing() {
33047 use crate::ast::Aspect;
33049 use crate::parser::Parser;
33050 let mut parser = Parser::new("fn process·ing() { return 42; }");
33051 let file = parser.parse_file().unwrap();
33052 if let crate::ast::Item::Function(f) = &file.items[0].node {
33053 assert_eq!(f.name.name, "process");
33054 assert_eq!(f.aspect, Some(Aspect::Progressive));
33055 } else {
33056 panic!("Expected function item");
33057 }
33058 }
33059
33060 #[test]
33061 fn test_aspect_perfective_parsing() {
33062 use crate::ast::Aspect;
33064 use crate::parser::Parser;
33065 let mut parser = Parser::new("fn process·ed() { return 42; }");
33066 let file = parser.parse_file().unwrap();
33067 if let crate::ast::Item::Function(f) = &file.items[0].node {
33068 assert_eq!(f.name.name, "process");
33069 assert_eq!(f.aspect, Some(Aspect::Perfective));
33070 } else {
33071 panic!("Expected function item");
33072 }
33073 }
33074
33075 #[test]
33076 fn test_aspect_potential_parsing() {
33077 use crate::ast::Aspect;
33079 use crate::parser::Parser;
33080 let mut parser = Parser::new("fn parse·able() { return true; }");
33081 let file = parser.parse_file().unwrap();
33082 if let crate::ast::Item::Function(f) = &file.items[0].node {
33083 assert_eq!(f.name.name, "parse");
33084 assert_eq!(f.aspect, Some(Aspect::Potential));
33085 } else {
33086 panic!("Expected function item");
33087 }
33088 }
33089
33090 #[test]
33091 fn test_aspect_resultative_parsing() {
33092 use crate::ast::Aspect;
33094 use crate::parser::Parser;
33095 let mut parser = Parser::new("fn destruct·ive() { return 42; }");
33096 let file = parser.parse_file().unwrap();
33097 if let crate::ast::Item::Function(f) = &file.items[0].node {
33098 assert_eq!(f.name.name, "destruct");
33099 assert_eq!(f.aspect, Some(Aspect::Resultative));
33100 } else {
33101 panic!("Expected function item");
33102 }
33103 }
33104
33105 #[test]
33108 fn test_choice_single_element() {
33109 assert!(matches!(
33111 eval("fn main() { return choice([42]); }"),
33112 Ok(Value::Int(42))
33113 ));
33114 }
33115
33116 #[test]
33117 fn test_nth_edge_cases() {
33118 assert!(matches!(
33120 eval("fn main() { return nth([10, 20, 30], 2); }"),
33121 Ok(Value::Int(30))
33122 ));
33123 assert!(matches!(
33125 eval("fn main() { return nth([10, 20, 30], 0); }"),
33126 Ok(Value::Int(10))
33127 ));
33128 }
33129
33130 #[test]
33131 fn test_next_peek_usage() {
33132 assert!(matches!(
33134 eval("fn main() { return next([1, 2, 3]); }"),
33135 Ok(Value::Int(1))
33136 ));
33137 assert!(matches!(
33139 eval("fn main() { return peek([1, 2, 3]); }"),
33140 Ok(Value::Int(1))
33141 ));
33142 }
33143
33144 #[test]
33145 fn test_zip_with_empty() {
33146 let result = eval(r#"fn main() { return len(zip_with([], [], "add")); }"#);
33148 assert!(matches!(result, Ok(Value::Int(0))));
33149 }
33150
33151 #[test]
33152 fn test_zip_with_different_lengths() {
33153 let result = eval(r#"fn main() { return len(zip_with([1, 2], [3, 4, 5], "add")); }"#);
33155 assert!(matches!(result, Ok(Value::Int(2))));
33156 }
33157
33158 #[test]
33159 fn test_supremum_edge_cases() {
33160 assert!(matches!(
33162 eval("fn main() { return supremum(5, 5); }"),
33163 Ok(Value::Int(5))
33164 ));
33165 assert!(matches!(
33167 eval("fn main() { return supremum(-5, -3); }"),
33168 Ok(Value::Int(-3))
33169 ));
33170 assert!(
33172 matches!(eval("fn main() { return supremum(1.5, 2.5); }"), Ok(Value::Float(f)) if (f - 2.5).abs() < 0.001)
33173 );
33174 }
33175
33176 #[test]
33177 fn test_infimum_edge_cases() {
33178 assert!(matches!(
33180 eval("fn main() { return infimum(5, 5); }"),
33181 Ok(Value::Int(5))
33182 ));
33183 assert!(matches!(
33185 eval("fn main() { return infimum(-5, -3); }"),
33186 Ok(Value::Int(-5))
33187 ));
33188 assert!(
33190 matches!(eval("fn main() { return infimum(1.5, 2.5); }"), Ok(Value::Float(f)) if (f - 1.5).abs() < 0.001)
33191 );
33192 }
33193
33194 #[test]
33195 fn test_supremum_infimum_arrays() {
33196 let result = eval("fn main() { return supremum([1, 5, 3], [2, 4, 6]); }");
33198 if let Ok(Value::Array(arr)) = result {
33199 let arr = arr.borrow();
33200 assert_eq!(arr.len(), 3);
33201 assert!(matches!(arr[0], Value::Int(2)));
33202 assert!(matches!(arr[1], Value::Int(5)));
33203 assert!(matches!(arr[2], Value::Int(6)));
33204 } else {
33205 panic!("Expected array");
33206 }
33207
33208 let result = eval("fn main() { return infimum([1, 5, 3], [2, 4, 6]); }");
33210 if let Ok(Value::Array(arr)) = result {
33211 let arr = arr.borrow();
33212 assert_eq!(arr.len(), 3);
33213 assert!(matches!(arr[0], Value::Int(1)));
33214 assert!(matches!(arr[1], Value::Int(4)));
33215 assert!(matches!(arr[2], Value::Int(3)));
33216 } else {
33217 panic!("Expected array");
33218 }
33219 }
33220
33221 #[test]
33222 fn test_pipe_access_morphemes() {
33223 assert!(matches!(
33225 eval("fn main() { return [10, 20, 30] |α; }"),
33226 Ok(Value::Int(10))
33227 ));
33228 assert!(matches!(
33230 eval("fn main() { return [10, 20, 30] |ω; }"),
33231 Ok(Value::Int(30))
33232 ));
33233 assert!(matches!(
33235 eval("fn main() { return [10, 20, 30] |μ; }"),
33236 Ok(Value::Int(20))
33237 ));
33238 }
33239
33240 #[test]
33241 fn test_pipe_nth_syntax() {
33242 assert!(matches!(
33244 eval("fn main() { return [10, 20, 30, 40] |ν{1}; }"),
33245 Ok(Value::Int(20))
33246 ));
33247 assert!(matches!(
33248 eval("fn main() { return [10, 20, 30, 40] |ν{3}; }"),
33249 Ok(Value::Int(40))
33250 ));
33251 }
33252
33253 #[test]
33256 fn test_quaternion_identity() {
33257 let result = eval("fn main() { let q = quat_identity(); return q; }");
33258 if let Ok(Value::Array(arr)) = result {
33259 let arr = arr.borrow();
33260 assert_eq!(arr.len(), 4);
33261 if let (Value::Float(w), Value::Float(x), Value::Float(y), Value::Float(z)) =
33262 (&arr[0], &arr[1], &arr[2], &arr[3])
33263 {
33264 assert!((w - 1.0).abs() < 0.001);
33265 assert!(x.abs() < 0.001);
33266 assert!(y.abs() < 0.001);
33267 assert!(z.abs() < 0.001);
33268 }
33269 } else {
33270 panic!("Expected quaternion array");
33271 }
33272 }
33273
33274 #[test]
33275 fn test_quaternion_from_axis_angle() {
33276 let result =
33278 eval("fn main() { let q = quat_from_axis_angle(vec3(0, 1, 0), 1.5707963); return q; }");
33279 if let Ok(Value::Array(arr)) = result {
33280 let arr = arr.borrow();
33281 assert_eq!(arr.len(), 4);
33282 if let (Value::Float(w), Value::Float(x), Value::Float(y), Value::Float(z)) =
33284 (&arr[0], &arr[1], &arr[2], &arr[3])
33285 {
33286 assert!((w - 0.707).abs() < 0.01, "w={}", w);
33287 assert!(x.abs() < 0.01);
33288 assert!((y - 0.707).abs() < 0.01, "y={}", y);
33289 assert!(z.abs() < 0.01);
33290 }
33291 } else {
33292 panic!("Expected quaternion array");
33293 }
33294 }
33295
33296 #[test]
33297 fn test_quaternion_rotate_vector() {
33298 let result = eval(
33300 r#"
33301 fn main() {
33302 let q = quat_from_axis_angle(vec3(0, 0, 1), 1.5707963);
33303 let v = vec3(1, 0, 0);
33304 return quat_rotate(q, v);
33305 }
33306 "#,
33307 );
33308 if let Ok(Value::Array(arr)) = result {
33309 let arr = arr.borrow();
33310 assert_eq!(arr.len(), 3);
33311 if let (Value::Float(x), Value::Float(y), Value::Float(z)) = (&arr[0], &arr[1], &arr[2])
33312 {
33313 assert!(x.abs() < 0.01, "x={}", x);
33314 assert!((y - 1.0).abs() < 0.01, "y={}", y);
33315 assert!(z.abs() < 0.01);
33316 }
33317 } else {
33318 panic!("Expected vec3 array");
33319 }
33320 }
33321
33322 #[test]
33323 fn test_quaternion_slerp() {
33324 let result = eval(
33326 r#"
33327 fn main() {
33328 let q1 = quat_identity();
33329 let q2 = quat_from_axis_angle(vec3(0, 1, 0), 1.5707963);
33330 return quat_slerp(q1, q2, 0.5);
33331 }
33332 "#,
33333 );
33334 if let Ok(Value::Array(arr)) = result {
33335 let arr = arr.borrow();
33336 assert_eq!(arr.len(), 4);
33337 if let Value::Float(w) = &arr[0] {
33339 assert!((w - 0.924).abs() < 0.05, "w={}", w);
33341 }
33342 } else {
33343 panic!("Expected quaternion array");
33344 }
33345 }
33346
33347 #[test]
33348 fn test_vec3_operations() {
33349 let result = eval("fn main() { return vec3_add(vec3(1, 2, 3), vec3(4, 5, 6)); }");
33351 if let Ok(Value::Array(arr)) = result {
33352 let arr = arr.borrow();
33353 if let (Value::Float(x), Value::Float(y), Value::Float(z)) = (&arr[0], &arr[1], &arr[2])
33354 {
33355 assert!((x - 5.0).abs() < 0.001);
33356 assert!((y - 7.0).abs() < 0.001);
33357 assert!((z - 9.0).abs() < 0.001);
33358 }
33359 }
33360
33361 let result = eval("fn main() { return vec3_dot(vec3(1, 2, 3), vec3(4, 5, 6)); }");
33363 assert!(matches!(result, Ok(Value::Float(f)) if (f - 32.0).abs() < 0.001));
33364
33365 let result = eval("fn main() { return vec3_cross(vec3(1, 0, 0), vec3(0, 1, 0)); }");
33367 if let Ok(Value::Array(arr)) = result {
33368 let arr = arr.borrow();
33369 if let (Value::Float(x), Value::Float(y), Value::Float(z)) = (&arr[0], &arr[1], &arr[2])
33370 {
33371 assert!(x.abs() < 0.001);
33372 assert!(y.abs() < 0.001);
33373 assert!((z - 1.0).abs() < 0.001);
33374 }
33375 }
33376
33377 let result = eval("fn main() { return vec3_length(vec3(3, 4, 0)); }");
33379 assert!(matches!(result, Ok(Value::Float(f)) if (f - 5.0).abs() < 0.001));
33380
33381 let result = eval("fn main() { return vec3_normalize(vec3(3, 0, 0)); }");
33383 if let Ok(Value::Array(arr)) = result {
33384 let arr = arr.borrow();
33385 if let Value::Float(x) = &arr[0] {
33386 assert!((x - 1.0).abs() < 0.001);
33387 }
33388 }
33389 }
33390
33391 #[test]
33392 fn test_vec3_reflect() {
33393 let result = eval("fn main() { return vec3_reflect(vec3(1, -1, 0), vec3(0, 1, 0)); }");
33395 if let Ok(Value::Array(arr)) = result {
33396 let arr = arr.borrow();
33397 if let (Value::Float(x), Value::Float(y), Value::Float(z)) = (&arr[0], &arr[1], &arr[2])
33398 {
33399 assert!((x - 1.0).abs() < 0.001);
33400 assert!((y - 1.0).abs() < 0.001);
33401 assert!(z.abs() < 0.001);
33402 }
33403 }
33404 }
33405
33406 #[test]
33407 fn test_mat4_identity() {
33408 let result = eval("fn main() { return mat4_identity(); }");
33409 if let Ok(Value::Array(arr)) = result {
33410 let arr = arr.borrow();
33411 assert_eq!(arr.len(), 16);
33412 if let (Value::Float(m00), Value::Float(m55), Value::Float(m10), Value::Float(m15)) =
33414 (&arr[0], &arr[5], &arr[10], &arr[15])
33415 {
33416 assert!((m00 - 1.0).abs() < 0.001);
33417 assert!((m55 - 1.0).abs() < 0.001);
33418 assert!((m10 - 1.0).abs() < 0.001);
33419 assert!((m15 - 1.0).abs() < 0.001);
33420 }
33421 }
33422 }
33423
33424 #[test]
33425 fn test_mat4_translate() {
33426 let result = eval(
33427 r#"
33428 fn main() {
33429 let t = mat4_translate(5.0, 10.0, 15.0);
33430 let v = vec4(0, 0, 0, 1);
33431 return mat4_transform(t, v);
33432 }
33433 "#,
33434 );
33435 if let Ok(Value::Array(arr)) = result {
33436 let arr = arr.borrow();
33437 if let (Value::Float(x), Value::Float(y), Value::Float(z), Value::Float(w)) =
33438 (&arr[0], &arr[1], &arr[2], &arr[3])
33439 {
33440 assert!((x - 5.0).abs() < 0.001);
33441 assert!((y - 10.0).abs() < 0.001);
33442 assert!((z - 15.0).abs() < 0.001);
33443 assert!((w - 1.0).abs() < 0.001);
33444 }
33445 }
33446 }
33447
33448 #[test]
33449 fn test_mat4_perspective() {
33450 let result = eval("fn main() { return mat4_perspective(1.0472, 1.777, 0.1, 100.0); }");
33452 if let Ok(Value::Array(arr)) = result {
33453 let arr = arr.borrow();
33454 assert_eq!(arr.len(), 16);
33455 } else {
33456 panic!("Expected mat4 array");
33457 }
33458 }
33459
33460 #[test]
33461 fn test_mat4_look_at() {
33462 let result = eval(
33463 r#"
33464 fn main() {
33465 let eye = vec3(0, 0, 5);
33466 let center = vec3(0, 0, 0);
33467 let up = vec3(0, 1, 0);
33468 return mat4_look_at(eye, center, up);
33469 }
33470 "#,
33471 );
33472 if let Ok(Value::Array(arr)) = result {
33473 let arr = arr.borrow();
33474 assert_eq!(arr.len(), 16);
33475 } else {
33476 panic!("Expected mat4 array");
33477 }
33478 }
33479
33480 #[test]
33481 fn test_mat4_inverse() {
33482 let result = eval(
33484 r#"
33485 fn main() {
33486 let m = mat4_identity();
33487 return mat4_inverse(m);
33488 }
33489 "#,
33490 );
33491 if let Ok(Value::Array(arr)) = result {
33492 let arr = arr.borrow();
33493 assert_eq!(arr.len(), 16);
33494 if let Value::Float(m00) = &arr[0] {
33495 assert!((m00 - 1.0).abs() < 0.001);
33496 }
33497 }
33498 }
33499
33500 #[test]
33501 fn test_mat3_operations() {
33502 let result = eval("fn main() { return mat3_identity(); }");
33504 if let Ok(Value::Array(arr)) = result {
33505 let arr = arr.borrow();
33506 assert_eq!(arr.len(), 9);
33507 }
33508
33509 let result = eval(
33511 r#"
33512 fn main() {
33513 let m = mat3_identity();
33514 let v = vec3(1, 2, 3);
33515 return mat3_transform(m, v);
33516 }
33517 "#,
33518 );
33519 if let Ok(Value::Array(arr)) = result {
33520 let arr = arr.borrow();
33521 if let (Value::Float(x), Value::Float(y), Value::Float(z)) = (&arr[0], &arr[1], &arr[2])
33522 {
33523 assert!((x - 1.0).abs() < 0.001);
33524 assert!((y - 2.0).abs() < 0.001);
33525 assert!((z - 3.0).abs() < 0.001);
33526 }
33527 }
33528 }
33529
33530 #[test]
33531 fn test_quat_to_mat4() {
33532 let result = eval(
33534 r#"
33535 fn main() {
33536 let q = quat_identity();
33537 return quat_to_mat4(q);
33538 }
33539 "#,
33540 );
33541 if let Ok(Value::Array(arr)) = result {
33542 let arr = arr.borrow();
33543 assert_eq!(arr.len(), 16);
33544 if let (Value::Float(m00), Value::Float(m55)) = (&arr[0], &arr[5]) {
33546 assert!((m00 - 1.0).abs() < 0.001);
33547 assert!((m55 - 1.0).abs() < 0.001);
33548 }
33549 }
33550 }
33551
33552 #[test]
33556 fn test_channel_basic_send_recv() {
33557 let result = eval(
33559 r#"
33560 fn main() {
33561 let ch = channel_new();
33562 channel_send(ch, 42);
33563 return channel_recv(ch);
33564 }
33565 "#,
33566 );
33567 assert!(matches!(result, Ok(Value::Int(42))));
33568 }
33569
33570 #[test]
33571 fn test_channel_multiple_values() {
33572 let result = eval(
33574 r#"
33575 fn main() {
33576 let ch = channel_new();
33577 channel_send(ch, 1);
33578 channel_send(ch, 2);
33579 channel_send(ch, 3);
33580 let a = channel_recv(ch);
33581 let b = channel_recv(ch);
33582 let c = channel_recv(ch);
33583 return a * 100 + b * 10 + c;
33584 }
33585 "#,
33586 );
33587 assert!(matches!(result, Ok(Value::Int(123))));
33588 }
33589
33590 #[test]
33591 fn test_channel_high_throughput() {
33592 let result = eval(
33594 r#"
33595 fn main() {
33596 let ch = channel_new();
33597 let count = 1000;
33598 let mut i = 0;
33599 while i < count {
33600 channel_send(ch, i);
33601 i = i + 1;
33602 }
33603
33604 // Receive all and compute sum to verify no data loss
33605 let mut sum = 0;
33606 let mut j = 0;
33607 while j < count {
33608 let val = channel_recv(ch);
33609 sum = sum + val;
33610 j = j + 1;
33611 }
33612
33613 // Sum of 0..999 = 499500
33614 return sum;
33615 }
33616 "#,
33617 );
33618 assert!(matches!(result, Ok(Value::Int(499500))));
33619 }
33620
33621 #[test]
33622 fn test_channel_data_integrity() {
33623 let result = eval(
33625 r#"
33626 fn main() {
33627 let ch = channel_new();
33628
33629 // Send various types
33630 channel_send(ch, 42);
33631 channel_send(ch, 3.14);
33632 channel_send(ch, "hello");
33633 channel_send(ch, [1, 2, 3]);
33634
33635 // Receive and verify types
33636 let int_val = channel_recv(ch);
33637 let float_val = channel_recv(ch);
33638 let str_val = channel_recv(ch);
33639 let arr_val = channel_recv(ch);
33640
33641 // Verify by combining results
33642 return int_val + floor(float_val) + len(str_val) + len(arr_val);
33643 }
33644 "#,
33645 );
33646 assert!(matches!(result, Ok(Value::Int(53))));
33648 }
33649
33650 #[test]
33651 fn test_channel_try_recv_empty() {
33652 let result = eval(
33655 r#"
33656 fn main() {
33657 let ch = channel_new();
33658 let result = channel_try_recv(ch);
33659 // Can't pattern match variants in interpreter, so just verify it returns
33660 return type_of(result);
33661 }
33662 "#,
33663 );
33664 assert!(result.is_ok());
33666 }
33667
33668 #[test]
33669 fn test_channel_try_recv_with_value() {
33670 let result = eval(
33672 r#"
33673 fn main() {
33674 let ch = channel_new();
33675 channel_send(ch, 99);
33676 // Use blocking recv since try_recv returns Option variant
33677 // which can't be pattern matched in interpreter
33678 let val = channel_recv(ch);
33679 return val;
33680 }
33681 "#,
33682 );
33683 assert!(matches!(result, Ok(Value::Int(99))));
33684 }
33685
33686 #[test]
33687 fn test_channel_recv_timeout_expires() {
33688 let result = eval(
33690 r#"
33691 fn main() {
33692 let ch = channel_new();
33693 let result = channel_recv_timeout(ch, 10); // 10ms timeout
33694 // Just verify it completes without blocking forever
33695 return 42;
33696 }
33697 "#,
33698 );
33699 assert!(matches!(result, Ok(Value::Int(42))));
33700 }
33701
33702 #[test]
33703 fn test_actor_basic_messaging() {
33704 let result = eval(
33706 r#"
33707 fn main() {
33708 let act = spawn_actor("test_actor");
33709 send_to_actor(act, "ping", 42);
33710 return get_actor_msg_count(act);
33711 }
33712 "#,
33713 );
33714 assert!(matches!(result, Ok(Value::Int(1))));
33715 }
33716
33717 #[test]
33718 fn test_actor_message_storm() {
33719 let result = eval(
33721 r#"
33722 fn main() {
33723 let act = spawn_actor("stress_actor");
33724 let count = 10000;
33725 let mut i = 0;
33726 while i < count {
33727 send_to_actor(act, "msg", i);
33728 i = i + 1;
33729 }
33730 return get_actor_msg_count(act);
33731 }
33732 "#,
33733 );
33734 assert!(matches!(result, Ok(Value::Int(10000))));
33735 }
33736
33737 #[test]
33738 fn test_actor_pending_count() {
33739 let result = eval(
33741 r#"
33742 fn main() {
33743 let act = spawn_actor("pending_test");
33744
33745 // Send 5 messages
33746 send_to_actor(act, "m1", 1);
33747 send_to_actor(act, "m2", 2);
33748 send_to_actor(act, "m3", 3);
33749 send_to_actor(act, "m4", 4);
33750 send_to_actor(act, "m5", 5);
33751
33752 let pending_before = get_actor_pending(act);
33753
33754 // Receive 2 messages
33755 recv_from_actor(act);
33756 recv_from_actor(act);
33757
33758 let pending_after = get_actor_pending(act);
33759
33760 // Should have 5 pending initially, 3 after receiving 2
33761 return pending_before * 10 + pending_after;
33762 }
33763 "#,
33764 );
33765 assert!(matches!(result, Ok(Value::Int(53)))); }
33767
33768 #[test]
33769 fn test_actor_message_order() {
33770 let result = eval(
33773 r#"
33774 fn main() {
33775 let act = spawn_actor("order_test");
33776 send_to_actor(act, "a", 1);
33777 send_to_actor(act, "b", 2);
33778 send_to_actor(act, "c", 3);
33779
33780 // pop() gives LIFO order, so we get c, b, a
33781 let r1 = recv_from_actor(act);
33782 let r2 = recv_from_actor(act);
33783 let r3 = recv_from_actor(act);
33784
33785 // Return the message types concatenated via their first char values
33786 // c=3, b=2, a=1 in our test
33787 return get_actor_pending(act); // Should be 0 after draining
33788 }
33789 "#,
33790 );
33791 assert!(matches!(result, Ok(Value::Int(0))));
33792 }
33793
33794 #[test]
33795 fn test_actor_recv_empty() {
33796 let result = eval(
33799 r#"
33800 fn main() {
33801 let act = spawn_actor("empty_actor");
33802 // No messages sent, so pending should be 0
33803 return get_actor_pending(act);
33804 }
33805 "#,
33806 );
33807 assert!(matches!(result, Ok(Value::Int(0))));
33808 }
33809
33810 #[test]
33811 fn test_actor_tell_alias() {
33812 let result = eval(
33814 r#"
33815 fn main() {
33816 let act = spawn_actor("tell_test");
33817 tell_actor(act, "hello", 123);
33818 tell_actor(act, "world", 456);
33819 return get_actor_msg_count(act);
33820 }
33821 "#,
33822 );
33823 assert!(matches!(result, Ok(Value::Int(2))));
33824 }
33825
33826 #[test]
33827 fn test_actor_name() {
33828 let result = eval(
33830 r#"
33831 fn main() {
33832 let act = spawn_actor("my_special_actor");
33833 return get_actor_name(act);
33834 }
33835 "#,
33836 );
33837 assert!(matches!(result, Ok(Value::String(s)) if s.as_str() == "my_special_actor"));
33838 }
33839
33840 #[test]
33841 fn test_multiple_actors() {
33842 let result = eval(
33844 r#"
33845 fn main() {
33846 let a1 = spawn_actor("actor1");
33847 let a2 = spawn_actor("actor2");
33848 let a3 = spawn_actor("actor3");
33849
33850 send_to_actor(a1, "m", 1);
33851 send_to_actor(a2, "m", 1);
33852 send_to_actor(a2, "m", 2);
33853 send_to_actor(a3, "m", 1);
33854 send_to_actor(a3, "m", 2);
33855 send_to_actor(a3, "m", 3);
33856
33857 let c1 = get_actor_msg_count(a1);
33858 let c2 = get_actor_msg_count(a2);
33859 let c3 = get_actor_msg_count(a3);
33860
33861 return c1 * 100 + c2 * 10 + c3;
33862 }
33863 "#,
33864 );
33865 assert!(matches!(result, Ok(Value::Int(123)))); }
33867
33868 #[test]
33869 fn test_multiple_channels() {
33870 let result = eval(
33872 r#"
33873 fn main() {
33874 let ch1 = channel_new();
33875 let ch2 = channel_new();
33876 let ch3 = channel_new();
33877
33878 channel_send(ch1, 100);
33879 channel_send(ch2, 200);
33880 channel_send(ch3, 300);
33881
33882 let v1 = channel_recv(ch1);
33883 let v2 = channel_recv(ch2);
33884 let v3 = channel_recv(ch3);
33885
33886 return v1 + v2 + v3;
33887 }
33888 "#,
33889 );
33890 assert!(matches!(result, Ok(Value::Int(600))));
33891 }
33892
33893 #[test]
33894 fn test_thread_sleep() {
33895 let result = eval(
33897 r#"
33898 fn main() {
33899 thread_sleep(1); // Sleep 1ms
33900 return 42;
33901 }
33902 "#,
33903 );
33904 assert!(matches!(result, Ok(Value::Int(42))));
33905 }
33906
33907 #[test]
33908 fn test_thread_yield() {
33909 let result = eval(
33911 r#"
33912 fn main() {
33913 thread_yield();
33914 return 42;
33915 }
33916 "#,
33917 );
33918 assert!(matches!(result, Ok(Value::Int(42))));
33919 }
33920
33921 #[test]
33922 fn test_thread_id() {
33923 let result = eval(
33925 r#"
33926 fn main() {
33927 let id = thread_id();
33928 return len(id) > 0;
33929 }
33930 "#,
33931 );
33932 assert!(matches!(result, Ok(Value::Bool(true))));
33933 }
33934
33935 #[test]
33936 fn test_channel_stress_interleaved() {
33937 let result = eval(
33939 r#"
33940 fn main() {
33941 let ch = channel_new();
33942 let mut sum = 0;
33943 let mut i = 0;
33944 while i < 100 {
33945 channel_send(ch, i);
33946 channel_send(ch, i * 2);
33947 let a = channel_recv(ch);
33948 let b = channel_recv(ch);
33949 sum = sum + a + b;
33950 i = i + 1;
33951 }
33952 // Sum: sum of i + i*2 for i in 0..99
33953 // = sum of 3*i for i in 0..99 = 3 * (99*100/2) = 3 * 4950 = 14850
33954 return sum;
33955 }
33956 "#,
33957 );
33958 assert!(matches!(result, Ok(Value::Int(14850))));
33959 }
33960
33961 #[test]
33962 fn test_actor_stress_with_receive() {
33963 let result = eval(
33965 r#"
33966 fn main() {
33967 let act = spawn_actor("recv_stress");
33968 let count = 1000;
33969 let mut i = 0;
33970 while i < count {
33971 send_to_actor(act, "data", i);
33972 i = i + 1;
33973 }
33974
33975 // Drain all messages
33976 let mut drained = 0;
33977 while get_actor_pending(act) > 0 {
33978 recv_from_actor(act);
33979 drained = drained + 1;
33980 }
33981
33982 return drained;
33983 }
33984 "#,
33985 );
33986 assert!(matches!(result, Ok(Value::Int(1000))));
33987 }
33988
33989 use proptest::prelude::*;
33993
33994 proptest! {
33997 #![proptest_config(ProptestConfig::with_cases(100))]
33998
33999 #[test]
34000 fn test_parser_doesnt_crash_on_random_input(s in "\\PC*") {
34001 let mut parser = Parser::new(&s);
34003 let _ = parser.parse_file(); }
34005
34006 #[test]
34007 fn test_parser_handles_unicode(s in "[\\p{L}\\p{N}\\p{P}\\s]{0,100}") {
34008 let mut parser = Parser::new(&s);
34010 let _ = parser.parse_file();
34011 }
34012
34013 #[test]
34014 fn test_parser_nested_brackets(depth in 0..20usize) {
34015 let open: String = (0..depth).map(|_| '(').collect();
34017 let close: String = (0..depth).map(|_| ')').collect();
34018 let code = format!("fn main() {{ return {}1{}; }}", open, close);
34019 let mut parser = Parser::new(&code);
34020 let _ = parser.parse_file();
34021 }
34022
34023 #[test]
34024 fn test_parser_long_identifiers(len in 1..500usize) {
34025 let ident: String = (0..len).map(|_| 'a').collect();
34027 let code = format!("fn main() {{ let {} = 1; return {}; }}", ident, ident);
34028 let result = eval(&code);
34029 assert!(matches!(result, Ok(Value::Int(1))));
34030 }
34031
34032 #[test]
34033 fn test_parser_many_arguments(count in 0..50usize) {
34034 let args: String = (0..count).map(|i| format!("{}", i)).collect::<Vec<_>>().join(", ");
34036 let code = format!("fn main() {{ return len([{}]); }}", args);
34037 let result = eval(&code);
34038 assert!(matches!(result, Ok(Value::Int(c)) if c == count as i64));
34039 }
34040 }
34041
34042 proptest! {
34045 #![proptest_config(ProptestConfig::with_cases(50))]
34046
34047 #[test]
34048 fn test_ga_bivector_anticommutative(x1 in -100.0f64..100.0, y1 in -100.0f64..100.0, z1 in -100.0f64..100.0,
34049 x2 in -100.0f64..100.0, y2 in -100.0f64..100.0, z2 in -100.0f64..100.0) {
34050 let code = format!(r#"
34053 fn main() {{
34054 let a = vec3({}, {}, {});
34055 let b = vec3({}, {}, {});
34056 let ab = vec3_cross(a, b);
34057 let ba = vec3_cross(b, a);
34058 let diff_x = get(ab, 0) + get(ba, 0);
34059 let diff_y = get(ab, 1) + get(ba, 1);
34060 let diff_z = get(ab, 2) + get(ba, 2);
34061 let eps = 0.001;
34062 return eps > abs(diff_x) && eps > abs(diff_y) && eps > abs(diff_z);
34063 }}
34064 "#, x1, y1, z1, x2, y2, z2);
34065 let result = eval(&code);
34066 assert!(matches!(result, Ok(Value::Bool(true))));
34067 }
34068
34069 #[test]
34070 fn test_vec3_dot_commutative(x1 in -100.0f64..100.0, y1 in -100.0f64..100.0, z1 in -100.0f64..100.0,
34071 x2 in -100.0f64..100.0, y2 in -100.0f64..100.0, z2 in -100.0f64..100.0) {
34072 let code = format!(r#"
34074 fn main() {{
34075 let a = vec3({}, {}, {});
34076 let b = vec3({}, {}, {});
34077 let ab = vec3_dot(a, b);
34078 let ba = vec3_dot(b, a);
34079 let eps = 0.001;
34080 return eps > abs(ab - ba);
34081 }}
34082 "#, x1, y1, z1, x2, y2, z2);
34083 let result = eval(&code);
34084 assert!(matches!(result, Ok(Value::Bool(true))));
34085 }
34086
34087 #[test]
34088 fn test_quat_identity_preserves_vector(x in -100.0f64..100.0, y in -100.0f64..100.0, z in -100.0f64..100.0) {
34089 let code = format!(r#"
34091 fn main() {{
34092 let v = vec3({}, {}, {});
34093 let q = quat_identity();
34094 let rotated = quat_rotate(q, v);
34095 let diff_x = abs(get(v, 0) - get(rotated, 0));
34096 let diff_y = abs(get(v, 1) - get(rotated, 1));
34097 let diff_z = abs(get(v, 2) - get(rotated, 2));
34098 let eps = 0.001;
34099 return eps > diff_x && eps > diff_y && eps > diff_z;
34100 }}
34101 "#, x, y, z);
34102 let result = eval(&code);
34103 assert!(matches!(result, Ok(Value::Bool(true))));
34104 }
34105
34106 #[test]
34107 fn test_quat_double_rotation_equals_double_angle(x in -100.0f64..100.0, y in -100.0f64..100.0, z in -100.0f64..100.0,
34108 angle in -3.14f64..3.14) {
34109 let code = format!(r#"
34111 fn main() {{
34112 let v = vec3({}, {}, {});
34113 let axis = vec3(0.0, 1.0, 0.0);
34114 let q1 = quat_from_axis_angle(axis, {});
34115 let q2 = quat_from_axis_angle(axis, {} * 2.0);
34116 let q1q1 = quat_mul(q1, q1);
34117 let eps = 0.01;
34118 let same = eps > abs(get(q2, 0) - get(q1q1, 0)) &&
34119 eps > abs(get(q2, 1) - get(q1q1, 1)) &&
34120 eps > abs(get(q2, 2) - get(q1q1, 2)) &&
34121 eps > abs(get(q2, 3) - get(q1q1, 3));
34122 let neg_same = eps > abs(get(q2, 0) + get(q1q1, 0)) &&
34123 eps > abs(get(q2, 1) + get(q1q1, 1)) &&
34124 eps > abs(get(q2, 2) + get(q1q1, 2)) &&
34125 eps > abs(get(q2, 3) + get(q1q1, 3));
34126 return same || neg_same;
34127 }}
34128 "#, x, y, z, angle, angle);
34129 let result = eval(&code);
34130 assert!(matches!(result, Ok(Value::Bool(true))));
34131 }
34132
34133 #[test]
34134 fn test_vec3_add_associative(x1 in -100.0f64..100.0, y1 in -100.0f64..100.0, z1 in -100.0f64..100.0,
34135 x2 in -100.0f64..100.0, y2 in -100.0f64..100.0, z2 in -100.0f64..100.0,
34136 x3 in -100.0f64..100.0, y3 in -100.0f64..100.0, z3 in -100.0f64..100.0) {
34137 let code = format!(r#"
34139 fn main() {{
34140 let a = vec3({}, {}, {});
34141 let b = vec3({}, {}, {});
34142 let c = vec3({}, {}, {});
34143 let ab_c = vec3_add(vec3_add(a, b), c);
34144 let a_bc = vec3_add(a, vec3_add(b, c));
34145 let diff_x = abs(get(ab_c, 0) - get(a_bc, 0));
34146 let diff_y = abs(get(ab_c, 1) - get(a_bc, 1));
34147 let diff_z = abs(get(ab_c, 2) - get(a_bc, 2));
34148 let eps = 0.001;
34149 return eps > diff_x && eps > diff_y && eps > diff_z;
34150 }}
34151 "#, x1, y1, z1, x2, y2, z2, x3, y3, z3);
34152 let result = eval(&code);
34153 assert!(matches!(result, Ok(Value::Bool(true))));
34154 }
34155
34156 #[test]
34157 fn test_vec3_scale_distributive(x in -100.0f64..100.0, y in -100.0f64..100.0, z in -100.0f64..100.0,
34158 s1 in -10.0f64..10.0, s2 in -10.0f64..10.0) {
34159 let code = format!(r#"
34161 fn main() {{
34162 let v = vec3({}, {}, {});
34163 let s1 = {};
34164 let s2 = {};
34165 let combined = vec3_scale(v, s1 + s2);
34166 let separate = vec3_add(vec3_scale(v, s1), vec3_scale(v, s2));
34167 let diff_x = abs(get(combined, 0) - get(separate, 0));
34168 let diff_y = abs(get(combined, 1) - get(separate, 1));
34169 let diff_z = abs(get(combined, 2) - get(separate, 2));
34170 let eps = 0.01;
34171 return eps > diff_x && eps > diff_y && eps > diff_z;
34172 }}
34173 "#, x, y, z, s1, s2);
34174 let result = eval(&code);
34175 assert!(matches!(result, Ok(Value::Bool(true))));
34176 }
34177 }
34178
34179 proptest! {
34182 #![proptest_config(ProptestConfig::with_cases(30))]
34183
34184 #[test]
34185 fn test_grad_of_constant_is_zero(c in -100.0f64..100.0, x in -100.0f64..100.0) {
34186 let code = format!(r#"
34188 fn main() {{
34189 fn constant(x) {{ return {}; }}
34190 let g = grad(constant, {});
34191 let eps = 0.001;
34192 return eps > abs(g);
34193 }}
34194 "#, c, x);
34195 let result = eval(&code);
34196 assert!(matches!(result, Ok(Value::Bool(true))));
34197 }
34198
34199 #[test]
34200 fn test_grad_of_x_is_one(x in -100.0f64..100.0) {
34201 let code = format!(r#"
34203 fn main() {{
34204 fn identity(x) {{ return x; }}
34205 let g = grad(identity, {});
34206 let eps = 0.001;
34207 return eps > abs(g - 1.0);
34208 }}
34209 "#, x);
34210 let result = eval(&code);
34211 assert!(matches!(result, Ok(Value::Bool(true))));
34212 }
34213
34214 #[test]
34215 fn test_grad_of_x_squared(x in -50.0f64..50.0) {
34216 let code = format!(r#"
34218 fn main() {{
34219 fn square(x) {{ return x * x; }}
34220 let g = grad(square, {});
34221 let expected = 2.0 * {};
34222 let eps = 0.1;
34223 return eps > abs(g - expected);
34224 }}
34225 "#, x, x);
34226 let result = eval(&code);
34227 assert!(matches!(result, Ok(Value::Bool(true))));
34228 }
34229
34230 #[test]
34231 fn test_grad_linearity(a in -10.0f64..10.0, b in -10.0f64..10.0, x in -10.0f64..10.0) {
34232 let code = format!(r#"
34234 fn main() {{
34235 fn lin(x) {{ return {} * x + {}; }}
34236 let g = grad(lin, {});
34237 let eps = 0.1;
34238 return eps > abs(g - {});
34239 }}
34240 "#, a, b, x, a);
34241 let result = eval(&code);
34242 assert!(matches!(result, Ok(Value::Bool(true))));
34243 }
34244 }
34245
34246 proptest! {
34249 #![proptest_config(ProptestConfig::with_cases(50))]
34250
34251 #[test]
34252 fn test_addition_commutative(a in -1000i64..1000, b in -1000i64..1000) {
34253 let code = format!("fn main() {{ return {} + {} == {} + {}; }}", a, b, b, a);
34254 let result = eval(&code);
34255 assert!(matches!(result, Ok(Value::Bool(true))));
34256 }
34257
34258 #[test]
34259 fn test_multiplication_commutative(a in -100i64..100, b in -100i64..100) {
34260 let code = format!("fn main() {{ return {} * {} == {} * {}; }}", a, b, b, a);
34261 let result = eval(&code);
34262 assert!(matches!(result, Ok(Value::Bool(true))));
34263 }
34264
34265 #[test]
34266 fn test_addition_identity(a in -1000i64..1000) {
34267 let code = format!("fn main() {{ return {} + 0 == {}; }}", a, a);
34268 let result = eval(&code);
34269 assert!(matches!(result, Ok(Value::Bool(true))));
34270 }
34271
34272 #[test]
34273 fn test_multiplication_identity(a in -1000i64..1000) {
34274 let code = format!("fn main() {{ return {} * 1 == {}; }}", a, a);
34275 let result = eval(&code);
34276 assert!(matches!(result, Ok(Value::Bool(true))));
34277 }
34278
34279 #[test]
34280 fn test_distributive_property(a in -20i64..20, b in -20i64..20, c in -20i64..20) {
34281 let code = format!("fn main() {{ return {} * ({} + {}) == {} * {} + {} * {}; }}", a, b, c, a, b, a, c);
34282 let result = eval(&code);
34283 assert!(matches!(result, Ok(Value::Bool(true))));
34284 }
34285 }
34286
34287 proptest! {
34290 #![proptest_config(ProptestConfig::with_cases(30))]
34291
34292 #[test]
34293 fn test_array_len_after_push(initial_len in 0..20usize, value in -100i64..100) {
34294 let initial: String = (0..initial_len).map(|i| format!("{}", i)).collect::<Vec<_>>().join(", ");
34295 let code = format!(r#"
34296 fn main() {{
34297 let arr = [{}];
34298 push(arr, {});
34299 return len(arr);
34300 }}
34301 "#, initial, value);
34302 let result = eval(&code);
34303 assert!(matches!(result, Ok(Value::Int(n)) if n == (initial_len + 1) as i64));
34304 }
34305
34306 #[test]
34307 fn test_reverse_reverse_identity(elements in prop::collection::vec(-100i64..100, 0..10)) {
34308 let arr_str = elements.iter().map(|n| n.to_string()).collect::<Vec<_>>().join(", ");
34309 let code = format!(r#"
34310 fn main() {{
34311 let arr = [{}];
34312 let rev1 = reverse(arr);
34313 let rev2 = reverse(rev1);
34314 let mut same = true;
34315 let mut i = 0;
34316 while i < len(arr) {{
34317 if get(arr, i) != get(rev2, i) {{
34318 same = false;
34319 }}
34320 i = i + 1;
34321 }}
34322 return same;
34323 }}
34324 "#, arr_str);
34325 let result = eval(&code);
34326 assert!(matches!(result, Ok(Value::Bool(true))));
34327 }
34328
34329 #[test]
34330 fn test_sum_equals_manual_sum(elements in prop::collection::vec(-100i64..100, 0..20)) {
34331 let arr_str = elements.iter().map(|n| n.to_string()).collect::<Vec<_>>().join(", ");
34332 let expected_sum: i64 = elements.iter().sum();
34333 let code = format!("fn main() {{ return sum([{}]); }}", arr_str);
34334 let result = eval(&code);
34335 assert!(matches!(result, Ok(Value::Int(n)) if n == expected_sum));
34336 }
34337 }
34338
34339 #[test]
34347 fn test_no_leak_repeated_array_operations() {
34348 let result = eval(
34350 r#"
34351 fn main() {
34352 let mut i = 0;
34353 while i < 1000 {
34354 let arr = [1, 2, 3, 4, 5];
34355 push(arr, 6);
34356 let rev = reverse(arr);
34357 let s = sum(arr);
34358 i = i + 1;
34359 }
34360 return i;
34361 }
34362 "#,
34363 );
34364 assert!(matches!(result, Ok(Value::Int(1000))));
34365 }
34366
34367 #[test]
34368 fn test_no_leak_repeated_function_calls() {
34369 let result = eval(
34371 r#"
34372 fn fib(n) {
34373 if n <= 1 { return n; }
34374 return fib(n - 1) + fib(n - 2);
34375 }
34376 fn main() {
34377 let mut i = 0;
34378 let mut total = 0;
34379 while i < 100 {
34380 total = total + fib(10);
34381 i = i + 1;
34382 }
34383 return total;
34384 }
34385 "#,
34386 );
34387 assert!(matches!(result, Ok(Value::Int(5500))));
34388 }
34389
34390 #[test]
34391 fn test_no_leak_repeated_map_operations() {
34392 let result = eval(
34394 r#"
34395 fn main() {
34396 let mut i = 0;
34397 while i < 500 {
34398 let m = map_new();
34399 map_set(m, "key1", 1);
34400 map_set(m, "key2", 2);
34401 map_set(m, "key3", 3);
34402 let v = map_get(m, "key1");
34403 i = i + 1;
34404 }
34405 return i;
34406 }
34407 "#,
34408 );
34409 assert!(matches!(result, Ok(Value::Int(500))));
34410 }
34411
34412 #[test]
34413 fn test_no_leak_repeated_string_operations() {
34414 let result = eval(
34416 r#"
34417 fn main() {
34418 let mut i = 0;
34419 while i < 1000 {
34420 let s = "hello world";
34421 let upper_s = upper(s);
34422 let lower_s = lower(upper_s);
34423 let concat_s = s ++ " " ++ upper_s;
34424 let replaced = replace(concat_s, "o", "0");
34425 i = i + 1;
34426 }
34427 return i;
34428 }
34429 "#,
34430 );
34431 assert!(matches!(result, Ok(Value::Int(1000))));
34432 }
34433
34434 #[test]
34435 fn test_no_leak_repeated_ecs_operations() {
34436 let result = eval(
34438 r#"
34439 fn main() {
34440 let world = ecs_world();
34441 let mut i = 0;
34442 while i < 500 {
34443 let entity = ecs_spawn(world);
34444 ecs_attach(world, entity, "Position", vec3(1.0, 2.0, 3.0));
34445 ecs_attach(world, entity, "Velocity", vec3(0.0, 0.0, 0.0));
34446 let pos = ecs_get(world, entity, "Position");
34447 i = i + 1;
34448 }
34449 return i;
34450 }
34451 "#,
34452 );
34453 assert!(matches!(result, Ok(Value::Int(500))));
34454 }
34455
34456 #[test]
34457 fn test_no_leak_repeated_channel_operations() {
34458 let result = eval(
34460 r#"
34461 fn main() {
34462 let mut i = 0;
34463 while i < 500 {
34464 let ch = channel_new();
34465 channel_send(ch, i);
34466 channel_send(ch, i + 1);
34467 let v1 = channel_recv(ch);
34468 let v2 = channel_recv(ch);
34469 i = i + 1;
34470 }
34471 return i;
34472 }
34473 "#,
34474 );
34475 assert!(matches!(result, Ok(Value::Int(500))));
34476 }
34477
34478 #[test]
34479 fn test_no_leak_repeated_actor_operations() {
34480 let result = eval(
34482 r#"
34483 fn main() {
34484 let mut i = 0;
34485 while i < 100 {
34486 let act = spawn_actor("leak_test_actor");
34487 send_to_actor(act, "msg", i);
34488 send_to_actor(act, "msg", i + 1);
34489 let count = get_actor_msg_count(act);
34490 i = i + 1;
34491 }
34492 return i;
34493 }
34494 "#,
34495 );
34496 assert!(matches!(result, Ok(Value::Int(100))));
34497 }
34498
34499 #[test]
34500 fn test_no_leak_repeated_vec3_operations() {
34501 let result = eval(
34503 r#"
34504 fn main() {
34505 let mut i = 0;
34506 while i < 1000 {
34507 let v1 = vec3(1.0, 2.0, 3.0);
34508 let v2 = vec3(4.0, 5.0, 6.0);
34509 let added = vec3_add(v1, v2);
34510 let scaled = vec3_scale(added, 2.0);
34511 let dot = vec3_dot(v1, v2);
34512 let crossed = vec3_cross(v1, v2);
34513 let normalized = vec3_normalize(crossed);
34514 i = i + 1;
34515 }
34516 return i;
34517 }
34518 "#,
34519 );
34520 assert!(matches!(result, Ok(Value::Int(1000))));
34521 }
34522
34523 #[test]
34524 fn test_no_leak_repeated_closure_creation() {
34525 let result = eval(
34527 r#"
34528 fn main() {
34529 let mut i = 0;
34530 let mut total = 0;
34531 while i < 500 {
34532 let x = i;
34533 fn add_x(y) { return x + y; }
34534 total = total + add_x(1);
34535 i = i + 1;
34536 }
34537 return total;
34538 }
34539 "#,
34540 );
34541 assert!(matches!(result, Ok(Value::Int(125250))));
34543 }
34544
34545 #[test]
34546 fn test_no_leak_nested_data_structures() {
34547 let result = eval(
34549 r#"
34550 fn main() {
34551 let mut i = 0;
34552 while i < 200 {
34553 let inner1 = [1, 2, 3];
34554 let inner2 = [4, 5, 6];
34555 let outer = [inner1, inner2];
34556 let m = map_new();
34557 map_set(m, "arr", outer);
34558 map_set(m, "nested", map_new());
34559 i = i + 1;
34560 }
34561 return i;
34562 }
34563 "#,
34564 );
34565 assert!(matches!(result, Ok(Value::Int(200))));
34566 }
34567
34568 #[test]
34569 fn test_no_leak_repeated_interpreter_creation() {
34570 for _ in 0..50 {
34572 let result = eval(
34573 r#"
34574 fn main() {
34575 let arr = [1, 2, 3, 4, 5];
34576 let total = sum(arr);
34577 return total * 2;
34578 }
34579 "#,
34580 );
34581 assert!(matches!(result, Ok(Value::Int(30))));
34582 }
34583 }
34584}