sigil_parser/
stdlib.rs

1//! Sigil Standard Library
2//!
3//! A comprehensive collection of built-in functions that leverage
4//! Sigil's polysynthetic syntax and evidentiality type system.
5//!
6//! ## Modules
7//!
8//! - **core**: Essential functions (print, assert, panic)
9//! - **math**: Mathematical operations including poly-cultural math
10//! - **collections**: Array, map, set operations
11//! - **string**: String manipulation
12//! - **evidence**: Evidentiality markers and operations
13//! - **iter**: Iterator-style operations for pipes
14//! - **io**: File and console I/O
15//! - **time**: Date, time, and measurement
16//! - **random**: Random number generation
17//! - **convert**: Type conversions
18//! - **json**: JSON parsing and serialization
19//! - **fs**: File system operations
20//! - **crypto**: Hashing and encoding (SHA256, MD5, base64)
21//! - **regex**: Regular expression matching
22//! - **uuid**: UUID generation
23//! - **system**: Environment, args, process control
24//! - **stats**: Statistical functions
25//! - **matrix**: Matrix operations
26//! - **polycultural_text**: World-class text handling for all scripts
27//!   - Script detection (Latin, Arabic, CJK, Cyrillic, etc.)
28//!   - Bidirectional text (RTL/LTR)
29//!   - Locale-aware case mapping (Turkish İ, German ß)
30//!   - Locale-aware collation (Swedish ä vs German ä)
31//!   - ICU-based segmentation (Thai, CJK word boundaries)
32//!   - Transliteration to ASCII
33//!   - Emoji handling
34//!   - Diacritic manipulation
35//! - **text_intelligence**: AI-native text analysis
36//!   - String similarity (Levenshtein, Jaro-Winkler, Sørensen-Dice)
37//!   - Phonetic encoding (Soundex, Metaphone, Cologne)
38//!   - Language detection with confidence scores
39//!   - LLM token counting (OpenAI, Claude-compatible)
40//!   - Stemming (Porter, Snowball for 15+ languages)
41//!   - Stopword filtering
42//!   - N-grams and shingles for similarity
43//!   - Fuzzy matching utilities
44
45use 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
58// Native resource registry for TcpListeners
59static 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
105// External crates for extended stdlib
106use 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
114// Polycultural text processing
115use 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
125// Text intelligence
126use rust_stemmers::{Algorithm as StemAlgorithm, Stemmer};
127use tiktoken_rs::{cl100k_base, p50k_base, r50k_base};
128use whatlang::{detect, Lang, Script as WhatLangScript};
129
130// Cryptographic primitives for experimental crypto
131use rand::Rng;
132
133/// Register all standard library functions
134pub 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    // Phase 4: Extended stdlib
151    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    // Phase 5: Language power-ups
160    register_functional(interp);
161    register_benchmark(interp);
162    register_itertools(interp);
163    register_ranges(interp);
164    register_bitwise(interp);
165    register_format(interp);
166    // Phase 6: Pattern matching power-ups
167    register_pattern(interp);
168    // Phase 7: DevEx enhancements
169    register_devex(interp);
170    // Phase 8: Performance optimizations
171    register_soa(interp);
172    register_tensor(interp);
173    register_autodiff(interp);
174    register_spatial(interp);
175    register_physics(interp);
176    // Phase 9: Differentiating features
177    register_geometric_algebra(interp);
178    register_dimensional(interp);
179    register_ecs(interp);
180    // Phase 10: Polycultural text processing
181    register_polycultural_text(interp);
182    // Phase 11: Text intelligence (AI-native)
183    register_text_intelligence(interp);
184    // Phase 12: Emotional hologram and experimental crypto
185    register_hologram(interp);
186    register_experimental_crypto(interp);
187    // Phase 13: Multi-base encoding and cultural numerology
188    register_multibase(interp);
189    // Phase 14: Polycultural audio - world tuning, sacred frequencies, synthesis
190    register_audio(interp);
191    // Phase 15: Spirituality - divination, sacred geometry, gematria, archetypes
192    register_spirituality(interp);
193    // Phase 16: Polycultural color - synesthesia, cultural color systems, color spaces
194    register_color(interp);
195    // Phase 17: Protocol support - HTTP, gRPC, WebSocket, Kafka, AMQP, GraphQL
196    register_protocol(interp);
197    // Phase 18: AI Agent infrastructure - Tools, LLM, Planning, Memory, Vectors
198    register_agent_tools(interp);
199    register_agent_llm(interp);
200    register_agent_memory(interp);
201    register_agent_planning(interp);
202    register_agent_vectors(interp);
203    // Phase 19: Multi-Agent Coordination and Reasoning
204    register_agent_swarm(interp);
205    register_agent_reasoning(interp);
206    // Phase 20: Terminal/Console - ANSI styling, progress bars, tables
207    register_terminal(interp);
208}
209
210// Helper to define a builtin
211fn define(
212    interp: &mut Interpreter,
213    name: &str,
214    arity: Option<usize>,
215    func: fn(&mut Interpreter, Vec<Value>) -> Result<Value, RuntimeError>,
216) {
217    let builtin = Value::BuiltIn(Rc::new(BuiltInFn {
218        name: name.to_string(),
219        arity,
220        func,
221    }));
222    interp
223        .globals
224        .borrow_mut()
225        .define(name.to_string(), builtin);
226}
227
228// Helper function for value equality comparison
229fn values_equal_simple(a: &Value, b: &Value) -> bool {
230    match (a, b) {
231        (Value::Int(x), Value::Int(y)) => x == y,
232        (Value::Float(x), Value::Float(y)) => (x - y).abs() < f64::EPSILON,
233        (Value::Int(x), Value::Float(y)) | (Value::Float(y), Value::Int(x)) => {
234            (*x as f64 - y).abs() < f64::EPSILON
235        }
236        (Value::Bool(x), Value::Bool(y)) => x == y,
237        (Value::String(x), Value::String(y)) => x == y,
238        (Value::Char(x), Value::Char(y)) => x == y,
239        (Value::Null, Value::Null) => true,
240        (Value::Empty, Value::Empty) => true,
241        (Value::Infinity, Value::Infinity) => true,
242        _ => false,
243    }
244}
245
246// ============================================================================
247// CORE FUNCTIONS
248// ============================================================================
249
250fn register_core(interp: &mut Interpreter) {
251    // --- PRIMITIVE TYPE CONSTANTS ---
252    // u64::MAX, i64::MAX, etc.
253    interp.globals.borrow_mut().define("u64·MAX".to_string(), Value::Int(u64::MAX as i64));
254    interp.globals.borrow_mut().define("u64·MIN".to_string(), Value::Int(0));
255    interp.globals.borrow_mut().define("i64·MAX".to_string(), Value::Int(i64::MAX));
256    interp.globals.borrow_mut().define("i64·MIN".to_string(), Value::Int(i64::MIN));
257    interp.globals.borrow_mut().define("u32·MAX".to_string(), Value::Int(u32::MAX as i64));
258    interp.globals.borrow_mut().define("u32·MIN".to_string(), Value::Int(0));
259    interp.globals.borrow_mut().define("i32·MAX".to_string(), Value::Int(i32::MAX as i64));
260    interp.globals.borrow_mut().define("i32·MIN".to_string(), Value::Int(i32::MIN as i64));
261    interp.globals.borrow_mut().define("u16·MAX".to_string(), Value::Int(u16::MAX as i64));
262    interp.globals.borrow_mut().define("u8·MAX".to_string(), Value::Int(u8::MAX as i64));
263    interp.globals.borrow_mut().define("usize·MAX".to_string(), Value::Int(usize::MAX as i64));
264    interp.globals.borrow_mut().define("isize·MAX".to_string(), Value::Int(isize::MAX as i64));
265    interp.globals.borrow_mut().define("isize·MIN".to_string(), Value::Int(isize::MIN as i64));
266    interp.globals.borrow_mut().define("f64·INFINITY".to_string(), Value::Float(f64::INFINITY));
267    interp.globals.borrow_mut().define("f64·NEG_INFINITY".to_string(), Value::Float(f64::NEG_INFINITY));
268    interp.globals.borrow_mut().define("f64·NAN".to_string(), Value::Float(f64::NAN));
269
270    // SeekFrom enum variants for file seeking (register as variant constructors)
271    interp.variant_constructors.insert("SeekFrom·Start".to_string(), ("SeekFrom".to_string(), "Start".to_string(), 1));
272    interp.variant_constructors.insert("SeekFrom·End".to_string(), ("SeekFrom".to_string(), "End".to_string(), 1));
273    interp.variant_constructors.insert("SeekFrom·Current".to_string(), ("SeekFrom".to_string(), "Current".to_string(), 1));
274
275    // Atomic Ordering enum variants (used by std::sync::atomic)
276    let ordering_variants = ["SeqCst", "Acquire", "Release", "AcqRel", "Relaxed"];
277    for variant in ordering_variants {
278        let full_name = format!("std·sync·atomic·Ordering·{}", variant);
279        let short_name = format!("Ordering·{}", variant);
280        interp.globals.borrow_mut().define(full_name, Value::Variant {
281            enum_name: "Ordering".to_string(),
282            variant_name: variant.to_string(),
283            fields: None,
284        });
285        interp.globals.borrow_mut().define(short_name, Value::Variant {
286            enum_name: "Ordering".to_string(),
287            variant_name: variant.to_string(),
288            fields: None,
289        });
290    }
291
292    // IO ErrorKind enum variants (used by std::io::ErrorKind)
293    let error_kind_variants = ["NotFound", "PermissionDenied", "ConnectionRefused", "ConnectionReset",
294        "ConnectionAborted", "NotConnected", "AddrInUse", "AddrNotAvailable", "BrokenPipe",
295        "AlreadyExists", "WouldBlock", "InvalidInput", "InvalidData", "TimedOut", "WriteZero",
296        "Interrupted", "UnexpectedEof", "Other"];
297    for variant in error_kind_variants {
298        let full_name = format!("std·io·ErrorKind·{}", variant);
299        let short_name = format!("ErrorKind·{}", variant);
300        interp.globals.borrow_mut().define(full_name, Value::Variant {
301            enum_name: "ErrorKind".to_string(),
302            variant_name: variant.to_string(),
303            fields: None,
304        });
305        interp.globals.borrow_mut().define(short_name, Value::Variant {
306            enum_name: "ErrorKind".to_string(),
307            variant_name: variant.to_string(),
308            fields: None,
309        });
310    }
311
312    // print - variadic print without newline
313    define(interp, "print", None, |interp, args| {
314        let output: Vec<String> = args.iter().map(|v| format!("{}", v)).collect();
315        let line = output.join(" ");
316        print!("{}", line);
317        std::io::stdout().flush().ok();
318        interp.output.push(line);
319        Ok(Value::Null)
320    });
321
322    // println - print with newline
323    define(interp, "println", None, |interp, args| {
324        let output: Vec<String> = args.iter().map(|v| format!("{}", v)).collect();
325        let line = output.join(" ");
326        println!("{}", line);
327        interp.output.push(line);
328        Ok(Value::Null)
329    });
330
331    // eprint - print to stderr without newline
332    define(interp, "eprint", None, |interp, args| {
333        let output: Vec<String> = args.iter().map(|v| format!("{}", v)).collect();
334        let line = output.join(" ");
335        eprint!("{}", line);
336        std::io::stderr().flush().ok();
337        interp.output.push(line);
338        Ok(Value::Null)
339    });
340
341    // eprintln - print to stderr with newline
342    define(interp, "eprintln", None, |interp, args| {
343        let output: Vec<String> = args.iter().map(|v| format!("{}", v)).collect();
344        let line = output.join(" ");
345        eprintln!("{}", line);
346        interp.output.push(line);
347        Ok(Value::Null)
348    });
349
350    // dbg - debug print with source info
351    define(interp, "dbg", Some(1), |interp, args| {
352        let output = format!("[DEBUG] {:?}", args[0]);
353        println!("{}", output);
354        interp.output.push(output);
355        Ok(args[0].clone())
356    });
357
358    // type_of - get type name
359    define(interp, "type_of", Some(1), |_, args| {
360        let type_name = match &args[0] {
361            Value::Null => "null",
362            Value::Bool(_) => "bool",
363            Value::Int(_) => "i64",
364            Value::Float(_) => "f64",
365            Value::String(_) => "str",
366            Value::Char(_) => "char",
367            Value::Array(_) => "array",
368            Value::Tuple(_) => "tuple",
369            Value::Struct { name, .. } => name,
370            Value::Variant { enum_name, .. } => enum_name,
371            Value::Function(_) => "fn",
372            Value::BuiltIn(_) => "builtin",
373            Value::Ref(_) => "ref",
374            Value::Infinity => "infinity",
375            Value::Empty => "empty",
376            Value::Evidential { evidence, .. } => match evidence {
377                Evidence::Known => "known",
378                Evidence::Uncertain => "uncertain",
379                Evidence::Reported => "reported",
380                Evidence::Paradox => "paradox",
381            },
382            Value::Affective { .. } => "affective",
383            Value::Map(_) => "map",
384            Value::Set(_) => "set",
385            Value::Channel(_) => "channel",
386            Value::ThreadHandle(_) => "thread",
387            Value::Actor(_) => "actor",
388            Value::Future(_) => "future",
389            Value::VariantConstructor { .. } => "variant_constructor",
390            Value::DefaultConstructor { .. } => "default_constructor",
391            Value::Range { .. } => "range",
392            Value::RefCellValue(_) => "refcell",
393            Value::TraitObject { trait_name, .. } => return Ok(Value::String(Rc::new(format!("dyn {}", trait_name)))),
394        };
395        Ok(Value::String(Rc::new(type_name.to_string())))
396    });
397
398    // assert - assertion with optional message
399    define(interp, "assert", None, |_, args| {
400        if args.is_empty() {
401            return Err(RuntimeError::new("assert() requires at least one argument"));
402        }
403        let condition = match &args[0] {
404            Value::Bool(b) => *b,
405            _ => return Err(RuntimeError::new("assert() condition must be bool")),
406        };
407        if !condition {
408            let msg = if args.len() > 1 {
409                format!("{}", args[1])
410            } else {
411                "assertion failed".to_string()
412            };
413            return Err(RuntimeError::new(format!("Assertion failed: {}", msg)));
414        }
415        Ok(Value::Null)
416    });
417
418    // panic - abort execution with message
419    define(interp, "panic", None, |_, args| {
420        let msg = if args.is_empty() {
421            "explicit panic".to_string()
422        } else {
423            args.iter()
424                .map(|v| format!("{}", v))
425                .collect::<Vec<_>>()
426                .join(" ")
427        };
428        Err(RuntimeError::new(format!("PANIC: {}", msg)))
429    });
430
431    // todo - mark unimplemented code
432    define(interp, "todo", None, |_, args| {
433        let msg = if args.is_empty() {
434            "not yet implemented".to_string()
435        } else {
436            format!("{}", args[0])
437        };
438        Err(RuntimeError::new(format!("TODO: {}", msg)))
439    });
440
441    // unreachable - mark code that should never execute
442    define(interp, "unreachable", None, |_, args| {
443        let msg = if args.is_empty() {
444            "entered unreachable code".to_string()
445        } else {
446            format!("{}", args[0])
447        };
448        Err(RuntimeError::new(format!("UNREACHABLE: {}", msg)))
449    });
450
451    // clone - deep clone a value
452    define(interp, "clone", Some(1), |_, args| Ok(deep_clone(&args[0])));
453
454    // identity - return value unchanged (useful in pipes)
455    define(interp, "id", Some(1), |_, args| Ok(args[0].clone()));
456
457    // default - return default value for a type
458    // Can be called with 0 args (when context provides type) or 1 arg (type name string)
459    define(interp, "default", None, |interp, args| {
460        let type_name = if args.is_empty() {
461            // When called with 0 args (e.g., from TypeName::default() fallback),
462            // try to use current_self_type or return a generic empty struct
463            match &interp.current_self_type {
464                Some(t) => t.clone(),
465                None => return Ok(Value::Struct {
466                    name: "Default".to_string(),
467                    fields: Rc::new(RefCell::new(std::collections::HashMap::new())),
468                }),
469            }
470        } else {
471            match &args[0] {
472                Value::String(s) => s.to_string(),
473                _ => return Err(RuntimeError::new("default() requires type name string")),
474            }
475        };
476        let type_name = type_name.as_str();
477        match type_name {
478            "bool" => Ok(Value::Bool(false)),
479            "i64" | "int" => Ok(Value::Int(0)),
480            "f64" | "float" => Ok(Value::Float(0.0)),
481            "str" | "string" => Ok(Value::String(Rc::new(String::new()))),
482            "array" => Ok(Value::Array(Rc::new(RefCell::new(Vec::new())))),
483            _ => {
484                // Check if type is registered in default_structs
485                if let Some(struct_def) = interp.default_structs.get(type_name).cloned() {
486                    use crate::ast::StructFields;
487                    let mut fields = std::collections::HashMap::new();
488                    if let StructFields::Named(field_defs) = &struct_def.fields {
489                        for field in field_defs {
490                            // Use field default expression if available, otherwise Null
491                            let default_val = if let Some(ref default_expr) = field.default {
492                                match interp.evaluate(default_expr) {
493                                    Ok(v) => v,
494                                    Err(_) => Value::Null,
495                                }
496                            } else {
497                                Value::Null
498                            };
499                            fields.insert(field.name.name.clone(), default_val);
500                        }
501                    }
502                    Ok(Value::Struct {
503                        name: type_name.to_string(),
504                        fields: Rc::new(RefCell::new(fields)),
505                    })
506                } else {
507                    // For unknown types (e.g., from external crates), create empty struct
508                    Ok(Value::Struct {
509                        name: type_name.to_string(),
510                        fields: Rc::new(RefCell::new(std::collections::HashMap::new())),
511                    })
512                }
513            }
514        }
515    });
516
517    // Result::Ok - create Ok variant
518    define(interp, "Result·Ok", Some(1), |_, args| {
519        Ok(Value::Variant {
520            enum_name: "Result".to_string(),
521            variant_name: "Ok".to_string(),
522            fields: Some(Rc::new(vec![args[0].clone()])),
523        })
524    });
525
526    // Ok shorthand (without Result:: prefix)
527    define(interp, "Ok", Some(1), |_, args| {
528        Ok(Value::Variant {
529            enum_name: "Result".to_string(),
530            variant_name: "Ok".to_string(),
531            fields: Some(Rc::new(vec![args[0].clone()])),
532        })
533    });
534
535    // Result::Err - create Err variant
536    define(interp, "Result·Err", Some(1), |_, args| {
537        Ok(Value::Variant {
538            enum_name: "Result".to_string(),
539            variant_name: "Err".to_string(),
540            fields: Some(Rc::new(vec![args[0].clone()])),
541        })
542    });
543
544    // Err shorthand (without Result:: prefix)
545    define(interp, "Err", Some(1), |_, args| {
546        Ok(Value::Variant {
547            enum_name: "Result".to_string(),
548            variant_name: "Err".to_string(),
549            fields: Some(Rc::new(vec![args[0].clone()])),
550        })
551    });
552
553    // Option::Some - create Some variant
554    define(interp, "Option·Some", Some(1), |_, args| {
555        Ok(Value::Variant {
556            enum_name: "Option".to_string(),
557            variant_name: "Some".to_string(),
558            fields: Some(Rc::new(vec![args[0].clone()])),
559        })
560    });
561
562    // Some shorthand (without Option:: prefix)
563    define(interp, "Some", Some(1), |_, args| {
564        Ok(Value::Variant {
565            enum_name: "Option".to_string(),
566            variant_name: "Some".to_string(),
567            fields: Some(Rc::new(vec![args[0].clone()])),
568        })
569    });
570
571    // Option::None - create None variant (direct value, not a function)
572    interp.globals.borrow_mut().define(
573        "Option·None".to_string(),
574        Value::Variant {
575            enum_name: "Option".to_string(),
576            variant_name: "None".to_string(),
577            fields: None,
578        },
579    );
580
581    // None shorthand (without Option:: prefix) - direct value
582    interp.globals.borrow_mut().define(
583        "None".to_string(),
584        Value::Variant {
585            enum_name: "Option".to_string(),
586            variant_name: "None".to_string(),
587            fields: None,
588        },
589    );
590
591    // Map::new - create empty map
592    define(interp, "Map·new", Some(0), |_, _| {
593        Ok(Value::Map(Rc::new(RefCell::new(HashMap::new()))))
594    });
595
596    // HashMap::new
597    define(interp, "HashMap·new", Some(0), |_, _| {
598        Ok(Value::Map(Rc::new(RefCell::new(HashMap::new()))))
599    });
600
601    // HashMap::with_capacity
602    define(interp, "HashMap·with_capacity", Some(1), |_, _args| {
603        // Capacity hint is ignored in our implementation
604        Ok(Value::Map(Rc::new(RefCell::new(HashMap::new()))))
605    });
606
607    // std::collections::HashMap::new
608    define(interp, "std·collections·HashMap·new", Some(0), |_, _| {
609        Ok(Value::Map(Rc::new(RefCell::new(HashMap::new()))))
610    });
611
612    // std::collections::HashMap::with_capacity
613    define(interp, "std·collections·HashMap·with_capacity", Some(1), |_, _args| {
614        Ok(Value::Map(Rc::new(RefCell::new(HashMap::new()))))
615    });
616
617    // HashSet::new
618    define(interp, "HashSet·new", Some(0), |_, _| {
619        Ok(Value::Set(Rc::new(RefCell::new(std::collections::HashSet::new()))))
620    });
621
622    // HashSet::with_capacity
623    define(interp, "HashSet·with_capacity", Some(1), |_, _args| {
624        Ok(Value::Set(Rc::new(RefCell::new(std::collections::HashSet::new()))))
625    });
626
627    // std::collections::HashSet::new
628    define(interp, "std·collections·HashSet·new", Some(0), |_, _| {
629        Ok(Value::Set(Rc::new(RefCell::new(std::collections::HashSet::new()))))
630    });
631
632    // Vec::new - create empty vector/array
633    define(interp, "Vec·new", Some(0), |_, _| {
634        Ok(Value::Array(Rc::new(RefCell::new(Vec::new()))))
635    });
636
637    // String::new - create empty string
638    define(interp, "String·new", Some(0), |_, _| {
639        Ok(Value::String(Rc::new(String::new())))
640    });
641
642    // String::from - create string from value
643    define(interp, "String·from", Some(1), |_, args| {
644        let s = match &args[0] {
645            Value::String(s) => (**s).clone(),
646            Value::Int(n) => n.to_string(),
647            Value::Float(f) => f.to_string(),
648            Value::Bool(b) => b.to_string(),
649            Value::Char(c) => c.to_string(),
650            _ => format!("{}", args[0]),
651        };
652        Ok(Value::String(Rc::new(s)))
653    });
654
655    // Box::new - just return the value (Box is transparent in interpreter)
656    define(interp, "Box·new", Some(1), |_, args| {
657        Ok(args[0].clone())
658    });
659
660    // String::from_raw_parts - FFI emulation: construct string from "pointer", len, capacity
661    define(interp, "String·from_raw_parts", Some(3), |_, args| {
662        // In our FFI emulation, the first arg is already the string content
663        match &args[0] {
664            Value::String(s) => Ok(Value::String(s.clone())),
665            Value::Null => Ok(Value::String(Rc::new(String::new()))),
666            _ => Ok(Value::String(Rc::new(format!("{}", args[0])))),
667        }
668    });
669
670    // slice::from_raw_parts - FFI emulation
671    define(interp, "slice·from_raw_parts", Some(2), |_, args| {
672        // First arg is the "pointer" (string), second is len
673        match &args[0] {
674            Value::String(s) => Ok(Value::String(s.clone())),
675            Value::Array(arr) => Ok(Value::Array(arr.clone())),
676            _ => Ok(args[0].clone()),
677        }
678    });
679}
680
681// Deep clone helper
682fn deep_clone(value: &Value) -> Value {
683    match value {
684        Value::Array(arr) => {
685            let cloned: Vec<Value> = arr.borrow().iter().map(deep_clone).collect();
686            Value::Array(Rc::new(RefCell::new(cloned)))
687        }
688        Value::Struct { name, fields } => {
689            let cloned: HashMap<String, Value> = fields
690                .borrow()
691                .iter()
692                .map(|(k, v)| (k.clone(), deep_clone(v)))
693                .collect();
694            Value::Struct {
695                name: name.clone(),
696                fields: Rc::new(RefCell::new(cloned)),
697            }
698        }
699        Value::Evidential { value, evidence } => Value::Evidential {
700            value: Box::new(deep_clone(value)),
701            evidence: *evidence,
702        },
703        other => other.clone(),
704    }
705}
706
707// ============================================================================
708// MATH FUNCTIONS
709// ============================================================================
710
711fn register_math(interp: &mut Interpreter) {
712    // Basic math
713    define(interp, "abs", Some(1), |_, args| match &args[0] {
714        Value::Int(n) => Ok(Value::Int(n.abs())),
715        Value::Float(n) => Ok(Value::Float(n.abs())),
716        _ => Err(RuntimeError::new("abs() requires number")),
717    });
718
719    define(interp, "neg", Some(1), |_, args| match &args[0] {
720        Value::Int(n) => Ok(Value::Int(-n)),
721        Value::Float(n) => Ok(Value::Float(-n)),
722        _ => Err(RuntimeError::new("neg() requires number")),
723    });
724
725    define(interp, "sqrt", Some(1), |_, args| match &args[0] {
726        Value::Int(n) => Ok(Value::Float((*n as f64).sqrt())),
727        Value::Float(n) => Ok(Value::Float(n.sqrt())),
728        _ => Err(RuntimeError::new("sqrt() requires number")),
729    });
730
731    define(interp, "cbrt", Some(1), |_, args| match &args[0] {
732        Value::Int(n) => Ok(Value::Float((*n as f64).cbrt())),
733        Value::Float(n) => Ok(Value::Float(n.cbrt())),
734        _ => Err(RuntimeError::new("cbrt() requires number")),
735    });
736
737    define(interp, "pow", Some(2), |_, args| {
738        match (&args[0], &args[1]) {
739            (Value::Int(base), Value::Int(exp)) => {
740                if *exp >= 0 {
741                    Ok(Value::Int(base.pow(*exp as u32)))
742                } else {
743                    Ok(Value::Float((*base as f64).powi(*exp as i32)))
744                }
745            }
746            (Value::Float(base), Value::Int(exp)) => Ok(Value::Float(base.powi(*exp as i32))),
747            (Value::Float(base), Value::Float(exp)) => Ok(Value::Float(base.powf(*exp))),
748            (Value::Int(base), Value::Float(exp)) => Ok(Value::Float((*base as f64).powf(*exp))),
749            _ => Err(RuntimeError::new("pow() requires numbers")),
750        }
751    });
752
753    define(interp, "exp", Some(1), |_, args| match &args[0] {
754        Value::Int(n) => Ok(Value::Float((*n as f64).exp())),
755        Value::Float(n) => Ok(Value::Float(n.exp())),
756        _ => Err(RuntimeError::new("exp() requires number")),
757    });
758
759    define(interp, "ln", Some(1), |_, args| match &args[0] {
760        Value::Int(n) => Ok(Value::Float((*n as f64).ln())),
761        Value::Float(n) => Ok(Value::Float(n.ln())),
762        _ => Err(RuntimeError::new("ln() requires number")),
763    });
764
765    define(interp, "log", Some(2), |_, args| {
766        let (value, base) = match (&args[0], &args[1]) {
767            (Value::Int(v), Value::Int(b)) => (*v as f64, *b as f64),
768            (Value::Float(v), Value::Int(b)) => (*v, *b as f64),
769            (Value::Int(v), Value::Float(b)) => (*v as f64, *b),
770            (Value::Float(v), Value::Float(b)) => (*v, *b),
771            _ => return Err(RuntimeError::new("log() requires numbers")),
772        };
773        Ok(Value::Float(value.log(base)))
774    });
775
776    define(interp, "log10", Some(1), |_, args| match &args[0] {
777        Value::Int(n) => Ok(Value::Float((*n as f64).log10())),
778        Value::Float(n) => Ok(Value::Float(n.log10())),
779        _ => Err(RuntimeError::new("log10() requires number")),
780    });
781
782    define(interp, "log2", Some(1), |_, args| match &args[0] {
783        Value::Int(n) => Ok(Value::Float((*n as f64).log2())),
784        Value::Float(n) => Ok(Value::Float(n.log2())),
785        _ => Err(RuntimeError::new("log2() requires number")),
786    });
787
788    // Trigonometry
789    define(interp, "sin", Some(1), |_, args| match &args[0] {
790        Value::Int(n) => Ok(Value::Float((*n as f64).sin())),
791        Value::Float(n) => Ok(Value::Float(n.sin())),
792        _ => Err(RuntimeError::new("sin() requires number")),
793    });
794
795    define(interp, "cos", Some(1), |_, args| match &args[0] {
796        Value::Int(n) => Ok(Value::Float((*n as f64).cos())),
797        Value::Float(n) => Ok(Value::Float(n.cos())),
798        _ => Err(RuntimeError::new("cos() requires number")),
799    });
800
801    define(interp, "tan", Some(1), |_, args| match &args[0] {
802        Value::Int(n) => Ok(Value::Float((*n as f64).tan())),
803        Value::Float(n) => Ok(Value::Float(n.tan())),
804        _ => Err(RuntimeError::new("tan() requires number")),
805    });
806
807    define(interp, "asin", Some(1), |_, args| match &args[0] {
808        Value::Int(n) => Ok(Value::Float((*n as f64).asin())),
809        Value::Float(n) => Ok(Value::Float(n.asin())),
810        _ => Err(RuntimeError::new("asin() requires number")),
811    });
812
813    define(interp, "acos", Some(1), |_, args| match &args[0] {
814        Value::Int(n) => Ok(Value::Float((*n as f64).acos())),
815        Value::Float(n) => Ok(Value::Float(n.acos())),
816        _ => Err(RuntimeError::new("acos() requires number")),
817    });
818
819    define(interp, "atan", Some(1), |_, args| match &args[0] {
820        Value::Int(n) => Ok(Value::Float((*n as f64).atan())),
821        Value::Float(n) => Ok(Value::Float(n.atan())),
822        _ => Err(RuntimeError::new("atan() requires number")),
823    });
824
825    define(interp, "atan2", Some(2), |_, args| {
826        let (y, x) = match (&args[0], &args[1]) {
827            (Value::Int(y), Value::Int(x)) => (*y as f64, *x as f64),
828            (Value::Float(y), Value::Int(x)) => (*y, *x as f64),
829            (Value::Int(y), Value::Float(x)) => (*y as f64, *x),
830            (Value::Float(y), Value::Float(x)) => (*y, *x),
831            _ => return Err(RuntimeError::new("atan2() requires numbers")),
832        };
833        Ok(Value::Float(y.atan2(x)))
834    });
835
836    // Hyperbolic
837    define(interp, "sinh", Some(1), |_, args| match &args[0] {
838        Value::Int(n) => Ok(Value::Float((*n as f64).sinh())),
839        Value::Float(n) => Ok(Value::Float(n.sinh())),
840        _ => Err(RuntimeError::new("sinh() requires number")),
841    });
842
843    define(interp, "cosh", Some(1), |_, args| match &args[0] {
844        Value::Int(n) => Ok(Value::Float((*n as f64).cosh())),
845        Value::Float(n) => Ok(Value::Float(n.cosh())),
846        _ => Err(RuntimeError::new("cosh() requires number")),
847    });
848
849    define(interp, "tanh", Some(1), |_, args| match &args[0] {
850        Value::Int(n) => Ok(Value::Float((*n as f64).tanh())),
851        Value::Float(n) => Ok(Value::Float(n.tanh())),
852        _ => Err(RuntimeError::new("tanh() requires number")),
853    });
854
855    // Rounding
856    define(interp, "floor", Some(1), |_, args| match &args[0] {
857        Value::Int(n) => Ok(Value::Int(*n)),
858        Value::Float(n) => Ok(Value::Int(n.floor() as i64)),
859        _ => Err(RuntimeError::new("floor() requires number")),
860    });
861
862    define(interp, "ceil", Some(1), |_, args| match &args[0] {
863        Value::Int(n) => Ok(Value::Int(*n)),
864        Value::Float(n) => Ok(Value::Int(n.ceil() as i64)),
865        _ => Err(RuntimeError::new("ceil() requires number")),
866    });
867
868    define(interp, "round", Some(1), |_, args| match &args[0] {
869        Value::Int(n) => Ok(Value::Int(*n)),
870        Value::Float(n) => Ok(Value::Int(n.round() as i64)),
871        _ => Err(RuntimeError::new("round() requires number")),
872    });
873
874    define(interp, "trunc", Some(1), |_, args| match &args[0] {
875        Value::Int(n) => Ok(Value::Int(*n)),
876        Value::Float(n) => Ok(Value::Int(n.trunc() as i64)),
877        _ => Err(RuntimeError::new("trunc() requires number")),
878    });
879
880    define(interp, "fract", Some(1), |_, args| match &args[0] {
881        Value::Int(_) => Ok(Value::Float(0.0)),
882        Value::Float(n) => Ok(Value::Float(n.fract())),
883        _ => Err(RuntimeError::new("fract() requires number")),
884    });
885
886    // Min/Max/Clamp
887    define(interp, "min", Some(2), |_, args| {
888        match (&args[0], &args[1]) {
889            (Value::Int(a), Value::Int(b)) => Ok(Value::Int(*a.min(b))),
890            (Value::Float(a), Value::Float(b)) => Ok(Value::Float(a.min(*b))),
891            (Value::Int(a), Value::Float(b)) => Ok(Value::Float((*a as f64).min(*b))),
892            (Value::Float(a), Value::Int(b)) => Ok(Value::Float(a.min(*b as f64))),
893            _ => Err(RuntimeError::new("min() requires numbers")),
894        }
895    });
896
897    define(interp, "max", Some(2), |_, args| {
898        match (&args[0], &args[1]) {
899            (Value::Int(a), Value::Int(b)) => Ok(Value::Int(*a.max(b))),
900            (Value::Float(a), Value::Float(b)) => Ok(Value::Float(a.max(*b))),
901            (Value::Int(a), Value::Float(b)) => Ok(Value::Float((*a as f64).max(*b))),
902            (Value::Float(a), Value::Int(b)) => Ok(Value::Float(a.max(*b as f64))),
903            _ => Err(RuntimeError::new("max() requires numbers")),
904        }
905    });
906
907    define(interp, "clamp", Some(3), |_, args| {
908        match (&args[0], &args[1], &args[2]) {
909            (Value::Int(val), Value::Int(min), Value::Int(max)) => {
910                Ok(Value::Int(*val.max(min).min(max)))
911            }
912            (Value::Float(val), Value::Float(min), Value::Float(max)) => {
913                Ok(Value::Float(val.max(*min).min(*max)))
914            }
915            _ => Err(RuntimeError::new("clamp() requires matching number types")),
916        }
917    });
918
919    // Sign
920    define(interp, "sign", Some(1), |_, args| match &args[0] {
921        Value::Int(n) => Ok(Value::Int(n.signum())),
922        Value::Float(n) => Ok(Value::Float(if *n > 0.0 {
923            1.0
924        } else if *n < 0.0 {
925            -1.0
926        } else {
927            0.0
928        })),
929        _ => Err(RuntimeError::new("sign() requires number")),
930    });
931
932    // Constants
933    define(interp, "PI", Some(0), |_, _| {
934        Ok(Value::Float(std::f64::consts::PI))
935    });
936    define(interp, "E", Some(0), |_, _| {
937        Ok(Value::Float(std::f64::consts::E))
938    });
939    define(interp, "TAU", Some(0), |_, _| {
940        Ok(Value::Float(std::f64::consts::TAU))
941    });
942    define(interp, "PHI", Some(0), |_, _| {
943        Ok(Value::Float(1.618033988749895))
944    }); // Golden ratio
945
946    // GCD/LCM
947    define(interp, "gcd", Some(2), |_, args| {
948        match (&args[0], &args[1]) {
949            (Value::Int(a), Value::Int(b)) => Ok(Value::Int(gcd(*a, *b))),
950            _ => Err(RuntimeError::new("gcd() requires integers")),
951        }
952    });
953
954    define(interp, "lcm", Some(2), |_, args| {
955        match (&args[0], &args[1]) {
956            (Value::Int(a), Value::Int(b)) => {
957                let g = gcd(*a, *b);
958                Ok(Value::Int((a * b).abs() / g))
959            }
960            _ => Err(RuntimeError::new("lcm() requires integers")),
961        }
962    });
963
964    // Factorial
965    define(interp, "factorial", Some(1), |_, args| match &args[0] {
966        Value::Int(n) if *n >= 0 => {
967            let mut result: i64 = 1;
968            for i in 2..=(*n as u64) {
969                result = result.saturating_mul(i as i64);
970            }
971            Ok(Value::Int(result))
972        }
973        Value::Int(_) => Err(RuntimeError::new(
974            "factorial() requires non-negative integer",
975        )),
976        _ => Err(RuntimeError::new("factorial() requires integer")),
977    });
978
979    // Is checks
980    define(interp, "is_nan", Some(1), |_, args| match &args[0] {
981        Value::Float(n) => Ok(Value::Bool(n.is_nan())),
982        Value::Int(_) => Ok(Value::Bool(false)),
983        _ => Err(RuntimeError::new("is_nan() requires number")),
984    });
985
986    define(interp, "is_infinite", Some(1), |_, args| match &args[0] {
987        Value::Float(n) => Ok(Value::Bool(n.is_infinite())),
988        Value::Int(_) => Ok(Value::Bool(false)),
989        Value::Infinity => Ok(Value::Bool(true)),
990        _ => Err(RuntimeError::new("is_infinite() requires number")),
991    });
992
993    define(interp, "is_finite", Some(1), |_, args| match &args[0] {
994        Value::Float(n) => Ok(Value::Bool(n.is_finite())),
995        Value::Int(_) => Ok(Value::Bool(true)),
996        Value::Infinity => Ok(Value::Bool(false)),
997        _ => Err(RuntimeError::new("is_finite() requires number")),
998    });
999
1000    define(interp, "is_even", Some(1), |_, args| match &args[0] {
1001        Value::Int(n) => Ok(Value::Bool(n % 2 == 0)),
1002        _ => Err(RuntimeError::new("is_even() requires integer")),
1003    });
1004
1005    define(interp, "is_odd", Some(1), |_, args| match &args[0] {
1006        Value::Int(n) => Ok(Value::Bool(n % 2 != 0)),
1007        _ => Err(RuntimeError::new("is_odd() requires integer")),
1008    });
1009
1010    define(interp, "is_prime", Some(1), |_, args| match &args[0] {
1011        Value::Int(n) => Ok(Value::Bool(is_prime(*n))),
1012        _ => Err(RuntimeError::new("is_prime() requires integer")),
1013    });
1014}
1015
1016fn gcd(mut a: i64, mut b: i64) -> i64 {
1017    a = a.abs();
1018    b = b.abs();
1019    while b != 0 {
1020        let t = b;
1021        b = a % b;
1022        a = t;
1023    }
1024    a
1025}
1026
1027fn is_prime(n: i64) -> bool {
1028    if n < 2 {
1029        return false;
1030    }
1031    if n == 2 {
1032        return true;
1033    }
1034    if n % 2 == 0 {
1035        return false;
1036    }
1037    let sqrt = (n as f64).sqrt() as i64;
1038    for i in (3..=sqrt).step_by(2) {
1039        if n % i == 0 {
1040            return false;
1041        }
1042    }
1043    true
1044}
1045
1046// ============================================================================
1047// COLLECTION FUNCTIONS
1048// ============================================================================
1049
1050fn register_collections(interp: &mut Interpreter) {
1051    // Basic operations
1052    define(interp, "len", Some(1), |_, args| match &args[0] {
1053        Value::Array(arr) => Ok(Value::Int(arr.borrow().len() as i64)),
1054        Value::String(s) => Ok(Value::Int(s.chars().count() as i64)),
1055        Value::Tuple(t) => Ok(Value::Int(t.len() as i64)),
1056        Value::Map(m) => Ok(Value::Int(m.borrow().len() as i64)),
1057        Value::Set(s) => Ok(Value::Int(s.borrow().len() as i64)),
1058        _ => Err(RuntimeError::new(
1059            "len() requires array, string, tuple, map, or set",
1060        )),
1061    });
1062
1063    define(interp, "is_empty", Some(1), |_, args| match &args[0] {
1064        Value::Array(arr) => Ok(Value::Bool(arr.borrow().is_empty())),
1065        Value::String(s) => Ok(Value::Bool(s.is_empty())),
1066        Value::Tuple(t) => Ok(Value::Bool(t.is_empty())),
1067        Value::Map(m) => Ok(Value::Bool(m.borrow().is_empty())),
1068        Value::Set(s) => Ok(Value::Bool(s.borrow().is_empty())),
1069        _ => Err(RuntimeError::new("is_empty() requires collection")),
1070    });
1071
1072    // Array operations
1073    define(interp, "push", Some(2), |_, args| match &args[0] {
1074        Value::Array(arr) => {
1075            arr.borrow_mut().push(args[1].clone());
1076            Ok(Value::Null)
1077        }
1078        _ => Err(RuntimeError::new("push() requires array")),
1079    });
1080
1081    define(interp, "pop", Some(1), |_, args| match &args[0] {
1082        Value::Array(arr) => arr
1083            .borrow_mut()
1084            .pop()
1085            .ok_or_else(|| RuntimeError::new("pop() on empty array")),
1086        _ => Err(RuntimeError::new("pop() requires array")),
1087    });
1088
1089    define(interp, "first", Some(1), |_, args| match &args[0] {
1090        Value::Array(arr) => arr
1091            .borrow()
1092            .first()
1093            .cloned()
1094            .ok_or_else(|| RuntimeError::new("first() on empty array")),
1095        Value::Tuple(t) => t
1096            .first()
1097            .cloned()
1098            .ok_or_else(|| RuntimeError::new("first() on empty tuple")),
1099        _ => Err(RuntimeError::new("first() requires array or tuple")),
1100    });
1101
1102    define(interp, "last", Some(1), |_, args| match &args[0] {
1103        Value::Array(arr) => arr
1104            .borrow()
1105            .last()
1106            .cloned()
1107            .ok_or_else(|| RuntimeError::new("last() on empty array")),
1108        Value::Tuple(t) => t
1109            .last()
1110            .cloned()
1111            .ok_or_else(|| RuntimeError::new("last() on empty tuple")),
1112        _ => Err(RuntimeError::new("last() requires array or tuple")),
1113    });
1114
1115    // μ (mu) - middle/median element
1116    define(interp, "middle", Some(1), |_, args| match &args[0] {
1117        Value::Array(arr) => {
1118            let arr = arr.borrow();
1119            if arr.is_empty() {
1120                return Err(RuntimeError::new("middle() on empty array"));
1121            }
1122            let mid = arr.len() / 2;
1123            Ok(arr[mid].clone())
1124        }
1125        Value::Tuple(t) => {
1126            if t.is_empty() {
1127                return Err(RuntimeError::new("middle() on empty tuple"));
1128            }
1129            let mid = t.len() / 2;
1130            Ok(t[mid].clone())
1131        }
1132        _ => Err(RuntimeError::new("middle() requires array or tuple")),
1133    });
1134
1135    // χ (chi) - random choice from collection
1136    define(interp, "choice", Some(1), |_, args| {
1137        use std::time::{SystemTime, UNIX_EPOCH};
1138        match &args[0] {
1139            Value::Array(arr) => {
1140                let arr = arr.borrow();
1141                if arr.is_empty() {
1142                    return Err(RuntimeError::new("choice() on empty array"));
1143                }
1144                let seed = SystemTime::now()
1145                    .duration_since(UNIX_EPOCH)
1146                    .unwrap_or(std::time::Duration::ZERO)
1147                    .as_nanos() as u64;
1148                let idx = ((seed.wrapping_mul(1103515245).wrapping_add(12345)) >> 16) as usize
1149                    % arr.len();
1150                Ok(arr[idx].clone())
1151            }
1152            Value::Tuple(t) => {
1153                if t.is_empty() {
1154                    return Err(RuntimeError::new("choice() on empty tuple"));
1155                }
1156                let seed = SystemTime::now()
1157                    .duration_since(UNIX_EPOCH)
1158                    .unwrap_or(std::time::Duration::ZERO)
1159                    .as_nanos() as u64;
1160                let idx =
1161                    ((seed.wrapping_mul(1103515245).wrapping_add(12345)) >> 16) as usize % t.len();
1162                Ok(t[idx].clone())
1163            }
1164            _ => Err(RuntimeError::new("choice() requires array or tuple")),
1165        }
1166    });
1167
1168    // ν (nu) - nth element (alias for get with better semantics)
1169    define(interp, "nth", Some(2), |_, args| {
1170        let n = match &args[1] {
1171            Value::Int(i) => *i,
1172            _ => return Err(RuntimeError::new("nth() index must be integer")),
1173        };
1174        match &args[0] {
1175            Value::Array(arr) => {
1176                let arr = arr.borrow();
1177                if n < 0 || n as usize >= arr.len() {
1178                    return Err(RuntimeError::new("nth() index out of bounds"));
1179                }
1180                Ok(arr[n as usize].clone())
1181            }
1182            Value::Tuple(t) => {
1183                if n < 0 || n as usize >= t.len() {
1184                    return Err(RuntimeError::new("nth() index out of bounds"));
1185                }
1186                Ok(t[n as usize].clone())
1187            }
1188            _ => Err(RuntimeError::new("nth() requires array or tuple")),
1189        }
1190    });
1191
1192    // ξ (xi) - next: pop and return first element (advances iterator)
1193    define(interp, "next", Some(1), |_, args| match &args[0] {
1194        Value::Array(arr) => {
1195            let mut arr = arr.borrow_mut();
1196            if arr.is_empty() {
1197                return Err(RuntimeError::new("next() on empty array"));
1198            }
1199            Ok(arr.remove(0))
1200        }
1201        _ => Err(RuntimeError::new("next() requires array")),
1202    });
1203
1204    // peek - look at first element without consuming (for iterators)
1205    define(interp, "peek", Some(1), |_, args| match &args[0] {
1206        Value::Array(arr) => arr
1207            .borrow()
1208            .first()
1209            .cloned()
1210            .ok_or_else(|| RuntimeError::new("peek() on empty array")),
1211        _ => Err(RuntimeError::new("peek() requires array")),
1212    });
1213
1214    define(interp, "get", Some(2), |_, args| {
1215        let index = match &args[1] {
1216            Value::Int(i) => *i,
1217            _ => return Err(RuntimeError::new("get() index must be integer")),
1218        };
1219        match &args[0] {
1220            Value::Array(arr) => {
1221                let arr = arr.borrow();
1222                let idx = if index < 0 {
1223                    arr.len() as i64 + index
1224                } else {
1225                    index
1226                } as usize;
1227                arr.get(idx)
1228                    .cloned()
1229                    .ok_or_else(|| RuntimeError::new("index out of bounds"))
1230            }
1231            Value::Tuple(t) => {
1232                let idx = if index < 0 {
1233                    t.len() as i64 + index
1234                } else {
1235                    index
1236                } as usize;
1237                t.get(idx)
1238                    .cloned()
1239                    .ok_or_else(|| RuntimeError::new("index out of bounds"))
1240            }
1241            _ => Err(RuntimeError::new("get() requires array or tuple")),
1242        }
1243    });
1244
1245    define(interp, "set", Some(3), |_, args| {
1246        let index = match &args[1] {
1247            Value::Int(i) => *i as usize,
1248            _ => return Err(RuntimeError::new("set() index must be integer")),
1249        };
1250        match &args[0] {
1251            Value::Array(arr) => {
1252                let mut arr = arr.borrow_mut();
1253                if index >= arr.len() {
1254                    return Err(RuntimeError::new("index out of bounds"));
1255                }
1256                arr[index] = args[2].clone();
1257                Ok(Value::Null)
1258            }
1259            _ => Err(RuntimeError::new("set() requires array")),
1260        }
1261    });
1262
1263    define(interp, "insert", Some(3), |_, args| {
1264        let index = match &args[1] {
1265            Value::Int(i) => *i as usize,
1266            _ => return Err(RuntimeError::new("insert() index must be integer")),
1267        };
1268        match &args[0] {
1269            Value::Array(arr) => {
1270                let mut arr = arr.borrow_mut();
1271                if index > arr.len() {
1272                    return Err(RuntimeError::new("index out of bounds"));
1273                }
1274                arr.insert(index, args[2].clone());
1275                Ok(Value::Null)
1276            }
1277            _ => Err(RuntimeError::new("insert() requires array")),
1278        }
1279    });
1280
1281    define(interp, "remove", Some(2), |_, args| {
1282        let index = match &args[1] {
1283            Value::Int(i) => *i as usize,
1284            _ => return Err(RuntimeError::new("remove() index must be integer")),
1285        };
1286        match &args[0] {
1287            Value::Array(arr) => {
1288                let mut arr = arr.borrow_mut();
1289                if index >= arr.len() {
1290                    return Err(RuntimeError::new("index out of bounds"));
1291                }
1292                Ok(arr.remove(index))
1293            }
1294            _ => Err(RuntimeError::new("remove() requires array")),
1295        }
1296    });
1297
1298    define(interp, "clear", Some(1), |_, args| match &args[0] {
1299        Value::Array(arr) => {
1300            arr.borrow_mut().clear();
1301            Ok(Value::Null)
1302        }
1303        _ => Err(RuntimeError::new("clear() requires array")),
1304    });
1305
1306    // Searching
1307    define(interp, "contains", Some(2), |_, args| match &args[0] {
1308        Value::Array(arr) => Ok(Value::Bool(
1309            arr.borrow().iter().any(|v| values_equal(v, &args[1])),
1310        )),
1311        Value::String(s) => match &args[1] {
1312            Value::String(sub) => Ok(Value::Bool(s.contains(sub.as_str()))),
1313            Value::Char(c) => Ok(Value::Bool(s.contains(*c))),
1314            _ => Err(RuntimeError::new(
1315                "string contains() requires string or char",
1316            )),
1317        },
1318        _ => Err(RuntimeError::new("contains() requires array or string")),
1319    });
1320
1321    define(interp, "index_of", Some(2), |_, args| match &args[0] {
1322        Value::Array(arr) => {
1323            let idx = arr.borrow().iter().position(|v| values_equal(v, &args[1]));
1324            match idx {
1325                Some(i) => Ok(Value::Int(i as i64)),
1326                None => Ok(Value::Int(-1)),
1327            }
1328        }
1329        Value::String(s) => match &args[1] {
1330            Value::String(sub) => match s.find(sub.as_str()) {
1331                Some(i) => Ok(Value::Int(i as i64)),
1332                None => Ok(Value::Int(-1)),
1333            },
1334            Value::Char(c) => match s.find(*c) {
1335                Some(i) => Ok(Value::Int(i as i64)),
1336                None => Ok(Value::Int(-1)),
1337            },
1338            _ => Err(RuntimeError::new(
1339                "string index_of() requires string or char",
1340            )),
1341        },
1342        _ => Err(RuntimeError::new("index_of() requires array or string")),
1343    });
1344
1345    // Transformations
1346    define(interp, "reverse", Some(1), |_, args| match &args[0] {
1347        Value::Array(arr) => {
1348            let mut reversed: Vec<Value> = arr.borrow().clone();
1349            reversed.reverse();
1350            Ok(Value::Array(Rc::new(RefCell::new(reversed))))
1351        }
1352        Value::String(s) => {
1353            let reversed: String = s.chars().rev().collect();
1354            Ok(Value::String(Rc::new(reversed)))
1355        }
1356        _ => Err(RuntimeError::new("reverse() requires array or string")),
1357    });
1358
1359    define(interp, "sort", Some(1), |_, args| match &args[0] {
1360        Value::Array(arr) => {
1361            let mut sorted: Vec<Value> = arr.borrow().clone();
1362            sorted.sort_by(compare_values);
1363            Ok(Value::Array(Rc::new(RefCell::new(sorted))))
1364        }
1365        _ => Err(RuntimeError::new("sort() requires array")),
1366    });
1367
1368    define(interp, "sort_desc", Some(1), |_, args| match &args[0] {
1369        Value::Array(arr) => {
1370            let mut sorted: Vec<Value> = arr.borrow().clone();
1371            sorted.sort_by(|a, b| compare_values(b, a));
1372            Ok(Value::Array(Rc::new(RefCell::new(sorted))))
1373        }
1374        _ => Err(RuntimeError::new("sort_desc() requires array")),
1375    });
1376
1377    define(interp, "unique", Some(1), |_, args| match &args[0] {
1378        Value::Array(arr) => {
1379            let arr = arr.borrow();
1380            let mut seen = Vec::new();
1381            let unique: Vec<Value> = arr
1382                .iter()
1383                .filter(|v| {
1384                    if seen.iter().any(|s| values_equal(s, v)) {
1385                        false
1386                    } else {
1387                        seen.push((*v).clone());
1388                        true
1389                    }
1390                })
1391                .cloned()
1392                .collect();
1393            Ok(Value::Array(Rc::new(RefCell::new(unique))))
1394        }
1395        _ => Err(RuntimeError::new("unique() requires array")),
1396    });
1397
1398    define(interp, "flatten", Some(1), |_, args| match &args[0] {
1399        Value::Array(arr) => {
1400            let mut flattened = Vec::new();
1401            for item in arr.borrow().iter() {
1402                match item {
1403                    Value::Array(inner) => flattened.extend(inner.borrow().clone()),
1404                    other => flattened.push(other.clone()),
1405                }
1406            }
1407            Ok(Value::Array(Rc::new(RefCell::new(flattened))))
1408        }
1409        _ => Err(RuntimeError::new("flatten() requires array")),
1410    });
1411
1412    // Combining
1413    define(interp, "concat", Some(2), |_, args| {
1414        match (&args[0], &args[1]) {
1415            (Value::Array(a), Value::Array(b)) => {
1416                let mut result = a.borrow().clone();
1417                result.extend(b.borrow().clone());
1418                Ok(Value::Array(Rc::new(RefCell::new(result))))
1419            }
1420            (Value::String(a), Value::String(b)) => {
1421                Ok(Value::String(Rc::new(format!("{}{}", a, b))))
1422            }
1423            _ => Err(RuntimeError::new(
1424                "concat() requires two arrays or two strings",
1425            )),
1426        }
1427    });
1428
1429    define(interp, "zip", Some(2), |_, args| {
1430        match (&args[0], &args[1]) {
1431            (Value::Array(a), Value::Array(b)) => {
1432                let a = a.borrow();
1433                let b = b.borrow();
1434                let zipped: Vec<Value> = a
1435                    .iter()
1436                    .zip(b.iter())
1437                    .map(|(x, y)| Value::Tuple(Rc::new(vec![x.clone(), y.clone()])))
1438                    .collect();
1439                Ok(Value::Array(Rc::new(RefCell::new(zipped))))
1440            }
1441            _ => Err(RuntimeError::new("zip() requires two arrays")),
1442        }
1443    });
1444
1445    define(interp, "enumerate", Some(1), |_, args| match &args[0] {
1446        Value::Array(arr) => {
1447            let enumerated: Vec<Value> = arr
1448                .borrow()
1449                .iter()
1450                .enumerate()
1451                .map(|(i, v)| Value::Tuple(Rc::new(vec![Value::Int(i as i64), v.clone()])))
1452                .collect();
1453            Ok(Value::Array(Rc::new(RefCell::new(enumerated))))
1454        }
1455        _ => Err(RuntimeError::new("enumerate() requires array")),
1456    });
1457
1458    // ⋈ (bowtie) - zip_with: combine two arrays with a function
1459    // Since closures are complex, provide a simple zip variant that takes a mode
1460    define(interp, "zip_with", Some(3), |_, args| {
1461        let mode = match &args[2] {
1462            Value::String(s) => s.as_str(),
1463            _ => return Err(RuntimeError::new("zip_with() mode must be string")),
1464        };
1465        match (&args[0], &args[1]) {
1466            (Value::Array(a), Value::Array(b)) => {
1467                let a = a.borrow();
1468                let b = b.borrow();
1469                let result: Result<Vec<Value>, RuntimeError> = a
1470                    .iter()
1471                    .zip(b.iter())
1472                    .map(|(x, y)| match (x, y, mode) {
1473                        (Value::Int(a), Value::Int(b), "add") => Ok(Value::Int(a + b)),
1474                        (Value::Int(a), Value::Int(b), "sub") => Ok(Value::Int(a - b)),
1475                        (Value::Int(a), Value::Int(b), "mul") => Ok(Value::Int(a * b)),
1476                        (Value::Float(a), Value::Float(b), "add") => Ok(Value::Float(a + b)),
1477                        (Value::Float(a), Value::Float(b), "sub") => Ok(Value::Float(a - b)),
1478                        (Value::Float(a), Value::Float(b), "mul") => Ok(Value::Float(a * b)),
1479                        (_, _, "pair") => Ok(Value::Tuple(Rc::new(vec![x.clone(), y.clone()]))),
1480                        _ => Err(RuntimeError::new("zip_with() incompatible types or mode")),
1481                    })
1482                    .collect();
1483                Ok(Value::Array(Rc::new(RefCell::new(result?))))
1484            }
1485            _ => Err(RuntimeError::new("zip_with() requires two arrays")),
1486        }
1487    });
1488
1489    // ⊔ (square cup) - lattice join / supremum (max of two values)
1490    define(interp, "supremum", Some(2), |_, args| {
1491        match (&args[0], &args[1]) {
1492            (Value::Int(a), Value::Int(b)) => Ok(Value::Int(*a.max(b))),
1493            (Value::Float(a), Value::Float(b)) => Ok(Value::Float(a.max(*b))),
1494            (Value::Array(a), Value::Array(b)) => {
1495                // Element-wise max
1496                let a = a.borrow();
1497                let b = b.borrow();
1498                let result: Result<Vec<Value>, RuntimeError> = a
1499                    .iter()
1500                    .zip(b.iter())
1501                    .map(|(x, y)| match (x, y) {
1502                        (Value::Int(a), Value::Int(b)) => Ok(Value::Int(*a.max(b))),
1503                        (Value::Float(a), Value::Float(b)) => Ok(Value::Float(a.max(*b))),
1504                        _ => Err(RuntimeError::new("supremum() requires numeric arrays")),
1505                    })
1506                    .collect();
1507                Ok(Value::Array(Rc::new(RefCell::new(result?))))
1508            }
1509            _ => Err(RuntimeError::new(
1510                "supremum() requires numeric values or arrays",
1511            )),
1512        }
1513    });
1514
1515    // ⊓ (square cap) - lattice meet / infimum (min of two values)
1516    define(interp, "infimum", Some(2), |_, args| {
1517        match (&args[0], &args[1]) {
1518            (Value::Int(a), Value::Int(b)) => Ok(Value::Int(*a.min(b))),
1519            (Value::Float(a), Value::Float(b)) => Ok(Value::Float(a.min(*b))),
1520            (Value::Array(a), Value::Array(b)) => {
1521                // Element-wise min
1522                let a = a.borrow();
1523                let b = b.borrow();
1524                let result: Result<Vec<Value>, RuntimeError> = a
1525                    .iter()
1526                    .zip(b.iter())
1527                    .map(|(x, y)| match (x, y) {
1528                        (Value::Int(a), Value::Int(b)) => Ok(Value::Int(*a.min(b))),
1529                        (Value::Float(a), Value::Float(b)) => Ok(Value::Float(a.min(*b))),
1530                        _ => Err(RuntimeError::new("infimum() requires numeric arrays")),
1531                    })
1532                    .collect();
1533                Ok(Value::Array(Rc::new(RefCell::new(result?))))
1534            }
1535            _ => Err(RuntimeError::new(
1536                "infimum() requires numeric values or arrays",
1537            )),
1538        }
1539    });
1540
1541    // Slicing
1542    define(interp, "slice", Some(3), |_, args| {
1543        let start = match &args[1] {
1544            Value::Int(i) => *i as usize,
1545            _ => return Err(RuntimeError::new("slice() start must be integer")),
1546        };
1547        let end = match &args[2] {
1548            Value::Int(i) => *i as usize,
1549            _ => return Err(RuntimeError::new("slice() end must be integer")),
1550        };
1551        match &args[0] {
1552            Value::Array(arr) => {
1553                let arr = arr.borrow();
1554                let end = end.min(arr.len());
1555                let sliced: Vec<Value> = arr[start..end].to_vec();
1556                Ok(Value::Array(Rc::new(RefCell::new(sliced))))
1557            }
1558            Value::String(s) => {
1559                let chars: Vec<char> = s.chars().collect();
1560                let end = end.min(chars.len());
1561                let sliced: String = chars[start..end].iter().collect();
1562                Ok(Value::String(Rc::new(sliced)))
1563            }
1564            _ => Err(RuntimeError::new("slice() requires array or string")),
1565        }
1566    });
1567
1568    define(interp, "take", Some(2), |_, args| {
1569        let n = match &args[1] {
1570            Value::Int(i) => *i as usize,
1571            _ => return Err(RuntimeError::new("take() n must be integer")),
1572        };
1573        match &args[0] {
1574            Value::Array(arr) => {
1575                let taken: Vec<Value> = arr.borrow().iter().take(n).cloned().collect();
1576                Ok(Value::Array(Rc::new(RefCell::new(taken))))
1577            }
1578            _ => Err(RuntimeError::new("take() requires array")),
1579        }
1580    });
1581
1582    define(interp, "skip", Some(2), |_, args| {
1583        let n = match &args[1] {
1584            Value::Int(i) => *i as usize,
1585            _ => return Err(RuntimeError::new("skip() n must be integer")),
1586        };
1587        match &args[0] {
1588            Value::Array(arr) => {
1589                let skipped: Vec<Value> = arr.borrow().iter().skip(n).cloned().collect();
1590                Ok(Value::Array(Rc::new(RefCell::new(skipped))))
1591            }
1592            _ => Err(RuntimeError::new("skip() requires array")),
1593        }
1594    });
1595
1596    define(interp, "chunk", Some(2), |_, args| {
1597        let size = match &args[1] {
1598            Value::Int(i) if *i > 0 => *i as usize,
1599            _ => return Err(RuntimeError::new("chunk() size must be positive integer")),
1600        };
1601        match &args[0] {
1602            Value::Array(arr) => {
1603                let chunks: Vec<Value> = arr
1604                    .borrow()
1605                    .chunks(size)
1606                    .map(|c| Value::Array(Rc::new(RefCell::new(c.to_vec()))))
1607                    .collect();
1608                Ok(Value::Array(Rc::new(RefCell::new(chunks))))
1609            }
1610            _ => Err(RuntimeError::new("chunk() requires array")),
1611        }
1612    });
1613
1614    // Range
1615    define(interp, "range", Some(2), |_, args| {
1616        let start = match &args[0] {
1617            Value::Int(n) => *n,
1618            _ => return Err(RuntimeError::new("range() requires integers")),
1619        };
1620        let end = match &args[1] {
1621            Value::Int(n) => *n,
1622            _ => return Err(RuntimeError::new("range() requires integers")),
1623        };
1624        let values: Vec<Value> = (start..end).map(Value::Int).collect();
1625        Ok(Value::Array(Rc::new(RefCell::new(values))))
1626    });
1627
1628    define(interp, "range_inclusive", Some(2), |_, args| {
1629        let start = match &args[0] {
1630            Value::Int(n) => *n,
1631            _ => return Err(RuntimeError::new("range_inclusive() requires integers")),
1632        };
1633        let end = match &args[1] {
1634            Value::Int(n) => *n,
1635            _ => return Err(RuntimeError::new("range_inclusive() requires integers")),
1636        };
1637        let values: Vec<Value> = (start..=end).map(Value::Int).collect();
1638        Ok(Value::Array(Rc::new(RefCell::new(values))))
1639    });
1640
1641    define(interp, "repeat", Some(2), |_, args| {
1642        let n = match &args[1] {
1643            Value::Int(i) if *i >= 0 => *i as usize,
1644            _ => {
1645                return Err(RuntimeError::new(
1646                    "repeat() count must be non-negative integer",
1647                ))
1648            }
1649        };
1650        let repeated: Vec<Value> = std::iter::repeat(args[0].clone()).take(n).collect();
1651        Ok(Value::Array(Rc::new(RefCell::new(repeated))))
1652    });
1653
1654    // ========================================
1655    // HashMap operations
1656    // ========================================
1657
1658    // map_new - create empty HashMap
1659    define(interp, "map_new", Some(0), |_, _| {
1660        Ok(Value::Map(Rc::new(RefCell::new(HashMap::new()))))
1661    });
1662
1663    // map_get - get value by key
1664    define(interp, "map_get", Some(2), |_, args| {
1665        let key = match &args[1] {
1666            Value::String(s) => s.to_string(),
1667            _ => return Err(RuntimeError::new("map_get() key must be string")),
1668        };
1669        match &args[0] {
1670            Value::Map(map) => Ok(map.borrow().get(&key).cloned().unwrap_or(Value::Null)),
1671            _ => Err(RuntimeError::new("map_get() requires map")),
1672        }
1673    });
1674
1675    // map_set - set key-value pair
1676    define(interp, "map_set", Some(3), |_, args| {
1677        let key = match &args[1] {
1678            Value::String(s) => s.to_string(),
1679            _ => return Err(RuntimeError::new("map_set() key must be string")),
1680        };
1681        match &args[0] {
1682            Value::Map(map) => {
1683                map.borrow_mut().insert(key, args[2].clone());
1684                Ok(Value::Null)
1685            }
1686            _ => Err(RuntimeError::new("map_set() requires map")),
1687        }
1688    });
1689
1690    // map_has - check if key exists
1691    define(interp, "map_has", Some(2), |_, args| {
1692        let key = match &args[1] {
1693            Value::String(s) => s.to_string(),
1694            _ => return Err(RuntimeError::new("map_has() key must be string")),
1695        };
1696        match &args[0] {
1697            Value::Map(map) => Ok(Value::Bool(map.borrow().contains_key(&key))),
1698            _ => Err(RuntimeError::new("map_has() requires map")),
1699        }
1700    });
1701
1702    // map_remove - remove key from map
1703    define(interp, "map_remove", Some(2), |_, args| {
1704        let key = match &args[1] {
1705            Value::String(s) => s.to_string(),
1706            _ => return Err(RuntimeError::new("map_remove() key must be string")),
1707        };
1708        match &args[0] {
1709            Value::Map(map) => Ok(map.borrow_mut().remove(&key).unwrap_or(Value::Null)),
1710            _ => Err(RuntimeError::new("map_remove() requires map")),
1711        }
1712    });
1713
1714    // map_keys - get all keys as array
1715    define(interp, "map_keys", Some(1), |_, args| match &args[0] {
1716        Value::Map(map) => {
1717            let keys: Vec<Value> = map
1718                .borrow()
1719                .keys()
1720                .map(|k| Value::String(Rc::new(k.clone())))
1721                .collect();
1722            Ok(Value::Array(Rc::new(RefCell::new(keys))))
1723        }
1724        _ => Err(RuntimeError::new("map_keys() requires map")),
1725    });
1726
1727    // map_values - get all values as array
1728    define(interp, "map_values", Some(1), |_, args| match &args[0] {
1729        Value::Map(map) => {
1730            let values: Vec<Value> = map.borrow().values().cloned().collect();
1731            Ok(Value::Array(Rc::new(RefCell::new(values))))
1732        }
1733        _ => Err(RuntimeError::new("map_values() requires map")),
1734    });
1735
1736    // map_len - get number of entries
1737    define(interp, "map_len", Some(1), |_, args| match &args[0] {
1738        Value::Map(map) => Ok(Value::Int(map.borrow().len() as i64)),
1739        _ => Err(RuntimeError::new("map_len() requires map")),
1740    });
1741
1742    // map_clear - remove all entries
1743    define(interp, "map_clear", Some(1), |_, args| match &args[0] {
1744        Value::Map(map) => {
1745            map.borrow_mut().clear();
1746            Ok(Value::Null)
1747        }
1748        _ => Err(RuntimeError::new("map_clear() requires map")),
1749    });
1750
1751    // ========================================
1752    // HashSet operations
1753    // ========================================
1754
1755    // set_new - create empty HashSet
1756    define(interp, "set_new", Some(0), |_, _| {
1757        Ok(Value::Set(Rc::new(RefCell::new(
1758            std::collections::HashSet::new(),
1759        ))))
1760    });
1761
1762    // set_add - add item to set
1763    define(interp, "set_add", Some(2), |_, args| {
1764        let item = match &args[1] {
1765            Value::String(s) => s.to_string(),
1766            _ => return Err(RuntimeError::new("set_add() item must be string")),
1767        };
1768        match &args[0] {
1769            Value::Set(set) => {
1770                set.borrow_mut().insert(item);
1771                Ok(Value::Null)
1772            }
1773            _ => Err(RuntimeError::new("set_add() requires set")),
1774        }
1775    });
1776
1777    // set_has - check if item exists
1778    define(interp, "set_has", Some(2), |_, args| {
1779        let item = match &args[1] {
1780            Value::String(s) => s.to_string(),
1781            _ => return Err(RuntimeError::new("set_has() item must be string")),
1782        };
1783        match &args[0] {
1784            Value::Set(set) => Ok(Value::Bool(set.borrow().contains(&item))),
1785            _ => Err(RuntimeError::new("set_has() requires set")),
1786        }
1787    });
1788
1789    // set_remove - remove item from set
1790    define(interp, "set_remove", Some(2), |_, args| {
1791        let item = match &args[1] {
1792            Value::String(s) => s.to_string(),
1793            _ => return Err(RuntimeError::new("set_remove() item must be string")),
1794        };
1795        match &args[0] {
1796            Value::Set(set) => Ok(Value::Bool(set.borrow_mut().remove(&item))),
1797            _ => Err(RuntimeError::new("set_remove() requires set")),
1798        }
1799    });
1800
1801    // set_to_array - convert set to array
1802    define(interp, "set_to_array", Some(1), |_, args| match &args[0] {
1803        Value::Set(set) => {
1804            let items: Vec<Value> = set
1805                .borrow()
1806                .iter()
1807                .map(|s| Value::String(Rc::new(s.clone())))
1808                .collect();
1809            Ok(Value::Array(Rc::new(RefCell::new(items))))
1810        }
1811        _ => Err(RuntimeError::new("set_to_array() requires set")),
1812    });
1813
1814    // set_len - get number of items
1815    define(interp, "set_len", Some(1), |_, args| match &args[0] {
1816        Value::Set(set) => Ok(Value::Int(set.borrow().len() as i64)),
1817        _ => Err(RuntimeError::new("set_len() requires set")),
1818    });
1819
1820    // set_clear - remove all items
1821    define(interp, "set_clear", Some(1), |_, args| match &args[0] {
1822        Value::Set(set) => {
1823            set.borrow_mut().clear();
1824            Ok(Value::Null)
1825        }
1826        _ => Err(RuntimeError::new("set_clear() requires set")),
1827    });
1828}
1829
1830fn values_equal(a: &Value, b: &Value) -> bool {
1831    match (a, b) {
1832        (Value::Null, Value::Null) => true,
1833        (Value::Bool(a), Value::Bool(b)) => a == b,
1834        (Value::Int(a), Value::Int(b)) => a == b,
1835        (Value::Float(a), Value::Float(b)) => (a - b).abs() < f64::EPSILON,
1836        (Value::String(a), Value::String(b)) => a == b,
1837        (Value::Char(a), Value::Char(b)) => a == b,
1838        (Value::Array(a), Value::Array(b)) => {
1839            let a = a.borrow();
1840            let b = b.borrow();
1841            a.len() == b.len() && a.iter().zip(b.iter()).all(|(x, y)| values_equal(x, y))
1842        }
1843        (Value::Tuple(a), Value::Tuple(b)) => {
1844            a.len() == b.len() && a.iter().zip(b.iter()).all(|(x, y)| values_equal(x, y))
1845        }
1846        _ => false,
1847    }
1848}
1849
1850fn compare_values(a: &Value, b: &Value) -> std::cmp::Ordering {
1851    match (a, b) {
1852        (Value::Int(a), Value::Int(b)) => a.cmp(b),
1853        (Value::Float(a), Value::Float(b)) => a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal),
1854        (Value::String(a), Value::String(b)) => a.cmp(b),
1855        (Value::Char(a), Value::Char(b)) => a.cmp(b),
1856        _ => std::cmp::Ordering::Equal,
1857    }
1858}
1859
1860// ============================================================================
1861// STRING FUNCTIONS
1862// ============================================================================
1863
1864fn register_string(interp: &mut Interpreter) {
1865    define(interp, "chars", Some(1), |_, args| match &args[0] {
1866        Value::String(s) => {
1867            let chars: Vec<Value> = s.chars().map(Value::Char).collect();
1868            Ok(Value::Array(Rc::new(RefCell::new(chars))))
1869        }
1870        _ => Err(RuntimeError::new("chars() requires string")),
1871    });
1872
1873    define(interp, "bytes", Some(1), |_, args| match &args[0] {
1874        Value::String(s) => {
1875            let bytes: Vec<Value> = s.bytes().map(|b| Value::Int(b as i64)).collect();
1876            Ok(Value::Array(Rc::new(RefCell::new(bytes))))
1877        }
1878        _ => Err(RuntimeError::new("bytes() requires string")),
1879    });
1880
1881    define(interp, "split", Some(2), |_, args| {
1882        match (&args[0], &args[1]) {
1883            (Value::String(s), Value::String(sep)) => {
1884                let parts: Vec<Value> = s
1885                    .split(sep.as_str())
1886                    .map(|p| Value::String(Rc::new(p.to_string())))
1887                    .collect();
1888                Ok(Value::Array(Rc::new(RefCell::new(parts))))
1889            }
1890            (Value::String(s), Value::Char(sep)) => {
1891                let parts: Vec<Value> = s
1892                    .split(*sep)
1893                    .map(|p| Value::String(Rc::new(p.to_string())))
1894                    .collect();
1895                Ok(Value::Array(Rc::new(RefCell::new(parts))))
1896            }
1897            _ => Err(RuntimeError::new("split() requires string and separator")),
1898        }
1899    });
1900
1901    define(interp, "join", Some(2), |_, args| {
1902        match (&args[0], &args[1]) {
1903            (Value::Array(arr), Value::String(sep)) => {
1904                let parts: Vec<String> = arr.borrow().iter().map(|v| format!("{}", v)).collect();
1905                Ok(Value::String(Rc::new(parts.join(sep.as_str()))))
1906            }
1907            _ => Err(RuntimeError::new(
1908                "join() requires array and separator string",
1909            )),
1910        }
1911    });
1912
1913    define(interp, "trim", Some(1), |_, args| match &args[0] {
1914        Value::String(s) => Ok(Value::String(Rc::new(s.trim().to_string()))),
1915        _ => Err(RuntimeError::new("trim() requires string")),
1916    });
1917
1918    define(interp, "trim_start", Some(1), |_, args| match &args[0] {
1919        Value::String(s) => Ok(Value::String(Rc::new(s.trim_start().to_string()))),
1920        _ => Err(RuntimeError::new("trim_start() requires string")),
1921    });
1922
1923    define(interp, "trim_end", Some(1), |_, args| match &args[0] {
1924        Value::String(s) => Ok(Value::String(Rc::new(s.trim_end().to_string()))),
1925        _ => Err(RuntimeError::new("trim_end() requires string")),
1926    });
1927
1928    define(interp, "upper", Some(1), |_, args| match &args[0] {
1929        Value::String(s) => Ok(Value::String(Rc::new(s.to_uppercase()))),
1930        Value::Char(c) => Ok(Value::Char(c.to_uppercase().next().unwrap_or(*c))),
1931        _ => Err(RuntimeError::new("upper() requires string or char")),
1932    });
1933
1934    define(interp, "lower", Some(1), |_, args| match &args[0] {
1935        Value::String(s) => Ok(Value::String(Rc::new(s.to_lowercase()))),
1936        Value::Char(c) => Ok(Value::Char(c.to_lowercase().next().unwrap_or(*c))),
1937        _ => Err(RuntimeError::new("lower() requires string or char")),
1938    });
1939
1940    define(interp, "capitalize", Some(1), |_, args| match &args[0] {
1941        Value::String(s) => {
1942            let mut chars = s.chars();
1943            let capitalized = match chars.next() {
1944                None => String::new(),
1945                Some(c) => c.to_uppercase().chain(chars).collect(),
1946            };
1947            Ok(Value::String(Rc::new(capitalized)))
1948        }
1949        _ => Err(RuntimeError::new("capitalize() requires string")),
1950    });
1951
1952    define(interp, "replace", Some(3), |_, args| {
1953        match (&args[0], &args[1], &args[2]) {
1954            (Value::String(s), Value::String(from), Value::String(to)) => Ok(Value::String(
1955                Rc::new(s.replace(from.as_str(), to.as_str())),
1956            )),
1957            _ => Err(RuntimeError::new("replace() requires three strings")),
1958        }
1959    });
1960
1961    define(interp, "starts_with", Some(2), |_, args| {
1962        match (&args[0], &args[1]) {
1963            (Value::String(s), Value::String(prefix)) => {
1964                Ok(Value::Bool(s.starts_with(prefix.as_str())))
1965            }
1966            _ => Err(RuntimeError::new("starts_with() requires two strings")),
1967        }
1968    });
1969
1970    define(interp, "ends_with", Some(2), |_, args| {
1971        match (&args[0], &args[1]) {
1972            (Value::String(s), Value::String(suffix)) => {
1973                Ok(Value::Bool(s.ends_with(suffix.as_str())))
1974            }
1975            _ => Err(RuntimeError::new("ends_with() requires two strings")),
1976        }
1977    });
1978
1979    define(interp, "repeat_str", Some(2), |_, args| {
1980        match (&args[0], &args[1]) {
1981            (Value::String(s), Value::Int(n)) if *n >= 0 => {
1982                Ok(Value::String(Rc::new(s.repeat(*n as usize))))
1983            }
1984            _ => Err(RuntimeError::new(
1985                "repeat_str() requires string and non-negative integer",
1986            )),
1987        }
1988    });
1989
1990    define(interp, "pad_left", Some(3), |_, args| {
1991        match (&args[0], &args[1], &args[2]) {
1992            (Value::String(s), Value::Int(width), Value::Char(c)) => {
1993                let width = *width as usize;
1994                if s.len() >= width {
1995                    Ok(Value::String(s.clone()))
1996                } else {
1997                    let padding: String = std::iter::repeat(*c).take(width - s.len()).collect();
1998                    Ok(Value::String(Rc::new(format!("{}{}", padding, s))))
1999                }
2000            }
2001            _ => Err(RuntimeError::new(
2002                "pad_left() requires string, width, and char",
2003            )),
2004        }
2005    });
2006
2007    define(interp, "pad_right", Some(3), |_, args| {
2008        match (&args[0], &args[1], &args[2]) {
2009            (Value::String(s), Value::Int(width), Value::Char(c)) => {
2010                let width = *width as usize;
2011                if s.len() >= width {
2012                    Ok(Value::String(s.clone()))
2013                } else {
2014                    let padding: String = std::iter::repeat(*c).take(width - s.len()).collect();
2015                    Ok(Value::String(Rc::new(format!("{}{}", s, padding))))
2016                }
2017            }
2018            _ => Err(RuntimeError::new(
2019                "pad_right() requires string, width, and char",
2020            )),
2021        }
2022    });
2023
2024    define(interp, "lines", Some(1), |_, args| match &args[0] {
2025        Value::String(s) => {
2026            let lines: Vec<Value> = s
2027                .lines()
2028                .map(|l| Value::String(Rc::new(l.to_string())))
2029                .collect();
2030            Ok(Value::Array(Rc::new(RefCell::new(lines))))
2031        }
2032        _ => Err(RuntimeError::new("lines() requires string")),
2033    });
2034
2035    define(interp, "words", Some(1), |_, args| match &args[0] {
2036        Value::String(s) => {
2037            let words: Vec<Value> = s
2038                .split_whitespace()
2039                .map(|w| Value::String(Rc::new(w.to_string())))
2040                .collect();
2041            Ok(Value::Array(Rc::new(RefCell::new(words))))
2042        }
2043        _ => Err(RuntimeError::new("words() requires string")),
2044    });
2045
2046    define(interp, "is_alpha", Some(1), |_, args| match &args[0] {
2047        Value::String(s) => Ok(Value::Bool(
2048            !s.is_empty() && s.chars().all(|c| c.is_alphabetic()),
2049        )),
2050        Value::Char(c) => Ok(Value::Bool(c.is_alphabetic())),
2051        _ => Err(RuntimeError::new("is_alpha() requires string or char")),
2052    });
2053
2054    define(interp, "is_digit", Some(1), |_, args| match &args[0] {
2055        Value::String(s) => Ok(Value::Bool(
2056            !s.is_empty() && s.chars().all(|c| c.is_ascii_digit()),
2057        )),
2058        Value::Char(c) => Ok(Value::Bool(c.is_ascii_digit())),
2059        _ => Err(RuntimeError::new("is_digit() requires string or char")),
2060    });
2061
2062    define(interp, "is_alnum", Some(1), |_, args| match &args[0] {
2063        Value::String(s) => Ok(Value::Bool(
2064            !s.is_empty() && s.chars().all(|c| c.is_alphanumeric()),
2065        )),
2066        Value::Char(c) => Ok(Value::Bool(c.is_alphanumeric())),
2067        _ => Err(RuntimeError::new("is_alnum() requires string or char")),
2068    });
2069
2070    define(interp, "is_space", Some(1), |_, args| match &args[0] {
2071        Value::String(s) => Ok(Value::Bool(
2072            !s.is_empty() && s.chars().all(|c| c.is_whitespace()),
2073        )),
2074        Value::Char(c) => Ok(Value::Bool(c.is_whitespace())),
2075        _ => Err(RuntimeError::new("is_space() requires string or char")),
2076    });
2077
2078    // =========================================================================
2079    // ADVANCED STRING FUNCTIONS
2080    // =========================================================================
2081
2082    // find - find first occurrence of substring, returns index or -1
2083    define(interp, "find", Some(2), |_, args| {
2084        match (&args[0], &args[1]) {
2085            (Value::String(s), Value::String(sub)) => {
2086                match s.find(sub.as_str()) {
2087                    Some(byte_idx) => {
2088                        // Convert byte index to character index
2089                        let char_idx = s[..byte_idx].chars().count() as i64;
2090                        Ok(Value::Int(char_idx))
2091                    }
2092                    None => Ok(Value::Int(-1)),
2093                }
2094            }
2095            (Value::String(s), Value::Char(c)) => match s.find(*c) {
2096                Some(byte_idx) => {
2097                    let char_idx = s[..byte_idx].chars().count() as i64;
2098                    Ok(Value::Int(char_idx))
2099                }
2100                None => Ok(Value::Int(-1)),
2101            },
2102            _ => Err(RuntimeError::new(
2103                "find() requires string and substring/char",
2104            )),
2105        }
2106    });
2107
2108    // index_of - find index of element in array or substring in string
2109    define(interp, "index_of", Some(2), |_, args| {
2110        match (&args[0], &args[1]) {
2111            (Value::String(s), Value::String(sub)) => match s.find(sub.as_str()) {
2112                Some(byte_idx) => {
2113                    let char_idx = s[..byte_idx].chars().count() as i64;
2114                    Ok(Value::Int(char_idx))
2115                }
2116                None => Ok(Value::Int(-1)),
2117            },
2118            (Value::String(s), Value::Char(c)) => match s.find(*c) {
2119                Some(byte_idx) => {
2120                    let char_idx = s[..byte_idx].chars().count() as i64;
2121                    Ok(Value::Int(char_idx))
2122                }
2123                None => Ok(Value::Int(-1)),
2124            },
2125            (Value::Array(arr), search) => {
2126                // Array index_of - use Value comparison
2127                for (i, v) in arr.borrow().iter().enumerate() {
2128                    if values_equal_simple(v, search) {
2129                        return Ok(Value::Int(i as i64));
2130                    }
2131                }
2132                Ok(Value::Int(-1))
2133            }
2134            _ => Err(RuntimeError::new(
2135                "index_of() requires array/string and element/substring",
2136            )),
2137        }
2138    });
2139
2140    // last_index_of - find last occurrence of substring
2141    define(interp, "last_index_of", Some(2), |_, args| {
2142        match (&args[0], &args[1]) {
2143            (Value::String(s), Value::String(sub)) => match s.rfind(sub.as_str()) {
2144                Some(byte_idx) => {
2145                    let char_idx = s[..byte_idx].chars().count() as i64;
2146                    Ok(Value::Int(char_idx))
2147                }
2148                None => Ok(Value::Int(-1)),
2149            },
2150            (Value::String(s), Value::Char(c)) => match s.rfind(*c) {
2151                Some(byte_idx) => {
2152                    let char_idx = s[..byte_idx].chars().count() as i64;
2153                    Ok(Value::Int(char_idx))
2154                }
2155                None => Ok(Value::Int(-1)),
2156            },
2157            _ => Err(RuntimeError::new(
2158                "last_index_of() requires string and substring/char",
2159            )),
2160        }
2161    });
2162
2163    // substring - extract substring by character indices
2164    define(interp, "substring", Some(3), |_, args| {
2165        let s = match &args[0] {
2166            Value::String(s) => (**s).clone(),
2167            _ => {
2168                return Err(RuntimeError::new(
2169                    "substring: first argument must be a string",
2170                ))
2171            }
2172        };
2173        let start = match &args[1] {
2174            Value::Int(n) if *n >= 0 => *n as usize,
2175            _ => {
2176                return Err(RuntimeError::new(
2177                    "substring: start must be a non-negative integer",
2178                ))
2179            }
2180        };
2181        let end = match &args[2] {
2182            Value::Int(n) if *n >= 0 => *n as usize,
2183            _ => {
2184                return Err(RuntimeError::new(
2185                    "substring: end must be a non-negative integer",
2186                ))
2187            }
2188        };
2189        let chars: Vec<char> = s.chars().collect();
2190        let len = chars.len();
2191        let actual_start = start.min(len);
2192        let actual_end = end.min(len);
2193        if actual_start >= actual_end {
2194            return Ok(Value::String(Rc::new(String::new())));
2195        }
2196        let result: String = chars[actual_start..actual_end].iter().collect();
2197        Ok(Value::String(Rc::new(result)))
2198    });
2199
2200    // count - count occurrences of substring
2201    define(interp, "count", Some(2), |_, args| {
2202        match (&args[0], &args[1]) {
2203            (Value::String(s), Value::String(sub)) => {
2204                if sub.is_empty() {
2205                    return Err(RuntimeError::new("count: cannot count empty string"));
2206                }
2207                let count = s.matches(sub.as_str()).count() as i64;
2208                Ok(Value::Int(count))
2209            }
2210            (Value::String(s), Value::Char(c)) => {
2211                let count = s.chars().filter(|&ch| ch == *c).count() as i64;
2212                Ok(Value::Int(count))
2213            }
2214            _ => Err(RuntimeError::new(
2215                "count() requires string and substring/char",
2216            )),
2217        }
2218    });
2219
2220    // char_at - get character at byte index (safer than indexing)
2221    // Uses byte-based indexing to match self-hosted lexer's pos tracking
2222    define(interp, "char_at", Some(2), |_, args| {
2223        let s = match &args[0] {
2224            Value::String(s) => (**s).clone(),
2225            _ => {
2226                return Err(RuntimeError::new(
2227                    "char_at: first argument must be a string",
2228                ))
2229            }
2230        };
2231        let idx = match &args[1] {
2232            Value::Int(n) => *n,
2233            _ => {
2234                return Err(RuntimeError::new(
2235                    "char_at: second argument must be an integer",
2236                ))
2237            }
2238        };
2239        // Use byte-based indexing
2240        let actual_idx = if idx < 0 {
2241            // Negative indexing counts from end of string (in bytes)
2242            (s.len() as i64 + idx) as usize
2243        } else {
2244            idx as usize
2245        };
2246        if actual_idx < s.len() {
2247            let remaining = &s[actual_idx..];
2248            match remaining.chars().next() {
2249                Some(c) => Ok(Value::Char(c)),
2250                None => Ok(Value::Null),
2251            }
2252        } else {
2253            Ok(Value::Null)
2254        }
2255    });
2256
2257    // char_code_at - get Unicode code point at index
2258    define(interp, "char_code_at", Some(2), |_, args| {
2259        let s = match &args[0] {
2260            Value::String(s) => (**s).clone(),
2261            _ => {
2262                return Err(RuntimeError::new(
2263                    "char_code_at: first argument must be a string",
2264                ))
2265            }
2266        };
2267        let idx = match &args[1] {
2268            Value::Int(n) => *n,
2269            _ => {
2270                return Err(RuntimeError::new(
2271                    "char_code_at: second argument must be an integer",
2272                ))
2273            }
2274        };
2275        let chars: Vec<char> = s.chars().collect();
2276        let actual_idx = if idx < 0 {
2277            (chars.len() as i64 + idx) as usize
2278        } else {
2279            idx as usize
2280        };
2281        match chars.get(actual_idx) {
2282            Some(c) => Ok(Value::Int(*c as i64)),
2283            None => Ok(Value::Null),
2284        }
2285    });
2286
2287    // from_char_code - create string from Unicode code point
2288    define(interp, "from_char_code", Some(1), |_, args| {
2289        let code = match &args[0] {
2290            Value::Int(n) => *n as u32,
2291            _ => {
2292                return Err(RuntimeError::new(
2293                    "from_char_code: argument must be an integer",
2294                ))
2295            }
2296        };
2297        match char::from_u32(code) {
2298            Some(c) => Ok(Value::String(Rc::new(c.to_string()))),
2299            None => Err(RuntimeError::new(
2300                "from_char_code: invalid Unicode code point",
2301            )),
2302        }
2303    });
2304
2305    // insert - insert string at index
2306    define(interp, "insert", Some(3), |_, args| {
2307        let s = match &args[0] {
2308            Value::String(s) => (**s).clone(),
2309            _ => return Err(RuntimeError::new("insert: first argument must be a string")),
2310        };
2311        let idx = match &args[1] {
2312            Value::Int(n) if *n >= 0 => *n as usize,
2313            _ => {
2314                return Err(RuntimeError::new(
2315                    "insert: index must be a non-negative integer",
2316                ))
2317            }
2318        };
2319        let insertion = match &args[2] {
2320            Value::String(s) => (**s).clone(),
2321            _ => return Err(RuntimeError::new("insert: third argument must be a string")),
2322        };
2323        let chars: Vec<char> = s.chars().collect();
2324        let actual_idx = idx.min(chars.len());
2325        let mut result: String = chars[..actual_idx].iter().collect();
2326        result.push_str(&insertion);
2327        result.extend(chars[actual_idx..].iter());
2328        Ok(Value::String(Rc::new(result)))
2329    });
2330
2331    // remove - remove range from string
2332    define(interp, "remove", Some(3), |_, args| {
2333        let s = match &args[0] {
2334            Value::String(s) => (**s).clone(),
2335            _ => return Err(RuntimeError::new("remove: first argument must be a string")),
2336        };
2337        let start = match &args[1] {
2338            Value::Int(n) if *n >= 0 => *n as usize,
2339            _ => {
2340                return Err(RuntimeError::new(
2341                    "remove: start must be a non-negative integer",
2342                ))
2343            }
2344        };
2345        let len = match &args[2] {
2346            Value::Int(n) if *n >= 0 => *n as usize,
2347            _ => {
2348                return Err(RuntimeError::new(
2349                    "remove: length must be a non-negative integer",
2350                ))
2351            }
2352        };
2353        let chars: Vec<char> = s.chars().collect();
2354        let str_len = chars.len();
2355        let actual_start = start.min(str_len);
2356        let actual_end = (start + len).min(str_len);
2357        let mut result: String = chars[..actual_start].iter().collect();
2358        result.extend(chars[actual_end..].iter());
2359        Ok(Value::String(Rc::new(result)))
2360    });
2361
2362    // compare - compare two strings, returns -1, 0, or 1
2363    define(interp, "compare", Some(2), |_, args| {
2364        match (&args[0], &args[1]) {
2365            (Value::String(a), Value::String(b)) => {
2366                let result = match a.cmp(b) {
2367                    std::cmp::Ordering::Less => -1,
2368                    std::cmp::Ordering::Equal => 0,
2369                    std::cmp::Ordering::Greater => 1,
2370                };
2371                Ok(Value::Int(result))
2372            }
2373            _ => Err(RuntimeError::new("compare() requires two strings")),
2374        }
2375    });
2376
2377    // compare_ignore_case - case-insensitive comparison
2378    define(interp, "compare_ignore_case", Some(2), |_, args| {
2379        match (&args[0], &args[1]) {
2380            (Value::String(a), Value::String(b)) => {
2381                let result = match a.to_lowercase().cmp(&b.to_lowercase()) {
2382                    std::cmp::Ordering::Less => -1,
2383                    std::cmp::Ordering::Equal => 0,
2384                    std::cmp::Ordering::Greater => 1,
2385                };
2386                Ok(Value::Int(result))
2387            }
2388            _ => Err(RuntimeError::new(
2389                "compare_ignore_case() requires two strings",
2390            )),
2391        }
2392    });
2393
2394    // char_count - get character count (not byte length)
2395    define(interp, "char_count", Some(1), |_, args| match &args[0] {
2396        Value::String(s) => Ok(Value::Int(s.chars().count() as i64)),
2397        _ => Err(RuntimeError::new("char_count() requires string")),
2398    });
2399
2400    // byte_count - get byte length (for UTF-8 awareness)
2401    define(interp, "byte_count", Some(1), |_, args| match &args[0] {
2402        Value::String(s) => Ok(Value::Int(s.len() as i64)),
2403        _ => Err(RuntimeError::new("byte_count() requires string")),
2404    });
2405
2406    // is_empty - check if string is empty
2407    define(interp, "is_empty", Some(1), |_, args| match &args[0] {
2408        Value::String(s) => Ok(Value::Bool(s.is_empty())),
2409        Value::Array(arr) => Ok(Value::Bool(arr.borrow().is_empty())),
2410        _ => Err(RuntimeError::new("is_empty() requires string or array")),
2411    });
2412
2413    // is_blank - check if string is empty or only whitespace
2414    define(interp, "is_blank", Some(1), |_, args| match &args[0] {
2415        Value::String(s) => Ok(Value::Bool(s.trim().is_empty())),
2416        _ => Err(RuntimeError::new("is_blank() requires string")),
2417    });
2418
2419    // =========================================================================
2420    // UNICODE NORMALIZATION FUNCTIONS
2421    // =========================================================================
2422
2423    // nfc - Unicode Normalization Form C (Canonical Decomposition, followed by Canonical Composition)
2424    define(interp, "nfc", Some(1), |_, args| match &args[0] {
2425        Value::String(s) => Ok(Value::String(Rc::new(s.nfc().collect()))),
2426        _ => Err(RuntimeError::new("nfc() requires string")),
2427    });
2428
2429    // nfd - Unicode Normalization Form D (Canonical Decomposition)
2430    define(interp, "nfd", Some(1), |_, args| match &args[0] {
2431        Value::String(s) => Ok(Value::String(Rc::new(s.nfd().collect()))),
2432        _ => Err(RuntimeError::new("nfd() requires string")),
2433    });
2434
2435    // nfkc - Unicode Normalization Form KC (Compatibility Decomposition, followed by Canonical Composition)
2436    define(interp, "nfkc", Some(1), |_, args| match &args[0] {
2437        Value::String(s) => Ok(Value::String(Rc::new(s.nfkc().collect()))),
2438        _ => Err(RuntimeError::new("nfkc() requires string")),
2439    });
2440
2441    // nfkd - Unicode Normalization Form KD (Compatibility Decomposition)
2442    define(interp, "nfkd", Some(1), |_, args| match &args[0] {
2443        Value::String(s) => Ok(Value::String(Rc::new(s.nfkd().collect()))),
2444        _ => Err(RuntimeError::new("nfkd() requires string")),
2445    });
2446
2447    // is_nfc - check if string is in NFC form
2448    define(interp, "is_nfc", Some(1), |_, args| match &args[0] {
2449        Value::String(s) => {
2450            let normalized: String = s.nfc().collect();
2451            Ok(Value::Bool(*s.as_ref() == normalized))
2452        }
2453        _ => Err(RuntimeError::new("is_nfc() requires string")),
2454    });
2455
2456    // is_nfd - check if string is in NFD form
2457    define(interp, "is_nfd", Some(1), |_, args| match &args[0] {
2458        Value::String(s) => {
2459            let normalized: String = s.nfd().collect();
2460            Ok(Value::Bool(*s.as_ref() == normalized))
2461        }
2462        _ => Err(RuntimeError::new("is_nfd() requires string")),
2463    });
2464
2465    // =========================================================================
2466    // GRAPHEME CLUSTER FUNCTIONS
2467    // =========================================================================
2468
2469    // graphemes - split string into grapheme clusters (user-perceived characters)
2470    define(interp, "graphemes", Some(1), |_, args| match &args[0] {
2471        Value::String(s) => {
2472            let graphemes: Vec<Value> = s
2473                .graphemes(true)
2474                .map(|g| Value::String(Rc::new(g.to_string())))
2475                .collect();
2476            Ok(Value::Array(Rc::new(RefCell::new(graphemes))))
2477        }
2478        _ => Err(RuntimeError::new("graphemes() requires string")),
2479    });
2480
2481    // grapheme_count - count grapheme clusters (correct for emoji, combining chars, etc.)
2482    define(interp, "grapheme_count", Some(1), |_, args| {
2483        match &args[0] {
2484            Value::String(s) => Ok(Value::Int(s.graphemes(true).count() as i64)),
2485            _ => Err(RuntimeError::new("grapheme_count() requires string")),
2486        }
2487    });
2488
2489    // grapheme_at - get grapheme cluster at index
2490    define(interp, "grapheme_at", Some(2), |_, args| {
2491        let s = match &args[0] {
2492            Value::String(s) => (**s).clone(),
2493            _ => {
2494                return Err(RuntimeError::new(
2495                    "grapheme_at: first argument must be a string",
2496                ))
2497            }
2498        };
2499        let idx = match &args[1] {
2500            Value::Int(n) => *n,
2501            _ => {
2502                return Err(RuntimeError::new(
2503                    "grapheme_at: second argument must be an integer",
2504                ))
2505            }
2506        };
2507        let graphemes: Vec<&str> = s.graphemes(true).collect();
2508        let actual_idx = if idx < 0 {
2509            (graphemes.len() as i64 + idx) as usize
2510        } else {
2511            idx as usize
2512        };
2513        match graphemes.get(actual_idx) {
2514            Some(g) => Ok(Value::String(Rc::new(g.to_string()))),
2515            None => Ok(Value::Null),
2516        }
2517    });
2518
2519    // grapheme_slice - slice string by grapheme indices (proper Unicode slicing)
2520    define(interp, "grapheme_slice", Some(3), |_, args| {
2521        let s = match &args[0] {
2522            Value::String(s) => (**s).clone(),
2523            _ => {
2524                return Err(RuntimeError::new(
2525                    "grapheme_slice: first argument must be a string",
2526                ))
2527            }
2528        };
2529        let start = match &args[1] {
2530            Value::Int(n) if *n >= 0 => *n as usize,
2531            _ => {
2532                return Err(RuntimeError::new(
2533                    "grapheme_slice: start must be a non-negative integer",
2534                ))
2535            }
2536        };
2537        let end = match &args[2] {
2538            Value::Int(n) if *n >= 0 => *n as usize,
2539            _ => {
2540                return Err(RuntimeError::new(
2541                    "grapheme_slice: end must be a non-negative integer",
2542                ))
2543            }
2544        };
2545        let graphemes: Vec<&str> = s.graphemes(true).collect();
2546        let len = graphemes.len();
2547        let actual_start = start.min(len);
2548        let actual_end = end.min(len);
2549        if actual_start >= actual_end {
2550            return Ok(Value::String(Rc::new(String::new())));
2551        }
2552        let result: String = graphemes[actual_start..actual_end].join("");
2553        Ok(Value::String(Rc::new(result)))
2554    });
2555
2556    // grapheme_reverse - reverse string by grapheme clusters (correct for emoji, etc.)
2557    define(interp, "grapheme_reverse", Some(1), |_, args| {
2558        match &args[0] {
2559            Value::String(s) => {
2560                let reversed: String = s.graphemes(true).rev().collect();
2561                Ok(Value::String(Rc::new(reversed)))
2562            }
2563            _ => Err(RuntimeError::new("grapheme_reverse() requires string")),
2564        }
2565    });
2566
2567    // word_indices - get word boundaries
2568    define(interp, "word_boundaries", Some(1), |_, args| {
2569        match &args[0] {
2570            Value::String(s) => {
2571                let words: Vec<Value> = s
2572                    .unicode_words()
2573                    .map(|w| Value::String(Rc::new(w.to_string())))
2574                    .collect();
2575                Ok(Value::Array(Rc::new(RefCell::new(words))))
2576            }
2577            _ => Err(RuntimeError::new("word_boundaries() requires string")),
2578        }
2579    });
2580
2581    // =========================================================================
2582    // STRING BUILDER
2583    // =========================================================================
2584
2585    // string_builder - create a new string builder (just returns empty string for now,
2586    // operations can be chained with concat)
2587    define(interp, "string_builder", Some(0), |_, _| {
2588        Ok(Value::String(Rc::new(String::new())))
2589    });
2590
2591    // concat_all - concatenate array of strings efficiently
2592    define(interp, "concat_all", Some(1), |_, args| match &args[0] {
2593        Value::Array(arr) => {
2594            let parts: Vec<String> = arr
2595                .borrow()
2596                .iter()
2597                .map(|v| match v {
2598                    Value::String(s) => (**s).clone(),
2599                    other => format!("{}", other),
2600                })
2601                .collect();
2602            Ok(Value::String(Rc::new(parts.join(""))))
2603        }
2604        _ => Err(RuntimeError::new("concat_all() requires array")),
2605    });
2606
2607    // repeat_join - repeat a string n times with a separator
2608    define(interp, "repeat_join", Some(3), |_, args| {
2609        let s = match &args[0] {
2610            Value::String(s) => (**s).clone(),
2611            _ => {
2612                return Err(RuntimeError::new(
2613                    "repeat_join: first argument must be a string",
2614                ))
2615            }
2616        };
2617        let n = match &args[1] {
2618            Value::Int(n) if *n >= 0 => *n as usize,
2619            _ => {
2620                return Err(RuntimeError::new(
2621                    "repeat_join: count must be a non-negative integer",
2622                ))
2623            }
2624        };
2625        let sep = match &args[2] {
2626            Value::String(s) => (**s).clone(),
2627            _ => return Err(RuntimeError::new("repeat_join: separator must be a string")),
2628        };
2629        if n == 0 {
2630            return Ok(Value::String(Rc::new(String::new())));
2631        }
2632        let parts: Vec<&str> = std::iter::repeat(s.as_str()).take(n).collect();
2633        Ok(Value::String(Rc::new(parts.join(&sep))))
2634    });
2635}
2636
2637// ============================================================================
2638// EVIDENCE FUNCTIONS
2639// ============================================================================
2640
2641fn register_evidence(interp: &mut Interpreter) {
2642    use crate::interpreter::RuntimeConfidence;
2643
2644    // Create evidential values
2645    define(interp, "known", Some(1), |_, args| {
2646        Ok(Value::Evidential {
2647            value: Box::new(args[0].clone()),
2648            evidence: Evidence::Known,
2649        })
2650    });
2651
2652    define(interp, "uncertain", Some(1), |_, args| {
2653        Ok(Value::Evidential {
2654            value: Box::new(args[0].clone()),
2655            evidence: Evidence::Uncertain,
2656        })
2657    });
2658
2659    define(interp, "reported", Some(1), |_, args| {
2660        Ok(Value::Evidential {
2661            value: Box::new(args[0].clone()),
2662            evidence: Evidence::Reported,
2663        })
2664    });
2665
2666    define(interp, "paradox", Some(1), |_, args| {
2667        Ok(Value::Evidential {
2668            value: Box::new(args[0].clone()),
2669            evidence: Evidence::Paradox,
2670        })
2671    });
2672
2673    // Query evidence
2674    define(interp, "evidence_of", Some(1), |_, args| {
2675        match &args[0] {
2676            Value::Evidential { evidence, .. } => {
2677                let level = match evidence {
2678                    Evidence::Known => "known",
2679                    Evidence::Uncertain => "uncertain",
2680                    Evidence::Reported => "reported",
2681                    Evidence::Paradox => "paradox",
2682                };
2683                Ok(Value::String(Rc::new(level.to_string())))
2684            }
2685            _ => Ok(Value::String(Rc::new("known".to_string()))), // Non-evidential values are known
2686        }
2687    });
2688
2689    define(interp, "is_known", Some(1), |_, args| {
2690        match &args[0] {
2691            Value::Evidential {
2692                evidence: Evidence::Known,
2693                ..
2694            } => Ok(Value::Bool(true)),
2695            Value::Evidential { .. } => Ok(Value::Bool(false)),
2696            _ => Ok(Value::Bool(true)), // Non-evidential values are known
2697        }
2698    });
2699
2700    define(interp, "is_uncertain", Some(1), |_, args| match &args[0] {
2701        Value::Evidential {
2702            evidence: Evidence::Uncertain,
2703            ..
2704        } => Ok(Value::Bool(true)),
2705        _ => Ok(Value::Bool(false)),
2706    });
2707
2708    define(interp, "is_reported", Some(1), |_, args| match &args[0] {
2709        Value::Evidential {
2710            evidence: Evidence::Reported,
2711            ..
2712        } => Ok(Value::Bool(true)),
2713        _ => Ok(Value::Bool(false)),
2714    });
2715
2716    define(interp, "is_paradox", Some(1), |_, args| match &args[0] {
2717        Value::Evidential {
2718            evidence: Evidence::Paradox,
2719            ..
2720        } => Ok(Value::Bool(true)),
2721        _ => Ok(Value::Bool(false)),
2722    });
2723
2724    // Extract inner value
2725    define(interp, "strip_evidence", Some(1), |_, args| {
2726        match &args[0] {
2727            Value::Evidential { value, .. } => Ok(*value.clone()),
2728            other => Ok(other.clone()),
2729        }
2730    });
2731
2732    // Trust operations
2733    define(interp, "trust", Some(1), |_, args| {
2734        // Upgrade reported/uncertain to known (with assertion)
2735        match &args[0] {
2736            Value::Evidential { value, .. } => Ok(Value::Evidential {
2737                value: value.clone(),
2738                evidence: Evidence::Known,
2739            }),
2740            other => Ok(other.clone()),
2741        }
2742    });
2743
2744    define(interp, "verify", Some(2), |_, args| {
2745        // Verify evidential value with predicate, upgrading if true
2746        let pred_result = match &args[1] {
2747            Value::Bool(b) => *b,
2748            _ => return Err(RuntimeError::new("verify() predicate must be bool")),
2749        };
2750
2751        if pred_result {
2752            match &args[0] {
2753                Value::Evidential { value, .. } => Ok(Value::Evidential {
2754                    value: value.clone(),
2755                    evidence: Evidence::Known,
2756                }),
2757                other => Ok(other.clone()),
2758            }
2759        } else {
2760            Ok(args[0].clone()) // Keep original evidence
2761        }
2762    });
2763
2764    // Combine evidence (join in lattice)
2765    define(interp, "combine_evidence", Some(2), |_, args| {
2766        let ev1 = match &args[0] {
2767            Value::Evidential { evidence, .. } => *evidence,
2768            _ => Evidence::Known,
2769        };
2770        let ev2 = match &args[1] {
2771            Value::Evidential { evidence, .. } => *evidence,
2772            _ => Evidence::Known,
2773        };
2774
2775        // Join: max of the two
2776        let combined = match (ev1, ev2) {
2777            (Evidence::Paradox, _) | (_, Evidence::Paradox) => Evidence::Paradox,
2778            (Evidence::Reported, _) | (_, Evidence::Reported) => Evidence::Reported,
2779            (Evidence::Uncertain, _) | (_, Evidence::Uncertain) => Evidence::Uncertain,
2780            _ => Evidence::Known,
2781        };
2782
2783        Ok(Value::String(Rc::new(
2784            match combined {
2785                Evidence::Known => "known",
2786                Evidence::Uncertain => "uncertain",
2787                Evidence::Reported => "reported",
2788                Evidence::Paradox => "paradox",
2789            }
2790            .to_string(),
2791        )))
2792    });
2793
2794    // === Affect-Evidence Integration ===
2795
2796    // Derive evidence from affect markers
2797    define(interp, "affect_to_evidence", Some(1), |_, args| {
2798        match &args[0] {
2799            Value::Affective { affect, .. } => {
2800                // Sarcasm implies uncertainty (meaning is inverted)
2801                if affect.sarcasm {
2802                    return Ok(Value::String(Rc::new("uncertain".to_string())));
2803                }
2804                // Confidence maps to evidence
2805                match affect.confidence {
2806                    Some(RuntimeConfidence::High) => {
2807                        Ok(Value::String(Rc::new("known".to_string())))
2808                    }
2809                    Some(RuntimeConfidence::Low) => {
2810                        Ok(Value::String(Rc::new("uncertain".to_string())))
2811                    }
2812                    _ => Ok(Value::String(Rc::new("known".to_string()))),
2813                }
2814            }
2815            _ => Ok(Value::String(Rc::new("known".to_string()))),
2816        }
2817    });
2818
2819    // Convert affective value to evidential based on affect markers
2820    define(
2821        interp,
2822        "affect_as_evidence",
2823        Some(1),
2824        |_, args| match &args[0] {
2825            Value::Affective { value, affect } => {
2826                let evidence = if affect.sarcasm {
2827                    Evidence::Uncertain
2828                } else {
2829                    match affect.confidence {
2830                        Some(RuntimeConfidence::High) => Evidence::Known,
2831                        Some(RuntimeConfidence::Low) => Evidence::Uncertain,
2832                        _ => Evidence::Known,
2833                    }
2834                };
2835                Ok(Value::Evidential {
2836                    value: value.clone(),
2837                    evidence,
2838                })
2839            }
2840            other => Ok(other.clone()),
2841        },
2842    );
2843
2844    // Check if affective value implies uncertainty
2845    define(
2846        interp,
2847        "is_affect_uncertain",
2848        Some(1),
2849        |_, args| match &args[0] {
2850            Value::Affective { affect, .. } => {
2851                let uncertain =
2852                    affect.sarcasm || matches!(affect.confidence, Some(RuntimeConfidence::Low));
2853                Ok(Value::Bool(uncertain))
2854            }
2855            _ => Ok(Value::Bool(false)),
2856        },
2857    );
2858
2859    // Combine affect and evidence (wrap evidential in affect or vice versa)
2860    define(interp, "with_affect_evidence", Some(2), |_, args| {
2861        // args[0] = affect source, args[1] = value to wrap
2862        match &args[0] {
2863            Value::Affective { affect, .. } => {
2864                let evidence = if affect.sarcasm {
2865                    Evidence::Uncertain
2866                } else {
2867                    match affect.confidence {
2868                        Some(RuntimeConfidence::High) => Evidence::Known,
2869                        Some(RuntimeConfidence::Low) => Evidence::Uncertain,
2870                        _ => Evidence::Known,
2871                    }
2872                };
2873                Ok(Value::Evidential {
2874                    value: Box::new(args[1].clone()),
2875                    evidence,
2876                })
2877            }
2878            Value::Evidential { evidence, .. } => {
2879                // Preserve evidence on the new value
2880                Ok(Value::Evidential {
2881                    value: Box::new(args[1].clone()),
2882                    evidence: *evidence,
2883                })
2884            }
2885            _ => Ok(args[1].clone()),
2886        }
2887    });
2888}
2889
2890// ============================================================================
2891// AFFECT FUNCTIONS (Sentiment, Emotion, Sarcasm markers)
2892// ============================================================================
2893
2894fn register_affect(interp: &mut Interpreter) {
2895    use crate::interpreter::{
2896        RuntimeAffect, RuntimeConfidence, RuntimeEmotion, RuntimeFormality, RuntimeIntensity,
2897        RuntimeSentiment,
2898    };
2899
2900    // === Create affective values ===
2901
2902    // Sentiment markers
2903    define(interp, "positive", Some(1), |_, args| {
2904        Ok(Value::Affective {
2905            value: Box::new(args[0].clone()),
2906            affect: RuntimeAffect {
2907                sentiment: Some(RuntimeSentiment::Positive),
2908                sarcasm: false,
2909                intensity: None,
2910                formality: None,
2911                emotion: None,
2912                confidence: None,
2913            },
2914        })
2915    });
2916
2917    define(interp, "negative", Some(1), |_, args| {
2918        Ok(Value::Affective {
2919            value: Box::new(args[0].clone()),
2920            affect: RuntimeAffect {
2921                sentiment: Some(RuntimeSentiment::Negative),
2922                sarcasm: false,
2923                intensity: None,
2924                formality: None,
2925                emotion: None,
2926                confidence: None,
2927            },
2928        })
2929    });
2930
2931    define(interp, "neutral", Some(1), |_, args| {
2932        Ok(Value::Affective {
2933            value: Box::new(args[0].clone()),
2934            affect: RuntimeAffect {
2935                sentiment: Some(RuntimeSentiment::Neutral),
2936                sarcasm: false,
2937                intensity: None,
2938                formality: None,
2939                emotion: None,
2940                confidence: None,
2941            },
2942        })
2943    });
2944
2945    // Sarcasm marker
2946    define(interp, "sarcastic", Some(1), |_, args| {
2947        Ok(Value::Affective {
2948            value: Box::new(args[0].clone()),
2949            affect: RuntimeAffect {
2950                sentiment: None,
2951                sarcasm: true,
2952                intensity: None,
2953                formality: None,
2954                emotion: None,
2955                confidence: None,
2956            },
2957        })
2958    });
2959
2960    // Intensity markers
2961    define(interp, "intensify", Some(1), |_, args| {
2962        Ok(Value::Affective {
2963            value: Box::new(args[0].clone()),
2964            affect: RuntimeAffect {
2965                sentiment: None,
2966                sarcasm: false,
2967                intensity: Some(RuntimeIntensity::Up),
2968                formality: None,
2969                emotion: None,
2970                confidence: None,
2971            },
2972        })
2973    });
2974
2975    define(interp, "dampen", Some(1), |_, args| {
2976        Ok(Value::Affective {
2977            value: Box::new(args[0].clone()),
2978            affect: RuntimeAffect {
2979                sentiment: None,
2980                sarcasm: false,
2981                intensity: Some(RuntimeIntensity::Down),
2982                formality: None,
2983                emotion: None,
2984                confidence: None,
2985            },
2986        })
2987    });
2988
2989    define(interp, "maximize", Some(1), |_, args| {
2990        Ok(Value::Affective {
2991            value: Box::new(args[0].clone()),
2992            affect: RuntimeAffect {
2993                sentiment: None,
2994                sarcasm: false,
2995                intensity: Some(RuntimeIntensity::Max),
2996                formality: None,
2997                emotion: None,
2998                confidence: None,
2999            },
3000        })
3001    });
3002
3003    // Formality markers
3004    define(interp, "formal", Some(1), |_, args| {
3005        Ok(Value::Affective {
3006            value: Box::new(args[0].clone()),
3007            affect: RuntimeAffect {
3008                sentiment: None,
3009                sarcasm: false,
3010                intensity: None,
3011                formality: Some(RuntimeFormality::Formal),
3012                emotion: None,
3013                confidence: None,
3014            },
3015        })
3016    });
3017
3018    define(interp, "informal", Some(1), |_, args| {
3019        Ok(Value::Affective {
3020            value: Box::new(args[0].clone()),
3021            affect: RuntimeAffect {
3022                sentiment: None,
3023                sarcasm: false,
3024                intensity: None,
3025                formality: Some(RuntimeFormality::Informal),
3026                emotion: None,
3027                confidence: None,
3028            },
3029        })
3030    });
3031
3032    // Emotion markers (Plutchik's wheel)
3033    define(interp, "joyful", Some(1), |_, args| {
3034        Ok(Value::Affective {
3035            value: Box::new(args[0].clone()),
3036            affect: RuntimeAffect {
3037                sentiment: None,
3038                sarcasm: false,
3039                intensity: None,
3040                formality: None,
3041                emotion: Some(RuntimeEmotion::Joy),
3042                confidence: None,
3043            },
3044        })
3045    });
3046
3047    define(interp, "sad", Some(1), |_, args| {
3048        Ok(Value::Affective {
3049            value: Box::new(args[0].clone()),
3050            affect: RuntimeAffect {
3051                sentiment: None,
3052                sarcasm: false,
3053                intensity: None,
3054                formality: None,
3055                emotion: Some(RuntimeEmotion::Sadness),
3056                confidence: None,
3057            },
3058        })
3059    });
3060
3061    define(interp, "angry", Some(1), |_, args| {
3062        Ok(Value::Affective {
3063            value: Box::new(args[0].clone()),
3064            affect: RuntimeAffect {
3065                sentiment: None,
3066                sarcasm: false,
3067                intensity: None,
3068                formality: None,
3069                emotion: Some(RuntimeEmotion::Anger),
3070                confidence: None,
3071            },
3072        })
3073    });
3074
3075    define(interp, "fearful", Some(1), |_, args| {
3076        Ok(Value::Affective {
3077            value: Box::new(args[0].clone()),
3078            affect: RuntimeAffect {
3079                sentiment: None,
3080                sarcasm: false,
3081                intensity: None,
3082                formality: None,
3083                emotion: Some(RuntimeEmotion::Fear),
3084                confidence: None,
3085            },
3086        })
3087    });
3088
3089    define(interp, "surprised", Some(1), |_, args| {
3090        Ok(Value::Affective {
3091            value: Box::new(args[0].clone()),
3092            affect: RuntimeAffect {
3093                sentiment: None,
3094                sarcasm: false,
3095                intensity: None,
3096                formality: None,
3097                emotion: Some(RuntimeEmotion::Surprise),
3098                confidence: None,
3099            },
3100        })
3101    });
3102
3103    define(interp, "loving", Some(1), |_, args| {
3104        Ok(Value::Affective {
3105            value: Box::new(args[0].clone()),
3106            affect: RuntimeAffect {
3107                sentiment: None,
3108                sarcasm: false,
3109                intensity: None,
3110                formality: None,
3111                emotion: Some(RuntimeEmotion::Love),
3112                confidence: None,
3113            },
3114        })
3115    });
3116
3117    // Confidence markers
3118    define(interp, "high_confidence", Some(1), |_, args| {
3119        Ok(Value::Affective {
3120            value: Box::new(args[0].clone()),
3121            affect: RuntimeAffect {
3122                sentiment: None,
3123                sarcasm: false,
3124                intensity: None,
3125                formality: None,
3126                emotion: None,
3127                confidence: Some(RuntimeConfidence::High),
3128            },
3129        })
3130    });
3131
3132    define(interp, "medium_confidence", Some(1), |_, args| {
3133        Ok(Value::Affective {
3134            value: Box::new(args[0].clone()),
3135            affect: RuntimeAffect {
3136                sentiment: None,
3137                sarcasm: false,
3138                intensity: None,
3139                formality: None,
3140                emotion: None,
3141                confidence: Some(RuntimeConfidence::Medium),
3142            },
3143        })
3144    });
3145
3146    define(interp, "low_confidence", Some(1), |_, args| {
3147        Ok(Value::Affective {
3148            value: Box::new(args[0].clone()),
3149            affect: RuntimeAffect {
3150                sentiment: None,
3151                sarcasm: false,
3152                intensity: None,
3153                formality: None,
3154                emotion: None,
3155                confidence: Some(RuntimeConfidence::Low),
3156            },
3157        })
3158    });
3159
3160    // === Query affect ===
3161
3162    define(interp, "affect_of", Some(1), |_, args| match &args[0] {
3163        Value::Affective { affect, .. } => {
3164            let mut parts = Vec::new();
3165            if let Some(s) = &affect.sentiment {
3166                parts.push(match s {
3167                    RuntimeSentiment::Positive => "positive",
3168                    RuntimeSentiment::Negative => "negative",
3169                    RuntimeSentiment::Neutral => "neutral",
3170                });
3171            }
3172            if affect.sarcasm {
3173                parts.push("sarcastic");
3174            }
3175            if let Some(i) = &affect.intensity {
3176                parts.push(match i {
3177                    RuntimeIntensity::Up => "intensified",
3178                    RuntimeIntensity::Down => "dampened",
3179                    RuntimeIntensity::Max => "maximized",
3180                });
3181            }
3182            if let Some(f) = &affect.formality {
3183                parts.push(match f {
3184                    RuntimeFormality::Formal => "formal",
3185                    RuntimeFormality::Informal => "informal",
3186                });
3187            }
3188            if let Some(e) = &affect.emotion {
3189                parts.push(match e {
3190                    RuntimeEmotion::Joy => "joyful",
3191                    RuntimeEmotion::Sadness => "sad",
3192                    RuntimeEmotion::Anger => "angry",
3193                    RuntimeEmotion::Fear => "fearful",
3194                    RuntimeEmotion::Surprise => "surprised",
3195                    RuntimeEmotion::Love => "loving",
3196                });
3197            }
3198            if let Some(c) = &affect.confidence {
3199                parts.push(match c {
3200                    RuntimeConfidence::High => "high_confidence",
3201                    RuntimeConfidence::Medium => "medium_confidence",
3202                    RuntimeConfidence::Low => "low_confidence",
3203                });
3204            }
3205            Ok(Value::String(Rc::new(parts.join(", "))))
3206        }
3207        _ => Ok(Value::String(Rc::new("none".to_string()))),
3208    });
3209
3210    define(interp, "is_sarcastic", Some(1), |_, args| match &args[0] {
3211        Value::Affective { affect, .. } => Ok(Value::Bool(affect.sarcasm)),
3212        _ => Ok(Value::Bool(false)),
3213    });
3214
3215    define(interp, "is_positive", Some(1), |_, args| match &args[0] {
3216        Value::Affective { affect, .. } => Ok(Value::Bool(matches!(
3217            affect.sentiment,
3218            Some(RuntimeSentiment::Positive)
3219        ))),
3220        _ => Ok(Value::Bool(false)),
3221    });
3222
3223    define(interp, "is_negative", Some(1), |_, args| match &args[0] {
3224        Value::Affective { affect, .. } => Ok(Value::Bool(matches!(
3225            affect.sentiment,
3226            Some(RuntimeSentiment::Negative)
3227        ))),
3228        _ => Ok(Value::Bool(false)),
3229    });
3230
3231    define(interp, "is_formal", Some(1), |_, args| match &args[0] {
3232        Value::Affective { affect, .. } => Ok(Value::Bool(matches!(
3233            affect.formality,
3234            Some(RuntimeFormality::Formal)
3235        ))),
3236        _ => Ok(Value::Bool(false)),
3237    });
3238
3239    define(interp, "is_informal", Some(1), |_, args| match &args[0] {
3240        Value::Affective { affect, .. } => Ok(Value::Bool(matches!(
3241            affect.formality,
3242            Some(RuntimeFormality::Informal)
3243        ))),
3244        _ => Ok(Value::Bool(false)),
3245    });
3246
3247    define(interp, "emotion_of", Some(1), |_, args| match &args[0] {
3248        Value::Affective { affect, .. } => {
3249            let emotion_str = match &affect.emotion {
3250                Some(RuntimeEmotion::Joy) => "joy",
3251                Some(RuntimeEmotion::Sadness) => "sadness",
3252                Some(RuntimeEmotion::Anger) => "anger",
3253                Some(RuntimeEmotion::Fear) => "fear",
3254                Some(RuntimeEmotion::Surprise) => "surprise",
3255                Some(RuntimeEmotion::Love) => "love",
3256                None => "none",
3257            };
3258            Ok(Value::String(Rc::new(emotion_str.to_string())))
3259        }
3260        _ => Ok(Value::String(Rc::new("none".to_string()))),
3261    });
3262
3263    define(interp, "confidence_of", Some(1), |_, args| match &args[0] {
3264        Value::Affective { affect, .. } => {
3265            let conf_str = match &affect.confidence {
3266                Some(RuntimeConfidence::High) => "high",
3267                Some(RuntimeConfidence::Medium) => "medium",
3268                Some(RuntimeConfidence::Low) => "low",
3269                None => "none",
3270            };
3271            Ok(Value::String(Rc::new(conf_str.to_string())))
3272        }
3273        _ => Ok(Value::String(Rc::new("none".to_string()))),
3274    });
3275
3276    // Extract inner value
3277    define(interp, "strip_affect", Some(1), |_, args| match &args[0] {
3278        Value::Affective { value, .. } => Ok(*value.clone()),
3279        other => Ok(other.clone()),
3280    });
3281
3282    // Create full affect with multiple markers
3283    define(interp, "with_affect", None, |_, args| {
3284        if args.is_empty() {
3285            return Err(RuntimeError::new(
3286                "with_affect requires at least one argument",
3287            ));
3288        }
3289
3290        let base_value = args[0].clone();
3291        let mut affect = RuntimeAffect {
3292            sentiment: None,
3293            sarcasm: false,
3294            intensity: None,
3295            formality: None,
3296            emotion: None,
3297            confidence: None,
3298        };
3299
3300        // Parse string markers from remaining args
3301        for arg in args.iter().skip(1) {
3302            if let Value::String(s) = arg {
3303                match s.as_str() {
3304                    "positive" | "⊕" => affect.sentiment = Some(RuntimeSentiment::Positive),
3305                    "negative" | "⊖" => affect.sentiment = Some(RuntimeSentiment::Negative),
3306                    "neutral" | "⊜" => affect.sentiment = Some(RuntimeSentiment::Neutral),
3307                    "sarcastic" | "⸮" => affect.sarcasm = true,
3308                    "intensify" | "↑" => affect.intensity = Some(RuntimeIntensity::Up),
3309                    "dampen" | "↓" => affect.intensity = Some(RuntimeIntensity::Down),
3310                    "maximize" | "⇈" => affect.intensity = Some(RuntimeIntensity::Max),
3311                    "formal" | "♔" => affect.formality = Some(RuntimeFormality::Formal),
3312                    "informal" | "♟" => affect.formality = Some(RuntimeFormality::Informal),
3313                    "joy" | "☺" => affect.emotion = Some(RuntimeEmotion::Joy),
3314                    "sadness" | "☹" => affect.emotion = Some(RuntimeEmotion::Sadness),
3315                    "anger" | "⚡" => affect.emotion = Some(RuntimeEmotion::Anger),
3316                    "fear" | "❄" => affect.emotion = Some(RuntimeEmotion::Fear),
3317                    "surprise" | "✦" => affect.emotion = Some(RuntimeEmotion::Surprise),
3318                    "love" | "♡" => affect.emotion = Some(RuntimeEmotion::Love),
3319                    "high" | "◉" => affect.confidence = Some(RuntimeConfidence::High),
3320                    "medium" | "◎" => affect.confidence = Some(RuntimeConfidence::Medium),
3321                    "low" | "○" => affect.confidence = Some(RuntimeConfidence::Low),
3322                    _ => {}
3323                }
3324            }
3325        }
3326
3327        Ok(Value::Affective {
3328            value: Box::new(base_value),
3329            affect,
3330        })
3331    });
3332}
3333
3334// ============================================================================
3335// ITERATOR-STYLE FUNCTIONS (for use in pipes)
3336// ============================================================================
3337
3338fn register_iter(interp: &mut Interpreter) {
3339    // sum - sum all elements
3340    define(interp, "sum", Some(1), |_, args| match &args[0] {
3341        Value::Array(arr) => {
3342            let mut sum_int: i64 = 0;
3343            let mut sum_float: f64 = 0.0;
3344            let mut is_float = false;
3345
3346            for val in arr.borrow().iter() {
3347                match val {
3348                    Value::Int(n) => {
3349                        if is_float {
3350                            sum_float += *n as f64;
3351                        } else {
3352                            sum_int += n;
3353                        }
3354                    }
3355                    Value::Float(n) => {
3356                        if !is_float {
3357                            sum_float = sum_int as f64;
3358                            is_float = true;
3359                        }
3360                        sum_float += n;
3361                    }
3362                    _ => return Err(RuntimeError::new("sum() requires array of numbers")),
3363                }
3364            }
3365
3366            if is_float {
3367                Ok(Value::Float(sum_float))
3368            } else {
3369                Ok(Value::Int(sum_int))
3370            }
3371        }
3372        _ => Err(RuntimeError::new("sum() requires array")),
3373    });
3374
3375    // product - multiply all elements
3376    define(interp, "product", Some(1), |_, args| match &args[0] {
3377        Value::Array(arr) => {
3378            let mut prod_int: i64 = 1;
3379            let mut prod_float: f64 = 1.0;
3380            let mut is_float = false;
3381
3382            for val in arr.borrow().iter() {
3383                match val {
3384                    Value::Int(n) => {
3385                        if is_float {
3386                            prod_float *= *n as f64;
3387                        } else {
3388                            prod_int *= n;
3389                        }
3390                    }
3391                    Value::Float(n) => {
3392                        if !is_float {
3393                            prod_float = prod_int as f64;
3394                            is_float = true;
3395                        }
3396                        prod_float *= n;
3397                    }
3398                    _ => return Err(RuntimeError::new("product() requires array of numbers")),
3399                }
3400            }
3401
3402            if is_float {
3403                Ok(Value::Float(prod_float))
3404            } else {
3405                Ok(Value::Int(prod_int))
3406            }
3407        }
3408        _ => Err(RuntimeError::new("product() requires array")),
3409    });
3410
3411    // mean - average of elements
3412    define(interp, "mean", Some(1), |_, args| match &args[0] {
3413        Value::Array(arr) => {
3414            let arr = arr.borrow();
3415            if arr.is_empty() {
3416                return Err(RuntimeError::new("mean() on empty array"));
3417            }
3418
3419            let mut sum: f64 = 0.0;
3420            for val in arr.iter() {
3421                match val {
3422                    Value::Int(n) => sum += *n as f64,
3423                    Value::Float(n) => sum += n,
3424                    _ => return Err(RuntimeError::new("mean() requires array of numbers")),
3425                }
3426            }
3427
3428            Ok(Value::Float(sum / arr.len() as f64))
3429        }
3430        _ => Err(RuntimeError::new("mean() requires array")),
3431    });
3432
3433    // median - middle value
3434    define(interp, "median", Some(1), |_, args| match &args[0] {
3435        Value::Array(arr) => {
3436            let arr = arr.borrow();
3437            if arr.is_empty() {
3438                return Err(RuntimeError::new("median() on empty array"));
3439            }
3440
3441            let mut nums: Vec<f64> = Vec::new();
3442            for val in arr.iter() {
3443                match val {
3444                    Value::Int(n) => nums.push(*n as f64),
3445                    Value::Float(n) => nums.push(*n),
3446                    _ => return Err(RuntimeError::new("median() requires array of numbers")),
3447                }
3448            }
3449
3450            nums.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
3451            let mid = nums.len() / 2;
3452
3453            if nums.len() % 2 == 0 {
3454                Ok(Value::Float((nums[mid - 1] + nums[mid]) / 2.0))
3455            } else {
3456                Ok(Value::Float(nums[mid]))
3457            }
3458        }
3459        _ => Err(RuntimeError::new("median() requires array")),
3460    });
3461
3462    // min_of - minimum of array
3463    define(interp, "min_of", Some(1), |_, args| match &args[0] {
3464        Value::Array(arr) => {
3465            let arr = arr.borrow();
3466            if arr.is_empty() {
3467                return Err(RuntimeError::new("min_of() on empty array"));
3468            }
3469
3470            let mut min = &arr[0];
3471            for val in arr.iter().skip(1) {
3472                if matches!(compare_values(val, min), std::cmp::Ordering::Less) {
3473                    min = val;
3474                }
3475            }
3476            Ok(min.clone())
3477        }
3478        _ => Err(RuntimeError::new("min_of() requires array")),
3479    });
3480
3481    // max_of - maximum of array
3482    define(interp, "max_of", Some(1), |_, args| match &args[0] {
3483        Value::Array(arr) => {
3484            let arr = arr.borrow();
3485            if arr.is_empty() {
3486                return Err(RuntimeError::new("max_of() on empty array"));
3487            }
3488
3489            let mut max = &arr[0];
3490            for val in arr.iter().skip(1) {
3491                if matches!(compare_values(val, max), std::cmp::Ordering::Greater) {
3492                    max = val;
3493                }
3494            }
3495            Ok(max.clone())
3496        }
3497        _ => Err(RuntimeError::new("max_of() requires array")),
3498    });
3499
3500    // count - count elements (optionally matching predicate)
3501    define(interp, "count", Some(1), |_, args| match &args[0] {
3502        Value::Array(arr) => Ok(Value::Int(arr.borrow().len() as i64)),
3503        Value::String(s) => Ok(Value::Int(s.chars().count() as i64)),
3504        _ => Err(RuntimeError::new("count() requires array or string")),
3505    });
3506
3507    // any - check if any element is truthy
3508    define(interp, "any", Some(1), |_, args| match &args[0] {
3509        Value::Array(arr) => {
3510            for val in arr.borrow().iter() {
3511                if is_truthy(val) {
3512                    return Ok(Value::Bool(true));
3513                }
3514            }
3515            Ok(Value::Bool(false))
3516        }
3517        _ => Err(RuntimeError::new("any() requires array")),
3518    });
3519
3520    // all - check if all elements are truthy
3521    define(interp, "all", Some(1), |_, args| match &args[0] {
3522        Value::Array(arr) => {
3523            for val in arr.borrow().iter() {
3524                if !is_truthy(val) {
3525                    return Ok(Value::Bool(false));
3526                }
3527            }
3528            Ok(Value::Bool(true))
3529        }
3530        _ => Err(RuntimeError::new("all() requires array")),
3531    });
3532
3533    // none - check if no elements are truthy
3534    define(interp, "none", Some(1), |_, args| match &args[0] {
3535        Value::Array(arr) => {
3536            for val in arr.borrow().iter() {
3537                if is_truthy(val) {
3538                    return Ok(Value::Bool(false));
3539                }
3540            }
3541            Ok(Value::Bool(true))
3542        }
3543        _ => Err(RuntimeError::new("none() requires array")),
3544    });
3545}
3546
3547fn is_truthy(val: &Value) -> bool {
3548    match val {
3549        Value::Null | Value::Empty => false,
3550        Value::Bool(b) => *b,
3551        Value::Int(n) => *n != 0,
3552        Value::Float(n) => *n != 0.0 && !n.is_nan(),
3553        Value::String(s) => !s.is_empty(),
3554        Value::Array(arr) => !arr.borrow().is_empty(),
3555        Value::Evidential { value, .. } => is_truthy(value),
3556        _ => true,
3557    }
3558}
3559
3560// ============================================================================
3561// I/O FUNCTIONS
3562// ============================================================================
3563
3564fn register_io(interp: &mut Interpreter) {
3565    // read_file - read entire file as string
3566    define(interp, "read_file", Some(1), |_, args| {
3567        match &args[0] {
3568            Value::String(path) => {
3569                match std::fs::read_to_string(path.as_str()) {
3570                    Ok(content) => Ok(Value::Evidential {
3571                        value: Box::new(Value::String(Rc::new(content))),
3572                        evidence: Evidence::Reported, // File contents are reported, not known
3573                    }),
3574                    Err(e) => Err(RuntimeError::new(format!("read_file failed: {}", e))),
3575                }
3576            }
3577            _ => Err(RuntimeError::new("read_file() requires path string")),
3578        }
3579    });
3580
3581    // write_file - write string to file
3582    define(interp, "write_file", Some(2), |_, args| {
3583        match (&args[0], &args[1]) {
3584            (Value::String(path), Value::String(content)) => {
3585                match std::fs::write(path.as_str(), content.as_str()) {
3586                    Ok(_) => Ok(Value::Bool(true)),
3587                    Err(e) => Err(RuntimeError::new(format!("write_file failed: {}", e))),
3588                }
3589            }
3590            _ => Err(RuntimeError::new(
3591                "write_file() requires path and content strings",
3592            )),
3593        }
3594    });
3595
3596    // append_file - append to file
3597    define(interp, "append_file", Some(2), |_, args| {
3598        match (&args[0], &args[1]) {
3599            (Value::String(path), Value::String(content)) => {
3600                use std::fs::OpenOptions;
3601                let result = OpenOptions::new()
3602                    .create(true)
3603                    .append(true)
3604                    .open(path.as_str())
3605                    .and_then(|mut f| f.write_all(content.as_bytes()));
3606                match result {
3607                    Ok(_) => Ok(Value::Bool(true)),
3608                    Err(e) => Err(RuntimeError::new(format!("append_file failed: {}", e))),
3609                }
3610            }
3611            _ => Err(RuntimeError::new(
3612                "append_file() requires path and content strings",
3613            )),
3614        }
3615    });
3616
3617    // file_exists - check if file exists
3618    define(interp, "file_exists", Some(1), |_, args| match &args[0] {
3619        Value::String(path) => Ok(Value::Bool(std::path::Path::new(path.as_str()).exists())),
3620        _ => Err(RuntimeError::new("file_exists() requires path string")),
3621    });
3622
3623    // read_lines - read file as array of lines
3624    define(interp, "read_lines", Some(1), |_, args| match &args[0] {
3625        Value::String(path) => match std::fs::read_to_string(path.as_str()) {
3626            Ok(content) => {
3627                let lines: Vec<Value> = content
3628                    .lines()
3629                    .map(|l| Value::String(Rc::new(l.to_string())))
3630                    .collect();
3631                Ok(Value::Evidential {
3632                    value: Box::new(Value::Array(Rc::new(RefCell::new(lines)))),
3633                    evidence: Evidence::Reported,
3634                })
3635            }
3636            Err(e) => Err(RuntimeError::new(format!("read_lines failed: {}", e))),
3637        },
3638        _ => Err(RuntimeError::new("read_lines() requires path string")),
3639    });
3640
3641    // env - get environment variable
3642    define(interp, "env", Some(1), |_, args| {
3643        match &args[0] {
3644            Value::String(name) => {
3645                match std::env::var(name.as_str()) {
3646                    Ok(value) => Ok(Value::Evidential {
3647                        value: Box::new(Value::String(Rc::new(value))),
3648                        evidence: Evidence::Reported, // Env vars are external
3649                    }),
3650                    Err(_) => Ok(Value::Null),
3651                }
3652            }
3653            _ => Err(RuntimeError::new("env() requires variable name string")),
3654        }
3655    });
3656
3657    // env::var - Rust-style env::var that returns Result<String, VarError>
3658    define(interp, "env·var", Some(1), |_, args| {
3659        match &args[0] {
3660            Value::String(name) => {
3661                match std::env::var(name.as_str()) {
3662                    Ok(value) => Ok(Value::Variant {
3663                        enum_name: "Result".to_string(),
3664                        variant_name: "Ok".to_string(),
3665                        fields: Some(Rc::new(vec![Value::String(Rc::new(value))])),
3666                    }),
3667                    Err(_) => Ok(Value::Variant {
3668                        enum_name: "Result".to_string(),
3669                        variant_name: "Err".to_string(),
3670                        fields: Some(Rc::new(vec![Value::String(Rc::new("environment variable not found".to_string()))])),
3671                    }),
3672                }
3673            }
3674            _ => Err(RuntimeError::new("env::var() requires variable name string")),
3675        }
3676    });
3677
3678    // env_or - get environment variable with default
3679    define(interp, "env_or", Some(2), |_, args| {
3680        match (&args[0], &args[1]) {
3681            (Value::String(name), default) => match std::env::var(name.as_str()) {
3682                Ok(value) => Ok(Value::Evidential {
3683                    value: Box::new(Value::String(Rc::new(value))),
3684                    evidence: Evidence::Reported,
3685                }),
3686                Err(_) => Ok(default.clone()),
3687            },
3688            _ => Err(RuntimeError::new("env_or() requires variable name string")),
3689        }
3690    });
3691
3692    // cwd - current working directory
3693    define(interp, "cwd", Some(0), |_, _| {
3694        match std::env::current_dir() {
3695            Ok(path) => Ok(Value::String(Rc::new(path.to_string_lossy().to_string()))),
3696            Err(e) => Err(RuntimeError::new(format!("cwd() failed: {}", e))),
3697        }
3698    });
3699
3700    // args - command line arguments (filtered to exclude interpreter args)
3701    define(interp, "args", Some(0), |interp, _| {
3702        let args: Vec<Value> = if interp.program_args.as_ref().map(|v| v.is_empty()).unwrap_or(true) {
3703            // Fallback: return all args if program_args not set
3704            std::env::args()
3705                .map(|a| Value::String(Rc::new(a)))
3706                .collect()
3707        } else {
3708            // Return filtered program args
3709            interp.program_args.as_ref().unwrap().iter()
3710                .map(|a| Value::String(Rc::new(a.clone())))
3711                .collect()
3712        };
3713        Ok(Value::Array(Rc::new(RefCell::new(args))))
3714    });
3715}
3716
3717// ============================================================================
3718// TIME FUNCTIONS
3719// ============================================================================
3720
3721fn register_time(interp: &mut Interpreter) {
3722    // now - current Unix timestamp in milliseconds
3723    define(interp, "now", Some(0), |_, _| {
3724        let duration = SystemTime::now()
3725            .duration_since(UNIX_EPOCH)
3726            .unwrap_or(Duration::ZERO);
3727        Ok(Value::Int(duration.as_millis() as i64))
3728    });
3729
3730    // now_secs - current Unix timestamp in seconds
3731    define(interp, "now_secs", Some(0), |_, _| {
3732        let duration = SystemTime::now()
3733            .duration_since(UNIX_EPOCH)
3734            .unwrap_or(Duration::ZERO);
3735        Ok(Value::Int(duration.as_secs() as i64))
3736    });
3737
3738    // now_micros - current Unix timestamp in microseconds
3739    define(interp, "now_micros", Some(0), |_, _| {
3740        let duration = SystemTime::now()
3741            .duration_since(UNIX_EPOCH)
3742            .unwrap_or(Duration::ZERO);
3743        Ok(Value::Int(duration.as_micros() as i64))
3744    });
3745
3746    // sleep - sleep for milliseconds
3747    define(interp, "sleep", Some(1), |_, args| match &args[0] {
3748        Value::Int(ms) if *ms >= 0 => {
3749            std::thread::sleep(Duration::from_millis(*ms as u64));
3750            Ok(Value::Null)
3751        }
3752        _ => Err(RuntimeError::new(
3753            "sleep() requires non-negative integer milliseconds",
3754        )),
3755    });
3756
3757    // measure - measure execution time of a thunk (returns ms)
3758    // Note: This would need closure support to work properly
3759    // For now, we provide a simple timer API
3760
3761    // UNIX_EPOCH - constant representing Unix epoch (0 seconds)
3762    define(interp, "UNIX_EPOCH", Some(0), |_, _| {
3763        // Return a struct representing the Unix epoch
3764        let mut fields = std::collections::HashMap::new();
3765        fields.insert("secs".to_string(), Value::Int(0));
3766        fields.insert("nanos".to_string(), Value::Int(0));
3767        Ok(Value::Struct {
3768            name: "SystemTime".to_string(),
3769            fields: Rc::new(RefCell::new(fields)),
3770        })
3771    });
3772
3773    // std::time::UNIX_EPOCH alias
3774    define(interp, "std·time·UNIX_EPOCH", Some(0), |_, _| {
3775        let mut fields = std::collections::HashMap::new();
3776        fields.insert("secs".to_string(), Value::Int(0));
3777        fields.insert("nanos".to_string(), Value::Int(0));
3778        Ok(Value::Struct {
3779            name: "SystemTime".to_string(),
3780            fields: Rc::new(RefCell::new(fields)),
3781        })
3782    });
3783
3784    // timer_start - start a timer (returns opaque handle)
3785    define(interp, "timer_start", Some(0), |_, _| {
3786        let now = Instant::now();
3787        // Store as microseconds since we can't store Instant directly
3788        Ok(Value::Int(now.elapsed().as_nanos() as i64)) // This is a bit hacky
3789    });
3790}
3791
3792// ============================================================================
3793// RANDOM FUNCTIONS
3794// ============================================================================
3795
3796fn register_random(interp: &mut Interpreter) {
3797    // random - random float 0.0 to 1.0
3798    define(interp, "random", Some(0), |_, _| {
3799        // Simple LCG random - not cryptographically secure
3800        use std::time::SystemTime;
3801        let seed = SystemTime::now()
3802            .duration_since(UNIX_EPOCH)
3803            .unwrap_or(Duration::ZERO)
3804            .as_nanos() as u64;
3805        let rand = ((seed.wrapping_mul(1103515245).wrapping_add(12345)) >> 16) as f64;
3806        Ok(Value::Float(rand / u32::MAX as f64))
3807    });
3808
3809    // random_int - random integer in range [min, max)
3810    define(interp, "random_int", Some(2), |_, args| {
3811        match (&args[0], &args[1]) {
3812            (Value::Int(min), Value::Int(max)) if max > min => {
3813                use std::time::SystemTime;
3814                let seed = SystemTime::now()
3815                    .duration_since(UNIX_EPOCH)
3816                    .unwrap_or(Duration::ZERO)
3817                    .as_nanos() as u64;
3818                let range = (max - min) as u64;
3819                let rand = ((seed.wrapping_mul(1103515245).wrapping_add(12345)) >> 16) % range;
3820                Ok(Value::Int(*min + rand as i64))
3821            }
3822            _ => Err(RuntimeError::new(
3823                "random_int() requires min < max integers",
3824            )),
3825        }
3826    });
3827
3828    // shuffle - shuffle array in place (Fisher-Yates)
3829    define(interp, "shuffle", Some(1), |_, args| match &args[0] {
3830        Value::Array(arr) => {
3831            let mut arr = arr.borrow_mut();
3832            use std::time::SystemTime;
3833            let mut seed = SystemTime::now()
3834                .duration_since(UNIX_EPOCH)
3835                .unwrap_or(Duration::ZERO)
3836                .as_nanos() as u64;
3837
3838            for i in (1..arr.len()).rev() {
3839                seed = seed.wrapping_mul(1103515245).wrapping_add(12345);
3840                let j = ((seed >> 16) as usize) % (i + 1);
3841                arr.swap(i, j);
3842            }
3843            Ok(Value::Null)
3844        }
3845        _ => Err(RuntimeError::new("shuffle() requires array")),
3846    });
3847
3848    // sample - random sample from array
3849    define(interp, "sample", Some(1), |_, args| match &args[0] {
3850        Value::Array(arr) => {
3851            let arr = arr.borrow();
3852            if arr.is_empty() {
3853                return Err(RuntimeError::new("sample() on empty array"));
3854            }
3855
3856            use std::time::SystemTime;
3857            let seed = SystemTime::now()
3858                .duration_since(UNIX_EPOCH)
3859                .unwrap_or(Duration::ZERO)
3860                .as_nanos() as u64;
3861            let idx =
3862                ((seed.wrapping_mul(1103515245).wrapping_add(12345)) >> 16) as usize % arr.len();
3863            Ok(arr[idx].clone())
3864        }
3865        _ => Err(RuntimeError::new("sample() requires array")),
3866    });
3867}
3868
3869// ============================================================================
3870// CONVERSION FUNCTIONS
3871// ============================================================================
3872
3873fn register_convert(interp: &mut Interpreter) {
3874    // to_string - convert to string
3875    define(interp, "to_string", Some(1), |_, args| {
3876        Ok(Value::String(Rc::new(format!("{}", args[0]))))
3877    });
3878
3879    // to_int - convert to integer
3880    define(interp, "to_int", Some(1), |_, args| match &args[0] {
3881        Value::Int(n) => Ok(Value::Int(*n)),
3882        Value::Float(n) => Ok(Value::Int(*n as i64)),
3883        Value::Bool(b) => Ok(Value::Int(if *b { 1 } else { 0 })),
3884        Value::Char(c) => Ok(Value::Int(*c as i64)),
3885        Value::String(s) => s
3886            .parse::<i64>()
3887            .map(Value::Int)
3888            .map_err(|_| RuntimeError::new(format!("cannot parse '{}' as integer", s))),
3889        _ => Err(RuntimeError::new("to_int() cannot convert this type")),
3890    });
3891
3892    // to_float - convert to float
3893    define(interp, "to_float", Some(1), |_, args| match &args[0] {
3894        Value::Int(n) => Ok(Value::Float(*n as f64)),
3895        Value::Float(n) => Ok(Value::Float(*n)),
3896        Value::Bool(b) => Ok(Value::Float(if *b { 1.0 } else { 0.0 })),
3897        Value::String(s) => s
3898            .parse::<f64>()
3899            .map(Value::Float)
3900            .map_err(|_| RuntimeError::new(format!("cannot parse '{}' as float", s))),
3901        _ => Err(RuntimeError::new("to_float() cannot convert this type")),
3902    });
3903
3904    // to_bool - convert to boolean
3905    define(interp, "to_bool", Some(1), |_, args| {
3906        Ok(Value::Bool(is_truthy(&args[0])))
3907    });
3908
3909    // to_char - convert to character
3910    define(interp, "to_char", Some(1), |_, args| match &args[0] {
3911        Value::Char(c) => Ok(Value::Char(*c)),
3912        Value::Int(n) => char::from_u32(*n as u32)
3913            .map(Value::Char)
3914            .ok_or_else(|| RuntimeError::new(format!("invalid char code: {}", n))),
3915        Value::String(s) => s
3916            .chars()
3917            .next()
3918            .map(Value::Char)
3919            .ok_or_else(|| RuntimeError::new("to_char() on empty string")),
3920        _ => Err(RuntimeError::new("to_char() cannot convert this type")),
3921    });
3922
3923    // to_array - convert to array
3924    define(interp, "to_array", Some(1), |_, args| match &args[0] {
3925        Value::Array(arr) => Ok(Value::Array(arr.clone())),
3926        Value::Tuple(t) => Ok(Value::Array(Rc::new(RefCell::new(t.as_ref().clone())))),
3927        Value::String(s) => {
3928            let chars: Vec<Value> = s.chars().map(Value::Char).collect();
3929            Ok(Value::Array(Rc::new(RefCell::new(chars))))
3930        }
3931        _ => Ok(Value::Array(Rc::new(RefCell::new(vec![args[0].clone()])))),
3932    });
3933
3934    // to_tuple - convert to tuple
3935    define(interp, "to_tuple", Some(1), |_, args| match &args[0] {
3936        Value::Tuple(t) => Ok(Value::Tuple(t.clone())),
3937        Value::Array(arr) => Ok(Value::Tuple(Rc::new(arr.borrow().clone()))),
3938        _ => Ok(Value::Tuple(Rc::new(vec![args[0].clone()]))),
3939    });
3940
3941    // char_code - get unicode code point
3942    define(interp, "char_code", Some(1), |_, args| match &args[0] {
3943        Value::Char(c) => Ok(Value::Int(*c as i64)),
3944        _ => Err(RuntimeError::new("char_code() requires char")),
3945    });
3946
3947    // from_char_code - create char from code point
3948    define(interp, "from_char_code", Some(1), |_, args| {
3949        match &args[0] {
3950            Value::Int(n) => char::from_u32(*n as u32)
3951                .map(Value::Char)
3952                .ok_or_else(|| RuntimeError::new(format!("invalid char code: {}", n))),
3953            _ => Err(RuntimeError::new("from_char_code() requires integer")),
3954        }
3955    });
3956
3957    // hex - convert to hex string
3958    define(interp, "hex", Some(1), |_, args| match &args[0] {
3959        Value::Int(n) => Ok(Value::String(Rc::new(format!("{:x}", n)))),
3960        _ => Err(RuntimeError::new("hex() requires integer")),
3961    });
3962
3963    // oct - convert to octal string
3964    define(interp, "oct", Some(1), |_, args| match &args[0] {
3965        Value::Int(n) => Ok(Value::String(Rc::new(format!("{:o}", n)))),
3966        _ => Err(RuntimeError::new("oct() requires integer")),
3967    });
3968
3969    // bin - convert to binary string
3970    define(interp, "bin", Some(1), |_, args| match &args[0] {
3971        Value::Int(n) => Ok(Value::String(Rc::new(format!("{:b}", n)))),
3972        _ => Err(RuntimeError::new("bin() requires integer")),
3973    });
3974
3975    // parse_int - parse string as integer with optional base
3976    define(interp, "parse_int", Some(2), |_, args| {
3977        match (&args[0], &args[1]) {
3978            (Value::String(s), Value::Int(base)) if *base >= 2 && *base <= 36 => {
3979                i64::from_str_radix(s.trim(), *base as u32)
3980                    .map(Value::Int)
3981                    .map_err(|_| {
3982                        RuntimeError::new(format!("cannot parse '{}' as base-{} integer", s, base))
3983                    })
3984            }
3985            _ => Err(RuntimeError::new(
3986                "parse_int() requires string and base 2-36",
3987            )),
3988        }
3989    });
3990}
3991
3992// ============================================================================
3993// CYCLE (MODULAR ARITHMETIC) FUNCTIONS
3994// For poly-cultural mathematics
3995// ============================================================================
3996
3997fn register_cycle(interp: &mut Interpreter) {
3998    // cycle - create a cycle value (modular)
3999    define(interp, "cycle", Some(2), |_, args| {
4000        match (&args[0], &args[1]) {
4001            (Value::Int(value), Value::Int(modulus)) if *modulus > 0 => {
4002                let normalized = value.rem_euclid(*modulus);
4003                Ok(Value::Tuple(Rc::new(vec![
4004                    Value::Int(normalized),
4005                    Value::Int(*modulus),
4006                ])))
4007            }
4008            _ => Err(RuntimeError::new(
4009                "cycle() requires value and positive modulus",
4010            )),
4011        }
4012    });
4013
4014    // mod_add - modular addition
4015    define(interp, "mod_add", Some(3), |_, args| {
4016        match (&args[0], &args[1], &args[2]) {
4017            (Value::Int(a), Value::Int(b), Value::Int(m)) if *m > 0 => {
4018                Ok(Value::Int((a + b).rem_euclid(*m)))
4019            }
4020            _ => Err(RuntimeError::new(
4021                "mod_add() requires two integers and positive modulus",
4022            )),
4023        }
4024    });
4025
4026    // mod_sub - modular subtraction
4027    define(interp, "mod_sub", Some(3), |_, args| {
4028        match (&args[0], &args[1], &args[2]) {
4029            (Value::Int(a), Value::Int(b), Value::Int(m)) if *m > 0 => {
4030                Ok(Value::Int((a - b).rem_euclid(*m)))
4031            }
4032            _ => Err(RuntimeError::new(
4033                "mod_sub() requires two integers and positive modulus",
4034            )),
4035        }
4036    });
4037
4038    // mod_mul - modular multiplication
4039    define(interp, "mod_mul", Some(3), |_, args| {
4040        match (&args[0], &args[1], &args[2]) {
4041            (Value::Int(a), Value::Int(b), Value::Int(m)) if *m > 0 => {
4042                Ok(Value::Int((a * b).rem_euclid(*m)))
4043            }
4044            _ => Err(RuntimeError::new(
4045                "mod_mul() requires two integers and positive modulus",
4046            )),
4047        }
4048    });
4049
4050    // mod_pow - modular exponentiation (fast)
4051    define(interp, "mod_pow", Some(3), |_, args| {
4052        match (&args[0], &args[1], &args[2]) {
4053            (Value::Int(base), Value::Int(exp), Value::Int(m)) if *m > 0 && *exp >= 0 => {
4054                Ok(Value::Int(mod_pow(*base, *exp as u64, *m)))
4055            }
4056            _ => Err(RuntimeError::new(
4057                "mod_pow() requires base, non-negative exp, and positive modulus",
4058            )),
4059        }
4060    });
4061
4062    // mod_inv - modular multiplicative inverse (if exists)
4063    define(interp, "mod_inv", Some(2), |_, args| {
4064        match (&args[0], &args[1]) {
4065            (Value::Int(a), Value::Int(m)) if *m > 0 => match mod_inverse(*a, *m) {
4066                Some(inv) => Ok(Value::Int(inv)),
4067                None => Err(RuntimeError::new(format!(
4068                    "no modular inverse of {} mod {}",
4069                    a, m
4070                ))),
4071            },
4072            _ => Err(RuntimeError::new(
4073                "mod_inv() requires integer and positive modulus",
4074            )),
4075        }
4076    });
4077
4078    // Musical cycles (for tuning systems)
4079    // octave - normalize to octave (pitch class)
4080    define(interp, "octave", Some(1), |_, args| {
4081        match &args[0] {
4082            Value::Int(note) => Ok(Value::Int(note.rem_euclid(12))),
4083            Value::Float(freq) => {
4084                // Normalize frequency to octave starting at A4=440Hz
4085                let semitones = 12.0 * (freq / 440.0).log2();
4086                Ok(Value::Float(semitones.rem_euclid(12.0)))
4087            }
4088            _ => Err(RuntimeError::new("octave() requires number")),
4089        }
4090    });
4091
4092    // interval - musical interval (semitones)
4093    define(interp, "interval", Some(2), |_, args| {
4094        match (&args[0], &args[1]) {
4095            (Value::Int(a), Value::Int(b)) => Ok(Value::Int((b - a).rem_euclid(12))),
4096            _ => Err(RuntimeError::new("interval() requires two integers")),
4097        }
4098    });
4099
4100    // cents - convert semitones to cents or vice versa
4101    define(interp, "cents", Some(1), |_, args| match &args[0] {
4102        Value::Int(semitones) => Ok(Value::Int(*semitones * 100)),
4103        Value::Float(semitones) => Ok(Value::Float(*semitones * 100.0)),
4104        _ => Err(RuntimeError::new("cents() requires number")),
4105    });
4106
4107    // freq - convert MIDI note number to frequency
4108    define(interp, "freq", Some(1), |_, args| match &args[0] {
4109        Value::Int(midi) => {
4110            let freq = 440.0 * 2.0_f64.powf((*midi as f64 - 69.0) / 12.0);
4111            Ok(Value::Float(freq))
4112        }
4113        _ => Err(RuntimeError::new("freq() requires integer MIDI note")),
4114    });
4115
4116    // midi - convert frequency to MIDI note number
4117    define(interp, "midi", Some(1), |_, args| match &args[0] {
4118        Value::Float(freq) if *freq > 0.0 => {
4119            let midi = 69.0 + 12.0 * (freq / 440.0).log2();
4120            Ok(Value::Int(midi.round() as i64))
4121        }
4122        Value::Int(freq) if *freq > 0 => {
4123            let midi = 69.0 + 12.0 * (*freq as f64 / 440.0).log2();
4124            Ok(Value::Int(midi.round() as i64))
4125        }
4126        _ => Err(RuntimeError::new("midi() requires positive frequency")),
4127    });
4128}
4129
4130// Fast modular exponentiation
4131fn mod_pow(mut base: i64, mut exp: u64, modulus: i64) -> i64 {
4132    if modulus == 1 {
4133        return 0;
4134    }
4135    let mut result: i64 = 1;
4136    base = base.rem_euclid(modulus);
4137    while exp > 0 {
4138        if exp % 2 == 1 {
4139            result = (result * base).rem_euclid(modulus);
4140        }
4141        exp /= 2;
4142        base = (base * base).rem_euclid(modulus);
4143    }
4144    result
4145}
4146
4147// ============================================================================
4148// SIMD VECTOR FUNCTIONS
4149// High-performance vector operations for game/graphics math
4150// ============================================================================
4151
4152fn register_simd(interp: &mut Interpreter) {
4153    // simd_new - create a SIMD 4-component vector
4154    define(interp, "simd_new", Some(4), |_, args| {
4155        let values: Result<Vec<f64>, _> = args
4156            .iter()
4157            .map(|v| match v {
4158                Value::Float(f) => Ok(*f),
4159                Value::Int(i) => Ok(*i as f64),
4160                _ => Err(RuntimeError::new("simd_new() requires numbers")),
4161            })
4162            .collect();
4163        let values = values?;
4164        Ok(Value::Array(Rc::new(RefCell::new(vec![
4165            Value::Float(values[0]),
4166            Value::Float(values[1]),
4167            Value::Float(values[2]),
4168            Value::Float(values[3]),
4169        ]))))
4170    });
4171
4172    // simd_splat - create vector with all same components
4173    define(interp, "simd_splat", Some(1), |_, args| {
4174        let v = match &args[0] {
4175            Value::Float(f) => *f,
4176            Value::Int(i) => *i as f64,
4177            _ => return Err(RuntimeError::new("simd_splat() requires number")),
4178        };
4179        Ok(Value::Array(Rc::new(RefCell::new(vec![
4180            Value::Float(v),
4181            Value::Float(v),
4182            Value::Float(v),
4183            Value::Float(v),
4184        ]))))
4185    });
4186
4187    // simd_add - component-wise addition
4188    define(interp, "simd_add", Some(2), |_, args| {
4189        simd_binary_op(&args[0], &args[1], |a, b| a + b, "simd_add")
4190    });
4191
4192    // simd_sub - component-wise subtraction
4193    define(interp, "simd_sub", Some(2), |_, args| {
4194        simd_binary_op(&args[0], &args[1], |a, b| a - b, "simd_sub")
4195    });
4196
4197    // simd_mul - component-wise multiplication
4198    define(interp, "simd_mul", Some(2), |_, args| {
4199        simd_binary_op(&args[0], &args[1], |a, b| a * b, "simd_mul")
4200    });
4201
4202    // simd_div - component-wise division
4203    define(interp, "simd_div", Some(2), |_, args| {
4204        simd_binary_op(&args[0], &args[1], |a, b| a / b, "simd_div")
4205    });
4206
4207    // simd_dot - dot product of two vectors
4208    define(interp, "simd_dot", Some(2), |_, args| {
4209        let a = extract_simd(&args[0], "simd_dot")?;
4210        let b = extract_simd(&args[1], "simd_dot")?;
4211        let dot = a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
4212        Ok(Value::Float(dot))
4213    });
4214
4215    // simd_cross - 3D cross product (w component set to 0)
4216    define(interp, "simd_cross", Some(2), |_, args| {
4217        let a = extract_simd(&args[0], "simd_cross")?;
4218        let b = extract_simd(&args[1], "simd_cross")?;
4219        Ok(Value::Array(Rc::new(RefCell::new(vec![
4220            Value::Float(a[1] * b[2] - a[2] * b[1]),
4221            Value::Float(a[2] * b[0] - a[0] * b[2]),
4222            Value::Float(a[0] * b[1] - a[1] * b[0]),
4223            Value::Float(0.0),
4224        ]))))
4225    });
4226
4227    // simd_length - vector length (magnitude)
4228    define(interp, "simd_length", Some(1), |_, args| {
4229        let v = extract_simd(&args[0], "simd_length")?;
4230        let len_sq = v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3];
4231        Ok(Value::Float(len_sq.sqrt()))
4232    });
4233
4234    // simd_normalize - normalize vector to unit length
4235    define(interp, "simd_normalize", Some(1), |_, args| {
4236        let v = extract_simd(&args[0], "simd_normalize")?;
4237        let len_sq = v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3];
4238        let len = len_sq.sqrt();
4239        if len < 1e-10 {
4240            return Ok(Value::Array(Rc::new(RefCell::new(vec![
4241                Value::Float(0.0),
4242                Value::Float(0.0),
4243                Value::Float(0.0),
4244                Value::Float(0.0),
4245            ]))));
4246        }
4247        let inv_len = 1.0 / len;
4248        Ok(Value::Array(Rc::new(RefCell::new(vec![
4249            Value::Float(v[0] * inv_len),
4250            Value::Float(v[1] * inv_len),
4251            Value::Float(v[2] * inv_len),
4252            Value::Float(v[3] * inv_len),
4253        ]))))
4254    });
4255
4256    // simd_min - component-wise minimum
4257    define(interp, "simd_min", Some(2), |_, args| {
4258        simd_binary_op(&args[0], &args[1], |a, b| a.min(b), "simd_min")
4259    });
4260
4261    // simd_max - component-wise maximum
4262    define(interp, "simd_max", Some(2), |_, args| {
4263        simd_binary_op(&args[0], &args[1], |a, b| a.max(b), "simd_max")
4264    });
4265
4266    // simd_hadd - horizontal add (sum all components)
4267    define(interp, "simd_hadd", Some(1), |_, args| {
4268        let v = extract_simd(&args[0], "simd_hadd")?;
4269        Ok(Value::Float(v[0] + v[1] + v[2] + v[3]))
4270    });
4271
4272    // simd_extract - extract single component (0-3)
4273    define(interp, "simd_extract", Some(2), |_, args| {
4274        let v = extract_simd(&args[0], "simd_extract")?;
4275        let idx = match &args[1] {
4276            Value::Int(i) => *i as usize,
4277            _ => return Err(RuntimeError::new("simd_extract() requires integer index")),
4278        };
4279        if idx > 3 {
4280            return Err(RuntimeError::new("simd_extract() index must be 0-3"));
4281        }
4282        Ok(Value::Float(v[idx]))
4283    });
4284
4285    // simd_free - no-op in interpreter (for JIT compatibility)
4286    define(interp, "simd_free", Some(1), |_, _| Ok(Value::Null));
4287
4288    // simd_lerp - linear interpolation between vectors
4289    define(interp, "simd_lerp", Some(3), |_, args| {
4290        let a = extract_simd(&args[0], "simd_lerp")?;
4291        let b = extract_simd(&args[1], "simd_lerp")?;
4292        let t = match &args[2] {
4293            Value::Float(f) => *f,
4294            Value::Int(i) => *i as f64,
4295            _ => return Err(RuntimeError::new("simd_lerp() requires float t")),
4296        };
4297        let one_t = 1.0 - t;
4298        Ok(Value::Array(Rc::new(RefCell::new(vec![
4299            Value::Float(a[0] * one_t + b[0] * t),
4300            Value::Float(a[1] * one_t + b[1] * t),
4301            Value::Float(a[2] * one_t + b[2] * t),
4302            Value::Float(a[3] * one_t + b[3] * t),
4303        ]))))
4304    });
4305}
4306
4307// Helper to extract SIMD values from array
4308fn extract_simd(val: &Value, fn_name: &str) -> Result<[f64; 4], RuntimeError> {
4309    match val {
4310        Value::Array(arr) => {
4311            let arr = arr.borrow();
4312            if arr.len() < 4 {
4313                return Err(RuntimeError::new(format!(
4314                    "{}() requires 4-element array",
4315                    fn_name
4316                )));
4317            }
4318            let mut result = [0.0; 4];
4319            for (i, v) in arr.iter().take(4).enumerate() {
4320                result[i] = match v {
4321                    Value::Float(f) => *f,
4322                    Value::Int(n) => *n as f64,
4323                    _ => {
4324                        return Err(RuntimeError::new(format!(
4325                            "{}() requires numeric array",
4326                            fn_name
4327                        )))
4328                    }
4329                };
4330            }
4331            Ok(result)
4332        }
4333        _ => Err(RuntimeError::new(format!(
4334            "{}() requires array argument",
4335            fn_name
4336        ))),
4337    }
4338}
4339
4340// Helper for binary SIMD operations
4341fn simd_binary_op<F>(a: &Value, b: &Value, op: F, fn_name: &str) -> Result<Value, RuntimeError>
4342where
4343    F: Fn(f64, f64) -> f64,
4344{
4345    let a = extract_simd(a, fn_name)?;
4346    let b = extract_simd(b, fn_name)?;
4347    Ok(Value::Array(Rc::new(RefCell::new(vec![
4348        Value::Float(op(a[0], b[0])),
4349        Value::Float(op(a[1], b[1])),
4350        Value::Float(op(a[2], b[2])),
4351        Value::Float(op(a[3], b[3])),
4352    ]))))
4353}
4354
4355// ============================================================================
4356// GRAPHICS MATH LIBRARY
4357// ============================================================================
4358// Comprehensive 3D graphics mathematics for physics and rendering:
4359// - Quaternions for rotation without gimbal lock
4360// - vec2/vec3/vec4 vector types with swizzling
4361// - mat3/mat4 matrices with projection/view/model operations
4362// - Affine transforms, Euler angles, and interpolation
4363// ============================================================================
4364
4365fn register_graphics_math(interp: &mut Interpreter) {
4366    // -------------------------------------------------------------------------
4367    // QUATERNIONS - Essential for 3D rotations
4368    // -------------------------------------------------------------------------
4369    // Quaternion format: [w, x, y, z] where w is scalar, (x,y,z) is vector part
4370    // This follows the convention: q = w + xi + yj + zk
4371
4372    // quat_new(w, x, y, z) - create a quaternion
4373    define(interp, "quat_new", Some(4), |_, args| {
4374        let w = extract_number(&args[0], "quat_new")?;
4375        let x = extract_number(&args[1], "quat_new")?;
4376        let y = extract_number(&args[2], "quat_new")?;
4377        let z = extract_number(&args[3], "quat_new")?;
4378        Ok(make_vec4(w, x, y, z))
4379    });
4380
4381    // quat_identity() - identity quaternion (no rotation)
4382    define(interp, "quat_identity", Some(0), |_, _| {
4383        Ok(make_vec4(1.0, 0.0, 0.0, 0.0))
4384    });
4385
4386    // quat_from_axis_angle(axis_vec3, angle_radians) - create from axis-angle
4387    define(interp, "quat_from_axis_angle", Some(2), |_, args| {
4388        let axis = extract_vec3(&args[0], "quat_from_axis_angle")?;
4389        let angle = extract_number(&args[1], "quat_from_axis_angle")?;
4390
4391        // Normalize axis
4392        let len = (axis[0] * axis[0] + axis[1] * axis[1] + axis[2] * axis[2]).sqrt();
4393        if len < 1e-10 {
4394            return Ok(make_vec4(1.0, 0.0, 0.0, 0.0)); // Identity for zero axis
4395        }
4396        let ax = axis[0] / len;
4397        let ay = axis[1] / len;
4398        let az = axis[2] / len;
4399
4400        let half_angle = angle / 2.0;
4401        let s = half_angle.sin();
4402        let c = half_angle.cos();
4403
4404        Ok(make_vec4(c, ax * s, ay * s, az * s))
4405    });
4406
4407    // quat_from_euler(pitch, yaw, roll) - create from Euler angles (radians)
4408    // Uses XYZ order (pitch around X, yaw around Y, roll around Z)
4409    define(interp, "quat_from_euler", Some(3), |_, args| {
4410        let pitch = extract_number(&args[0], "quat_from_euler")?; // X
4411        let yaw = extract_number(&args[1], "quat_from_euler")?; // Y
4412        let roll = extract_number(&args[2], "quat_from_euler")?; // Z
4413
4414        let (sp, cp) = (pitch / 2.0).sin_cos();
4415        let (sy, cy) = (yaw / 2.0).sin_cos();
4416        let (sr, cr) = (roll / 2.0).sin_cos();
4417
4418        // Combined quaternion (XYZ order)
4419        let w = cp * cy * cr + sp * sy * sr;
4420        let x = sp * cy * cr - cp * sy * sr;
4421        let y = cp * sy * cr + sp * cy * sr;
4422        let z = cp * cy * sr - sp * sy * cr;
4423
4424        Ok(make_vec4(w, x, y, z))
4425    });
4426
4427    // quat_mul(q1, q2) - quaternion multiplication (q1 * q2)
4428    define(interp, "quat_mul", Some(2), |_, args| {
4429        let q1 = extract_vec4(&args[0], "quat_mul")?;
4430        let q2 = extract_vec4(&args[1], "quat_mul")?;
4431
4432        // Hamilton product
4433        let w = q1[0] * q2[0] - q1[1] * q2[1] - q1[2] * q2[2] - q1[3] * q2[3];
4434        let x = q1[0] * q2[1] + q1[1] * q2[0] + q1[2] * q2[3] - q1[3] * q2[2];
4435        let y = q1[0] * q2[2] - q1[1] * q2[3] + q1[2] * q2[0] + q1[3] * q2[1];
4436        let z = q1[0] * q2[3] + q1[1] * q2[2] - q1[2] * q2[1] + q1[3] * q2[0];
4437
4438        Ok(make_vec4(w, x, y, z))
4439    });
4440
4441    // quat_conjugate(q) - quaternion conjugate (inverse for unit quaternions)
4442    define(interp, "quat_conjugate", Some(1), |_, args| {
4443        let q = extract_vec4(&args[0], "quat_conjugate")?;
4444        Ok(make_vec4(q[0], -q[1], -q[2], -q[3]))
4445    });
4446
4447    // quat_inverse(q) - quaternion inverse (handles non-unit quaternions)
4448    define(interp, "quat_inverse", Some(1), |_, args| {
4449        let q = extract_vec4(&args[0], "quat_inverse")?;
4450        let norm_sq = q[0] * q[0] + q[1] * q[1] + q[2] * q[2] + q[3] * q[3];
4451        if norm_sq < 1e-10 {
4452            return Err(RuntimeError::new(
4453                "quat_inverse: cannot invert zero quaternion",
4454            ));
4455        }
4456        Ok(make_vec4(
4457            q[0] / norm_sq,
4458            -q[1] / norm_sq,
4459            -q[2] / norm_sq,
4460            -q[3] / norm_sq,
4461        ))
4462    });
4463
4464    // quat_normalize(q) - normalize to unit quaternion
4465    define(interp, "quat_normalize", Some(1), |_, args| {
4466        let q = extract_vec4(&args[0], "quat_normalize")?;
4467        let len = (q[0] * q[0] + q[1] * q[1] + q[2] * q[2] + q[3] * q[3]).sqrt();
4468        if len < 1e-10 {
4469            return Ok(make_vec4(1.0, 0.0, 0.0, 0.0));
4470        }
4471        Ok(make_vec4(q[0] / len, q[1] / len, q[2] / len, q[3] / len))
4472    });
4473
4474    // quat_rotate(q, vec3) - rotate a 3D vector by quaternion
4475    define(interp, "quat_rotate", Some(2), |_, args| {
4476        let q = extract_vec4(&args[0], "quat_rotate")?;
4477        let v = extract_vec3(&args[1], "quat_rotate")?;
4478
4479        // q * v * q^-1 optimized formula
4480        let qw = q[0];
4481        let qx = q[1];
4482        let qy = q[2];
4483        let qz = q[3];
4484        let vx = v[0];
4485        let vy = v[1];
4486        let vz = v[2];
4487
4488        // t = 2 * cross(q.xyz, v)
4489        let tx = 2.0 * (qy * vz - qz * vy);
4490        let ty = 2.0 * (qz * vx - qx * vz);
4491        let tz = 2.0 * (qx * vy - qy * vx);
4492
4493        // result = v + q.w * t + cross(q.xyz, t)
4494        let rx = vx + qw * tx + (qy * tz - qz * ty);
4495        let ry = vy + qw * ty + (qz * tx - qx * tz);
4496        let rz = vz + qw * tz + (qx * ty - qy * tx);
4497
4498        Ok(make_vec3(rx, ry, rz))
4499    });
4500
4501    // quat_slerp(q1, q2, t) - spherical linear interpolation
4502    define(interp, "quat_slerp", Some(3), |_, args| {
4503        let q1 = extract_vec4(&args[0], "quat_slerp")?;
4504        let mut q2 = extract_vec4(&args[1], "quat_slerp")?;
4505        let t = extract_number(&args[2], "quat_slerp")?;
4506
4507        // Compute dot product
4508        let mut dot = q1[0] * q2[0] + q1[1] * q2[1] + q1[2] * q2[2] + q1[3] * q2[3];
4509
4510        // If dot < 0, negate q2 to take shorter path
4511        if dot < 0.0 {
4512            q2 = [-q2[0], -q2[1], -q2[2], -q2[3]];
4513            dot = -dot;
4514        }
4515
4516        // If quaternions are very close, use linear interpolation
4517        if dot > 0.9995 {
4518            let w = q1[0] + t * (q2[0] - q1[0]);
4519            let x = q1[1] + t * (q2[1] - q1[1]);
4520            let y = q1[2] + t * (q2[2] - q1[2]);
4521            let z = q1[3] + t * (q2[3] - q1[3]);
4522            let len = (w * w + x * x + y * y + z * z).sqrt();
4523            return Ok(make_vec4(w / len, x / len, y / len, z / len));
4524        }
4525
4526        // Spherical interpolation
4527        let theta_0 = dot.acos();
4528        let theta = theta_0 * t;
4529        let sin_theta = theta.sin();
4530        let sin_theta_0 = theta_0.sin();
4531
4532        let s0 = (theta_0 - theta).cos() - dot * sin_theta / sin_theta_0;
4533        let s1 = sin_theta / sin_theta_0;
4534
4535        Ok(make_vec4(
4536            s0 * q1[0] + s1 * q2[0],
4537            s0 * q1[1] + s1 * q2[1],
4538            s0 * q1[2] + s1 * q2[2],
4539            s0 * q1[3] + s1 * q2[3],
4540        ))
4541    });
4542
4543    // quat_to_euler(q) - convert quaternion to Euler angles [pitch, yaw, roll]
4544    define(interp, "quat_to_euler", Some(1), |_, args| {
4545        let q = extract_vec4(&args[0], "quat_to_euler")?;
4546        let (w, x, y, z) = (q[0], q[1], q[2], q[3]);
4547
4548        // Roll (X-axis rotation)
4549        let sinr_cosp = 2.0 * (w * x + y * z);
4550        let cosr_cosp = 1.0 - 2.0 * (x * x + y * y);
4551        let roll = sinr_cosp.atan2(cosr_cosp);
4552
4553        // Pitch (Y-axis rotation)
4554        let sinp = 2.0 * (w * y - z * x);
4555        let pitch = if sinp.abs() >= 1.0 {
4556            std::f64::consts::FRAC_PI_2.copysign(sinp)
4557        } else {
4558            sinp.asin()
4559        };
4560
4561        // Yaw (Z-axis rotation)
4562        let siny_cosp = 2.0 * (w * z + x * y);
4563        let cosy_cosp = 1.0 - 2.0 * (y * y + z * z);
4564        let yaw = siny_cosp.atan2(cosy_cosp);
4565
4566        Ok(make_vec3(pitch, yaw, roll))
4567    });
4568
4569    // quat_to_mat4(q) - convert quaternion to 4x4 rotation matrix
4570    define(interp, "quat_to_mat4", Some(1), |_, args| {
4571        let q = extract_vec4(&args[0], "quat_to_mat4")?;
4572        let (w, x, y, z) = (q[0], q[1], q[2], q[3]);
4573
4574        let xx = x * x;
4575        let yy = y * y;
4576        let zz = z * z;
4577        let xy = x * y;
4578        let xz = x * z;
4579        let yz = y * z;
4580        let wx = w * x;
4581        let wy = w * y;
4582        let wz = w * z;
4583
4584        // Column-major 4x4 rotation matrix
4585        Ok(make_mat4([
4586            1.0 - 2.0 * (yy + zz),
4587            2.0 * (xy + wz),
4588            2.0 * (xz - wy),
4589            0.0,
4590            2.0 * (xy - wz),
4591            1.0 - 2.0 * (xx + zz),
4592            2.0 * (yz + wx),
4593            0.0,
4594            2.0 * (xz + wy),
4595            2.0 * (yz - wx),
4596            1.0 - 2.0 * (xx + yy),
4597            0.0,
4598            0.0,
4599            0.0,
4600            0.0,
4601            1.0,
4602        ]))
4603    });
4604
4605    // -------------------------------------------------------------------------
4606    // VECTOR TYPES - vec2, vec3, vec4
4607    // -------------------------------------------------------------------------
4608
4609    // vec2(x, y)
4610    define(interp, "vec2", Some(2), |_, args| {
4611        let x = extract_number(&args[0], "vec2")?;
4612        let y = extract_number(&args[1], "vec2")?;
4613        Ok(make_vec2(x, y))
4614    });
4615
4616    // vec3(x, y, z)
4617    define(interp, "vec3", Some(3), |_, args| {
4618        let x = extract_number(&args[0], "vec3")?;
4619        let y = extract_number(&args[1], "vec3")?;
4620        let z = extract_number(&args[2], "vec3")?;
4621        Ok(make_vec3(x, y, z))
4622    });
4623
4624    // vec4(x, y, z, w)
4625    define(interp, "vec4", Some(4), |_, args| {
4626        let x = extract_number(&args[0], "vec4")?;
4627        let y = extract_number(&args[1], "vec4")?;
4628        let z = extract_number(&args[2], "vec4")?;
4629        let w = extract_number(&args[3], "vec4")?;
4630        Ok(make_vec4(x, y, z, w))
4631    });
4632
4633    // vec3_add(a, b)
4634    define(interp, "vec3_add", Some(2), |_, args| {
4635        let a = extract_vec3(&args[0], "vec3_add")?;
4636        let b = extract_vec3(&args[1], "vec3_add")?;
4637        Ok(make_vec3(a[0] + b[0], a[1] + b[1], a[2] + b[2]))
4638    });
4639
4640    // vec3_sub(a, b)
4641    define(interp, "vec3_sub", Some(2), |_, args| {
4642        let a = extract_vec3(&args[0], "vec3_sub")?;
4643        let b = extract_vec3(&args[1], "vec3_sub")?;
4644        Ok(make_vec3(a[0] - b[0], a[1] - b[1], a[2] - b[2]))
4645    });
4646
4647    // vec3_scale(v, scalar)
4648    define(interp, "vec3_scale", Some(2), |_, args| {
4649        let v = extract_vec3(&args[0], "vec3_scale")?;
4650        let s = extract_number(&args[1], "vec3_scale")?;
4651        Ok(make_vec3(v[0] * s, v[1] * s, v[2] * s))
4652    });
4653
4654    // vec3_dot(a, b)
4655    define(interp, "vec3_dot", Some(2), |_, args| {
4656        let a = extract_vec3(&args[0], "vec3_dot")?;
4657        let b = extract_vec3(&args[1], "vec3_dot")?;
4658        Ok(Value::Float(a[0] * b[0] + a[1] * b[1] + a[2] * b[2]))
4659    });
4660
4661    // vec3_cross(a, b)
4662    define(interp, "vec3_cross", Some(2), |_, args| {
4663        let a = extract_vec3(&args[0], "vec3_cross")?;
4664        let b = extract_vec3(&args[1], "vec3_cross")?;
4665        Ok(make_vec3(
4666            a[1] * b[2] - a[2] * b[1],
4667            a[2] * b[0] - a[0] * b[2],
4668            a[0] * b[1] - a[1] * b[0],
4669        ))
4670    });
4671
4672    // vec3_length(v)
4673    define(interp, "vec3_length", Some(1), |_, args| {
4674        let v = extract_vec3(&args[0], "vec3_length")?;
4675        Ok(Value::Float(
4676            (v[0] * v[0] + v[1] * v[1] + v[2] * v[2]).sqrt(),
4677        ))
4678    });
4679
4680    // vec3_normalize(v)
4681    define(interp, "vec3_normalize", Some(1), |_, args| {
4682        let v = extract_vec3(&args[0], "vec3_normalize")?;
4683        let len = (v[0] * v[0] + v[1] * v[1] + v[2] * v[2]).sqrt();
4684        if len < 1e-10 {
4685            return Ok(make_vec3(0.0, 0.0, 0.0));
4686        }
4687        Ok(make_vec3(v[0] / len, v[1] / len, v[2] / len))
4688    });
4689
4690    // vec3_lerp(a, b, t) - linear interpolation
4691    define(interp, "vec3_lerp", Some(3), |_, args| {
4692        let a = extract_vec3(&args[0], "vec3_lerp")?;
4693        let b = extract_vec3(&args[1], "vec3_lerp")?;
4694        let t = extract_number(&args[2], "vec3_lerp")?;
4695        Ok(make_vec3(
4696            a[0] + t * (b[0] - a[0]),
4697            a[1] + t * (b[1] - a[1]),
4698            a[2] + t * (b[2] - a[2]),
4699        ))
4700    });
4701
4702    // vec3_reflect(incident, normal) - reflection vector
4703    define(interp, "vec3_reflect", Some(2), |_, args| {
4704        let i = extract_vec3(&args[0], "vec3_reflect")?;
4705        let n = extract_vec3(&args[1], "vec3_reflect")?;
4706        let dot = i[0] * n[0] + i[1] * n[1] + i[2] * n[2];
4707        Ok(make_vec3(
4708            i[0] - 2.0 * dot * n[0],
4709            i[1] - 2.0 * dot * n[1],
4710            i[2] - 2.0 * dot * n[2],
4711        ))
4712    });
4713
4714    // vec3_refract(incident, normal, eta) - refraction vector
4715    define(interp, "vec3_refract", Some(3), |_, args| {
4716        let i = extract_vec3(&args[0], "vec3_refract")?;
4717        let n = extract_vec3(&args[1], "vec3_refract")?;
4718        let eta = extract_number(&args[2], "vec3_refract")?;
4719
4720        let dot = i[0] * n[0] + i[1] * n[1] + i[2] * n[2];
4721        let k = 1.0 - eta * eta * (1.0 - dot * dot);
4722
4723        if k < 0.0 {
4724            // Total internal reflection
4725            return Ok(make_vec3(0.0, 0.0, 0.0));
4726        }
4727
4728        let coeff = eta * dot + k.sqrt();
4729        Ok(make_vec3(
4730            eta * i[0] - coeff * n[0],
4731            eta * i[1] - coeff * n[1],
4732            eta * i[2] - coeff * n[2],
4733        ))
4734    });
4735
4736    // vec4_dot(a, b)
4737    define(interp, "vec4_dot", Some(2), |_, args| {
4738        let a = extract_vec4(&args[0], "vec4_dot")?;
4739        let b = extract_vec4(&args[1], "vec4_dot")?;
4740        Ok(Value::Float(
4741            a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3],
4742        ))
4743    });
4744
4745    // -------------------------------------------------------------------------
4746    // MAT4 - 4x4 MATRICES (Column-major for OpenGL compatibility)
4747    // -------------------------------------------------------------------------
4748
4749    // mat4_identity() - 4x4 identity matrix
4750    define(interp, "mat4_identity", Some(0), |_, _| {
4751        Ok(make_mat4([
4752            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,
4753        ]))
4754    });
4755
4756    // mat4_mul(a, b) - matrix multiplication
4757    define(interp, "mat4_mul", Some(2), |_, args| {
4758        let a = extract_mat4(&args[0], "mat4_mul")?;
4759        let b = extract_mat4(&args[1], "mat4_mul")?;
4760
4761        let mut result = [0.0f64; 16];
4762        for col in 0..4 {
4763            for row in 0..4 {
4764                let mut sum = 0.0;
4765                for k in 0..4 {
4766                    sum += a[k * 4 + row] * b[col * 4 + k];
4767                }
4768                result[col * 4 + row] = sum;
4769            }
4770        }
4771        Ok(make_mat4(result))
4772    });
4773
4774    // mat4_transform(mat4, vec4) - transform vector by matrix
4775    define(interp, "mat4_transform", Some(2), |_, args| {
4776        let m = extract_mat4(&args[0], "mat4_transform")?;
4777        let v = extract_vec4(&args[1], "mat4_transform")?;
4778
4779        Ok(make_vec4(
4780            m[0] * v[0] + m[4] * v[1] + m[8] * v[2] + m[12] * v[3],
4781            m[1] * v[0] + m[5] * v[1] + m[9] * v[2] + m[13] * v[3],
4782            m[2] * v[0] + m[6] * v[1] + m[10] * v[2] + m[14] * v[3],
4783            m[3] * v[0] + m[7] * v[1] + m[11] * v[2] + m[15] * v[3],
4784        ))
4785    });
4786
4787    // mat4_translate(tx, ty, tz) - translation matrix
4788    define(interp, "mat4_translate", Some(3), |_, args| {
4789        let tx = extract_number(&args[0], "mat4_translate")?;
4790        let ty = extract_number(&args[1], "mat4_translate")?;
4791        let tz = extract_number(&args[2], "mat4_translate")?;
4792        Ok(make_mat4([
4793            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,
4794        ]))
4795    });
4796
4797    // mat4_scale(sx, sy, sz) - scale matrix
4798    define(interp, "mat4_scale", Some(3), |_, args| {
4799        let sx = extract_number(&args[0], "mat4_scale")?;
4800        let sy = extract_number(&args[1], "mat4_scale")?;
4801        let sz = extract_number(&args[2], "mat4_scale")?;
4802        Ok(make_mat4([
4803            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,
4804        ]))
4805    });
4806
4807    // mat4_rotate_x(angle) - rotation around X axis
4808    define(interp, "mat4_rotate_x", Some(1), |_, args| {
4809        let angle = extract_number(&args[0], "mat4_rotate_x")?;
4810        let (s, c) = angle.sin_cos();
4811        Ok(make_mat4([
4812            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,
4813        ]))
4814    });
4815
4816    // mat4_rotate_y(angle) - rotation around Y axis
4817    define(interp, "mat4_rotate_y", Some(1), |_, args| {
4818        let angle = extract_number(&args[0], "mat4_rotate_y")?;
4819        let (s, c) = angle.sin_cos();
4820        Ok(make_mat4([
4821            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,
4822        ]))
4823    });
4824
4825    // mat4_rotate_z(angle) - rotation around Z axis
4826    define(interp, "mat4_rotate_z", Some(1), |_, args| {
4827        let angle = extract_number(&args[0], "mat4_rotate_z")?;
4828        let (s, c) = angle.sin_cos();
4829        Ok(make_mat4([
4830            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,
4831        ]))
4832    });
4833
4834    // mat4_perspective(fov_y, aspect, near, far) - perspective projection
4835    define(interp, "mat4_perspective", Some(4), |_, args| {
4836        let fov_y = extract_number(&args[0], "mat4_perspective")?;
4837        let aspect = extract_number(&args[1], "mat4_perspective")?;
4838        let near = extract_number(&args[2], "mat4_perspective")?;
4839        let far = extract_number(&args[3], "mat4_perspective")?;
4840
4841        let f = 1.0 / (fov_y / 2.0).tan();
4842        let nf = 1.0 / (near - far);
4843
4844        Ok(make_mat4([
4845            f / aspect,
4846            0.0,
4847            0.0,
4848            0.0,
4849            0.0,
4850            f,
4851            0.0,
4852            0.0,
4853            0.0,
4854            0.0,
4855            (far + near) * nf,
4856            -1.0,
4857            0.0,
4858            0.0,
4859            2.0 * far * near * nf,
4860            0.0,
4861        ]))
4862    });
4863
4864    // mat4_ortho(left, right, bottom, top, near, far) - orthographic projection
4865    define(interp, "mat4_ortho", Some(6), |_, args| {
4866        let left = extract_number(&args[0], "mat4_ortho")?;
4867        let right = extract_number(&args[1], "mat4_ortho")?;
4868        let bottom = extract_number(&args[2], "mat4_ortho")?;
4869        let top = extract_number(&args[3], "mat4_ortho")?;
4870        let near = extract_number(&args[4], "mat4_ortho")?;
4871        let far = extract_number(&args[5], "mat4_ortho")?;
4872
4873        let lr = 1.0 / (left - right);
4874        let bt = 1.0 / (bottom - top);
4875        let nf = 1.0 / (near - far);
4876
4877        Ok(make_mat4([
4878            -2.0 * lr,
4879            0.0,
4880            0.0,
4881            0.0,
4882            0.0,
4883            -2.0 * bt,
4884            0.0,
4885            0.0,
4886            0.0,
4887            0.0,
4888            2.0 * nf,
4889            0.0,
4890            (left + right) * lr,
4891            (top + bottom) * bt,
4892            (far + near) * nf,
4893            1.0,
4894        ]))
4895    });
4896
4897    // mat4_look_at(eye, center, up) - view matrix (camera)
4898    define(interp, "mat4_look_at", Some(3), |_, args| {
4899        let eye = extract_vec3(&args[0], "mat4_look_at")?;
4900        let center = extract_vec3(&args[1], "mat4_look_at")?;
4901        let up = extract_vec3(&args[2], "mat4_look_at")?;
4902
4903        // Forward vector (z)
4904        let fx = center[0] - eye[0];
4905        let fy = center[1] - eye[1];
4906        let fz = center[2] - eye[2];
4907        let flen = (fx * fx + fy * fy + fz * fz).sqrt();
4908        let (fx, fy, fz) = (fx / flen, fy / flen, fz / flen);
4909
4910        // Right vector (x) = forward × up
4911        let rx = fy * up[2] - fz * up[1];
4912        let ry = fz * up[0] - fx * up[2];
4913        let rz = fx * up[1] - fy * up[0];
4914        let rlen = (rx * rx + ry * ry + rz * rz).sqrt();
4915        let (rx, ry, rz) = (rx / rlen, ry / rlen, rz / rlen);
4916
4917        // True up vector (y) = right × forward
4918        let ux = ry * fz - rz * fy;
4919        let uy = rz * fx - rx * fz;
4920        let uz = rx * fy - ry * fx;
4921
4922        Ok(make_mat4([
4923            rx,
4924            ux,
4925            -fx,
4926            0.0,
4927            ry,
4928            uy,
4929            -fy,
4930            0.0,
4931            rz,
4932            uz,
4933            -fz,
4934            0.0,
4935            -(rx * eye[0] + ry * eye[1] + rz * eye[2]),
4936            -(ux * eye[0] + uy * eye[1] + uz * eye[2]),
4937            -(-fx * eye[0] - fy * eye[1] - fz * eye[2]),
4938            1.0,
4939        ]))
4940    });
4941
4942    // mat4_inverse(m) - matrix inverse (for transformation matrices)
4943    define(interp, "mat4_inverse", Some(1), |_, args| {
4944        let m = extract_mat4(&args[0], "mat4_inverse")?;
4945
4946        // Optimized 4x4 matrix inverse using cofactors
4947        let a00 = m[0];
4948        let a01 = m[1];
4949        let a02 = m[2];
4950        let a03 = m[3];
4951        let a10 = m[4];
4952        let a11 = m[5];
4953        let a12 = m[6];
4954        let a13 = m[7];
4955        let a20 = m[8];
4956        let a21 = m[9];
4957        let a22 = m[10];
4958        let a23 = m[11];
4959        let a30 = m[12];
4960        let a31 = m[13];
4961        let a32 = m[14];
4962        let a33 = m[15];
4963
4964        let b00 = a00 * a11 - a01 * a10;
4965        let b01 = a00 * a12 - a02 * a10;
4966        let b02 = a00 * a13 - a03 * a10;
4967        let b03 = a01 * a12 - a02 * a11;
4968        let b04 = a01 * a13 - a03 * a11;
4969        let b05 = a02 * a13 - a03 * a12;
4970        let b06 = a20 * a31 - a21 * a30;
4971        let b07 = a20 * a32 - a22 * a30;
4972        let b08 = a20 * a33 - a23 * a30;
4973        let b09 = a21 * a32 - a22 * a31;
4974        let b10 = a21 * a33 - a23 * a31;
4975        let b11 = a22 * a33 - a23 * a32;
4976
4977        let det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
4978
4979        if det.abs() < 1e-10 {
4980            return Err(RuntimeError::new("mat4_inverse: singular matrix"));
4981        }
4982
4983        let inv_det = 1.0 / det;
4984
4985        Ok(make_mat4([
4986            (a11 * b11 - a12 * b10 + a13 * b09) * inv_det,
4987            (a02 * b10 - a01 * b11 - a03 * b09) * inv_det,
4988            (a31 * b05 - a32 * b04 + a33 * b03) * inv_det,
4989            (a22 * b04 - a21 * b05 - a23 * b03) * inv_det,
4990            (a12 * b08 - a10 * b11 - a13 * b07) * inv_det,
4991            (a00 * b11 - a02 * b08 + a03 * b07) * inv_det,
4992            (a32 * b02 - a30 * b05 - a33 * b01) * inv_det,
4993            (a20 * b05 - a22 * b02 + a23 * b01) * inv_det,
4994            (a10 * b10 - a11 * b08 + a13 * b06) * inv_det,
4995            (a01 * b08 - a00 * b10 - a03 * b06) * inv_det,
4996            (a30 * b04 - a31 * b02 + a33 * b00) * inv_det,
4997            (a21 * b02 - a20 * b04 - a23 * b00) * inv_det,
4998            (a11 * b07 - a10 * b09 - a12 * b06) * inv_det,
4999            (a00 * b09 - a01 * b07 + a02 * b06) * inv_det,
5000            (a31 * b01 - a30 * b03 - a32 * b00) * inv_det,
5001            (a20 * b03 - a21 * b01 + a22 * b00) * inv_det,
5002        ]))
5003    });
5004
5005    // mat4_transpose(m) - transpose matrix
5006    define(interp, "mat4_transpose", Some(1), |_, args| {
5007        let m = extract_mat4(&args[0], "mat4_transpose")?;
5008        Ok(make_mat4([
5009            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],
5010            m[11], m[15],
5011        ]))
5012    });
5013
5014    // -------------------------------------------------------------------------
5015    // MAT3 - 3x3 MATRICES (for normals, 2D transforms)
5016    // -------------------------------------------------------------------------
5017
5018    // mat3_identity() - 3x3 identity matrix
5019    define(interp, "mat3_identity", Some(0), |_, _| {
5020        Ok(make_mat3([1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0]))
5021    });
5022
5023    // mat3_from_mat4(m) - extract upper-left 3x3 from 4x4 (for normal matrix)
5024    define(interp, "mat3_from_mat4", Some(1), |_, args| {
5025        let m = extract_mat4(&args[0], "mat3_from_mat4")?;
5026        Ok(make_mat3([
5027            m[0], m[1], m[2], m[4], m[5], m[6], m[8], m[9], m[10],
5028        ]))
5029    });
5030
5031    // mat3_mul(a, b) - 3x3 matrix multiplication
5032    define(interp, "mat3_mul", Some(2), |_, args| {
5033        let a = extract_mat3(&args[0], "mat3_mul")?;
5034        let b = extract_mat3(&args[1], "mat3_mul")?;
5035
5036        let mut result = [0.0f64; 9];
5037        for col in 0..3 {
5038            for row in 0..3 {
5039                let mut sum = 0.0;
5040                for k in 0..3 {
5041                    sum += a[k * 3 + row] * b[col * 3 + k];
5042                }
5043                result[col * 3 + row] = sum;
5044            }
5045        }
5046        Ok(make_mat3(result))
5047    });
5048
5049    // mat3_transform(mat3, vec3) - transform 3D vector by 3x3 matrix
5050    define(interp, "mat3_transform", Some(2), |_, args| {
5051        let m = extract_mat3(&args[0], "mat3_transform")?;
5052        let v = extract_vec3(&args[1], "mat3_transform")?;
5053
5054        Ok(make_vec3(
5055            m[0] * v[0] + m[3] * v[1] + m[6] * v[2],
5056            m[1] * v[0] + m[4] * v[1] + m[7] * v[2],
5057            m[2] * v[0] + m[5] * v[1] + m[8] * v[2],
5058        ))
5059    });
5060
5061    // mat3_inverse(m) - 3x3 matrix inverse
5062    define(interp, "mat3_inverse", Some(1), |_, args| {
5063        let m = extract_mat3(&args[0], "mat3_inverse")?;
5064
5065        let det = m[0] * (m[4] * m[8] - m[5] * m[7]) - m[3] * (m[1] * m[8] - m[2] * m[7])
5066            + m[6] * (m[1] * m[5] - m[2] * m[4]);
5067
5068        if det.abs() < 1e-10 {
5069            return Err(RuntimeError::new("mat3_inverse: singular matrix"));
5070        }
5071
5072        let inv_det = 1.0 / det;
5073
5074        Ok(make_mat3([
5075            (m[4] * m[8] - m[5] * m[7]) * inv_det,
5076            (m[2] * m[7] - m[1] * m[8]) * inv_det,
5077            (m[1] * m[5] - m[2] * m[4]) * inv_det,
5078            (m[5] * m[6] - m[3] * m[8]) * inv_det,
5079            (m[0] * m[8] - m[2] * m[6]) * inv_det,
5080            (m[2] * m[3] - m[0] * m[5]) * inv_det,
5081            (m[3] * m[7] - m[4] * m[6]) * inv_det,
5082            (m[1] * m[6] - m[0] * m[7]) * inv_det,
5083            (m[0] * m[4] - m[1] * m[3]) * inv_det,
5084        ]))
5085    });
5086
5087    // mat3_transpose(m)
5088    define(interp, "mat3_transpose", Some(1), |_, args| {
5089        let m = extract_mat3(&args[0], "mat3_transpose")?;
5090        Ok(make_mat3([
5091            m[0], m[3], m[6], m[1], m[4], m[7], m[2], m[5], m[8],
5092        ]))
5093    });
5094}
5095
5096// Helper functions for graphics math
5097fn extract_number(v: &Value, fn_name: &str) -> Result<f64, RuntimeError> {
5098    match v {
5099        Value::Float(f) => Ok(*f),
5100        Value::Int(i) => Ok(*i as f64),
5101        _ => Err(RuntimeError::new(format!(
5102            "{}() requires number argument",
5103            fn_name
5104        ))),
5105    }
5106}
5107
5108fn extract_vec2(v: &Value, fn_name: &str) -> Result<[f64; 2], RuntimeError> {
5109    match v {
5110        Value::Array(arr) => {
5111            let arr = arr.borrow();
5112            if arr.len() < 2 {
5113                return Err(RuntimeError::new(format!(
5114                    "{}() requires vec2 (2 elements)",
5115                    fn_name
5116                )));
5117            }
5118            Ok([
5119                extract_number(&arr[0], fn_name)?,
5120                extract_number(&arr[1], fn_name)?,
5121            ])
5122        }
5123        _ => Err(RuntimeError::new(format!(
5124            "{}() requires vec2 array",
5125            fn_name
5126        ))),
5127    }
5128}
5129
5130fn extract_vec3(v: &Value, fn_name: &str) -> Result<[f64; 3], RuntimeError> {
5131    match v {
5132        Value::Array(arr) => {
5133            let arr = arr.borrow();
5134            if arr.len() < 3 {
5135                return Err(RuntimeError::new(format!(
5136                    "{}() requires vec3 (3 elements)",
5137                    fn_name
5138                )));
5139            }
5140            Ok([
5141                extract_number(&arr[0], fn_name)?,
5142                extract_number(&arr[1], fn_name)?,
5143                extract_number(&arr[2], fn_name)?,
5144            ])
5145        }
5146        _ => Err(RuntimeError::new(format!(
5147            "{}() requires vec3 array",
5148            fn_name
5149        ))),
5150    }
5151}
5152
5153fn extract_vec4(v: &Value, fn_name: &str) -> Result<[f64; 4], RuntimeError> {
5154    match v {
5155        Value::Array(arr) => {
5156            let arr = arr.borrow();
5157            if arr.len() < 4 {
5158                return Err(RuntimeError::new(format!(
5159                    "{}() requires vec4 (4 elements)",
5160                    fn_name
5161                )));
5162            }
5163            Ok([
5164                extract_number(&arr[0], fn_name)?,
5165                extract_number(&arr[1], fn_name)?,
5166                extract_number(&arr[2], fn_name)?,
5167                extract_number(&arr[3], fn_name)?,
5168            ])
5169        }
5170        _ => Err(RuntimeError::new(format!(
5171            "{}() requires vec4 array",
5172            fn_name
5173        ))),
5174    }
5175}
5176
5177fn extract_mat3(v: &Value, fn_name: &str) -> Result<[f64; 9], RuntimeError> {
5178    match v {
5179        Value::Array(arr) => {
5180            let arr = arr.borrow();
5181            if arr.len() < 9 {
5182                return Err(RuntimeError::new(format!(
5183                    "{}() requires mat3 (9 elements)",
5184                    fn_name
5185                )));
5186            }
5187            let mut result = [0.0f64; 9];
5188            for i in 0..9 {
5189                result[i] = extract_number(&arr[i], fn_name)?;
5190            }
5191            Ok(result)
5192        }
5193        _ => Err(RuntimeError::new(format!(
5194            "{}() requires mat3 array",
5195            fn_name
5196        ))),
5197    }
5198}
5199
5200fn extract_mat4(v: &Value, fn_name: &str) -> Result<[f64; 16], RuntimeError> {
5201    match v {
5202        Value::Array(arr) => {
5203            let arr = arr.borrow();
5204            if arr.len() < 16 {
5205                return Err(RuntimeError::new(format!(
5206                    "{}() requires mat4 (16 elements)",
5207                    fn_name
5208                )));
5209            }
5210            let mut result = [0.0f64; 16];
5211            for i in 0..16 {
5212                result[i] = extract_number(&arr[i], fn_name)?;
5213            }
5214            Ok(result)
5215        }
5216        _ => Err(RuntimeError::new(format!(
5217            "{}() requires mat4 array",
5218            fn_name
5219        ))),
5220    }
5221}
5222
5223fn make_vec2(x: f64, y: f64) -> Value {
5224    Value::Array(Rc::new(RefCell::new(vec![
5225        Value::Float(x),
5226        Value::Float(y),
5227    ])))
5228}
5229
5230fn make_vec3(x: f64, y: f64, z: f64) -> Value {
5231    Value::Array(Rc::new(RefCell::new(vec![
5232        Value::Float(x),
5233        Value::Float(y),
5234        Value::Float(z),
5235    ])))
5236}
5237
5238// Helper for making vec3 from array
5239fn make_vec3_arr(v: [f64; 3]) -> Value {
5240    make_vec3(v[0], v[1], v[2])
5241}
5242
5243fn make_vec4(x: f64, y: f64, z: f64, w: f64) -> Value {
5244    Value::Array(Rc::new(RefCell::new(vec![
5245        Value::Float(x),
5246        Value::Float(y),
5247        Value::Float(z),
5248        Value::Float(w),
5249    ])))
5250}
5251
5252fn make_mat3(m: [f64; 9]) -> Value {
5253    Value::Array(Rc::new(RefCell::new(
5254        m.iter().map(|&v| Value::Float(v)).collect(),
5255    )))
5256}
5257
5258fn make_mat4(m: [f64; 16]) -> Value {
5259    Value::Array(Rc::new(RefCell::new(
5260        m.iter().map(|&v| Value::Float(v)).collect(),
5261    )))
5262}
5263
5264// ============================================================================
5265// CONCURRENCY FUNCTIONS
5266// ============================================================================
5267// WARNING: Interpreter Limitations
5268// ---------------------------------
5269// The interpreter uses Rc<RefCell<>> which is NOT thread-safe (not Send/Sync).
5270// This means:
5271// - Channels work but block the main thread
5272// - Actors run single-threaded with message queuing
5273// - Thread primitives simulate behavior but don't provide true parallelism
5274// - Atomics work correctly for single-threaded access patterns
5275//
5276// For true parallel execution, compile with the JIT backend (--jit flag).
5277// The JIT uses Arc/Mutex and compiles to native code with proper threading.
5278// ============================================================================
5279
5280fn register_concurrency(interp: &mut Interpreter) {
5281    // --- CHANNELS ---
5282
5283    // channel_new - create a new channel for message passing
5284    define(interp, "channel_new", Some(0), |_, _| {
5285        let (sender, receiver) = mpsc::channel();
5286        let inner = ChannelInner {
5287            sender: Mutex::new(sender),
5288            receiver: Mutex::new(receiver),
5289        };
5290        Ok(Value::Channel(Arc::new(inner)))
5291    });
5292
5293    // channel_send - send a value on a channel (blocking)
5294    define(interp, "channel_send", Some(2), |_, args| {
5295        let channel = match &args[0] {
5296            Value::Channel(ch) => ch.clone(),
5297            _ => {
5298                return Err(RuntimeError::new(
5299                    "channel_send() requires channel as first argument",
5300                ))
5301            }
5302        };
5303        let value = args[1].clone();
5304
5305        let sender = channel
5306            .sender
5307            .lock()
5308            .map_err(|_| RuntimeError::new("channel mutex poisoned"))?;
5309        sender
5310            .send(value)
5311            .map_err(|_| RuntimeError::new("channel_send() failed: receiver dropped"))?;
5312
5313        Ok(Value::Null)
5314    });
5315
5316    // channel_recv - receive a value from a channel (blocking)
5317    define(interp, "channel_recv", Some(1), |_, args| {
5318        let channel = match &args[0] {
5319            Value::Channel(ch) => ch.clone(),
5320            _ => {
5321                return Err(RuntimeError::new(
5322                    "channel_recv() requires channel argument",
5323                ))
5324            }
5325        };
5326
5327        let receiver = channel
5328            .receiver
5329            .lock()
5330            .map_err(|_| RuntimeError::new("channel mutex poisoned"))?;
5331        match receiver.recv() {
5332            Ok(value) => Ok(value),
5333            Err(_) => Err(RuntimeError::new("channel_recv() failed: sender dropped")),
5334        }
5335    });
5336
5337    // channel_try_recv - non-blocking receive, returns Option
5338    define(interp, "channel_try_recv", Some(1), |_, args| {
5339        let channel = match &args[0] {
5340            Value::Channel(ch) => ch.clone(),
5341            _ => {
5342                return Err(RuntimeError::new(
5343                    "channel_try_recv() requires channel argument",
5344                ))
5345            }
5346        };
5347
5348        let receiver = channel
5349            .receiver
5350            .lock()
5351            .map_err(|_| RuntimeError::new("channel mutex poisoned"))?;
5352        match receiver.try_recv() {
5353            Ok(value) => {
5354                // Return Some(value) as a variant
5355                Ok(Value::Variant {
5356                    enum_name: "Option".to_string(),
5357                    variant_name: "Some".to_string(),
5358                    fields: Some(Rc::new(vec![value])),
5359                })
5360            }
5361            Err(mpsc::TryRecvError::Empty) => {
5362                // Return None
5363                Ok(Value::Variant {
5364                    enum_name: "Option".to_string(),
5365                    variant_name: "None".to_string(),
5366                    fields: None,
5367                })
5368            }
5369            Err(mpsc::TryRecvError::Disconnected) => Err(RuntimeError::new(
5370                "channel_try_recv() failed: sender dropped",
5371            )),
5372        }
5373    });
5374
5375    // channel_recv_timeout - receive with timeout in milliseconds
5376    define(interp, "channel_recv_timeout", Some(2), |_, args| {
5377        let channel = match &args[0] {
5378            Value::Channel(ch) => ch.clone(),
5379            _ => {
5380                return Err(RuntimeError::new(
5381                    "channel_recv_timeout() requires a channel as first argument.\n\
5382                 Create a channel with channel_new():\n\
5383                   let ch = channel_new();\n\
5384                   channel_send(ch, value);\n\
5385                   let result = channel_recv_timeout(ch, 1000);  // 1 second timeout",
5386                ))
5387            }
5388        };
5389        let timeout_ms = match &args[1] {
5390            Value::Int(ms) => *ms as u64,
5391            _ => {
5392                return Err(RuntimeError::new(
5393                    "channel_recv_timeout() requires timeout in milliseconds (integer).\n\
5394                 Example: channel_recv_timeout(ch, 1000)  // Wait up to 1 second",
5395                ))
5396            }
5397        };
5398
5399        let receiver = channel
5400            .receiver
5401            .lock()
5402            .map_err(|_| RuntimeError::new("channel mutex poisoned"))?;
5403        match receiver.recv_timeout(std::time::Duration::from_millis(timeout_ms)) {
5404            Ok(value) => Ok(Value::Variant {
5405                enum_name: "Option".to_string(),
5406                variant_name: "Some".to_string(),
5407                fields: Some(Rc::new(vec![value])),
5408            }),
5409            Err(mpsc::RecvTimeoutError::Timeout) => Ok(Value::Variant {
5410                enum_name: "Option".to_string(),
5411                variant_name: "None".to_string(),
5412                fields: None,
5413            }),
5414            Err(mpsc::RecvTimeoutError::Disconnected) => Err(RuntimeError::new(
5415                "channel_recv_timeout() failed: sender dropped",
5416            )),
5417        }
5418    });
5419
5420    // --- THREADS ---
5421    // Note: The interpreter's Value type uses Rc which is not Send.
5422    // For true threading, use channels to communicate primitive types.
5423    // These functions provide basic thread primitives.
5424
5425    // thread_spawn_detached - spawn a detached thread (no join)
5426    // Useful for background work, results communicated via channels
5427    define(interp, "thread_spawn_detached", Some(0), |_, _| {
5428        // Spawn a simple detached thread that does nothing
5429        // Real work should be done via channels
5430        thread::spawn(|| {
5431            // Background thread
5432        });
5433        Ok(Value::Null)
5434    });
5435
5436    // std::thread::spawn - spawn a thread with a closure
5437    // In interpreter mode, execute synchronously (Rc is not thread-safe)
5438    // Returns a JoinHandle-like value
5439    define(interp, "std·thread·spawn", Some(1), |interp, args| {
5440        // The argument should be a closure/function
5441        match &args[0] {
5442            Value::Function(f) => {
5443                // Execute the closure synchronously for now
5444                // This makes the server work in single-threaded mode
5445                match interp.call_function(f, vec![]) {
5446                    Ok(_) => {}
5447                    Err(e) => eprintln!("[Sigil thread] Error: {}", e),
5448                }
5449                // Return a mock JoinHandle
5450                let mut map = HashMap::new();
5451                map.insert("__type__".to_string(), Value::String(Rc::new("JoinHandle".to_string())));
5452                map.insert("done".to_string(), Value::Bool(true));
5453                Ok(Value::Map(Rc::new(RefCell::new(map))))
5454            }
5455            Value::BuiltIn(b) => {
5456                match (b.func)(interp, vec![]) {
5457                    Ok(_) => {}
5458                    Err(e) => eprintln!("[Sigil thread] Error: {}", e),
5459                }
5460                let mut map = HashMap::new();
5461                map.insert("__type__".to_string(), Value::String(Rc::new("JoinHandle".to_string())));
5462                map.insert("done".to_string(), Value::Bool(true));
5463                Ok(Value::Map(Rc::new(RefCell::new(map))))
5464            }
5465            _ => Err(RuntimeError::new("std::thread::spawn requires a closure")),
5466        }
5467    });
5468
5469    // thread_join - placeholder for join semantics
5470    // In interpreter, actual work is done via channels
5471    define(interp, "thread_join", Some(1), |_, args| {
5472        match &args[0] {
5473            Value::ThreadHandle(h) => {
5474                let mut guard = h
5475                    .lock()
5476                    .map_err(|_| RuntimeError::new("thread handle mutex poisoned"))?;
5477                if let Some(handle) = guard.take() {
5478                    match handle.join() {
5479                        Ok(v) => Ok(v),
5480                        Err(_) => Err(RuntimeError::new("thread panicked")),
5481                    }
5482                } else {
5483                    Err(RuntimeError::new("thread already joined"))
5484                }
5485            }
5486            // For non-handles, just return the value
5487            _ => Ok(args[0].clone()),
5488        }
5489    });
5490
5491    // thread_sleep - sleep for specified milliseconds
5492    define(interp, "thread_sleep", Some(1), |_, args| {
5493        let ms = match &args[0] {
5494            Value::Int(ms) => *ms as u64,
5495            Value::Float(ms) => *ms as u64,
5496            _ => {
5497                return Err(RuntimeError::new(
5498                    "thread_sleep() requires integer milliseconds",
5499                ))
5500            }
5501        };
5502
5503        thread::sleep(std::time::Duration::from_millis(ms));
5504        Ok(Value::Null)
5505    });
5506
5507    // thread_yield - yield the current thread
5508    define(interp, "thread_yield", Some(0), |_, _| {
5509        thread::yield_now();
5510        Ok(Value::Null)
5511    });
5512
5513    // thread_id - get current thread id as string
5514    define(interp, "thread_id", Some(0), |_, _| {
5515        let id = thread::current().id();
5516        Ok(Value::String(Rc::new(format!("{:?}", id))))
5517    });
5518
5519    // --- SYNCHRONIZATION PRIMITIVES ---
5520    // parking_lot::Mutex::new - create a mutex wrapper
5521    // Returns a Map with __type__="Mutex" and inner value
5522    define(interp, "parking_lot·Mutex·new", Some(1), |_, args| {
5523        let mut map = HashMap::new();
5524        map.insert("__type__".to_string(), Value::String(Rc::new("Mutex".to_string())));
5525        map.insert("inner".to_string(), args[0].clone());
5526        Ok(Value::Map(Rc::new(RefCell::new(map))))
5527    });
5528
5529    // Also register as std::sync::Mutex::new
5530    define(interp, "std·sync·Mutex·new", Some(1), |_, args| {
5531        let mut map = HashMap::new();
5532        map.insert("__type__".to_string(), Value::String(Rc::new("Mutex".to_string())));
5533        map.insert("inner".to_string(), args[0].clone());
5534        Ok(Value::Map(Rc::new(RefCell::new(map))))
5535    });
5536
5537    // parking_lot::RwLock::new - create a read-write lock wrapper
5538    define(interp, "parking_lot·RwLock·new", Some(1), |_, args| {
5539        let mut map = HashMap::new();
5540        map.insert("__type__".to_string(), Value::String(Rc::new("RwLock".to_string())));
5541        map.insert("inner".to_string(), args[0].clone());
5542        Ok(Value::Map(Rc::new(RefCell::new(map))))
5543    });
5544
5545    // std::sync::RwLock::new
5546    define(interp, "std·sync·RwLock·new", Some(1), |_, args| {
5547        let mut map = HashMap::new();
5548        map.insert("__type__".to_string(), Value::String(Rc::new("RwLock".to_string())));
5549        map.insert("inner".to_string(), args[0].clone());
5550        Ok(Value::Map(Rc::new(RefCell::new(map))))
5551    });
5552
5553    // RwLock::new (short form)
5554    define(interp, "RwLock·new", Some(1), |_, args| {
5555        let mut map = HashMap::new();
5556        map.insert("__type__".to_string(), Value::String(Rc::new("RwLock".to_string())));
5557        map.insert("inner".to_string(), args[0].clone());
5558        Ok(Value::Map(Rc::new(RefCell::new(map))))
5559    });
5560
5561    // AtomicU64::new - create atomic counter
5562    define(interp, "AtomicU64·new", Some(1), |_, args| {
5563        let val = match &args[0] {
5564            Value::Int(i) => *i,
5565            _ => 0,
5566        };
5567        let mut map = HashMap::new();
5568        map.insert("__type__".to_string(), Value::String(Rc::new("AtomicU64".to_string())));
5569        map.insert("value".to_string(), Value::Int(val));
5570        Ok(Value::Map(Rc::new(RefCell::new(map))))
5571    });
5572
5573    // std::sync::atomic::AtomicU64::new
5574    define(interp, "std·sync·atomic·AtomicU64·new", Some(1), |_, args| {
5575        let val = match &args[0] {
5576            Value::Int(i) => *i,
5577            _ => 0,
5578        };
5579        let mut map = HashMap::new();
5580        map.insert("__type__".to_string(), Value::String(Rc::new("AtomicU64".to_string())));
5581        map.insert("value".to_string(), Value::Int(val));
5582        Ok(Value::Map(Rc::new(RefCell::new(map))))
5583    });
5584
5585    // AtomicBool::new
5586    define(interp, "AtomicBool·new", Some(1), |_, args| {
5587        let val = match &args[0] {
5588            Value::Bool(b) => *b,
5589            _ => false,
5590        };
5591        let mut map = HashMap::new();
5592        map.insert("__type__".to_string(), Value::String(Rc::new("AtomicBool".to_string())));
5593        map.insert("value".to_string(), Value::Bool(val));
5594        Ok(Value::Map(Rc::new(RefCell::new(map))))
5595    });
5596
5597    define(interp, "std·sync·atomic·AtomicBool·new", Some(1), |_, args| {
5598        let val = match &args[0] {
5599            Value::Bool(b) => *b,
5600            _ => false,
5601        };
5602        let mut map = HashMap::new();
5603        map.insert("__type__".to_string(), Value::String(Rc::new("AtomicBool".to_string())));
5604        map.insert("value".to_string(), Value::Bool(val));
5605        Ok(Value::Map(Rc::new(RefCell::new(map))))
5606    });
5607
5608    // Arc::new - create atomic reference counted wrapper
5609    define(interp, "Arc·new", Some(1), |_, args| {
5610        let mut map = HashMap::new();
5611        map.insert("__type__".to_string(), Value::String(Rc::new("Arc".to_string())));
5612        map.insert("inner".to_string(), args[0].clone());
5613        Ok(Value::Map(Rc::new(RefCell::new(map))))
5614    });
5615
5616    define(interp, "std·sync·Arc·new", Some(1), |_, args| {
5617        let mut map = HashMap::new();
5618        map.insert("__type__".to_string(), Value::String(Rc::new("Arc".to_string())));
5619        map.insert("inner".to_string(), args[0].clone());
5620        Ok(Value::Map(Rc::new(RefCell::new(map))))
5621    });
5622
5623    // --- NETWORKING ---
5624    // TCP/IP networking support for HTTP servers
5625
5626    // TcpListener::bind - bind to an address and create a listener
5627    define(interp, "TcpListener·bind", Some(1), |_, args| {
5628        let addr_str = match &args[0] {
5629            Value::String(s) => s.to_string(),
5630            Value::Ref(r) => {
5631                if let Value::String(s) = &*r.borrow() {
5632                    s.to_string()
5633                } else {
5634                    return Err(RuntimeError::new("TcpListener::bind requires string address"));
5635                }
5636            }
5637            // Handle SocketAddr map (from parse())
5638            Value::Map(m) => {
5639                let borrowed = m.borrow();
5640                if let Some(Value::String(addr)) = borrowed.get("addr") {
5641                    addr.to_string()
5642                } else if let Some(Value::String(_)) = borrowed.get("__type__") {
5643                    // SocketAddr type, try addr field
5644                    if let Some(Value::String(addr)) = borrowed.get("addr") {
5645                        addr.to_string()
5646                    } else {
5647                        return Err(RuntimeError::new("SocketAddr missing addr field"));
5648                    }
5649                } else {
5650                    return Err(RuntimeError::new("TcpListener::bind requires string or SocketAddr"));
5651                }
5652            }
5653            _ => return Err(RuntimeError::new("TcpListener::bind requires string address")),
5654        };
5655
5656        // Parse the address
5657        let addr: std::net::SocketAddr = match addr_str.parse() {
5658            Ok(a) => a,
5659            Err(e) => return Err(RuntimeError::new(format!("Invalid address: {}", e))),
5660        };
5661
5662        // Bind the listener
5663        let listener = match std::net::TcpListener::bind(addr) {
5664            Ok(l) => l,
5665            Err(e) => return Err(RuntimeError::new(format!("Failed to bind: {}", e))),
5666        };
5667
5668        let local_addr = listener.local_addr().map(|a| a.to_string()).unwrap_or_default();
5669
5670        // Store the listener in the global registry
5671        let listener_id = store_listener(listener);
5672
5673        let mut map = HashMap::new();
5674        map.insert("__type__".to_string(), Value::String(Rc::new("TcpListener".to_string())));
5675        map.insert("addr".to_string(), Value::String(Rc::new(addr_str)));
5676        map.insert("local_addr".to_string(), Value::String(Rc::new(local_addr)));
5677        map.insert("__listener_id__".to_string(), Value::Int(listener_id as i64));
5678
5679        eprintln!("[Sigil] TcpListener bound to {} (id={})", addr, listener_id);
5680
5681        Ok(Value::Variant {
5682            enum_name: "Result".to_string(),
5683            variant_name: "Ok".to_string(),
5684            fields: Some(Rc::new(vec![Value::Map(Rc::new(RefCell::new(map)))])),
5685        })
5686    });
5687
5688    define(interp, "std·net·TcpListener·bind", Some(1), |_, args| {
5689        let addr_str = match &args[0] {
5690            Value::String(s) => s.to_string(),
5691            Value::Ref(r) => {
5692                if let Value::String(s) = &*r.borrow() {
5693                    s.to_string()
5694                } else {
5695                    return Err(RuntimeError::new("TcpListener::bind requires string address"));
5696                }
5697            }
5698            // Handle SocketAddr map (from parse())
5699            Value::Map(m) => {
5700                let borrowed = m.borrow();
5701                if let Some(Value::String(addr)) = borrowed.get("addr") {
5702                    addr.to_string()
5703                } else {
5704                    return Err(RuntimeError::new("TcpListener::bind requires string or SocketAddr"));
5705                }
5706            }
5707            _ => return Err(RuntimeError::new("TcpListener::bind requires string address")),
5708        };
5709
5710        let addr: std::net::SocketAddr = match addr_str.parse() {
5711            Ok(a) => a,
5712            Err(e) => return Err(RuntimeError::new(format!("Invalid address: {}", e))),
5713        };
5714
5715        let _listener = match std::net::TcpListener::bind(addr) {
5716            Ok(l) => l,
5717            Err(e) => return Err(RuntimeError::new(format!("Failed to bind: {}", e))),
5718        };
5719
5720        let mut map = HashMap::new();
5721        map.insert("__type__".to_string(), Value::String(Rc::new("TcpListener".to_string())));
5722        map.insert("addr".to_string(), Value::String(Rc::new(addr_str)));
5723
5724        eprintln!("[Sigil] TcpListener bound to {}", addr);
5725
5726        Ok(Value::Variant {
5727            enum_name: "Result".to_string(),
5728            variant_name: "Ok".to_string(),
5729            fields: Some(Rc::new(vec![Value::Map(Rc::new(RefCell::new(map)))])),
5730        })
5731    });
5732
5733    // SocketAddr::parse - parse a socket address string
5734    define(interp, "SocketAddr·parse", Some(1), |_, args| {
5735        let addr_str = match &args[0] {
5736            Value::String(s) => s.to_string(),
5737            _ => return Err(RuntimeError::new("SocketAddr::parse requires string")),
5738        };
5739
5740        match addr_str.parse::<std::net::SocketAddr>() {
5741            Ok(_) => {
5742                let mut map = HashMap::new();
5743                map.insert("__type__".to_string(), Value::String(Rc::new("SocketAddr".to_string())));
5744                map.insert("addr".to_string(), Value::String(Rc::new(addr_str)));
5745                Ok(Value::Variant {
5746                    enum_name: "Result".to_string(),
5747                    variant_name: "Ok".to_string(),
5748                    fields: Some(Rc::new(vec![Value::Map(Rc::new(RefCell::new(map)))])),
5749                })
5750            }
5751            Err(e) => Ok(Value::Variant {
5752                enum_name: "Result".to_string(),
5753                variant_name: "Err".to_string(),
5754                fields: Some(Rc::new(vec![Value::String(Rc::new(e.to_string()))])),
5755            }),
5756        }
5757    });
5758
5759    // --- TcpStream Methods ---
5760    // Methods for reading/writing from TcpStream connections
5761
5762    // TcpStream::peer_addr - get the remote address
5763    define(interp, "TcpStream·peer_addr", Some(1), |_, args| {
5764        let stream_id = match &args[0] {
5765            Value::Map(m) => {
5766                let borrowed = m.borrow();
5767                if let Some(Value::Int(id)) = borrowed.get("__stream_id__") {
5768                    *id as u64
5769                } else {
5770                    return Err(RuntimeError::new("TcpStream missing __stream_id__"));
5771                }
5772            }
5773            _ => return Err(RuntimeError::new("peer_addr requires TcpStream")),
5774        };
5775
5776        if let Some(guard) = get_stream_registry().lock().ok() {
5777            if let Some(stream) = guard.get(&stream_id) {
5778                match stream.peer_addr() {
5779                    Ok(addr) => {
5780                        let mut map = HashMap::new();
5781                        map.insert("__type__".to_string(), Value::String(Rc::new("SocketAddr".to_string())));
5782                        map.insert("addr".to_string(), Value::String(Rc::new(addr.to_string())));
5783                        Ok(Value::Variant {
5784                            enum_name: "Result".to_string(),
5785                            variant_name: "Ok".to_string(),
5786                            fields: Some(Rc::new(vec![Value::Map(Rc::new(RefCell::new(map)))])),
5787                        })
5788                    }
5789                    Err(e) => Ok(Value::Variant {
5790                        enum_name: "Result".to_string(),
5791                        variant_name: "Err".to_string(),
5792                        fields: Some(Rc::new(vec![Value::String(Rc::new(e.to_string()))])),
5793                    }),
5794                }
5795            } else {
5796                Err(RuntimeError::new("TcpStream not found in registry"))
5797            }
5798        } else {
5799            Err(RuntimeError::new("Failed to lock stream registry"))
5800        }
5801    });
5802
5803    // TcpStream::read - read bytes from stream
5804    define(interp, "TcpStream·read", Some(2), |_, args| {
5805        use std::io::Read;
5806
5807        let stream_id = match &args[0] {
5808            Value::Map(m) => {
5809                let borrowed = m.borrow();
5810                if let Some(Value::Int(id)) = borrowed.get("__stream_id__") {
5811                    *id as u64
5812                } else {
5813                    return Err(RuntimeError::new("TcpStream missing __stream_id__"));
5814                }
5815            }
5816            _ => return Err(RuntimeError::new("read requires TcpStream")),
5817        };
5818
5819        let size = match &args[1] {
5820            Value::Int(n) => *n as usize,
5821            _ => return Err(RuntimeError::new("read requires size as integer")),
5822        };
5823
5824        if let Some(mut guard) = get_stream_registry().lock().ok() {
5825            if let Some(stream) = guard.get_mut(&stream_id) {
5826                let mut buf = vec![0u8; size];
5827                match stream.read(&mut buf) {
5828                    Ok(n) => {
5829                        buf.truncate(n);
5830                        let bytes: Vec<Value> = buf.iter().map(|b| Value::Int(*b as i64)).collect();
5831                        Ok(Value::Variant {
5832                            enum_name: "Result".to_string(),
5833                            variant_name: "Ok".to_string(),
5834                            fields: Some(Rc::new(vec![Value::Array(Rc::new(RefCell::new(bytes)))])),
5835                        })
5836                    }
5837                    Err(e) => Ok(Value::Variant {
5838                        enum_name: "Result".to_string(),
5839                        variant_name: "Err".to_string(),
5840                        fields: Some(Rc::new(vec![Value::String(Rc::new(e.to_string()))])),
5841                    }),
5842                }
5843            } else {
5844                Err(RuntimeError::new("TcpStream not found in registry"))
5845            }
5846        } else {
5847            Err(RuntimeError::new("Failed to lock stream registry"))
5848        }
5849    });
5850
5851    // TcpStream::read_exact - read exact number of bytes
5852    define(interp, "TcpStream·read_exact", Some(2), |_, args| {
5853        use std::io::Read;
5854
5855        let stream_id = match &args[0] {
5856            Value::Map(m) => {
5857                let borrowed = m.borrow();
5858                if let Some(Value::Int(id)) = borrowed.get("__stream_id__") {
5859                    *id as u64
5860                } else {
5861                    return Err(RuntimeError::new("TcpStream missing __stream_id__"));
5862                }
5863            }
5864            _ => return Err(RuntimeError::new("read_exact requires TcpStream")),
5865        };
5866
5867        let size = match &args[1] {
5868            Value::Int(n) => *n as usize,
5869            _ => return Err(RuntimeError::new("read_exact requires size as integer")),
5870        };
5871
5872        if let Some(mut guard) = get_stream_registry().lock().ok() {
5873            if let Some(stream) = guard.get_mut(&stream_id) {
5874                let mut buf = vec![0u8; size];
5875                match stream.read_exact(&mut buf) {
5876                    Ok(()) => {
5877                        let bytes: Vec<Value> = buf.iter().map(|b| Value::Int(*b as i64)).collect();
5878                        Ok(Value::Variant {
5879                            enum_name: "Result".to_string(),
5880                            variant_name: "Ok".to_string(),
5881                            fields: Some(Rc::new(vec![Value::Array(Rc::new(RefCell::new(bytes)))])),
5882                        })
5883                    }
5884                    Err(e) => Ok(Value::Variant {
5885                        enum_name: "Result".to_string(),
5886                        variant_name: "Err".to_string(),
5887                        fields: Some(Rc::new(vec![Value::String(Rc::new(e.to_string()))])),
5888                    }),
5889                }
5890            } else {
5891                Err(RuntimeError::new("TcpStream not found in registry"))
5892            }
5893        } else {
5894            Err(RuntimeError::new("Failed to lock stream registry"))
5895        }
5896    });
5897
5898    // TcpStream::write_all - write all bytes to stream
5899    define(interp, "TcpStream·write_all", Some(2), |_, args| {
5900        use std::io::Write;
5901
5902        let stream_id = match &args[0] {
5903            Value::Map(m) => {
5904                let borrowed = m.borrow();
5905                if let Some(Value::Int(id)) = borrowed.get("__stream_id__") {
5906                    *id as u64
5907                } else {
5908                    return Err(RuntimeError::new("TcpStream missing __stream_id__"));
5909                }
5910            }
5911            _ => return Err(RuntimeError::new("write_all requires TcpStream")),
5912        };
5913
5914        // Handle various data types
5915        let data: Vec<u8> = match &args[1] {
5916            Value::String(s) => s.as_bytes().to_vec(),
5917            Value::Array(arr) => {
5918                arr.borrow().iter().filter_map(|v| {
5919                    if let Value::Int(n) = v { Some(*n as u8) } else { None }
5920                }).collect()
5921            }
5922            Value::Ref(r) => {
5923                if let Value::String(s) = &*r.borrow() {
5924                    s.as_bytes().to_vec()
5925                } else {
5926                    return Err(RuntimeError::new("write_all requires string or byte array"));
5927                }
5928            }
5929            _ => return Err(RuntimeError::new("write_all requires string or byte array")),
5930        };
5931
5932        if let Some(mut guard) = get_stream_registry().lock().ok() {
5933            if let Some(stream) = guard.get_mut(&stream_id) {
5934                match stream.write_all(&data) {
5935                    Ok(()) => Ok(Value::Variant {
5936                        enum_name: "Result".to_string(),
5937                        variant_name: "Ok".to_string(),
5938                        fields: Some(Rc::new(vec![Value::Null])),
5939                    }),
5940                    Err(e) => Ok(Value::Variant {
5941                        enum_name: "Result".to_string(),
5942                        variant_name: "Err".to_string(),
5943                        fields: Some(Rc::new(vec![Value::String(Rc::new(e.to_string()))])),
5944                    }),
5945                }
5946            } else {
5947                Err(RuntimeError::new("TcpStream not found in registry"))
5948            }
5949        } else {
5950            Err(RuntimeError::new("Failed to lock stream registry"))
5951        }
5952    });
5953
5954    // TcpStream::flush - flush the stream
5955    define(interp, "TcpStream·flush", Some(1), |_, args| {
5956        use std::io::Write;
5957
5958        let stream_id = match &args[0] {
5959            Value::Map(m) => {
5960                let borrowed = m.borrow();
5961                if let Some(Value::Int(id)) = borrowed.get("__stream_id__") {
5962                    *id as u64
5963                } else {
5964                    return Err(RuntimeError::new("TcpStream missing __stream_id__"));
5965                }
5966            }
5967            _ => return Err(RuntimeError::new("flush requires TcpStream")),
5968        };
5969
5970        if let Some(mut guard) = get_stream_registry().lock().ok() {
5971            if let Some(stream) = guard.get_mut(&stream_id) {
5972                match stream.flush() {
5973                    Ok(()) => Ok(Value::Variant {
5974                        enum_name: "Result".to_string(),
5975                        variant_name: "Ok".to_string(),
5976                        fields: Some(Rc::new(vec![Value::Null])),
5977                    }),
5978                    Err(e) => Ok(Value::Variant {
5979                        enum_name: "Result".to_string(),
5980                        variant_name: "Err".to_string(),
5981                        fields: Some(Rc::new(vec![Value::String(Rc::new(e.to_string()))])),
5982                    }),
5983                }
5984            } else {
5985                Err(RuntimeError::new("TcpStream not found in registry"))
5986            }
5987        } else {
5988            Err(RuntimeError::new("Failed to lock stream registry"))
5989        }
5990    });
5991
5992    // --- BufReader for HTTP parsing ---
5993
5994    // BufReader::new - create a buffered reader from a TcpStream
5995    define(interp, "BufReader·new", Some(1), |_, args| {
5996        use std::io::BufReader as StdBufReader;
5997
5998        // Handle both Map and Ref(Map) for &mut TcpStream
5999        let stream_id = match &args[0] {
6000            Value::Map(m) => {
6001                let borrowed = m.borrow();
6002                if let Some(Value::Int(id)) = borrowed.get("__stream_id__") {
6003                    *id as u64
6004                } else {
6005                    return Err(RuntimeError::new("BufReader::new requires TcpStream"));
6006                }
6007            }
6008            Value::Ref(r) => {
6009                // Handle &mut TcpStream - unwrap the Ref to get the Map
6010                let inner = r.borrow();
6011                if let Value::Map(m) = &*inner {
6012                    let borrowed = m.borrow();
6013                    if let Some(Value::Int(id)) = borrowed.get("__stream_id__") {
6014                        *id as u64
6015                    } else {
6016                        return Err(RuntimeError::new("BufReader::new requires TcpStream (missing stream_id in Ref)"));
6017                    }
6018                } else {
6019                    return Err(RuntimeError::new("BufReader::new requires TcpStream (Ref does not contain Map)"));
6020                }
6021            }
6022            _ => return Err(RuntimeError::new("BufReader::new requires TcpStream")),
6023        };
6024
6025        // Clone the stream and create a BufReader that persists
6026        let reader_id = if let Some(mut guard) = get_stream_registry().lock().ok() {
6027            if let Some(stream) = guard.get_mut(&stream_id) {
6028                let stream_clone = match stream.try_clone() {
6029                    Ok(s) => s,
6030                    Err(e) => return Err(RuntimeError::new(format!("Failed to clone stream: {}", e))),
6031                };
6032                let reader = StdBufReader::new(stream_clone);
6033                store_bufreader(reader)
6034            } else {
6035                return Err(RuntimeError::new("Stream not found in registry"));
6036            }
6037        } else {
6038            return Err(RuntimeError::new("Failed to lock stream registry"));
6039        };
6040
6041        let mut map = HashMap::new();
6042        map.insert("__type__".to_string(), Value::String(Rc::new("BufReader".to_string())));
6043        map.insert("__stream_id__".to_string(), Value::Int(stream_id as i64));
6044        map.insert("__reader_id__".to_string(), Value::Int(reader_id as i64));
6045        Ok(Value::Map(Rc::new(RefCell::new(map))))
6046    });
6047
6048    // BufReader::read_line - read a line from the buffered reader
6049    define(interp, "BufReader·read_line", Some(1), |_, args| {
6050        use std::io::BufRead;
6051
6052        let reader_id = match &args[0] {
6053            Value::Map(m) => {
6054                let borrowed = m.borrow();
6055                if let Some(Value::Int(id)) = borrowed.get("__reader_id__") {
6056                    *id as u64
6057                } else {
6058                    return Err(RuntimeError::new("BufReader missing __reader_id__"));
6059                }
6060            }
6061            _ => return Err(RuntimeError::new("read_line requires BufReader")),
6062        };
6063
6064        if let Some(mut guard) = get_bufreader_registry().lock().ok() {
6065            if let Some(reader) = guard.get_mut(&reader_id) {
6066                let mut line = String::new();
6067
6068                match reader.read_line(&mut line) {
6069                    Ok(n) => {
6070                        if n == 0 {
6071                            // EOF
6072                            Ok(Value::Variant {
6073                                enum_name: "Result".to_string(),
6074                                variant_name: "Ok".to_string(),
6075                                fields: Some(Rc::new(vec![Value::Null])),
6076                            })
6077                        } else {
6078                            Ok(Value::Variant {
6079                                enum_name: "Result".to_string(),
6080                                variant_name: "Ok".to_string(),
6081                                fields: Some(Rc::new(vec![Value::String(Rc::new(line))])),
6082                            })
6083                        }
6084                    }
6085                    Err(e) => Ok(Value::Variant {
6086                        enum_name: "Result".to_string(),
6087                        variant_name: "Err".to_string(),
6088                        fields: Some(Rc::new(vec![Value::String(Rc::new(e.to_string()))])),
6089                    }),
6090                }
6091            } else {
6092                Err(RuntimeError::new("BufReader not found in registry"))
6093            }
6094        } else {
6095            Err(RuntimeError::new("Failed to lock bufreader registry"))
6096        }
6097    });
6098
6099    // --- HTTP MIDDLEWARE STUBS ---
6100    // Stubs for Styx HTTP middleware until proper module path support is added
6101
6102    // Logger middleware
6103    define(interp, "styx_http·middleware·Logger·new", Some(0), |_, _| {
6104        let mut map = HashMap::new();
6105        map.insert("__type__".to_string(), Value::String(Rc::new("Logger".to_string())));
6106        map.insert("format".to_string(), Value::String(Rc::new("Common".to_string())));
6107        Ok(Value::Map(Rc::new(RefCell::new(map))))
6108    });
6109
6110    define(interp, "Logger·new", Some(0), |_, _| {
6111        let mut map = HashMap::new();
6112        map.insert("__type__".to_string(), Value::String(Rc::new("Logger".to_string())));
6113        map.insert("format".to_string(), Value::String(Rc::new("Common".to_string())));
6114        Ok(Value::Map(Rc::new(RefCell::new(map))))
6115    });
6116
6117    // CORS middleware
6118    define(interp, "styx_http·middleware·Cors·new", Some(0), |_, _| {
6119        let mut map = HashMap::new();
6120        map.insert("__type__".to_string(), Value::String(Rc::new("Cors".to_string())));
6121        map.insert("origins".to_string(), Value::Array(Rc::new(RefCell::new(vec![]))));
6122        Ok(Value::Map(Rc::new(RefCell::new(map))))
6123    });
6124
6125    define(interp, "Cors·new", Some(0), |_, _| {
6126        let mut map = HashMap::new();
6127        map.insert("__type__".to_string(), Value::String(Rc::new("Cors".to_string())));
6128        map.insert("origins".to_string(), Value::Array(Rc::new(RefCell::new(vec![]))));
6129        Ok(Value::Map(Rc::new(RefCell::new(map))))
6130    });
6131
6132    // Security headers middleware
6133    define(interp, "styx_http·middleware·SecurityHeaders·new", Some(0), |_, _| {
6134        let mut map = HashMap::new();
6135        map.insert("__type__".to_string(), Value::String(Rc::new("SecurityHeaders".to_string())));
6136        Ok(Value::Map(Rc::new(RefCell::new(map))))
6137    });
6138
6139    define(interp, "SecurityHeaders·new", Some(0), |_, _| {
6140        let mut map = HashMap::new();
6141        map.insert("__type__".to_string(), Value::String(Rc::new("SecurityHeaders".to_string())));
6142        Ok(Value::Map(Rc::new(RefCell::new(map))))
6143    });
6144
6145    // RateLimiter middleware
6146    define(interp, "styx_http·middleware·RateLimiter·new", Some(0), |_, _| {
6147        let mut map = HashMap::new();
6148        map.insert("__type__".to_string(), Value::String(Rc::new("RateLimiter".to_string())));
6149        Ok(Value::Map(Rc::new(RefCell::new(map))))
6150    });
6151
6152    define(interp, "RateLimiter·new", Some(0), |_, _| {
6153        let mut map = HashMap::new();
6154        map.insert("__type__".to_string(), Value::String(Rc::new("RateLimiter".to_string())));
6155        Ok(Value::Map(Rc::new(RefCell::new(map))))
6156    });
6157
6158    // RateLimit middleware (accepts rate and burst params)
6159    define(interp, "styx_http·middleware·RateLimit·new", None, |_, args| {
6160        let mut map = HashMap::new();
6161        map.insert("__type__".to_string(), Value::String(Rc::new("RateLimit".to_string())));
6162        if args.len() >= 2 {
6163            map.insert("rate".to_string(), args[0].clone());
6164            map.insert("burst".to_string(), args[1].clone());
6165        }
6166        Ok(Value::Map(Rc::new(RefCell::new(map))))
6167    });
6168
6169    define(interp, "RateLimit·new", None, |_, args| {
6170        let mut map = HashMap::new();
6171        map.insert("__type__".to_string(), Value::String(Rc::new("RateLimit".to_string())));
6172        if args.len() >= 2 {
6173            map.insert("rate".to_string(), args[0].clone());
6174            map.insert("burst".to_string(), args[1].clone());
6175        }
6176        Ok(Value::Map(Rc::new(RefCell::new(map))))
6177    });
6178
6179    // Compression middleware
6180    define(interp, "styx_http·middleware·Compression·new", Some(0), |_, _| {
6181        let mut map = HashMap::new();
6182        map.insert("__type__".to_string(), Value::String(Rc::new("Compression".to_string())));
6183        Ok(Value::Map(Rc::new(RefCell::new(map))))
6184    });
6185
6186    define(interp, "Compression·new", Some(0), |_, _| {
6187        let mut map = HashMap::new();
6188        map.insert("__type__".to_string(), Value::String(Rc::new("Compression".to_string())));
6189        Ok(Value::Map(Rc::new(RefCell::new(map))))
6190    });
6191
6192    // AuthMiddleware - authentication middleware with optional/required modes
6193    define(interp, "AuthMiddleware·optional", Some(0), |_, _| {
6194        let mut map = HashMap::new();
6195        map.insert("__type__".to_string(), Value::String(Rc::new("AuthMiddleware".to_string())));
6196        map.insert("mode".to_string(), Value::String(Rc::new("optional".to_string())));
6197        Ok(Value::Map(Rc::new(RefCell::new(map))))
6198    });
6199
6200    define(interp, "AuthMiddleware·required", Some(0), |_, _| {
6201        let mut map = HashMap::new();
6202        map.insert("__type__".to_string(), Value::String(Rc::new("AuthMiddleware".to_string())));
6203        map.insert("mode".to_string(), Value::String(Rc::new("required".to_string())));
6204        Ok(Value::Map(Rc::new(RefCell::new(map))))
6205    });
6206
6207    define(interp, "AuthMiddleware·new", Some(0), |_, _| {
6208        let mut map = HashMap::new();
6209        map.insert("__type__".to_string(), Value::String(Rc::new("AuthMiddleware".to_string())));
6210        map.insert("mode".to_string(), Value::String(Rc::new("required".to_string())));
6211        Ok(Value::Map(Rc::new(RefCell::new(map))))
6212    });
6213
6214    // --- ACTORS ---
6215    // Single-threaded actor model for the interpreter.
6216    // Messages are queued and processed synchronously.
6217    // For true async actors with background threads, use the JIT backend.
6218
6219    // spawn_actor - create a new actor with given name
6220    define(interp, "spawn_actor", Some(1), |_, args| {
6221        let name = match &args[0] {
6222            Value::String(s) => s.to_string(),
6223            _ => return Err(RuntimeError::new("actor_spawn() requires string name")),
6224        };
6225
6226        let inner = ActorInner {
6227            name,
6228            message_queue: Mutex::new(Vec::new()),
6229            message_count: std::sync::atomic::AtomicUsize::new(0),
6230        };
6231
6232        Ok(Value::Actor(Arc::new(inner)))
6233    });
6234
6235    // send_to_actor - send a message to an actor
6236    // Messages are queued for later processing
6237    define(interp, "send_to_actor", Some(3), |_, args| {
6238        let actor = match &args[0] {
6239            Value::Actor(a) => a.clone(),
6240            _ => {
6241                return Err(RuntimeError::new(
6242                    "actor_send() requires actor as first argument",
6243                ))
6244            }
6245        };
6246        let msg_type = match &args[1] {
6247            Value::String(s) => s.to_string(),
6248            _ => {
6249                return Err(RuntimeError::new(
6250                    "actor_send() requires string message type",
6251                ))
6252            }
6253        };
6254        let msg_data = format!("{}", args[2]);
6255
6256        let mut queue = actor
6257            .message_queue
6258            .lock()
6259            .map_err(|_| RuntimeError::new("actor queue poisoned"))?;
6260        queue.push((msg_type, msg_data));
6261        actor
6262            .message_count
6263            .fetch_add(1, std::sync::atomic::Ordering::SeqCst);
6264
6265        Ok(Value::Null)
6266    });
6267
6268    // tell_actor - alias for send_to_actor (Erlang/Akka style)
6269    define(interp, "tell_actor", Some(3), |_, args| {
6270        let actor = match &args[0] {
6271            Value::Actor(a) => a.clone(),
6272            _ => {
6273                return Err(RuntimeError::new(
6274                    "actor_tell() requires actor as first argument",
6275                ))
6276            }
6277        };
6278        let msg_type = match &args[1] {
6279            Value::String(s) => s.to_string(),
6280            _ => {
6281                return Err(RuntimeError::new(
6282                    "actor_tell() requires string message type",
6283                ))
6284            }
6285        };
6286        let msg_data = format!("{}", args[2]);
6287
6288        let mut queue = actor
6289            .message_queue
6290            .lock()
6291            .map_err(|_| RuntimeError::new("actor queue poisoned"))?;
6292        queue.push((msg_type, msg_data));
6293        actor
6294            .message_count
6295            .fetch_add(1, std::sync::atomic::Ordering::SeqCst);
6296
6297        Ok(Value::Null)
6298    });
6299
6300    // recv_from_actor - receive (pop) a message from the actor's queue
6301    // Returns Option<(type, data)>
6302    define(interp, "recv_from_actor", Some(1), |_, args| {
6303        let actor = match &args[0] {
6304            Value::Actor(a) => a.clone(),
6305            _ => return Err(RuntimeError::new("actor_recv() requires actor argument")),
6306        };
6307
6308        let mut queue = actor
6309            .message_queue
6310            .lock()
6311            .map_err(|_| RuntimeError::new("actor queue poisoned"))?;
6312        match queue.pop() {
6313            Some((msg_type, msg_data)) => {
6314                // Return Some((type, data))
6315                Ok(Value::Variant {
6316                    enum_name: "Option".to_string(),
6317                    variant_name: "Some".to_string(),
6318                    fields: Some(Rc::new(vec![Value::Tuple(Rc::new(vec![
6319                        Value::String(Rc::new(msg_type)),
6320                        Value::String(Rc::new(msg_data)),
6321                    ]))])),
6322                })
6323            }
6324            None => Ok(Value::Variant {
6325                enum_name: "Option".to_string(),
6326                variant_name: "None".to_string(),
6327                fields: None,
6328            }),
6329        }
6330    });
6331
6332    // get_actor_msg_count - get total messages ever sent to actor
6333    define(interp, "get_actor_msg_count", Some(1), |_, args| {
6334        let a = match &args[0] {
6335            Value::Actor(a) => a.clone(),
6336            _ => {
6337                return Err(RuntimeError::new(
6338                    "get_actor_msg_count() requires actor argument",
6339                ))
6340            }
6341        };
6342
6343        let count = a.message_count.load(std::sync::atomic::Ordering::SeqCst);
6344        Ok(Value::Int(count as i64))
6345    });
6346
6347    // get_actor_name - get actor's name
6348    define(interp, "get_actor_name", Some(1), |_, args| {
6349        let a = match &args[0] {
6350            Value::Actor(a) => a.clone(),
6351            _ => {
6352                return Err(RuntimeError::new(
6353                    "get_actor_name() requires actor argument",
6354                ))
6355            }
6356        };
6357
6358        Ok(Value::String(Rc::new(a.name.clone())))
6359    });
6360
6361    // get_actor_pending - get number of pending messages
6362    define(interp, "get_actor_pending", Some(1), |_, args| {
6363        let a = match &args[0] {
6364            Value::Actor(a) => a.clone(),
6365            _ => {
6366                return Err(RuntimeError::new(
6367                    "get_actor_pending() requires actor argument",
6368                ))
6369            }
6370        };
6371
6372        let queue = a
6373            .message_queue
6374            .lock()
6375            .map_err(|_| RuntimeError::new("actor queue poisoned"))?;
6376        Ok(Value::Int(queue.len() as i64))
6377    });
6378
6379    // --- SYNCHRONIZATION PRIMITIVES ---
6380
6381    // mutex_new - create a new mutex wrapping a value
6382    define(interp, "mutex_new", Some(1), |_, args| {
6383        let value = args[0].clone();
6384        // Store as a Map with special key for mutex semantics
6385        let mut map = std::collections::HashMap::new();
6386        map.insert("__mutex_value".to_string(), value);
6387        map.insert("__mutex_locked".to_string(), Value::Bool(false));
6388        Ok(Value::Map(Rc::new(RefCell::new(map))))
6389    });
6390
6391    // mutex_lock - lock a mutex and get the value
6392    define(interp, "mutex_lock", Some(1), |_, args| {
6393        let mutex = match &args[0] {
6394            Value::Map(m) => m.clone(),
6395            _ => return Err(RuntimeError::new("mutex_lock() requires mutex")),
6396        };
6397
6398        let mut map = mutex.borrow_mut();
6399        // Simple spin-wait for interpreter (not true mutex, but demonstrates concept)
6400        map.insert("__mutex_locked".to_string(), Value::Bool(true));
6401
6402        match map.get("__mutex_value") {
6403            Some(v) => Ok(v.clone()),
6404            None => Err(RuntimeError::new("invalid mutex")),
6405        }
6406    });
6407
6408    // mutex_unlock - unlock a mutex, optionally setting new value
6409    define(interp, "mutex_unlock", Some(2), |_, args| {
6410        let mutex = match &args[0] {
6411            Value::Map(m) => m.clone(),
6412            _ => return Err(RuntimeError::new("mutex_unlock() requires mutex")),
6413        };
6414        let new_value = args[1].clone();
6415
6416        let mut map = mutex.borrow_mut();
6417        map.insert("__mutex_value".to_string(), new_value);
6418        map.insert("__mutex_locked".to_string(), Value::Bool(false));
6419
6420        Ok(Value::Null)
6421    });
6422
6423    // atomic_new - create an atomic integer
6424    define(interp, "atomic_new", Some(1), |_, args| {
6425        let value = match &args[0] {
6426            Value::Int(i) => *i,
6427            _ => return Err(RuntimeError::new("atomic_new() requires integer")),
6428        };
6429
6430        // Wrap in Map with atomic semantics
6431        let mut map = std::collections::HashMap::new();
6432        map.insert("__atomic_value".to_string(), Value::Int(value));
6433        Ok(Value::Map(Rc::new(RefCell::new(map))))
6434    });
6435
6436    // atomic_load - atomically load value
6437    define(interp, "atomic_load", Some(1), |_, args| {
6438        let atomic = match &args[0] {
6439            Value::Map(m) => m.clone(),
6440            _ => return Err(RuntimeError::new("atomic_load() requires atomic")),
6441        };
6442
6443        let map = atomic.borrow();
6444        match map.get("__atomic_value") {
6445            Some(v) => Ok(v.clone()),
6446            None => Err(RuntimeError::new("invalid atomic")),
6447        }
6448    });
6449
6450    // atomic_store - atomically store value
6451    define(interp, "atomic_store", Some(2), |_, args| {
6452        let atomic = match &args[0] {
6453            Value::Map(m) => m.clone(),
6454            _ => return Err(RuntimeError::new("atomic_store() requires atomic")),
6455        };
6456        let value = match &args[1] {
6457            Value::Int(i) => *i,
6458            _ => return Err(RuntimeError::new("atomic_store() requires integer value")),
6459        };
6460
6461        let mut map = atomic.borrow_mut();
6462        map.insert("__atomic_value".to_string(), Value::Int(value));
6463        Ok(Value::Null)
6464    });
6465
6466    // atomic_add - atomically add and return old value
6467    define(interp, "atomic_add", Some(2), |_, args| {
6468        let atomic = match &args[0] {
6469            Value::Map(m) => m.clone(),
6470            _ => return Err(RuntimeError::new("atomic_add() requires atomic")),
6471        };
6472        let delta = match &args[1] {
6473            Value::Int(i) => *i,
6474            _ => return Err(RuntimeError::new("atomic_add() requires integer delta")),
6475        };
6476
6477        let mut map = atomic.borrow_mut();
6478        let old = match map.get("__atomic_value") {
6479            Some(Value::Int(i)) => *i,
6480            _ => return Err(RuntimeError::new("invalid atomic")),
6481        };
6482        map.insert("__atomic_value".to_string(), Value::Int(old + delta));
6483        Ok(Value::Int(old))
6484    });
6485
6486    // atomic_cas - compare and swap, returns bool success
6487    define(interp, "atomic_cas", Some(3), |_, args| {
6488        let atomic = match &args[0] {
6489            Value::Map(m) => m.clone(),
6490            _ => return Err(RuntimeError::new("atomic_cas() requires atomic")),
6491        };
6492        let expected = match &args[1] {
6493            Value::Int(i) => *i,
6494            _ => return Err(RuntimeError::new("atomic_cas() requires integer expected")),
6495        };
6496        let new_value = match &args[2] {
6497            Value::Int(i) => *i,
6498            _ => return Err(RuntimeError::new("atomic_cas() requires integer new value")),
6499        };
6500
6501        let mut map = atomic.borrow_mut();
6502        let current = match map.get("__atomic_value") {
6503            Some(Value::Int(i)) => *i,
6504            _ => return Err(RuntimeError::new("invalid atomic")),
6505        };
6506
6507        if current == expected {
6508            map.insert("__atomic_value".to_string(), Value::Int(new_value));
6509            Ok(Value::Bool(true))
6510        } else {
6511            Ok(Value::Bool(false))
6512        }
6513    });
6514
6515    // --- PARALLEL ITERATION ---
6516
6517    // parallel_map - map function over array in parallel (simplified)
6518    define(interp, "parallel_map", Some(2), |_, args| {
6519        let arr = match &args[0] {
6520            Value::Array(a) => a.borrow().clone(),
6521            _ => return Err(RuntimeError::new("parallel_map() requires array")),
6522        };
6523        let _func = args[1].clone();
6524
6525        // For interpreter, just return original array
6526        // Real parallelism needs thread-safe interpreter
6527        Ok(Value::Array(Rc::new(RefCell::new(arr))))
6528    });
6529
6530    // parallel_for - parallel for loop (simplified)
6531    define(interp, "parallel_for", Some(3), |_, args| {
6532        let start = match &args[0] {
6533            Value::Int(i) => *i,
6534            _ => return Err(RuntimeError::new("parallel_for() requires integer start")),
6535        };
6536        let end = match &args[1] {
6537            Value::Int(i) => *i,
6538            _ => return Err(RuntimeError::new("parallel_for() requires integer end")),
6539        };
6540        let _func = args[2].clone();
6541
6542        // For interpreter, execute sequentially
6543        // Returns range as array
6544        let range: Vec<Value> = (start..end).map(|i| Value::Int(i)).collect();
6545        Ok(Value::Array(Rc::new(RefCell::new(range))))
6546    });
6547
6548    // ============================================================================
6549    // ASYNC/AWAIT FUNCTIONS
6550    // ============================================================================
6551    // WARNING: Interpreter Blocking Behavior
6552    // --------------------------------------
6553    // In the interpreter, async operations use cooperative scheduling but
6554    // execute on the main thread. This means:
6555    // - async_sleep() blocks the interpreter for the specified duration
6556    // - await() polls futures but may block waiting for completion
6557    // - No true concurrent I/O - operations execute sequentially
6558    // - Future combinators (race, all) work but don't provide parallelism
6559    //
6560    // The async model is designed for composability and clean code structure.
6561    // For non-blocking async with true concurrency, use the JIT backend.
6562    // ============================================================================
6563
6564    // async_sleep - create a future that completes after specified milliseconds
6565    define(interp, "async_sleep", Some(1), |interp, args| {
6566        let ms = match &args[0] {
6567            Value::Int(ms) => *ms as u64,
6568            Value::Float(ms) => *ms as u64,
6569            _ => {
6570                return Err(RuntimeError::new(
6571                    "async_sleep() requires integer milliseconds",
6572                ))
6573            }
6574        };
6575
6576        Ok(interp.make_future_timer(std::time::Duration::from_millis(ms)))
6577    });
6578
6579    // future_ready - create an immediately resolved future
6580    define(interp, "future_ready", Some(1), |interp, args| {
6581        Ok(interp.make_future_immediate(args[0].clone()))
6582    });
6583
6584    // future_pending - create a pending future (never resolves)
6585    define(interp, "future_pending", Some(0), |_, _| {
6586        Ok(Value::Future(Rc::new(RefCell::new(
6587            crate::interpreter::FutureInner {
6588                state: crate::interpreter::FutureState::Pending,
6589                computation: None,
6590                complete_at: None,
6591            },
6592        ))))
6593    });
6594
6595    // is_future - check if a value is a future
6596    define(interp, "is_future", Some(1), |_, args| {
6597        Ok(Value::Bool(matches!(&args[0], Value::Future(_))))
6598    });
6599
6600    // is_ready - check if a future is ready
6601    define(interp, "is_ready", Some(1), |_, args| {
6602        match &args[0] {
6603            Value::Future(fut) => {
6604                let f = fut.borrow();
6605                Ok(Value::Bool(matches!(
6606                    f.state,
6607                    crate::interpreter::FutureState::Ready(_)
6608                )))
6609            }
6610            _ => Ok(Value::Bool(true)), // Non-futures are always "ready"
6611        }
6612    });
6613
6614    // join_futures - join multiple futures into one that resolves to array
6615    define(interp, "join_futures", Some(1), |_, args| {
6616        let futures = match &args[0] {
6617            Value::Array(arr) => {
6618                let arr = arr.borrow();
6619                let mut futs = Vec::new();
6620                for v in arr.iter() {
6621                    match v {
6622                        Value::Future(f) => futs.push(f.clone()),
6623                        _ => {
6624                            return Err(RuntimeError::new(
6625                                "join_futures() requires array of futures",
6626                            ))
6627                        }
6628                    }
6629                }
6630                futs
6631            }
6632            _ => {
6633                return Err(RuntimeError::new(
6634                    "join_futures() requires array of futures",
6635                ))
6636            }
6637        };
6638
6639        Ok(Value::Future(Rc::new(RefCell::new(
6640            crate::interpreter::FutureInner {
6641                state: crate::interpreter::FutureState::Pending,
6642                computation: Some(crate::interpreter::FutureComputation::Join(futures)),
6643                complete_at: None,
6644            },
6645        ))))
6646    });
6647
6648    // race_futures - return first future to complete
6649    define(interp, "race_futures", Some(1), |_, args| {
6650        let futures = match &args[0] {
6651            Value::Array(arr) => {
6652                let arr = arr.borrow();
6653                let mut futs = Vec::new();
6654                for v in arr.iter() {
6655                    match v {
6656                        Value::Future(f) => futs.push(f.clone()),
6657                        _ => {
6658                            return Err(RuntimeError::new(
6659                                "race_futures() requires array of futures",
6660                            ))
6661                        }
6662                    }
6663                }
6664                futs
6665            }
6666            _ => {
6667                return Err(RuntimeError::new(
6668                    "race_futures() requires array of futures",
6669                ))
6670            }
6671        };
6672
6673        Ok(Value::Future(Rc::new(RefCell::new(
6674            crate::interpreter::FutureInner {
6675                state: crate::interpreter::FutureState::Pending,
6676                computation: Some(crate::interpreter::FutureComputation::Race(futures)),
6677                complete_at: None,
6678            },
6679        ))))
6680    });
6681
6682    // poll_future - try to resolve a future without blocking (returns Option)
6683    define(interp, "poll_future", Some(1), |_, args| {
6684        match &args[0] {
6685            Value::Future(fut) => {
6686                let f = fut.borrow();
6687                match &f.state {
6688                    crate::interpreter::FutureState::Ready(v) => Ok(Value::Variant {
6689                        enum_name: "Option".to_string(),
6690                        variant_name: "Some".to_string(),
6691                        fields: Some(Rc::new(vec![(**v).clone()])),
6692                    }),
6693                    _ => Ok(Value::Variant {
6694                        enum_name: "Option".to_string(),
6695                        variant_name: "None".to_string(),
6696                        fields: None,
6697                    }),
6698                }
6699            }
6700            // Non-futures return Some(value)
6701            other => Ok(Value::Variant {
6702                enum_name: "Option".to_string(),
6703                variant_name: "Some".to_string(),
6704                fields: Some(Rc::new(vec![other.clone()])),
6705            }),
6706        }
6707    });
6708}
6709
6710// ============================================================================
6711// JSON FUNCTIONS
6712// ============================================================================
6713
6714fn register_json(interp: &mut Interpreter) {
6715    // json_parse - parse JSON string into Sigil value
6716    define(interp, "json_parse", Some(1), |_, args| {
6717        let json_str = match &args[0] {
6718            Value::String(s) => s.as_str(),
6719            _ => return Err(RuntimeError::new("json_parse() requires string argument")),
6720        };
6721
6722        fn json_to_value(json: &serde_json::Value) -> Value {
6723            match json {
6724                serde_json::Value::Null => Value::Null,
6725                serde_json::Value::Bool(b) => Value::Bool(*b),
6726                serde_json::Value::Number(n) => {
6727                    if let Some(i) = n.as_i64() {
6728                        Value::Int(i)
6729                    } else if let Some(f) = n.as_f64() {
6730                        Value::Float(f)
6731                    } else {
6732                        Value::Null
6733                    }
6734                }
6735                serde_json::Value::String(s) => Value::String(Rc::new(s.clone())),
6736                serde_json::Value::Array(arr) => {
6737                    let values: Vec<Value> = arr.iter().map(json_to_value).collect();
6738                    Value::Array(Rc::new(RefCell::new(values)))
6739                }
6740                serde_json::Value::Object(obj) => {
6741                    let mut map = HashMap::new();
6742                    for (k, v) in obj {
6743                        map.insert(k.clone(), json_to_value(v));
6744                    }
6745                    Value::Map(Rc::new(RefCell::new(map)))
6746                }
6747            }
6748        }
6749
6750        match serde_json::from_str(json_str) {
6751            Ok(json) => Ok(json_to_value(&json)),
6752            Err(e) => Err(RuntimeError::new(format!("JSON parse error: {}", e))),
6753        }
6754    });
6755
6756    // json_stringify - convert Sigil value to JSON string
6757    define(interp, "json_stringify", Some(1), |_, args| {
6758        fn value_to_json(val: &Value) -> serde_json::Value {
6759            match val {
6760                Value::Null => serde_json::Value::Null,
6761                Value::Bool(b) => serde_json::Value::Bool(*b),
6762                Value::Int(n) => serde_json::Value::Number(serde_json::Number::from(*n)),
6763                Value::Float(f) => serde_json::Number::from_f64(*f)
6764                    .map(serde_json::Value::Number)
6765                    .unwrap_or(serde_json::Value::Null),
6766                Value::String(s) => serde_json::Value::String(s.to_string()),
6767                Value::Array(arr) => {
6768                    let arr = arr.borrow();
6769                    serde_json::Value::Array(arr.iter().map(value_to_json).collect())
6770                }
6771                Value::Tuple(t) => serde_json::Value::Array(t.iter().map(value_to_json).collect()),
6772                Value::Map(map) => {
6773                    let map = map.borrow();
6774                    let obj: serde_json::Map<String, serde_json::Value> = map
6775                        .iter()
6776                        .map(|(k, v)| (k.clone(), value_to_json(v)))
6777                        .collect();
6778                    serde_json::Value::Object(obj)
6779                }
6780                Value::Struct { fields, .. } => {
6781                    let fields = fields.borrow();
6782                    let obj: serde_json::Map<String, serde_json::Value> = fields
6783                        .iter()
6784                        .map(|(k, v)| (k.clone(), value_to_json(v)))
6785                        .collect();
6786                    serde_json::Value::Object(obj)
6787                }
6788                _ => serde_json::Value::String(format!("{}", val)),
6789            }
6790        }
6791
6792        let json = value_to_json(&args[0]);
6793        Ok(Value::String(Rc::new(json.to_string())))
6794    });
6795
6796    // json_pretty - convert to pretty-printed JSON
6797    define(interp, "json_pretty", Some(1), |_, args| {
6798        fn value_to_json(val: &Value) -> serde_json::Value {
6799            match val {
6800                Value::Null => serde_json::Value::Null,
6801                Value::Bool(b) => serde_json::Value::Bool(*b),
6802                Value::Int(n) => serde_json::Value::Number(serde_json::Number::from(*n)),
6803                Value::Float(f) => serde_json::Number::from_f64(*f)
6804                    .map(serde_json::Value::Number)
6805                    .unwrap_or(serde_json::Value::Null),
6806                Value::String(s) => serde_json::Value::String(s.to_string()),
6807                Value::Array(arr) => {
6808                    let arr = arr.borrow();
6809                    serde_json::Value::Array(arr.iter().map(value_to_json).collect())
6810                }
6811                Value::Map(map) => {
6812                    let map = map.borrow();
6813                    let obj: serde_json::Map<String, serde_json::Value> = map
6814                        .iter()
6815                        .map(|(k, v)| (k.clone(), value_to_json(v)))
6816                        .collect();
6817                    serde_json::Value::Object(obj)
6818                }
6819                _ => serde_json::Value::String(format!("{}", val)),
6820            }
6821        }
6822
6823        let json = value_to_json(&args[0]);
6824        match serde_json::to_string_pretty(&json) {
6825            Ok(s) => Ok(Value::String(Rc::new(s))),
6826            Err(e) => Err(RuntimeError::new(format!("JSON stringify error: {}", e))),
6827        }
6828    });
6829
6830    // json_get - get value at JSON path (dot notation)
6831    define(interp, "json_get", Some(2), |_, args| {
6832        let path = match &args[1] {
6833            Value::String(s) => s.to_string(),
6834            _ => return Err(RuntimeError::new("json_get() requires string path")),
6835        };
6836
6837        let mut current = args[0].clone();
6838        for key in path.split('.') {
6839            current = match &current {
6840                Value::Map(map) => {
6841                    let map = map.borrow();
6842                    map.get(key).cloned().unwrap_or(Value::Null)
6843                }
6844                Value::Array(arr) => {
6845                    if let Ok(idx) = key.parse::<usize>() {
6846                        let arr = arr.borrow();
6847                        arr.get(idx).cloned().unwrap_or(Value::Null)
6848                    } else {
6849                        Value::Null
6850                    }
6851                }
6852                _ => Value::Null,
6853            };
6854        }
6855        Ok(current)
6856    });
6857
6858    // json_set - set value at JSON path
6859    define(interp, "json_set", Some(3), |_, args| {
6860        let path = match &args[1] {
6861            Value::String(s) => s.to_string(),
6862            _ => return Err(RuntimeError::new("json_set() requires string path")),
6863        };
6864        let new_value = args[2].clone();
6865
6866        // For simplicity, only handle single-level paths
6867        match &args[0] {
6868            Value::Map(map) => {
6869                let mut map = map.borrow_mut();
6870                map.insert(path, new_value);
6871                Ok(Value::Map(Rc::new(RefCell::new(map.clone()))))
6872            }
6873            _ => Err(RuntimeError::new("json_set() requires map/object")),
6874        }
6875    });
6876}
6877
6878// ============================================================================
6879// FILE SYSTEM FUNCTIONS
6880// ============================================================================
6881
6882fn register_fs(interp: &mut Interpreter) {
6883    // fs_read - read entire file as string
6884    define(interp, "fs_read", Some(1), |_, args| {
6885        let path = match &args[0] {
6886            Value::String(s) => s.to_string(),
6887            _ => return Err(RuntimeError::new("fs_read() requires string path")),
6888        };
6889
6890        match std::fs::read_to_string(&path) {
6891            Ok(content) => Ok(Value::String(Rc::new(content))),
6892            Err(e) => Err(RuntimeError::new(format!("fs_read() error: {}", e))),
6893        }
6894    });
6895
6896    // fs_read_bytes - read file as byte array
6897    define(interp, "fs_read_bytes", Some(1), |_, args| {
6898        let path = match &args[0] {
6899            Value::String(s) => s.to_string(),
6900            _ => return Err(RuntimeError::new("fs_read_bytes() requires string path")),
6901        };
6902
6903        match std::fs::read(&path) {
6904            Ok(bytes) => {
6905                let values: Vec<Value> = bytes.iter().map(|b| Value::Int(*b as i64)).collect();
6906                Ok(Value::Array(Rc::new(RefCell::new(values))))
6907            }
6908            Err(e) => Err(RuntimeError::new(format!("fs_read_bytes() error: {}", e))),
6909        }
6910    });
6911
6912    // fs_write - write string to file
6913    define(interp, "fs_write", Some(2), |_, args| {
6914        let path = match &args[0] {
6915            Value::String(s) => s.to_string(),
6916            _ => return Err(RuntimeError::new("fs_write() requires string path")),
6917        };
6918        let content = format!("{}", args[1]);
6919
6920        match std::fs::write(&path, content) {
6921            Ok(()) => Ok(Value::Null),
6922            Err(e) => Err(RuntimeError::new(format!("fs_write() error: {}", e))),
6923        }
6924    });
6925
6926    // fs_append - append to file
6927    define(interp, "fs_append", Some(2), |_, args| {
6928        let path = match &args[0] {
6929            Value::String(s) => s.to_string(),
6930            _ => return Err(RuntimeError::new("fs_append() requires string path")),
6931        };
6932        let content = format!("{}", args[1]);
6933
6934        use std::fs::OpenOptions;
6935        match OpenOptions::new().append(true).create(true).open(&path) {
6936            Ok(mut file) => {
6937                use std::io::Write;
6938                match file.write_all(content.as_bytes()) {
6939                    Ok(()) => Ok(Value::Null),
6940                    Err(e) => Err(RuntimeError::new(format!("fs_append() write error: {}", e))),
6941                }
6942            }
6943            Err(e) => Err(RuntimeError::new(format!("fs_append() error: {}", e))),
6944        }
6945    });
6946
6947    // fs_exists - check if path exists
6948    define(interp, "fs_exists", Some(1), |_, args| {
6949        let path = match &args[0] {
6950            Value::String(s) => s.to_string(),
6951            _ => return Err(RuntimeError::new("fs_exists() requires string path")),
6952        };
6953        Ok(Value::Bool(std::path::Path::new(&path).exists()))
6954    });
6955
6956    // fs_is_file - check if path is a file
6957    define(interp, "fs_is_file", Some(1), |_, args| {
6958        let path = match &args[0] {
6959            Value::String(s) => s.to_string(),
6960            _ => return Err(RuntimeError::new("fs_is_file() requires string path")),
6961        };
6962        Ok(Value::Bool(std::path::Path::new(&path).is_file()))
6963    });
6964
6965    // fs_is_dir - check if path is a directory
6966    define(interp, "fs_is_dir", Some(1), |_, args| {
6967        let path = match &args[0] {
6968            Value::String(s) => s.to_string(),
6969            _ => return Err(RuntimeError::new("fs_is_dir() requires string path")),
6970        };
6971        Ok(Value::Bool(std::path::Path::new(&path).is_dir()))
6972    });
6973
6974    // fs_mkdir - create directory
6975    define(interp, "fs_mkdir", Some(1), |_, args| {
6976        let path = match &args[0] {
6977            Value::String(s) => s.to_string(),
6978            _ => return Err(RuntimeError::new("fs_mkdir() requires string path")),
6979        };
6980
6981        match std::fs::create_dir_all(&path) {
6982            Ok(()) => Ok(Value::Null),
6983            Err(e) => Err(RuntimeError::new(format!("fs_mkdir() error: {}", e))),
6984        }
6985    });
6986
6987    // fs_remove - remove file or directory
6988    define(interp, "fs_remove", Some(1), |_, args| {
6989        let path = match &args[0] {
6990            Value::String(s) => s.to_string(),
6991            _ => return Err(RuntimeError::new("fs_remove() requires string path")),
6992        };
6993
6994        let p = std::path::Path::new(&path);
6995        let result = if p.is_dir() {
6996            std::fs::remove_dir_all(&path)
6997        } else {
6998            std::fs::remove_file(&path)
6999        };
7000
7001        match result {
7002            Ok(()) => Ok(Value::Null),
7003            Err(e) => Err(RuntimeError::new(format!("fs_remove() error: {}", e))),
7004        }
7005    });
7006
7007    // fs_list - list directory contents
7008    define(interp, "fs_list", Some(1), |_, args| {
7009        let path = match &args[0] {
7010            Value::String(s) => s.to_string(),
7011            _ => return Err(RuntimeError::new("fs_list() requires string path")),
7012        };
7013
7014        match std::fs::read_dir(&path) {
7015            Ok(entries) => {
7016                let mut files = Vec::new();
7017                for entry in entries.flatten() {
7018                    if let Some(name) = entry.file_name().to_str() {
7019                        files.push(Value::String(Rc::new(name.to_string())));
7020                    }
7021                }
7022                Ok(Value::Array(Rc::new(RefCell::new(files))))
7023            }
7024            Err(e) => Err(RuntimeError::new(format!("fs_list() error: {}", e))),
7025        }
7026    });
7027
7028    // fs_copy - copy file
7029    define(interp, "fs_copy", Some(2), |_, args| {
7030        let src = match &args[0] {
7031            Value::String(s) => s.to_string(),
7032            _ => return Err(RuntimeError::new("fs_copy() requires string source path")),
7033        };
7034        let dst = match &args[1] {
7035            Value::String(s) => s.to_string(),
7036            _ => {
7037                return Err(RuntimeError::new(
7038                    "fs_copy() requires string destination path",
7039                ))
7040            }
7041        };
7042
7043        match std::fs::copy(&src, &dst) {
7044            Ok(bytes) => Ok(Value::Int(bytes as i64)),
7045            Err(e) => Err(RuntimeError::new(format!("fs_copy() error: {}", e))),
7046        }
7047    });
7048
7049    // fs_rename - rename/move file
7050    define(interp, "fs_rename", Some(2), |_, args| {
7051        let src = match &args[0] {
7052            Value::String(s) => s.to_string(),
7053            _ => return Err(RuntimeError::new("fs_rename() requires string source path")),
7054        };
7055        let dst = match &args[1] {
7056            Value::String(s) => s.to_string(),
7057            _ => {
7058                return Err(RuntimeError::new(
7059                    "fs_rename() requires string destination path",
7060                ))
7061            }
7062        };
7063
7064        match std::fs::rename(&src, &dst) {
7065            Ok(()) => Ok(Value::Null),
7066            Err(e) => Err(RuntimeError::new(format!("fs_rename() error: {}", e))),
7067        }
7068    });
7069
7070    // fs_size - get file size in bytes
7071    define(interp, "fs_size", Some(1), |_, args| {
7072        let path = match &args[0] {
7073            Value::String(s) => s.to_string(),
7074            _ => return Err(RuntimeError::new("fs_size() requires string path")),
7075        };
7076
7077        match std::fs::metadata(&path) {
7078            Ok(meta) => Ok(Value::Int(meta.len() as i64)),
7079            Err(e) => Err(RuntimeError::new(format!("fs_size() error: {}", e))),
7080        }
7081    });
7082
7083    // path_join - join path components
7084    define(interp, "path_join", None, |_, args| {
7085        let mut path = std::path::PathBuf::new();
7086        for arg in &args {
7087            match arg {
7088                Value::String(s) => path.push(s.as_str()),
7089                Value::Array(arr) => {
7090                    for v in arr.borrow().iter() {
7091                        if let Value::String(s) = v {
7092                            path.push(s.as_str());
7093                        }
7094                    }
7095                }
7096                _ => {}
7097            }
7098        }
7099        Ok(Value::String(Rc::new(path.to_string_lossy().to_string())))
7100    });
7101
7102    // path_parent - get parent directory
7103    define(interp, "path_parent", Some(1), |_, args| {
7104        let path = match &args[0] {
7105            Value::String(s) => s.to_string(),
7106            _ => return Err(RuntimeError::new("path_parent() requires string path")),
7107        };
7108
7109        let p = std::path::Path::new(&path);
7110        match p.parent() {
7111            Some(parent) => Ok(Value::String(Rc::new(parent.to_string_lossy().to_string()))),
7112            None => Ok(Value::Null),
7113        }
7114    });
7115
7116    // path_filename - get filename component
7117    define(interp, "path_filename", Some(1), |_, args| {
7118        let path = match &args[0] {
7119            Value::String(s) => s.to_string(),
7120            _ => return Err(RuntimeError::new("path_filename() requires string path")),
7121        };
7122
7123        let p = std::path::Path::new(&path);
7124        match p.file_name() {
7125            Some(name) => Ok(Value::String(Rc::new(name.to_string_lossy().to_string()))),
7126            None => Ok(Value::Null),
7127        }
7128    });
7129
7130    // path_extension - get file extension
7131    define(interp, "path_extension", Some(1), |_, args| {
7132        let path = match &args[0] {
7133            Value::String(s) => s.to_string(),
7134            _ => return Err(RuntimeError::new("path_extension() requires string path")),
7135        };
7136
7137        let p = std::path::Path::new(&path);
7138        match p.extension() {
7139            Some(ext) => Ok(Value::String(Rc::new(ext.to_string_lossy().to_string()))),
7140            None => Ok(Value::Null),
7141        }
7142    });
7143
7144    // ============================================================================
7145    // FFI-style functions for self-hosted compiler compatibility
7146    // These provide the low-level file I/O that the self-hosted compiler expects
7147    // ============================================================================
7148
7149    // Store last read file content for sigil_file_len()
7150    use std::cell::RefCell;
7151    use std::collections::HashMap;
7152    thread_local! {
7153        static LAST_FILE_CONTENT: RefCell<String> = RefCell::new(String::new());
7154        // Fake pointer map: stores strings that can be looked up by pointer ID
7155        static FAKE_PTR_MAP: RefCell<HashMap<i64, String>> = RefCell::new(HashMap::new());
7156    }
7157
7158    // sigil_read_file - read file content (FFI-compatible interface)
7159    // Takes path pointer and length, returns pointer to content
7160    // In interpreter, we fake the pointer API and just read the file
7161    define(interp, "sigil_read_file", Some(2), |_, args| {
7162        // Look up the path from either a string or a fake pointer ID
7163        let path = match &args[0] {
7164            Value::String(s) => s.to_string(),
7165            Value::Int(ptr_id) => {
7166                // Look up the string from the fake pointer map
7167                FAKE_PTR_MAP.with(|map| {
7168                    map.borrow().get(ptr_id).cloned()
7169                }).ok_or_else(|| RuntimeError::new(format!(
7170                    "sigil_read_file: invalid pointer {}", ptr_id
7171                )))?
7172            }
7173            _ => return Err(RuntimeError::new("sigil_read_file() requires string path")),
7174        };
7175
7176        match std::fs::read_to_string(&path) {
7177            Ok(content) => {
7178                // Store content for sigil_file_len
7179                LAST_FILE_CONTENT.with(|last| {
7180                    *last.borrow_mut() = content.clone();
7181                });
7182                // Return the content as a string (not a pointer in interpreted mode)
7183                Ok(Value::String(Rc::new(content)))
7184            }
7185            Err(_) => Ok(Value::Null), // Return null for error (like a null pointer)
7186        }
7187    });
7188
7189    // sigil_file_len - get length of last read file
7190    define(interp, "sigil_file_len", Some(0), |_, _| {
7191        LAST_FILE_CONTENT.with(|last| {
7192            Ok(Value::Int(last.borrow().len() as i64))
7193        })
7194    });
7195
7196    // sigil_write_file - write content to file
7197    define(interp, "sigil_write_file", Some(4), |_, args| {
7198        // In interpreted mode, we receive the actual strings, not pointers
7199        let path = match &args[0] {
7200            Value::String(s) => s.to_string(),
7201            _ => return Err(RuntimeError::new("sigil_write_file() requires string path")),
7202        };
7203        let content = match &args[2] {
7204            Value::String(s) => s.to_string(),
7205            _ => return Err(RuntimeError::new("sigil_write_file() requires string content")),
7206        };
7207
7208        match std::fs::write(&path, content) {
7209            Ok(()) => Ok(Value::Bool(true)),
7210            Err(_) => Ok(Value::Bool(false)),
7211        }
7212    });
7213
7214    // write - POSIX write() syscall for stdout/stderr
7215    define(interp, "write", Some(3), |_, args| {
7216        let fd = match &args[0] {
7217            Value::Int(n) => *n,
7218            _ => return Err(RuntimeError::new("write() requires int fd")),
7219        };
7220
7221        // Get the content - could be a string, a fake pointer ID, or something else
7222        let content = match &args[1] {
7223            Value::String(s) => s.to_string(),
7224            Value::Int(ptr_id) => {
7225                // Look up the string from the fake pointer map
7226                FAKE_PTR_MAP.with(|map| {
7227                    map.borrow().get(ptr_id).cloned()
7228                }).unwrap_or_else(|| format!("{}", ptr_id))
7229            }
7230            _ => format!("{}", args[1]),
7231        };
7232
7233        // args[2] is the length - we use the actual string length in interpreted mode
7234        let len = match &args[2] {
7235            Value::Int(n) => *n as usize,
7236            _ => content.len(),
7237        };
7238
7239        let output = &content[..std::cmp::min(len, content.len())];
7240
7241        match fd {
7242            1 => {
7243                print!("{}", output);
7244                use std::io::Write;
7245                std::io::stdout().flush().ok();
7246                Ok(Value::Int(output.len() as i64))
7247            }
7248            2 => {
7249                eprint!("{}", output);
7250                use std::io::Write;
7251                std::io::stderr().flush().ok();
7252                Ok(Value::Int(output.len() as i64))
7253            }
7254            _ => Err(RuntimeError::new(format!("write() unsupported fd: {}", fd))),
7255        }
7256    });
7257
7258    // PathBuf::from - create PathBuf from string
7259    define(interp, "PathBuf·from", Some(1), |_, args| {
7260        let path = match &args[0] {
7261            Value::String(s) => s.to_string(),
7262            Value::Ref(r) => {
7263                if let Value::String(s) = &*r.borrow() {
7264                    s.to_string()
7265                } else {
7266                    return Err(RuntimeError::new("PathBuf::from() requires string"));
7267                }
7268            }
7269            _ => return Err(RuntimeError::new("PathBuf::from() requires string")),
7270        };
7271        Ok(Value::String(Rc::new(path)))
7272    });
7273
7274    // std::path::PathBuf::from - full path variant
7275    define(interp, "std·path·PathBuf·from", Some(1), |_, args| {
7276        let path = match &args[0] {
7277            Value::String(s) => s.to_string(),
7278            Value::Ref(r) => {
7279                if let Value::String(s) = &*r.borrow() {
7280                    s.to_string()
7281                } else {
7282                    return Err(RuntimeError::new("PathBuf::from() requires string"));
7283                }
7284            }
7285            _ => return Err(RuntimeError::new("PathBuf::from() requires string")),
7286        };
7287        Ok(Value::String(Rc::new(path)))
7288    });
7289
7290    // Path::new - create Path from string
7291    define(interp, "Path·new", Some(1), |_, args| {
7292        let path = match &args[0] {
7293            Value::String(s) => s.to_string(),
7294            Value::Ref(r) => {
7295                if let Value::String(s) = &*r.borrow() {
7296                    s.to_string()
7297                } else {
7298                    return Err(RuntimeError::new("Path::new() requires string"));
7299                }
7300            }
7301            _ => return Err(RuntimeError::new("Path::new() requires string")),
7302        };
7303        Ok(Value::String(Rc::new(path)))
7304    });
7305
7306    // std::path::Path::new - full path variant
7307    define(interp, "std·path·Path·new", Some(1), |_, args| {
7308        let path = match &args[0] {
7309            Value::String(s) => s.to_string(),
7310            _ => return Err(RuntimeError::new("Path::new() requires string")),
7311        };
7312        Ok(Value::String(Rc::new(path)))
7313    });
7314
7315    // std::fs::read_to_string - alias for fs_read
7316    define(interp, "std·fs·read_to_string", Some(1), |_, args| {
7317        let path = match &args[0] {
7318            Value::String(s) => s.to_string(),
7319            _ => return Err(RuntimeError::new("read_to_string() requires string path")),
7320        };
7321        match std::fs::read_to_string(&path) {
7322            Ok(content) => Ok(Value::String(Rc::new(content))),
7323            Err(e) => Err(RuntimeError::new(format!("read_to_string() error: {}", e))),
7324        }
7325    });
7326
7327    // std::fs::write - alias for fs_write
7328    define(interp, "std·fs·write", Some(2), |_, args| {
7329        let path = match &args[0] {
7330            Value::String(s) => s.to_string(),
7331            _ => return Err(RuntimeError::new("fs::write() requires string path")),
7332        };
7333        let content = format!("{}", args[1]);
7334        match std::fs::write(&path, content) {
7335            Ok(()) => Ok(Value::Null),
7336            Err(e) => Err(RuntimeError::new(format!("fs::write() error: {}", e))),
7337        }
7338    });
7339
7340    // std::fs::create_dir_all - create directory and all parents
7341    define(interp, "std·fs·create_dir_all", Some(1), |_, args| {
7342        let path = match &args[0] {
7343            Value::String(s) => s.to_string(),
7344            _ => return Err(RuntimeError::new("create_dir_all() requires string path")),
7345        };
7346        match std::fs::create_dir_all(&path) {
7347            Ok(()) => Ok(Value::Null),
7348            Err(e) => Err(RuntimeError::new(format!("create_dir_all() error: {}", e))),
7349        }
7350    });
7351
7352    // OpenOptions::new - create file open options builder
7353    // Returns a map that can be configured with .read(), .write(), etc.
7354    define(interp, "OpenOptions·new", Some(0), |_, _| {
7355        let mut opts = HashMap::new();
7356        opts.insert("read".to_string(), Value::Bool(false));
7357        opts.insert("write".to_string(), Value::Bool(false));
7358        opts.insert("append".to_string(), Value::Bool(false));
7359        opts.insert("truncate".to_string(), Value::Bool(false));
7360        opts.insert("create".to_string(), Value::Bool(false));
7361        opts.insert("create_new".to_string(), Value::Bool(false));
7362        opts.insert("__type__".to_string(), Value::String(Rc::new("OpenOptions".to_string())));
7363        Ok(Value::Map(Rc::new(RefCell::new(opts))))
7364    });
7365
7366    // std::fs::OpenOptions::new
7367    define(interp, "std·fs·OpenOptions·new", Some(0), |_, _| {
7368        let mut opts = HashMap::new();
7369        opts.insert("read".to_string(), Value::Bool(false));
7370        opts.insert("write".to_string(), Value::Bool(false));
7371        opts.insert("append".to_string(), Value::Bool(false));
7372        opts.insert("truncate".to_string(), Value::Bool(false));
7373        opts.insert("create".to_string(), Value::Bool(false));
7374        opts.insert("create_new".to_string(), Value::Bool(false));
7375        opts.insert("__type__".to_string(), Value::String(Rc::new("OpenOptions".to_string())));
7376        Ok(Value::Map(Rc::new(RefCell::new(opts))))
7377    });
7378
7379    // File::create - create a file for writing
7380    define(interp, "File·create", Some(1), |_, args| {
7381        let path = match &args[0] {
7382            Value::String(s) => s.to_string(),
7383            _ => return Err(RuntimeError::new("File::create() requires string path")),
7384        };
7385        // For interpreter, we just return the path as a "file handle"
7386        let mut handle = HashMap::new();
7387        handle.insert("path".to_string(), Value::String(Rc::new(path.clone())));
7388        handle.insert("mode".to_string(), Value::String(Rc::new("write".to_string())));
7389        handle.insert("__type__".to_string(), Value::String(Rc::new("File".to_string())));
7390        // Actually create the file
7391        match std::fs::File::create(&path) {
7392            Ok(_) => Ok(Value::Map(Rc::new(RefCell::new(handle)))),
7393            Err(e) => Err(RuntimeError::new(format!("File::create() error: {}", e))),
7394        }
7395    });
7396
7397    // std::fs::File::create
7398    define(interp, "std·fs·File·create", Some(1), |_, args| {
7399        let path = match &args[0] {
7400            Value::String(s) => s.to_string(),
7401            _ => return Err(RuntimeError::new("File::create() requires string path")),
7402        };
7403        let mut handle = HashMap::new();
7404        handle.insert("path".to_string(), Value::String(Rc::new(path.clone())));
7405        handle.insert("mode".to_string(), Value::String(Rc::new("write".to_string())));
7406        handle.insert("__type__".to_string(), Value::String(Rc::new("File".to_string())));
7407        match std::fs::File::create(&path) {
7408            Ok(_) => Ok(Value::Map(Rc::new(RefCell::new(handle)))),
7409            Err(e) => Err(RuntimeError::new(format!("File::create() error: {}", e))),
7410        }
7411    });
7412
7413    // File::open - open a file for reading
7414    define(interp, "File·open", Some(1), |_, args| {
7415        let path = match &args[0] {
7416            Value::String(s) => s.to_string(),
7417            _ => return Err(RuntimeError::new("File::open() requires string path")),
7418        };
7419        let mut handle = HashMap::new();
7420        handle.insert("path".to_string(), Value::String(Rc::new(path.clone())));
7421        handle.insert("mode".to_string(), Value::String(Rc::new("read".to_string())));
7422        handle.insert("__type__".to_string(), Value::String(Rc::new("File".to_string())));
7423        match std::fs::File::open(&path) {
7424            Ok(_) => Ok(Value::Map(Rc::new(RefCell::new(handle)))),
7425            Err(e) => Err(RuntimeError::new(format!("File::open() error: {}", e))),
7426        }
7427    });
7428
7429    // std::fs::File::open
7430    define(interp, "std·fs·File·open", Some(1), |_, args| {
7431        let path = match &args[0] {
7432            Value::String(s) => s.to_string(),
7433            _ => return Err(RuntimeError::new("File::open() requires string path")),
7434        };
7435        let mut handle = HashMap::new();
7436        handle.insert("path".to_string(), Value::String(Rc::new(path.clone())));
7437        handle.insert("mode".to_string(), Value::String(Rc::new("read".to_string())));
7438        handle.insert("__type__".to_string(), Value::String(Rc::new("File".to_string())));
7439        match std::fs::File::open(&path) {
7440            Ok(_) => Ok(Value::Map(Rc::new(RefCell::new(handle)))),
7441            Err(e) => Err(RuntimeError::new(format!("File::open() error: {}", e))),
7442        }
7443    });
7444
7445    // BufWriter::new - create a buffered writer wrapper
7446    define(interp, "BufWriter·new", Some(1), |_, args| {
7447        // BufWriter wraps a file and provides buffering
7448        // In our implementation, we pass through the underlying file handle with a buffer
7449        match &args[0] {
7450            Value::Map(file_map) => {
7451                let mut wrapper = HashMap::new();
7452                wrapper.insert("inner".to_string(), Value::Map(file_map.clone()));
7453                wrapper.insert("buffer".to_string(), Value::Array(Rc::new(RefCell::new(Vec::new()))));
7454                wrapper.insert("__type__".to_string(), Value::String(Rc::new("BufWriter".to_string())));
7455                Ok(Value::Map(Rc::new(RefCell::new(wrapper))))
7456            }
7457            _ => Err(RuntimeError::new("BufWriter::new requires a file handle")),
7458        }
7459    });
7460
7461    // std::io::BufWriter::new
7462    define(interp, "std·io·BufWriter·new", Some(1), |_, args| {
7463        match &args[0] {
7464            Value::Map(file_map) => {
7465                let mut wrapper = HashMap::new();
7466                wrapper.insert("inner".to_string(), Value::Map(file_map.clone()));
7467                wrapper.insert("buffer".to_string(), Value::Array(Rc::new(RefCell::new(Vec::new()))));
7468                wrapper.insert("__type__".to_string(), Value::String(Rc::new("BufWriter".to_string())));
7469                Ok(Value::Map(Rc::new(RefCell::new(wrapper))))
7470            }
7471            _ => Err(RuntimeError::new("BufWriter::new requires a file handle")),
7472        }
7473    });
7474
7475    // BufReader::new - create a buffered reader wrapper (handles both file and TcpStream)
7476    define(interp, "BufReader·new", Some(1), |_, args| {
7477        use std::io::BufReader as StdBufReader;
7478
7479        // Helper to extract map from value, handling Ref wrappers
7480        let get_map = |val: &Value| -> Option<Rc<RefCell<HashMap<String, Value>>>> {
7481            match val {
7482                Value::Map(m) => Some(m.clone()),
7483                Value::Ref(r) => {
7484                    let inner = r.borrow();
7485                    if let Value::Map(m) = &*inner {
7486                        Some(m.clone())
7487                    } else {
7488                        None
7489                    }
7490                }
7491                _ => None,
7492            }
7493        };
7494
7495        if let Some(file_map) = get_map(&args[0]) {
7496            let borrowed = file_map.borrow();
7497            let mut wrapper = HashMap::new();
7498
7499            // Check if this is a TcpStream - if so, create a REAL BufReader
7500            if let Some(Value::String(t)) = borrowed.get("__type__") {
7501                if t.as_str() == "TcpStream" {
7502                    if let Some(Value::Int(stream_id)) = borrowed.get("__stream_id__") {
7503                        let stream_id_val = *stream_id as u64;
7504                        drop(borrowed);
7505
7506                        // Create and store a real BufReader
7507                        if let Some(mut guard) = get_stream_registry().lock().ok() {
7508                            if let Some(stream) = guard.get_mut(&stream_id_val) {
7509                                let stream_clone = match stream.try_clone() {
7510                                    Ok(s) => s,
7511                                    Err(e) => return Err(RuntimeError::new(format!("Failed to clone stream: {}", e))),
7512                                };
7513                                let reader = StdBufReader::new(stream_clone);
7514                                let reader_id = store_bufreader(reader);
7515
7516                                wrapper.insert("__type__".to_string(), Value::String(Rc::new("BufReader".to_string())));
7517                                wrapper.insert("__stream_id__".to_string(), Value::Int(stream_id_val as i64));
7518                                wrapper.insert("__reader_id__".to_string(), Value::Int(reader_id as i64));
7519                                return Ok(Value::Map(Rc::new(RefCell::new(wrapper))));
7520                            }
7521                        }
7522                        return Err(RuntimeError::new("TcpStream not found in registry"));
7523                    }
7524                }
7525            }
7526
7527            // For regular files, just wrap it
7528            drop(borrowed);
7529            wrapper.insert("inner".to_string(), Value::Map(file_map.clone()));
7530            wrapper.insert("__type__".to_string(), Value::String(Rc::new("BufReader".to_string())));
7531            Ok(Value::Map(Rc::new(RefCell::new(wrapper))))
7532        } else {
7533            Err(RuntimeError::new("BufReader::new requires a file handle or TcpStream"))
7534        }
7535    });
7536
7537    // std::io::BufReader::new
7538    define(interp, "std·io·BufReader·new", Some(1), |_, args| {
7539        // Helper to extract map from value, handling Ref wrappers
7540        let get_map = |val: &Value| -> Option<Rc<RefCell<HashMap<String, Value>>>> {
7541            match val {
7542                Value::Map(m) => Some(m.clone()),
7543                Value::Ref(r) => {
7544                    let inner = r.borrow();
7545                    if let Value::Map(m) = &*inner {
7546                        Some(m.clone())
7547                    } else {
7548                        None
7549                    }
7550                }
7551                _ => None,
7552            }
7553        };
7554
7555        if let Some(file_map) = get_map(&args[0]) {
7556            let borrowed = file_map.borrow();
7557            let mut wrapper = HashMap::new();
7558
7559            // Check if this is a TcpStream
7560            if let Some(Value::String(t)) = borrowed.get("__type__") {
7561                if t.as_str() == "TcpStream" {
7562                    if let Some(Value::Int(stream_id)) = borrowed.get("__stream_id__") {
7563                        wrapper.insert("__stream_id__".to_string(), Value::Int(*stream_id));
7564                    }
7565                }
7566            }
7567
7568            drop(borrowed);
7569            wrapper.insert("inner".to_string(), Value::Map(file_map.clone()));
7570            wrapper.insert("__type__".to_string(), Value::String(Rc::new("BufReader".to_string())));
7571            Ok(Value::Map(Rc::new(RefCell::new(wrapper))))
7572        } else {
7573            Err(RuntimeError::new("BufReader::new requires a file handle or TcpStream"))
7574        }
7575    });
7576
7577    // dirs_next::config_dir - get user config directory
7578    define(interp, "dirs_next·config_dir", Some(0), |_, _| {
7579        match dirs::config_dir() {
7580            Some(path) => Ok(Value::String(Rc::new(path.to_string_lossy().to_string()))),
7581            None => Ok(Value::Null),
7582        }
7583    });
7584
7585    // dirs_next::data_dir - get user data directory
7586    define(interp, "dirs_next·data_dir", Some(0), |_, _| {
7587        match dirs::data_dir() {
7588            Some(path) => Ok(Value::String(Rc::new(path.to_string_lossy().to_string()))),
7589            None => Ok(Value::Null),
7590        }
7591    });
7592
7593    // dirs_next::home_dir - get user home directory
7594    define(interp, "dirs_next·home_dir", Some(0), |_, _| {
7595        match dirs::home_dir() {
7596            Some(path) => Ok(Value::String(Rc::new(path.to_string_lossy().to_string()))),
7597            None => Ok(Value::Null),
7598        }
7599    });
7600}
7601
7602// ============================================================================
7603// CRYPTOGRAPHY FUNCTIONS - AI-Native Evidential Cryptography
7604// ============================================================================
7605//
7606// Sigil's crypto module is unique in several ways:
7607//
7608// 1. EVIDENTIALITY-AWARE: All crypto operations track provenance
7609//    - Generated keys are "known" (!)
7610//    - External/imported keys are "reported" (~)
7611//    - Decryption results are "uncertain" (?) until verified
7612//    - Signatures verified from external sources remain (~) until trusted
7613//
7614// 2. CEREMONY-BASED KEY MANAGEMENT: Cultural metaphors for key lifecycle
7615//    - Key generation as "birth ceremony"
7616//    - Key exchange as "handshake ritual"
7617//    - Multi-party as "council of elders" (Shamir secret sharing)
7618//    - Verification as "witness testimony"
7619//
7620// 3. MATHEMATICAL INTEGRATION: Leverages Sigil's math capabilities
7621//    - Cycle<N> for modular arithmetic
7622//    - Field operations for elliptic curves
7623//
7624// Available algorithms:
7625//   Hashing: SHA-256, SHA-512, SHA3-256, SHA3-512, BLAKE3, MD5 (deprecated)
7626//   Symmetric: AES-256-GCM, ChaCha20-Poly1305
7627//   Asymmetric: Ed25519 (signatures), X25519 (key exchange)
7628//   KDF: Argon2id, HKDF, PBKDF2
7629//   MAC: HMAC-SHA256, HMAC-SHA512, BLAKE3-keyed
7630//   Secret Sharing: Shamir's Secret Sharing
7631// ============================================================================
7632
7633fn register_crypto(interp: &mut Interpreter) {
7634    // Helper to extract bytes from Value
7635    fn extract_bytes(v: &Value, fn_name: &str) -> Result<Vec<u8>, RuntimeError> {
7636        match v {
7637            Value::String(s) => Ok(s.as_bytes().to_vec()),
7638            Value::Array(arr) => {
7639                let arr = arr.borrow();
7640                Ok(arr
7641                    .iter()
7642                    .filter_map(|v| {
7643                        if let Value::Int(n) = v {
7644                            Some(*n as u8)
7645                        } else {
7646                            None
7647                        }
7648                    })
7649                    .collect())
7650            }
7651            _ => Err(RuntimeError::new(format!(
7652                "{}() requires string or byte array",
7653                fn_name
7654            ))),
7655        }
7656    }
7657
7658    fn bytes_to_array(bytes: &[u8]) -> Value {
7659        let values: Vec<Value> = bytes.iter().map(|b| Value::Int(*b as i64)).collect();
7660        Value::Array(Rc::new(RefCell::new(values)))
7661    }
7662
7663    // ========================================================================
7664    // HASHING
7665    // ========================================================================
7666
7667    // sha256 - SHA-256 hash
7668    define(interp, "sha256", Some(1), |_, args| {
7669        let data = extract_bytes(&args[0], "sha256")?;
7670        let mut hasher = Sha256::new();
7671        hasher.update(&data);
7672        let result = hasher.finalize();
7673        Ok(Value::String(Rc::new(
7674            result.iter().map(|b| format!("{:02x}", b)).collect(),
7675        )))
7676    });
7677
7678    // sha512 - SHA-512 hash
7679    define(interp, "sha512", Some(1), |_, args| {
7680        let data = extract_bytes(&args[0], "sha512")?;
7681        let mut hasher = Sha512::new();
7682        hasher.update(&data);
7683        let result = hasher.finalize();
7684        Ok(Value::String(Rc::new(
7685            result.iter().map(|b| format!("{:02x}", b)).collect(),
7686        )))
7687    });
7688
7689    // sha3_256 - SHA-3 (Keccak) 256-bit
7690    define(interp, "sha3_256", Some(1), |_, args| {
7691        use sha3::{Digest as Sha3Digest, Sha3_256};
7692        let data = extract_bytes(&args[0], "sha3_256")?;
7693        let mut hasher = Sha3_256::new();
7694        hasher.update(&data);
7695        let result = hasher.finalize();
7696        Ok(Value::String(Rc::new(
7697            result.iter().map(|b| format!("{:02x}", b)).collect(),
7698        )))
7699    });
7700
7701    // sha3_512 - SHA-3 (Keccak) 512-bit
7702    define(interp, "sha3_512", Some(1), |_, args| {
7703        use sha3::{Digest as Sha3Digest, Sha3_512};
7704        let data = extract_bytes(&args[0], "sha3_512")?;
7705        let mut hasher = Sha3_512::new();
7706        hasher.update(&data);
7707        let result = hasher.finalize();
7708        Ok(Value::String(Rc::new(
7709            result.iter().map(|b| format!("{:02x}", b)).collect(),
7710        )))
7711    });
7712
7713    // blake3 - BLAKE3 hash (fastest secure hash)
7714    define(interp, "blake3", Some(1), |_, args| {
7715        let data = extract_bytes(&args[0], "blake3")?;
7716        let hash = blake3::hash(&data);
7717        Ok(Value::String(Rc::new(hash.to_hex().to_string())))
7718    });
7719
7720    // blake3_keyed - BLAKE3 keyed hash (MAC)
7721    define(interp, "blake3_keyed", Some(2), |_, args| {
7722        let key = extract_bytes(&args[0], "blake3_keyed")?;
7723        let data = extract_bytes(&args[1], "blake3_keyed")?;
7724        if key.len() != 32 {
7725            return Err(RuntimeError::new("blake3_keyed() requires 32-byte key"));
7726        }
7727        let mut key_arr = [0u8; 32];
7728        key_arr.copy_from_slice(&key);
7729        let hash = blake3::keyed_hash(&key_arr, &data);
7730        Ok(Value::String(Rc::new(hash.to_hex().to_string())))
7731    });
7732
7733    // md5 - MD5 hash (⚠️ DEPRECATED)
7734    define(interp, "md5", Some(1), |_, args| {
7735        let data = extract_bytes(&args[0], "md5")?;
7736        let mut hasher = Md5::new();
7737        hasher.update(&data);
7738        let result = hasher.finalize();
7739        Ok(Value::String(Rc::new(
7740            result.iter().map(|b| format!("{:02x}", b)).collect(),
7741        )))
7742    });
7743
7744    // ========================================================================
7745    // SYMMETRIC ENCRYPTION
7746    // ========================================================================
7747
7748    // aes_gcm_encrypt - AES-256-GCM authenticated encryption
7749    define(interp, "aes_gcm_encrypt", Some(2), |_, args| {
7750        use aes_gcm::{aead::Aead, Aes256Gcm, KeyInit, Nonce};
7751        use rand::RngCore;
7752
7753        let key = extract_bytes(&args[0], "aes_gcm_encrypt")?;
7754        let plaintext = extract_bytes(&args[1], "aes_gcm_encrypt")?;
7755
7756        if key.len() != 32 {
7757            return Err(RuntimeError::new("aes_gcm_encrypt() requires 32-byte key"));
7758        }
7759
7760        let cipher = Aes256Gcm::new_from_slice(&key)
7761            .map_err(|e| RuntimeError::new(format!("AES key error: {}", e)))?;
7762
7763        let mut nonce_bytes = [0u8; 12];
7764        rand::thread_rng().fill_bytes(&mut nonce_bytes);
7765        let nonce = Nonce::from_slice(&nonce_bytes);
7766
7767        let ciphertext = cipher
7768            .encrypt(nonce, plaintext.as_ref())
7769            .map_err(|e| RuntimeError::new(format!("AES encryption error: {}", e)))?;
7770
7771        let mut result = HashMap::new();
7772        result.insert("ciphertext".to_string(), bytes_to_array(&ciphertext));
7773        result.insert("nonce".to_string(), bytes_to_array(&nonce_bytes));
7774        Ok(Value::Map(Rc::new(RefCell::new(result))))
7775    });
7776
7777    // aes_gcm_decrypt - AES-256-GCM decryption
7778    define(interp, "aes_gcm_decrypt", Some(3), |_, args| {
7779        use aes_gcm::{aead::Aead, Aes256Gcm, KeyInit, Nonce};
7780
7781        let key = extract_bytes(&args[0], "aes_gcm_decrypt")?;
7782        let ciphertext = extract_bytes(&args[1], "aes_gcm_decrypt")?;
7783        let nonce_bytes = extract_bytes(&args[2], "aes_gcm_decrypt")?;
7784
7785        if key.len() != 32 {
7786            return Err(RuntimeError::new("aes_gcm_decrypt() requires 32-byte key"));
7787        }
7788        if nonce_bytes.len() != 12 {
7789            return Err(RuntimeError::new(
7790                "aes_gcm_decrypt() requires 12-byte nonce",
7791            ));
7792        }
7793
7794        let cipher = Aes256Gcm::new_from_slice(&key)
7795            .map_err(|e| RuntimeError::new(format!("AES key error: {}", e)))?;
7796        let nonce = Nonce::from_slice(&nonce_bytes);
7797
7798        let plaintext = cipher
7799            .decrypt(nonce, ciphertext.as_ref())
7800            .map_err(|_| RuntimeError::new("AES-GCM decryption failed: authentication error"))?;
7801
7802        match String::from_utf8(plaintext.clone()) {
7803            Ok(s) => Ok(Value::String(Rc::new(s))),
7804            Err(_) => Ok(bytes_to_array(&plaintext)),
7805        }
7806    });
7807
7808    // chacha20_encrypt - ChaCha20-Poly1305 encryption
7809    define(interp, "chacha20_encrypt", Some(2), |_, args| {
7810        use chacha20poly1305::{aead::Aead, ChaCha20Poly1305, KeyInit, Nonce};
7811        use rand::RngCore;
7812
7813        let key = extract_bytes(&args[0], "chacha20_encrypt")?;
7814        let plaintext = extract_bytes(&args[1], "chacha20_encrypt")?;
7815
7816        if key.len() != 32 {
7817            return Err(RuntimeError::new("chacha20_encrypt() requires 32-byte key"));
7818        }
7819
7820        let cipher = ChaCha20Poly1305::new_from_slice(&key)
7821            .map_err(|e| RuntimeError::new(format!("ChaCha20 key error: {}", e)))?;
7822
7823        let mut nonce_bytes = [0u8; 12];
7824        rand::thread_rng().fill_bytes(&mut nonce_bytes);
7825        let nonce = Nonce::from_slice(&nonce_bytes);
7826
7827        let ciphertext = cipher
7828            .encrypt(nonce, plaintext.as_ref())
7829            .map_err(|e| RuntimeError::new(format!("ChaCha20 encryption error: {}", e)))?;
7830
7831        let mut result = HashMap::new();
7832        result.insert("ciphertext".to_string(), bytes_to_array(&ciphertext));
7833        result.insert("nonce".to_string(), bytes_to_array(&nonce_bytes));
7834        Ok(Value::Map(Rc::new(RefCell::new(result))))
7835    });
7836
7837    // chacha20_decrypt - ChaCha20-Poly1305 decryption
7838    define(interp, "chacha20_decrypt", Some(3), |_, args| {
7839        use chacha20poly1305::{aead::Aead, ChaCha20Poly1305, KeyInit, Nonce};
7840
7841        let key = extract_bytes(&args[0], "chacha20_decrypt")?;
7842        let ciphertext = extract_bytes(&args[1], "chacha20_decrypt")?;
7843        let nonce_bytes = extract_bytes(&args[2], "chacha20_decrypt")?;
7844
7845        if key.len() != 32 {
7846            return Err(RuntimeError::new("chacha20_decrypt() requires 32-byte key"));
7847        }
7848        if nonce_bytes.len() != 12 {
7849            return Err(RuntimeError::new(
7850                "chacha20_decrypt() requires 12-byte nonce",
7851            ));
7852        }
7853
7854        let cipher = ChaCha20Poly1305::new_from_slice(&key)
7855            .map_err(|e| RuntimeError::new(format!("ChaCha20 key error: {}", e)))?;
7856        let nonce = Nonce::from_slice(&nonce_bytes);
7857
7858        let plaintext = cipher
7859            .decrypt(nonce, ciphertext.as_ref())
7860            .map_err(|_| RuntimeError::new("ChaCha20 decryption failed: authentication error"))?;
7861
7862        match String::from_utf8(plaintext.clone()) {
7863            Ok(s) => Ok(Value::String(Rc::new(s))),
7864            Err(_) => Ok(bytes_to_array(&plaintext)),
7865        }
7866    });
7867
7868    // ========================================================================
7869    // ASYMMETRIC CRYPTOGRAPHY
7870    // ========================================================================
7871
7872    // ed25519_keygen - Generate Ed25519 keypair
7873    define(interp, "ed25519_keygen", Some(0), |_, _| {
7874        use ed25519_dalek::SigningKey;
7875        use rand::rngs::OsRng;
7876
7877        let signing_key = SigningKey::generate(&mut OsRng);
7878        let verifying_key = signing_key.verifying_key();
7879
7880        let mut result = HashMap::new();
7881        result.insert(
7882            "private_key".to_string(),
7883            Value::String(Rc::new(
7884                signing_key
7885                    .to_bytes()
7886                    .iter()
7887                    .map(|b| format!("{:02x}", b))
7888                    .collect(),
7889            )),
7890        );
7891        result.insert(
7892            "public_key".to_string(),
7893            Value::String(Rc::new(
7894                verifying_key
7895                    .to_bytes()
7896                    .iter()
7897                    .map(|b| format!("{:02x}", b))
7898                    .collect(),
7899            )),
7900        );
7901        Ok(Value::Map(Rc::new(RefCell::new(result))))
7902    });
7903
7904    // ed25519_sign - Sign with Ed25519
7905    define(interp, "ed25519_sign", Some(2), |_, args| {
7906        use ed25519_dalek::{Signer, SigningKey};
7907
7908        let private_key_hex = match &args[0] {
7909            Value::String(s) => s.to_string(),
7910            _ => return Err(RuntimeError::new("ed25519_sign() requires hex private key")),
7911        };
7912        let message = extract_bytes(&args[1], "ed25519_sign")?;
7913
7914        let key_bytes: Vec<u8> = (0..private_key_hex.len())
7915            .step_by(2)
7916            .map(|i| u8::from_str_radix(&private_key_hex[i..i + 2], 16))
7917            .collect::<Result<Vec<_>, _>>()
7918            .map_err(|_| RuntimeError::new("Invalid private key hex"))?;
7919
7920        if key_bytes.len() != 32 {
7921            return Err(RuntimeError::new(
7922                "ed25519_sign() requires 32-byte private key",
7923            ));
7924        }
7925
7926        let mut key_arr = [0u8; 32];
7927        key_arr.copy_from_slice(&key_bytes);
7928        let signing_key = SigningKey::from_bytes(&key_arr);
7929        let signature = signing_key.sign(&message);
7930
7931        Ok(Value::String(Rc::new(
7932            signature
7933                .to_bytes()
7934                .iter()
7935                .map(|b| format!("{:02x}", b))
7936                .collect(),
7937        )))
7938    });
7939
7940    // ed25519_verify - Verify Ed25519 signature
7941    define(interp, "ed25519_verify", Some(3), |_, args| {
7942        use ed25519_dalek::{Signature, Verifier, VerifyingKey};
7943
7944        let public_key_hex = match &args[0] {
7945            Value::String(s) => s.to_string(),
7946            _ => {
7947                return Err(RuntimeError::new(
7948                    "ed25519_verify() requires hex public key",
7949                ))
7950            }
7951        };
7952        let message = extract_bytes(&args[1], "ed25519_verify")?;
7953        let signature_hex = match &args[2] {
7954            Value::String(s) => s.to_string(),
7955            _ => return Err(RuntimeError::new("ed25519_verify() requires hex signature")),
7956        };
7957
7958        let key_bytes: Vec<u8> = (0..public_key_hex.len())
7959            .step_by(2)
7960            .map(|i| u8::from_str_radix(&public_key_hex[i..i + 2], 16))
7961            .collect::<Result<Vec<_>, _>>()
7962            .map_err(|_| RuntimeError::new("Invalid public key hex"))?;
7963        let sig_bytes: Vec<u8> = (0..signature_hex.len())
7964            .step_by(2)
7965            .map(|i| u8::from_str_radix(&signature_hex[i..i + 2], 16))
7966            .collect::<Result<Vec<_>, _>>()
7967            .map_err(|_| RuntimeError::new("Invalid signature hex"))?;
7968
7969        if key_bytes.len() != 32 {
7970            return Err(RuntimeError::new(
7971                "ed25519_verify() requires 32-byte public key",
7972            ));
7973        }
7974        if sig_bytes.len() != 64 {
7975            return Err(RuntimeError::new(
7976                "ed25519_verify() requires 64-byte signature",
7977            ));
7978        }
7979
7980        let mut key_arr = [0u8; 32];
7981        key_arr.copy_from_slice(&key_bytes);
7982        let mut sig_arr = [0u8; 64];
7983        sig_arr.copy_from_slice(&sig_bytes);
7984
7985        let verifying_key = VerifyingKey::from_bytes(&key_arr)
7986            .map_err(|e| RuntimeError::new(format!("Invalid public key: {}", e)))?;
7987        let signature = Signature::from_bytes(&sig_arr);
7988
7989        match verifying_key.verify(&message, &signature) {
7990            Ok(_) => Ok(Value::Bool(true)),
7991            Err(_) => Ok(Value::Bool(false)),
7992        }
7993    });
7994
7995    // x25519_keygen - Generate X25519 key exchange keypair
7996    define(interp, "x25519_keygen", Some(0), |_, _| {
7997        use rand::rngs::OsRng;
7998        use x25519_dalek::{PublicKey, StaticSecret};
7999
8000        let secret = StaticSecret::random_from_rng(OsRng);
8001        let public = PublicKey::from(&secret);
8002
8003        let mut result = HashMap::new();
8004        result.insert(
8005            "private_key".to_string(),
8006            Value::String(Rc::new(
8007                secret
8008                    .as_bytes()
8009                    .iter()
8010                    .map(|b| format!("{:02x}", b))
8011                    .collect(),
8012            )),
8013        );
8014        result.insert(
8015            "public_key".to_string(),
8016            Value::String(Rc::new(
8017                public
8018                    .as_bytes()
8019                    .iter()
8020                    .map(|b| format!("{:02x}", b))
8021                    .collect(),
8022            )),
8023        );
8024        Ok(Value::Map(Rc::new(RefCell::new(result))))
8025    });
8026
8027    // x25519_exchange - Diffie-Hellman key exchange
8028    define(interp, "x25519_exchange", Some(2), |_, args| {
8029        use x25519_dalek::{PublicKey, StaticSecret};
8030
8031        let my_private_hex = match &args[0] {
8032            Value::String(s) => s.to_string(),
8033            _ => {
8034                return Err(RuntimeError::new(
8035                    "x25519_exchange() requires hex private key",
8036                ))
8037            }
8038        };
8039        let their_public_hex = match &args[1] {
8040            Value::String(s) => s.to_string(),
8041            _ => {
8042                return Err(RuntimeError::new(
8043                    "x25519_exchange() requires hex public key",
8044                ))
8045            }
8046        };
8047
8048        let my_private_bytes: Vec<u8> = (0..my_private_hex.len())
8049            .step_by(2)
8050            .map(|i| u8::from_str_radix(&my_private_hex[i..i + 2], 16))
8051            .collect::<Result<Vec<_>, _>>()
8052            .map_err(|_| RuntimeError::new("Invalid private key hex"))?;
8053        let their_public_bytes: Vec<u8> = (0..their_public_hex.len())
8054            .step_by(2)
8055            .map(|i| u8::from_str_radix(&their_public_hex[i..i + 2], 16))
8056            .collect::<Result<Vec<_>, _>>()
8057            .map_err(|_| RuntimeError::new("Invalid public key hex"))?;
8058
8059        if my_private_bytes.len() != 32 || their_public_bytes.len() != 32 {
8060            return Err(RuntimeError::new("x25519_exchange() requires 32-byte keys"));
8061        }
8062
8063        let mut priv_arr = [0u8; 32];
8064        priv_arr.copy_from_slice(&my_private_bytes);
8065        let mut pub_arr = [0u8; 32];
8066        pub_arr.copy_from_slice(&their_public_bytes);
8067
8068        let my_secret = StaticSecret::from(priv_arr);
8069        let their_public = PublicKey::from(pub_arr);
8070        let shared_secret = my_secret.diffie_hellman(&their_public);
8071
8072        Ok(Value::String(Rc::new(
8073            shared_secret
8074                .as_bytes()
8075                .iter()
8076                .map(|b| format!("{:02x}", b))
8077                .collect(),
8078        )))
8079    });
8080
8081    // ========================================================================
8082    // KEY DERIVATION (Ceremony of Strengthening)
8083    // ========================================================================
8084
8085    // argon2_hash - Argon2id password hashing (RECOMMENDED for passwords)
8086    define(interp, "argon2_hash", Some(1), |_, args| {
8087        use argon2::{
8088            password_hash::{PasswordHasher, SaltString},
8089            Argon2,
8090        };
8091        use rand::rngs::OsRng;
8092
8093        let password = extract_bytes(&args[0], "argon2_hash")?;
8094        let salt = SaltString::generate(&mut OsRng);
8095        let argon2 = Argon2::default();
8096
8097        let hash = argon2
8098            .hash_password(&password, &salt)
8099            .map_err(|e| RuntimeError::new(format!("Argon2 error: {}", e)))?;
8100
8101        let mut result = HashMap::new();
8102        result.insert("hash".to_string(), Value::String(Rc::new(hash.to_string())));
8103        result.insert("salt".to_string(), Value::String(Rc::new(salt.to_string())));
8104        Ok(Value::Map(Rc::new(RefCell::new(result))))
8105    });
8106
8107    // argon2_verify - Verify Argon2 password
8108    define(interp, "argon2_verify", Some(2), |_, args| {
8109        use argon2::{Argon2, PasswordHash, PasswordVerifier};
8110
8111        let password = extract_bytes(&args[0], "argon2_verify")?;
8112        let hash_str = match &args[1] {
8113            Value::String(s) => s.to_string(),
8114            _ => return Err(RuntimeError::new("argon2_verify() requires hash string")),
8115        };
8116
8117        let parsed_hash = PasswordHash::new(&hash_str)
8118            .map_err(|e| RuntimeError::new(format!("Invalid hash: {}", e)))?;
8119
8120        match Argon2::default().verify_password(&password, &parsed_hash) {
8121            Ok(_) => Ok(Value::Bool(true)),
8122            Err(_) => Ok(Value::Bool(false)),
8123        }
8124    });
8125
8126    // hkdf_expand - HKDF key derivation
8127    define(interp, "hkdf_expand", Some(3), |_, args| {
8128        use hkdf::Hkdf;
8129
8130        let ikm = extract_bytes(&args[0], "hkdf_expand")?;
8131        let salt = extract_bytes(&args[1], "hkdf_expand")?;
8132        let info = extract_bytes(&args[2], "hkdf_expand")?;
8133
8134        let hk = Hkdf::<Sha256>::new(Some(&salt), &ikm);
8135        let mut okm = [0u8; 32];
8136        hk.expand(&info, &mut okm)
8137            .map_err(|e| RuntimeError::new(format!("HKDF error: {}", e)))?;
8138
8139        Ok(Value::String(Rc::new(
8140            okm.iter().map(|b| format!("{:02x}", b)).collect(),
8141        )))
8142    });
8143
8144    // pbkdf2_derive - PBKDF2 key derivation
8145    define(interp, "pbkdf2_derive", Some(3), |_, args| {
8146        let password = extract_bytes(&args[0], "pbkdf2_derive")?;
8147        let salt = extract_bytes(&args[1], "pbkdf2_derive")?;
8148        let iterations = match &args[2] {
8149            Value::Int(n) => *n as u32,
8150            _ => {
8151                return Err(RuntimeError::new(
8152                    "pbkdf2_derive() requires integer iterations",
8153                ))
8154            }
8155        };
8156
8157        let mut key = [0u8; 32];
8158        pbkdf2::pbkdf2_hmac::<Sha256>(&password, &salt, iterations, &mut key);
8159        Ok(Value::String(Rc::new(
8160            key.iter().map(|b| format!("{:02x}", b)).collect(),
8161        )))
8162    });
8163
8164    // ========================================================================
8165    // MESSAGE AUTHENTICATION
8166    // ========================================================================
8167
8168    // hmac_sha256 - HMAC-SHA256
8169    define(interp, "hmac_sha256", Some(2), |_, args| {
8170        use hmac::{Hmac, Mac};
8171        type HmacSha256 = Hmac<Sha256>;
8172
8173        let key = extract_bytes(&args[0], "hmac_sha256")?;
8174        let message = extract_bytes(&args[1], "hmac_sha256")?;
8175
8176        let mut mac = HmacSha256::new_from_slice(&key)
8177            .map_err(|e| RuntimeError::new(format!("HMAC key error: {}", e)))?;
8178        mac.update(&message);
8179        let result = mac.finalize();
8180        Ok(Value::String(Rc::new(
8181            result
8182                .into_bytes()
8183                .iter()
8184                .map(|b| format!("{:02x}", b))
8185                .collect(),
8186        )))
8187    });
8188
8189    // hmac_sha512 - HMAC-SHA512
8190    define(interp, "hmac_sha512", Some(2), |_, args| {
8191        use hmac::{Hmac, Mac};
8192        type HmacSha512 = Hmac<Sha512>;
8193
8194        let key = extract_bytes(&args[0], "hmac_sha512")?;
8195        let message = extract_bytes(&args[1], "hmac_sha512")?;
8196
8197        let mut mac = HmacSha512::new_from_slice(&key)
8198            .map_err(|e| RuntimeError::new(format!("HMAC key error: {}", e)))?;
8199        mac.update(&message);
8200        let result = mac.finalize();
8201        Ok(Value::String(Rc::new(
8202            result
8203                .into_bytes()
8204                .iter()
8205                .map(|b| format!("{:02x}", b))
8206                .collect(),
8207        )))
8208    });
8209
8210    // hmac_verify - Constant-time HMAC verification
8211    define(interp, "hmac_verify", Some(3), |_, args| {
8212        use hmac::{Hmac, Mac};
8213        type HmacSha256 = Hmac<Sha256>;
8214
8215        let key = extract_bytes(&args[0], "hmac_verify")?;
8216        let message = extract_bytes(&args[1], "hmac_verify")?;
8217        let expected_hex = match &args[2] {
8218            Value::String(s) => s.to_string(),
8219            _ => return Err(RuntimeError::new("hmac_verify() requires hex MAC")),
8220        };
8221
8222        let expected: Vec<u8> = (0..expected_hex.len())
8223            .step_by(2)
8224            .map(|i| u8::from_str_radix(&expected_hex[i..i + 2], 16))
8225            .collect::<Result<Vec<_>, _>>()
8226            .map_err(|_| RuntimeError::new("Invalid MAC hex"))?;
8227
8228        let mut mac = HmacSha256::new_from_slice(&key)
8229            .map_err(|e| RuntimeError::new(format!("HMAC key error: {}", e)))?;
8230        mac.update(&message);
8231
8232        match mac.verify_slice(&expected) {
8233            Ok(_) => Ok(Value::Bool(true)),
8234            Err(_) => Ok(Value::Bool(false)),
8235        }
8236    });
8237
8238    // ========================================================================
8239    // SECURE RANDOM (Birth Ceremony)
8240    // ========================================================================
8241
8242    // secure_random_bytes - Cryptographically secure random bytes
8243    define(interp, "secure_random_bytes", Some(1), |_, args| {
8244        use rand::RngCore;
8245
8246        let length = match &args[0] {
8247            Value::Int(n) => *n as usize,
8248            _ => {
8249                return Err(RuntimeError::new(
8250                    "secure_random_bytes() requires integer length",
8251                ))
8252            }
8253        };
8254
8255        if length > 1024 * 1024 {
8256            return Err(RuntimeError::new("secure_random_bytes() max 1MB"));
8257        }
8258
8259        let mut bytes = vec![0u8; length];
8260        rand::thread_rng().fill_bytes(&mut bytes);
8261        Ok(bytes_to_array(&bytes))
8262    });
8263
8264    // secure_random_hex - Random hex string
8265    define(interp, "secure_random_hex", Some(1), |_, args| {
8266        use rand::RngCore;
8267
8268        let byte_length = match &args[0] {
8269            Value::Int(n) => *n as usize,
8270            _ => {
8271                return Err(RuntimeError::new(
8272                    "secure_random_hex() requires integer length",
8273                ))
8274            }
8275        };
8276
8277        if byte_length > 1024 * 1024 {
8278            return Err(RuntimeError::new("secure_random_hex() max 1MB"));
8279        }
8280
8281        let mut bytes = vec![0u8; byte_length];
8282        rand::thread_rng().fill_bytes(&mut bytes);
8283        Ok(Value::String(Rc::new(
8284            bytes.iter().map(|b| format!("{:02x}", b)).collect(),
8285        )))
8286    });
8287
8288    // generate_key - Generate symmetric key
8289    define(interp, "generate_key", Some(1), |_, args| {
8290        use rand::RngCore;
8291
8292        let bits = match &args[0] {
8293            Value::Int(n) => *n as usize,
8294            _ => return Err(RuntimeError::new("generate_key() requires bit length")),
8295        };
8296
8297        if bits % 8 != 0 {
8298            return Err(RuntimeError::new(
8299                "generate_key() bit length must be multiple of 8",
8300            ));
8301        }
8302        if bits > 512 {
8303            return Err(RuntimeError::new("generate_key() max 512 bits"));
8304        }
8305
8306        let bytes = bits / 8;
8307        let mut key = vec![0u8; bytes];
8308        rand::thread_rng().fill_bytes(&mut key);
8309        Ok(Value::String(Rc::new(
8310            key.iter().map(|b| format!("{:02x}", b)).collect(),
8311        )))
8312    });
8313
8314    // ========================================================================
8315    // ENCODING
8316    // ========================================================================
8317
8318    // base64_encode
8319    define(interp, "base64_encode", Some(1), |_, args| {
8320        let data = extract_bytes(&args[0], "base64_encode")?;
8321        Ok(Value::String(Rc::new(
8322            general_purpose::STANDARD.encode(&data),
8323        )))
8324    });
8325
8326    // base64_decode
8327    define(interp, "base64_decode", Some(1), |_, args| {
8328        let encoded = match &args[0] {
8329            Value::String(s) => s.to_string(),
8330            _ => return Err(RuntimeError::new("base64_decode() requires string")),
8331        };
8332
8333        match general_purpose::STANDARD.decode(&encoded) {
8334            Ok(bytes) => match String::from_utf8(bytes.clone()) {
8335                Ok(s) => Ok(Value::String(Rc::new(s))),
8336                Err(_) => Ok(bytes_to_array(&bytes)),
8337            },
8338            Err(e) => Err(RuntimeError::new(format!("base64_decode() error: {}", e))),
8339        }
8340    });
8341
8342    // hex_encode
8343    define(interp, "hex_encode", Some(1), |_, args| {
8344        let data = extract_bytes(&args[0], "hex_encode")?;
8345        Ok(Value::String(Rc::new(
8346            data.iter().map(|b| format!("{:02x}", b)).collect(),
8347        )))
8348    });
8349
8350    // hex_decode
8351    define(interp, "hex_decode", Some(1), |_, args| {
8352        let hex_str = match &args[0] {
8353            Value::String(s) => s.to_string(),
8354            _ => return Err(RuntimeError::new("hex_decode() requires string")),
8355        };
8356
8357        let hex_str = hex_str.trim();
8358        if hex_str.len() % 2 != 0 {
8359            return Err(RuntimeError::new(
8360                "hex_decode() requires even-length hex string",
8361            ));
8362        }
8363
8364        let bytes: Vec<Value> = (0..hex_str.len())
8365            .step_by(2)
8366            .map(|i| u8::from_str_radix(&hex_str[i..i + 2], 16).map(|b| Value::Int(b as i64)))
8367            .collect::<Result<Vec<_>, _>>()
8368            .map_err(|_| RuntimeError::new("hex_decode() invalid hex"))?;
8369        Ok(Value::Array(Rc::new(RefCell::new(bytes))))
8370    });
8371
8372    // ========================================================================
8373    // CONSTANT-TIME OPERATIONS
8374    // ========================================================================
8375
8376    // constant_time_eq - Constant-time comparison (prevents timing attacks)
8377    define(interp, "constant_time_eq", Some(2), |_, args| {
8378        let a = extract_bytes(&args[0], "constant_time_eq")?;
8379        let b = extract_bytes(&args[1], "constant_time_eq")?;
8380
8381        if a.len() != b.len() {
8382            return Ok(Value::Bool(false));
8383        }
8384
8385        let mut result = 0u8;
8386        for (x, y) in a.iter().zip(b.iter()) {
8387            result |= x ^ y;
8388        }
8389        Ok(Value::Bool(result == 0))
8390    });
8391
8392    // ========================================================================
8393    // CRYPTO INFO
8394    // ========================================================================
8395
8396    // crypto_info - Get crypto module capabilities
8397    define(interp, "crypto_info", Some(0), |_, _| {
8398        let mut info = HashMap::new();
8399        info.insert(
8400            "version".to_string(),
8401            Value::String(Rc::new("2.0".to_string())),
8402        );
8403        info.insert(
8404            "phase".to_string(),
8405            Value::String(Rc::new("Evidential Cryptography".to_string())),
8406        );
8407
8408        let capabilities = vec![
8409            "sha256",
8410            "sha512",
8411            "sha3_256",
8412            "sha3_512",
8413            "blake3",
8414            "md5",
8415            "aes_gcm_encrypt",
8416            "aes_gcm_decrypt",
8417            "chacha20_encrypt",
8418            "chacha20_decrypt",
8419            "ed25519_keygen",
8420            "ed25519_sign",
8421            "ed25519_verify",
8422            "x25519_keygen",
8423            "x25519_exchange",
8424            "argon2_hash",
8425            "argon2_verify",
8426            "hkdf_expand",
8427            "pbkdf2_derive",
8428            "hmac_sha256",
8429            "hmac_sha512",
8430            "hmac_verify",
8431            "secure_random_bytes",
8432            "secure_random_hex",
8433            "generate_key",
8434            "base64_encode",
8435            "base64_decode",
8436            "hex_encode",
8437            "hex_decode",
8438            "constant_time_eq",
8439        ];
8440        let cap_values: Vec<Value> = capabilities
8441            .iter()
8442            .map(|s| Value::String(Rc::new(s.to_string())))
8443            .collect();
8444        info.insert(
8445            "functions".to_string(),
8446            Value::Array(Rc::new(RefCell::new(cap_values))),
8447        );
8448
8449        Ok(Value::Map(Rc::new(RefCell::new(info))))
8450    });
8451}
8452
8453// ============================================================================
8454// REGEX FUNCTIONS
8455// ============================================================================
8456
8457fn register_regex(interp: &mut Interpreter) {
8458    // regex_match - check if string matches pattern
8459    define(interp, "regex_match", Some(2), |_, args| {
8460        let pattern = match &args[0] {
8461            Value::String(s) => s.to_string(),
8462            _ => return Err(RuntimeError::new("regex_match() requires string pattern")),
8463        };
8464        let text = match &args[1] {
8465            Value::String(s) => s.to_string(),
8466            _ => return Err(RuntimeError::new("regex_match() requires string text")),
8467        };
8468
8469        match Regex::new(&pattern) {
8470            Ok(re) => Ok(Value::Bool(re.is_match(&text))),
8471            Err(e) => Err(RuntimeError::new(format!(
8472                "regex_match() invalid pattern: {}",
8473                e
8474            ))),
8475        }
8476    });
8477
8478    // regex_find - find first match
8479    define(interp, "regex_find", Some(2), |_, args| {
8480        let pattern = match &args[0] {
8481            Value::String(s) => s.to_string(),
8482            _ => return Err(RuntimeError::new("regex_find() requires string pattern")),
8483        };
8484        let text = match &args[1] {
8485            Value::String(s) => s.to_string(),
8486            _ => return Err(RuntimeError::new("regex_find() requires string text")),
8487        };
8488
8489        match Regex::new(&pattern) {
8490            Ok(re) => match re.find(&text) {
8491                Some(m) => Ok(Value::String(Rc::new(m.as_str().to_string()))),
8492                None => Ok(Value::Null),
8493            },
8494            Err(e) => Err(RuntimeError::new(format!(
8495                "regex_find() invalid pattern: {}",
8496                e
8497            ))),
8498        }
8499    });
8500
8501    // regex_find_all - find all matches
8502    define(interp, "regex_find_all", Some(2), |_, args| {
8503        let pattern = match &args[0] {
8504            Value::String(s) => s.to_string(),
8505            _ => {
8506                return Err(RuntimeError::new(
8507                    "regex_find_all() requires string pattern",
8508                ))
8509            }
8510        };
8511        let text = match &args[1] {
8512            Value::String(s) => s.to_string(),
8513            _ => return Err(RuntimeError::new("regex_find_all() requires string text")),
8514        };
8515
8516        match Regex::new(&pattern) {
8517            Ok(re) => {
8518                let matches: Vec<Value> = re
8519                    .find_iter(&text)
8520                    .map(|m| Value::String(Rc::new(m.as_str().to_string())))
8521                    .collect();
8522                Ok(Value::Array(Rc::new(RefCell::new(matches))))
8523            }
8524            Err(e) => Err(RuntimeError::new(format!(
8525                "regex_find_all() invalid pattern: {}",
8526                e
8527            ))),
8528        }
8529    });
8530
8531    // regex_replace - replace first match
8532    define(interp, "regex_replace", Some(3), |_, args| {
8533        let pattern = match &args[0] {
8534            Value::String(s) => s.to_string(),
8535            _ => return Err(RuntimeError::new("regex_replace() requires string pattern")),
8536        };
8537        let text = match &args[1] {
8538            Value::String(s) => s.to_string(),
8539            _ => return Err(RuntimeError::new("regex_replace() requires string text")),
8540        };
8541        let replacement = match &args[2] {
8542            Value::String(s) => s.to_string(),
8543            _ => {
8544                return Err(RuntimeError::new(
8545                    "regex_replace() requires string replacement",
8546                ))
8547            }
8548        };
8549
8550        match Regex::new(&pattern) {
8551            Ok(re) => {
8552                let result = re.replace(&text, replacement.as_str());
8553                Ok(Value::String(Rc::new(result.to_string())))
8554            }
8555            Err(e) => Err(RuntimeError::new(format!(
8556                "regex_replace() invalid pattern: {}",
8557                e
8558            ))),
8559        }
8560    });
8561
8562    // regex_replace_all - replace all matches
8563    define(interp, "regex_replace_all", Some(3), |_, args| {
8564        let pattern = match &args[0] {
8565            Value::String(s) => s.to_string(),
8566            _ => {
8567                return Err(RuntimeError::new(
8568                    "regex_replace_all() requires string pattern",
8569                ))
8570            }
8571        };
8572        let text = match &args[1] {
8573            Value::String(s) => s.to_string(),
8574            _ => {
8575                return Err(RuntimeError::new(
8576                    "regex_replace_all() requires string text",
8577                ))
8578            }
8579        };
8580        let replacement = match &args[2] {
8581            Value::String(s) => s.to_string(),
8582            _ => {
8583                return Err(RuntimeError::new(
8584                    "regex_replace_all() requires string replacement",
8585                ))
8586            }
8587        };
8588
8589        match Regex::new(&pattern) {
8590            Ok(re) => {
8591                let result = re.replace_all(&text, replacement.as_str());
8592                Ok(Value::String(Rc::new(result.to_string())))
8593            }
8594            Err(e) => Err(RuntimeError::new(format!(
8595                "regex_replace_all() invalid pattern: {}",
8596                e
8597            ))),
8598        }
8599    });
8600
8601    // regex_split - split by pattern
8602    define(interp, "regex_split", Some(2), |_, args| {
8603        let pattern = match &args[0] {
8604            Value::String(s) => s.to_string(),
8605            _ => return Err(RuntimeError::new("regex_split() requires string pattern")),
8606        };
8607        let text = match &args[1] {
8608            Value::String(s) => s.to_string(),
8609            _ => return Err(RuntimeError::new("regex_split() requires string text")),
8610        };
8611
8612        match Regex::new(&pattern) {
8613            Ok(re) => {
8614                let parts: Vec<Value> = re
8615                    .split(&text)
8616                    .map(|s| Value::String(Rc::new(s.to_string())))
8617                    .collect();
8618                Ok(Value::Array(Rc::new(RefCell::new(parts))))
8619            }
8620            Err(e) => Err(RuntimeError::new(format!(
8621                "regex_split() invalid pattern: {}",
8622                e
8623            ))),
8624        }
8625    });
8626
8627    // regex_captures - capture groups
8628    define(interp, "regex_captures", Some(2), |_, args| {
8629        let pattern = match &args[0] {
8630            Value::String(s) => s.to_string(),
8631            _ => {
8632                return Err(RuntimeError::new(
8633                    "regex_captures() requires string pattern",
8634                ))
8635            }
8636        };
8637        let text = match &args[1] {
8638            Value::String(s) => s.to_string(),
8639            _ => return Err(RuntimeError::new("regex_captures() requires string text")),
8640        };
8641
8642        match Regex::new(&pattern) {
8643            Ok(re) => match re.captures(&text) {
8644                Some(caps) => {
8645                    let captures: Vec<Value> = caps
8646                        .iter()
8647                        .map(|m| {
8648                            m.map(|m| Value::String(Rc::new(m.as_str().to_string())))
8649                                .unwrap_or(Value::Null)
8650                        })
8651                        .collect();
8652                    Ok(Value::Array(Rc::new(RefCell::new(captures))))
8653                }
8654                None => Ok(Value::Null),
8655            },
8656            Err(e) => Err(RuntimeError::new(format!(
8657                "regex_captures() invalid pattern: {}",
8658                e
8659            ))),
8660        }
8661    });
8662}
8663
8664// ============================================================================
8665// UUID FUNCTIONS
8666// ============================================================================
8667
8668fn register_uuid(interp: &mut Interpreter) {
8669    // uuid_v4 - generate random UUID v4
8670    define(interp, "uuid_v4", Some(0), |_, _| {
8671        let id = Uuid::new_v4();
8672        Ok(Value::String(Rc::new(id.to_string())))
8673    });
8674
8675    // uuid_nil - get nil UUID (all zeros)
8676    define(interp, "uuid_nil", Some(0), |_, _| {
8677        Ok(Value::String(Rc::new(Uuid::nil().to_string())))
8678    });
8679
8680    // uuid_parse - parse UUID string
8681    define(interp, "uuid_parse", Some(1), |_, args| {
8682        let s = match &args[0] {
8683            Value::String(s) => s.to_string(),
8684            _ => return Err(RuntimeError::new("uuid_parse() requires string")),
8685        };
8686
8687        match Uuid::parse_str(&s) {
8688            Ok(id) => Ok(Value::String(Rc::new(id.to_string()))),
8689            Err(e) => Err(RuntimeError::new(format!("uuid_parse() error: {}", e))),
8690        }
8691    });
8692
8693    // uuid_is_valid - check if string is valid UUID
8694    define(interp, "uuid_is_valid", Some(1), |_, args| {
8695        let s = match &args[0] {
8696            Value::String(s) => s.to_string(),
8697            _ => return Ok(Value::Bool(false)),
8698        };
8699        Ok(Value::Bool(Uuid::parse_str(&s).is_ok()))
8700    });
8701}
8702
8703// ============================================================================
8704// SYSTEM FUNCTIONS
8705// ============================================================================
8706
8707fn register_system(interp: &mut Interpreter) {
8708    // env_get - get environment variable
8709    define(interp, "env_get", Some(1), |_, args| {
8710        let key = match &args[0] {
8711            Value::String(s) => s.to_string(),
8712            _ => return Err(RuntimeError::new("env_get() requires string key")),
8713        };
8714
8715        match std::env::var(&key) {
8716            Ok(val) => Ok(Value::String(Rc::new(val))),
8717            Err(_) => Ok(Value::Null),
8718        }
8719    });
8720
8721    // env_set - set environment variable
8722    define(interp, "env_set", Some(2), |_, args| {
8723        let key = match &args[0] {
8724            Value::String(s) => s.to_string(),
8725            _ => return Err(RuntimeError::new("env_set() requires string key")),
8726        };
8727        let val = match &args[1] {
8728            Value::String(s) => s.to_string(),
8729            _ => format!("{}", args[1]),
8730        };
8731
8732        std::env::set_var(&key, &val);
8733        Ok(Value::Null)
8734    });
8735
8736    // env_remove - remove environment variable
8737    define(interp, "env_remove", Some(1), |_, args| {
8738        let key = match &args[0] {
8739            Value::String(s) => s.to_string(),
8740            _ => return Err(RuntimeError::new("env_remove() requires string key")),
8741        };
8742
8743        std::env::remove_var(&key);
8744        Ok(Value::Null)
8745    });
8746
8747    // env_vars - get all environment variables as map
8748    define(interp, "env_vars", Some(0), |_, _| {
8749        let mut map = HashMap::new();
8750        for (key, val) in std::env::vars() {
8751            map.insert(key, Value::String(Rc::new(val)));
8752        }
8753        Ok(Value::Map(Rc::new(RefCell::new(map))))
8754    });
8755
8756    // std::env::var - get single environment variable as Result<String, VarError>
8757    define(interp, "std·env·var", Some(1), |_, args| {
8758        let key = match &args[0] {
8759            Value::String(s) => s.as_str().to_string(),
8760            _ => return Err(RuntimeError::new("env::var expects string key")),
8761        };
8762        match std::env::var(&key) {
8763            Ok(val) => Ok(Value::Variant {
8764                enum_name: "Result".to_string(),
8765                variant_name: "Ok".to_string(),
8766                fields: Some(Rc::new(vec![Value::String(Rc::new(val))])),
8767            }),
8768            Err(_) => Ok(Value::Variant {
8769                enum_name: "Result".to_string(),
8770                variant_name: "Err".to_string(),
8771                fields: Some(Rc::new(vec![Value::String(Rc::new("environment variable not found".to_string()))])),
8772            }),
8773        }
8774    });
8775
8776    // std::env::temp_dir - get system temp directory
8777    define(interp, "std·env·temp_dir", Some(0), |_, _| {
8778        let temp_dir = std::env::temp_dir();
8779        Ok(Value::String(Rc::new(temp_dir.to_string_lossy().to_string())))
8780    });
8781
8782    // Also register with alternate names
8783    define(interp, "temp_dir", Some(0), |_, _| {
8784        let temp_dir = std::env::temp_dir();
8785        Ok(Value::String(Rc::new(temp_dir.to_string_lossy().to_string())))
8786    });
8787
8788    // std::env::current_dir - get current working directory (alternate name)
8789    define(interp, "std·env·current_dir", Some(0), |_, _| {
8790        match std::env::current_dir() {
8791            Ok(path) => Ok(Value::String(Rc::new(path.to_string_lossy().to_string()))),
8792            Err(e) => Err(RuntimeError::new(format!("current_dir() error: {}", e))),
8793        }
8794    });
8795
8796    // std::env::args - get command line arguments (filtered to exclude interpreter args)
8797    define(interp, "std·env·args", Some(0), |interp, _| {
8798        let args: Vec<Value> = if interp.program_args.as_ref().map(|v| v.is_empty()).unwrap_or(true) {
8799            // Fallback: return all args if program_args not set
8800            std::env::args()
8801                .map(|s| Value::String(Rc::new(s)))
8802                .collect()
8803        } else {
8804            // Return filtered program args
8805            interp.program_args.as_ref().unwrap().iter()
8806                .map(|a| Value::String(Rc::new(a.clone())))
8807                .collect()
8808        };
8809        Ok(Value::Array(Rc::new(RefCell::new(args))))
8810    });
8811
8812    // args - get command line arguments (filtered to exclude interpreter args)
8813    define(interp, "args", Some(0), |interp, _| {
8814        let args: Vec<Value> = if interp.program_args.as_ref().map(|v| v.is_empty()).unwrap_or(true) {
8815            // Fallback: return all args if program_args not set
8816            std::env::args()
8817                .map(|s| Value::String(Rc::new(s)))
8818                .collect()
8819        } else {
8820            // Return filtered program args
8821            interp.program_args.as_ref().unwrap().iter()
8822                .map(|a| Value::String(Rc::new(a.clone())))
8823                .collect()
8824        };
8825        Ok(Value::Array(Rc::new(RefCell::new(args))))
8826    });
8827
8828    // cwd - get current working directory
8829    define(interp, "cwd", Some(0), |_, _| {
8830        match std::env::current_dir() {
8831            Ok(path) => Ok(Value::String(Rc::new(path.to_string_lossy().to_string()))),
8832            Err(e) => Err(RuntimeError::new(format!("cwd() error: {}", e))),
8833        }
8834    });
8835
8836    // chdir - change current directory
8837    define(interp, "chdir", Some(1), |_, args| {
8838        let path = match &args[0] {
8839            Value::String(s) => s.to_string(),
8840            _ => return Err(RuntimeError::new("chdir() requires string path")),
8841        };
8842
8843        match std::env::set_current_dir(&path) {
8844            Ok(()) => Ok(Value::Null),
8845            Err(e) => Err(RuntimeError::new(format!("chdir() error: {}", e))),
8846        }
8847    });
8848
8849    // hostname - get system hostname
8850    define(interp, "hostname", Some(0), |_, _| {
8851        // Try to read from /etc/hostname or use fallback
8852        match std::fs::read_to_string("/etc/hostname") {
8853            Ok(name) => Ok(Value::String(Rc::new(name.trim().to_string()))),
8854            Err(_) => Ok(Value::String(Rc::new("unknown".to_string()))),
8855        }
8856    });
8857
8858    // pid - get current process ID
8859    define(interp, "pid", Some(0), |_, _| {
8860        Ok(Value::Int(std::process::id() as i64))
8861    });
8862
8863    // exit - exit the program with code
8864    define(interp, "exit", Some(1), |_, args| {
8865        let code = match &args[0] {
8866            Value::Int(n) => *n as i32,
8867            _ => 0,
8868        };
8869        std::process::exit(code);
8870    });
8871
8872    // std::process::exit - exit the program with code (qualified name)
8873    define(interp, "std·process·exit", Some(1), |_, args| {
8874        let code = match &args[0] {
8875            Value::Int(n) => *n as i32,
8876            _ => 0,
8877        };
8878        std::process::exit(code);
8879    });
8880
8881    // shell - execute shell command and return output
8882    define(interp, "shell", Some(1), |_, args| {
8883        let cmd = match &args[0] {
8884            Value::String(s) => s.to_string(),
8885            _ => return Err(RuntimeError::new("shell() requires string command")),
8886        };
8887
8888        match std::process::Command::new("sh")
8889            .arg("-c")
8890            .arg(&cmd)
8891            .output()
8892        {
8893            Ok(output) => {
8894                let stdout = String::from_utf8_lossy(&output.stdout).to_string();
8895                let stderr = String::from_utf8_lossy(&output.stderr).to_string();
8896                let code = output.status.code().unwrap_or(-1);
8897
8898                let mut result = HashMap::new();
8899                result.insert("stdout".to_string(), Value::String(Rc::new(stdout)));
8900                result.insert("stderr".to_string(), Value::String(Rc::new(stderr)));
8901                result.insert("code".to_string(), Value::Int(code as i64));
8902                result.insert("success".to_string(), Value::Bool(output.status.success()));
8903
8904                Ok(Value::Map(Rc::new(RefCell::new(result))))
8905            }
8906            Err(e) => Err(RuntimeError::new(format!("shell() error: {}", e))),
8907        }
8908    });
8909
8910    // platform - get OS name
8911    define(interp, "platform", Some(0), |_, _| {
8912        Ok(Value::String(Rc::new(std::env::consts::OS.to_string())))
8913    });
8914
8915    // arch - get CPU architecture
8916    define(interp, "arch", Some(0), |_, _| {
8917        Ok(Value::String(Rc::new(std::env::consts::ARCH.to_string())))
8918    });
8919
8920    // num_cpus::get - get number of available CPUs
8921    define(interp, "num_cpus·get", Some(0), |_, _| {
8922        Ok(Value::Int(num_cpus::get() as i64))
8923    });
8924
8925    // num_cpus::get_physical - get number of physical CPU cores
8926    define(interp, "num_cpus·get_physical", Some(0), |_, _| {
8927        Ok(Value::Int(num_cpus::get_physical() as i64))
8928    });
8929}
8930
8931// ============================================================================
8932// STATISTICS FUNCTIONS
8933// ============================================================================
8934
8935fn register_stats(interp: &mut Interpreter) {
8936    // Helper to extract numbers from array
8937    fn extract_numbers(val: &Value) -> Result<Vec<f64>, RuntimeError> {
8938        match val {
8939            Value::Array(arr) => {
8940                let arr = arr.borrow();
8941                let mut nums = Vec::new();
8942                for v in arr.iter() {
8943                    match v {
8944                        Value::Int(n) => nums.push(*n as f64),
8945                        Value::Float(f) => nums.push(*f),
8946                        _ => {
8947                            return Err(RuntimeError::new("stats functions require numeric array"))
8948                        }
8949                    }
8950                }
8951                Ok(nums)
8952            }
8953            _ => Err(RuntimeError::new("stats functions require array")),
8954        }
8955    }
8956
8957    // mean - arithmetic mean
8958    define(interp, "mean", Some(1), |_, args| {
8959        let nums = extract_numbers(&args[0])?;
8960        if nums.is_empty() {
8961            return Ok(Value::Float(0.0));
8962        }
8963        let sum: f64 = nums.iter().sum();
8964        Ok(Value::Float(sum / nums.len() as f64))
8965    });
8966
8967    // median - middle value
8968    define(interp, "median", Some(1), |_, args| {
8969        let mut nums = extract_numbers(&args[0])?;
8970        if nums.is_empty() {
8971            return Ok(Value::Float(0.0));
8972        }
8973        nums.sort_by(|a, b| a.partial_cmp(b).unwrap());
8974        let len = nums.len();
8975        if len % 2 == 0 {
8976            Ok(Value::Float((nums[len / 2 - 1] + nums[len / 2]) / 2.0))
8977        } else {
8978            Ok(Value::Float(nums[len / 2]))
8979        }
8980    });
8981
8982    // mode - most frequent value
8983    define(interp, "mode", Some(1), |_, args| {
8984        let nums = extract_numbers(&args[0])?;
8985        if nums.is_empty() {
8986            return Ok(Value::Null);
8987        }
8988
8989        let mut counts: HashMap<String, usize> = HashMap::new();
8990        for n in &nums {
8991            let key = format!("{:.10}", n);
8992            *counts.entry(key).or_insert(0) += 1;
8993        }
8994
8995        let max_count = counts.values().max().unwrap_or(&0);
8996        for n in &nums {
8997            let key = format!("{:.10}", n);
8998            if counts.get(&key) == Some(max_count) {
8999                return Ok(Value::Float(*n));
9000            }
9001        }
9002        Ok(Value::Null)
9003    });
9004
9005    // variance - population variance
9006    define(interp, "variance", Some(1), |_, args| {
9007        let nums = extract_numbers(&args[0])?;
9008        if nums.is_empty() {
9009            return Ok(Value::Float(0.0));
9010        }
9011        let mean: f64 = nums.iter().sum::<f64>() / nums.len() as f64;
9012        let variance: f64 =
9013            nums.iter().map(|x| (x - mean).powi(2)).sum::<f64>() / nums.len() as f64;
9014        Ok(Value::Float(variance))
9015    });
9016
9017    // stddev - standard deviation
9018    define(interp, "stddev", Some(1), |_, args| {
9019        let nums = extract_numbers(&args[0])?;
9020        if nums.is_empty() {
9021            return Ok(Value::Float(0.0));
9022        }
9023        let mean: f64 = nums.iter().sum::<f64>() / nums.len() as f64;
9024        let variance: f64 =
9025            nums.iter().map(|x| (x - mean).powi(2)).sum::<f64>() / nums.len() as f64;
9026        Ok(Value::Float(variance.sqrt()))
9027    });
9028
9029    // percentile - compute nth percentile
9030    define(interp, "percentile", Some(2), |_, args| {
9031        let mut nums = extract_numbers(&args[0])?;
9032        let p = match &args[1] {
9033            Value::Int(n) => *n as f64,
9034            Value::Float(f) => *f,
9035            _ => {
9036                return Err(RuntimeError::new(
9037                    "percentile() requires numeric percentile",
9038                ))
9039            }
9040        };
9041
9042        if nums.is_empty() {
9043            return Ok(Value::Float(0.0));
9044        }
9045
9046        nums.sort_by(|a, b| a.partial_cmp(b).unwrap());
9047        let idx = (p / 100.0 * (nums.len() - 1) as f64).round() as usize;
9048        Ok(Value::Float(nums[idx.min(nums.len() - 1)]))
9049    });
9050
9051    // correlation - Pearson correlation coefficient
9052    define(interp, "correlation", Some(2), |_, args| {
9053        let x = extract_numbers(&args[0])?;
9054        let y = extract_numbers(&args[1])?;
9055
9056        if x.len() != y.len() || x.is_empty() {
9057            return Err(RuntimeError::new(
9058                "correlation() requires equal-length non-empty arrays",
9059            ));
9060        }
9061
9062        let n = x.len() as f64;
9063        let mean_x: f64 = x.iter().sum::<f64>() / n;
9064        let mean_y: f64 = y.iter().sum::<f64>() / n;
9065
9066        let mut cov = 0.0;
9067        let mut var_x = 0.0;
9068        let mut var_y = 0.0;
9069
9070        for i in 0..x.len() {
9071            let dx = x[i] - mean_x;
9072            let dy = y[i] - mean_y;
9073            cov += dx * dy;
9074            var_x += dx * dx;
9075            var_y += dy * dy;
9076        }
9077
9078        if var_x == 0.0 || var_y == 0.0 {
9079            return Ok(Value::Float(0.0));
9080        }
9081
9082        Ok(Value::Float(cov / (var_x.sqrt() * var_y.sqrt())))
9083    });
9084
9085    // range - difference between max and min
9086    define(interp, "range", Some(1), |_, args| {
9087        let nums = extract_numbers(&args[0])?;
9088        if nums.is_empty() {
9089            return Ok(Value::Float(0.0));
9090        }
9091        let min = nums.iter().cloned().fold(f64::INFINITY, f64::min);
9092        let max = nums.iter().cloned().fold(f64::NEG_INFINITY, f64::max);
9093        Ok(Value::Float(max - min))
9094    });
9095
9096    // zscore - compute z-scores for array
9097    define(interp, "zscore", Some(1), |_, args| {
9098        let nums = extract_numbers(&args[0])?;
9099        if nums.is_empty() {
9100            return Ok(Value::Array(Rc::new(RefCell::new(vec![]))));
9101        }
9102
9103        let mean: f64 = nums.iter().sum::<f64>() / nums.len() as f64;
9104        let variance: f64 =
9105            nums.iter().map(|x| (x - mean).powi(2)).sum::<f64>() / nums.len() as f64;
9106        let stddev = variance.sqrt();
9107
9108        if stddev == 0.0 {
9109            let zeros: Vec<Value> = nums.iter().map(|_| Value::Float(0.0)).collect();
9110            return Ok(Value::Array(Rc::new(RefCell::new(zeros))));
9111        }
9112
9113        let zscores: Vec<Value> = nums
9114            .iter()
9115            .map(|x| Value::Float((x - mean) / stddev))
9116            .collect();
9117        Ok(Value::Array(Rc::new(RefCell::new(zscores))))
9118    });
9119}
9120
9121// ============================================================================
9122// MATRIX FUNCTIONS
9123// ============================================================================
9124
9125fn register_matrix(interp: &mut Interpreter) {
9126    // Helper to extract 2D matrix from nested arrays
9127    fn extract_matrix(val: &Value) -> Result<Vec<Vec<f64>>, RuntimeError> {
9128        match val {
9129            Value::Array(arr) => {
9130                let arr = arr.borrow();
9131                let mut matrix = Vec::new();
9132                for row in arr.iter() {
9133                    match row {
9134                        Value::Array(row_arr) => {
9135                            let row_arr = row_arr.borrow();
9136                            let mut row_vec = Vec::new();
9137                            for v in row_arr.iter() {
9138                                match v {
9139                                    Value::Int(n) => row_vec.push(*n as f64),
9140                                    Value::Float(f) => row_vec.push(*f),
9141                                    _ => {
9142                                        return Err(RuntimeError::new(
9143                                            "matrix requires numeric values",
9144                                        ))
9145                                    }
9146                                }
9147                            }
9148                            matrix.push(row_vec);
9149                        }
9150                        _ => return Err(RuntimeError::new("matrix requires 2D array")),
9151                    }
9152                }
9153                Ok(matrix)
9154            }
9155            _ => Err(RuntimeError::new("matrix requires array")),
9156        }
9157    }
9158
9159    fn matrix_to_value(m: Vec<Vec<f64>>) -> Value {
9160        let rows: Vec<Value> = m
9161            .into_iter()
9162            .map(|row| {
9163                let cols: Vec<Value> = row.into_iter().map(Value::Float).collect();
9164                Value::Array(Rc::new(RefCell::new(cols)))
9165            })
9166            .collect();
9167        Value::Array(Rc::new(RefCell::new(rows)))
9168    }
9169
9170    // matrix_new - create matrix filled with value
9171    define(interp, "matrix_new", Some(3), |_, args| {
9172        let rows = match &args[0] {
9173            Value::Int(n) => *n as usize,
9174            _ => return Err(RuntimeError::new("matrix_new() requires integer rows")),
9175        };
9176        let cols = match &args[1] {
9177            Value::Int(n) => *n as usize,
9178            _ => return Err(RuntimeError::new("matrix_new() requires integer cols")),
9179        };
9180        let fill = match &args[2] {
9181            Value::Int(n) => *n as f64,
9182            Value::Float(f) => *f,
9183            _ => 0.0,
9184        };
9185
9186        let matrix = vec![vec![fill; cols]; rows];
9187        Ok(matrix_to_value(matrix))
9188    });
9189
9190    // matrix_identity - create identity matrix
9191    define(interp, "matrix_identity", Some(1), |_, args| {
9192        let size = match &args[0] {
9193            Value::Int(n) => *n as usize,
9194            _ => return Err(RuntimeError::new("matrix_identity() requires integer size")),
9195        };
9196
9197        let mut matrix = vec![vec![0.0; size]; size];
9198        for i in 0..size {
9199            matrix[i][i] = 1.0;
9200        }
9201        Ok(matrix_to_value(matrix))
9202    });
9203
9204    // matrix_add - add two matrices
9205    define(interp, "matrix_add", Some(2), |_, args| {
9206        let a = extract_matrix(&args[0])?;
9207        let b = extract_matrix(&args[1])?;
9208
9209        if a.len() != b.len() || a.is_empty() || a[0].len() != b[0].len() {
9210            return Err(RuntimeError::new(
9211                "matrix_add() requires same-size matrices",
9212            ));
9213        }
9214
9215        let result: Vec<Vec<f64>> = a
9216            .iter()
9217            .zip(b.iter())
9218            .map(|(row_a, row_b)| row_a.iter().zip(row_b.iter()).map(|(x, y)| x + y).collect())
9219            .collect();
9220
9221        Ok(matrix_to_value(result))
9222    });
9223
9224    // matrix_sub - subtract two matrices
9225    define(interp, "matrix_sub", Some(2), |_, args| {
9226        let a = extract_matrix(&args[0])?;
9227        let b = extract_matrix(&args[1])?;
9228
9229        if a.len() != b.len() || a.is_empty() || a[0].len() != b[0].len() {
9230            return Err(RuntimeError::new(
9231                "matrix_sub() requires same-size matrices",
9232            ));
9233        }
9234
9235        let result: Vec<Vec<f64>> = a
9236            .iter()
9237            .zip(b.iter())
9238            .map(|(row_a, row_b)| row_a.iter().zip(row_b.iter()).map(|(x, y)| x - y).collect())
9239            .collect();
9240
9241        Ok(matrix_to_value(result))
9242    });
9243
9244    // matrix_mul - multiply two matrices
9245    define(interp, "matrix_mul", Some(2), |_, args| {
9246        let a = extract_matrix(&args[0])?;
9247        let b = extract_matrix(&args[1])?;
9248
9249        if a.is_empty() || b.is_empty() || a[0].len() != b.len() {
9250            return Err(RuntimeError::new(
9251                "matrix_mul() requires compatible matrices (a.cols == b.rows)",
9252            ));
9253        }
9254
9255        let rows = a.len();
9256        let cols = b[0].len();
9257        let inner = b.len();
9258
9259        let mut result = vec![vec![0.0; cols]; rows];
9260        for i in 0..rows {
9261            for j in 0..cols {
9262                for k in 0..inner {
9263                    result[i][j] += a[i][k] * b[k][j];
9264                }
9265            }
9266        }
9267
9268        Ok(matrix_to_value(result))
9269    });
9270
9271    // matrix_scale - multiply matrix by scalar
9272    define(interp, "matrix_scale", Some(2), |_, args| {
9273        let m = extract_matrix(&args[0])?;
9274        let scale = match &args[1] {
9275            Value::Int(n) => *n as f64,
9276            Value::Float(f) => *f,
9277            _ => return Err(RuntimeError::new("matrix_scale() requires numeric scalar")),
9278        };
9279
9280        let result: Vec<Vec<f64>> = m
9281            .iter()
9282            .map(|row| row.iter().map(|x| x * scale).collect())
9283            .collect();
9284
9285        Ok(matrix_to_value(result))
9286    });
9287
9288    // matrix_transpose - transpose matrix
9289    define(interp, "matrix_transpose", Some(1), |_, args| {
9290        let m = extract_matrix(&args[0])?;
9291        if m.is_empty() {
9292            return Ok(Value::Array(Rc::new(RefCell::new(vec![]))));
9293        }
9294
9295        let rows = m.len();
9296        let cols = m[0].len();
9297        let mut result = vec![vec![0.0; rows]; cols];
9298
9299        for i in 0..rows {
9300            for j in 0..cols {
9301                result[j][i] = m[i][j];
9302            }
9303        }
9304
9305        Ok(matrix_to_value(result))
9306    });
9307
9308    // matrix_det - determinant (for 2x2 and 3x3)
9309    define(interp, "matrix_det", Some(1), |_, args| {
9310        let m = extract_matrix(&args[0])?;
9311
9312        if m.is_empty() || m.len() != m[0].len() {
9313            return Err(RuntimeError::new("matrix_det() requires square matrix"));
9314        }
9315
9316        let n = m.len();
9317        match n {
9318            1 => Ok(Value::Float(m[0][0])),
9319            2 => Ok(Value::Float(m[0][0] * m[1][1] - m[0][1] * m[1][0])),
9320            3 => {
9321                let det = m[0][0] * (m[1][1] * m[2][2] - m[1][2] * m[2][1])
9322                    - m[0][1] * (m[1][0] * m[2][2] - m[1][2] * m[2][0])
9323                    + m[0][2] * (m[1][0] * m[2][1] - m[1][1] * m[2][0]);
9324                Ok(Value::Float(det))
9325            }
9326            _ => Err(RuntimeError::new(
9327                "matrix_det() only supports up to 3x3 matrices",
9328            )),
9329        }
9330    });
9331
9332    // matrix_trace - trace (sum of diagonal)
9333    define(interp, "matrix_trace", Some(1), |_, args| {
9334        let m = extract_matrix(&args[0])?;
9335
9336        let size = m.len().min(if m.is_empty() { 0 } else { m[0].len() });
9337        let trace: f64 = (0..size).map(|i| m[i][i]).sum();
9338
9339        Ok(Value::Float(trace))
9340    });
9341
9342    // matrix_dot - dot product of vectors (1D arrays)
9343    define(interp, "matrix_dot", Some(2), |_, args| {
9344        fn extract_vector(val: &Value) -> Result<Vec<f64>, RuntimeError> {
9345            match val {
9346                Value::Array(arr) => {
9347                    let arr = arr.borrow();
9348                    let mut vec = Vec::new();
9349                    for v in arr.iter() {
9350                        match v {
9351                            Value::Int(n) => vec.push(*n as f64),
9352                            Value::Float(f) => vec.push(*f),
9353                            _ => {
9354                                return Err(RuntimeError::new(
9355                                    "dot product requires numeric vectors",
9356                                ))
9357                            }
9358                        }
9359                    }
9360                    Ok(vec)
9361                }
9362                _ => Err(RuntimeError::new("dot product requires arrays")),
9363            }
9364        }
9365
9366        let a = extract_vector(&args[0])?;
9367        let b = extract_vector(&args[1])?;
9368
9369        if a.len() != b.len() {
9370            return Err(RuntimeError::new(
9371                "matrix_dot() requires same-length vectors",
9372            ));
9373        }
9374
9375        let dot: f64 = a.iter().zip(b.iter()).map(|(x, y)| x * y).sum();
9376        Ok(Value::Float(dot))
9377    });
9378}
9379
9380// Extended Euclidean algorithm for modular inverse
9381fn mod_inverse(a: i64, m: i64) -> Option<i64> {
9382    let (mut old_r, mut r) = (a, m);
9383    let (mut old_s, mut s) = (1i64, 0i64);
9384
9385    while r != 0 {
9386        let q = old_r / r;
9387        (old_r, r) = (r, old_r - q * r);
9388        (old_s, s) = (s, old_s - q * s);
9389    }
9390
9391    if old_r != 1 {
9392        None // No inverse exists
9393    } else {
9394        Some(old_s.rem_euclid(m))
9395    }
9396}
9397
9398// ============================================================================
9399// Phase 5: Language Power-Ups
9400// ============================================================================
9401
9402/// Functional programming utilities
9403fn register_functional(interp: &mut Interpreter) {
9404    // identity - returns its argument unchanged
9405    define(interp, "identity", Some(1), |_, args| Ok(args[0].clone()));
9406
9407    // const_fn - returns a function that always returns the given value
9408    define(interp, "const_fn", Some(1), |_, args| Ok(args[0].clone()));
9409
9410    // apply - apply a function to an array of arguments
9411    define(interp, "apply", Some(2), |interp, args| {
9412        let func = match &args[0] {
9413            Value::Function(f) => f.clone(),
9414            _ => {
9415                return Err(RuntimeError::new(
9416                    "apply: first argument must be a function",
9417                ))
9418            }
9419        };
9420        let fn_args = match &args[1] {
9421            Value::Array(arr) => arr.borrow().clone(),
9422            _ => return Err(RuntimeError::new("apply: second argument must be an array")),
9423        };
9424        interp.call_function(&func, fn_args)
9425    });
9426
9427    // flip - swap the first two arguments of a binary function
9428    define(interp, "flip", Some(3), |interp, args| {
9429        let func = match &args[0] {
9430            Value::Function(f) => f.clone(),
9431            _ => return Err(RuntimeError::new("flip: first argument must be a function")),
9432        };
9433        let flipped_args = vec![args[2].clone(), args[1].clone()];
9434        interp.call_function(&func, flipped_args)
9435    });
9436
9437    // tap - execute a function for side effects, return original value
9438    define(interp, "tap", Some(2), |interp, args| {
9439        let val = args[0].clone();
9440        let func = match &args[1] {
9441            Value::Function(f) => f.clone(),
9442            _ => return Err(RuntimeError::new("tap: second argument must be a function")),
9443        };
9444        let _ = interp.call_function(&func, vec![val.clone()]);
9445        Ok(val)
9446    });
9447
9448    // thunk - create a delayed computation (wrap in array for later forcing)
9449    define(interp, "thunk", Some(1), |_, args| {
9450        Ok(Value::Array(Rc::new(RefCell::new(vec![args[0].clone()]))))
9451    });
9452
9453    // force - force evaluation of a thunk
9454    define(interp, "force", Some(1), |interp, args| match &args[0] {
9455        Value::Array(arr) => {
9456            let arr = arr.borrow();
9457            if arr.len() == 1 {
9458                if let Value::Function(f) = &arr[0] {
9459                    return interp.call_function(f, vec![]);
9460                }
9461            }
9462            Ok(arr.get(0).cloned().unwrap_or(Value::Null))
9463        }
9464        v => Ok(v.clone()),
9465    });
9466
9467    // negate - negate a predicate function result
9468    define(interp, "negate", Some(2), |interp, args| {
9469        let func = match &args[0] {
9470            Value::Function(f) => f.clone(),
9471            _ => {
9472                return Err(RuntimeError::new(
9473                    "negate: first argument must be a function",
9474                ))
9475            }
9476        };
9477        let result = interp.call_function(&func, vec![args[1].clone()])?;
9478        Ok(Value::Bool(!is_truthy(&result)))
9479    });
9480
9481    // complement - same as negate
9482    define(interp, "complement", Some(2), |interp, args| {
9483        let func = match &args[0] {
9484            Value::Function(f) => f.clone(),
9485            _ => {
9486                return Err(RuntimeError::new(
9487                    "complement: first argument must be a function",
9488                ))
9489            }
9490        };
9491        let result = interp.call_function(&func, vec![args[1].clone()])?;
9492        Ok(Value::Bool(!is_truthy(&result)))
9493    });
9494
9495    // partial - partially apply a function with some arguments
9496    define(interp, "partial", None, |interp, args| {
9497        if args.len() < 2 {
9498            return Err(RuntimeError::new(
9499                "partial: requires at least function and one argument",
9500            ));
9501        }
9502        let func = match &args[0] {
9503            Value::Function(f) => f.clone(),
9504            _ => {
9505                return Err(RuntimeError::new(
9506                    "partial: first argument must be a function",
9507                ))
9508            }
9509        };
9510        let partial_args: Vec<Value> = args[1..].to_vec();
9511        interp.call_function(&func, partial_args)
9512    });
9513
9514    // juxt - apply multiple functions to same args, return array of results
9515    define(interp, "juxt", None, |interp, args| {
9516        if args.len() < 2 {
9517            return Err(RuntimeError::new("juxt: requires functions and a value"));
9518        }
9519        let val = args.last().unwrap().clone();
9520        let results: Result<Vec<Value>, _> = args[..args.len() - 1]
9521            .iter()
9522            .map(|f| match f {
9523                Value::Function(func) => interp.call_function(func, vec![val.clone()]),
9524                _ => Err(RuntimeError::new(
9525                    "juxt: all but last argument must be functions",
9526                )),
9527            })
9528            .collect();
9529        Ok(Value::Array(Rc::new(RefCell::new(results?))))
9530    });
9531}
9532
9533/// Benchmarking and profiling utilities
9534fn register_benchmark(interp: &mut Interpreter) {
9535    // bench - run a function N times and return average time in ms
9536    define(interp, "bench", Some(2), |interp, args| {
9537        let func = match &args[0] {
9538            Value::Function(f) => f.clone(),
9539            _ => {
9540                return Err(RuntimeError::new(
9541                    "bench: first argument must be a function",
9542                ))
9543            }
9544        };
9545        let iterations = match &args[1] {
9546            Value::Int(n) => *n as usize,
9547            _ => {
9548                return Err(RuntimeError::new(
9549                    "bench: second argument must be an integer",
9550                ))
9551            }
9552        };
9553
9554        let start = std::time::Instant::now();
9555        for _ in 0..iterations {
9556            let _ = interp.call_function(&func, vec![])?;
9557        }
9558        let elapsed = start.elapsed();
9559        let avg_ms = elapsed.as_secs_f64() * 1000.0 / iterations as f64;
9560        Ok(Value::Float(avg_ms))
9561    });
9562
9563    // time_it - run a function once and return (result, time_ms) tuple
9564    define(interp, "time_it", Some(1), |interp, args| {
9565        let func = match &args[0] {
9566            Value::Function(f) => f.clone(),
9567            _ => return Err(RuntimeError::new("time_it: argument must be a function")),
9568        };
9569
9570        let start = std::time::Instant::now();
9571        let result = interp.call_function(&func, vec![])?;
9572        let elapsed_ms = start.elapsed().as_secs_f64() * 1000.0;
9573
9574        Ok(Value::Tuple(Rc::new(vec![
9575            result,
9576            Value::Float(elapsed_ms),
9577        ])))
9578    });
9579
9580    // stopwatch_start - return current time in ms
9581    define(interp, "stopwatch_start", Some(0), |_, _| {
9582        let elapsed = std::time::SystemTime::now()
9583            .duration_since(std::time::UNIX_EPOCH)
9584            .unwrap_or_default();
9585        Ok(Value::Float(elapsed.as_secs_f64() * 1000.0))
9586    });
9587
9588    // stopwatch_elapsed - get elapsed time since a stopwatch start
9589    define(interp, "stopwatch_elapsed", Some(1), |_, args| {
9590        let start_ms = match &args[0] {
9591            Value::Float(f) => *f,
9592            Value::Int(n) => *n as f64,
9593            _ => {
9594                return Err(RuntimeError::new(
9595                    "stopwatch_elapsed: argument must be a number",
9596                ))
9597            }
9598        };
9599        let now = std::time::SystemTime::now()
9600            .duration_since(std::time::UNIX_EPOCH)
9601            .unwrap_or_default();
9602        let now_ms = now.as_secs_f64() * 1000.0;
9603        Ok(Value::Float(now_ms - start_ms))
9604    });
9605
9606    // compare_bench - compare two functions, return speedup ratio
9607    define(interp, "compare_bench", Some(3), |interp, args| {
9608        let func1 = match &args[0] {
9609            Value::Function(f) => f.clone(),
9610            _ => {
9611                return Err(RuntimeError::new(
9612                    "compare_bench: first argument must be a function",
9613                ))
9614            }
9615        };
9616        let func2 = match &args[1] {
9617            Value::Function(f) => f.clone(),
9618            _ => {
9619                return Err(RuntimeError::new(
9620                    "compare_bench: second argument must be a function",
9621                ))
9622            }
9623        };
9624        let iterations = match &args[2] {
9625            Value::Int(n) => *n as usize,
9626            _ => {
9627                return Err(RuntimeError::new(
9628                    "compare_bench: third argument must be an integer",
9629                ))
9630            }
9631        };
9632
9633        let start1 = std::time::Instant::now();
9634        for _ in 0..iterations {
9635            let _ = interp.call_function(&func1, vec![])?;
9636        }
9637        let time1 = start1.elapsed().as_secs_f64();
9638
9639        let start2 = std::time::Instant::now();
9640        for _ in 0..iterations {
9641            let _ = interp.call_function(&func2, vec![])?;
9642        }
9643        let time2 = start2.elapsed().as_secs_f64();
9644
9645        let mut results = std::collections::HashMap::new();
9646        results.insert("time1_ms".to_string(), Value::Float(time1 * 1000.0));
9647        results.insert("time2_ms".to_string(), Value::Float(time2 * 1000.0));
9648        results.insert("speedup".to_string(), Value::Float(time1 / time2));
9649        results.insert("iterations".to_string(), Value::Int(iterations as i64));
9650
9651        Ok(Value::Struct {
9652            name: "BenchResult".to_string(),
9653            fields: Rc::new(RefCell::new(results)),
9654        })
9655    });
9656
9657    // memory_usage - placeholder
9658    define(interp, "memory_usage", Some(0), |_, _| Ok(Value::Int(0)));
9659}
9660
9661/// Extended iterator utilities (itertools-inspired)
9662fn register_itertools(interp: &mut Interpreter) {
9663    // cycle - create infinite cycle of array elements (returns first N)
9664    define(interp, "cycle", Some(2), |_, args| {
9665        let arr = match &args[0] {
9666            Value::Array(a) => a.borrow().clone(),
9667            _ => return Err(RuntimeError::new("cycle: first argument must be an array")),
9668        };
9669        let n = match &args[1] {
9670            Value::Int(n) => *n as usize,
9671            _ => {
9672                return Err(RuntimeError::new(
9673                    "cycle: second argument must be an integer",
9674                ))
9675            }
9676        };
9677
9678        if arr.is_empty() {
9679            return Ok(Value::Array(Rc::new(RefCell::new(vec![]))));
9680        }
9681
9682        let result: Vec<Value> = (0..n).map(|i| arr[i % arr.len()].clone()).collect();
9683        Ok(Value::Array(Rc::new(RefCell::new(result))))
9684    });
9685
9686    // repeat_val - repeat a value N times
9687    define(interp, "repeat_val", Some(2), |_, args| {
9688        let val = args[0].clone();
9689        let n = match &args[1] {
9690            Value::Int(n) => *n as usize,
9691            _ => {
9692                return Err(RuntimeError::new(
9693                    "repeat_val: second argument must be an integer",
9694                ))
9695            }
9696        };
9697
9698        let result: Vec<Value> = std::iter::repeat(val).take(n).collect();
9699        Ok(Value::Array(Rc::new(RefCell::new(result))))
9700    });
9701
9702    // take_while - take elements while predicate is true
9703    define(interp, "take_while", Some(2), |interp, args| {
9704        let arr = match &args[0] {
9705            Value::Array(a) => a.borrow().clone(),
9706            _ => {
9707                return Err(RuntimeError::new(
9708                    "take_while: first argument must be an array",
9709                ))
9710            }
9711        };
9712        let pred = match &args[1] {
9713            Value::Function(f) => f.clone(),
9714            _ => {
9715                return Err(RuntimeError::new(
9716                    "take_while: second argument must be a function",
9717                ))
9718            }
9719        };
9720
9721        let mut result = Vec::new();
9722        for item in arr {
9723            let keep = interp.call_function(&pred, vec![item.clone()])?;
9724            if is_truthy(&keep) {
9725                result.push(item);
9726            } else {
9727                break;
9728            }
9729        }
9730        Ok(Value::Array(Rc::new(RefCell::new(result))))
9731    });
9732
9733    // drop_while - drop elements while predicate is true
9734    define(interp, "drop_while", Some(2), |interp, args| {
9735        let arr = match &args[0] {
9736            Value::Array(a) => a.borrow().clone(),
9737            _ => {
9738                return Err(RuntimeError::new(
9739                    "drop_while: first argument must be an array",
9740                ))
9741            }
9742        };
9743        let pred = match &args[1] {
9744            Value::Function(f) => f.clone(),
9745            _ => {
9746                return Err(RuntimeError::new(
9747                    "drop_while: second argument must be a function",
9748                ))
9749            }
9750        };
9751
9752        let mut dropping = true;
9753        let mut result = Vec::new();
9754        for item in arr {
9755            if dropping {
9756                let drop = interp.call_function(&pred, vec![item.clone()])?;
9757                if !is_truthy(&drop) {
9758                    dropping = false;
9759                    result.push(item);
9760                }
9761            } else {
9762                result.push(item);
9763            }
9764        }
9765        Ok(Value::Array(Rc::new(RefCell::new(result))))
9766    });
9767
9768    // group_by - group consecutive elements by key function
9769    define(interp, "group_by", Some(2), |interp, args| {
9770        let arr = match &args[0] {
9771            Value::Array(a) => a.borrow().clone(),
9772            _ => {
9773                return Err(RuntimeError::new(
9774                    "group_by: first argument must be an array",
9775                ))
9776            }
9777        };
9778        let key_fn = match &args[1] {
9779            Value::Function(f) => f.clone(),
9780            _ => {
9781                return Err(RuntimeError::new(
9782                    "group_by: second argument must be a function",
9783                ))
9784            }
9785        };
9786
9787        let mut groups: Vec<Value> = Vec::new();
9788        let mut current_group: Vec<Value> = Vec::new();
9789        let mut current_key: Option<Value> = None;
9790
9791        for item in arr {
9792            let key = interp.call_function(&key_fn, vec![item.clone()])?;
9793            match &current_key {
9794                Some(k) if value_eq(k, &key) => {
9795                    current_group.push(item);
9796                }
9797                _ => {
9798                    if !current_group.is_empty() {
9799                        groups.push(Value::Array(Rc::new(RefCell::new(current_group))));
9800                    }
9801                    current_group = vec![item];
9802                    current_key = Some(key);
9803                }
9804            }
9805        }
9806        if !current_group.is_empty() {
9807            groups.push(Value::Array(Rc::new(RefCell::new(current_group))));
9808        }
9809
9810        Ok(Value::Array(Rc::new(RefCell::new(groups))))
9811    });
9812
9813    // partition - split array by predicate into (true_items, false_items)
9814    define(interp, "partition", Some(2), |interp, args| {
9815        let arr = match &args[0] {
9816            Value::Array(a) => a.borrow().clone(),
9817            _ => {
9818                return Err(RuntimeError::new(
9819                    "partition: first argument must be an array",
9820                ))
9821            }
9822        };
9823        let pred = match &args[1] {
9824            Value::Function(f) => f.clone(),
9825            _ => {
9826                return Err(RuntimeError::new(
9827                    "partition: second argument must be a function",
9828                ))
9829            }
9830        };
9831
9832        let mut true_items = Vec::new();
9833        let mut false_items = Vec::new();
9834
9835        for item in arr {
9836            let result = interp.call_function(&pred, vec![item.clone()])?;
9837            if is_truthy(&result) {
9838                true_items.push(item);
9839            } else {
9840                false_items.push(item);
9841            }
9842        }
9843
9844        Ok(Value::Tuple(Rc::new(vec![
9845            Value::Array(Rc::new(RefCell::new(true_items))),
9846            Value::Array(Rc::new(RefCell::new(false_items))),
9847        ])))
9848    });
9849
9850    // interleave - interleave two arrays
9851    define(interp, "interleave", Some(2), |_, args| {
9852        let arr1 = match &args[0] {
9853            Value::Array(a) => a.borrow().clone(),
9854            _ => {
9855                return Err(RuntimeError::new(
9856                    "interleave: first argument must be an array",
9857                ))
9858            }
9859        };
9860        let arr2 = match &args[1] {
9861            Value::Array(a) => a.borrow().clone(),
9862            _ => {
9863                return Err(RuntimeError::new(
9864                    "interleave: second argument must be an array",
9865                ))
9866            }
9867        };
9868
9869        let mut result = Vec::new();
9870        let mut i1 = arr1.into_iter();
9871        let mut i2 = arr2.into_iter();
9872
9873        loop {
9874            match (i1.next(), i2.next()) {
9875                (Some(a), Some(b)) => {
9876                    result.push(a);
9877                    result.push(b);
9878                }
9879                (Some(a), None) => {
9880                    result.push(a);
9881                    result.extend(i1);
9882                    break;
9883                }
9884                (None, Some(b)) => {
9885                    result.push(b);
9886                    result.extend(i2);
9887                    break;
9888                }
9889                (None, None) => break,
9890            }
9891        }
9892
9893        Ok(Value::Array(Rc::new(RefCell::new(result))))
9894    });
9895
9896    // chunks - split array into chunks of size N
9897    define(interp, "chunks", Some(2), |_, args| {
9898        let arr = match &args[0] {
9899            Value::Array(a) => a.borrow().clone(),
9900            _ => return Err(RuntimeError::new("chunks: first argument must be an array")),
9901        };
9902        let size = match &args[1] {
9903            Value::Int(n) if *n > 0 => *n as usize,
9904            _ => {
9905                return Err(RuntimeError::new(
9906                    "chunks: second argument must be a positive integer",
9907                ))
9908            }
9909        };
9910
9911        let chunks: Vec<Value> = arr
9912            .chunks(size)
9913            .map(|chunk| Value::Array(Rc::new(RefCell::new(chunk.to_vec()))))
9914            .collect();
9915
9916        Ok(Value::Array(Rc::new(RefCell::new(chunks))))
9917    });
9918
9919    // windows - sliding windows of size N
9920    define(interp, "windows", Some(2), |_, args| {
9921        let arr = match &args[0] {
9922            Value::Array(a) => a.borrow().clone(),
9923            _ => {
9924                return Err(RuntimeError::new(
9925                    "windows: first argument must be an array",
9926                ))
9927            }
9928        };
9929        let size = match &args[1] {
9930            Value::Int(n) if *n > 0 => *n as usize,
9931            _ => {
9932                return Err(RuntimeError::new(
9933                    "windows: second argument must be a positive integer",
9934                ))
9935            }
9936        };
9937
9938        if arr.len() < size {
9939            return Ok(Value::Array(Rc::new(RefCell::new(vec![]))));
9940        }
9941
9942        let windows: Vec<Value> = arr
9943            .windows(size)
9944            .map(|window| Value::Array(Rc::new(RefCell::new(window.to_vec()))))
9945            .collect();
9946
9947        Ok(Value::Array(Rc::new(RefCell::new(windows))))
9948    });
9949
9950    // scan - like fold but returns all intermediate values
9951    define(interp, "scan", Some(3), |interp, args| {
9952        let arr = match &args[0] {
9953            Value::Array(a) => a.borrow().clone(),
9954            _ => return Err(RuntimeError::new("scan: first argument must be an array")),
9955        };
9956        let init = args[1].clone();
9957        let func = match &args[2] {
9958            Value::Function(f) => f.clone(),
9959            _ => return Err(RuntimeError::new("scan: third argument must be a function")),
9960        };
9961
9962        let mut results = vec![init.clone()];
9963        let mut acc = init;
9964
9965        for item in arr {
9966            acc = interp.call_function(&func, vec![acc, item])?;
9967            results.push(acc.clone());
9968        }
9969
9970        Ok(Value::Array(Rc::new(RefCell::new(results))))
9971    });
9972
9973    // frequencies - count occurrences of each element
9974    define(interp, "frequencies", Some(1), |_, args| {
9975        let arr = match &args[0] {
9976            Value::Array(a) => a.borrow().clone(),
9977            _ => return Err(RuntimeError::new("frequencies: argument must be an array")),
9978        };
9979
9980        let mut counts: std::collections::HashMap<String, i64> = std::collections::HashMap::new();
9981        for item in &arr {
9982            let key = format!("{}", item);
9983            *counts.entry(key).or_insert(0) += 1;
9984        }
9985
9986        let result: std::collections::HashMap<String, Value> = counts
9987            .into_iter()
9988            .map(|(k, v)| (k, Value::Int(v)))
9989            .collect();
9990
9991        Ok(Value::Map(Rc::new(RefCell::new(result))))
9992    });
9993
9994    // dedupe - remove consecutive duplicates
9995    define(interp, "dedupe", Some(1), |_, args| {
9996        let arr = match &args[0] {
9997            Value::Array(a) => a.borrow().clone(),
9998            _ => return Err(RuntimeError::new("dedupe: argument must be an array")),
9999        };
10000
10001        let mut result = Vec::new();
10002        let mut prev: Option<Value> = None;
10003
10004        for item in arr {
10005            match &prev {
10006                Some(p) if value_eq(p, &item) => continue,
10007                _ => {
10008                    result.push(item.clone());
10009                    prev = Some(item);
10010                }
10011            }
10012        }
10013
10014        Ok(Value::Array(Rc::new(RefCell::new(result))))
10015    });
10016
10017    // unique - remove all duplicates (not just consecutive)
10018    define(interp, "unique", Some(1), |_, args| {
10019        let arr = match &args[0] {
10020            Value::Array(a) => a.borrow().clone(),
10021            _ => return Err(RuntimeError::new("unique: argument must be an array")),
10022        };
10023
10024        let mut seen = std::collections::HashSet::new();
10025        let mut result = Vec::new();
10026
10027        for item in arr {
10028            let key = format!("{}", item);
10029            if seen.insert(key) {
10030                result.push(item);
10031            }
10032        }
10033
10034        Ok(Value::Array(Rc::new(RefCell::new(result))))
10035    });
10036}
10037
10038/// Advanced range utilities
10039fn register_ranges(interp: &mut Interpreter) {
10040    // range_step - range with custom step
10041    define(interp, "range_step", Some(3), |_, args| {
10042        let start = match &args[0] {
10043            Value::Int(n) => *n,
10044            Value::Float(f) => *f as i64,
10045            _ => return Err(RuntimeError::new("range_step: start must be a number")),
10046        };
10047        let end = match &args[1] {
10048            Value::Int(n) => *n,
10049            Value::Float(f) => *f as i64,
10050            _ => return Err(RuntimeError::new("range_step: end must be a number")),
10051        };
10052        let step = match &args[2] {
10053            Value::Int(n) if *n != 0 => *n,
10054            Value::Float(f) if *f != 0.0 => *f as i64,
10055            _ => {
10056                return Err(RuntimeError::new(
10057                    "range_step: step must be a non-zero number",
10058                ))
10059            }
10060        };
10061
10062        let mut result = Vec::new();
10063        if step > 0 {
10064            let mut i = start;
10065            while i < end {
10066                result.push(Value::Int(i));
10067                i += step;
10068            }
10069        } else {
10070            let mut i = start;
10071            while i > end {
10072                result.push(Value::Int(i));
10073                i += step;
10074            }
10075        }
10076
10077        Ok(Value::Array(Rc::new(RefCell::new(result))))
10078    });
10079
10080    // linspace - N evenly spaced values from start to end (inclusive)
10081    define(interp, "linspace", Some(3), |_, args| {
10082        let start = match &args[0] {
10083            Value::Int(n) => *n as f64,
10084            Value::Float(f) => *f,
10085            _ => return Err(RuntimeError::new("linspace: start must be a number")),
10086        };
10087        let end = match &args[1] {
10088            Value::Int(n) => *n as f64,
10089            Value::Float(f) => *f,
10090            _ => return Err(RuntimeError::new("linspace: end must be a number")),
10091        };
10092        let n = match &args[2] {
10093            Value::Int(n) if *n > 0 => *n as usize,
10094            _ => {
10095                return Err(RuntimeError::new(
10096                    "linspace: count must be a positive integer",
10097                ))
10098            }
10099        };
10100
10101        if n == 1 {
10102            return Ok(Value::Array(Rc::new(RefCell::new(vec![Value::Float(
10103                start,
10104            )]))));
10105        }
10106
10107        let step = (end - start) / (n - 1) as f64;
10108        let result: Vec<Value> = (0..n)
10109            .map(|i| Value::Float(start + step * i as f64))
10110            .collect();
10111
10112        Ok(Value::Array(Rc::new(RefCell::new(result))))
10113    });
10114
10115    // logspace - N logarithmically spaced values
10116    define(interp, "logspace", Some(3), |_, args| {
10117        let start_exp = match &args[0] {
10118            Value::Int(n) => *n as f64,
10119            Value::Float(f) => *f,
10120            _ => {
10121                return Err(RuntimeError::new(
10122                    "logspace: start exponent must be a number",
10123                ))
10124            }
10125        };
10126        let end_exp = match &args[1] {
10127            Value::Int(n) => *n as f64,
10128            Value::Float(f) => *f,
10129            _ => return Err(RuntimeError::new("logspace: end exponent must be a number")),
10130        };
10131        let n = match &args[2] {
10132            Value::Int(n) if *n > 0 => *n as usize,
10133            _ => {
10134                return Err(RuntimeError::new(
10135                    "logspace: count must be a positive integer",
10136                ))
10137            }
10138        };
10139
10140        if n == 1 {
10141            return Ok(Value::Array(Rc::new(RefCell::new(vec![Value::Float(
10142                10f64.powf(start_exp),
10143            )]))));
10144        }
10145
10146        let step = (end_exp - start_exp) / (n - 1) as f64;
10147        let result: Vec<Value> = (0..n)
10148            .map(|i| Value::Float(10f64.powf(start_exp + step * i as f64)))
10149            .collect();
10150
10151        Ok(Value::Array(Rc::new(RefCell::new(result))))
10152    });
10153
10154    // arange - like numpy arange (start, stop, step with float support)
10155    define(interp, "arange", Some(3), |_, args| {
10156        let start = match &args[0] {
10157            Value::Int(n) => *n as f64,
10158            Value::Float(f) => *f,
10159            _ => return Err(RuntimeError::new("arange: start must be a number")),
10160        };
10161        let stop = match &args[1] {
10162            Value::Int(n) => *n as f64,
10163            Value::Float(f) => *f,
10164            _ => return Err(RuntimeError::new("arange: stop must be a number")),
10165        };
10166        let step = match &args[2] {
10167            Value::Int(n) if *n != 0 => *n as f64,
10168            Value::Float(f) if *f != 0.0 => *f,
10169            _ => return Err(RuntimeError::new("arange: step must be a non-zero number")),
10170        };
10171
10172        let mut result = Vec::new();
10173        if step > 0.0 {
10174            let mut x = start;
10175            while x < stop {
10176                result.push(Value::Float(x));
10177                x += step;
10178            }
10179        } else {
10180            let mut x = start;
10181            while x > stop {
10182                result.push(Value::Float(x));
10183                x += step;
10184            }
10185        }
10186
10187        Ok(Value::Array(Rc::new(RefCell::new(result))))
10188    });
10189
10190    // geomspace - geometrically spaced values (like logspace but using actual values)
10191    define(interp, "geomspace", Some(3), |_, args| {
10192        let start = match &args[0] {
10193            Value::Int(n) if *n > 0 => *n as f64,
10194            Value::Float(f) if *f > 0.0 => *f,
10195            _ => {
10196                return Err(RuntimeError::new(
10197                    "geomspace: start must be a positive number",
10198                ))
10199            }
10200        };
10201        let end = match &args[1] {
10202            Value::Int(n) if *n > 0 => *n as f64,
10203            Value::Float(f) if *f > 0.0 => *f,
10204            _ => {
10205                return Err(RuntimeError::new(
10206                    "geomspace: end must be a positive number",
10207                ))
10208            }
10209        };
10210        let n = match &args[2] {
10211            Value::Int(n) if *n > 0 => *n as usize,
10212            _ => {
10213                return Err(RuntimeError::new(
10214                    "geomspace: count must be a positive integer",
10215                ))
10216            }
10217        };
10218
10219        if n == 1 {
10220            return Ok(Value::Array(Rc::new(RefCell::new(vec![Value::Float(
10221                start,
10222            )]))));
10223        }
10224
10225        let ratio = (end / start).powf(1.0 / (n - 1) as f64);
10226        let result: Vec<Value> = (0..n)
10227            .map(|i| Value::Float(start * ratio.powi(i as i32)))
10228            .collect();
10229
10230        Ok(Value::Array(Rc::new(RefCell::new(result))))
10231    });
10232}
10233
10234/// Bitwise operations
10235fn register_bitwise(interp: &mut Interpreter) {
10236    define(interp, "bit_and", Some(2), |_, args| {
10237        let a = match &args[0] {
10238            Value::Int(n) => *n,
10239            _ => return Err(RuntimeError::new("bit_and: arguments must be integers")),
10240        };
10241        let b = match &args[1] {
10242            Value::Int(n) => *n,
10243            _ => return Err(RuntimeError::new("bit_and: arguments must be integers")),
10244        };
10245        Ok(Value::Int(a & b))
10246    });
10247
10248    define(interp, "bit_or", Some(2), |_, args| {
10249        let a = match &args[0] {
10250            Value::Int(n) => *n,
10251            _ => return Err(RuntimeError::new("bit_or: arguments must be integers")),
10252        };
10253        let b = match &args[1] {
10254            Value::Int(n) => *n,
10255            _ => return Err(RuntimeError::new("bit_or: arguments must be integers")),
10256        };
10257        Ok(Value::Int(a | b))
10258    });
10259
10260    define(interp, "bit_xor", Some(2), |_, args| {
10261        let a = match &args[0] {
10262            Value::Int(n) => *n,
10263            _ => return Err(RuntimeError::new("bit_xor: arguments must be integers")),
10264        };
10265        let b = match &args[1] {
10266            Value::Int(n) => *n,
10267            _ => return Err(RuntimeError::new("bit_xor: arguments must be integers")),
10268        };
10269        Ok(Value::Int(a ^ b))
10270    });
10271
10272    define(interp, "bit_not", Some(1), |_, args| {
10273        let a = match &args[0] {
10274            Value::Int(n) => *n,
10275            _ => return Err(RuntimeError::new("bit_not: argument must be an integer")),
10276        };
10277        Ok(Value::Int(!a))
10278    });
10279
10280    define(interp, "bit_shl", Some(2), |_, args| {
10281        let a = match &args[0] {
10282            Value::Int(n) => *n,
10283            _ => {
10284                return Err(RuntimeError::new(
10285                    "bit_shl: first argument must be an integer",
10286                ))
10287            }
10288        };
10289        let b = match &args[1] {
10290            Value::Int(n) if *n >= 0 && *n < 64 => *n as u32,
10291            _ => return Err(RuntimeError::new("bit_shl: shift amount must be 0-63")),
10292        };
10293        Ok(Value::Int(a << b))
10294    });
10295
10296    define(interp, "bit_shr", Some(2), |_, args| {
10297        let a = match &args[0] {
10298            Value::Int(n) => *n,
10299            _ => {
10300                return Err(RuntimeError::new(
10301                    "bit_shr: first argument must be an integer",
10302                ))
10303            }
10304        };
10305        let b = match &args[1] {
10306            Value::Int(n) if *n >= 0 && *n < 64 => *n as u32,
10307            _ => return Err(RuntimeError::new("bit_shr: shift amount must be 0-63")),
10308        };
10309        Ok(Value::Int(a >> b))
10310    });
10311
10312    define(interp, "popcount", Some(1), |_, args| {
10313        let a = match &args[0] {
10314            Value::Int(n) => *n,
10315            _ => return Err(RuntimeError::new("popcount: argument must be an integer")),
10316        };
10317        Ok(Value::Int(a.count_ones() as i64))
10318    });
10319
10320    define(interp, "leading_zeros", Some(1), |_, args| {
10321        let a = match &args[0] {
10322            Value::Int(n) => *n,
10323            _ => {
10324                return Err(RuntimeError::new(
10325                    "leading_zeros: argument must be an integer",
10326                ))
10327            }
10328        };
10329        Ok(Value::Int(a.leading_zeros() as i64))
10330    });
10331
10332    define(interp, "trailing_zeros", Some(1), |_, args| {
10333        let a = match &args[0] {
10334            Value::Int(n) => *n,
10335            _ => {
10336                return Err(RuntimeError::new(
10337                    "trailing_zeros: argument must be an integer",
10338                ))
10339            }
10340        };
10341        Ok(Value::Int(a.trailing_zeros() as i64))
10342    });
10343
10344    define(interp, "bit_test", Some(2), |_, args| {
10345        let a = match &args[0] {
10346            Value::Int(n) => *n,
10347            _ => {
10348                return Err(RuntimeError::new(
10349                    "bit_test: first argument must be an integer",
10350                ))
10351            }
10352        };
10353        let pos = match &args[1] {
10354            Value::Int(n) if *n >= 0 && *n < 64 => *n as u32,
10355            _ => return Err(RuntimeError::new("bit_test: position must be 0-63")),
10356        };
10357        Ok(Value::Bool((a >> pos) & 1 == 1))
10358    });
10359
10360    define(interp, "bit_set", Some(2), |_, args| {
10361        let a = match &args[0] {
10362            Value::Int(n) => *n,
10363            _ => {
10364                return Err(RuntimeError::new(
10365                    "bit_set: first argument must be an integer",
10366                ))
10367            }
10368        };
10369        let pos = match &args[1] {
10370            Value::Int(n) if *n >= 0 && *n < 64 => *n as u32,
10371            _ => return Err(RuntimeError::new("bit_set: position must be 0-63")),
10372        };
10373        Ok(Value::Int(a | (1 << pos)))
10374    });
10375
10376    define(interp, "bit_clear", Some(2), |_, args| {
10377        let a = match &args[0] {
10378            Value::Int(n) => *n,
10379            _ => {
10380                return Err(RuntimeError::new(
10381                    "bit_clear: first argument must be an integer",
10382                ))
10383            }
10384        };
10385        let pos = match &args[1] {
10386            Value::Int(n) if *n >= 0 && *n < 64 => *n as u32,
10387            _ => return Err(RuntimeError::new("bit_clear: position must be 0-63")),
10388        };
10389        Ok(Value::Int(a & !(1 << pos)))
10390    });
10391
10392    define(interp, "bit_toggle", Some(2), |_, args| {
10393        let a = match &args[0] {
10394            Value::Int(n) => *n,
10395            _ => {
10396                return Err(RuntimeError::new(
10397                    "bit_toggle: first argument must be an integer",
10398                ))
10399            }
10400        };
10401        let pos = match &args[1] {
10402            Value::Int(n) if *n >= 0 && *n < 64 => *n as u32,
10403            _ => return Err(RuntimeError::new("bit_toggle: position must be 0-63")),
10404        };
10405        Ok(Value::Int(a ^ (1 << pos)))
10406    });
10407
10408    define(interp, "to_binary", Some(1), |_, args| {
10409        let a = match &args[0] {
10410            Value::Int(n) => *n,
10411            _ => return Err(RuntimeError::new("to_binary: argument must be an integer")),
10412        };
10413        Ok(Value::String(Rc::new(format!("{:b}", a))))
10414    });
10415
10416    define(interp, "from_binary", Some(1), |_, args| {
10417        let s = match &args[0] {
10418            Value::String(s) => (**s).clone(),
10419            _ => return Err(RuntimeError::new("from_binary: argument must be a string")),
10420        };
10421        match i64::from_str_radix(&s, 2) {
10422            Ok(n) => Ok(Value::Int(n)),
10423            Err(_) => Err(RuntimeError::new("from_binary: invalid binary string")),
10424        }
10425    });
10426
10427    define(interp, "to_hex", Some(1), |_, args| {
10428        let a = match &args[0] {
10429            Value::Int(n) => *n,
10430            _ => return Err(RuntimeError::new("to_hex: argument must be an integer")),
10431        };
10432        Ok(Value::String(Rc::new(format!("{:x}", a))))
10433    });
10434
10435    define(interp, "from_hex", Some(1), |_, args| {
10436        let s = match &args[0] {
10437            Value::String(s) => s.trim_start_matches("0x").to_string(),
10438            _ => return Err(RuntimeError::new("from_hex: argument must be a string")),
10439        };
10440        match i64::from_str_radix(&s, 16) {
10441            Ok(n) => Ok(Value::Int(n)),
10442            Err(_) => Err(RuntimeError::new("from_hex: invalid hex string")),
10443        }
10444    });
10445
10446    define(interp, "to_octal", Some(1), |_, args| {
10447        let a = match &args[0] {
10448            Value::Int(n) => *n,
10449            _ => return Err(RuntimeError::new("to_octal: argument must be an integer")),
10450        };
10451        Ok(Value::String(Rc::new(format!("{:o}", a))))
10452    });
10453
10454    define(interp, "from_octal", Some(1), |_, args| {
10455        let s = match &args[0] {
10456            Value::String(s) => s.trim_start_matches("0o").to_string(),
10457            _ => return Err(RuntimeError::new("from_octal: argument must be a string")),
10458        };
10459        match i64::from_str_radix(&s, 8) {
10460            Ok(n) => Ok(Value::Int(n)),
10461            Err(_) => Err(RuntimeError::new("from_octal: invalid octal string")),
10462        }
10463    });
10464}
10465
10466/// String formatting utilities
10467fn register_format(interp: &mut Interpreter) {
10468    // format - basic string formatting with {} placeholders
10469    define(interp, "format", None, |_, args| {
10470        if args.is_empty() {
10471            return Err(RuntimeError::new(
10472                "format: requires at least a format string",
10473            ));
10474        }
10475        let template = match &args[0] {
10476            Value::String(s) => (**s).clone(),
10477            _ => return Err(RuntimeError::new("format: first argument must be a string")),
10478        };
10479        let mut result = template;
10480        for arg in &args[1..] {
10481            if let Some(pos) = result.find("{}") {
10482                result = format!("{}{}{}", &result[..pos], arg, &result[pos + 2..]);
10483            }
10484        }
10485        Ok(Value::String(Rc::new(result)))
10486    });
10487
10488    // pad_left - left-pad string to length with char (uses character count, not bytes)
10489    define(interp, "pad_left", Some(3), |_, args| {
10490        let s = match &args[0] {
10491            Value::String(s) => (**s).clone(),
10492            _ => {
10493                return Err(RuntimeError::new(
10494                    "pad_left: first argument must be a string",
10495                ))
10496            }
10497        };
10498        let width = match &args[1] {
10499            Value::Int(n) if *n >= 0 => *n as usize,
10500            _ => {
10501                return Err(RuntimeError::new(
10502                    "pad_left: width must be a non-negative integer",
10503                ))
10504            }
10505        };
10506        let pad_char = match &args[2] {
10507            Value::String(s) if !s.is_empty() => s.chars().next().unwrap(),
10508            Value::Char(c) => *c,
10509            _ => {
10510                return Err(RuntimeError::new(
10511                    "pad_left: pad character must be a non-empty string or char",
10512                ))
10513            }
10514        };
10515        let char_count = s.chars().count();
10516        if char_count >= width {
10517            return Ok(Value::String(Rc::new(s)));
10518        }
10519        let padding: String = std::iter::repeat(pad_char)
10520            .take(width - char_count)
10521            .collect();
10522        Ok(Value::String(Rc::new(format!("{}{}", padding, s))))
10523    });
10524
10525    // pad_right - right-pad string to length with char (uses character count, not bytes)
10526    define(interp, "pad_right", Some(3), |_, args| {
10527        let s = match &args[0] {
10528            Value::String(s) => (**s).clone(),
10529            _ => {
10530                return Err(RuntimeError::new(
10531                    "pad_right: first argument must be a string",
10532                ))
10533            }
10534        };
10535        let width = match &args[1] {
10536            Value::Int(n) if *n >= 0 => *n as usize,
10537            _ => {
10538                return Err(RuntimeError::new(
10539                    "pad_right: width must be a non-negative integer",
10540                ))
10541            }
10542        };
10543        let pad_char = match &args[2] {
10544            Value::String(s) if !s.is_empty() => s.chars().next().unwrap(),
10545            Value::Char(c) => *c,
10546            _ => {
10547                return Err(RuntimeError::new(
10548                    "pad_right: pad character must be a non-empty string or char",
10549                ))
10550            }
10551        };
10552        let char_count = s.chars().count();
10553        if char_count >= width {
10554            return Ok(Value::String(Rc::new(s)));
10555        }
10556        let padding: String = std::iter::repeat(pad_char)
10557            .take(width - char_count)
10558            .collect();
10559        Ok(Value::String(Rc::new(format!("{}{}", s, padding))))
10560    });
10561
10562    // center - center string with padding (uses character count, not bytes)
10563    define(interp, "center", Some(3), |_, args| {
10564        let s = match &args[0] {
10565            Value::String(s) => (**s).clone(),
10566            _ => return Err(RuntimeError::new("center: first argument must be a string")),
10567        };
10568        let width = match &args[1] {
10569            Value::Int(n) if *n >= 0 => *n as usize,
10570            _ => {
10571                return Err(RuntimeError::new(
10572                    "center: width must be a non-negative integer",
10573                ))
10574            }
10575        };
10576        let pad_char = match &args[2] {
10577            Value::String(s) if !s.is_empty() => s.chars().next().unwrap(),
10578            Value::Char(c) => *c,
10579            _ => {
10580                return Err(RuntimeError::new(
10581                    "center: pad character must be a non-empty string or char",
10582                ))
10583            }
10584        };
10585        let char_count = s.chars().count();
10586        if char_count >= width {
10587            return Ok(Value::String(Rc::new(s)));
10588        }
10589        let total_padding = width - char_count;
10590        let left_padding = total_padding / 2;
10591        let right_padding = total_padding - left_padding;
10592        let left: String = std::iter::repeat(pad_char).take(left_padding).collect();
10593        let right: String = std::iter::repeat(pad_char).take(right_padding).collect();
10594        Ok(Value::String(Rc::new(format!("{}{}{}", left, s, right))))
10595    });
10596
10597    // number_format - format number with thousand separators
10598    define(interp, "number_format", Some(1), |_, args| {
10599        let n = match &args[0] {
10600            Value::Int(n) => *n,
10601            Value::Float(f) => *f as i64,
10602            _ => {
10603                return Err(RuntimeError::new(
10604                    "number_format: argument must be a number",
10605                ))
10606            }
10607        };
10608        let s = n.abs().to_string();
10609        let mut result = String::new();
10610        for (i, c) in s.chars().rev().enumerate() {
10611            if i > 0 && i % 3 == 0 {
10612                result.push(',');
10613            }
10614            result.push(c);
10615        }
10616        let formatted: String = result.chars().rev().collect();
10617        if n < 0 {
10618            Ok(Value::String(Rc::new(format!("-{}", formatted))))
10619        } else {
10620            Ok(Value::String(Rc::new(formatted)))
10621        }
10622    });
10623
10624    // ordinal - convert number to ordinal string (1st, 2nd, 3rd, etc)
10625    define(interp, "ordinal", Some(1), |_, args| {
10626        let n = match &args[0] {
10627            Value::Int(n) => *n,
10628            _ => return Err(RuntimeError::new("ordinal: argument must be an integer")),
10629        };
10630        let suffix = match (n % 10, n % 100) {
10631            (1, 11) => "th",
10632            (2, 12) => "th",
10633            (3, 13) => "th",
10634            (1, _) => "st",
10635            (2, _) => "nd",
10636            (3, _) => "rd",
10637            _ => "th",
10638        };
10639        Ok(Value::String(Rc::new(format!("{}{}", n, suffix))))
10640    });
10641
10642    // pluralize - simple pluralization
10643    define(interp, "pluralize", Some(3), |_, args| {
10644        let count = match &args[0] {
10645            Value::Int(n) => *n,
10646            _ => {
10647                return Err(RuntimeError::new(
10648                    "pluralize: first argument must be an integer",
10649                ))
10650            }
10651        };
10652        let singular = match &args[1] {
10653            Value::String(s) => s.clone(),
10654            _ => {
10655                return Err(RuntimeError::new(
10656                    "pluralize: second argument must be a string",
10657                ))
10658            }
10659        };
10660        let plural = match &args[2] {
10661            Value::String(s) => s.clone(),
10662            _ => {
10663                return Err(RuntimeError::new(
10664                    "pluralize: third argument must be a string",
10665                ))
10666            }
10667        };
10668        if count == 1 || count == -1 {
10669            Ok(Value::String(singular))
10670        } else {
10671            Ok(Value::String(plural))
10672        }
10673    });
10674
10675    // truncate - truncate string with ellipsis (uses character count, not bytes)
10676    define(interp, "truncate", Some(2), |_, args| {
10677        let s = match &args[0] {
10678            Value::String(s) => (**s).clone(),
10679            _ => {
10680                return Err(RuntimeError::new(
10681                    "truncate: first argument must be a string",
10682                ))
10683            }
10684        };
10685        let max_len = match &args[1] {
10686            Value::Int(n) if *n >= 0 => *n as usize,
10687            _ => {
10688                return Err(RuntimeError::new(
10689                    "truncate: max length must be a non-negative integer",
10690                ))
10691            }
10692        };
10693        let char_count = s.chars().count();
10694        if char_count <= max_len {
10695            return Ok(Value::String(Rc::new(s)));
10696        }
10697        if max_len <= 3 {
10698            return Ok(Value::String(Rc::new(s.chars().take(max_len).collect())));
10699        }
10700        let truncated: String = s.chars().take(max_len - 3).collect();
10701        Ok(Value::String(Rc::new(format!("{}...", truncated))))
10702    });
10703
10704    // word_wrap - wrap text at specified width
10705    define(interp, "word_wrap", Some(2), |_, args| {
10706        let s = match &args[0] {
10707            Value::String(s) => (**s).clone(),
10708            _ => {
10709                return Err(RuntimeError::new(
10710                    "word_wrap: first argument must be a string",
10711                ))
10712            }
10713        };
10714        let width = match &args[1] {
10715            Value::Int(n) if *n > 0 => *n as usize,
10716            _ => {
10717                return Err(RuntimeError::new(
10718                    "word_wrap: width must be a positive integer",
10719                ))
10720            }
10721        };
10722        let mut result = String::new();
10723        let mut line_len = 0;
10724        for word in s.split_whitespace() {
10725            if line_len > 0 && line_len + 1 + word.len() > width {
10726                result.push('\n');
10727                line_len = 0;
10728            } else if line_len > 0 {
10729                result.push(' ');
10730                line_len += 1;
10731            }
10732            result.push_str(word);
10733            line_len += word.len();
10734        }
10735        Ok(Value::String(Rc::new(result)))
10736    });
10737
10738    // snake_case - convert string to snake_case
10739    define(interp, "snake_case", Some(1), |_, args| {
10740        let s = match &args[0] {
10741            Value::String(s) => (**s).clone(),
10742            _ => return Err(RuntimeError::new("snake_case: argument must be a string")),
10743        };
10744        let mut result = String::new();
10745        for (i, c) in s.chars().enumerate() {
10746            if c.is_uppercase() {
10747                if i > 0 {
10748                    result.push('_');
10749                }
10750                result.push(c.to_lowercase().next().unwrap());
10751            } else if c == ' ' || c == '-' {
10752                result.push('_');
10753            } else {
10754                result.push(c);
10755            }
10756        }
10757        Ok(Value::String(Rc::new(result)))
10758    });
10759
10760    // camel_case - convert string to camelCase
10761    define(interp, "camel_case", Some(1), |_, args| {
10762        let s = match &args[0] {
10763            Value::String(s) => (**s).clone(),
10764            _ => return Err(RuntimeError::new("camel_case: argument must be a string")),
10765        };
10766        let mut result = String::new();
10767        let mut capitalize_next = false;
10768        for (i, c) in s.chars().enumerate() {
10769            if c == '_' || c == '-' || c == ' ' {
10770                capitalize_next = true;
10771            } else if capitalize_next {
10772                result.push(c.to_uppercase().next().unwrap());
10773                capitalize_next = false;
10774            } else if i == 0 {
10775                result.push(c.to_lowercase().next().unwrap());
10776            } else {
10777                result.push(c);
10778            }
10779        }
10780        Ok(Value::String(Rc::new(result)))
10781    });
10782
10783    // kebab_case - convert string to kebab-case
10784    define(interp, "kebab_case", Some(1), |_, args| {
10785        let s = match &args[0] {
10786            Value::String(s) => (**s).clone(),
10787            _ => return Err(RuntimeError::new("kebab_case: argument must be a string")),
10788        };
10789        let mut result = String::new();
10790        for (i, c) in s.chars().enumerate() {
10791            if c.is_uppercase() {
10792                if i > 0 {
10793                    result.push('-');
10794                }
10795                result.push(c.to_lowercase().next().unwrap());
10796            } else if c == '_' || c == ' ' {
10797                result.push('-');
10798            } else {
10799                result.push(c);
10800            }
10801        }
10802        Ok(Value::String(Rc::new(result)))
10803    });
10804
10805    // title_case - convert string to Title Case
10806    define(interp, "title_case", Some(1), |_, args| {
10807        let s = match &args[0] {
10808            Value::String(s) => (**s).clone(),
10809            _ => return Err(RuntimeError::new("title_case: argument must be a string")),
10810        };
10811        let result: String = s
10812            .split_whitespace()
10813            .map(|word| {
10814                let mut chars = word.chars();
10815                match chars.next() {
10816                    None => String::new(),
10817                    Some(first) => {
10818                        first.to_uppercase().collect::<String>() + &chars.as_str().to_lowercase()
10819                    }
10820                }
10821            })
10822            .collect::<Vec<_>>()
10823            .join(" ");
10824        Ok(Value::String(Rc::new(result)))
10825    });
10826}
10827
10828// ============================================================================
10829// PATTERN MATCHING FUNCTIONS (Phase 6)
10830// ============================================================================
10831// Advanced pattern matching utilities for expressive data manipulation.
10832// These complement Sigil's match expressions with functional alternatives.
10833// ============================================================================
10834
10835fn register_pattern(interp: &mut Interpreter) {
10836    // --- TYPE MATCHING ---
10837
10838    // type_of - get the type name as a string
10839    define(interp, "type_of", Some(1), |_, args| {
10840        let type_name = match &args[0] {
10841            Value::Null => "null",
10842            Value::Bool(_) => "bool",
10843            Value::Int(_) => "int",
10844            Value::Float(_) => "float",
10845            Value::String(_) => "string",
10846            Value::Char(_) => "char",
10847            Value::Array(_) => "array",
10848            Value::Tuple(_) => "tuple",
10849            Value::Map(_) => "map",
10850            Value::Set(_) => "set",
10851            Value::Struct { name, .. } => {
10852                return Ok(Value::String(Rc::new(format!("struct:{}", name))))
10853            }
10854            Value::Variant {
10855                enum_name,
10856                variant_name,
10857                ..
10858            } => {
10859                return Ok(Value::String(Rc::new(format!(
10860                    "{}::{}",
10861                    enum_name, variant_name
10862                ))))
10863            }
10864            Value::Function(_) => "function",
10865            Value::BuiltIn(_) => "builtin",
10866            Value::Ref(_) => "ref",
10867            Value::Infinity => "infinity",
10868            Value::Empty => "empty",
10869            Value::Evidential { .. } => "evidential",
10870            Value::Affective { .. } => "affective",
10871            Value::Channel(_) => "channel",
10872            Value::ThreadHandle(_) => "thread",
10873            Value::Actor(_) => "actor",
10874            Value::Future(_) => "future",
10875            Value::VariantConstructor { .. } => "variant_constructor",
10876            Value::DefaultConstructor { .. } => "default_constructor",
10877            Value::Range { .. } => "range",
10878            Value::RefCellValue(_) => "refcell",
10879            Value::TraitObject { trait_name, .. } => return Ok(Value::String(Rc::new(format!("dyn {}", trait_name)))),
10880        };
10881        Ok(Value::String(Rc::new(type_name.to_string())))
10882    });
10883
10884    // is_type - check if value matches type name
10885    define(interp, "is_type", Some(2), |_, args| {
10886        let type_name = match &args[1] {
10887            Value::String(s) => s.to_lowercase(),
10888            _ => {
10889                return Err(RuntimeError::new(
10890                    "is_type: second argument must be type name string",
10891                ))
10892            }
10893        };
10894        let matches = match (&args[0], type_name.as_str()) {
10895            (Value::Null, "null") => true,
10896            (Value::Bool(_), "bool") => true,
10897            (Value::Int(_), "int") | (Value::Int(_), "integer") => true,
10898            (Value::Float(_), "float") | (Value::Float(_), "number") => true,
10899            (Value::Int(_), "number") => true,
10900            (Value::String(_), "string") => true,
10901            (Value::Array(_), "array") | (Value::Array(_), "list") => true,
10902            (Value::Tuple(_), "tuple") => true,
10903            (Value::Map(_), "map") | (Value::Map(_), "dict") | (Value::Map(_), "object") => true,
10904            (Value::Set(_), "set") => true,
10905            (Value::Function(_), "function") | (Value::Function(_), "fn") => true,
10906            (Value::BuiltIn(_), "function") | (Value::BuiltIn(_), "builtin") => true,
10907            (Value::Struct { name, .. }, t) => t == "struct" || t == &name.to_lowercase(),
10908            (Value::Variant { enum_name, .. }, t) => {
10909                t == "variant" || t == "enum" || t == &enum_name.to_lowercase()
10910            }
10911            (Value::Channel(_), "channel") => true,
10912            (Value::ThreadHandle(_), "thread") => true,
10913            (Value::Actor(_), "actor") => true,
10914            (Value::Future(_), "future") => true,
10915            _ => false,
10916        };
10917        Ok(Value::Bool(matches))
10918    });
10919
10920    // is_null, is_bool, is_int, is_float, is_string, is_array, is_map - type predicates
10921    define(interp, "is_null", Some(1), |_, args| {
10922        Ok(Value::Bool(matches!(&args[0], Value::Null)))
10923    });
10924    define(interp, "is_bool", Some(1), |_, args| {
10925        Ok(Value::Bool(matches!(&args[0], Value::Bool(_))))
10926    });
10927    define(interp, "is_int", Some(1), |_, args| {
10928        Ok(Value::Bool(matches!(&args[0], Value::Int(_))))
10929    });
10930    define(interp, "is_float", Some(1), |_, args| {
10931        Ok(Value::Bool(matches!(&args[0], Value::Float(_))))
10932    });
10933    define(interp, "is_number", Some(1), |_, args| {
10934        Ok(Value::Bool(matches!(
10935            &args[0],
10936            Value::Int(_) | Value::Float(_)
10937        )))
10938    });
10939    define(interp, "is_string", Some(1), |_, args| {
10940        Ok(Value::Bool(matches!(&args[0], Value::String(_))))
10941    });
10942    define(interp, "is_array", Some(1), |_, args| {
10943        Ok(Value::Bool(matches!(&args[0], Value::Array(_))))
10944    });
10945    define(interp, "is_tuple", Some(1), |_, args| {
10946        Ok(Value::Bool(matches!(&args[0], Value::Tuple(_))))
10947    });
10948    define(interp, "is_map", Some(1), |_, args| {
10949        Ok(Value::Bool(matches!(&args[0], Value::Map(_))))
10950    });
10951    define(interp, "is_set", Some(1), |_, args| {
10952        Ok(Value::Bool(matches!(&args[0], Value::Set(_))))
10953    });
10954    define(interp, "is_function", Some(1), |_, args| {
10955        Ok(Value::Bool(matches!(
10956            &args[0],
10957            Value::Function(_) | Value::BuiltIn(_)
10958        )))
10959    });
10960    define(interp, "is_struct", Some(1), |_, args| {
10961        Ok(Value::Bool(matches!(&args[0], Value::Struct { .. })))
10962    });
10963    define(interp, "is_variant", Some(1), |_, args| {
10964        Ok(Value::Bool(matches!(&args[0], Value::Variant { .. })))
10965    });
10966    define(interp, "is_future", Some(1), |_, args| {
10967        Ok(Value::Bool(matches!(&args[0], Value::Future(_))))
10968    });
10969    define(interp, "is_channel", Some(1), |_, args| {
10970        Ok(Value::Bool(matches!(&args[0], Value::Channel(_))))
10971    });
10972
10973    // is_empty - check if collection is empty
10974    define(interp, "is_empty", Some(1), |_, args| {
10975        let empty = match &args[0] {
10976            Value::Null => true,
10977            Value::String(s) => s.is_empty(),
10978            Value::Array(a) => a.borrow().is_empty(),
10979            Value::Tuple(t) => t.is_empty(),
10980            Value::Map(m) => m.borrow().is_empty(),
10981            Value::Set(s) => s.borrow().is_empty(),
10982            _ => false,
10983        };
10984        Ok(Value::Bool(empty))
10985    });
10986
10987    // --- REGEX PATTERN MATCHING ---
10988
10989    // match_regex - match string against regex, return captures or null
10990    define(interp, "match_regex", Some(2), |_, args| {
10991        let text = match &args[0] {
10992            Value::String(s) => (**s).clone(),
10993            _ => {
10994                return Err(RuntimeError::new(
10995                    "match_regex: first argument must be a string",
10996                ))
10997            }
10998        };
10999        let pattern = match &args[1] {
11000            Value::String(s) => (**s).clone(),
11001            _ => {
11002                return Err(RuntimeError::new(
11003                    "match_regex: second argument must be a regex pattern string",
11004                ))
11005            }
11006        };
11007
11008        let re = match Regex::new(&pattern) {
11009            Ok(r) => r,
11010            Err(e) => {
11011                return Err(RuntimeError::new(format!(
11012                    "match_regex: invalid regex: {}",
11013                    e
11014                )))
11015            }
11016        };
11017
11018        match re.captures(&text) {
11019            Some(caps) => {
11020                let mut captures: Vec<Value> = Vec::new();
11021                for i in 0..caps.len() {
11022                    if let Some(m) = caps.get(i) {
11023                        captures.push(Value::String(Rc::new(m.as_str().to_string())));
11024                    } else {
11025                        captures.push(Value::Null);
11026                    }
11027                }
11028                Ok(Value::Array(Rc::new(RefCell::new(captures))))
11029            }
11030            None => Ok(Value::Null),
11031        }
11032    });
11033
11034    // match_all_regex - find all matches of regex in string
11035    define(interp, "match_all_regex", Some(2), |_, args| {
11036        let text = match &args[0] {
11037            Value::String(s) => (**s).clone(),
11038            _ => {
11039                return Err(RuntimeError::new(
11040                    "match_all_regex: first argument must be a string",
11041                ))
11042            }
11043        };
11044        let pattern = match &args[1] {
11045            Value::String(s) => (**s).clone(),
11046            _ => {
11047                return Err(RuntimeError::new(
11048                    "match_all_regex: second argument must be a regex pattern string",
11049                ))
11050            }
11051        };
11052
11053        let re = match Regex::new(&pattern) {
11054            Ok(r) => r,
11055            Err(e) => {
11056                return Err(RuntimeError::new(format!(
11057                    "match_all_regex: invalid regex: {}",
11058                    e
11059                )))
11060            }
11061        };
11062
11063        let matches: Vec<Value> = re
11064            .find_iter(&text)
11065            .map(|m| Value::String(Rc::new(m.as_str().to_string())))
11066            .collect();
11067        Ok(Value::Array(Rc::new(RefCell::new(matches))))
11068    });
11069
11070    // capture_named - extract named captures from regex match
11071    define(interp, "capture_named", Some(2), |_, args| {
11072        let text = match &args[0] {
11073            Value::String(s) => (**s).clone(),
11074            _ => {
11075                return Err(RuntimeError::new(
11076                    "capture_named: first argument must be a string",
11077                ))
11078            }
11079        };
11080        let pattern = match &args[1] {
11081            Value::String(s) => (**s).clone(),
11082            _ => {
11083                return Err(RuntimeError::new(
11084                    "capture_named: second argument must be a regex pattern string",
11085                ))
11086            }
11087        };
11088
11089        let re = match Regex::new(&pattern) {
11090            Ok(r) => r,
11091            Err(e) => {
11092                return Err(RuntimeError::new(format!(
11093                    "capture_named: invalid regex: {}",
11094                    e
11095                )))
11096            }
11097        };
11098
11099        match re.captures(&text) {
11100            Some(caps) => {
11101                let mut result: HashMap<String, Value> = HashMap::new();
11102                for name in re.capture_names().flatten() {
11103                    if let Some(m) = caps.name(name) {
11104                        result.insert(
11105                            name.to_string(),
11106                            Value::String(Rc::new(m.as_str().to_string())),
11107                        );
11108                    }
11109                }
11110                Ok(Value::Map(Rc::new(RefCell::new(result))))
11111            }
11112            None => Ok(Value::Null),
11113        }
11114    });
11115
11116    // --- STRUCTURAL PATTERN MATCHING ---
11117
11118    // match_struct - check if value is a struct with given name
11119    define(interp, "match_struct", Some(2), |_, args| {
11120        let expected_name = match &args[1] {
11121            Value::String(s) => (**s).clone(),
11122            _ => {
11123                return Err(RuntimeError::new(
11124                    "match_struct: second argument must be struct name string",
11125                ))
11126            }
11127        };
11128        match &args[0] {
11129            Value::Struct { name, .. } => Ok(Value::Bool(name == &expected_name)),
11130            _ => Ok(Value::Bool(false)),
11131        }
11132    });
11133
11134    // match_variant - check if value is a variant with given enum and variant name
11135    define(interp, "match_variant", Some(3), |_, args| {
11136        let expected_enum = match &args[1] {
11137            Value::String(s) => (**s).clone(),
11138            _ => {
11139                return Err(RuntimeError::new(
11140                    "match_variant: second argument must be enum name string",
11141                ))
11142            }
11143        };
11144        let expected_variant = match &args[2] {
11145            Value::String(s) => (**s).clone(),
11146            _ => {
11147                return Err(RuntimeError::new(
11148                    "match_variant: third argument must be variant name string",
11149                ))
11150            }
11151        };
11152        match &args[0] {
11153            Value::Variant {
11154                enum_name,
11155                variant_name,
11156                ..
11157            } => Ok(Value::Bool(
11158                enum_name == &expected_enum && variant_name == &expected_variant,
11159            )),
11160            _ => Ok(Value::Bool(false)),
11161        }
11162    });
11163
11164    // get_field - get field from struct by name (returns null if not found)
11165    define(interp, "get_field", Some(2), |_, args| {
11166        let field_name = match &args[1] {
11167            Value::String(s) => (**s).clone(),
11168            _ => {
11169                return Err(RuntimeError::new(
11170                    "get_field: second argument must be field name string",
11171                ))
11172            }
11173        };
11174        match &args[0] {
11175            Value::Struct { fields, .. } => Ok(fields
11176                .borrow()
11177                .get(&field_name)
11178                .cloned()
11179                .unwrap_or(Value::Null)),
11180            Value::Map(m) => Ok(m.borrow().get(&field_name).cloned().unwrap_or(Value::Null)),
11181            _ => Ok(Value::Null),
11182        }
11183    });
11184
11185    // has_field - check if struct/map has a field
11186    define(interp, "has_field", Some(2), |_, args| {
11187        let field_name = match &args[1] {
11188            Value::String(s) => (**s).clone(),
11189            _ => {
11190                return Err(RuntimeError::new(
11191                    "has_field: second argument must be field name string",
11192                ))
11193            }
11194        };
11195        match &args[0] {
11196            Value::Struct { fields, .. } => {
11197                Ok(Value::Bool(fields.borrow().contains_key(&field_name)))
11198            }
11199            Value::Map(m) => Ok(Value::Bool(m.borrow().contains_key(&field_name))),
11200            _ => Ok(Value::Bool(false)),
11201        }
11202    });
11203
11204    // get_fields - get all field names from struct/map
11205    define(interp, "get_fields", Some(1), |_, args| {
11206        let fields: Vec<Value> = match &args[0] {
11207            Value::Struct { fields, .. } => fields
11208                .borrow()
11209                .keys()
11210                .map(|k| Value::String(Rc::new(k.clone())))
11211                .collect(),
11212            Value::Map(m) => m
11213                .borrow()
11214                .keys()
11215                .map(|k| Value::String(Rc::new(k.clone())))
11216                .collect(),
11217            _ => {
11218                return Err(RuntimeError::new(
11219                    "get_fields: argument must be struct or map",
11220                ))
11221            }
11222        };
11223        Ok(Value::Array(Rc::new(RefCell::new(fields))))
11224    });
11225
11226    // struct_name - get the name of a struct
11227    define(interp, "struct_name", Some(1), |_, args| match &args[0] {
11228        Value::Struct { name, .. } => Ok(Value::String(Rc::new(name.clone()))),
11229        _ => Ok(Value::Null),
11230    });
11231
11232    // variant_name - get the variant name of an enum value
11233    define(interp, "variant_name", Some(1), |_, args| match &args[0] {
11234        Value::Variant { variant_name, .. } => Ok(Value::String(Rc::new(variant_name.clone()))),
11235        _ => Ok(Value::Null),
11236    });
11237
11238    // variant_data - get the data payload of a variant
11239    define(interp, "variant_data", Some(1), |_, args| match &args[0] {
11240        Value::Variant { fields, .. } => match fields {
11241            Some(f) => Ok(Value::Array(Rc::new(RefCell::new((**f).clone())))),
11242            None => Ok(Value::Null),
11243        },
11244        _ => Ok(Value::Null),
11245    });
11246
11247    // --- GUARDS AND CONDITIONALS ---
11248
11249    // guard - conditionally return value or null (for pattern guard chains)
11250    define(interp, "guard", Some(2), |_, args| {
11251        if is_truthy(&args[0]) {
11252            Ok(args[1].clone())
11253        } else {
11254            Ok(Value::Null)
11255        }
11256    });
11257
11258    // when - like guard but evaluates a function if condition is true
11259    define(interp, "when", Some(2), |interp, args| {
11260        if is_truthy(&args[0]) {
11261            match &args[1] {
11262                Value::Function(f) => interp.call_function(f, vec![]),
11263                other => Ok(other.clone()),
11264            }
11265        } else {
11266            Ok(Value::Null)
11267        }
11268    });
11269
11270    // unless - opposite of when
11271    define(interp, "unless", Some(2), |interp, args| {
11272        if !is_truthy(&args[0]) {
11273            match &args[1] {
11274                Value::Function(f) => interp.call_function(f, vec![]),
11275                other => Ok(other.clone()),
11276            }
11277        } else {
11278            Ok(Value::Null)
11279        }
11280    });
11281
11282    // cond - evaluate conditions in order, return first matching result
11283    // cond([[cond1, val1], [cond2, val2], ...])
11284    define(interp, "cond", Some(1), |interp, args| {
11285        let clauses = match &args[0] {
11286            Value::Array(a) => a.borrow().clone(),
11287            _ => {
11288                return Err(RuntimeError::new(
11289                    "cond: argument must be array of [condition, value] pairs",
11290                ))
11291            }
11292        };
11293
11294        for clause in clauses {
11295            let pair = match &clause {
11296                Value::Array(a) => a.borrow().clone(),
11297                Value::Tuple(t) => (**t).clone(),
11298                _ => {
11299                    return Err(RuntimeError::new(
11300                        "cond: each clause must be [condition, value] pair",
11301                    ))
11302                }
11303            };
11304            if pair.len() != 2 {
11305                return Err(RuntimeError::new(
11306                    "cond: each clause must have exactly 2 elements",
11307                ));
11308            }
11309
11310            if is_truthy(&pair[0]) {
11311                return match &pair[1] {
11312                    Value::Function(f) => interp.call_function(f, vec![]),
11313                    other => Ok(other.clone()),
11314                };
11315            }
11316        }
11317        Ok(Value::Null)
11318    });
11319
11320    // case - match value against patterns, return matching result
11321    // case(val, [[pattern1, result1], [pattern2, result2], ...])
11322    define(interp, "case", Some(2), |interp, args| {
11323        let value = &args[0];
11324        let clauses = match &args[1] {
11325            Value::Array(a) => a.borrow().clone(),
11326            _ => {
11327                return Err(RuntimeError::new(
11328                    "case: second argument must be array of [pattern, result] pairs",
11329                ))
11330            }
11331        };
11332
11333        for clause in clauses {
11334            let pair = match &clause {
11335                Value::Array(a) => a.borrow().clone(),
11336                Value::Tuple(t) => (**t).clone(),
11337                _ => {
11338                    return Err(RuntimeError::new(
11339                        "case: each clause must be [pattern, result] pair",
11340                    ))
11341                }
11342            };
11343            if pair.len() != 2 {
11344                return Err(RuntimeError::new(
11345                    "case: each clause must have exactly 2 elements",
11346                ));
11347            }
11348
11349            if value_eq(value, &pair[0]) {
11350                return match &pair[1] {
11351                    Value::Function(f) => interp.call_function(f, vec![value.clone()]),
11352                    other => Ok(other.clone()),
11353                };
11354            }
11355        }
11356        Ok(Value::Null)
11357    });
11358
11359    // --- DESTRUCTURING ---
11360
11361    // destructure_array - extract elements at specified indices
11362    define(interp, "destructure_array", Some(2), |_, args| {
11363        let arr = match &args[0] {
11364            Value::Array(a) => a.borrow().clone(),
11365            Value::Tuple(t) => (**t).clone(),
11366            _ => {
11367                return Err(RuntimeError::new(
11368                    "destructure_array: first argument must be array or tuple",
11369                ))
11370            }
11371        };
11372        let indices = match &args[1] {
11373            Value::Array(a) => a.borrow().clone(),
11374            _ => {
11375                return Err(RuntimeError::new(
11376                    "destructure_array: second argument must be array of indices",
11377                ))
11378            }
11379        };
11380
11381        let mut result = Vec::new();
11382        for idx in indices {
11383            match idx {
11384                Value::Int(i) => {
11385                    let i = if i < 0 { arr.len() as i64 + i } else { i } as usize;
11386                    result.push(arr.get(i).cloned().unwrap_or(Value::Null));
11387                }
11388                _ => result.push(Value::Null),
11389            }
11390        }
11391        Ok(Value::Array(Rc::new(RefCell::new(result))))
11392    });
11393
11394    // destructure_map - extract values for specified keys
11395    define(interp, "destructure_map", Some(2), |_, args| {
11396        let map = match &args[0] {
11397            Value::Map(m) => m.borrow().clone(),
11398            Value::Struct { fields, .. } => fields.borrow().clone(),
11399            _ => {
11400                return Err(RuntimeError::new(
11401                    "destructure_map: first argument must be map or struct",
11402                ))
11403            }
11404        };
11405        let keys = match &args[1] {
11406            Value::Array(a) => a.borrow().clone(),
11407            _ => {
11408                return Err(RuntimeError::new(
11409                    "destructure_map: second argument must be array of keys",
11410                ))
11411            }
11412        };
11413
11414        let mut result = Vec::new();
11415        for key in keys {
11416            match key {
11417                Value::String(k) => {
11418                    result.push(map.get(&*k).cloned().unwrap_or(Value::Null));
11419                }
11420                _ => result.push(Value::Null),
11421            }
11422        }
11423        Ok(Value::Array(Rc::new(RefCell::new(result))))
11424    });
11425
11426    // head_tail - split array into [head, tail]
11427    define(interp, "head_tail", Some(1), |_, args| {
11428        let arr = match &args[0] {
11429            Value::Array(a) => a.borrow().clone(),
11430            _ => return Err(RuntimeError::new("head_tail: argument must be array")),
11431        };
11432
11433        if arr.is_empty() {
11434            Ok(Value::Tuple(Rc::new(vec![
11435                Value::Null,
11436                Value::Array(Rc::new(RefCell::new(vec![]))),
11437            ])))
11438        } else {
11439            let head = arr[0].clone();
11440            let tail = arr[1..].to_vec();
11441            Ok(Value::Tuple(Rc::new(vec![
11442                head,
11443                Value::Array(Rc::new(RefCell::new(tail))),
11444            ])))
11445        }
11446    });
11447
11448    // init_last - split array into [init, last]
11449    define(interp, "init_last", Some(1), |_, args| {
11450        let arr = match &args[0] {
11451            Value::Array(a) => a.borrow().clone(),
11452            _ => return Err(RuntimeError::new("init_last: argument must be array")),
11453        };
11454
11455        if arr.is_empty() {
11456            Ok(Value::Tuple(Rc::new(vec![
11457                Value::Array(Rc::new(RefCell::new(vec![]))),
11458                Value::Null,
11459            ])))
11460        } else {
11461            let last = arr[arr.len() - 1].clone();
11462            let init = arr[..arr.len() - 1].to_vec();
11463            Ok(Value::Tuple(Rc::new(vec![
11464                Value::Array(Rc::new(RefCell::new(init))),
11465                last,
11466            ])))
11467        }
11468    });
11469
11470    // split_at - split array at index into [left, right]
11471    define(interp, "split_at", Some(2), |_, args| {
11472        let arr = match &args[0] {
11473            Value::Array(a) => a.borrow().clone(),
11474            _ => return Err(RuntimeError::new("split_at: first argument must be array")),
11475        };
11476        let idx = match &args[1] {
11477            Value::Int(i) => *i as usize,
11478            _ => {
11479                return Err(RuntimeError::new(
11480                    "split_at: second argument must be integer",
11481                ))
11482            }
11483        };
11484
11485        let idx = idx.min(arr.len());
11486        let left = arr[..idx].to_vec();
11487        let right = arr[idx..].to_vec();
11488        Ok(Value::Tuple(Rc::new(vec![
11489            Value::Array(Rc::new(RefCell::new(left))),
11490            Value::Array(Rc::new(RefCell::new(right))),
11491        ])))
11492    });
11493
11494    // --- OPTIONAL/NULLABLE HELPERS ---
11495
11496    // unwrap_or - return value if not null, else default
11497    define(interp, "unwrap_or", Some(2), |_, args| {
11498        if matches!(&args[0], Value::Null) {
11499            Ok(args[1].clone())
11500        } else {
11501            Ok(args[0].clone())
11502        }
11503    });
11504
11505    // unwrap_or_else - return value if not null, else call function
11506    define(interp, "unwrap_or_else", Some(2), |interp, args| {
11507        if matches!(&args[0], Value::Null) {
11508            match &args[1] {
11509                Value::Function(f) => interp.call_function(f, vec![]),
11510                other => Ok(other.clone()),
11511            }
11512        } else {
11513            Ok(args[0].clone())
11514        }
11515    });
11516
11517    // map_or - if value is not null, apply function, else return default
11518    define(interp, "map_or", Some(3), |interp, args| {
11519        if matches!(&args[0], Value::Null) {
11520            Ok(args[1].clone())
11521        } else {
11522            match &args[2] {
11523                Value::Function(f) => interp.call_function(f, vec![args[0].clone()]),
11524                _ => Err(RuntimeError::new(
11525                    "map_or: third argument must be a function",
11526                )),
11527            }
11528        }
11529    });
11530
11531    // coalesce - return first non-null value from array
11532    define(interp, "coalesce", Some(1), |_, args| {
11533        let values = match &args[0] {
11534            Value::Array(a) => a.borrow().clone(),
11535            _ => return Err(RuntimeError::new("coalesce: argument must be array")),
11536        };
11537
11538        for v in values {
11539            if !matches!(v, Value::Null) {
11540                return Ok(v);
11541            }
11542        }
11543        Ok(Value::Null)
11544    });
11545
11546    // --- EQUALITY AND COMPARISON ---
11547
11548    // deep_eq - deep structural equality check
11549    define(interp, "deep_eq", Some(2), |_, args| {
11550        Ok(Value::Bool(deep_value_eq(&args[0], &args[1])))
11551    });
11552
11553    // same_type - check if two values have the same type
11554    define(interp, "same_type", Some(2), |_, args| {
11555        let same = match (&args[0], &args[1]) {
11556            (Value::Null, Value::Null) => true,
11557            (Value::Bool(_), Value::Bool(_)) => true,
11558            (Value::Int(_), Value::Int(_)) => true,
11559            (Value::Float(_), Value::Float(_)) => true,
11560            (Value::String(_), Value::String(_)) => true,
11561            (Value::Array(_), Value::Array(_)) => true,
11562            (Value::Tuple(_), Value::Tuple(_)) => true,
11563            (Value::Map(_), Value::Map(_)) => true,
11564            (Value::Set(_), Value::Set(_)) => true,
11565            (Value::Function(_), Value::Function(_)) => true,
11566            (Value::BuiltIn(_), Value::BuiltIn(_)) => true,
11567            (Value::Struct { name: n1, .. }, Value::Struct { name: n2, .. }) => n1 == n2,
11568            (Value::Variant { enum_name: e1, .. }, Value::Variant { enum_name: e2, .. }) => {
11569                e1 == e2
11570            }
11571            _ => false,
11572        };
11573        Ok(Value::Bool(same))
11574    });
11575
11576    // compare - three-way comparison: -1, 0, or 1
11577    define(interp, "compare", Some(2), |_, args| {
11578        let cmp = match (&args[0], &args[1]) {
11579            (Value::Int(a), Value::Int(b)) => a.cmp(b),
11580            (Value::Float(a), Value::Float(b)) => {
11581                a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal)
11582            }
11583            (Value::Int(a), Value::Float(b)) => (*a as f64)
11584                .partial_cmp(b)
11585                .unwrap_or(std::cmp::Ordering::Equal),
11586            (Value::Float(a), Value::Int(b)) => a
11587                .partial_cmp(&(*b as f64))
11588                .unwrap_or(std::cmp::Ordering::Equal),
11589            (Value::String(a), Value::String(b)) => a.cmp(b),
11590            _ => {
11591                return Err(RuntimeError::new(
11592                    "compare: can only compare numbers or strings",
11593                ))
11594            }
11595        };
11596        Ok(Value::Int(match cmp {
11597            std::cmp::Ordering::Less => -1,
11598            std::cmp::Ordering::Equal => 0,
11599            std::cmp::Ordering::Greater => 1,
11600        }))
11601    });
11602
11603    // between - check if value is between min and max (inclusive)
11604    define(interp, "between", Some(3), |_, args| {
11605        let in_range = match (&args[0], &args[1], &args[2]) {
11606            (Value::Int(v), Value::Int(min), Value::Int(max)) => v >= min && v <= max,
11607            (Value::Float(v), Value::Float(min), Value::Float(max)) => v >= min && v <= max,
11608            (Value::Int(v), Value::Int(min), Value::Float(max)) => {
11609                (*v as f64) >= (*min as f64) && (*v as f64) <= *max
11610            }
11611            (Value::Int(v), Value::Float(min), Value::Int(max)) => {
11612                (*v as f64) >= *min && (*v as f64) <= (*max as f64)
11613            }
11614            (Value::Float(v), Value::Int(min), Value::Int(max)) => {
11615                *v >= (*min as f64) && *v <= (*max as f64)
11616            }
11617            (Value::String(v), Value::String(min), Value::String(max)) => v >= min && v <= max,
11618            _ => {
11619                return Err(RuntimeError::new(
11620                    "between: arguments must be comparable (numbers or strings)",
11621                ))
11622            }
11623        };
11624        Ok(Value::Bool(in_range))
11625    });
11626
11627    // clamp - constrain value to range
11628    define(interp, "clamp", Some(3), |_, args| {
11629        match (&args[0], &args[1], &args[2]) {
11630            (Value::Int(v), Value::Int(min), Value::Int(max)) => {
11631                Ok(Value::Int((*v).max(*min).min(*max)))
11632            }
11633            (Value::Float(v), Value::Float(min), Value::Float(max)) => {
11634                Ok(Value::Float(v.max(*min).min(*max)))
11635            }
11636            (Value::Int(v), Value::Int(min), Value::Float(max)) => {
11637                Ok(Value::Float((*v as f64).max(*min as f64).min(*max)))
11638            }
11639            _ => Err(RuntimeError::new("clamp: arguments must be numbers")),
11640        }
11641    });
11642}
11643
11644// Deep value equality for nested structures
11645fn deep_value_eq(a: &Value, b: &Value) -> bool {
11646    match (a, b) {
11647        (Value::Null, Value::Null) => true,
11648        (Value::Bool(a), Value::Bool(b)) => a == b,
11649        (Value::Int(a), Value::Int(b)) => a == b,
11650        (Value::Float(a), Value::Float(b)) => (a - b).abs() < f64::EPSILON,
11651        (Value::Int(a), Value::Float(b)) | (Value::Float(b), Value::Int(a)) => {
11652            (*a as f64 - b).abs() < f64::EPSILON
11653        }
11654        (Value::String(a), Value::String(b)) => a == b,
11655        (Value::Array(a), Value::Array(b)) => {
11656            let a = a.borrow();
11657            let b = b.borrow();
11658            a.len() == b.len() && a.iter().zip(b.iter()).all(|(x, y)| deep_value_eq(x, y))
11659        }
11660        (Value::Tuple(a), Value::Tuple(b)) => {
11661            a.len() == b.len() && a.iter().zip(b.iter()).all(|(x, y)| deep_value_eq(x, y))
11662        }
11663        (Value::Map(a), Value::Map(b)) => {
11664            let a = a.borrow();
11665            let b = b.borrow();
11666            a.len() == b.len()
11667                && a.iter()
11668                    .all(|(k, v)| b.get(k).map_or(false, |bv| deep_value_eq(v, bv)))
11669        }
11670        (Value::Set(a), Value::Set(b)) => {
11671            let a = a.borrow();
11672            let b = b.borrow();
11673            a.len() == b.len() && a.iter().all(|k| b.contains(k))
11674        }
11675        (
11676            Value::Struct {
11677                name: n1,
11678                fields: f1,
11679            },
11680            Value::Struct {
11681                name: n2,
11682                fields: f2,
11683            },
11684        ) => {
11685            let f1 = f1.borrow();
11686            let f2 = f2.borrow();
11687            n1 == n2
11688                && f1.len() == f2.len()
11689                && f1
11690                    .iter()
11691                    .all(|(k, v)| f2.get(k).map_or(false, |v2| deep_value_eq(v, v2)))
11692        }
11693        (
11694            Value::Variant {
11695                enum_name: e1,
11696                variant_name: v1,
11697                fields: d1,
11698            },
11699            Value::Variant {
11700                enum_name: e2,
11701                variant_name: v2,
11702                fields: d2,
11703            },
11704        ) => {
11705            if e1 != e2 || v1 != v2 {
11706                return false;
11707            }
11708            match (d1, d2) {
11709                (Some(f1), Some(f2)) => {
11710                    f1.len() == f2.len()
11711                        && f1.iter().zip(f2.iter()).all(|(x, y)| deep_value_eq(x, y))
11712                }
11713                (None, None) => true,
11714                _ => false,
11715            }
11716        }
11717        _ => false,
11718    }
11719}
11720
11721// Helper for value equality comparison
11722fn value_eq(a: &Value, b: &Value) -> bool {
11723    match (a, b) {
11724        (Value::Null, Value::Null) => true,
11725        (Value::Bool(a), Value::Bool(b)) => a == b,
11726        (Value::Int(a), Value::Int(b)) => a == b,
11727        (Value::Float(a), Value::Float(b)) => (a - b).abs() < f64::EPSILON,
11728        (Value::String(a), Value::String(b)) => a == b,
11729        (Value::Int(a), Value::Float(b)) | (Value::Float(b), Value::Int(a)) => {
11730            (*a as f64 - b).abs() < f64::EPSILON
11731        }
11732        _ => false,
11733    }
11734}
11735
11736// ============================================================================
11737// DEVEX FUNCTIONS (Phase 7)
11738// ============================================================================
11739// Developer experience enhancements: debugging, assertions, profiling,
11740// documentation, and introspection utilities.
11741// ============================================================================
11742
11743fn register_devex(interp: &mut Interpreter) {
11744    // --- DEBUGGING AND INTROSPECTION ---
11745
11746    // debug - print value with type info for debugging
11747    define(interp, "debug", Some(1), |_, args| {
11748        let type_name = match &args[0] {
11749            Value::Null => "null".to_string(),
11750            Value::Bool(_) => "bool".to_string(),
11751            Value::Int(_) => "int".to_string(),
11752            Value::Float(_) => "float".to_string(),
11753            Value::String(_) => "string".to_string(),
11754            Value::Char(_) => "char".to_string(),
11755            Value::Array(a) => format!("array[{}]", a.borrow().len()),
11756            Value::Tuple(t) => format!("tuple[{}]", t.len()),
11757            Value::Map(m) => format!("map[{}]", m.borrow().len()),
11758            Value::Set(s) => format!("set[{}]", s.borrow().len()),
11759            Value::Struct { name, fields } => format!("struct {}[{}]", name, fields.borrow().len()),
11760            Value::Variant {
11761                enum_name,
11762                variant_name,
11763                ..
11764            } => format!("{}::{}", enum_name, variant_name),
11765            Value::Function(_) => "function".to_string(),
11766            Value::BuiltIn(_) => "builtin".to_string(),
11767            Value::Ref(_) => "ref".to_string(),
11768            Value::Infinity => "infinity".to_string(),
11769            Value::Empty => "empty".to_string(),
11770            Value::Evidential { evidence, .. } => format!("evidential[{:?}]", evidence),
11771            Value::Affective { affect, .. } => format!("affective[sarcasm={}]", affect.sarcasm),
11772            Value::Channel(_) => "channel".to_string(),
11773            Value::ThreadHandle(_) => "thread".to_string(),
11774            Value::Actor(_) => "actor".to_string(),
11775            Value::Future(_) => "future".to_string(),
11776            Value::VariantConstructor { enum_name, variant_name } => {
11777                format!("<constructor {}::{}>", enum_name, variant_name)
11778            }
11779            Value::DefaultConstructor { type_name } => {
11780                format!("<default {}>", type_name)
11781            }
11782            Value::Range { start, end, inclusive } => {
11783                match (start, end) {
11784                    (Some(s), Some(e)) => if *inclusive {
11785                        format!("range({}..={})", s, e)
11786                    } else {
11787                        format!("range({}..{})", s, e)
11788                    },
11789                    (Some(s), None) => format!("range({}..)", s),
11790                    (None, Some(e)) => if *inclusive {
11791                        format!("range(..={})", e)
11792                    } else {
11793                        format!("range(..{})", e)
11794                    },
11795                    (None, None) => "range(..)".to_string(),
11796                }
11797            }
11798            Value::RefCellValue(rc) => format!("refcell({:?})", rc.value.borrow()),
11799            Value::TraitObject { trait_name, concrete_type, .. } => format!("dyn {}({})", trait_name, concrete_type),
11800        };
11801        let value_repr = format_value_debug(&args[0]);
11802        println!("[DEBUG] {}: {}", type_name, value_repr);
11803        Ok(args[0].clone())
11804    });
11805
11806    // inspect - return detailed string representation of value
11807    define(interp, "inspect", Some(1), |_, args| {
11808        Ok(Value::String(Rc::new(format_value_debug(&args[0]))))
11809    });
11810
11811    // dbg - print and return value (tap for debugging)
11812    define(interp, "dbg", Some(1), |_, args| {
11813        println!("{}", format_value_debug(&args[0]));
11814        Ok(args[0].clone())
11815    });
11816
11817    // trace - print message and value, return value
11818    define(interp, "trace", Some(2), |_, args| {
11819        let label = match &args[0] {
11820            Value::String(s) => (**s).clone(),
11821            _ => format_value_debug(&args[0]),
11822        };
11823        println!("[TRACE] {}: {}", label, format_value_debug(&args[1]));
11824        Ok(args[1].clone())
11825    });
11826
11827    // pp - pretty print with indentation
11828    define(interp, "pp", Some(1), |_, args| {
11829        println!("{}", pretty_print_value(&args[0], 0));
11830        Ok(Value::Null)
11831    });
11832
11833    // --- RICH ASSERTIONS ---
11834
11835    // assert_eq - assert two values are equal
11836    define(interp, "assert_eq", Some(2), |_, args| {
11837        if deep_value_eq(&args[0], &args[1]) {
11838            Ok(Value::Bool(true))
11839        } else {
11840            Err(RuntimeError::new(format!(
11841                "Assertion failed: expected {} to equal {}",
11842                format_value_debug(&args[0]),
11843                format_value_debug(&args[1])
11844            )))
11845        }
11846    });
11847
11848    // assert_ne - assert two values are not equal
11849    define(interp, "assert_ne", Some(2), |_, args| {
11850        if !deep_value_eq(&args[0], &args[1]) {
11851            Ok(Value::Bool(true))
11852        } else {
11853            Err(RuntimeError::new(format!(
11854                "Assertion failed: expected {} to not equal {}",
11855                format_value_debug(&args[0]),
11856                format_value_debug(&args[1])
11857            )))
11858        }
11859    });
11860
11861    // assert_lt - assert first value is less than second
11862    define(interp, "assert_lt", Some(2), |_, args| {
11863        let cmp = devex_compare(&args[0], &args[1])?;
11864        if cmp < 0 {
11865            Ok(Value::Bool(true))
11866        } else {
11867            Err(RuntimeError::new(format!(
11868                "Assertion failed: expected {} < {}",
11869                format_value_debug(&args[0]),
11870                format_value_debug(&args[1])
11871            )))
11872        }
11873    });
11874
11875    // assert_le - assert first value is less than or equal to second
11876    define(interp, "assert_le", Some(2), |_, args| {
11877        let cmp = devex_compare(&args[0], &args[1])?;
11878        if cmp <= 0 {
11879            Ok(Value::Bool(true))
11880        } else {
11881            Err(RuntimeError::new(format!(
11882                "Assertion failed: expected {} <= {}",
11883                format_value_debug(&args[0]),
11884                format_value_debug(&args[1])
11885            )))
11886        }
11887    });
11888
11889    // assert_gt - assert first value is greater than second
11890    define(interp, "assert_gt", Some(2), |_, args| {
11891        let cmp = devex_compare(&args[0], &args[1])?;
11892        if cmp > 0 {
11893            Ok(Value::Bool(true))
11894        } else {
11895            Err(RuntimeError::new(format!(
11896                "Assertion failed: expected {} > {}",
11897                format_value_debug(&args[0]),
11898                format_value_debug(&args[1])
11899            )))
11900        }
11901    });
11902
11903    // assert_ge - assert first value is greater than or equal to second
11904    define(interp, "assert_ge", Some(2), |_, args| {
11905        let cmp = devex_compare(&args[0], &args[1])?;
11906        if cmp >= 0 {
11907            Ok(Value::Bool(true))
11908        } else {
11909            Err(RuntimeError::new(format!(
11910                "Assertion failed: expected {} >= {}",
11911                format_value_debug(&args[0]),
11912                format_value_debug(&args[1])
11913            )))
11914        }
11915    });
11916
11917    // assert_true - assert value is truthy
11918    define(interp, "assert_true", Some(1), |_, args| {
11919        if is_truthy(&args[0]) {
11920            Ok(Value::Bool(true))
11921        } else {
11922            Err(RuntimeError::new(format!(
11923                "Assertion failed: expected {} to be truthy",
11924                format_value_debug(&args[0])
11925            )))
11926        }
11927    });
11928
11929    // assert_false - assert value is falsy
11930    define(interp, "assert_false", Some(1), |_, args| {
11931        if !is_truthy(&args[0]) {
11932            Ok(Value::Bool(true))
11933        } else {
11934            Err(RuntimeError::new(format!(
11935                "Assertion failed: expected {} to be falsy",
11936                format_value_debug(&args[0])
11937            )))
11938        }
11939    });
11940
11941    // assert_null - assert value is null
11942    define(interp, "assert_null", Some(1), |_, args| {
11943        if matches!(&args[0], Value::Null) {
11944            Ok(Value::Bool(true))
11945        } else {
11946            Err(RuntimeError::new(format!(
11947                "Assertion failed: expected null, got {}",
11948                format_value_debug(&args[0])
11949            )))
11950        }
11951    });
11952
11953    // assert_not_null - assert value is not null
11954    define(interp, "assert_not_null", Some(1), |_, args| {
11955        if !matches!(&args[0], Value::Null) {
11956            Ok(Value::Bool(true))
11957        } else {
11958            Err(RuntimeError::new(
11959                "Assertion failed: expected non-null value, got null",
11960            ))
11961        }
11962    });
11963
11964    // assert_type - assert value has expected type
11965    define(interp, "assert_type", Some(2), |_, args| {
11966        let expected = match &args[1] {
11967            Value::String(s) => s.to_lowercase(),
11968            _ => {
11969                return Err(RuntimeError::new(
11970                    "assert_type: second argument must be type name string",
11971                ))
11972            }
11973        };
11974        let actual = get_type_name(&args[0]).to_lowercase();
11975        if actual == expected || matches_type_alias(&args[0], &expected) {
11976            Ok(Value::Bool(true))
11977        } else {
11978            Err(RuntimeError::new(format!(
11979                "Assertion failed: expected type '{}', got '{}'",
11980                expected, actual
11981            )))
11982        }
11983    });
11984
11985    // assert_contains - assert collection contains value
11986    define(interp, "assert_contains", Some(2), |_, args| {
11987        let contains = match &args[0] {
11988            Value::Array(a) => a.borrow().iter().any(|v| deep_value_eq(v, &args[1])),
11989            Value::String(s) => {
11990                if let Value::String(sub) = &args[1] {
11991                    s.contains(&**sub)
11992                } else {
11993                    false
11994                }
11995            }
11996            Value::Map(m) => {
11997                if let Value::String(k) = &args[1] {
11998                    m.borrow().contains_key(&**k)
11999                } else {
12000                    false
12001                }
12002            }
12003            Value::Set(s) => {
12004                if let Value::String(k) = &args[1] {
12005                    s.borrow().contains(&**k)
12006                } else {
12007                    false
12008                }
12009            }
12010            _ => false,
12011        };
12012        if contains {
12013            Ok(Value::Bool(true))
12014        } else {
12015            Err(RuntimeError::new(format!(
12016                "Assertion failed: {} does not contain {}",
12017                format_value_debug(&args[0]),
12018                format_value_debug(&args[1])
12019            )))
12020        }
12021    });
12022
12023    // assert_len - assert collection has expected length
12024    define(interp, "assert_len", Some(2), |_, args| {
12025        let expected = match &args[1] {
12026            Value::Int(n) => *n as usize,
12027            _ => {
12028                return Err(RuntimeError::new(
12029                    "assert_len: second argument must be integer",
12030                ))
12031            }
12032        };
12033        let actual = match &args[0] {
12034            Value::String(s) => s.len(),
12035            Value::Array(a) => a.borrow().len(),
12036            Value::Tuple(t) => t.len(),
12037            Value::Map(m) => m.borrow().len(),
12038            Value::Set(s) => s.borrow().len(),
12039            _ => {
12040                return Err(RuntimeError::new(
12041                    "assert_len: first argument must be a collection",
12042                ))
12043            }
12044        };
12045        if actual == expected {
12046            Ok(Value::Bool(true))
12047        } else {
12048            Err(RuntimeError::new(format!(
12049                "Assertion failed: expected length {}, got {}",
12050                expected, actual
12051            )))
12052        }
12053    });
12054
12055    // assert_match - assert string matches regex
12056    define(interp, "assert_match", Some(2), |_, args| {
12057        let text = match &args[0] {
12058            Value::String(s) => (**s).clone(),
12059            _ => {
12060                return Err(RuntimeError::new(
12061                    "assert_match: first argument must be string",
12062                ))
12063            }
12064        };
12065        let pattern = match &args[1] {
12066            Value::String(s) => (**s).clone(),
12067            _ => {
12068                return Err(RuntimeError::new(
12069                    "assert_match: second argument must be regex pattern",
12070                ))
12071            }
12072        };
12073        let re =
12074            Regex::new(&pattern).map_err(|e| RuntimeError::new(format!("Invalid regex: {}", e)))?;
12075        if re.is_match(&text) {
12076            Ok(Value::Bool(true))
12077        } else {
12078            Err(RuntimeError::new(format!(
12079                "Assertion failed: '{}' does not match pattern '{}'",
12080                text, pattern
12081            )))
12082        }
12083    });
12084
12085    // --- TESTING UTILITIES ---
12086
12087    // test - run a test function and report result
12088    define(interp, "test", Some(2), |interp, args| {
12089        let name = match &args[0] {
12090            Value::String(s) => (**s).clone(),
12091            _ => {
12092                return Err(RuntimeError::new(
12093                    "test: first argument must be test name string",
12094                ))
12095            }
12096        };
12097        let func = match &args[1] {
12098            Value::Function(f) => f.clone(),
12099            _ => {
12100                return Err(RuntimeError::new(
12101                    "test: second argument must be test function",
12102                ))
12103            }
12104        };
12105
12106        let start = Instant::now();
12107        let result = interp.call_function(&func, vec![]);
12108        let elapsed = start.elapsed();
12109
12110        match result {
12111            Ok(_) => {
12112                println!("✓ {} ({:.2}ms)", name, elapsed.as_secs_f64() * 1000.0);
12113                Ok(Value::Bool(true))
12114            }
12115            Err(e) => {
12116                println!(
12117                    "✗ {} ({:.2}ms): {}",
12118                    name,
12119                    elapsed.as_secs_f64() * 1000.0,
12120                    e
12121                );
12122                Ok(Value::Bool(false))
12123            }
12124        }
12125    });
12126
12127    // skip - mark a test as skipped
12128    define(interp, "skip", Some(1), |_, args| {
12129        let reason = match &args[0] {
12130            Value::String(s) => (**s).clone(),
12131            _ => "skipped".to_string(),
12132        };
12133        println!("⊘ {}", reason);
12134        Ok(Value::Null)
12135    });
12136
12137    // --- PROFILING ---
12138
12139    // profile - profile a function call and return [result, timing_info]
12140    define(interp, "profile", Some(1), |interp, args| {
12141        let func = match &args[0] {
12142            Value::Function(f) => f.clone(),
12143            _ => return Err(RuntimeError::new("profile: argument must be function")),
12144        };
12145
12146        let start = Instant::now();
12147        let result = interp.call_function(&func, vec![])?;
12148        let elapsed = start.elapsed();
12149
12150        let mut timing = HashMap::new();
12151        timing.insert(
12152            "ms".to_string(),
12153            Value::Float(elapsed.as_secs_f64() * 1000.0),
12154        );
12155        timing.insert("us".to_string(), Value::Float(elapsed.as_micros() as f64));
12156        timing.insert("ns".to_string(), Value::Int(elapsed.as_nanos() as i64));
12157
12158        Ok(Value::Tuple(Rc::new(vec![
12159            result,
12160            Value::Map(Rc::new(RefCell::new(timing))),
12161        ])))
12162    });
12163
12164    // measure - measure execution time of function N times
12165    define(interp, "measure", Some(2), |interp, args| {
12166        let func = match &args[0] {
12167            Value::Function(f) => f.clone(),
12168            _ => {
12169                return Err(RuntimeError::new(
12170                    "measure: first argument must be function",
12171                ))
12172            }
12173        };
12174        let iterations = match &args[1] {
12175            Value::Int(n) => *n as usize,
12176            _ => {
12177                return Err(RuntimeError::new(
12178                    "measure: second argument must be iteration count",
12179                ))
12180            }
12181        };
12182
12183        let mut times: Vec<f64> = Vec::new();
12184        let mut last_result = Value::Null;
12185
12186        for _ in 0..iterations {
12187            let start = Instant::now();
12188            last_result = interp.call_function(&func, vec![])?;
12189            times.push(start.elapsed().as_secs_f64() * 1000.0);
12190        }
12191
12192        let sum: f64 = times.iter().sum();
12193        let avg = sum / iterations as f64;
12194        let min = times.iter().cloned().fold(f64::INFINITY, f64::min);
12195        let max = times.iter().cloned().fold(f64::NEG_INFINITY, f64::max);
12196
12197        let variance: f64 =
12198            times.iter().map(|t| (t - avg).powi(2)).sum::<f64>() / iterations as f64;
12199        let stddev = variance.sqrt();
12200
12201        let mut stats = HashMap::new();
12202        stats.insert("iterations".to_string(), Value::Int(iterations as i64));
12203        stats.insert("total_ms".to_string(), Value::Float(sum));
12204        stats.insert("avg_ms".to_string(), Value::Float(avg));
12205        stats.insert("min_ms".to_string(), Value::Float(min));
12206        stats.insert("max_ms".to_string(), Value::Float(max));
12207        stats.insert("stddev_ms".to_string(), Value::Float(stddev));
12208
12209        Ok(Value::Tuple(Rc::new(vec![
12210            last_result,
12211            Value::Map(Rc::new(RefCell::new(stats))),
12212        ])))
12213    });
12214
12215    // --- DOCUMENTATION ---
12216
12217    // help - get help text for a builtin function
12218    define(interp, "help", Some(1), |_, args| {
12219        let name = match &args[0] {
12220            Value::String(s) => (**s).clone(),
12221            Value::BuiltIn(f) => f.name.clone(),
12222            _ => {
12223                return Err(RuntimeError::new(
12224                    "help: argument must be function name or builtin",
12225                ))
12226            }
12227        };
12228
12229        // Return documentation for known functions
12230        let doc = get_function_doc(&name);
12231        Ok(Value::String(Rc::new(doc)))
12232    });
12233
12234    // list_builtins - list common builtin functions (categories)
12235    define(interp, "list_builtins", Some(0), |_, _| {
12236        let categories = vec![
12237            "Core: print, println, assert, panic, len, type_of",
12238            "Math: abs, floor, ceil, round, sqrt, pow, log, sin, cos, tan",
12239            "Collections: map, filter, reduce, zip, flatten, first, last, sort, reverse",
12240            "Strings: upper, lower, trim, split, join, contains, replace, format",
12241            "IO: read_file, write_file, file_exists, read_line",
12242            "Time: now, sleep, timestamp, format_time",
12243            "JSON: json_parse, json_stringify",
12244            "Crypto: sha256, sha512, md5, base64_encode, base64_decode",
12245            "Regex: regex_match, regex_replace, regex_split",
12246            "Pattern: type_of, is_type, match_regex, match_struct, guard, when",
12247            "DevEx: debug, inspect, trace, assert_eq, assert_ne, test, profile",
12248        ];
12249        let values: Vec<Value> = categories
12250            .iter()
12251            .map(|s| Value::String(Rc::new(s.to_string())))
12252            .collect();
12253        Ok(Value::Array(Rc::new(RefCell::new(values))))
12254    });
12255
12256    // --- UTILITY ---
12257
12258    // todo - placeholder that throws with message
12259    define(interp, "todo", Some(0), |_, _| {
12260        Err(RuntimeError::new("not yet implemented"))
12261    });
12262
12263    // unreachable - mark code as unreachable
12264    define(interp, "unreachable", Some(0), |_, _| {
12265        Err(RuntimeError::new("reached unreachable code"))
12266    });
12267
12268    // unimplemented - mark feature as unimplemented
12269    define(interp, "unimplemented", Some(1), |_, args| {
12270        let msg = match &args[0] {
12271            Value::String(s) => (**s).clone(),
12272            _ => "unimplemented".to_string(),
12273        };
12274        Err(RuntimeError::new(format!("unimplemented: {}", msg)))
12275    });
12276
12277    // deprecated - warn about deprecated usage and return value
12278    define(interp, "deprecated", Some(2), |_, args| {
12279        let msg = match &args[0] {
12280            Value::String(s) => (**s).clone(),
12281            _ => "deprecated".to_string(),
12282        };
12283        eprintln!("[DEPRECATED] {}", msg);
12284        Ok(args[1].clone())
12285    });
12286
12287    // version - return Sigil version info
12288    define(interp, "version", Some(0), |_, _| {
12289        let mut info = HashMap::new();
12290        info.insert(
12291            "sigil".to_string(),
12292            Value::String(Rc::new("0.1.0".to_string())),
12293        );
12294        info.insert(
12295            "stdlib".to_string(),
12296            Value::String(Rc::new("7.0".to_string())),
12297        );
12298        info.insert(
12299            "phase".to_string(),
12300            Value::String(Rc::new("Phase 7 - DevEx".to_string())),
12301        );
12302        Ok(Value::Map(Rc::new(RefCell::new(info))))
12303    });
12304}
12305
12306// Helper to format value for debug output
12307fn format_value_debug(value: &Value) -> String {
12308    match value {
12309        Value::Null => "null".to_string(),
12310        Value::Bool(b) => b.to_string(),
12311        Value::Int(n) => n.to_string(),
12312        Value::Float(f) => format!("{:.6}", f),
12313        Value::String(s) => format!("\"{}\"", s),
12314        Value::Char(c) => format!("'{}'", c),
12315        Value::Array(a) => {
12316            let items: Vec<String> = a.borrow().iter().take(10).map(format_value_debug).collect();
12317            if a.borrow().len() > 10 {
12318                format!(
12319                    "[{}, ... ({} more)]",
12320                    items.join(", "),
12321                    a.borrow().len() - 10
12322                )
12323            } else {
12324                format!("[{}]", items.join(", "))
12325            }
12326        }
12327        Value::Tuple(t) => {
12328            let items: Vec<String> = t.iter().map(format_value_debug).collect();
12329            format!("({})", items.join(", "))
12330        }
12331        Value::Map(m) => {
12332            let items: Vec<String> = m
12333                .borrow()
12334                .iter()
12335                .take(5)
12336                .map(|(k, v)| format!("{}: {}", k, format_value_debug(v)))
12337                .collect();
12338            if m.borrow().len() > 5 {
12339                format!(
12340                    "{{{}, ... ({} more)}}",
12341                    items.join(", "),
12342                    m.borrow().len() - 5
12343                )
12344            } else {
12345                format!("{{{}}}", items.join(", "))
12346            }
12347        }
12348        Value::Set(s) => {
12349            let items: Vec<String> = s.borrow().iter().take(5).cloned().collect();
12350            if s.borrow().len() > 5 {
12351                format!(
12352                    "#{{{}, ... ({} more)}}",
12353                    items.join(", "),
12354                    s.borrow().len() - 5
12355                )
12356            } else {
12357                format!("#{{{}}}", items.join(", "))
12358            }
12359        }
12360        Value::Struct { name, fields } => {
12361            let items: Vec<String> = fields
12362                .borrow()
12363                .iter()
12364                .map(|(k, v)| format!("{}: {}", k, format_value_debug(v)))
12365                .collect();
12366            format!("{} {{{}}}", name, items.join(", "))
12367        }
12368        Value::Variant {
12369            enum_name,
12370            variant_name,
12371            fields,
12372        } => match fields {
12373            Some(f) => {
12374                let items: Vec<String> = f.iter().map(format_value_debug).collect();
12375                format!("{}::{}({})", enum_name, variant_name, items.join(", "))
12376            }
12377            None => format!("{}::{}", enum_name, variant_name),
12378        },
12379        Value::Function(_) => "<function>".to_string(),
12380        Value::BuiltIn(f) => format!("<builtin:{}>", f.name),
12381        Value::Ref(r) => format!("&{}", format_value_debug(&r.borrow())),
12382        Value::Infinity => "∞".to_string(),
12383        Value::Empty => "∅".to_string(),
12384        Value::Evidential { value, evidence } => {
12385            format!("{:?}({})", evidence, format_value_debug(value))
12386        }
12387        Value::Affective { value, affect } => {
12388            let mut markers = Vec::new();
12389            if let Some(s) = &affect.sentiment {
12390                markers.push(format!("{:?}", s));
12391            }
12392            if affect.sarcasm {
12393                markers.push("sarcasm".to_string());
12394            }
12395            if let Some(i) = &affect.intensity {
12396                markers.push(format!("{:?}", i));
12397            }
12398            if let Some(f) = &affect.formality {
12399                markers.push(format!("{:?}", f));
12400            }
12401            if let Some(e) = &affect.emotion {
12402                markers.push(format!("{:?}", e));
12403            }
12404            if let Some(c) = &affect.confidence {
12405                markers.push(format!("{:?}", c));
12406            }
12407            format!("{}[{}]", format_value_debug(value), markers.join(","))
12408        }
12409        Value::Channel(_) => "<channel>".to_string(),
12410        Value::ThreadHandle(_) => "<thread>".to_string(),
12411        Value::Actor(_) => "<actor>".to_string(),
12412        Value::Future(_) => "<future>".to_string(),
12413        Value::VariantConstructor { enum_name, variant_name } => {
12414            format!("<constructor {}::{}>", enum_name, variant_name)
12415        }
12416        Value::DefaultConstructor { type_name } => {
12417            format!("<default {}>", type_name)
12418        }
12419        Value::Range { start, end, inclusive } => {
12420            match (start, end) {
12421                (Some(s), Some(e)) => if *inclusive {
12422                    format!("{}..={}", s, e)
12423                } else {
12424                    format!("{}..{}", s, e)
12425                },
12426                (Some(s), None) => format!("{}..", s),
12427                (None, Some(e)) => if *inclusive {
12428                    format!("..={}", e)
12429                } else {
12430                    format!("..{}", e)
12431                },
12432                (None, None) => "..".to_string(),
12433            }
12434        }
12435        Value::RefCellValue(rc) => format!("RefCell({})", format_value_debug(&rc.value.borrow())),
12436        Value::TraitObject { value, trait_name, concrete_type } => format!("dyn {}({}: {})", trait_name, concrete_type, format_value_debug(value)),
12437    }
12438}
12439
12440// Helper for pretty printing with indentation
12441fn pretty_print_value(value: &Value, indent: usize) -> String {
12442    let prefix = "  ".repeat(indent);
12443    match value {
12444        Value::Array(a) => {
12445            if a.borrow().is_empty() {
12446                "[]".to_string()
12447            } else {
12448                let items: Vec<String> = a
12449                    .borrow()
12450                    .iter()
12451                    .map(|v| {
12452                        format!(
12453                            "{}{}",
12454                            "  ".repeat(indent + 1),
12455                            pretty_print_value(v, indent + 1)
12456                        )
12457                    })
12458                    .collect();
12459                format!("[\n{}\n{}]", items.join(",\n"), prefix)
12460            }
12461        }
12462        Value::Map(m) => {
12463            if m.borrow().is_empty() {
12464                "{}".to_string()
12465            } else {
12466                let items: Vec<String> = m
12467                    .borrow()
12468                    .iter()
12469                    .map(|(k, v)| {
12470                        format!(
12471                            "{}\"{}\": {}",
12472                            "  ".repeat(indent + 1),
12473                            k,
12474                            pretty_print_value(v, indent + 1)
12475                        )
12476                    })
12477                    .collect();
12478                format!("{{\n{}\n{}}}", items.join(",\n"), prefix)
12479            }
12480        }
12481        Value::Struct { name, fields } => {
12482            if fields.borrow().is_empty() {
12483                format!("{} {{}}", name)
12484            } else {
12485                let items: Vec<String> = fields
12486                    .borrow()
12487                    .iter()
12488                    .map(|(k, v)| {
12489                        format!(
12490                            "{}{}: {}",
12491                            "  ".repeat(indent + 1),
12492                            k,
12493                            pretty_print_value(v, indent + 1)
12494                        )
12495                    })
12496                    .collect();
12497                format!("{} {{\n{}\n{}}}", name, items.join(",\n"), prefix)
12498            }
12499        }
12500        _ => format_value_debug(value),
12501    }
12502}
12503
12504// Helper to compare values for ordering (DevEx assertions)
12505fn devex_compare(a: &Value, b: &Value) -> Result<i64, RuntimeError> {
12506    match (a, b) {
12507        (Value::Int(a), Value::Int(b)) => Ok(if a < b {
12508            -1
12509        } else if a > b {
12510            1
12511        } else {
12512            0
12513        }),
12514        (Value::Float(a), Value::Float(b)) => Ok(if a < b {
12515            -1
12516        } else if a > b {
12517            1
12518        } else {
12519            0
12520        }),
12521        (Value::Int(a), Value::Float(b)) => {
12522            let a = *a as f64;
12523            Ok(if a < *b {
12524                -1
12525            } else if a > *b {
12526                1
12527            } else {
12528                0
12529            })
12530        }
12531        (Value::Float(a), Value::Int(b)) => {
12532            let b = *b as f64;
12533            Ok(if *a < b {
12534                -1
12535            } else if *a > b {
12536                1
12537            } else {
12538                0
12539            })
12540        }
12541        (Value::String(a), Value::String(b)) => Ok(if a < b {
12542            -1
12543        } else if a > b {
12544            1
12545        } else {
12546            0
12547        }),
12548        _ => Err(RuntimeError::new("cannot compare these types")),
12549    }
12550}
12551
12552// Helper to get type name
12553fn get_type_name(value: &Value) -> String {
12554    match value {
12555        Value::Null => "null".to_string(),
12556        Value::Bool(_) => "bool".to_string(),
12557        Value::Int(_) => "int".to_string(),
12558        Value::Float(_) => "float".to_string(),
12559        Value::String(_) => "string".to_string(),
12560        Value::Char(_) => "char".to_string(),
12561        Value::Array(_) => "array".to_string(),
12562        Value::Tuple(_) => "tuple".to_string(),
12563        Value::Map(_) => "map".to_string(),
12564        Value::Set(_) => "set".to_string(),
12565        Value::Struct { name, .. } => name.clone(),
12566        Value::Variant { enum_name, .. } => enum_name.clone(),
12567        Value::Function(_) => "function".to_string(),
12568        Value::BuiltIn(_) => "builtin".to_string(),
12569        Value::Ref(_) => "ref".to_string(),
12570        Value::Infinity => "infinity".to_string(),
12571        Value::Empty => "empty".to_string(),
12572        Value::Evidential { .. } => "evidential".to_string(),
12573        Value::Affective { .. } => "affective".to_string(),
12574        Value::Channel(_) => "channel".to_string(),
12575        Value::ThreadHandle(_) => "thread".to_string(),
12576        Value::Actor(_) => "actor".to_string(),
12577        Value::Future(_) => "future".to_string(),
12578        Value::VariantConstructor { enum_name, .. } => format!("{}_constructor", enum_name),
12579        Value::DefaultConstructor { type_name } => format!("{}_default", type_name),
12580        Value::Range { .. } => "range".to_string(),
12581        Value::RefCellValue(_) => "refcell".to_string(),
12582        Value::TraitObject { trait_name, .. } => format!("dyn {}", trait_name),
12583    }
12584}
12585
12586// Helper to check type aliases
12587fn matches_type_alias(value: &Value, type_name: &str) -> bool {
12588    match (value, type_name) {
12589        (Value::Int(_), "number") | (Value::Float(_), "number") => true,
12590        (Value::Int(_), "integer") => true,
12591        (Value::Array(_), "list") => true,
12592        (Value::Map(_), "dict") | (Value::Map(_), "object") => true,
12593        (Value::Function(_), "fn") | (Value::BuiltIn(_), "fn") => true,
12594        (Value::BuiltIn(_), "function") => true,
12595        _ => false,
12596    }
12597}
12598
12599// Helper to get function documentation
12600fn get_function_doc(name: &str) -> String {
12601    match name {
12602        "print" => "print(value) - Print value to stdout".to_string(),
12603        "println" => "println(value) - Print value with newline".to_string(),
12604        "len" => "len(collection) - Get length of string, array, map, or set".to_string(),
12605        "type_of" => "type_of(value) - Get type name as string".to_string(),
12606        "assert" => "assert(condition) - Assert condition is truthy, panic if false".to_string(),
12607        "assert_eq" => "assert_eq(a, b) - Assert two values are deeply equal".to_string(),
12608        "debug" => "debug(value) - Print value with type info and return it".to_string(),
12609        "map" => "map(array, fn) - Apply function to each element".to_string(),
12610        "filter" => "filter(array, fn) - Keep elements where predicate is true".to_string(),
12611        "reduce" => "reduce(array, init, fn) - Fold array with function".to_string(),
12612        "range" => "range(start, end) - Create array of integers from start to end".to_string(),
12613        "sum" => "sum(array) - Sum all numeric elements".to_string(),
12614        "product" => "product(array) - Multiply all numeric elements".to_string(),
12615        "sort" => "sort(array) - Sort array in ascending order".to_string(),
12616        "reverse" => "reverse(array) - Reverse array order".to_string(),
12617        "join" => "join(array, sep) - Join array elements with separator".to_string(),
12618        "split" => "split(string, sep) - Split string by separator".to_string(),
12619        "trim" => "trim(string) - Remove leading/trailing whitespace".to_string(),
12620        "upper" => "upper(string) - Convert to uppercase".to_string(),
12621        "lower" => "lower(string) - Convert to lowercase".to_string(),
12622        _ => format!("No documentation available for '{}'", name),
12623    }
12624}
12625
12626// ============================================================================
12627// PHASE 8: PERFORMANCE OPTIMIZATIONS
12628// ============================================================================
12629// SoA transforms, tensor ops, autodiff, spatial hashing, constraint solving
12630
12631// ============================================================================
12632// SOA (STRUCT OF ARRAYS) TRANSFORMS
12633// ============================================================================
12634// Convert between AoS (Array of Structs) and SoA (Struct of Arrays) layouts
12635// Critical for SIMD and cache-friendly physics/graphics computations
12636
12637fn register_soa(interp: &mut Interpreter) {
12638    // aos_to_soa(array, keys) - Convert Array of Structs to Struct of Arrays
12639    // Example: aos_to_soa([{x:1,y:2}, {x:3,y:4}], ["x","y"]) -> {x:[1,3], y:[2,4]}
12640    define(interp, "aos_to_soa", Some(2), |_, args| {
12641        let arr = match &args[0] {
12642            Value::Array(arr) => arr.borrow().clone(),
12643            _ => {
12644                return Err(RuntimeError::new(
12645                    "aos_to_soa: first argument must be array",
12646                ))
12647            }
12648        };
12649        let keys = match &args[1] {
12650            Value::Array(keys) => keys.borrow().clone(),
12651            _ => {
12652                return Err(RuntimeError::new(
12653                    "aos_to_soa: second argument must be array of keys",
12654                ))
12655            }
12656        };
12657
12658        if arr.is_empty() {
12659            // Return empty SoA
12660            let mut result = HashMap::new();
12661            for key in &keys {
12662                if let Value::String(k) = key {
12663                    result.insert((**k).clone(), Value::Array(Rc::new(RefCell::new(vec![]))));
12664                }
12665            }
12666            return Ok(Value::Map(Rc::new(RefCell::new(result))));
12667        }
12668
12669        // Extract key names
12670        let key_names: Vec<String> = keys
12671            .iter()
12672            .filter_map(|k| {
12673                if let Value::String(s) = k {
12674                    Some((**s).clone())
12675                } else {
12676                    None
12677                }
12678            })
12679            .collect();
12680
12681        // Build arrays for each key
12682        let mut soa: HashMap<String, Vec<Value>> = HashMap::new();
12683        for key in &key_names {
12684            soa.insert(key.clone(), Vec::with_capacity(arr.len()));
12685        }
12686
12687        // Extract values from each struct
12688        for item in &arr {
12689            match item {
12690                Value::Map(map) => {
12691                    let map = map.borrow();
12692                    for key in &key_names {
12693                        let val = map.get(key).cloned().unwrap_or(Value::Null);
12694                        soa.get_mut(key).unwrap().push(val);
12695                    }
12696                }
12697                Value::Struct { fields, .. } => {
12698                    let fields = fields.borrow();
12699                    for key in &key_names {
12700                        let val = fields.get(key).cloned().unwrap_or(Value::Null);
12701                        soa.get_mut(key).unwrap().push(val);
12702                    }
12703                }
12704                _ => {
12705                    return Err(RuntimeError::new(
12706                        "aos_to_soa: array must contain structs or maps",
12707                    ))
12708                }
12709            }
12710        }
12711
12712        // Convert to Value::Map
12713        let result: HashMap<String, Value> = soa
12714            .into_iter()
12715            .map(|(k, v)| (k, Value::Array(Rc::new(RefCell::new(v)))))
12716            .collect();
12717
12718        Ok(Value::Map(Rc::new(RefCell::new(result))))
12719    });
12720
12721    // soa_to_aos(soa) - Convert Struct of Arrays back to Array of Structs
12722    // Example: soa_to_aos({x:[1,3], y:[2,4]}) -> [{x:1,y:2}, {x:3,y:4}]
12723    define(interp, "soa_to_aos", Some(1), |_, args| {
12724        let soa = match &args[0] {
12725            Value::Map(map) => map.borrow().clone(),
12726            _ => return Err(RuntimeError::new("soa_to_aos: argument must be map")),
12727        };
12728
12729        if soa.is_empty() {
12730            return Ok(Value::Array(Rc::new(RefCell::new(vec![]))));
12731        }
12732
12733        // Get the length from first array
12734        let len = soa
12735            .values()
12736            .next()
12737            .and_then(|v| {
12738                if let Value::Array(arr) = v {
12739                    Some(arr.borrow().len())
12740                } else {
12741                    None
12742                }
12743            })
12744            .unwrap_or(0);
12745
12746        // Build array of structs
12747        let mut aos: Vec<Value> = Vec::with_capacity(len);
12748        for i in 0..len {
12749            let mut fields = HashMap::new();
12750            for (key, value) in &soa {
12751                if let Value::Array(arr) = value {
12752                    let arr = arr.borrow();
12753                    if i < arr.len() {
12754                        fields.insert(key.clone(), arr[i].clone());
12755                    }
12756                }
12757            }
12758            aos.push(Value::Map(Rc::new(RefCell::new(fields))));
12759        }
12760
12761        Ok(Value::Array(Rc::new(RefCell::new(aos))))
12762    });
12763
12764    // soa_map(soa, key, fn) - Apply function to a single array in SoA
12765    // Allows SIMD-friendly operations on one field at a time
12766    define(interp, "soa_map", Some(3), |interp, args| {
12767        let mut soa = match &args[0] {
12768            Value::Map(map) => map.borrow().clone(),
12769            _ => return Err(RuntimeError::new("soa_map: first argument must be SoA map")),
12770        };
12771        let key = match &args[1] {
12772            Value::String(s) => (**s).clone(),
12773            _ => {
12774                return Err(RuntimeError::new(
12775                    "soa_map: second argument must be key string",
12776                ))
12777            }
12778        };
12779        let func = match &args[2] {
12780            Value::Function(f) => f.clone(),
12781            _ => {
12782                return Err(RuntimeError::new(
12783                    "soa_map: third argument must be a function",
12784                ))
12785            }
12786        };
12787
12788        // Get the array for this key
12789        let arr = soa
12790            .get(&key)
12791            .ok_or_else(|| RuntimeError::new(format!("soa_map: key '{}' not found", key)))?;
12792
12793        let arr_vals = match arr {
12794            Value::Array(a) => a.borrow().clone(),
12795            _ => return Err(RuntimeError::new("soa_map: key must map to array")),
12796        };
12797
12798        // Apply function to each element
12799        let results: Vec<Value> = arr_vals
12800            .iter()
12801            .map(|val| interp.call_function(&func, vec![val.clone()]))
12802            .collect::<Result<_, _>>()?;
12803
12804        // Update SoA
12805        soa.insert(key, Value::Array(Rc::new(RefCell::new(results))));
12806
12807        Ok(Value::Map(Rc::new(RefCell::new(soa))))
12808    });
12809
12810    // soa_zip(soa, keys, fn) - Apply function to multiple fields in parallel
12811    // Example: soa_zip(soa, ["x", "y"], fn(x, y) { sqrt(x*x + y*y) }) -> array of magnitudes
12812    define(interp, "soa_zip", Some(3), |interp, args| {
12813        let soa = match &args[0] {
12814            Value::Map(map) => map.borrow().clone(),
12815            _ => return Err(RuntimeError::new("soa_zip: first argument must be SoA map")),
12816        };
12817        let keys = match &args[1] {
12818            Value::Array(keys) => keys.borrow().clone(),
12819            _ => {
12820                return Err(RuntimeError::new(
12821                    "soa_zip: second argument must be array of keys",
12822                ))
12823            }
12824        };
12825        let func = match &args[2] {
12826            Value::Function(f) => f.clone(),
12827            _ => {
12828                return Err(RuntimeError::new(
12829                    "soa_zip: third argument must be a function",
12830                ))
12831            }
12832        };
12833
12834        // Extract arrays for each key
12835        let arrays: Vec<Vec<Value>> = keys
12836            .iter()
12837            .filter_map(|k| {
12838                if let Value::String(s) = k {
12839                    if let Some(Value::Array(arr)) = soa.get(&**s) {
12840                        return Some(arr.borrow().clone());
12841                    }
12842                }
12843                None
12844            })
12845            .collect();
12846
12847        if arrays.is_empty() {
12848            return Ok(Value::Array(Rc::new(RefCell::new(vec![]))));
12849        }
12850
12851        let len = arrays[0].len();
12852
12853        // Apply function with zipped values
12854        let results: Vec<Value> = (0..len)
12855            .map(|i| {
12856                let fn_args: Vec<Value> = arrays
12857                    .iter()
12858                    .filter_map(|arr| arr.get(i).cloned())
12859                    .collect();
12860                interp.call_function(&func, fn_args)
12861            })
12862            .collect::<Result<_, _>>()?;
12863
12864        Ok(Value::Array(Rc::new(RefCell::new(results))))
12865    });
12866
12867    // interleave(arrays...) - Interleave multiple arrays (for position/normal/uv vertices)
12868    // Example: interleave([x1,x2], [y1,y2], [z1,z2]) -> [x1,y1,z1,x2,y2,z2]
12869    define(interp, "interleave", None, |_, args| {
12870        if args.is_empty() {
12871            return Ok(Value::Array(Rc::new(RefCell::new(vec![]))));
12872        }
12873
12874        let arrays: Vec<Vec<Value>> = args
12875            .iter()
12876            .filter_map(|arg| {
12877                if let Value::Array(arr) = arg {
12878                    Some(arr.borrow().clone())
12879                } else {
12880                    None
12881                }
12882            })
12883            .collect();
12884
12885        if arrays.is_empty() {
12886            return Ok(Value::Array(Rc::new(RefCell::new(vec![]))));
12887        }
12888
12889        let len = arrays[0].len();
12890        let stride = arrays.len();
12891        let mut result = Vec::with_capacity(len * stride);
12892
12893        for i in 0..len {
12894            for arr in &arrays {
12895                if let Some(val) = arr.get(i) {
12896                    result.push(val.clone());
12897                }
12898            }
12899        }
12900
12901        Ok(Value::Array(Rc::new(RefCell::new(result))))
12902    });
12903
12904    // deinterleave(array, stride) - Deinterleave an array (inverse of interleave)
12905    // Example: deinterleave([x1,y1,z1,x2,y2,z2], 3) -> [[x1,x2], [y1,y2], [z1,z2]]
12906    define(interp, "deinterleave", Some(2), |_, args| {
12907        let arr = match &args[0] {
12908            Value::Array(arr) => arr.borrow().clone(),
12909            _ => {
12910                return Err(RuntimeError::new(
12911                    "deinterleave: first argument must be array",
12912                ))
12913            }
12914        };
12915        let stride = match &args[1] {
12916            Value::Int(n) => *n as usize,
12917            _ => {
12918                return Err(RuntimeError::new(
12919                    "deinterleave: second argument must be integer stride",
12920                ))
12921            }
12922        };
12923
12924        if stride == 0 {
12925            return Err(RuntimeError::new("deinterleave: stride must be > 0"));
12926        }
12927
12928        let mut result: Vec<Vec<Value>> = (0..stride).map(|_| Vec::new()).collect();
12929
12930        for (i, val) in arr.iter().enumerate() {
12931            result[i % stride].push(val.clone());
12932        }
12933
12934        Ok(Value::Array(Rc::new(RefCell::new(
12935            result
12936                .into_iter()
12937                .map(|v| Value::Array(Rc::new(RefCell::new(v))))
12938                .collect(),
12939        ))))
12940    });
12941}
12942
12943// ============================================================================
12944// TENSOR OPERATIONS
12945// ============================================================================
12946// Outer products, contractions, tensor transpose for advanced linear algebra
12947
12948fn register_tensor(interp: &mut Interpreter) {
12949    // outer_product(a, b) - Tensor outer product: a ⊗ b
12950    // vec × vec -> matrix, mat × vec -> rank-3 tensor
12951    define(interp, "outer_product", Some(2), |_, args| {
12952        let a = match &args[0] {
12953            Value::Array(arr) => arr.borrow().clone(),
12954            _ => return Err(RuntimeError::new("outer_product: arguments must be arrays")),
12955        };
12956        let b = match &args[1] {
12957            Value::Array(arr) => arr.borrow().clone(),
12958            _ => return Err(RuntimeError::new("outer_product: arguments must be arrays")),
12959        };
12960
12961        // vec ⊗ vec -> matrix
12962        let mut result: Vec<Value> = Vec::with_capacity(a.len() * b.len());
12963        for ai in &a {
12964            for bi in &b {
12965                let product = match (ai, bi) {
12966                    (Value::Float(x), Value::Float(y)) => Value::Float(x * y),
12967                    (Value::Int(x), Value::Int(y)) => Value::Int(x * y),
12968                    (Value::Float(x), Value::Int(y)) => Value::Float(x * (*y as f64)),
12969                    (Value::Int(x), Value::Float(y)) => Value::Float((*x as f64) * y),
12970                    _ => return Err(RuntimeError::new("outer_product: elements must be numeric")),
12971                };
12972                result.push(product);
12973            }
12974        }
12975
12976        Ok(Value::Array(Rc::new(RefCell::new(result))))
12977    });
12978
12979    // tensor_contract(a, b, axis_a, axis_b) - Contract tensors along specified axes
12980    // Generalized matrix multiplication and index contraction
12981    define(interp, "tensor_contract", Some(4), |_, args| {
12982        let a = match &args[0] {
12983            Value::Array(arr) => arr.borrow().clone(),
12984            _ => {
12985                return Err(RuntimeError::new(
12986                    "tensor_contract: first argument must be array",
12987                ))
12988            }
12989        };
12990        let b = match &args[1] {
12991            Value::Array(arr) => arr.borrow().clone(),
12992            _ => {
12993                return Err(RuntimeError::new(
12994                    "tensor_contract: second argument must be array",
12995                ))
12996            }
12997        };
12998        let _axis_a = match &args[2] {
12999            Value::Int(n) => *n as usize,
13000            _ => return Err(RuntimeError::new("tensor_contract: axis must be integer")),
13001        };
13002        let _axis_b = match &args[3] {
13003            Value::Int(n) => *n as usize,
13004            _ => return Err(RuntimeError::new("tensor_contract: axis must be integer")),
13005        };
13006
13007        // Simple dot product for 1D tensors (vectors)
13008        if a.len() != b.len() {
13009            return Err(RuntimeError::new(
13010                "tensor_contract: vectors must have same length for contraction",
13011            ));
13012        }
13013
13014        let mut sum = 0.0f64;
13015        for (ai, bi) in a.iter().zip(b.iter()) {
13016            let product = match (ai, bi) {
13017                (Value::Float(x), Value::Float(y)) => x * y,
13018                (Value::Int(x), Value::Int(y)) => (*x as f64) * (*y as f64),
13019                (Value::Float(x), Value::Int(y)) => x * (*y as f64),
13020                (Value::Int(x), Value::Float(y)) => (*x as f64) * y,
13021                _ => {
13022                    return Err(RuntimeError::new(
13023                        "tensor_contract: elements must be numeric",
13024                    ))
13025                }
13026            };
13027            sum += product;
13028        }
13029
13030        Ok(Value::Float(sum))
13031    });
13032
13033    // kronecker_product(a, b) - Kronecker tensor product
13034    // Used in quantum computing and multi-linear algebra
13035    define(interp, "kronecker_product", Some(2), |_, args| {
13036        let a = match &args[0] {
13037            Value::Array(arr) => arr.borrow().clone(),
13038            _ => {
13039                return Err(RuntimeError::new(
13040                    "kronecker_product: arguments must be arrays",
13041                ))
13042            }
13043        };
13044        let b = match &args[1] {
13045            Value::Array(arr) => arr.borrow().clone(),
13046            _ => {
13047                return Err(RuntimeError::new(
13048                    "kronecker_product: arguments must be arrays",
13049                ))
13050            }
13051        };
13052
13053        // For 1D vectors: same as outer product
13054        let mut result: Vec<Value> = Vec::with_capacity(a.len() * b.len());
13055        for ai in &a {
13056            for bi in &b {
13057                let product = match (ai, bi) {
13058                    (Value::Float(x), Value::Float(y)) => Value::Float(x * y),
13059                    (Value::Int(x), Value::Int(y)) => Value::Int(x * y),
13060                    (Value::Float(x), Value::Int(y)) => Value::Float(x * (*y as f64)),
13061                    (Value::Int(x), Value::Float(y)) => Value::Float((*x as f64) * y),
13062                    _ => {
13063                        return Err(RuntimeError::new(
13064                            "kronecker_product: elements must be numeric",
13065                        ))
13066                    }
13067                };
13068                result.push(product);
13069            }
13070        }
13071
13072        Ok(Value::Array(Rc::new(RefCell::new(result))))
13073    });
13074
13075    // hadamard_product(a, b) - Element-wise product (Hadamard/Schur product)
13076    define(interp, "hadamard_product", Some(2), |_, args| {
13077        let a = match &args[0] {
13078            Value::Array(arr) => arr.borrow().clone(),
13079            _ => {
13080                return Err(RuntimeError::new(
13081                    "hadamard_product: arguments must be arrays",
13082                ))
13083            }
13084        };
13085        let b = match &args[1] {
13086            Value::Array(arr) => arr.borrow().clone(),
13087            _ => {
13088                return Err(RuntimeError::new(
13089                    "hadamard_product: arguments must be arrays",
13090                ))
13091            }
13092        };
13093
13094        if a.len() != b.len() {
13095            return Err(RuntimeError::new(
13096                "hadamard_product: arrays must have same length",
13097            ));
13098        }
13099
13100        let result: Vec<Value> = a
13101            .iter()
13102            .zip(b.iter())
13103            .map(|(ai, bi)| match (ai, bi) {
13104                (Value::Float(x), Value::Float(y)) => Ok(Value::Float(x * y)),
13105                (Value::Int(x), Value::Int(y)) => Ok(Value::Int(x * y)),
13106                (Value::Float(x), Value::Int(y)) => Ok(Value::Float(x * (*y as f64))),
13107                (Value::Int(x), Value::Float(y)) => Ok(Value::Float((*x as f64) * y)),
13108                _ => Err(RuntimeError::new(
13109                    "hadamard_product: elements must be numeric",
13110                )),
13111            })
13112            .collect::<Result<_, _>>()?;
13113
13114        Ok(Value::Array(Rc::new(RefCell::new(result))))
13115    });
13116
13117    // trace(matrix, size) - Trace of square matrix (sum of diagonal)
13118    define(interp, "trace", Some(2), |_, args| {
13119        let arr = match &args[0] {
13120            Value::Array(arr) => arr.borrow().clone(),
13121            _ => return Err(RuntimeError::new("trace: first argument must be array")),
13122        };
13123        let size = match &args[1] {
13124            Value::Int(n) => *n as usize,
13125            _ => {
13126                return Err(RuntimeError::new(
13127                    "trace: second argument must be matrix size",
13128                ))
13129            }
13130        };
13131
13132        let mut sum = 0.0f64;
13133        for i in 0..size {
13134            let idx = i * size + i;
13135            if idx < arr.len() {
13136                sum += match &arr[idx] {
13137                    Value::Float(f) => *f,
13138                    Value::Int(n) => *n as f64,
13139                    _ => return Err(RuntimeError::new("trace: elements must be numeric")),
13140                };
13141            }
13142        }
13143
13144        Ok(Value::Float(sum))
13145    });
13146}
13147
13148// ============================================================================
13149// AUTOMATIC DIFFERENTIATION
13150// ============================================================================
13151//
13152// This module provides numerical differentiation using finite differences.
13153// While not as accurate as symbolic or dual-number autodiff, it's simple
13154// and works for any function without special annotations.
13155//
13156// ## Available Functions
13157//
13158// | Function | Description | Complexity |
13159// |----------|-------------|------------|
13160// | `grad(f, x, [h])` | Gradient of f at x | O(n) function calls |
13161// | `jacobian(f, x, [h])` | Jacobian matrix | O(m*n) function calls |
13162// | `hessian(f, x, [h])` | Hessian matrix | O(n²) function calls |
13163// | `directional_derivative(f, x, v, [h])` | Derivative along v | O(1) |
13164// | `laplacian(f, x, [h])` | Sum of second partials | O(n) |
13165//
13166// ## Algorithm Details
13167//
13168// All functions use central differences: (f(x+h) - f(x-h)) / 2h
13169// Default step size h = 1e-7 (optimized for f64 precision)
13170//
13171// ## Usage Examples
13172//
13173// ```sigil
13174// // Scalar function gradient
13175// fn f(x) { return x * x; }
13176// let df = grad(f, 3.0);  // Returns 6.0 (derivative of x² at x=3)
13177//
13178// // Multi-variable gradient
13179// fn g(x) { return get(x, 0)*get(x, 0) + get(x, 1)*get(x, 1); }
13180// let dg = grad(g, [1.0, 2.0]);  // Returns [2.0, 4.0]
13181//
13182// // Hessian of f at point x
13183// let H = hessian(f, [x, y]);  // Returns 2D array of second derivatives
13184// ```
13185//
13186// ## Performance Notes
13187//
13188// - grad: 2n function evaluations for n-dimensional input
13189// - jacobian: 2mn evaluations for m-output, n-input function
13190// - hessian: 4n² evaluations (computed from gradient)
13191// - For performance-critical code, consider symbolic differentiation
13192
13193fn register_autodiff(interp: &mut Interpreter) {
13194    // grad(f, x, h) - Numerical gradient of f at x using finite differences
13195    // h is optional step size (default 1e-7)
13196    define(interp, "grad", None, |interp, args| {
13197        if args.len() < 2 {
13198            return Err(RuntimeError::new(
13199                "grad() requires function and point arguments.\n\
13200                 Usage: grad(f, x) or grad(f, x, step_size)\n\
13201                 Example:\n\
13202                   fn f(x) { return x * x; }\n\
13203                   let derivative = grad(f, 3.0);  // Returns 6.0",
13204            ));
13205        }
13206
13207        let func = match &args[0] {
13208            Value::Function(f) => f.clone(),
13209            _ => {
13210                return Err(RuntimeError::new(
13211                    "grad() first argument must be a function.\n\
13212                 Got non-function value. Define a function first:\n\
13213                   fn my_func(x) { return x * x; }\n\
13214                   grad(my_func, 2.0)",
13215                ))
13216            }
13217        };
13218        let x = match &args[1] {
13219            Value::Float(f) => *f,
13220            Value::Int(n) => *n as f64,
13221            Value::Array(arr) => {
13222                // Multi-variable gradient
13223                let arr = arr.borrow().clone();
13224                let h = if args.len() > 2 {
13225                    match &args[2] {
13226                        Value::Float(f) => *f,
13227                        Value::Int(n) => *n as f64,
13228                        _ => 1e-7,
13229                    }
13230                } else {
13231                    1e-7
13232                };
13233
13234                let mut gradient = Vec::with_capacity(arr.len());
13235                for (i, xi) in arr.iter().enumerate() {
13236                    let xi_val = match xi {
13237                        Value::Float(f) => *f,
13238                        Value::Int(n) => *n as f64,
13239                        _ => continue,
13240                    };
13241
13242                    // f(x + h*ei) - f(x - h*ei) / 2h
13243                    let mut x_plus = arr.clone();
13244                    let mut x_minus = arr.clone();
13245                    x_plus[i] = Value::Float(xi_val + h);
13246                    x_minus[i] = Value::Float(xi_val - h);
13247
13248                    let f_plus = interp
13249                        .call_function(&func, vec![Value::Array(Rc::new(RefCell::new(x_plus)))])?;
13250                    let f_minus = interp
13251                        .call_function(&func, vec![Value::Array(Rc::new(RefCell::new(x_minus)))])?;
13252
13253                    let grad_i = match (f_plus, f_minus) {
13254                        (Value::Float(fp), Value::Float(fm)) => (fp - fm) / (2.0 * h),
13255                        (Value::Int(fp), Value::Int(fm)) => (fp - fm) as f64 / (2.0 * h),
13256                        _ => return Err(RuntimeError::new("grad: function must return numeric")),
13257                    };
13258
13259                    gradient.push(Value::Float(grad_i));
13260                }
13261
13262                return Ok(Value::Array(Rc::new(RefCell::new(gradient))));
13263            }
13264            _ => return Err(RuntimeError::new("grad: x must be numeric or array")),
13265        };
13266
13267        let h = if args.len() > 2 {
13268            match &args[2] {
13269                Value::Float(f) => *f,
13270                Value::Int(n) => *n as f64,
13271                _ => 1e-7,
13272            }
13273        } else {
13274            1e-7
13275        };
13276
13277        // Single variable derivative using central difference
13278        let f_plus = interp.call_function(&func, vec![Value::Float(x + h)])?;
13279        let f_minus = interp.call_function(&func, vec![Value::Float(x - h)])?;
13280
13281        let derivative = match (f_plus, f_minus) {
13282            (Value::Float(fp), Value::Float(fm)) => (fp - fm) / (2.0 * h),
13283            (Value::Int(fp), Value::Int(fm)) => (fp - fm) as f64 / (2.0 * h),
13284            _ => return Err(RuntimeError::new("grad: function must return numeric")),
13285        };
13286
13287        Ok(Value::Float(derivative))
13288    });
13289
13290    // jacobian(f, x) - Compute Jacobian matrix for vector function
13291    define(interp, "jacobian", Some(2), |interp, args| {
13292        let func = match &args[0] {
13293            Value::Function(f) => f.clone(),
13294            _ => {
13295                return Err(RuntimeError::new(
13296                    "jacobian: first argument must be a function",
13297                ))
13298            }
13299        };
13300        let x = match &args[1] {
13301            Value::Array(arr) => arr.borrow().clone(),
13302            _ => return Err(RuntimeError::new("jacobian: second argument must be array")),
13303        };
13304
13305        let h = 1e-7;
13306        let n = x.len();
13307
13308        // Evaluate f at x to get output dimension
13309        let f_x =
13310            interp.call_function(&func, vec![Value::Array(Rc::new(RefCell::new(x.clone())))])?;
13311        let m = match &f_x {
13312            Value::Array(arr) => arr.borrow().len(),
13313            _ => 1,
13314        };
13315
13316        // Build Jacobian matrix (m x n)
13317        let mut jacobian: Vec<Value> = Vec::with_capacity(m * n);
13318
13319        for j in 0..n {
13320            let xj = match &x[j] {
13321                Value::Float(f) => *f,
13322                Value::Int(i) => *i as f64,
13323                _ => continue,
13324            };
13325
13326            let mut x_plus = x.clone();
13327            let mut x_minus = x.clone();
13328            x_plus[j] = Value::Float(xj + h);
13329            x_minus[j] = Value::Float(xj - h);
13330
13331            let f_plus =
13332                interp.call_function(&func, vec![Value::Array(Rc::new(RefCell::new(x_plus)))])?;
13333            let f_minus =
13334                interp.call_function(&func, vec![Value::Array(Rc::new(RefCell::new(x_minus)))])?;
13335
13336            // Extract derivatives for each output component
13337            match (&f_plus, &f_minus) {
13338                (Value::Array(fp), Value::Array(fm)) => {
13339                    let fp = fp.borrow();
13340                    let fm = fm.borrow();
13341                    for i in 0..m {
13342                        let dfi_dxj = match (&fp[i], &fm[i]) {
13343                            (Value::Float(a), Value::Float(b)) => (*a - *b) / (2.0 * h),
13344                            (Value::Int(a), Value::Int(b)) => (*a - *b) as f64 / (2.0 * h),
13345                            _ => 0.0,
13346                        };
13347                        jacobian.push(Value::Float(dfi_dxj));
13348                    }
13349                }
13350                (Value::Float(fp), Value::Float(fm)) => {
13351                    jacobian.push(Value::Float((fp - fm) / (2.0 * h)));
13352                }
13353                _ => {
13354                    return Err(RuntimeError::new(
13355                        "jacobian: function must return array or numeric",
13356                    ))
13357                }
13358            }
13359        }
13360
13361        Ok(Value::Array(Rc::new(RefCell::new(jacobian))))
13362    });
13363
13364    // hessian(f, x) - Compute Hessian matrix (second derivatives)
13365    define(interp, "hessian", Some(2), |interp, args| {
13366        let func = match &args[0] {
13367            Value::Function(f) => f.clone(),
13368            _ => {
13369                return Err(RuntimeError::new(
13370                    "hessian: first argument must be a function",
13371                ))
13372            }
13373        };
13374        let x = match &args[1] {
13375            Value::Array(arr) => arr.borrow().clone(),
13376            _ => return Err(RuntimeError::new("hessian: second argument must be array")),
13377        };
13378
13379        let h = 1e-5; // Larger h for second derivatives
13380        let n = x.len();
13381
13382        let mut hessian: Vec<Value> = Vec::with_capacity(n * n);
13383
13384        for i in 0..n {
13385            for j in 0..n {
13386                let xi = match &x[i] {
13387                    Value::Float(f) => *f,
13388                    Value::Int(k) => *k as f64,
13389                    _ => continue,
13390                };
13391                let xj = match &x[j] {
13392                    Value::Float(f) => *f,
13393                    Value::Int(k) => *k as f64,
13394                    _ => continue,
13395                };
13396
13397                // Second partial derivative using finite differences
13398                let mut x_pp = x.clone();
13399                let mut x_pm = x.clone();
13400                let mut x_mp = x.clone();
13401                let mut x_mm = x.clone();
13402
13403                x_pp[i] = Value::Float(xi + h);
13404                x_pp[j] = Value::Float(if i == j { xi + 2.0 * h } else { xj + h });
13405                x_pm[i] = Value::Float(xi + h);
13406                x_pm[j] = Value::Float(if i == j { xi } else { xj - h });
13407                x_mp[i] = Value::Float(xi - h);
13408                x_mp[j] = Value::Float(if i == j { xi } else { xj + h });
13409                x_mm[i] = Value::Float(xi - h);
13410                x_mm[j] = Value::Float(if i == j { xi - 2.0 * h } else { xj - h });
13411
13412                let f_pp =
13413                    interp.call_function(&func, vec![Value::Array(Rc::new(RefCell::new(x_pp)))])?;
13414                let f_pm =
13415                    interp.call_function(&func, vec![Value::Array(Rc::new(RefCell::new(x_pm)))])?;
13416                let f_mp =
13417                    interp.call_function(&func, vec![Value::Array(Rc::new(RefCell::new(x_mp)))])?;
13418                let f_mm =
13419                    interp.call_function(&func, vec![Value::Array(Rc::new(RefCell::new(x_mm)))])?;
13420
13421                let d2f = match (f_pp, f_pm, f_mp, f_mm) {
13422                    (
13423                        Value::Float(fpp),
13424                        Value::Float(fpm),
13425                        Value::Float(fmp),
13426                        Value::Float(fmm),
13427                    ) => (fpp - fpm - fmp + fmm) / (4.0 * h * h),
13428                    _ => 0.0,
13429                };
13430
13431                hessian.push(Value::Float(d2f));
13432            }
13433        }
13434
13435        Ok(Value::Array(Rc::new(RefCell::new(hessian))))
13436    });
13437
13438    // divergence(f, x) - Compute divergence of vector field (∇·F)
13439    define(interp, "divergence", Some(2), |interp, args| {
13440        let func = match &args[0] {
13441            Value::Function(f) => f.clone(),
13442            _ => {
13443                return Err(RuntimeError::new(
13444                    "divergence: first argument must be a function",
13445                ))
13446            }
13447        };
13448        let x = match &args[1] {
13449            Value::Array(arr) => arr.borrow().clone(),
13450            _ => {
13451                return Err(RuntimeError::new(
13452                    "divergence: second argument must be array",
13453                ))
13454            }
13455        };
13456
13457        let h = 1e-7;
13458        let mut div = 0.0f64;
13459
13460        for (i, xi) in x.iter().enumerate() {
13461            let xi_val = match xi {
13462                Value::Float(f) => *f,
13463                Value::Int(n) => *n as f64,
13464                _ => continue,
13465            };
13466
13467            let mut x_plus = x.clone();
13468            let mut x_minus = x.clone();
13469            x_plus[i] = Value::Float(xi_val + h);
13470            x_minus[i] = Value::Float(xi_val - h);
13471
13472            let f_plus =
13473                interp.call_function(&func, vec![Value::Array(Rc::new(RefCell::new(x_plus)))])?;
13474            let f_minus =
13475                interp.call_function(&func, vec![Value::Array(Rc::new(RefCell::new(x_minus)))])?;
13476
13477            // Extract i-th component
13478            let df_i = match (&f_plus, &f_minus) {
13479                (Value::Array(fp), Value::Array(fm)) => {
13480                    let fp = fp.borrow();
13481                    let fm = fm.borrow();
13482                    if i < fp.len() && i < fm.len() {
13483                        match (&fp[i], &fm[i]) {
13484                            (Value::Float(a), Value::Float(b)) => (*a - *b) / (2.0 * h),
13485                            (Value::Int(a), Value::Int(b)) => (*a - *b) as f64 / (2.0 * h),
13486                            _ => 0.0,
13487                        }
13488                    } else {
13489                        0.0
13490                    }
13491                }
13492                _ => 0.0,
13493            };
13494
13495            div += df_i;
13496        }
13497
13498        Ok(Value::Float(div))
13499    });
13500}
13501
13502// ============================================================================
13503// SPATIAL HASHING / ACCELERATION STRUCTURES
13504// ============================================================================
13505// BVH, octrees, spatial hashing for efficient collision detection and queries
13506
13507fn register_spatial(interp: &mut Interpreter) {
13508    // spatial_hash_new(cell_size) - Create new spatial hash grid
13509    define(interp, "spatial_hash_new", Some(1), |_, args| {
13510        let cell_size = match &args[0] {
13511            Value::Float(f) => *f,
13512            Value::Int(n) => *n as f64,
13513            _ => {
13514                return Err(RuntimeError::new(
13515                    "spatial_hash_new: cell_size must be numeric",
13516                ))
13517            }
13518        };
13519
13520        let mut config = HashMap::new();
13521        config.insert("cell_size".to_string(), Value::Float(cell_size));
13522        config.insert(
13523            "buckets".to_string(),
13524            Value::Map(Rc::new(RefCell::new(HashMap::new()))),
13525        );
13526
13527        Ok(Value::Map(Rc::new(RefCell::new(config))))
13528    });
13529
13530    // spatial_hash_insert(hash, id, position) - Insert object at position
13531    define(interp, "spatial_hash_insert", Some(3), |_, args| {
13532        let hash = match &args[0] {
13533            Value::Map(map) => map.clone(),
13534            _ => {
13535                return Err(RuntimeError::new(
13536                    "spatial_hash_insert: first argument must be spatial hash",
13537                ))
13538            }
13539        };
13540        let id = args[1].clone();
13541        let pos = match &args[2] {
13542            Value::Array(arr) => arr.borrow().clone(),
13543            _ => {
13544                return Err(RuntimeError::new(
13545                    "spatial_hash_insert: position must be array",
13546                ))
13547            }
13548        };
13549
13550        let cell_size = {
13551            let h = hash.borrow();
13552            match h.get("cell_size") {
13553                Some(Value::Float(f)) => *f,
13554                _ => 1.0,
13555            }
13556        };
13557
13558        // Compute cell key
13559        let key = pos
13560            .iter()
13561            .filter_map(|v| match v {
13562                Value::Float(f) => Some((*f / cell_size).floor() as i64),
13563                Value::Int(n) => Some(*n / (cell_size as i64)),
13564                _ => None,
13565            })
13566            .map(|n| n.to_string())
13567            .collect::<Vec<_>>()
13568            .join(",");
13569
13570        // Insert into bucket
13571        {
13572            let mut h = hash.borrow_mut();
13573            let buckets = h
13574                .entry("buckets".to_string())
13575                .or_insert_with(|| Value::Map(Rc::new(RefCell::new(HashMap::new()))));
13576
13577            if let Value::Map(buckets_map) = buckets {
13578                let mut bm = buckets_map.borrow_mut();
13579                let bucket = bm
13580                    .entry(key)
13581                    .or_insert_with(|| Value::Array(Rc::new(RefCell::new(vec![]))));
13582
13583                if let Value::Array(arr) = bucket {
13584                    arr.borrow_mut().push(id);
13585                }
13586            }
13587        }
13588
13589        Ok(Value::Map(hash))
13590    });
13591
13592    // spatial_hash_query(hash, position, radius) - Query objects near position
13593    define(interp, "spatial_hash_query", Some(3), |_, args| {
13594        let hash = match &args[0] {
13595            Value::Map(map) => map.borrow().clone(),
13596            _ => {
13597                return Err(RuntimeError::new(
13598                    "spatial_hash_query: first argument must be spatial hash",
13599                ))
13600            }
13601        };
13602        let pos = match &args[1] {
13603            Value::Array(arr) => arr.borrow().clone(),
13604            _ => {
13605                return Err(RuntimeError::new(
13606                    "spatial_hash_query: position must be array",
13607                ))
13608            }
13609        };
13610        let radius = match &args[2] {
13611            Value::Float(f) => *f,
13612            Value::Int(n) => *n as f64,
13613            _ => {
13614                return Err(RuntimeError::new(
13615                    "spatial_hash_query: radius must be numeric",
13616                ))
13617            }
13618        };
13619
13620        let cell_size = match hash.get("cell_size") {
13621            Some(Value::Float(f)) => *f,
13622            _ => 1.0,
13623        };
13624
13625        // Get center cell
13626        let center: Vec<i64> = pos
13627            .iter()
13628            .filter_map(|v| match v {
13629                Value::Float(f) => Some((*f / cell_size).floor() as i64),
13630                Value::Int(n) => Some(*n / (cell_size as i64)),
13631                _ => None,
13632            })
13633            .collect();
13634
13635        // Compute cell range to check
13636        let cells_to_check = (radius / cell_size).ceil() as i64;
13637
13638        let mut results: Vec<Value> = Vec::new();
13639
13640        if let Some(Value::Map(buckets)) = hash.get("buckets") {
13641            let buckets = buckets.borrow();
13642
13643            // Check neighboring cells
13644            if center.len() >= 2 {
13645                for dx in -cells_to_check..=cells_to_check {
13646                    for dy in -cells_to_check..=cells_to_check {
13647                        let key = format!("{},{}", center[0] + dx, center[1] + dy);
13648                        if let Some(Value::Array(bucket)) = buckets.get(&key) {
13649                            for item in bucket.borrow().iter() {
13650                                // Push without duplicate check since Value doesn't impl PartialEq
13651                                // For production use, would need to track IDs separately
13652                                results.push(item.clone());
13653                            }
13654                        }
13655                    }
13656                }
13657            }
13658        }
13659
13660        Ok(Value::Array(Rc::new(RefCell::new(results))))
13661    });
13662
13663    // aabb_new(min, max) - Create axis-aligned bounding box
13664    define(interp, "aabb_new", Some(2), |_, args| {
13665        let min = match &args[0] {
13666            Value::Array(arr) => arr.borrow().clone(),
13667            _ => return Err(RuntimeError::new("aabb_new: min must be array")),
13668        };
13669        let max = match &args[1] {
13670            Value::Array(arr) => arr.borrow().clone(),
13671            _ => return Err(RuntimeError::new("aabb_new: max must be array")),
13672        };
13673
13674        let mut aabb = HashMap::new();
13675        aabb.insert("min".to_string(), Value::Array(Rc::new(RefCell::new(min))));
13676        aabb.insert("max".to_string(), Value::Array(Rc::new(RefCell::new(max))));
13677
13678        Ok(Value::Map(Rc::new(RefCell::new(aabb))))
13679    });
13680
13681    // aabb_intersects(a, b) - Test if two AABBs intersect
13682    define(interp, "aabb_intersects", Some(2), |_, args| {
13683        let a = match &args[0] {
13684            Value::Map(map) => map.borrow().clone(),
13685            _ => {
13686                return Err(RuntimeError::new(
13687                    "aabb_intersects: arguments must be AABBs",
13688                ))
13689            }
13690        };
13691        let b = match &args[1] {
13692            Value::Map(map) => map.borrow().clone(),
13693            _ => {
13694                return Err(RuntimeError::new(
13695                    "aabb_intersects: arguments must be AABBs",
13696                ))
13697            }
13698        };
13699
13700        let a_min = extract_vec_from_map(&a, "min")?;
13701        let a_max = extract_vec_from_map(&a, "max")?;
13702        let b_min = extract_vec_from_map(&b, "min")?;
13703        let b_max = extract_vec_from_map(&b, "max")?;
13704
13705        // Check overlap in each dimension
13706        for i in 0..a_min
13707            .len()
13708            .min(a_max.len())
13709            .min(b_min.len())
13710            .min(b_max.len())
13711        {
13712            if a_max[i] < b_min[i] || b_max[i] < a_min[i] {
13713                return Ok(Value::Bool(false));
13714            }
13715        }
13716
13717        Ok(Value::Bool(true))
13718    });
13719
13720    // aabb_contains(aabb, point) - Test if AABB contains point
13721    define(interp, "aabb_contains", Some(2), |_, args| {
13722        let aabb = match &args[0] {
13723            Value::Map(map) => map.borrow().clone(),
13724            _ => {
13725                return Err(RuntimeError::new(
13726                    "aabb_contains: first argument must be AABB",
13727                ))
13728            }
13729        };
13730        let point = match &args[1] {
13731            Value::Array(arr) => arr.borrow().clone(),
13732            _ => {
13733                return Err(RuntimeError::new(
13734                    "aabb_contains: second argument must be point array",
13735                ))
13736            }
13737        };
13738
13739        let min = extract_vec_from_map(&aabb, "min")?;
13740        let max = extract_vec_from_map(&aabb, "max")?;
13741
13742        for (i, p) in point.iter().enumerate() {
13743            let p_val = match p {
13744                Value::Float(f) => *f,
13745                Value::Int(n) => *n as f64,
13746                _ => continue,
13747            };
13748
13749            if i < min.len() && p_val < min[i] {
13750                return Ok(Value::Bool(false));
13751            }
13752            if i < max.len() && p_val > max[i] {
13753                return Ok(Value::Bool(false));
13754            }
13755        }
13756
13757        Ok(Value::Bool(true))
13758    });
13759}
13760
13761// Helper for extracting vector from AABB map
13762fn extract_vec_from_map(map: &HashMap<String, Value>, key: &str) -> Result<Vec<f64>, RuntimeError> {
13763    match map.get(key) {
13764        Some(Value::Array(arr)) => arr
13765            .borrow()
13766            .iter()
13767            .map(|v| match v {
13768                Value::Float(f) => Ok(*f),
13769                Value::Int(n) => Ok(*n as f64),
13770                _ => Err(RuntimeError::new("Expected numeric value")),
13771            })
13772            .collect(),
13773        _ => Err(RuntimeError::new(format!(
13774            "Missing or invalid '{}' in AABB",
13775            key
13776        ))),
13777    }
13778}
13779
13780// ============================================================================
13781// PHYSICS / CONSTRAINT SOLVER
13782// ============================================================================
13783// Verlet integration, constraint solving, spring systems
13784
13785fn register_physics(interp: &mut Interpreter) {
13786    // verlet_integrate(pos, prev_pos, accel, dt) - Verlet integration step
13787    // Returns new position: pos + (pos - prev_pos) + accel * dt^2
13788    define(interp, "verlet_integrate", Some(4), |_, args| {
13789        let pos = extract_vec3(&args[0], "verlet_integrate")?;
13790        let prev = extract_vec3(&args[1], "verlet_integrate")?;
13791        let accel = extract_vec3(&args[2], "verlet_integrate")?;
13792        let dt = match &args[3] {
13793            Value::Float(f) => *f,
13794            Value::Int(n) => *n as f64,
13795            _ => return Err(RuntimeError::new("verlet_integrate: dt must be numeric")),
13796        };
13797
13798        let dt2 = dt * dt;
13799        let new_pos = [
13800            pos[0] + (pos[0] - prev[0]) + accel[0] * dt2,
13801            pos[1] + (pos[1] - prev[1]) + accel[1] * dt2,
13802            pos[2] + (pos[2] - prev[2]) + accel[2] * dt2,
13803        ];
13804
13805        Ok(make_vec3_arr(new_pos))
13806    });
13807
13808    // spring_force(p1, p2, rest_length, stiffness) - Compute spring force
13809    define(interp, "spring_force", Some(4), |_, args| {
13810        let p1 = extract_vec3(&args[0], "spring_force")?;
13811        let p2 = extract_vec3(&args[1], "spring_force")?;
13812        let rest_length = match &args[2] {
13813            Value::Float(f) => *f,
13814            Value::Int(n) => *n as f64,
13815            _ => {
13816                return Err(RuntimeError::new(
13817                    "spring_force: rest_length must be numeric",
13818                ))
13819            }
13820        };
13821        let stiffness = match &args[3] {
13822            Value::Float(f) => *f,
13823            Value::Int(n) => *n as f64,
13824            _ => return Err(RuntimeError::new("spring_force: stiffness must be numeric")),
13825        };
13826
13827        let delta = [p2[0] - p1[0], p2[1] - p1[1], p2[2] - p1[2]];
13828        let length = (delta[0] * delta[0] + delta[1] * delta[1] + delta[2] * delta[2]).sqrt();
13829
13830        if length < 1e-10 {
13831            return Ok(make_vec3_arr([0.0, 0.0, 0.0]));
13832        }
13833
13834        let displacement = length - rest_length;
13835        let force_mag = stiffness * displacement;
13836        let normalized = [delta[0] / length, delta[1] / length, delta[2] / length];
13837
13838        Ok(make_vec3_arr([
13839            normalized[0] * force_mag,
13840            normalized[1] * force_mag,
13841            normalized[2] * force_mag,
13842        ]))
13843    });
13844
13845    // distance_constraint(p1, p2, target_distance) - Apply distance constraint
13846    // Returns tuple of (new_p1, new_p2) that satisfy the constraint
13847    define(interp, "distance_constraint", Some(3), |_, args| {
13848        let p1 = extract_vec3(&args[0], "distance_constraint")?;
13849        let p2 = extract_vec3(&args[1], "distance_constraint")?;
13850        let target = match &args[2] {
13851            Value::Float(f) => *f,
13852            Value::Int(n) => *n as f64,
13853            _ => {
13854                return Err(RuntimeError::new(
13855                    "distance_constraint: target must be numeric",
13856                ))
13857            }
13858        };
13859
13860        let delta = [p2[0] - p1[0], p2[1] - p1[1], p2[2] - p1[2]];
13861        let length = (delta[0] * delta[0] + delta[1] * delta[1] + delta[2] * delta[2]).sqrt();
13862
13863        if length < 1e-10 {
13864            return Ok(Value::Tuple(Rc::new(vec![
13865                make_vec3_arr(p1),
13866                make_vec3_arr(p2),
13867            ])));
13868        }
13869
13870        let correction = (length - target) / length * 0.5;
13871        let corr_vec = [
13872            delta[0] * correction,
13873            delta[1] * correction,
13874            delta[2] * correction,
13875        ];
13876
13877        let new_p1 = [
13878            p1[0] + corr_vec[0],
13879            p1[1] + corr_vec[1],
13880            p1[2] + corr_vec[2],
13881        ];
13882        let new_p2 = [
13883            p2[0] - corr_vec[0],
13884            p2[1] - corr_vec[1],
13885            p2[2] - corr_vec[2],
13886        ];
13887
13888        Ok(Value::Tuple(Rc::new(vec![
13889            make_vec3_arr(new_p1),
13890            make_vec3_arr(new_p2),
13891        ])))
13892    });
13893
13894    // solve_constraints(points, constraints, iterations) - Iterative constraint solver
13895    // constraints: array of {type, indices, params}
13896    define(interp, "solve_constraints", Some(3), |_, args| {
13897        let mut points = match &args[0] {
13898            Value::Array(arr) => arr.borrow().clone(),
13899            _ => {
13900                return Err(RuntimeError::new(
13901                    "solve_constraints: first argument must be array of points",
13902                ))
13903            }
13904        };
13905        let constraints = match &args[1] {
13906            Value::Array(arr) => arr.borrow().clone(),
13907            _ => {
13908                return Err(RuntimeError::new(
13909                    "solve_constraints: second argument must be array of constraints",
13910                ))
13911            }
13912        };
13913        let iterations = match &args[2] {
13914            Value::Int(n) => *n as usize,
13915            _ => {
13916                return Err(RuntimeError::new(
13917                    "solve_constraints: iterations must be integer",
13918                ))
13919            }
13920        };
13921
13922        for _ in 0..iterations {
13923            for constraint in &constraints {
13924                match constraint {
13925                    Value::Map(c) => {
13926                        let c = c.borrow();
13927                        let constraint_type = c
13928                            .get("type")
13929                            .and_then(|v| {
13930                                if let Value::String(s) = v {
13931                                    Some((**s).clone())
13932                                } else {
13933                                    None
13934                                }
13935                            })
13936                            .unwrap_or_default();
13937
13938                        match constraint_type.as_str() {
13939                            "distance" => {
13940                                let indices = match c.get("indices") {
13941                                    Some(Value::Array(arr)) => arr.borrow().clone(),
13942                                    _ => continue,
13943                                };
13944                                let target = match c.get("distance") {
13945                                    Some(Value::Float(f)) => *f,
13946                                    Some(Value::Int(n)) => *n as f64,
13947                                    _ => continue,
13948                                };
13949
13950                                if indices.len() >= 2 {
13951                                    let i1 = match &indices[0] {
13952                                        Value::Int(n) => *n as usize,
13953                                        _ => continue,
13954                                    };
13955                                    let i2 = match &indices[1] {
13956                                        Value::Int(n) => *n as usize,
13957                                        _ => continue,
13958                                    };
13959
13960                                    if i1 < points.len() && i2 < points.len() {
13961                                        // Apply distance constraint inline
13962                                        let p1 = extract_vec3(&points[i1], "solve")?;
13963                                        let p2 = extract_vec3(&points[i2], "solve")?;
13964
13965                                        let delta = [p2[0] - p1[0], p2[1] - p1[1], p2[2] - p1[2]];
13966                                        let length = (delta[0] * delta[0]
13967                                            + delta[1] * delta[1]
13968                                            + delta[2] * delta[2])
13969                                            .sqrt();
13970
13971                                        if length > 1e-10 {
13972                                            let correction = (length - target) / length * 0.5;
13973                                            let corr_vec = [
13974                                                delta[0] * correction,
13975                                                delta[1] * correction,
13976                                                delta[2] * correction,
13977                                            ];
13978
13979                                            points[i1] = make_vec3_arr([
13980                                                p1[0] + corr_vec[0],
13981                                                p1[1] + corr_vec[1],
13982                                                p1[2] + corr_vec[2],
13983                                            ]);
13984                                            points[i2] = make_vec3_arr([
13985                                                p2[0] - corr_vec[0],
13986                                                p2[1] - corr_vec[1],
13987                                                p2[2] - corr_vec[2],
13988                                            ]);
13989                                        }
13990                                    }
13991                                }
13992                            }
13993                            _ => {}
13994                        }
13995                    }
13996                    _ => continue,
13997                }
13998            }
13999        }
14000
14001        Ok(Value::Array(Rc::new(RefCell::new(points))))
14002    });
14003
14004    // ray_sphere_intersect(ray_origin, ray_dir, sphere_center, radius) - Ray-sphere intersection
14005    // Returns distance to intersection or -1 if no hit
14006    define(interp, "ray_sphere_intersect", Some(4), |_, args| {
14007        let origin = extract_vec3(&args[0], "ray_sphere_intersect")?;
14008        let dir = extract_vec3(&args[1], "ray_sphere_intersect")?;
14009        let center = extract_vec3(&args[2], "ray_sphere_intersect")?;
14010        let radius = match &args[3] {
14011            Value::Float(f) => *f,
14012            Value::Int(n) => *n as f64,
14013            _ => {
14014                return Err(RuntimeError::new(
14015                    "ray_sphere_intersect: radius must be numeric",
14016                ))
14017            }
14018        };
14019
14020        let oc = [
14021            origin[0] - center[0],
14022            origin[1] - center[1],
14023            origin[2] - center[2],
14024        ];
14025
14026        let a = dir[0] * dir[0] + dir[1] * dir[1] + dir[2] * dir[2];
14027        let b = 2.0 * (oc[0] * dir[0] + oc[1] * dir[1] + oc[2] * dir[2]);
14028        let c = oc[0] * oc[0] + oc[1] * oc[1] + oc[2] * oc[2] - radius * radius;
14029
14030        let discriminant = b * b - 4.0 * a * c;
14031
14032        if discriminant < 0.0 {
14033            Ok(Value::Float(-1.0))
14034        } else {
14035            let t = (-b - discriminant.sqrt()) / (2.0 * a);
14036            if t > 0.0 {
14037                Ok(Value::Float(t))
14038            } else {
14039                let t2 = (-b + discriminant.sqrt()) / (2.0 * a);
14040                if t2 > 0.0 {
14041                    Ok(Value::Float(t2))
14042                } else {
14043                    Ok(Value::Float(-1.0))
14044                }
14045            }
14046        }
14047    });
14048
14049    // ray_plane_intersect(ray_origin, ray_dir, plane_point, plane_normal) - Ray-plane intersection
14050    define(interp, "ray_plane_intersect", Some(4), |_, args| {
14051        let origin = extract_vec3(&args[0], "ray_plane_intersect")?;
14052        let dir = extract_vec3(&args[1], "ray_plane_intersect")?;
14053        let plane_pt = extract_vec3(&args[2], "ray_plane_intersect")?;
14054        let normal = extract_vec3(&args[3], "ray_plane_intersect")?;
14055
14056        let denom = dir[0] * normal[0] + dir[1] * normal[1] + dir[2] * normal[2];
14057
14058        if denom.abs() < 1e-10 {
14059            return Ok(Value::Float(-1.0)); // Parallel to plane
14060        }
14061
14062        let diff = [
14063            plane_pt[0] - origin[0],
14064            plane_pt[1] - origin[1],
14065            plane_pt[2] - origin[2],
14066        ];
14067        let t = (diff[0] * normal[0] + diff[1] * normal[1] + diff[2] * normal[2]) / denom;
14068
14069        if t > 0.0 {
14070            Ok(Value::Float(t))
14071        } else {
14072            Ok(Value::Float(-1.0))
14073        }
14074    });
14075}
14076
14077// ============================================================================
14078// GEOMETRIC ALGEBRA (GA3D - Cl(3,0,0))
14079// ============================================================================
14080//
14081// Complete Clifford Algebra implementation in 3D. Geometric Algebra unifies:
14082// - Complex numbers (as rotations in 2D)
14083// - Quaternions (as rotors in 3D)
14084// - Vectors, bivectors, and trivectors
14085// - Reflections, rotations, and projections
14086//
14087// ## Multivector Structure
14088//
14089// | Grade | Basis | Name | Geometric Meaning |
14090// |-------|-------|------|-------------------|
14091// | 0 | 1 | Scalar | Magnitude |
14092// | 1 | e₁, e₂, e₃ | Vectors | Directed lengths |
14093// | 2 | e₁₂, e₂₃, e₃₁ | Bivectors | Oriented planes |
14094// | 3 | e₁₂₃ | Trivector | Oriented volume |
14095//
14096// ## Key Operations
14097//
14098// | Function | Description | Mathematical Form |
14099// |----------|-------------|-------------------|
14100// | `mv_new(s, e1..e123)` | Create multivector | s + e₁v₁ + ... + e₁₂₃t |
14101// | `mv_geometric_product(a, b)` | Geometric product | ab (non-commutative) |
14102// | `mv_inner_product(a, b)` | Inner product | a·b |
14103// | `mv_outer_product(a, b)` | Outer product | a∧b (wedge) |
14104// | `rotor_from_axis_angle(axis, θ)` | Create rotor | cos(θ/2) + sin(θ/2)·B |
14105// | `rotor_apply(R, v)` | Apply rotor | RvR† (sandwich) |
14106//
14107// ## Rotor Properties
14108//
14109// Rotors are normalized even-grade multivectors (scalar + bivector).
14110// They rotate vectors via the "sandwich product": v' = RvR†
14111// This is more efficient than matrix multiplication and composes naturally.
14112//
14113// ## Usage Examples
14114//
14115// ```sigil
14116// // Create a 90° rotation around Z-axis
14117// let axis = vec3(0, 0, 1);
14118// let R = rotor_from_axis_angle(axis, PI / 2.0);
14119//
14120// // Rotate a vector
14121// let v = vec3(1, 0, 0);
14122// let v_rotated = rotor_apply(R, v);  // Returns [0, 1, 0]
14123//
14124// // Compose rotations
14125// let R2 = rotor_from_axis_angle(vec3(0, 1, 0), PI / 4.0);
14126// let R_combined = rotor_compose(R, R2);  // First R, then R2
14127// ```
14128//
14129// ## Grade Extraction
14130//
14131// | Function | Returns |
14132// |----------|---------|
14133// | `mv_grade(mv, 0)` | Scalar part |
14134// | `mv_grade(mv, 1)` | Vector part |
14135// | `mv_grade(mv, 2)` | Bivector part |
14136// | `mv_grade(mv, 3)` | Trivector part |
14137
14138fn register_geometric_algebra(interp: &mut Interpreter) {
14139    // Helper to create a multivector from 8 components
14140    fn make_multivector(components: [f64; 8]) -> Value {
14141        let mut mv = HashMap::new();
14142        mv.insert("s".to_string(), Value::Float(components[0])); // scalar
14143        mv.insert("e1".to_string(), Value::Float(components[1])); // e₁
14144        mv.insert("e2".to_string(), Value::Float(components[2])); // e₂
14145        mv.insert("e3".to_string(), Value::Float(components[3])); // e₃
14146        mv.insert("e12".to_string(), Value::Float(components[4])); // e₁₂
14147        mv.insert("e23".to_string(), Value::Float(components[5])); // e₂₃
14148        mv.insert("e31".to_string(), Value::Float(components[6])); // e₃₁
14149        mv.insert("e123".to_string(), Value::Float(components[7])); // e₁₂₃ (pseudoscalar)
14150        mv.insert(
14151            "_type".to_string(),
14152            Value::String(Rc::new("multivector".to_string())),
14153        );
14154        Value::Map(Rc::new(RefCell::new(mv)))
14155    }
14156
14157    fn extract_multivector(v: &Value, fn_name: &str) -> Result<[f64; 8], RuntimeError> {
14158        match v {
14159            Value::Map(map) => {
14160                let map = map.borrow();
14161                let get_component = |key: &str| -> f64 {
14162                    match map.get(key) {
14163                        Some(Value::Float(f)) => *f,
14164                        Some(Value::Int(n)) => *n as f64,
14165                        _ => 0.0,
14166                    }
14167                };
14168                Ok([
14169                    get_component("s"),
14170                    get_component("e1"),
14171                    get_component("e2"),
14172                    get_component("e3"),
14173                    get_component("e12"),
14174                    get_component("e23"),
14175                    get_component("e31"),
14176                    get_component("e123"),
14177                ])
14178            }
14179            _ => Err(RuntimeError::new(format!(
14180                "{}: expected multivector",
14181                fn_name
14182            ))),
14183        }
14184    }
14185
14186    // mv_new(s, e1, e2, e3, e12, e23, e31, e123) - Create multivector from components
14187    define(interp, "mv_new", Some(8), |_, args| {
14188        let mut components = [0.0f64; 8];
14189        for (i, arg) in args.iter().enumerate().take(8) {
14190            components[i] = match arg {
14191                Value::Float(f) => *f,
14192                Value::Int(n) => *n as f64,
14193                _ => 0.0,
14194            };
14195        }
14196        Ok(make_multivector(components))
14197    });
14198
14199    // mv_scalar(s) - Create scalar multivector
14200    define(interp, "mv_scalar", Some(1), |_, args| {
14201        let s = match &args[0] {
14202            Value::Float(f) => *f,
14203            Value::Int(n) => *n as f64,
14204            _ => return Err(RuntimeError::new("mv_scalar: expected number")),
14205        };
14206        Ok(make_multivector([s, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]))
14207    });
14208
14209    // mv_vector(x, y, z) - Create vector (grade-1 multivector)
14210    define(interp, "mv_vector", Some(3), |_, args| {
14211        let x = match &args[0] {
14212            Value::Float(f) => *f,
14213            Value::Int(n) => *n as f64,
14214            _ => 0.0,
14215        };
14216        let y = match &args[1] {
14217            Value::Float(f) => *f,
14218            Value::Int(n) => *n as f64,
14219            _ => 0.0,
14220        };
14221        let z = match &args[2] {
14222            Value::Float(f) => *f,
14223            Value::Int(n) => *n as f64,
14224            _ => 0.0,
14225        };
14226        Ok(make_multivector([0.0, x, y, z, 0.0, 0.0, 0.0, 0.0]))
14227    });
14228
14229    // mv_bivector(xy, yz, zx) - Create bivector (grade-2, represents oriented planes)
14230    define(interp, "mv_bivector", Some(3), |_, args| {
14231        let xy = match &args[0] {
14232            Value::Float(f) => *f,
14233            Value::Int(n) => *n as f64,
14234            _ => 0.0,
14235        };
14236        let yz = match &args[1] {
14237            Value::Float(f) => *f,
14238            Value::Int(n) => *n as f64,
14239            _ => 0.0,
14240        };
14241        let zx = match &args[2] {
14242            Value::Float(f) => *f,
14243            Value::Int(n) => *n as f64,
14244            _ => 0.0,
14245        };
14246        Ok(make_multivector([0.0, 0.0, 0.0, 0.0, xy, yz, zx, 0.0]))
14247    });
14248
14249    // mv_trivector(xyz) - Create trivector/pseudoscalar (grade-3, represents oriented volume)
14250    define(interp, "mv_trivector", Some(1), |_, args| {
14251        let xyz = match &args[0] {
14252            Value::Float(f) => *f,
14253            Value::Int(n) => *n as f64,
14254            _ => 0.0,
14255        };
14256        Ok(make_multivector([0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, xyz]))
14257    });
14258
14259    // mv_add(a, b) - Add two multivectors
14260    define(interp, "mv_add", Some(2), |_, args| {
14261        let a = extract_multivector(&args[0], "mv_add")?;
14262        let b = extract_multivector(&args[1], "mv_add")?;
14263        Ok(make_multivector([
14264            a[0] + b[0],
14265            a[1] + b[1],
14266            a[2] + b[2],
14267            a[3] + b[3],
14268            a[4] + b[4],
14269            a[5] + b[5],
14270            a[6] + b[6],
14271            a[7] + b[7],
14272        ]))
14273    });
14274
14275    // mv_sub(a, b) - Subtract two multivectors
14276    define(interp, "mv_sub", Some(2), |_, args| {
14277        let a = extract_multivector(&args[0], "mv_sub")?;
14278        let b = extract_multivector(&args[1], "mv_sub")?;
14279        Ok(make_multivector([
14280            a[0] - b[0],
14281            a[1] - b[1],
14282            a[2] - b[2],
14283            a[3] - b[3],
14284            a[4] - b[4],
14285            a[5] - b[5],
14286            a[6] - b[6],
14287            a[7] - b[7],
14288        ]))
14289    });
14290
14291    // mv_scale(mv, scalar) - Scale a multivector
14292    define(interp, "mv_scale", Some(2), |_, args| {
14293        let a = extract_multivector(&args[0], "mv_scale")?;
14294        let s = match &args[1] {
14295            Value::Float(f) => *f,
14296            Value::Int(n) => *n as f64,
14297            _ => {
14298                return Err(RuntimeError::new(
14299                    "mv_scale: second argument must be number",
14300                ))
14301            }
14302        };
14303        Ok(make_multivector([
14304            a[0] * s,
14305            a[1] * s,
14306            a[2] * s,
14307            a[3] * s,
14308            a[4] * s,
14309            a[5] * s,
14310            a[6] * s,
14311            a[7] * s,
14312        ]))
14313    });
14314
14315    // mv_geometric(a, b) - Geometric product (THE fundamental operation)
14316    // This is what makes GA powerful: ab = a·b + a∧b
14317    define(interp, "mv_geometric", Some(2), |_, args| {
14318        let a = extract_multivector(&args[0], "mv_geometric")?;
14319        let b = extract_multivector(&args[1], "mv_geometric")?;
14320
14321        // Full geometric product in Cl(3,0,0)
14322        // Using: e₁² = e₂² = e₃² = 1, eᵢeⱼ = -eⱼeᵢ for i≠j
14323        let mut r = [0.0f64; 8];
14324
14325        // Scalar part
14326        r[0] = a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]
14327            - a[4] * b[4]
14328            - a[5] * b[5]
14329            - a[6] * b[6]
14330            - a[7] * b[7];
14331
14332        // e₁ part
14333        r[1] = a[0] * b[1] + a[1] * b[0] - a[2] * b[4] + a[3] * b[6] + a[4] * b[2]
14334            - a[5] * b[7]
14335            - a[6] * b[3]
14336            - a[7] * b[5];
14337
14338        // e₂ part
14339        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]
14340            - a[6] * b[7]
14341            - a[7] * b[6];
14342
14343        // e₃ part
14344        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]
14345            + a[6] * b[1]
14346            - a[7] * b[4];
14347
14348        // e₁₂ part
14349        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]
14350            - a[6] * b[5]
14351            + a[7] * b[3];
14352
14353        // e₂₃ part
14354        r[5] = a[0] * b[5] + a[1] * b[7] + a[2] * b[3] - a[3] * b[2] - a[4] * b[6]
14355            + a[5] * b[0]
14356            + a[6] * b[4]
14357            + a[7] * b[1];
14358
14359        // e₃₁ part
14360        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]
14361            + a[6] * b[0]
14362            + a[7] * b[2];
14363
14364        // e₁₂₃ part
14365        r[7] = a[0] * b[7]
14366            + a[1] * b[5]
14367            + a[2] * b[6]
14368            + a[3] * b[4]
14369            + a[4] * b[3]
14370            + a[5] * b[1]
14371            + a[6] * b[2]
14372            + a[7] * b[0];
14373
14374        Ok(make_multivector(r))
14375    });
14376
14377    // mv_wedge(a, b) - Outer/wedge product (∧) - antisymmetric part
14378    // Creates higher-grade elements: vector ∧ vector = bivector
14379    define(interp, "mv_wedge", Some(2), |_, args| {
14380        let a = extract_multivector(&args[0], "mv_wedge")?;
14381        let b = extract_multivector(&args[1], "mv_wedge")?;
14382
14383        let mut r = [0.0f64; 8];
14384
14385        // Scalar ∧ anything = scalar * anything (grade 0)
14386        r[0] = a[0] * b[0];
14387
14388        // Vector parts (grade 1): s∧v + v∧s
14389        r[1] = a[0] * b[1] + a[1] * b[0];
14390        r[2] = a[0] * b[2] + a[2] * b[0];
14391        r[3] = a[0] * b[3] + a[3] * b[0];
14392
14393        // Bivector parts (grade 2): s∧B + v∧v + B∧s
14394        r[4] = a[0] * b[4] + a[1] * b[2] - a[2] * b[1] + a[4] * b[0];
14395        r[5] = a[0] * b[5] + a[2] * b[3] - a[3] * b[2] + a[5] * b[0];
14396        r[6] = a[0] * b[6] + a[3] * b[1] - a[1] * b[3] + a[6] * b[0];
14397
14398        // Trivector part (grade 3): s∧T + v∧B + B∧v + T∧s
14399        r[7] = a[0] * b[7] + a[7] * b[0] + a[1] * b[5] + a[2] * b[6] + a[3] * b[4]
14400            - a[4] * b[3]
14401            - a[5] * b[1]
14402            - a[6] * b[2];
14403
14404        Ok(make_multivector(r))
14405    });
14406
14407    // mv_inner(a, b) - Inner/dot product (⟂) - symmetric contraction
14408    // Lowers grade: vector · vector = scalar, bivector · vector = vector
14409    define(interp, "mv_inner", Some(2), |_, args| {
14410        let a = extract_multivector(&args[0], "mv_inner")?;
14411        let b = extract_multivector(&args[1], "mv_inner")?;
14412
14413        let mut r = [0.0f64; 8];
14414
14415        // Left contraction formula
14416        // Scalar (vectors dotted)
14417        r[0] = a[1] * b[1] + a[2] * b[2] + a[3] * b[3]
14418            - a[4] * b[4]
14419            - a[5] * b[5]
14420            - a[6] * b[6]
14421            - a[7] * b[7];
14422
14423        // Vector parts (bivector · vector)
14424        r[1] = a[4] * b[2] - a[6] * b[3] - a[5] * b[7];
14425        r[2] = -a[4] * b[1] + a[5] * b[3] - a[6] * b[7];
14426        r[3] = a[6] * b[1] - a[5] * b[2] - a[4] * b[7];
14427
14428        // Bivector parts (trivector · vector)
14429        r[4] = a[7] * b[3];
14430        r[5] = a[7] * b[1];
14431        r[6] = a[7] * b[2];
14432
14433        Ok(make_multivector(r))
14434    });
14435
14436    // mv_reverse(a) - Reverse (†) - reverses order of basis vectors
14437    // (e₁e₂)† = e₂e₁ = -e₁e₂
14438    define(interp, "mv_reverse", Some(1), |_, args| {
14439        let a = extract_multivector(&args[0], "mv_reverse")?;
14440        // Grade 0,1 unchanged; Grade 2,3 negated
14441        Ok(make_multivector([
14442            a[0], a[1], a[2], a[3], -a[4], -a[5], -a[6], -a[7],
14443        ]))
14444    });
14445
14446    // mv_dual(a) - Dual (Hodge star) - multiply by pseudoscalar
14447    // Maps grade k to grade (n-k) in n dimensions
14448    define(interp, "mv_dual", Some(1), |_, args| {
14449        let a = extract_multivector(&args[0], "mv_dual")?;
14450        // In 3D: dual(1) = e123, dual(e1) = e23, etc.
14451        // Multiplying by e123: since e123² = -1 in Cl(3,0,0)
14452        Ok(make_multivector([
14453            -a[7], // s ← -e123
14454            -a[5], // e1 ← -e23
14455            -a[6], // e2 ← -e31
14456            -a[4], // e3 ← -e12
14457            a[3],  // e12 ← e3
14458            a[1],  // e23 ← e1
14459            a[2],  // e31 ← e2
14460            a[0],  // e123 ← s
14461        ]))
14462    });
14463
14464    // mv_magnitude(a) - Magnitude/norm of multivector
14465    define(interp, "mv_magnitude", Some(1), |_, args| {
14466        let a = extract_multivector(&args[0], "mv_magnitude")?;
14467        let mag_sq = a[0] * a[0]
14468            + a[1] * a[1]
14469            + a[2] * a[2]
14470            + a[3] * a[3]
14471            + a[4] * a[4]
14472            + a[5] * a[5]
14473            + a[6] * a[6]
14474            + a[7] * a[7];
14475        Ok(Value::Float(mag_sq.sqrt()))
14476    });
14477
14478    // mv_normalize(a) - Normalize multivector
14479    define(interp, "mv_normalize", Some(1), |_, args| {
14480        let a = extract_multivector(&args[0], "mv_normalize")?;
14481        let mag = (a[0] * a[0]
14482            + a[1] * a[1]
14483            + a[2] * a[2]
14484            + a[3] * a[3]
14485            + a[4] * a[4]
14486            + a[5] * a[5]
14487            + a[6] * a[6]
14488            + a[7] * a[7])
14489            .sqrt();
14490        if mag < 1e-10 {
14491            return Ok(make_multivector([0.0; 8]));
14492        }
14493        Ok(make_multivector([
14494            a[0] / mag,
14495            a[1] / mag,
14496            a[2] / mag,
14497            a[3] / mag,
14498            a[4] / mag,
14499            a[5] / mag,
14500            a[6] / mag,
14501            a[7] / mag,
14502        ]))
14503    });
14504
14505    // rotor_from_axis_angle(axis, angle) - Create rotor from axis-angle
14506    // Rotor R = cos(θ/2) + sin(θ/2) * B where B is the normalized bivector plane
14507    define(interp, "rotor_from_axis_angle", Some(2), |_, args| {
14508        let axis = extract_vec3(&args[0], "rotor_from_axis_angle")?;
14509        let angle = match &args[1] {
14510            Value::Float(f) => *f,
14511            Value::Int(n) => *n as f64,
14512            _ => {
14513                return Err(RuntimeError::new(
14514                    "rotor_from_axis_angle: angle must be number",
14515                ))
14516            }
14517        };
14518
14519        // Normalize axis
14520        let len = (axis[0] * axis[0] + axis[1] * axis[1] + axis[2] * axis[2]).sqrt();
14521        if len < 1e-10 {
14522            // Return identity rotor
14523            return Ok(make_multivector([1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]));
14524        }
14525        let (nx, ny, nz) = (axis[0] / len, axis[1] / len, axis[2] / len);
14526
14527        let half_angle = angle / 2.0;
14528        let (s, c) = half_angle.sin_cos();
14529
14530        // Rotor: cos(θ/2) - sin(θ/2) * (n₁e₂₃ + n₂e₃₁ + n₃e₁₂)
14531        // Note: axis maps to bivector via dual
14532        Ok(make_multivector([
14533            c, // scalar
14534            0.0,
14535            0.0,
14536            0.0,     // no vector part
14537            -s * nz, // e12 (axis z → bivector xy)
14538            -s * nx, // e23 (axis x → bivector yz)
14539            -s * ny, // e31 (axis y → bivector zx)
14540            0.0,     // no trivector
14541        ]))
14542    });
14543
14544    // rotor_apply(rotor, vector) - Apply rotor to vector: RvR†
14545    // This is the sandwich product - THE way to rotate in GA
14546    define(interp, "rotor_apply", Some(2), |_, args| {
14547        let r = extract_multivector(&args[0], "rotor_apply")?;
14548        let v = extract_vec3(&args[1], "rotor_apply")?;
14549
14550        // Create vector multivector
14551        let v_mv = [0.0, v[0], v[1], v[2], 0.0, 0.0, 0.0, 0.0];
14552
14553        // Compute R† (reverse of rotor)
14554        let r_rev = [r[0], r[1], r[2], r[3], -r[4], -r[5], -r[6], -r[7]];
14555
14556        // First: R * v
14557        let mut rv = [0.0f64; 8];
14558        rv[0] = r[0] * v_mv[0] + r[1] * v_mv[1] + r[2] * v_mv[2] + r[3] * v_mv[3]
14559            - r[4] * v_mv[4]
14560            - r[5] * v_mv[5]
14561            - r[6] * v_mv[6]
14562            - r[7] * v_mv[7];
14563        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]
14564            - r[5] * v_mv[7]
14565            - r[6] * v_mv[3]
14566            - r[7] * v_mv[5];
14567        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]
14568            + r[5] * v_mv[3]
14569            - r[6] * v_mv[7]
14570            - r[7] * v_mv[6];
14571        rv[3] = r[0] * v_mv[3] - r[1] * v_mv[6] + r[2] * v_mv[5] + r[3] * v_mv[0]
14572            - r[4] * v_mv[7]
14573            - r[5] * v_mv[2]
14574            + r[6] * v_mv[1]
14575            - r[7] * v_mv[4];
14576        rv[4] = r[0] * v_mv[4] + r[1] * v_mv[2] - r[2] * v_mv[1]
14577            + r[3] * v_mv[7]
14578            + r[4] * v_mv[0]
14579            + r[5] * v_mv[6]
14580            - r[6] * v_mv[5]
14581            + r[7] * v_mv[3];
14582        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]
14583            + r[5] * v_mv[0]
14584            + r[6] * v_mv[4]
14585            + r[7] * v_mv[1];
14586        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]
14587            - r[5] * v_mv[4]
14588            + r[6] * v_mv[0]
14589            + r[7] * v_mv[2];
14590        rv[7] = r[0] * v_mv[7]
14591            + r[1] * v_mv[5]
14592            + r[2] * v_mv[6]
14593            + r[3] * v_mv[4]
14594            + r[4] * v_mv[3]
14595            + r[5] * v_mv[1]
14596            + r[6] * v_mv[2]
14597            + r[7] * v_mv[0];
14598
14599        // Then: (R * v) * R†
14600        let mut result = [0.0f64; 8];
14601        result[1] = rv[0] * r_rev[1] + rv[1] * r_rev[0] - rv[2] * r_rev[4]
14602            + rv[3] * r_rev[6]
14603            + rv[4] * r_rev[2]
14604            - rv[5] * r_rev[7]
14605            - rv[6] * r_rev[3]
14606            - rv[7] * r_rev[5];
14607        result[2] = rv[0] * r_rev[2] + rv[1] * r_rev[4] + rv[2] * r_rev[0]
14608            - rv[3] * r_rev[5]
14609            - rv[4] * r_rev[1]
14610            + rv[5] * r_rev[3]
14611            - rv[6] * r_rev[7]
14612            - rv[7] * r_rev[6];
14613        result[3] = rv[0] * r_rev[3] - rv[1] * r_rev[6] + rv[2] * r_rev[5] + rv[3] * r_rev[0]
14614            - rv[4] * r_rev[7]
14615            - rv[5] * r_rev[2]
14616            + rv[6] * r_rev[1]
14617            - rv[7] * r_rev[4];
14618
14619        // Return as vec3
14620        Ok(make_vec3(result[1], result[2], result[3]))
14621    });
14622
14623    // rotor_compose(r1, r2) - Compose rotors: R1 * R2
14624    define(interp, "rotor_compose", Some(2), |_, args| {
14625        let a = extract_multivector(&args[0], "rotor_compose")?;
14626        let b = extract_multivector(&args[1], "rotor_compose")?;
14627
14628        // Same as geometric product
14629        let mut r = [0.0f64; 8];
14630        r[0] = a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]
14631            - a[4] * b[4]
14632            - a[5] * b[5]
14633            - a[6] * b[6]
14634            - a[7] * b[7];
14635        r[1] = a[0] * b[1] + a[1] * b[0] - a[2] * b[4] + a[3] * b[6] + a[4] * b[2]
14636            - a[5] * b[7]
14637            - a[6] * b[3]
14638            - a[7] * b[5];
14639        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]
14640            - a[6] * b[7]
14641            - a[7] * b[6];
14642        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]
14643            + a[6] * b[1]
14644            - a[7] * b[4];
14645        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]
14646            - a[6] * b[5]
14647            + a[7] * b[3];
14648        r[5] = a[0] * b[5] + a[1] * b[7] + a[2] * b[3] - a[3] * b[2] - a[4] * b[6]
14649            + a[5] * b[0]
14650            + a[6] * b[4]
14651            + a[7] * b[1];
14652        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]
14653            + a[6] * b[0]
14654            + a[7] * b[2];
14655        r[7] = a[0] * b[7]
14656            + a[1] * b[5]
14657            + a[2] * b[6]
14658            + a[3] * b[4]
14659            + a[4] * b[3]
14660            + a[5] * b[1]
14661            + a[6] * b[2]
14662            + a[7] * b[0];
14663
14664        Ok(make_multivector(r))
14665    });
14666
14667    // mv_reflect(v, n) - Reflect vector v in plane with normal n
14668    // Reflection: -n * v * n (sandwich with negative)
14669    define(interp, "mv_reflect", Some(2), |_, args| {
14670        let v = extract_vec3(&args[0], "mv_reflect")?;
14671        let n = extract_vec3(&args[1], "mv_reflect")?;
14672
14673        // Normalize n
14674        let len = (n[0] * n[0] + n[1] * n[1] + n[2] * n[2]).sqrt();
14675        if len < 1e-10 {
14676            return Ok(make_vec3(v[0], v[1], v[2]));
14677        }
14678        let (nx, ny, nz) = (n[0] / len, n[1] / len, n[2] / len);
14679
14680        // v - 2(v·n)n
14681        let dot = v[0] * nx + v[1] * ny + v[2] * nz;
14682        Ok(make_vec3(
14683            v[0] - 2.0 * dot * nx,
14684            v[1] - 2.0 * dot * ny,
14685            v[2] - 2.0 * dot * nz,
14686        ))
14687    });
14688
14689    // mv_project(v, n) - Project vector v onto plane with normal n
14690    define(interp, "mv_project", Some(2), |_, args| {
14691        let v = extract_vec3(&args[0], "mv_project")?;
14692        let n = extract_vec3(&args[1], "mv_project")?;
14693
14694        let len = (n[0] * n[0] + n[1] * n[1] + n[2] * n[2]).sqrt();
14695        if len < 1e-10 {
14696            return Ok(make_vec3(v[0], v[1], v[2]));
14697        }
14698        let (nx, ny, nz) = (n[0] / len, n[1] / len, n[2] / len);
14699
14700        // v - (v·n)n
14701        let dot = v[0] * nx + v[1] * ny + v[2] * nz;
14702        Ok(make_vec3(v[0] - dot * nx, v[1] - dot * ny, v[2] - dot * nz))
14703    });
14704
14705    // mv_grade(mv, k) - Extract grade-k part of multivector
14706    define(interp, "mv_grade", Some(2), |_, args| {
14707        let a = extract_multivector(&args[0], "mv_grade")?;
14708        let k = match &args[1] {
14709            Value::Int(n) => *n,
14710            _ => return Err(RuntimeError::new("mv_grade: grade must be integer")),
14711        };
14712
14713        match k {
14714            0 => Ok(make_multivector([a[0], 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0])),
14715            1 => Ok(make_multivector([
14716                0.0, a[1], a[2], a[3], 0.0, 0.0, 0.0, 0.0,
14717            ])),
14718            2 => Ok(make_multivector([
14719                0.0, 0.0, 0.0, 0.0, a[4], a[5], a[6], 0.0,
14720            ])),
14721            3 => Ok(make_multivector([0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, a[7]])),
14722            _ => Ok(make_multivector([0.0; 8])),
14723        }
14724    });
14725}
14726
14727// ============================================================================
14728// DIMENSIONAL ANALYSIS (Unit-aware arithmetic)
14729// ============================================================================
14730// Automatic unit tracking and conversion - catch physics errors at runtime
14731// Base SI units: m (length), kg (mass), s (time), A (current), K (temperature), mol, cd
14732
14733fn register_dimensional(interp: &mut Interpreter) {
14734    // Helper to create a quantity with units
14735    // Units stored as exponents: [m, kg, s, A, K, mol, cd]
14736    fn make_quantity(value: f64, units: [i32; 7]) -> Value {
14737        let mut q = HashMap::new();
14738        q.insert("value".to_string(), Value::Float(value));
14739        q.insert("m".to_string(), Value::Int(units[0] as i64)); // meters
14740        q.insert("kg".to_string(), Value::Int(units[1] as i64)); // kilograms
14741        q.insert("s".to_string(), Value::Int(units[2] as i64)); // seconds
14742        q.insert("A".to_string(), Value::Int(units[3] as i64)); // amperes
14743        q.insert("K".to_string(), Value::Int(units[4] as i64)); // kelvin
14744        q.insert("mol".to_string(), Value::Int(units[5] as i64)); // moles
14745        q.insert("cd".to_string(), Value::Int(units[6] as i64)); // candela
14746        q.insert(
14747            "_type".to_string(),
14748            Value::String(Rc::new("quantity".to_string())),
14749        );
14750        Value::Map(Rc::new(RefCell::new(q)))
14751    }
14752
14753    fn extract_quantity(v: &Value, fn_name: &str) -> Result<(f64, [i32; 7]), RuntimeError> {
14754        match v {
14755            Value::Map(map) => {
14756                let map = map.borrow();
14757                let value = match map.get("value") {
14758                    Some(Value::Float(f)) => *f,
14759                    Some(Value::Int(n)) => *n as f64,
14760                    _ => return Err(RuntimeError::new(format!("{}: missing value", fn_name))),
14761                };
14762                let get_exp = |key: &str| -> i32 {
14763                    match map.get(key) {
14764                        Some(Value::Int(n)) => *n as i32,
14765                        _ => 0,
14766                    }
14767                };
14768                Ok((
14769                    value,
14770                    [
14771                        get_exp("m"),
14772                        get_exp("kg"),
14773                        get_exp("s"),
14774                        get_exp("A"),
14775                        get_exp("K"),
14776                        get_exp("mol"),
14777                        get_exp("cd"),
14778                    ],
14779                ))
14780            }
14781            Value::Float(f) => Ok((*f, [0; 7])),
14782            Value::Int(n) => Ok((*n as f64, [0; 7])),
14783            _ => Err(RuntimeError::new(format!(
14784                "{}: expected quantity or number",
14785                fn_name
14786            ))),
14787        }
14788    }
14789
14790    fn units_to_string(units: [i32; 7]) -> String {
14791        let names = ["m", "kg", "s", "A", "K", "mol", "cd"];
14792        let mut parts = Vec::new();
14793        for (i, &exp) in units.iter().enumerate() {
14794            if exp == 1 {
14795                parts.push(names[i].to_string());
14796            } else if exp != 0 {
14797                parts.push(format!("{}^{}", names[i], exp));
14798            }
14799        }
14800        if parts.is_empty() {
14801            "dimensionless".to_string()
14802        } else {
14803            parts.join("·")
14804        }
14805    }
14806
14807    // qty(value, unit_string) - Create quantity with units
14808    // e.g., qty(9.8, "m/s^2") for acceleration
14809    define(interp, "qty", Some(2), |_, args| {
14810        let value = match &args[0] {
14811            Value::Float(f) => *f,
14812            Value::Int(n) => *n as f64,
14813            _ => return Err(RuntimeError::new("qty: first argument must be number")),
14814        };
14815        let unit_str = match &args[1] {
14816            Value::String(s) => s.to_string(),
14817            _ => {
14818                return Err(RuntimeError::new(
14819                    "qty: second argument must be unit string",
14820                ))
14821            }
14822        };
14823
14824        // Parse unit string
14825        let mut units = [0i32; 7];
14826        // Simplified: if '/' present, treat everything as denominator
14827        // For proper parsing, would need to track position relative to '/'
14828        let in_denominator = unit_str.contains('/');
14829
14830        // Simple parser for common units
14831        for part in unit_str.split(|c: char| c == '*' || c == '·' || c == ' ') {
14832            let part = part.trim();
14833            if part.is_empty() {
14834                continue;
14835            }
14836
14837            let (base, exp) = if let Some(idx) = part.find('^') {
14838                let (b, e) = part.split_at(idx);
14839                (b, e[1..].parse::<i32>().unwrap_or(1))
14840            } else if part.contains('/') {
14841                // Handle division inline
14842                continue;
14843            } else {
14844                (part, 1)
14845            };
14846
14847            let sign = if in_denominator { -1 } else { 1 };
14848            match base {
14849                "m" | "meter" | "meters" => units[0] += exp * sign,
14850                "kg" | "kilogram" | "kilograms" => units[1] += exp * sign,
14851                "s" | "sec" | "second" | "seconds" => units[2] += exp * sign,
14852                "A" | "amp" | "ampere" | "amperes" => units[3] += exp * sign,
14853                "K" | "kelvin" => units[4] += exp * sign,
14854                "mol" | "mole" | "moles" => units[5] += exp * sign,
14855                "cd" | "candela" => units[6] += exp * sign,
14856                // Derived units
14857                "N" | "newton" | "newtons" => {
14858                    units[1] += sign;
14859                    units[0] += sign;
14860                    units[2] -= 2 * sign;
14861                }
14862                "J" | "joule" | "joules" => {
14863                    units[1] += sign;
14864                    units[0] += 2 * sign;
14865                    units[2] -= 2 * sign;
14866                }
14867                "W" | "watt" | "watts" => {
14868                    units[1] += sign;
14869                    units[0] += 2 * sign;
14870                    units[2] -= 3 * sign;
14871                }
14872                "Pa" | "pascal" | "pascals" => {
14873                    units[1] += sign;
14874                    units[0] -= sign;
14875                    units[2] -= 2 * sign;
14876                }
14877                "Hz" | "hertz" => {
14878                    units[2] -= sign;
14879                }
14880                "C" | "coulomb" | "coulombs" => {
14881                    units[3] += sign;
14882                    units[2] += sign;
14883                }
14884                "V" | "volt" | "volts" => {
14885                    units[1] += sign;
14886                    units[0] += 2 * sign;
14887                    units[2] -= 3 * sign;
14888                    units[3] -= sign;
14889                }
14890                "Ω" | "ohm" | "ohms" => {
14891                    units[1] += sign;
14892                    units[0] += 2 * sign;
14893                    units[2] -= 3 * sign;
14894                    units[3] -= 2 * sign;
14895                }
14896                _ => {}
14897            }
14898        }
14899
14900        Ok(make_quantity(value, units))
14901    });
14902
14903    // qty_add(a, b) - Add quantities (must have same units)
14904    define(interp, "qty_add", Some(2), |_, args| {
14905        let (val_a, units_a) = extract_quantity(&args[0], "qty_add")?;
14906        let (val_b, units_b) = extract_quantity(&args[1], "qty_add")?;
14907
14908        if units_a != units_b {
14909            return Err(RuntimeError::new(format!(
14910                "qty_add: unit mismatch: {} vs {}",
14911                units_to_string(units_a),
14912                units_to_string(units_b)
14913            )));
14914        }
14915
14916        Ok(make_quantity(val_a + val_b, units_a))
14917    });
14918
14919    // qty_sub(a, b) - Subtract quantities (must have same units)
14920    define(interp, "qty_sub", Some(2), |_, args| {
14921        let (val_a, units_a) = extract_quantity(&args[0], "qty_sub")?;
14922        let (val_b, units_b) = extract_quantity(&args[1], "qty_sub")?;
14923
14924        if units_a != units_b {
14925            return Err(RuntimeError::new(format!(
14926                "qty_sub: unit mismatch: {} vs {}",
14927                units_to_string(units_a),
14928                units_to_string(units_b)
14929            )));
14930        }
14931
14932        Ok(make_quantity(val_a - val_b, units_a))
14933    });
14934
14935    // qty_mul(a, b) - Multiply quantities (units add)
14936    define(interp, "qty_mul", Some(2), |_, args| {
14937        let (val_a, units_a) = extract_quantity(&args[0], "qty_mul")?;
14938        let (val_b, units_b) = extract_quantity(&args[1], "qty_mul")?;
14939
14940        let mut result_units = [0i32; 7];
14941        for i in 0..7 {
14942            result_units[i] = units_a[i] + units_b[i];
14943        }
14944
14945        Ok(make_quantity(val_a * val_b, result_units))
14946    });
14947
14948    // qty_div(a, b) - Divide quantities (units subtract)
14949    define(interp, "qty_div", Some(2), |_, args| {
14950        let (val_a, units_a) = extract_quantity(&args[0], "qty_div")?;
14951        let (val_b, units_b) = extract_quantity(&args[1], "qty_div")?;
14952
14953        if val_b.abs() < 1e-15 {
14954            return Err(RuntimeError::new("qty_div: division by zero"));
14955        }
14956
14957        let mut result_units = [0i32; 7];
14958        for i in 0..7 {
14959            result_units[i] = units_a[i] - units_b[i];
14960        }
14961
14962        Ok(make_quantity(val_a / val_b, result_units))
14963    });
14964
14965    // qty_pow(q, n) - Raise quantity to power (units multiply)
14966    define(interp, "qty_pow", Some(2), |_, args| {
14967        let (val, units) = extract_quantity(&args[0], "qty_pow")?;
14968        let n = match &args[1] {
14969            Value::Int(n) => *n as i32,
14970            Value::Float(f) => *f as i32,
14971            _ => return Err(RuntimeError::new("qty_pow: exponent must be number")),
14972        };
14973
14974        let mut result_units = [0i32; 7];
14975        for i in 0..7 {
14976            result_units[i] = units[i] * n;
14977        }
14978
14979        Ok(make_quantity(val.powi(n), result_units))
14980    });
14981
14982    // qty_sqrt(q) - Square root of quantity (units halve)
14983    define(interp, "qty_sqrt", Some(1), |_, args| {
14984        let (val, units) = extract_quantity(&args[0], "qty_sqrt")?;
14985
14986        // Check that all exponents are even
14987        for (i, &exp) in units.iter().enumerate() {
14988            if exp % 2 != 0 {
14989                let names = ["m", "kg", "s", "A", "K", "mol", "cd"];
14990                return Err(RuntimeError::new(format!(
14991                    "qty_sqrt: cannot take sqrt of {} (odd exponent on {})",
14992                    units_to_string(units),
14993                    names[i]
14994                )));
14995            }
14996        }
14997
14998        let mut result_units = [0i32; 7];
14999        for i in 0..7 {
15000            result_units[i] = units[i] / 2;
15001        }
15002
15003        Ok(make_quantity(val.sqrt(), result_units))
15004    });
15005
15006    // qty_value(q) - Get numeric value of quantity
15007    define(interp, "qty_value", Some(1), |_, args| {
15008        let (val, _) = extract_quantity(&args[0], "qty_value")?;
15009        Ok(Value::Float(val))
15010    });
15011
15012    // qty_units(q) - Get units as string
15013    define(interp, "qty_units", Some(1), |_, args| {
15014        let (_, units) = extract_quantity(&args[0], "qty_units")?;
15015        Ok(Value::String(Rc::new(units_to_string(units))))
15016    });
15017
15018    // qty_convert(q, target_units) - Convert to different units
15019    // Currently just validates compatible dimensions
15020    define(interp, "qty_convert", Some(2), |_, args| {
15021        let (val, units) = extract_quantity(&args[0], "qty_convert")?;
15022        let _target = match &args[1] {
15023            Value::String(s) => s.to_string(),
15024            _ => return Err(RuntimeError::new("qty_convert: target must be unit string")),
15025        };
15026
15027        // For now, just return with same value if dimensions match
15028        // A full implementation would handle unit prefixes (kilo, milli, etc.)
15029        Ok(make_quantity(val, units))
15030    });
15031
15032    // qty_check(q, expected_units) - Check if quantity has expected dimensions
15033    define(interp, "qty_check", Some(2), |_, args| {
15034        let (_, units) = extract_quantity(&args[0], "qty_check")?;
15035        let expected = match &args[1] {
15036            Value::String(s) => s.to_string(),
15037            _ => return Err(RuntimeError::new("qty_check: expected string")),
15038        };
15039
15040        // Quick dimension check by comparing unit string patterns
15041        let actual_str = units_to_string(units);
15042        Ok(Value::Bool(
15043            actual_str.contains(&expected) || expected.contains(&actual_str),
15044        ))
15045    });
15046
15047    // Common physical constants with units
15048    // c - speed of light
15049    define(interp, "c_light", Some(0), |_, _| {
15050        Ok(make_quantity(299792458.0, [1, 0, -1, 0, 0, 0, 0])) // m/s
15051    });
15052
15053    // G - gravitational constant
15054    define(interp, "G_gravity", Some(0), |_, _| {
15055        Ok(make_quantity(6.67430e-11, [3, -1, -2, 0, 0, 0, 0])) // m³/(kg·s²)
15056    });
15057
15058    // h - Planck constant
15059    define(interp, "h_planck", Some(0), |_, _| {
15060        Ok(make_quantity(6.62607015e-34, [2, 1, -1, 0, 0, 0, 0])) // J·s = m²·kg/s
15061    });
15062
15063    // e - elementary charge
15064    define(interp, "e_charge", Some(0), |_, _| {
15065        Ok(make_quantity(1.602176634e-19, [0, 0, 1, 1, 0, 0, 0])) // C = A·s
15066    });
15067
15068    // k_B - Boltzmann constant
15069    define(interp, "k_boltzmann", Some(0), |_, _| {
15070        Ok(make_quantity(1.380649e-23, [2, 1, -2, 0, -1, 0, 0])) // J/K = m²·kg/(s²·K)
15071    });
15072}
15073
15074// ============================================================================
15075// ENTITY COMPONENT SYSTEM (ECS)
15076// ============================================================================
15077//
15078// A lightweight Entity Component System for game development and simulations.
15079// ECS separates data (components) from behavior (systems) for maximum flexibility.
15080//
15081// ## Core Concepts
15082//
15083// | Concept | Description |
15084// |---------|-------------|
15085// | World | Container for all entities and components |
15086// | Entity | Unique ID representing a game object |
15087// | Component | Data attached to an entity (position, velocity, health) |
15088// | Query | Retrieve entities with specific components |
15089//
15090// ## Available Functions
15091//
15092// ### World Management
15093// | Function | Description |
15094// |----------|-------------|
15095// | `ecs_world()` | Create a new ECS world |
15096// | `ecs_count(world)` | Count total entities |
15097//
15098// ### Entity Management
15099// | Function | Description |
15100// |----------|-------------|
15101// | `ecs_spawn(world)` | Create entity, returns ID |
15102// | `ecs_despawn(world, id)` | Remove entity and components |
15103// | `ecs_exists(world, id)` | Check if entity exists |
15104//
15105// ### Component Management
15106// | Function | Description |
15107// |----------|-------------|
15108// | `ecs_attach(world, id, name, data)` | Add component to entity |
15109// | `ecs_detach(world, id, name)` | Remove component |
15110// | `ecs_get(world, id, name)` | Get component data |
15111// | `ecs_has(world, id, name)` | Check if entity has component |
15112//
15113// ### Querying
15114// | Function | Description |
15115// |----------|-------------|
15116// | `ecs_query(world, ...names)` | Find entities with all listed components |
15117// | `ecs_query_any(world, ...names)` | Find entities with any listed component |
15118//
15119// ## Usage Example
15120//
15121// ```sigil
15122// // Create world and entities
15123// let world = ecs_world();
15124// let player = ecs_spawn(world);
15125// let enemy = ecs_spawn(world);
15126//
15127// // Attach components
15128// ecs_attach(world, player, "Position", vec3(0, 0, 0));
15129// ecs_attach(world, player, "Velocity", vec3(1, 0, 0));
15130// ecs_attach(world, player, "Health", 100);
15131//
15132// ecs_attach(world, enemy, "Position", vec3(10, 0, 0));
15133// ecs_attach(world, enemy, "Health", 50);
15134//
15135// // Query all entities with Position and Health
15136// let living = ecs_query(world, "Position", "Health");
15137// // Returns [player_id, enemy_id]
15138//
15139// // Update loop
15140// for id in ecs_query(world, "Position", "Velocity") {
15141//     let pos = ecs_get(world, id, "Position");
15142//     let vel = ecs_get(world, id, "Velocity");
15143//     ecs_attach(world, id, "Position", vec3_add(pos, vel));
15144// }
15145// ```
15146//
15147// ## Performance Notes
15148//
15149// - Queries are O(entities) - for large worlds, consider caching results
15150// - Component access is O(1) via hash lookup
15151// - Entity spawning is O(1)
15152
15153fn register_ecs(interp: &mut Interpreter) {
15154    // ecs_world() - Create new ECS world
15155    define(interp, "ecs_world", Some(0), |_, _| {
15156        let mut world = HashMap::new();
15157        world.insert(
15158            "_type".to_string(),
15159            Value::String(Rc::new("ecs_world".to_string())),
15160        );
15161        world.insert("next_id".to_string(), Value::Int(0));
15162        world.insert(
15163            "entities".to_string(),
15164            Value::Map(Rc::new(RefCell::new(HashMap::new()))),
15165        );
15166        world.insert(
15167            "components".to_string(),
15168            Value::Map(Rc::new(RefCell::new(HashMap::new()))),
15169        );
15170        Ok(Value::Map(Rc::new(RefCell::new(world))))
15171    });
15172
15173    // ecs_spawn(world) - Spawn new entity, returns entity ID
15174    define(interp, "ecs_spawn", Some(1), |_, args| {
15175        let world = match &args[0] {
15176            Value::Map(m) => m.clone(),
15177            _ => return Err(RuntimeError::new("ecs_spawn: expected world")),
15178        };
15179
15180        let mut world_ref = world.borrow_mut();
15181        let id = match world_ref.get("next_id") {
15182            Some(Value::Int(n)) => *n,
15183            _ => 0,
15184        };
15185
15186        // Increment next_id
15187        world_ref.insert("next_id".to_string(), Value::Int(id + 1));
15188
15189        // Add to entities set
15190        if let Some(Value::Map(entities)) = world_ref.get("entities") {
15191            entities
15192                .borrow_mut()
15193                .insert(id.to_string(), Value::Bool(true));
15194        }
15195
15196        Ok(Value::Int(id))
15197    });
15198
15199    // ecs_despawn(world, entity_id) - Remove entity and all its components
15200    define(interp, "ecs_despawn", Some(2), |_, args| {
15201        let world = match &args[0] {
15202            Value::Map(m) => m.clone(),
15203            _ => return Err(RuntimeError::new("ecs_despawn: expected world")),
15204        };
15205        let id = match &args[1] {
15206            Value::Int(n) => *n,
15207            _ => return Err(RuntimeError::new("ecs_despawn: expected entity id")),
15208        };
15209
15210        let world_ref = world.borrow();
15211
15212        // Remove from entities
15213        if let Some(Value::Map(entities)) = world_ref.get("entities") {
15214            entities.borrow_mut().remove(&id.to_string());
15215        }
15216
15217        // Remove all components for this entity
15218        if let Some(Value::Map(components)) = world_ref.get("components") {
15219            let comps = components.borrow();
15220            for (_, comp_storage) in comps.iter() {
15221                if let Value::Map(storage) = comp_storage {
15222                    storage.borrow_mut().remove(&id.to_string());
15223                }
15224            }
15225        }
15226
15227        Ok(Value::Bool(true))
15228    });
15229
15230    // ecs_attach(world, entity_id, component_name, data) - Add component to entity
15231    define(interp, "ecs_attach", Some(4), |_, args| {
15232        let world = match &args[0] {
15233            Value::Map(m) => m.clone(),
15234            _ => {
15235                return Err(RuntimeError::new(
15236                    "ecs_attach() expects a world as first argument.\n\
15237                 Usage: ecs_attach(world, entity_id, component_name, data)\n\
15238                 Example:\n\
15239                   let world = ecs_world();\n\
15240                   let e = ecs_spawn(world);\n\
15241                   ecs_attach(world, e, \"Position\", vec3(0, 0, 0));",
15242                ))
15243            }
15244        };
15245        let id = match &args[1] {
15246            Value::Int(n) => *n,
15247            _ => {
15248                return Err(RuntimeError::new(
15249                    "ecs_attach() expects an entity ID (integer) as second argument.\n\
15250                 Entity IDs are returned by ecs_spawn().\n\
15251                 Example:\n\
15252                   let entity = ecs_spawn(world);  // Returns 0, 1, 2...\n\
15253                   ecs_attach(world, entity, \"Health\", 100);",
15254                ))
15255            }
15256        };
15257        let comp_name = match &args[2] {
15258            Value::String(s) => s.to_string(),
15259            _ => {
15260                return Err(RuntimeError::new(
15261                    "ecs_attach() expects a string component name as third argument.\n\
15262                 Common component names: \"Position\", \"Velocity\", \"Health\", \"Sprite\"\n\
15263                 Example: ecs_attach(world, entity, \"Position\", vec3(0, 0, 0));",
15264                ))
15265            }
15266        };
15267        let data = args[3].clone();
15268
15269        let world_ref = world.borrow();
15270
15271        // Get or create component storage
15272        if let Some(Value::Map(components)) = world_ref.get("components") {
15273            let mut comps = components.borrow_mut();
15274
15275            let storage = comps
15276                .entry(comp_name.clone())
15277                .or_insert_with(|| Value::Map(Rc::new(RefCell::new(HashMap::new()))));
15278
15279            if let Value::Map(storage_map) = storage {
15280                storage_map.borrow_mut().insert(id.to_string(), data);
15281            }
15282        }
15283
15284        Ok(Value::Bool(true))
15285    });
15286
15287    // ecs_get(world, entity_id, component_name) - Get component data
15288    define(interp, "ecs_get", Some(3), |_, args| {
15289        let world = match &args[0] {
15290            Value::Map(m) => m.clone(),
15291            _ => return Err(RuntimeError::new("ecs_get: expected world")),
15292        };
15293        let id = match &args[1] {
15294            Value::Int(n) => *n,
15295            _ => return Err(RuntimeError::new("ecs_get: expected entity id")),
15296        };
15297        let comp_name = match &args[2] {
15298            Value::String(s) => s.to_string(),
15299            _ => return Err(RuntimeError::new("ecs_get: expected component name")),
15300        };
15301
15302        let world_ref = world.borrow();
15303
15304        if let Some(Value::Map(components)) = world_ref.get("components") {
15305            let comps = components.borrow();
15306            if let Some(Value::Map(storage)) = comps.get(&comp_name) {
15307                if let Some(data) = storage.borrow().get(&id.to_string()) {
15308                    return Ok(data.clone());
15309                }
15310            }
15311        }
15312
15313        Ok(Value::Null)
15314    });
15315
15316    // ecs_has(world, entity_id, component_name) - Check if entity has component
15317    define(interp, "ecs_has", Some(3), |_, args| {
15318        let world = match &args[0] {
15319            Value::Map(m) => m.clone(),
15320            _ => return Err(RuntimeError::new("ecs_has: expected world")),
15321        };
15322        let id = match &args[1] {
15323            Value::Int(n) => *n,
15324            _ => return Err(RuntimeError::new("ecs_has: expected entity id")),
15325        };
15326        let comp_name = match &args[2] {
15327            Value::String(s) => s.to_string(),
15328            _ => return Err(RuntimeError::new("ecs_has: expected component name")),
15329        };
15330
15331        let world_ref = world.borrow();
15332
15333        if let Some(Value::Map(components)) = world_ref.get("components") {
15334            let comps = components.borrow();
15335            if let Some(Value::Map(storage)) = comps.get(&comp_name) {
15336                return Ok(Value::Bool(storage.borrow().contains_key(&id.to_string())));
15337            }
15338        }
15339
15340        Ok(Value::Bool(false))
15341    });
15342
15343    // ecs_remove(world, entity_id, component_name) - Remove component from entity
15344    define(interp, "ecs_remove", Some(3), |_, args| {
15345        let world = match &args[0] {
15346            Value::Map(m) => m.clone(),
15347            _ => return Err(RuntimeError::new("ecs_remove: expected world")),
15348        };
15349        let id = match &args[1] {
15350            Value::Int(n) => *n,
15351            _ => return Err(RuntimeError::new("ecs_remove: expected entity id")),
15352        };
15353        let comp_name = match &args[2] {
15354            Value::String(s) => s.to_string(),
15355            _ => return Err(RuntimeError::new("ecs_remove: expected component name")),
15356        };
15357
15358        let world_ref = world.borrow();
15359
15360        if let Some(Value::Map(components)) = world_ref.get("components") {
15361            let comps = components.borrow();
15362            if let Some(Value::Map(storage)) = comps.get(&comp_name) {
15363                storage.borrow_mut().remove(&id.to_string());
15364                return Ok(Value::Bool(true));
15365            }
15366        }
15367
15368        Ok(Value::Bool(false))
15369    });
15370
15371    // ecs_query(world, component_names...) - Get all entities with all specified components
15372    // Returns array of entity IDs
15373    define(interp, "ecs_query", None, |_, args| {
15374        if args.is_empty() {
15375            return Err(RuntimeError::new(
15376                "ecs_query: expected at least world argument",
15377            ));
15378        }
15379
15380        let world = match &args[0] {
15381            Value::Map(m) => m.clone(),
15382            _ => return Err(RuntimeError::new("ecs_query: expected world")),
15383        };
15384
15385        let comp_names: Vec<String> = args[1..]
15386            .iter()
15387            .filter_map(|a| match a {
15388                Value::String(s) => Some(s.to_string()),
15389                _ => None,
15390            })
15391            .collect();
15392
15393        if comp_names.is_empty() {
15394            // Return all entities
15395            let world_ref = world.borrow();
15396            if let Some(Value::Map(entities)) = world_ref.get("entities") {
15397                let result: Vec<Value> = entities
15398                    .borrow()
15399                    .keys()
15400                    .filter_map(|k| k.parse::<i64>().ok().map(Value::Int))
15401                    .collect();
15402                return Ok(Value::Array(Rc::new(RefCell::new(result))));
15403            }
15404            return Ok(Value::Array(Rc::new(RefCell::new(vec![]))));
15405        }
15406
15407        let world_ref = world.borrow();
15408        let mut result_ids: Option<Vec<String>> = None;
15409
15410        if let Some(Value::Map(components)) = world_ref.get("components") {
15411            let comps = components.borrow();
15412
15413            for comp_name in &comp_names {
15414                if let Some(Value::Map(storage)) = comps.get(comp_name) {
15415                    let keys: Vec<String> = storage.borrow().keys().cloned().collect();
15416
15417                    result_ids = Some(match result_ids {
15418                        None => keys,
15419                        Some(existing) => {
15420                            existing.into_iter().filter(|k| keys.contains(k)).collect()
15421                        }
15422                    });
15423                } else {
15424                    // Component type doesn't exist, no entities match
15425                    return Ok(Value::Array(Rc::new(RefCell::new(vec![]))));
15426                }
15427            }
15428        }
15429
15430        let result: Vec<Value> = result_ids
15431            .unwrap_or_default()
15432            .iter()
15433            .filter_map(|k| k.parse::<i64>().ok().map(Value::Int))
15434            .collect();
15435
15436        Ok(Value::Array(Rc::new(RefCell::new(result))))
15437    });
15438
15439    // ecs_query_with(world, component_names, callback) - Iterate over matching entities
15440    // Callback receives (entity_id, components_map)
15441    define(interp, "ecs_query_with", Some(3), |interp, args| {
15442        let world = match &args[0] {
15443            Value::Map(m) => m.clone(),
15444            _ => return Err(RuntimeError::new("ecs_query_with: expected world")),
15445        };
15446        let comp_names: Vec<String> = match &args[1] {
15447            Value::Array(arr) => arr
15448                .borrow()
15449                .iter()
15450                .filter_map(|v| match v {
15451                    Value::String(s) => Some(s.to_string()),
15452                    _ => None,
15453                })
15454                .collect(),
15455            _ => {
15456                return Err(RuntimeError::new(
15457                    "ecs_query_with: expected array of component names",
15458                ))
15459            }
15460        };
15461        let callback = match &args[2] {
15462            Value::Function(f) => f.clone(),
15463            _ => {
15464                return Err(RuntimeError::new(
15465                    "ecs_query_with: expected callback function",
15466                ))
15467            }
15468        };
15469
15470        // Pre-collect all data to avoid borrow issues during callbacks
15471        let mut callback_data: Vec<(i64, HashMap<String, Value>)> = Vec::new();
15472
15473        {
15474            let world_ref = world.borrow();
15475            let mut result_ids: Option<Vec<String>> = None;
15476
15477            if let Some(Value::Map(components)) = world_ref.get("components") {
15478                let comps = components.borrow();
15479
15480                for comp_name in &comp_names {
15481                    if let Some(Value::Map(storage)) = comps.get(comp_name) {
15482                        let keys: Vec<String> = storage.borrow().keys().cloned().collect();
15483                        result_ids = Some(match result_ids {
15484                            None => keys,
15485                            Some(existing) => {
15486                                existing.into_iter().filter(|k| keys.contains(k)).collect()
15487                            }
15488                        });
15489                    } else {
15490                        result_ids = Some(vec![]);
15491                        break;
15492                    }
15493                }
15494
15495                // Collect data for each matching entity
15496                for id_str in result_ids.unwrap_or_default() {
15497                    if let Ok(id) = id_str.parse::<i64>() {
15498                        let mut entity_comps = HashMap::new();
15499                        for comp_name in &comp_names {
15500                            if let Some(Value::Map(storage)) = comps.get(comp_name) {
15501                                if let Some(data) = storage.borrow().get(&id_str) {
15502                                    entity_comps.insert(comp_name.clone(), data.clone());
15503                                }
15504                            }
15505                        }
15506                        callback_data.push((id, entity_comps));
15507                    }
15508                }
15509            }
15510        } // Release borrows here
15511
15512        // Now call callbacks without holding borrows
15513        for (id, entity_comps) in callback_data {
15514            let callback_args = vec![
15515                Value::Int(id),
15516                Value::Map(Rc::new(RefCell::new(entity_comps))),
15517            ];
15518            interp.call_function(&callback, callback_args)?;
15519        }
15520
15521        Ok(Value::Null)
15522    });
15523
15524    // ecs_count(world) - Count total entities
15525    define(interp, "ecs_count", Some(1), |_, args| {
15526        let world = match &args[0] {
15527            Value::Map(m) => m.clone(),
15528            _ => return Err(RuntimeError::new("ecs_count: expected world")),
15529        };
15530
15531        let world_ref = world.borrow();
15532        if let Some(Value::Map(entities)) = world_ref.get("entities") {
15533            return Ok(Value::Int(entities.borrow().len() as i64));
15534        }
15535
15536        Ok(Value::Int(0))
15537    });
15538
15539    // ecs_alive(world, entity_id) - Check if entity is alive
15540    define(interp, "ecs_alive", Some(2), |_, args| {
15541        let world = match &args[0] {
15542            Value::Map(m) => m.clone(),
15543            _ => return Err(RuntimeError::new("ecs_alive: expected world")),
15544        };
15545        let id = match &args[1] {
15546            Value::Int(n) => *n,
15547            _ => return Err(RuntimeError::new("ecs_alive: expected entity id")),
15548        };
15549
15550        let world_ref = world.borrow();
15551        if let Some(Value::Map(entities)) = world_ref.get("entities") {
15552            return Ok(Value::Bool(entities.borrow().contains_key(&id.to_string())));
15553        }
15554
15555        Ok(Value::Bool(false))
15556    });
15557}
15558
15559// ============================================================================
15560// POLYCULTURAL TEXT PROCESSING
15561// ============================================================================
15562//
15563// Sigil's philosophy: Mathematics is poly-cultural, and so is TEXT.
15564// Different writing systems have different needs:
15565//
15566// | Writing System | Special Needs |
15567// |----------------|---------------|
15568// | Latin          | Diacritics, ligatures, case folding |
15569// | Arabic/Hebrew  | RTL, contextual shaping, vowel marks |
15570// | CJK            | No word boundaries, display width, ruby text |
15571// | Devanagari     | Complex clusters, conjuncts |
15572// | Thai           | No spaces between words |
15573// | Hangul         | Jamo composition/decomposition |
15574//
15575// This module provides world-class text handling for ALL scripts.
15576//
15577
15578fn register_polycultural_text(interp: &mut Interpreter) {
15579    // =========================================================================
15580    // SCRIPT DETECTION
15581    // =========================================================================
15582    //
15583    // Detect what writing system(s) a text uses.
15584    // Essential for choosing appropriate processing strategies.
15585    //
15586
15587    // script - get the dominant script of a string
15588    define(interp, "script", Some(1), |_, args| {
15589        match &args[0] {
15590            Value::String(s) => {
15591                // Count scripts
15592                let mut script_counts: HashMap<String, usize> = HashMap::new();
15593                for c in s.chars() {
15594                    if !c.is_whitespace() && !c.is_ascii_punctuation() {
15595                        let script = c.script();
15596                        let name = format!("{:?}", script);
15597                        *script_counts.entry(name).or_insert(0) += 1;
15598                    }
15599                }
15600                // Find dominant script
15601                let dominant = script_counts
15602                    .into_iter()
15603                    .max_by_key(|(_, count)| *count)
15604                    .map(|(name, _)| name)
15605                    .unwrap_or_else(|| "Unknown".to_string());
15606                Ok(Value::String(Rc::new(dominant)))
15607            }
15608            _ => Err(RuntimeError::new("script() requires string")),
15609        }
15610    });
15611
15612    // scripts - get all scripts present in text
15613    define(interp, "scripts", Some(1), |_, args| match &args[0] {
15614        Value::String(s) => {
15615            let mut scripts: Vec<String> = s
15616                .chars()
15617                .filter(|c| !c.is_whitespace() && !c.is_ascii_punctuation())
15618                .map(|c| format!("{:?}", c.script()))
15619                .collect();
15620            scripts.sort();
15621            scripts.dedup();
15622            let values: Vec<Value> = scripts
15623                .into_iter()
15624                .map(|s| Value::String(Rc::new(s)))
15625                .collect();
15626            Ok(Value::Array(Rc::new(RefCell::new(values))))
15627        }
15628        _ => Err(RuntimeError::new("scripts() requires string")),
15629    });
15630
15631    // is_script - check if text is primarily in a specific script
15632    define(interp, "is_script", Some(2), |_, args| {
15633        match (&args[0], &args[1]) {
15634            (Value::String(s), Value::String(script_name)) => {
15635                let target = script_name.to_lowercase();
15636                let mut matching = 0usize;
15637                let mut total = 0usize;
15638                for c in s.chars() {
15639                    if !c.is_whitespace() && !c.is_ascii_punctuation() {
15640                        total += 1;
15641                        let script_str = format!("{:?}", c.script()).to_lowercase();
15642                        if script_str == target {
15643                            matching += 1;
15644                        }
15645                    }
15646                }
15647                let ratio = if total > 0 {
15648                    matching as f64 / total as f64
15649                } else {
15650                    0.0
15651                };
15652                Ok(Value::Bool(ratio > 0.5))
15653            }
15654            _ => Err(RuntimeError::new(
15655                "is_script() requires string and script name",
15656            )),
15657        }
15658    });
15659
15660    // Script-specific detection functions
15661    define(interp, "is_latin", Some(1), |_, args| match &args[0] {
15662        Value::String(s) => {
15663            let is_latin = s
15664                .chars()
15665                .filter(|c| !c.is_whitespace())
15666                .all(|c| matches!(c.script(), Script::Latin | Script::Common));
15667            Ok(Value::Bool(is_latin && !s.is_empty()))
15668        }
15669        _ => Err(RuntimeError::new("is_latin() requires string")),
15670    });
15671
15672    define(interp, "is_cjk", Some(1), |_, args| match &args[0] {
15673        Value::String(s) => {
15674            let has_cjk = s.chars().any(|c| {
15675                matches!(
15676                    c.script(),
15677                    Script::Han
15678                        | Script::Hiragana
15679                        | Script::Katakana
15680                        | Script::Hangul
15681                        | Script::Bopomofo
15682                )
15683            });
15684            Ok(Value::Bool(has_cjk))
15685        }
15686        _ => Err(RuntimeError::new("is_cjk() requires string")),
15687    });
15688
15689    define(interp, "is_arabic", Some(1), |_, args| match &args[0] {
15690        Value::String(s) => {
15691            let has_arabic = s.chars().any(|c| matches!(c.script(), Script::Arabic));
15692            Ok(Value::Bool(has_arabic))
15693        }
15694        _ => Err(RuntimeError::new("is_arabic() requires string")),
15695    });
15696
15697    define(interp, "is_hebrew", Some(1), |_, args| match &args[0] {
15698        Value::String(s) => {
15699            let has_hebrew = s.chars().any(|c| matches!(c.script(), Script::Hebrew));
15700            Ok(Value::Bool(has_hebrew))
15701        }
15702        _ => Err(RuntimeError::new("is_hebrew() requires string")),
15703    });
15704
15705    define(interp, "is_cyrillic", Some(1), |_, args| match &args[0] {
15706        Value::String(s) => {
15707            let has_cyrillic = s.chars().any(|c| matches!(c.script(), Script::Cyrillic));
15708            Ok(Value::Bool(has_cyrillic))
15709        }
15710        _ => Err(RuntimeError::new("is_cyrillic() requires string")),
15711    });
15712
15713    define(interp, "is_greek", Some(1), |_, args| match &args[0] {
15714        Value::String(s) => {
15715            let has_greek = s.chars().any(|c| matches!(c.script(), Script::Greek));
15716            Ok(Value::Bool(has_greek))
15717        }
15718        _ => Err(RuntimeError::new("is_greek() requires string")),
15719    });
15720
15721    define(interp, "is_devanagari", Some(1), |_, args| match &args[0] {
15722        Value::String(s) => {
15723            let has_devanagari = s.chars().any(|c| matches!(c.script(), Script::Devanagari));
15724            Ok(Value::Bool(has_devanagari))
15725        }
15726        _ => Err(RuntimeError::new("is_devanagari() requires string")),
15727    });
15728
15729    define(interp, "is_thai", Some(1), |_, args| match &args[0] {
15730        Value::String(s) => {
15731            let has_thai = s.chars().any(|c| matches!(c.script(), Script::Thai));
15732            Ok(Value::Bool(has_thai))
15733        }
15734        _ => Err(RuntimeError::new("is_thai() requires string")),
15735    });
15736
15737    define(interp, "is_hangul", Some(1), |_, args| match &args[0] {
15738        Value::String(s) => {
15739            let has_hangul = s.chars().any(|c| matches!(c.script(), Script::Hangul));
15740            Ok(Value::Bool(has_hangul))
15741        }
15742        _ => Err(RuntimeError::new("is_hangul() requires string")),
15743    });
15744
15745    define(interp, "is_hiragana", Some(1), |_, args| match &args[0] {
15746        Value::String(s) => {
15747            let has_hiragana = s.chars().any(|c| matches!(c.script(), Script::Hiragana));
15748            Ok(Value::Bool(has_hiragana))
15749        }
15750        _ => Err(RuntimeError::new("is_hiragana() requires string")),
15751    });
15752
15753    define(interp, "is_katakana", Some(1), |_, args| match &args[0] {
15754        Value::String(s) => {
15755            let has_katakana = s.chars().any(|c| matches!(c.script(), Script::Katakana));
15756            Ok(Value::Bool(has_katakana))
15757        }
15758        _ => Err(RuntimeError::new("is_katakana() requires string")),
15759    });
15760
15761    // char_script - get script of a single character
15762    define(interp, "char_script", Some(1), |_, args| match &args[0] {
15763        Value::Char(c) => {
15764            let script = format!("{:?}", c.script());
15765            Ok(Value::String(Rc::new(script)))
15766        }
15767        Value::String(s) if s.chars().count() == 1 => {
15768            let c = s.chars().next().unwrap();
15769            let script = format!("{:?}", c.script());
15770            Ok(Value::String(Rc::new(script)))
15771        }
15772        _ => Err(RuntimeError::new("char_script() requires single character")),
15773    });
15774
15775    // =========================================================================
15776    // BIDIRECTIONAL TEXT (RTL/LTR)
15777    // =========================================================================
15778    //
15779    // Arabic, Hebrew, and other scripts are written right-to-left.
15780    // Mixed text (e.g., Arabic with English) needs bidirectional handling.
15781    //
15782
15783    // text_direction - get overall text direction
15784    define(interp, "text_direction", Some(1), |_, args| {
15785        match &args[0] {
15786            Value::String(s) => {
15787                let bidi_info = BidiInfo::new(s, None);
15788                // Check if any paragraph is RTL
15789                let has_rtl = bidi_info.paragraphs.iter().any(|p| p.level.is_rtl());
15790                let direction = if has_rtl { "rtl" } else { "ltr" };
15791                Ok(Value::String(Rc::new(direction.to_string())))
15792            }
15793            _ => Err(RuntimeError::new("text_direction() requires string")),
15794        }
15795    });
15796
15797    // is_rtl - check if text is right-to-left
15798    define(interp, "is_rtl", Some(1), |_, args| match &args[0] {
15799        Value::String(s) => {
15800            let bidi_info = BidiInfo::new(s, None);
15801            let has_rtl = bidi_info.paragraphs.iter().any(|p| p.level.is_rtl());
15802            Ok(Value::Bool(has_rtl))
15803        }
15804        _ => Err(RuntimeError::new("is_rtl() requires string")),
15805    });
15806
15807    // is_ltr - check if text is left-to-right
15808    define(interp, "is_ltr", Some(1), |_, args| match &args[0] {
15809        Value::String(s) => {
15810            let bidi_info = BidiInfo::new(s, None);
15811            let is_ltr = bidi_info.paragraphs.iter().all(|p| !p.level.is_rtl());
15812            Ok(Value::Bool(is_ltr))
15813        }
15814        _ => Err(RuntimeError::new("is_ltr() requires string")),
15815    });
15816
15817    // is_bidi - check if text contains mixed directions
15818    define(interp, "is_bidi", Some(1), |_, args| {
15819        match &args[0] {
15820            Value::String(s) => {
15821                // Check for both RTL and LTR characters
15822                let has_rtl = s.chars().any(|c| {
15823                    matches!(
15824                        c.script(),
15825                        Script::Arabic | Script::Hebrew | Script::Syriac | Script::Thaana
15826                    )
15827                });
15828                let has_ltr = s.chars().any(|c| {
15829                    matches!(c.script(), Script::Latin | Script::Greek | Script::Cyrillic)
15830                });
15831                Ok(Value::Bool(has_rtl && has_ltr))
15832            }
15833            _ => Err(RuntimeError::new("is_bidi() requires string")),
15834        }
15835    });
15836
15837    // bidi_reorder - reorder text for visual display
15838    define(interp, "bidi_reorder", Some(1), |_, args| match &args[0] {
15839        Value::String(s) => {
15840            let bidi_info = BidiInfo::new(s, None);
15841            let mut result = String::new();
15842            for para in &bidi_info.paragraphs {
15843                let line = para.range.clone();
15844                let reordered = bidi_info.reorder_line(para, line);
15845                result.push_str(&reordered);
15846            }
15847            Ok(Value::String(Rc::new(result)))
15848        }
15849        _ => Err(RuntimeError::new("bidi_reorder() requires string")),
15850    });
15851
15852    // =========================================================================
15853    // DISPLAY WIDTH (CJK-aware)
15854    // =========================================================================
15855    //
15856    // CJK characters are "full-width" (2 columns), while Latin is "half-width".
15857    // Critical for proper terminal output and text alignment.
15858    //
15859
15860    // display_width - get visual width in terminal columns
15861    define(interp, "display_width", Some(1), |_, args| match &args[0] {
15862        Value::String(s) => {
15863            let width = UnicodeWidthStr::width(s.as_str());
15864            Ok(Value::Int(width as i64))
15865        }
15866        _ => Err(RuntimeError::new("display_width() requires string")),
15867    });
15868
15869    // is_fullwidth - check if string contains full-width characters
15870    define(interp, "is_fullwidth", Some(1), |_, args| {
15871        match &args[0] {
15872            Value::String(s) => {
15873                let char_count = s.chars().count();
15874                let display_width = UnicodeWidthStr::width(s.as_str());
15875                // If display width > char count, we have full-width chars
15876                Ok(Value::Bool(display_width > char_count))
15877            }
15878            _ => Err(RuntimeError::new("is_fullwidth() requires string")),
15879        }
15880    });
15881
15882    // pad_display - pad string to display width (CJK-aware)
15883    define(interp, "pad_display", Some(3), |_, args| {
15884        match (&args[0], &args[1], &args[2]) {
15885            (Value::String(s), Value::Int(target_width), Value::String(align)) => {
15886                let current_width = UnicodeWidthStr::width(s.as_str());
15887                let target = *target_width as usize;
15888                if current_width >= target {
15889                    return Ok(Value::String(s.clone()));
15890                }
15891                let padding = target - current_width;
15892                let result = match align.as_str() {
15893                    "left" => format!("{}{}", s, " ".repeat(padding)),
15894                    "right" => format!("{}{}", " ".repeat(padding), s),
15895                    "center" => {
15896                        let left = padding / 2;
15897                        let right = padding - left;
15898                        format!("{}{}{}", " ".repeat(left), s, " ".repeat(right))
15899                    }
15900                    _ => {
15901                        return Err(RuntimeError::new(
15902                            "pad_display: align must be 'left', 'right', or 'center'",
15903                        ))
15904                    }
15905                };
15906                Ok(Value::String(Rc::new(result)))
15907            }
15908            _ => Err(RuntimeError::new(
15909                "pad_display() requires string, width, and alignment",
15910            )),
15911        }
15912    });
15913
15914    // =========================================================================
15915    // TRANSLITERATION
15916    // =========================================================================
15917    //
15918    // Convert text from any script to ASCII representation.
15919    // Essential for: search, URLs, usernames, file names.
15920    //
15921
15922    // transliterate - convert any Unicode text to ASCII
15923    define(interp, "transliterate", Some(1), |_, args| match &args[0] {
15924        Value::String(s) => {
15925            let ascii = deunicode(s);
15926            Ok(Value::String(Rc::new(ascii)))
15927        }
15928        _ => Err(RuntimeError::new("transliterate() requires string")),
15929    });
15930
15931    // to_ascii - alias for transliterate
15932    define(interp, "to_ascii", Some(1), |_, args| match &args[0] {
15933        Value::String(s) => {
15934            let ascii = deunicode(s);
15935            Ok(Value::String(Rc::new(ascii)))
15936        }
15937        _ => Err(RuntimeError::new("to_ascii() requires string")),
15938    });
15939
15940    // slugify - create URL-safe slug from any text
15941    define(interp, "slugify", Some(1), |_, args| {
15942        match &args[0] {
15943            Value::String(s) => {
15944                let ascii = deunicode(s);
15945                let slug: String = ascii
15946                    .to_lowercase()
15947                    .chars()
15948                    .map(|c| if c.is_alphanumeric() { c } else { '-' })
15949                    .collect();
15950                // Collapse multiple dashes and trim
15951                let mut result = String::new();
15952                let mut last_was_dash = true; // Start true to trim leading dashes
15953                for c in slug.chars() {
15954                    if c == '-' {
15955                        if !last_was_dash {
15956                            result.push(c);
15957                            last_was_dash = true;
15958                        }
15959                    } else {
15960                        result.push(c);
15961                        last_was_dash = false;
15962                    }
15963                }
15964                // Trim trailing dash
15965                if result.ends_with('-') {
15966                    result.pop();
15967                }
15968                Ok(Value::String(Rc::new(result)))
15969            }
15970            _ => Err(RuntimeError::new("slugify() requires string")),
15971        }
15972    });
15973
15974    // =========================================================================
15975    // DIACRITICS AND ACCENTS
15976    // =========================================================================
15977    //
15978    // Many scripts use combining marks: é = e + ́ (combining acute)
15979    // Need to handle decomposition, stripping, and normalization.
15980    //
15981
15982    // strip_diacritics - remove accents and combining marks
15983    define(interp, "strip_diacritics", Some(1), |_, args| {
15984        match &args[0] {
15985            Value::String(s) => {
15986                // NFD decomposition separates base chars from combining marks
15987                let decomposed: String = s.nfd().collect();
15988                // Filter out combining marks (category Mn, Mc, Me)
15989                let stripped: String = decomposed
15990                    .chars()
15991                    .filter(|c| {
15992                        // Keep if not a combining mark
15993                        // Combining marks are in Unicode categories Mn, Mc, Me
15994                        // which are roughly in ranges U+0300-U+036F (common) and others
15995                        let code = *c as u32;
15996                        // Quick check for common combining diacritical marks
15997                        !(0x0300..=0x036F).contains(&code)
15998                            && !(0x1AB0..=0x1AFF).contains(&code)
15999                            && !(0x1DC0..=0x1DFF).contains(&code)
16000                            && !(0x20D0..=0x20FF).contains(&code)
16001                            && !(0xFE20..=0xFE2F).contains(&code)
16002                    })
16003                    .collect();
16004                Ok(Value::String(Rc::new(stripped)))
16005            }
16006            _ => Err(RuntimeError::new("strip_diacritics() requires string")),
16007        }
16008    });
16009
16010    // has_diacritics - check if string contains diacritical marks
16011    define(interp, "has_diacritics", Some(1), |_, args| {
16012        match &args[0] {
16013            Value::String(s) => {
16014                let decomposed: String = s.nfd().collect();
16015                let has_marks = decomposed.chars().any(|c| {
16016                    let code = c as u32;
16017                    (0x0300..=0x036F).contains(&code)
16018                        || (0x1AB0..=0x1AFF).contains(&code)
16019                        || (0x1DC0..=0x1DFF).contains(&code)
16020                        || (0x20D0..=0x20FF).contains(&code)
16021                        || (0xFE20..=0xFE2F).contains(&code)
16022                });
16023                Ok(Value::Bool(has_marks))
16024            }
16025            _ => Err(RuntimeError::new("has_diacritics() requires string")),
16026        }
16027    });
16028
16029    // normalize_accents - convert composed to decomposed or vice versa
16030    define(interp, "normalize_accents", Some(2), |_, args| {
16031        match (&args[0], &args[1]) {
16032            (Value::String(s), Value::String(form)) => {
16033                let result = match form.as_str() {
16034                    "composed" | "nfc" => s.nfc().collect(),
16035                    "decomposed" | "nfd" => s.nfd().collect(),
16036                    _ => {
16037                        return Err(RuntimeError::new(
16038                            "normalize_accents: form must be 'composed' or 'decomposed'",
16039                        ))
16040                    }
16041                };
16042                Ok(Value::String(Rc::new(result)))
16043            }
16044            _ => Err(RuntimeError::new(
16045                "normalize_accents() requires string and form",
16046            )),
16047        }
16048    });
16049
16050    // =========================================================================
16051    // LOCALE-AWARE CASE MAPPING
16052    // =========================================================================
16053    //
16054    // Case mapping varies by locale:
16055    // - Turkish: i ↔ İ, ı ↔ I (dotted/dotless distinction)
16056    // - German: ß → SS (uppercase), but SS → ss or ß (lowercase)
16057    // - Greek: final sigma rules
16058    //
16059
16060    // upper_locale - locale-aware uppercase
16061    define(interp, "upper_locale", Some(2), |_, args| {
16062        match (&args[0], &args[1]) {
16063            (Value::String(s), Value::String(locale_str)) => {
16064                let case_mapper = CaseMapper::new();
16065                let langid: LanguageIdentifier =
16066                    locale_str.parse().unwrap_or_else(|_| "en".parse().unwrap());
16067                let result = case_mapper.uppercase_to_string(s, &langid);
16068                Ok(Value::String(Rc::new(result)))
16069            }
16070            _ => Err(RuntimeError::new(
16071                "upper_locale() requires string and locale",
16072            )),
16073        }
16074    });
16075
16076    // lower_locale - locale-aware lowercase
16077    define(interp, "lower_locale", Some(2), |_, args| {
16078        match (&args[0], &args[1]) {
16079            (Value::String(s), Value::String(locale_str)) => {
16080                let case_mapper = CaseMapper::new();
16081                let langid: LanguageIdentifier =
16082                    locale_str.parse().unwrap_or_else(|_| "en".parse().unwrap());
16083                let result = case_mapper.lowercase_to_string(s, &langid);
16084                Ok(Value::String(Rc::new(result)))
16085            }
16086            _ => Err(RuntimeError::new(
16087                "lower_locale() requires string and locale",
16088            )),
16089        }
16090    });
16091
16092    // titlecase_locale - locale-aware titlecase
16093    define(interp, "titlecase_locale", Some(2), |_, args| {
16094        match (&args[0], &args[1]) {
16095            (Value::String(s), Value::String(locale_str)) => {
16096                let case_mapper = CaseMapper::new();
16097                let langid: LanguageIdentifier =
16098                    locale_str.parse().unwrap_or_else(|_| "en".parse().unwrap());
16099                let options = TitlecaseOptions::default();
16100                let result = case_mapper
16101                    .titlecase_segment_with_only_case_data_to_string(s, &langid, options);
16102                Ok(Value::String(Rc::new(result)))
16103            }
16104            _ => Err(RuntimeError::new(
16105                "titlecase_locale() requires string and locale",
16106            )),
16107        }
16108    });
16109
16110    // case_fold - Unicode case folding for comparison
16111    define(interp, "case_fold", Some(1), |_, args| match &args[0] {
16112        Value::String(s) => {
16113            let case_mapper = CaseMapper::new();
16114            let result = case_mapper.fold_string(s);
16115            Ok(Value::String(Rc::new(result)))
16116        }
16117        _ => Err(RuntimeError::new("case_fold() requires string")),
16118    });
16119
16120    // case_insensitive_eq - compare strings ignoring case (using case folding)
16121    define(interp, "case_insensitive_eq", Some(2), |_, args| {
16122        match (&args[0], &args[1]) {
16123            (Value::String(a), Value::String(b)) => {
16124                let case_mapper = CaseMapper::new();
16125                let folded_a = case_mapper.fold_string(a);
16126                let folded_b = case_mapper.fold_string(b);
16127                Ok(Value::Bool(folded_a == folded_b))
16128            }
16129            _ => Err(RuntimeError::new(
16130                "case_insensitive_eq() requires two strings",
16131            )),
16132        }
16133    });
16134
16135    // =========================================================================
16136    // LOCALE-AWARE COLLATION (SORTING)
16137    // =========================================================================
16138    //
16139    // Sorting order varies dramatically by locale:
16140    // - German: ä sorts with a
16141    // - Swedish: ä sorts after z
16142    // - Spanish: ñ is a separate letter after n
16143    //
16144
16145    // compare_locale - locale-aware string comparison
16146    define(interp, "compare_locale", Some(3), |_, args| {
16147        match (&args[0], &args[1], &args[2]) {
16148            (Value::String(a), Value::String(b), Value::String(locale_str)) => {
16149                let locale: Locale = locale_str.parse().unwrap_or_else(|_| "en".parse().unwrap());
16150                let options = CollatorOptions::new();
16151                let collator = Collator::try_new(&locale.into(), options)
16152                    .unwrap_or_else(|_| Collator::try_new(&Default::default(), options).unwrap());
16153                let result = match collator.compare(a, b) {
16154                    std::cmp::Ordering::Less => -1,
16155                    std::cmp::Ordering::Equal => 0,
16156                    std::cmp::Ordering::Greater => 1,
16157                };
16158                Ok(Value::Int(result))
16159            }
16160            _ => Err(RuntimeError::new(
16161                "compare_locale() requires two strings and locale",
16162            )),
16163        }
16164    });
16165
16166    // sort_locale - sort array of strings by locale
16167    define(interp, "sort_locale", Some(2), |_, args| {
16168        match (&args[0], &args[1]) {
16169            (Value::Array(arr), Value::String(locale_str)) => {
16170                let locale: Locale = locale_str.parse().unwrap_or_else(|_| "en".parse().unwrap());
16171                let options = CollatorOptions::new();
16172                let collator = Collator::try_new(&locale.into(), options)
16173                    .unwrap_or_else(|_| Collator::try_new(&Default::default(), options).unwrap());
16174
16175                let mut items: Vec<(String, Value)> = arr
16176                    .borrow()
16177                    .iter()
16178                    .map(|v| {
16179                        let s = match v {
16180                            Value::String(s) => (**s).clone(),
16181                            _ => format!("{}", v),
16182                        };
16183                        (s, v.clone())
16184                    })
16185                    .collect();
16186
16187                items.sort_by(|(a, _), (b, _)| collator.compare(a, b));
16188
16189                let sorted: Vec<Value> = items.into_iter().map(|(_, v)| v).collect();
16190                Ok(Value::Array(Rc::new(RefCell::new(sorted))))
16191            }
16192            _ => Err(RuntimeError::new("sort_locale() requires array and locale")),
16193        }
16194    });
16195
16196    // =========================================================================
16197    // ADVANCED SEGMENTATION
16198    // =========================================================================
16199    //
16200    // Different languages have different boundary rules:
16201    // - Thai/Lao/Khmer: No spaces between words
16202    // - CJK: Characters can be words themselves
16203    // - German: Compound words are single words
16204    //
16205
16206    // sentences - split text into sentences (locale-aware)
16207    define(interp, "sentences", Some(1), |_, args| match &args[0] {
16208        Value::String(s) => {
16209            let segmenter = SentenceSegmenter::new();
16210            let breakpoints: Vec<usize> = segmenter.segment_str(s).collect();
16211            let mut sentences = Vec::new();
16212            let mut start = 0;
16213            for end in breakpoints {
16214                let sentence = s[start..end].trim();
16215                if !sentence.is_empty() {
16216                    sentences.push(Value::String(Rc::new(sentence.to_string())));
16217                }
16218                start = end;
16219            }
16220            Ok(Value::Array(Rc::new(RefCell::new(sentences))))
16221        }
16222        _ => Err(RuntimeError::new("sentences() requires string")),
16223    });
16224
16225    // sentence_count - count sentences
16226    define(interp, "sentence_count", Some(1), |_, args| {
16227        match &args[0] {
16228            Value::String(s) => {
16229                let segmenter = SentenceSegmenter::new();
16230                let breakpoints: Vec<usize> = segmenter.segment_str(s).collect();
16231                // Sentences are between breakpoints
16232                let count = breakpoints.len().saturating_sub(1);
16233                Ok(Value::Int(count as i64))
16234            }
16235            _ => Err(RuntimeError::new("sentence_count() requires string")),
16236        }
16237    });
16238
16239    // words_icu - ICU-based word segmentation (better for CJK, Thai)
16240    define(interp, "words_icu", Some(1), |_, args| {
16241        match &args[0] {
16242            Value::String(s) => {
16243                let segmenter = WordSegmenter::new_auto();
16244                let breakpoints: Vec<usize> = segmenter.segment_str(s).collect();
16245                let mut words = Vec::new();
16246                let mut start = 0;
16247                for end in breakpoints {
16248                    let word = &s[start..end];
16249                    // Filter out whitespace-only segments
16250                    if !word.trim().is_empty() {
16251                        words.push(Value::String(Rc::new(word.to_string())));
16252                    }
16253                    start = end;
16254                }
16255                Ok(Value::Array(Rc::new(RefCell::new(words))))
16256            }
16257            _ => Err(RuntimeError::new("words_icu() requires string")),
16258        }
16259    });
16260
16261    // word_count_icu - ICU-based word count (handles Thai, CJK correctly)
16262    define(interp, "word_count_icu", Some(1), |_, args| {
16263        match &args[0] {
16264            Value::String(s) => {
16265                let segmenter = WordSegmenter::new_auto();
16266                let breakpoints: Vec<usize> = segmenter.segment_str(s).collect();
16267                let mut count = 0;
16268                let mut start = 0;
16269                for end in breakpoints {
16270                    let word = &s[start..end];
16271                    if !word.trim().is_empty() && word.chars().any(|c| c.is_alphanumeric()) {
16272                        count += 1;
16273                    }
16274                    start = end;
16275                }
16276                Ok(Value::Int(count))
16277            }
16278            _ => Err(RuntimeError::new("word_count_icu() requires string")),
16279        }
16280    });
16281
16282    // =========================================================================
16283    // SCRIPT-SPECIFIC UTILITIES
16284    // =========================================================================
16285
16286    // is_emoji - check if string contains emoji
16287    define(interp, "is_emoji", Some(1), |_, args| {
16288        match &args[0] {
16289            Value::String(s) => {
16290                let has_emoji = s.chars().any(|c| {
16291                    let code = c as u32;
16292                    // Common emoji ranges
16293                    (0x1F600..=0x1F64F).contains(&code) ||  // Emoticons
16294                    (0x1F300..=0x1F5FF).contains(&code) ||  // Misc Symbols and Pictographs
16295                    (0x1F680..=0x1F6FF).contains(&code) ||  // Transport and Map
16296                    (0x1F1E0..=0x1F1FF).contains(&code) ||  // Flags
16297                    (0x2600..=0x26FF).contains(&code) ||    // Misc symbols
16298                    (0x2700..=0x27BF).contains(&code) ||    // Dingbats
16299                    (0xFE00..=0xFE0F).contains(&code) ||    // Variation Selectors
16300                    (0x1F900..=0x1F9FF).contains(&code) ||  // Supplemental Symbols and Pictographs
16301                    (0x1FA00..=0x1FA6F).contains(&code) ||  // Chess Symbols
16302                    (0x1FA70..=0x1FAFF).contains(&code) ||  // Symbols and Pictographs Extended-A
16303                    (0x231A..=0x231B).contains(&code) ||    // Watch, Hourglass
16304                    (0x23E9..=0x23F3).contains(&code) ||    // Various symbols
16305                    (0x23F8..=0x23FA).contains(&code) // Various symbols
16306                });
16307                Ok(Value::Bool(has_emoji))
16308            }
16309            _ => Err(RuntimeError::new("is_emoji() requires string")),
16310        }
16311    });
16312
16313    // extract_emoji - extract all emoji from text
16314    define(interp, "extract_emoji", Some(1), |_, args| match &args[0] {
16315        Value::String(s) => {
16316            let emoji: Vec<Value> = s
16317                .graphemes(true)
16318                .filter(|g| {
16319                    g.chars().any(|c| {
16320                        let code = c as u32;
16321                        (0x1F600..=0x1F64F).contains(&code)
16322                            || (0x1F300..=0x1F5FF).contains(&code)
16323                            || (0x1F680..=0x1F6FF).contains(&code)
16324                            || (0x1F1E0..=0x1F1FF).contains(&code)
16325                            || (0x2600..=0x26FF).contains(&code)
16326                            || (0x2700..=0x27BF).contains(&code)
16327                            || (0x1F900..=0x1F9FF).contains(&code)
16328                            || (0x1FA00..=0x1FA6F).contains(&code)
16329                            || (0x1FA70..=0x1FAFF).contains(&code)
16330                    })
16331                })
16332                .map(|g| Value::String(Rc::new(g.to_string())))
16333                .collect();
16334            Ok(Value::Array(Rc::new(RefCell::new(emoji))))
16335        }
16336        _ => Err(RuntimeError::new("extract_emoji() requires string")),
16337    });
16338
16339    // strip_emoji - remove emoji from text
16340    define(interp, "strip_emoji", Some(1), |_, args| match &args[0] {
16341        Value::String(s) => {
16342            let stripped: String = s
16343                .graphemes(true)
16344                .filter(|g| {
16345                    !g.chars().any(|c| {
16346                        let code = c as u32;
16347                        (0x1F600..=0x1F64F).contains(&code)
16348                            || (0x1F300..=0x1F5FF).contains(&code)
16349                            || (0x1F680..=0x1F6FF).contains(&code)
16350                            || (0x1F1E0..=0x1F1FF).contains(&code)
16351                            || (0x2600..=0x26FF).contains(&code)
16352                            || (0x2700..=0x27BF).contains(&code)
16353                            || (0x1F900..=0x1F9FF).contains(&code)
16354                            || (0x1FA00..=0x1FA6F).contains(&code)
16355                            || (0x1FA70..=0x1FAFF).contains(&code)
16356                    })
16357                })
16358                .collect();
16359            Ok(Value::String(Rc::new(stripped)))
16360        }
16361        _ => Err(RuntimeError::new("strip_emoji() requires string")),
16362    });
16363
16364    // =========================================================================
16365    // MIXED SCRIPT TEXT UTILITIES
16366    // =========================================================================
16367
16368    // script_runs - split text into runs of the same script
16369    define(interp, "script_runs", Some(1), |_, args| {
16370        match &args[0] {
16371            Value::String(s) => {
16372                let mut runs: Vec<Value> = Vec::new();
16373                let mut current_run = String::new();
16374                let mut current_script: Option<Script> = None;
16375
16376                for c in s.chars() {
16377                    let script = c.script();
16378                    // Common and Inherited scripts don't start new runs
16379                    if script != Script::Common && script != Script::Inherited {
16380                        if let Some(curr) = current_script {
16381                            if script != curr {
16382                                // New script - save current run
16383                                if !current_run.is_empty() {
16384                                    runs.push(Value::String(Rc::new(current_run.clone())));
16385                                    current_run.clear();
16386                                }
16387                                current_script = Some(script);
16388                            }
16389                        } else {
16390                            current_script = Some(script);
16391                        }
16392                    }
16393                    current_run.push(c);
16394                }
16395
16396                // Don't forget the last run
16397                if !current_run.is_empty() {
16398                    runs.push(Value::String(Rc::new(current_run)));
16399                }
16400
16401                Ok(Value::Array(Rc::new(RefCell::new(runs))))
16402            }
16403            _ => Err(RuntimeError::new("script_runs() requires string")),
16404        }
16405    });
16406
16407    // script_ratio - get ratio of scripts in text
16408    define(interp, "script_ratio", Some(1), |_, args| {
16409        match &args[0] {
16410            Value::String(s) => {
16411                let mut script_counts: HashMap<String, usize> = HashMap::new();
16412                let mut total = 0usize;
16413
16414                for c in s.chars() {
16415                    if !c.is_whitespace() && c != ' ' {
16416                        let script = format!("{:?}", c.script());
16417                        *script_counts.entry(script).or_insert(0) += 1;
16418                        total += 1;
16419                    }
16420                }
16421
16422                // Convert to map of ratios
16423                let mut result = HashMap::new();
16424                for (script, count) in script_counts {
16425                    let ratio = if total > 0 {
16426                        count as f64 / total as f64
16427                    } else {
16428                        0.0
16429                    };
16430                    result.insert(script, Value::Float(ratio));
16431                }
16432
16433                let map = Rc::new(RefCell::new(result));
16434                Ok(Value::Map(map))
16435            }
16436            _ => Err(RuntimeError::new("script_ratio() requires string")),
16437        }
16438    });
16439
16440    // =========================================================================
16441    // INTERNATIONALIZATION HELPERS
16442    // =========================================================================
16443
16444    // locale_name - get display name for a locale
16445    define(interp, "locale_name", Some(1), |_, args| {
16446        match &args[0] {
16447            Value::String(locale_str) => {
16448                // Return the locale code itself as a simple implementation
16449                // A full implementation would use ICU's display names
16450                Ok(Value::String(locale_str.clone()))
16451            }
16452            _ => Err(RuntimeError::new("locale_name() requires string")),
16453        }
16454    });
16455
16456    // supported_locales - list of supported locales for collation
16457    define(interp, "supported_locales", Some(0), |_, _| {
16458        // Common locales supported by ICU
16459        let locales = vec![
16460            "ar", "bg", "ca", "cs", "da", "de", "el", "en", "es", "et", "fi", "fr", "he", "hi",
16461            "hr", "hu", "id", "it", "ja", "ko", "lt", "lv", "ms", "nb", "nl", "pl", "pt", "ro",
16462            "ru", "sk", "sl", "sr", "sv", "th", "tr", "uk", "vi", "zh",
16463        ];
16464        let values: Vec<Value> = locales
16465            .into_iter()
16466            .map(|s| Value::String(Rc::new(s.to_string())))
16467            .collect();
16468        Ok(Value::Array(Rc::new(RefCell::new(values))))
16469    });
16470}
16471
16472// =============================================================================
16473// TEXT INTELLIGENCE MODULE - AI-Native Text Analysis
16474// =============================================================================
16475
16476fn register_text_intelligence(interp: &mut Interpreter) {
16477    // =========================================================================
16478    // STRING SIMILARITY METRICS
16479    // =========================================================================
16480
16481    // levenshtein - edit distance between strings
16482    define(interp, "levenshtein", Some(2), |_, args| {
16483        match (&args[0], &args[1]) {
16484            (Value::String(a), Value::String(b)) => {
16485                let distance = strsim::levenshtein(a, b);
16486                Ok(Value::Int(distance as i64))
16487            }
16488            _ => Err(RuntimeError::new("levenshtein() requires two strings")),
16489        }
16490    });
16491
16492    // levenshtein_normalized - normalized edit distance (0.0 to 1.0)
16493    define(
16494        interp,
16495        "levenshtein_normalized",
16496        Some(2),
16497        |_, args| match (&args[0], &args[1]) {
16498            (Value::String(a), Value::String(b)) => {
16499                let distance = strsim::normalized_levenshtein(a, b);
16500                Ok(Value::Float(distance))
16501            }
16502            _ => Err(RuntimeError::new(
16503                "levenshtein_normalized() requires two strings",
16504            )),
16505        },
16506    );
16507
16508    // jaro - Jaro similarity (0.0 to 1.0)
16509    define(interp, "jaro", Some(2), |_, args| {
16510        match (&args[0], &args[1]) {
16511            (Value::String(a), Value::String(b)) => {
16512                let sim = strsim::jaro(a, b);
16513                Ok(Value::Float(sim))
16514            }
16515            _ => Err(RuntimeError::new("jaro() requires two strings")),
16516        }
16517    });
16518
16519    // jaro_winkler - Jaro-Winkler similarity (0.0 to 1.0, favors common prefixes)
16520    define(interp, "jaro_winkler", Some(2), |_, args| {
16521        match (&args[0], &args[1]) {
16522            (Value::String(a), Value::String(b)) => {
16523                let sim = strsim::jaro_winkler(a, b);
16524                Ok(Value::Float(sim))
16525            }
16526            _ => Err(RuntimeError::new("jaro_winkler() requires two strings")),
16527        }
16528    });
16529
16530    // sorensen_dice - Sørensen-Dice coefficient (0.0 to 1.0)
16531    define(interp, "sorensen_dice", Some(2), |_, args| {
16532        match (&args[0], &args[1]) {
16533            (Value::String(a), Value::String(b)) => {
16534                let sim = strsim::sorensen_dice(a, b);
16535                Ok(Value::Float(sim))
16536            }
16537            _ => Err(RuntimeError::new("sorensen_dice() requires two strings")),
16538        }
16539    });
16540
16541    // damerau_levenshtein - edit distance with transpositions
16542    define(interp, "damerau_levenshtein", Some(2), |_, args| {
16543        match (&args[0], &args[1]) {
16544            (Value::String(a), Value::String(b)) => {
16545                let distance = strsim::damerau_levenshtein(a, b);
16546                Ok(Value::Int(distance as i64))
16547            }
16548            _ => Err(RuntimeError::new(
16549                "damerau_levenshtein() requires two strings",
16550            )),
16551        }
16552    });
16553
16554    // osa_distance - Optimal String Alignment distance
16555    define(interp, "osa_distance", Some(2), |_, args| {
16556        match (&args[0], &args[1]) {
16557            (Value::String(a), Value::String(b)) => {
16558                let distance = strsim::osa_distance(a, b);
16559                Ok(Value::Int(distance as i64))
16560            }
16561            _ => Err(RuntimeError::new("osa_distance() requires two strings")),
16562        }
16563    });
16564
16565    // fuzzy_match - check if strings are similar above threshold
16566    define(interp, "fuzzy_match", Some(3), |_, args| {
16567        match (&args[0], &args[1], &args[2]) {
16568            (Value::String(a), Value::String(b), Value::Float(threshold)) => {
16569                let sim = strsim::jaro_winkler(a, b);
16570                Ok(Value::Bool(sim >= *threshold))
16571            }
16572            (Value::String(a), Value::String(b), Value::Int(threshold)) => {
16573                let sim = strsim::jaro_winkler(a, b);
16574                Ok(Value::Bool(sim >= *threshold as f64))
16575            }
16576            _ => Err(RuntimeError::new(
16577                "fuzzy_match() requires two strings and threshold",
16578            )),
16579        }
16580    });
16581
16582    // fuzzy_search - find best matches in array
16583    define(interp, "fuzzy_search", Some(3), |_, args| {
16584        match (&args[0], &args[1], &args[2]) {
16585            (Value::String(query), Value::Array(items), Value::Int(limit)) => {
16586                let items_ref = items.borrow();
16587                let mut scores: Vec<(f64, &str)> = items_ref
16588                    .iter()
16589                    .filter_map(|v| {
16590                        if let Value::String(s) = v {
16591                            Some((strsim::jaro_winkler(query, s), s.as_str()))
16592                        } else {
16593                            None
16594                        }
16595                    })
16596                    .collect();
16597                scores.sort_by(|a, b| b.0.partial_cmp(&a.0).unwrap_or(std::cmp::Ordering::Equal));
16598                let results: Vec<Value> = scores
16599                    .into_iter()
16600                    .take(*limit as usize)
16601                    .map(|(_, s)| Value::String(Rc::new(s.to_string())))
16602                    .collect();
16603                Ok(Value::Array(Rc::new(RefCell::new(results))))
16604            }
16605            _ => Err(RuntimeError::new(
16606                "fuzzy_search() requires query string, array, and limit",
16607            )),
16608        }
16609    });
16610
16611    // =========================================================================
16612    // PHONETIC ENCODING
16613    // =========================================================================
16614
16615    // soundex - American Soundex encoding
16616    define(interp, "soundex", Some(1), |_, args| match &args[0] {
16617        Value::String(s) => {
16618            let code = compute_soundex(s);
16619            Ok(Value::String(Rc::new(code)))
16620        }
16621        _ => Err(RuntimeError::new("soundex() requires string")),
16622    });
16623
16624    // soundex_match - check if two strings have same Soundex code
16625    define(interp, "soundex_match", Some(2), |_, args| {
16626        match (&args[0], &args[1]) {
16627            (Value::String(a), Value::String(b)) => {
16628                let code_a = compute_soundex(a);
16629                let code_b = compute_soundex(b);
16630                Ok(Value::Bool(code_a == code_b))
16631            }
16632            _ => Err(RuntimeError::new("soundex_match() requires two strings")),
16633        }
16634    });
16635
16636    // metaphone - Metaphone encoding (better for English)
16637    define(interp, "metaphone", Some(1), |_, args| match &args[0] {
16638        Value::String(s) => {
16639            let code = compute_metaphone(s);
16640            Ok(Value::String(Rc::new(code)))
16641        }
16642        _ => Err(RuntimeError::new("metaphone() requires string")),
16643    });
16644
16645    // metaphone_match - check if two strings have same Metaphone code
16646    define(interp, "metaphone_match", Some(2), |_, args| {
16647        match (&args[0], &args[1]) {
16648            (Value::String(a), Value::String(b)) => {
16649                let code_a = compute_metaphone(a);
16650                let code_b = compute_metaphone(b);
16651                Ok(Value::Bool(code_a == code_b))
16652            }
16653            _ => Err(RuntimeError::new("metaphone_match() requires two strings")),
16654        }
16655    });
16656
16657    // cologne_phonetic - Cologne phonetic encoding (for German)
16658    define(interp, "cologne_phonetic", Some(1), |_, args| {
16659        match &args[0] {
16660            Value::String(s) => {
16661                let code = compute_cologne(s);
16662                Ok(Value::String(Rc::new(code)))
16663            }
16664            _ => Err(RuntimeError::new("cologne_phonetic() requires string")),
16665        }
16666    });
16667
16668    // =========================================================================
16669    // LANGUAGE DETECTION
16670    // =========================================================================
16671
16672    // detect_language - detect the language of text
16673    define(interp, "detect_language", Some(1), |_, args| {
16674        match &args[0] {
16675            Value::String(s) => {
16676                if let Some(info) = detect(s) {
16677                    let lang_code = match info.lang() {
16678                        Lang::Eng => "en",
16679                        Lang::Spa => "es",
16680                        Lang::Fra => "fr",
16681                        Lang::Deu => "de",
16682                        Lang::Ita => "it",
16683                        Lang::Por => "pt",
16684                        Lang::Rus => "ru",
16685                        Lang::Ara => "ar",
16686                        Lang::Hin => "hi",
16687                        Lang::Cmn => "zh",
16688                        Lang::Jpn => "ja",
16689                        Lang::Kor => "ko",
16690                        Lang::Nld => "nl",
16691                        Lang::Swe => "sv",
16692                        Lang::Tur => "tr",
16693                        Lang::Pol => "pl",
16694                        Lang::Ukr => "uk",
16695                        Lang::Ces => "cs",
16696                        Lang::Dan => "da",
16697                        Lang::Fin => "fi",
16698                        Lang::Ell => "el",
16699                        Lang::Heb => "he",
16700                        Lang::Hun => "hu",
16701                        Lang::Ind => "id",
16702                        Lang::Nob => "no",
16703                        Lang::Ron => "ro",
16704                        Lang::Slk => "sk",
16705                        Lang::Tha => "th",
16706                        Lang::Vie => "vi",
16707                        _ => "unknown",
16708                    };
16709                    Ok(Value::String(Rc::new(lang_code.to_string())))
16710                } else {
16711                    Ok(Value::String(Rc::new("unknown".to_string())))
16712                }
16713            }
16714            _ => Err(RuntimeError::new("detect_language() requires string")),
16715        }
16716    });
16717
16718    // detect_language_confidence - detect language with confidence score
16719    define(
16720        interp,
16721        "detect_language_confidence",
16722        Some(1),
16723        |_, args| match &args[0] {
16724            Value::String(s) => {
16725                if let Some(info) = detect(s) {
16726                    let lang_code = match info.lang() {
16727                        Lang::Eng => "en",
16728                        Lang::Spa => "es",
16729                        Lang::Fra => "fr",
16730                        Lang::Deu => "de",
16731                        Lang::Ita => "it",
16732                        Lang::Por => "pt",
16733                        Lang::Rus => "ru",
16734                        Lang::Ara => "ar",
16735                        Lang::Cmn => "zh",
16736                        Lang::Jpn => "ja",
16737                        _ => "unknown",
16738                    };
16739                    let confidence = info.confidence();
16740                    let mut map = HashMap::new();
16741                    map.insert(
16742                        "lang".to_string(),
16743                        Value::String(Rc::new(lang_code.to_string())),
16744                    );
16745                    map.insert("confidence".to_string(), Value::Float(confidence as f64));
16746                    Ok(Value::Map(Rc::new(RefCell::new(map))))
16747                } else {
16748                    let mut map = HashMap::new();
16749                    map.insert(
16750                        "lang".to_string(),
16751                        Value::String(Rc::new("unknown".to_string())),
16752                    );
16753                    map.insert("confidence".to_string(), Value::Float(0.0));
16754                    Ok(Value::Map(Rc::new(RefCell::new(map))))
16755                }
16756            }
16757            _ => Err(RuntimeError::new(
16758                "detect_language_confidence() requires string",
16759            )),
16760        },
16761    );
16762
16763    // detect_script - detect the script of text using whatlang
16764    define(
16765        interp,
16766        "detect_script_whatlang",
16767        Some(1),
16768        |_, args| match &args[0] {
16769            Value::String(s) => {
16770                if let Some(info) = detect(s) {
16771                    let script_name = match info.script() {
16772                        WhatLangScript::Latin => "Latin",
16773                        WhatLangScript::Cyrillic => "Cyrillic",
16774                        WhatLangScript::Arabic => "Arabic",
16775                        WhatLangScript::Devanagari => "Devanagari",
16776                        WhatLangScript::Ethiopic => "Ethiopic",
16777                        WhatLangScript::Georgian => "Georgian",
16778                        WhatLangScript::Greek => "Greek",
16779                        WhatLangScript::Gujarati => "Gujarati",
16780                        WhatLangScript::Gurmukhi => "Gurmukhi",
16781                        WhatLangScript::Hangul => "Hangul",
16782                        WhatLangScript::Hebrew => "Hebrew",
16783                        WhatLangScript::Hiragana => "Hiragana",
16784                        WhatLangScript::Kannada => "Kannada",
16785                        WhatLangScript::Katakana => "Katakana",
16786                        WhatLangScript::Khmer => "Khmer",
16787                        WhatLangScript::Malayalam => "Malayalam",
16788                        WhatLangScript::Mandarin => "Mandarin",
16789                        WhatLangScript::Myanmar => "Myanmar",
16790                        WhatLangScript::Oriya => "Oriya",
16791                        WhatLangScript::Sinhala => "Sinhala",
16792                        WhatLangScript::Tamil => "Tamil",
16793                        WhatLangScript::Telugu => "Telugu",
16794                        WhatLangScript::Thai => "Thai",
16795                        WhatLangScript::Bengali => "Bengali",
16796                        WhatLangScript::Armenian => "Armenian",
16797                    };
16798                    Ok(Value::String(Rc::new(script_name.to_string())))
16799                } else {
16800                    Ok(Value::String(Rc::new("Unknown".to_string())))
16801                }
16802            }
16803            _ => Err(RuntimeError::new(
16804                "detect_script_whatlang() requires string",
16805            )),
16806        },
16807    );
16808
16809    // is_language - check if text is in a specific language
16810    define(interp, "is_language", Some(2), |_, args| {
16811        match (&args[0], &args[1]) {
16812            (Value::String(s), Value::String(lang)) => {
16813                if let Some(info) = detect(s) {
16814                    let detected = match info.lang() {
16815                        Lang::Eng => "en",
16816                        Lang::Spa => "es",
16817                        Lang::Fra => "fr",
16818                        Lang::Deu => "de",
16819                        Lang::Ita => "it",
16820                        Lang::Por => "pt",
16821                        Lang::Rus => "ru",
16822                        _ => "unknown",
16823                    };
16824                    Ok(Value::Bool(detected == lang.as_str()))
16825                } else {
16826                    Ok(Value::Bool(false))
16827                }
16828            }
16829            _ => Err(RuntimeError::new(
16830                "is_language() requires string and language code",
16831            )),
16832        }
16833    });
16834
16835    // =========================================================================
16836    // LLM TOKEN COUNTING
16837    // =========================================================================
16838
16839    // token_count - count tokens using cl100k_base (GPT-4, Claude compatible)
16840    define(interp, "token_count", Some(1), |_, args| match &args[0] {
16841        Value::String(s) => {
16842            if let Ok(bpe) = cl100k_base() {
16843                let tokens = bpe.encode_with_special_tokens(s);
16844                Ok(Value::Int(tokens.len() as i64))
16845            } else {
16846                Err(RuntimeError::new("Failed to initialize tokenizer"))
16847            }
16848        }
16849        _ => Err(RuntimeError::new("token_count() requires string")),
16850    });
16851
16852    // token_count_model - count tokens for specific model
16853    define(interp, "token_count_model", Some(2), |_, args| {
16854        match (&args[0], &args[1]) {
16855            (Value::String(s), Value::String(model)) => {
16856                let bpe_result = match model.as_str() {
16857                    "gpt4" | "gpt-4" | "claude" | "cl100k" => cl100k_base(),
16858                    "gpt3" | "gpt-3" | "p50k" => p50k_base(),
16859                    "codex" | "r50k" => r50k_base(),
16860                    _ => cl100k_base(), // Default to GPT-4/Claude
16861                };
16862                if let Ok(bpe) = bpe_result {
16863                    let tokens = bpe.encode_with_special_tokens(s);
16864                    Ok(Value::Int(tokens.len() as i64))
16865                } else {
16866                    Err(RuntimeError::new("Failed to initialize tokenizer"))
16867                }
16868            }
16869            _ => Err(RuntimeError::new(
16870                "token_count_model() requires string and model name",
16871            )),
16872        }
16873    });
16874
16875    // tokenize_ids - get token IDs as array
16876    define(interp, "tokenize_ids", Some(1), |_, args| match &args[0] {
16877        Value::String(s) => {
16878            if let Ok(bpe) = cl100k_base() {
16879                let tokens = bpe.encode_with_special_tokens(s);
16880                let values: Vec<Value> = tokens.into_iter().map(|t| Value::Int(t as i64)).collect();
16881                Ok(Value::Array(Rc::new(RefCell::new(values))))
16882            } else {
16883                Err(RuntimeError::new("Failed to initialize tokenizer"))
16884            }
16885        }
16886        _ => Err(RuntimeError::new("tokenize_ids() requires string")),
16887    });
16888
16889    // truncate_tokens - truncate string to max tokens
16890    define(interp, "truncate_tokens", Some(2), |_, args| {
16891        match (&args[0], &args[1]) {
16892            (Value::String(s), Value::Int(max_tokens)) => {
16893                if let Ok(bpe) = cl100k_base() {
16894                    let tokens = bpe.encode_with_special_tokens(s);
16895                    if tokens.len() <= *max_tokens as usize {
16896                        Ok(Value::String(s.clone()))
16897                    } else {
16898                        let truncated: Vec<usize> =
16899                            tokens.into_iter().take(*max_tokens as usize).collect();
16900                        if let Ok(decoded) = bpe.decode(truncated) {
16901                            Ok(Value::String(Rc::new(decoded)))
16902                        } else {
16903                            Err(RuntimeError::new("Failed to decode tokens"))
16904                        }
16905                    }
16906                } else {
16907                    Err(RuntimeError::new("Failed to initialize tokenizer"))
16908                }
16909            }
16910            _ => Err(RuntimeError::new(
16911                "truncate_tokens() requires string and max tokens",
16912            )),
16913        }
16914    });
16915
16916    // estimate_cost - estimate API cost based on token count
16917    define(interp, "estimate_cost", Some(3), |_, args| {
16918        match (&args[0], &args[1], &args[2]) {
16919            (Value::String(s), Value::Float(input_cost), Value::Float(output_cost)) => {
16920                if let Ok(bpe) = cl100k_base() {
16921                    let tokens = bpe.encode_with_special_tokens(s);
16922                    let count = tokens.len() as f64;
16923                    // Cost per 1K tokens
16924                    let input_total = (count / 1000.0) * input_cost;
16925                    let output_total = (count / 1000.0) * output_cost;
16926                    let mut map = HashMap::new();
16927                    map.insert("tokens".to_string(), Value::Int(tokens.len() as i64));
16928                    map.insert("input_cost".to_string(), Value::Float(input_total));
16929                    map.insert("output_cost".to_string(), Value::Float(output_total));
16930                    Ok(Value::Map(Rc::new(RefCell::new(map))))
16931                } else {
16932                    Err(RuntimeError::new("Failed to initialize tokenizer"))
16933                }
16934            }
16935            _ => Err(RuntimeError::new(
16936                "estimate_cost() requires string, input cost, output cost",
16937            )),
16938        }
16939    });
16940
16941    // =========================================================================
16942    // STEMMING
16943    // =========================================================================
16944
16945    // stem - stem a word using Porter algorithm
16946    define(interp, "stem", Some(1), |_, args| match &args[0] {
16947        Value::String(s) => {
16948            let stemmer = Stemmer::create(StemAlgorithm::English);
16949            let stemmed = stemmer.stem(s);
16950            Ok(Value::String(Rc::new(stemmed.to_string())))
16951        }
16952        _ => Err(RuntimeError::new("stem() requires string")),
16953    });
16954
16955    // stem_language - stem a word for specific language
16956    define(interp, "stem_language", Some(2), |_, args| {
16957        match (&args[0], &args[1]) {
16958            (Value::String(s), Value::String(lang)) => {
16959                let algorithm = match lang.as_str() {
16960                    "en" | "english" => StemAlgorithm::English,
16961                    "fr" | "french" => StemAlgorithm::French,
16962                    "de" | "german" => StemAlgorithm::German,
16963                    "es" | "spanish" => StemAlgorithm::Spanish,
16964                    "it" | "italian" => StemAlgorithm::Italian,
16965                    "pt" | "portuguese" => StemAlgorithm::Portuguese,
16966                    "nl" | "dutch" => StemAlgorithm::Dutch,
16967                    "sv" | "swedish" => StemAlgorithm::Swedish,
16968                    "no" | "norwegian" => StemAlgorithm::Norwegian,
16969                    "da" | "danish" => StemAlgorithm::Danish,
16970                    "fi" | "finnish" => StemAlgorithm::Finnish,
16971                    "ru" | "russian" => StemAlgorithm::Russian,
16972                    "ro" | "romanian" => StemAlgorithm::Romanian,
16973                    "hu" | "hungarian" => StemAlgorithm::Hungarian,
16974                    "tr" | "turkish" => StemAlgorithm::Turkish,
16975                    "ar" | "arabic" => StemAlgorithm::Arabic,
16976                    _ => StemAlgorithm::English,
16977                };
16978                let stemmer = Stemmer::create(algorithm);
16979                let stemmed = stemmer.stem(s);
16980                Ok(Value::String(Rc::new(stemmed.to_string())))
16981            }
16982            _ => Err(RuntimeError::new(
16983                "stem_language() requires string and language code",
16984            )),
16985        }
16986    });
16987
16988    // stem_all - stem all words in array
16989    define(interp, "stem_all", Some(1), |_, args| match &args[0] {
16990        Value::Array(arr) => {
16991            let stemmer = Stemmer::create(StemAlgorithm::English);
16992            let arr_ref = arr.borrow();
16993            let results: Vec<Value> = arr_ref
16994                .iter()
16995                .filter_map(|v| {
16996                    if let Value::String(s) = v {
16997                        Some(Value::String(Rc::new(stemmer.stem(s).to_string())))
16998                    } else {
16999                        None
17000                    }
17001                })
17002                .collect();
17003            Ok(Value::Array(Rc::new(RefCell::new(results))))
17004        }
17005        _ => Err(RuntimeError::new("stem_all() requires array of strings")),
17006    });
17007
17008    // =========================================================================
17009    // STOPWORDS
17010    // =========================================================================
17011
17012    // is_stopword - check if word is a stopword
17013    define(interp, "is_stopword", Some(1), |_, args| match &args[0] {
17014        Value::String(s) => {
17015            let word = s.to_lowercase();
17016            let stopwords = get_stopwords("en");
17017            Ok(Value::Bool(stopwords.contains(&word.as_str())))
17018        }
17019        _ => Err(RuntimeError::new("is_stopword() requires string")),
17020    });
17021
17022    // is_stopword_language - check if word is stopword in language
17023    define(interp, "is_stopword_language", Some(2), |_, args| {
17024        match (&args[0], &args[1]) {
17025            (Value::String(s), Value::String(lang)) => {
17026                let word = s.to_lowercase();
17027                let stopwords = get_stopwords(lang);
17028                Ok(Value::Bool(stopwords.contains(&word.as_str())))
17029            }
17030            _ => Err(RuntimeError::new(
17031                "is_stopword_language() requires string and language",
17032            )),
17033        }
17034    });
17035
17036    // remove_stopwords - remove stopwords from array
17037    define(interp, "remove_stopwords", Some(1), |_, args| {
17038        match &args[0] {
17039            Value::Array(arr) => {
17040                let stopwords = get_stopwords("en");
17041                let arr_ref = arr.borrow();
17042                let results: Vec<Value> = arr_ref
17043                    .iter()
17044                    .filter(|v| {
17045                        if let Value::String(s) = v {
17046                            !stopwords.contains(&s.to_lowercase().as_str())
17047                        } else {
17048                            true
17049                        }
17050                    })
17051                    .cloned()
17052                    .collect();
17053                Ok(Value::Array(Rc::new(RefCell::new(results))))
17054            }
17055            _ => Err(RuntimeError::new(
17056                "remove_stopwords() requires array of strings",
17057            )),
17058        }
17059    });
17060
17061    // remove_stopwords_text - remove stopwords from text string
17062    define(
17063        interp,
17064        "remove_stopwords_text",
17065        Some(1),
17066        |_, args| match &args[0] {
17067            Value::String(s) => {
17068                let stopwords = get_stopwords("en");
17069                let words: Vec<&str> = s
17070                    .split_whitespace()
17071                    .filter(|w| !stopwords.contains(&w.to_lowercase().as_str()))
17072                    .collect();
17073                Ok(Value::String(Rc::new(words.join(" "))))
17074            }
17075            _ => Err(RuntimeError::new("remove_stopwords_text() requires string")),
17076        },
17077    );
17078
17079    // get_stopwords_list - get list of stopwords for language
17080    define(
17081        interp,
17082        "get_stopwords_list",
17083        Some(1),
17084        |_, args| match &args[0] {
17085            Value::String(lang) => {
17086                let stopwords = get_stopwords(lang);
17087                let values: Vec<Value> = stopwords
17088                    .iter()
17089                    .map(|s| Value::String(Rc::new(s.to_string())))
17090                    .collect();
17091                Ok(Value::Array(Rc::new(RefCell::new(values))))
17092            }
17093            _ => Err(RuntimeError::new(
17094                "get_stopwords_list() requires language code",
17095            )),
17096        },
17097    );
17098
17099    // =========================================================================
17100    // N-GRAMS AND SHINGLES
17101    // =========================================================================
17102
17103    // ngrams - extract word n-grams
17104    define(interp, "ngrams", Some(2), |_, args| {
17105        match (&args[0], &args[1]) {
17106            (Value::String(s), Value::Int(n)) => {
17107                let words: Vec<&str> = s.split_whitespace().collect();
17108                let n = *n as usize;
17109                if n == 0 || n > words.len() {
17110                    return Ok(Value::Array(Rc::new(RefCell::new(vec![]))));
17111                }
17112                let ngrams: Vec<Value> = words
17113                    .windows(n)
17114                    .map(|w| Value::String(Rc::new(w.join(" "))))
17115                    .collect();
17116                Ok(Value::Array(Rc::new(RefCell::new(ngrams))))
17117            }
17118            _ => Err(RuntimeError::new("ngrams() requires string and n")),
17119        }
17120    });
17121
17122    // char_ngrams - extract character n-grams
17123    define(interp, "char_ngrams", Some(2), |_, args| {
17124        match (&args[0], &args[1]) {
17125            (Value::String(s), Value::Int(n)) => {
17126                let chars: Vec<char> = s.chars().collect();
17127                let n = *n as usize;
17128                if n == 0 || n > chars.len() {
17129                    return Ok(Value::Array(Rc::new(RefCell::new(vec![]))));
17130                }
17131                let ngrams: Vec<Value> = chars
17132                    .windows(n)
17133                    .map(|w| Value::String(Rc::new(w.iter().collect())))
17134                    .collect();
17135                Ok(Value::Array(Rc::new(RefCell::new(ngrams))))
17136            }
17137            _ => Err(RuntimeError::new("char_ngrams() requires string and n")),
17138        }
17139    });
17140
17141    // shingles - extract word shingles (same as ngrams, but as set)
17142    define(interp, "shingles", Some(2), |_, args| {
17143        match (&args[0], &args[1]) {
17144            (Value::String(s), Value::Int(n)) => {
17145                let words: Vec<&str> = s.split_whitespace().collect();
17146                let n = *n as usize;
17147                if n == 0 || n > words.len() {
17148                    return Ok(Value::Array(Rc::new(RefCell::new(vec![]))));
17149                }
17150                let mut seen = std::collections::HashSet::new();
17151                let shingles: Vec<Value> = words
17152                    .windows(n)
17153                    .filter_map(|w| {
17154                        let s = w.join(" ");
17155                        if seen.insert(s.clone()) {
17156                            Some(Value::String(Rc::new(s)))
17157                        } else {
17158                            None
17159                        }
17160                    })
17161                    .collect();
17162                Ok(Value::Array(Rc::new(RefCell::new(shingles))))
17163            }
17164            _ => Err(RuntimeError::new("shingles() requires string and n")),
17165        }
17166    });
17167
17168    // jaccard_similarity - Jaccard similarity between two sets of shingles
17169    define(interp, "jaccard_similarity", Some(2), |_, args| {
17170        match (&args[0], &args[1]) {
17171            (Value::Array(a), Value::Array(b)) => {
17172                let a_ref = a.borrow();
17173                let b_ref = b.borrow();
17174                let set_a: std::collections::HashSet<String> = a_ref
17175                    .iter()
17176                    .filter_map(|v| {
17177                        if let Value::String(s) = v {
17178                            Some(s.to_string())
17179                        } else {
17180                            None
17181                        }
17182                    })
17183                    .collect();
17184                let set_b: std::collections::HashSet<String> = b_ref
17185                    .iter()
17186                    .filter_map(|v| {
17187                        if let Value::String(s) = v {
17188                            Some(s.to_string())
17189                        } else {
17190                            None
17191                        }
17192                    })
17193                    .collect();
17194                let intersection = set_a.intersection(&set_b).count();
17195                let union = set_a.union(&set_b).count();
17196                if union == 0 {
17197                    Ok(Value::Float(0.0))
17198                } else {
17199                    Ok(Value::Float(intersection as f64 / union as f64))
17200                }
17201            }
17202            _ => Err(RuntimeError::new(
17203                "jaccard_similarity() requires two arrays",
17204            )),
17205        }
17206    });
17207
17208    // minhash_signature - compute MinHash signature for LSH
17209    define(interp, "minhash_signature", Some(2), |_, args| {
17210        match (&args[0], &args[1]) {
17211            (Value::Array(arr), Value::Int(num_hashes)) => {
17212                let arr_ref = arr.borrow();
17213                let items: std::collections::HashSet<String> = arr_ref
17214                    .iter()
17215                    .filter_map(|v| {
17216                        if let Value::String(s) = v {
17217                            Some(s.to_string())
17218                        } else {
17219                            None
17220                        }
17221                    })
17222                    .collect();
17223
17224                // Simple MinHash using polynomial rolling hash
17225                let mut signature: Vec<Value> = Vec::with_capacity(*num_hashes as usize);
17226                for i in 0..*num_hashes {
17227                    let mut min_hash: u64 = u64::MAX;
17228                    for item in &items {
17229                        let hash = compute_hash(item, i as u64);
17230                        if hash < min_hash {
17231                            min_hash = hash;
17232                        }
17233                    }
17234                    signature.push(Value::Int(min_hash as i64));
17235                }
17236                Ok(Value::Array(Rc::new(RefCell::new(signature))))
17237            }
17238            _ => Err(RuntimeError::new(
17239                "minhash_signature() requires array and num_hashes",
17240            )),
17241        }
17242    });
17243
17244    // =========================================================================
17245    // TEXT PREPROCESSING
17246    // =========================================================================
17247
17248    // preprocess_text - full text preprocessing pipeline
17249    define(interp, "preprocess_text", Some(1), |_, args| {
17250        match &args[0] {
17251            Value::String(s) => {
17252                // Lowercase
17253                let lower = s.to_lowercase();
17254                // Remove punctuation (keep letters, numbers, spaces)
17255                let clean: String = lower
17256                    .chars()
17257                    .filter(|c| c.is_alphanumeric() || c.is_whitespace())
17258                    .collect();
17259                // Normalize whitespace
17260                let normalized: String = clean.split_whitespace().collect::<Vec<_>>().join(" ");
17261                Ok(Value::String(Rc::new(normalized)))
17262            }
17263            _ => Err(RuntimeError::new("preprocess_text() requires string")),
17264        }
17265    });
17266
17267    // tokenize_words - split text into word tokens
17268    define(interp, "tokenize_words", Some(1), |_, args| {
17269        match &args[0] {
17270            Value::String(s) => {
17271                let words: Vec<Value> = s
17272                    .split_whitespace()
17273                    .map(|w| Value::String(Rc::new(w.to_string())))
17274                    .collect();
17275                Ok(Value::Array(Rc::new(RefCell::new(words))))
17276            }
17277            _ => Err(RuntimeError::new("tokenize_words() requires string")),
17278        }
17279    });
17280
17281    // extract_keywords - extract likely keywords (content words)
17282    define(interp, "extract_keywords", Some(1), |_, args| {
17283        match &args[0] {
17284            Value::String(s) => {
17285                let stopwords = get_stopwords("en");
17286                let words: Vec<Value> = s
17287                    .split_whitespace()
17288                    .filter(|w| {
17289                        let lower = w.to_lowercase();
17290                        !stopwords.contains(&lower.as_str()) && lower.len() > 2
17291                    })
17292                    .map(|w| Value::String(Rc::new(w.to_lowercase())))
17293                    .collect();
17294                Ok(Value::Array(Rc::new(RefCell::new(words))))
17295            }
17296            _ => Err(RuntimeError::new("extract_keywords() requires string")),
17297        }
17298    });
17299
17300    // word_frequency - count word frequencies
17301    define(interp, "word_frequency", Some(1), |_, args| {
17302        match &args[0] {
17303            Value::String(s) => {
17304                let mut freq: HashMap<String, i64> = HashMap::new();
17305                for word in s.split_whitespace() {
17306                    let lower = word.to_lowercase();
17307                    *freq.entry(lower).or_insert(0) += 1;
17308                }
17309                let map: HashMap<String, Value> =
17310                    freq.into_iter().map(|(k, v)| (k, Value::Int(v))).collect();
17311                Ok(Value::Map(Rc::new(RefCell::new(map))))
17312            }
17313            _ => Err(RuntimeError::new("word_frequency() requires string")),
17314        }
17315    });
17316
17317    // =========================================================================
17318    // AFFECTIVE MARKERS (Emotional Intelligence)
17319    // =========================================================================
17320
17321    // sentiment_words - basic sentiment word detection
17322    define(interp, "sentiment_words", Some(1), |_, args| {
17323        match &args[0] {
17324            Value::String(s) => {
17325                let positive = vec![
17326                    "good",
17327                    "great",
17328                    "excellent",
17329                    "amazing",
17330                    "wonderful",
17331                    "fantastic",
17332                    "love",
17333                    "happy",
17334                    "joy",
17335                    "beautiful",
17336                    "awesome",
17337                    "perfect",
17338                    "best",
17339                    "brilliant",
17340                    "delightful",
17341                    "pleasant",
17342                    "positive",
17343                ];
17344                let negative = vec![
17345                    "bad",
17346                    "terrible",
17347                    "awful",
17348                    "horrible",
17349                    "hate",
17350                    "sad",
17351                    "angry",
17352                    "worst",
17353                    "poor",
17354                    "negative",
17355                    "disappointing",
17356                    "ugly",
17357                    "disgusting",
17358                    "painful",
17359                    "miserable",
17360                    "annoying",
17361                ];
17362
17363                let lower = s.to_lowercase();
17364                let words: Vec<&str> = lower.split_whitespace().collect();
17365                let pos_count: i64 = words.iter().filter(|w| positive.contains(w)).count() as i64;
17366                let neg_count: i64 = words.iter().filter(|w| negative.contains(w)).count() as i64;
17367
17368                let mut map = HashMap::new();
17369                map.insert("positive".to_string(), Value::Int(pos_count));
17370                map.insert("negative".to_string(), Value::Int(neg_count));
17371                map.insert("total".to_string(), Value::Int(words.len() as i64));
17372
17373                let score = if pos_count + neg_count > 0 {
17374                    (pos_count - neg_count) as f64 / (pos_count + neg_count) as f64
17375                } else {
17376                    0.0
17377                };
17378                map.insert("score".to_string(), Value::Float(score));
17379
17380                Ok(Value::Map(Rc::new(RefCell::new(map))))
17381            }
17382            _ => Err(RuntimeError::new("sentiment_words() requires string")),
17383        }
17384    });
17385
17386    // has_question - detect if text contains a question
17387    define(interp, "has_question", Some(1), |_, args| match &args[0] {
17388        Value::String(s) => {
17389            let has_q_mark = s.contains('?');
17390            let lower = s.to_lowercase();
17391            let question_words = [
17392                "what", "where", "when", "why", "how", "who", "which", "whose", "whom",
17393            ];
17394            let starts_with_q = question_words.iter().any(|w| lower.starts_with(w));
17395            Ok(Value::Bool(has_q_mark || starts_with_q))
17396        }
17397        _ => Err(RuntimeError::new("has_question() requires string")),
17398    });
17399
17400    // has_exclamation - detect if text has strong emotion markers
17401    define(interp, "has_exclamation", Some(1), |_, args| {
17402        match &args[0] {
17403            Value::String(s) => Ok(Value::Bool(s.contains('!'))),
17404            _ => Err(RuntimeError::new("has_exclamation() requires string")),
17405        }
17406    });
17407
17408    // text_formality - estimate text formality (0=informal, 1=formal)
17409    define(interp, "text_formality", Some(1), |_, args| {
17410        match &args[0] {
17411            Value::String(s) => {
17412                let lower = s.to_lowercase();
17413                let informal_markers = vec![
17414                    "gonna", "wanna", "gotta", "kinda", "sorta", "dunno", "yeah", "yep", "nope",
17415                    "ok", "lol", "omg", "btw", "u", "ur", "r", "y", "2", "4",
17416                ];
17417                let formal_markers = vec![
17418                    "therefore",
17419                    "furthermore",
17420                    "moreover",
17421                    "consequently",
17422                    "nevertheless",
17423                    "however",
17424                    "whereas",
17425                    "hereby",
17426                    "respectfully",
17427                    "sincerely",
17428                    "accordingly",
17429                ];
17430
17431                let words: Vec<&str> = lower.split_whitespace().collect();
17432                let informal_count = words
17433                    .iter()
17434                    .filter(|w| informal_markers.contains(w))
17435                    .count();
17436                let formal_count = words.iter().filter(|w| formal_markers.contains(w)).count();
17437
17438                let score = if informal_count + formal_count > 0 {
17439                    formal_count as f64 / (informal_count + formal_count) as f64
17440                } else {
17441                    0.5 // Neutral if no markers
17442                };
17443
17444                Ok(Value::Float(score))
17445            }
17446            _ => Err(RuntimeError::new("text_formality() requires string")),
17447        }
17448    });
17449
17450    // =========================================================================
17451    // VADER-STYLE SENTIMENT ANALYSIS
17452    // =========================================================================
17453
17454    // sentiment_vader - VADER-inspired sentiment analysis with intensity
17455    define(interp, "sentiment_vader", Some(1), |_, args| {
17456        match &args[0] {
17457            Value::String(s) => {
17458                let result = compute_vader_sentiment(s);
17459                let mut map = HashMap::new();
17460                map.insert("positive".to_string(), Value::Float(result.0));
17461                map.insert("negative".to_string(), Value::Float(result.1));
17462                map.insert("neutral".to_string(), Value::Float(result.2));
17463                map.insert("compound".to_string(), Value::Float(result.3));
17464                Ok(Value::Map(Rc::new(RefCell::new(map))))
17465            }
17466            _ => Err(RuntimeError::new("sentiment_vader() requires string")),
17467        }
17468    });
17469
17470    // emotion_detect - detect specific emotions
17471    define(interp, "emotion_detect", Some(1), |_, args| {
17472        match &args[0] {
17473            Value::String(s) => {
17474                let emotions = compute_emotions(s);
17475                let map: HashMap<String, Value> = emotions
17476                    .into_iter()
17477                    .map(|(k, v)| (k, Value::Float(v)))
17478                    .collect();
17479                Ok(Value::Map(Rc::new(RefCell::new(map))))
17480            }
17481            _ => Err(RuntimeError::new("emotion_detect() requires string")),
17482        }
17483    });
17484
17485    // intensity_words - detect intensity modifiers
17486    define(interp, "intensity_score", Some(1), |_, args| {
17487        match &args[0] {
17488            Value::String(s) => {
17489                let score = compute_intensity(s);
17490                Ok(Value::Float(score))
17491            }
17492            _ => Err(RuntimeError::new("intensity_score() requires string")),
17493        }
17494    });
17495
17496    // =========================================================================
17497    // SARCASM AND IRONY DETECTION
17498    // =========================================================================
17499
17500    // detect_sarcasm - detect potential sarcasm/irony markers
17501    define(interp, "detect_sarcasm", Some(1), |_, args| {
17502        match &args[0] {
17503            Value::String(s) => {
17504                let result = compute_sarcasm_score(s);
17505                let mut map = HashMap::new();
17506                map.insert("score".to_string(), Value::Float(result.0));
17507                map.insert("confidence".to_string(), Value::Float(result.1));
17508                let markers: Vec<Value> = result
17509                    .2
17510                    .into_iter()
17511                    .map(|m| Value::String(Rc::new(m)))
17512                    .collect();
17513                map.insert(
17514                    "markers".to_string(),
17515                    Value::Array(Rc::new(RefCell::new(markers))),
17516                );
17517                Ok(Value::Map(Rc::new(RefCell::new(map))))
17518            }
17519            _ => Err(RuntimeError::new("detect_sarcasm() requires string")),
17520        }
17521    });
17522
17523    // is_sarcastic - simple boolean sarcasm check
17524    define(interp, "is_sarcastic", Some(1), |_, args| match &args[0] {
17525        Value::String(s) => {
17526            let result = compute_sarcasm_score(s);
17527            Ok(Value::Bool(result.0 > 0.5))
17528        }
17529        _ => Err(RuntimeError::new("is_sarcastic() requires string")),
17530    });
17531
17532    // detect_irony - detect verbal irony patterns
17533    define(interp, "detect_irony", Some(1), |_, args| match &args[0] {
17534        Value::String(s) => {
17535            let score = compute_irony_score(s);
17536            Ok(Value::Float(score))
17537        }
17538        _ => Err(RuntimeError::new("detect_irony() requires string")),
17539    });
17540
17541    // =========================================================================
17542    // NAMED ENTITY RECOGNITION (Pattern-based)
17543    // =========================================================================
17544
17545    // extract_emails - extract email addresses
17546    define(interp, "extract_emails", Some(1), |_, args| {
17547        match &args[0] {
17548            Value::String(s) => {
17549                let re = Regex::new(r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}").unwrap();
17550                let emails: Vec<Value> = re
17551                    .find_iter(s)
17552                    .map(|m| Value::String(Rc::new(m.as_str().to_string())))
17553                    .collect();
17554                Ok(Value::Array(Rc::new(RefCell::new(emails))))
17555            }
17556            _ => Err(RuntimeError::new("extract_emails() requires string")),
17557        }
17558    });
17559
17560    // extract_urls - extract URLs
17561    define(interp, "extract_urls", Some(1), |_, args| match &args[0] {
17562        Value::String(s) => {
17563            let re = Regex::new(r"https?://[^\s<>\[\]{}|\\^]+").unwrap();
17564            let urls: Vec<Value> = re
17565                .find_iter(s)
17566                .map(|m| Value::String(Rc::new(m.as_str().to_string())))
17567                .collect();
17568            Ok(Value::Array(Rc::new(RefCell::new(urls))))
17569        }
17570        _ => Err(RuntimeError::new("extract_urls() requires string")),
17571    });
17572
17573    // extract_phone_numbers - extract phone numbers
17574    define(
17575        interp,
17576        "extract_phone_numbers",
17577        Some(1),
17578        |_, args| match &args[0] {
17579            Value::String(s) => {
17580                let re =
17581                    Regex::new(r"(?:\+?1[-.\s]?)?\(?[0-9]{3}\)?[-.\s]?[0-9]{3}[-.\s]?[0-9]{4}")
17582                        .unwrap();
17583                let phones: Vec<Value> = re
17584                    .find_iter(s)
17585                    .map(|m| Value::String(Rc::new(m.as_str().to_string())))
17586                    .collect();
17587                Ok(Value::Array(Rc::new(RefCell::new(phones))))
17588            }
17589            _ => Err(RuntimeError::new("extract_phone_numbers() requires string")),
17590        },
17591    );
17592
17593    // extract_dates - extract date patterns
17594    define(interp, "extract_dates", Some(1), |_, args| {
17595        match &args[0] {
17596            Value::String(s) => {
17597                // Various date formats
17598                let patterns = vec![
17599                    r"\d{4}-\d{2}-\d{2}", // 2024-01-15
17600                    r"\d{2}/\d{2}/\d{4}", // 01/15/2024
17601                    r"\d{2}-\d{2}-\d{4}", // 01-15-2024
17602                    r"(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[a-z]*\s+\d{1,2},?\s+\d{4}",
17603                    r"\d{1,2}\s+(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[a-z]*\s+\d{4}",
17604                ];
17605                let mut dates = Vec::new();
17606                for pattern in patterns {
17607                    if let Ok(re) = Regex::new(pattern) {
17608                        for m in re.find_iter(s) {
17609                            dates.push(Value::String(Rc::new(m.as_str().to_string())));
17610                        }
17611                    }
17612                }
17613                Ok(Value::Array(Rc::new(RefCell::new(dates))))
17614            }
17615            _ => Err(RuntimeError::new("extract_dates() requires string")),
17616        }
17617    });
17618
17619    // extract_money - extract monetary values
17620    define(interp, "extract_money", Some(1), |_, args| match &args[0] {
17621        Value::String(s) => {
17622            let re = Regex::new(r"[$€£¥]\s*\d+(?:,\d{3})*(?:\.\d{2})?|\d+(?:,\d{3})*(?:\.\d{2})?\s*(?:dollars?|euros?|pounds?|USD|EUR|GBP)").unwrap();
17623            let money: Vec<Value> = re
17624                .find_iter(s)
17625                .map(|m| Value::String(Rc::new(m.as_str().to_string())))
17626                .collect();
17627            Ok(Value::Array(Rc::new(RefCell::new(money))))
17628        }
17629        _ => Err(RuntimeError::new("extract_money() requires string")),
17630    });
17631
17632    // extract_hashtags - extract hashtags
17633    define(interp, "extract_hashtags", Some(1), |_, args| {
17634        match &args[0] {
17635            Value::String(s) => {
17636                let re = Regex::new(r"#\w+").unwrap();
17637                let tags: Vec<Value> = re
17638                    .find_iter(s)
17639                    .map(|m| Value::String(Rc::new(m.as_str().to_string())))
17640                    .collect();
17641                Ok(Value::Array(Rc::new(RefCell::new(tags))))
17642            }
17643            _ => Err(RuntimeError::new("extract_hashtags() requires string")),
17644        }
17645    });
17646
17647    // extract_mentions - extract @mentions
17648    define(interp, "extract_mentions", Some(1), |_, args| {
17649        match &args[0] {
17650            Value::String(s) => {
17651                let re = Regex::new(r"@\w+").unwrap();
17652                let mentions: Vec<Value> = re
17653                    .find_iter(s)
17654                    .map(|m| Value::String(Rc::new(m.as_str().to_string())))
17655                    .collect();
17656                Ok(Value::Array(Rc::new(RefCell::new(mentions))))
17657            }
17658            _ => Err(RuntimeError::new("extract_mentions() requires string")),
17659        }
17660    });
17661
17662    // extract_numbers - extract all numbers
17663    define(interp, "extract_numbers", Some(1), |_, args| {
17664        match &args[0] {
17665            Value::String(s) => {
17666                let re = Regex::new(r"-?\d+(?:,\d{3})*(?:\.\d+)?").unwrap();
17667                let numbers: Vec<Value> = re
17668                    .find_iter(s)
17669                    .filter_map(|m| {
17670                        let num_str = m.as_str().replace(",", "");
17671                        if let Ok(n) = num_str.parse::<f64>() {
17672                            Some(Value::Float(n))
17673                        } else {
17674                            None
17675                        }
17676                    })
17677                    .collect();
17678                Ok(Value::Array(Rc::new(RefCell::new(numbers))))
17679            }
17680            _ => Err(RuntimeError::new("extract_numbers() requires string")),
17681        }
17682    });
17683
17684    // extract_entities - extract likely named entities (capitalized words)
17685    define(interp, "extract_entities", Some(1), |_, args| {
17686        match &args[0] {
17687            Value::String(s) => {
17688                // Simple heuristic: capitalized words not at sentence start
17689                let re = Regex::new(r"(?:[.!?]\s+)?([A-Z][a-z]+(?:\s+[A-Z][a-z]+)*)").unwrap();
17690                let mut entities = std::collections::HashSet::new();
17691                for cap in re.captures_iter(s) {
17692                    if let Some(m) = cap.get(1) {
17693                        let entity = m.as_str().to_string();
17694                        // Filter out common sentence starters
17695                        let starters = [
17696                            "The", "A", "An", "This", "That", "It", "I", "We", "They", "He", "She",
17697                        ];
17698                        if !starters.contains(&entity.as_str()) {
17699                            entities.insert(entity);
17700                        }
17701                    }
17702                }
17703                let results: Vec<Value> = entities
17704                    .into_iter()
17705                    .map(|e| Value::String(Rc::new(e)))
17706                    .collect();
17707                Ok(Value::Array(Rc::new(RefCell::new(results))))
17708            }
17709            _ => Err(RuntimeError::new("extract_entities() requires string")),
17710        }
17711    });
17712
17713    // =========================================================================
17714    // TEXT EMBEDDINGS (Hash-based, no ML required)
17715    // =========================================================================
17716
17717    // text_hash_vector - create a simple hash-based embedding
17718    define(interp, "text_hash_vector", Some(2), |_, args| {
17719        match (&args[0], &args[1]) {
17720            (Value::String(s), Value::Int(dims)) => {
17721                let dims = *dims as usize;
17722                let mut vector = vec![0.0f64; dims];
17723
17724                // Hash each word and add to vector
17725                for word in s.to_lowercase().split_whitespace() {
17726                    let hash = compute_hash(word, 0);
17727                    let idx = (hash as usize) % dims;
17728                    vector[idx] += 1.0;
17729                }
17730
17731                // Normalize
17732                let magnitude: f64 = vector.iter().map(|x| x * x).sum::<f64>().sqrt();
17733                if magnitude > 0.0 {
17734                    for v in vector.iter_mut() {
17735                        *v /= magnitude;
17736                    }
17737                }
17738
17739                let values: Vec<Value> = vector.into_iter().map(Value::Float).collect();
17740                Ok(Value::Array(Rc::new(RefCell::new(values))))
17741            }
17742            _ => Err(RuntimeError::new(
17743                "text_hash_vector() requires string and dimensions",
17744            )),
17745        }
17746    });
17747
17748    // text_fingerprint - create a compact fingerprint of text
17749    define(interp, "text_fingerprint", Some(1), |_, args| {
17750        match &args[0] {
17751            Value::String(s) => {
17752                // Create 64-bit fingerprint using multiple hashes
17753                let lower = s.to_lowercase();
17754                let words: Vec<&str> = lower.split_whitespace().collect();
17755
17756                let mut fp: u64 = 0;
17757                for (i, word) in words.iter().enumerate() {
17758                    let h = compute_hash(word, i as u64);
17759                    fp ^= h.rotate_left((i % 64) as u32);
17760                }
17761
17762                Ok(Value::String(Rc::new(format!("{:016x}", fp))))
17763            }
17764            _ => Err(RuntimeError::new("text_fingerprint() requires string")),
17765        }
17766    });
17767
17768    // cosine_similarity - compute cosine similarity between two vectors
17769    define(interp, "cosine_similarity", Some(2), |_, args| {
17770        match (&args[0], &args[1]) {
17771            (Value::Array(a), Value::Array(b)) => {
17772                let a_ref = a.borrow();
17773                let b_ref = b.borrow();
17774
17775                if a_ref.len() != b_ref.len() {
17776                    return Err(RuntimeError::new("Vectors must have same length"));
17777                }
17778
17779                let mut dot = 0.0;
17780                let mut mag_a = 0.0;
17781                let mut mag_b = 0.0;
17782
17783                for (va, vb) in a_ref.iter().zip(b_ref.iter()) {
17784                    let fa = match va {
17785                        Value::Float(f) => *f,
17786                        Value::Int(i) => *i as f64,
17787                        _ => continue,
17788                    };
17789                    let fb = match vb {
17790                        Value::Float(f) => *f,
17791                        Value::Int(i) => *i as f64,
17792                        _ => continue,
17793                    };
17794                    dot += fa * fb;
17795                    mag_a += fa * fa;
17796                    mag_b += fb * fb;
17797                }
17798
17799                let denom = (mag_a.sqrt()) * (mag_b.sqrt());
17800                if denom == 0.0 {
17801                    Ok(Value::Float(0.0))
17802                } else {
17803                    Ok(Value::Float(dot / denom))
17804                }
17805            }
17806            _ => Err(RuntimeError::new("cosine_similarity() requires two arrays")),
17807        }
17808    });
17809
17810    // text_similarity_embedding - compare texts using hash embeddings
17811    define(interp, "text_similarity_embedding", Some(2), |_, args| {
17812        match (&args[0], &args[1]) {
17813            (Value::String(a), Value::String(b)) => {
17814                let dims = 128;
17815
17816                // Create vectors for both texts
17817                let vec_a = create_hash_vector(a, dims);
17818                let vec_b = create_hash_vector(b, dims);
17819
17820                // Compute cosine similarity
17821                let mut dot = 0.0;
17822                let mut mag_a = 0.0;
17823                let mut mag_b = 0.0;
17824
17825                for i in 0..dims {
17826                    dot += vec_a[i] * vec_b[i];
17827                    mag_a += vec_a[i] * vec_a[i];
17828                    mag_b += vec_b[i] * vec_b[i];
17829                }
17830
17831                let denom = (mag_a.sqrt()) * (mag_b.sqrt());
17832                if denom == 0.0 {
17833                    Ok(Value::Float(0.0))
17834                } else {
17835                    Ok(Value::Float(dot / denom))
17836                }
17837            }
17838            _ => Err(RuntimeError::new(
17839                "text_similarity_embedding() requires two strings",
17840            )),
17841        }
17842    });
17843
17844    // =========================================================================
17845    // READABILITY METRICS
17846    // =========================================================================
17847
17848    // flesch_reading_ease - Flesch Reading Ease score
17849    define(
17850        interp,
17851        "flesch_reading_ease",
17852        Some(1),
17853        |_, args| match &args[0] {
17854            Value::String(s) => {
17855                let (words, sentences, syllables) = count_text_stats(s);
17856                if words == 0 || sentences == 0 {
17857                    return Ok(Value::Float(0.0));
17858                }
17859                let score = 206.835
17860                    - 1.015 * (words as f64 / sentences as f64)
17861                    - 84.6 * (syllables as f64 / words as f64);
17862                Ok(Value::Float(score.max(0.0).min(100.0)))
17863            }
17864            _ => Err(RuntimeError::new("flesch_reading_ease() requires string")),
17865        },
17866    );
17867
17868    // flesch_kincaid_grade - Flesch-Kincaid Grade Level
17869    define(
17870        interp,
17871        "flesch_kincaid_grade",
17872        Some(1),
17873        |_, args| match &args[0] {
17874            Value::String(s) => {
17875                let (words, sentences, syllables) = count_text_stats(s);
17876                if words == 0 || sentences == 0 {
17877                    return Ok(Value::Float(0.0));
17878                }
17879                let grade = 0.39 * (words as f64 / sentences as f64)
17880                    + 11.8 * (syllables as f64 / words as f64)
17881                    - 15.59;
17882                Ok(Value::Float(grade.max(0.0)))
17883            }
17884            _ => Err(RuntimeError::new("flesch_kincaid_grade() requires string")),
17885        },
17886    );
17887
17888    // automated_readability_index - ARI score
17889    define(
17890        interp,
17891        "automated_readability_index",
17892        Some(1),
17893        |_, args| match &args[0] {
17894            Value::String(s) => {
17895                let chars: usize = s.chars().filter(|c| c.is_alphanumeric()).count();
17896                let words: usize = s.split_whitespace().count();
17897                let sentences: usize = s
17898                    .matches(|c| c == '.' || c == '!' || c == '?')
17899                    .count()
17900                    .max(1);
17901
17902                if words == 0 {
17903                    return Ok(Value::Float(0.0));
17904                }
17905
17906                let ari = 4.71 * (chars as f64 / words as f64)
17907                    + 0.5 * (words as f64 / sentences as f64)
17908                    - 21.43;
17909                Ok(Value::Float(ari.max(0.0)))
17910            }
17911            _ => Err(RuntimeError::new(
17912                "automated_readability_index() requires string",
17913            )),
17914        },
17915    );
17916
17917    // reading_time - estimated reading time in minutes
17918    define(interp, "reading_time", Some(1), |_, args| {
17919        match &args[0] {
17920            Value::String(s) => {
17921                let words = s.split_whitespace().count();
17922                let minutes = words as f64 / 200.0; // Average reading speed
17923                Ok(Value::Float(minutes))
17924            }
17925            _ => Err(RuntimeError::new("reading_time() requires string")),
17926        }
17927    });
17928
17929    // speaking_time - estimated speaking time in minutes
17930    define(interp, "speaking_time", Some(1), |_, args| {
17931        match &args[0] {
17932            Value::String(s) => {
17933                let words = s.split_whitespace().count();
17934                let minutes = words as f64 / 150.0; // Average speaking speed
17935                Ok(Value::Float(minutes))
17936            }
17937            _ => Err(RuntimeError::new("speaking_time() requires string")),
17938        }
17939    });
17940}
17941
17942// =============================================================================
17943// HELPER FUNCTIONS FOR TEXT INTELLIGENCE
17944// =============================================================================
17945
17946/// VADER-style sentiment computation
17947fn compute_vader_sentiment(s: &str) -> (f64, f64, f64, f64) {
17948    // Sentiment lexicon with intensity
17949    let positive_words: Vec<(&str, f64)> = vec![
17950        ("love", 3.0),
17951        ("loved", 3.0),
17952        ("loving", 3.0),
17953        ("excellent", 3.0),
17954        ("amazing", 3.0),
17955        ("fantastic", 3.0),
17956        ("wonderful", 3.0),
17957        ("great", 2.5),
17958        ("awesome", 2.5),
17959        ("brilliant", 2.5),
17960        ("superb", 2.5),
17961        ("good", 2.0),
17962        ("nice", 2.0),
17963        ("pleasant", 2.0),
17964        ("happy", 2.0),
17965        ("like", 1.5),
17966        ("enjoy", 1.5),
17967        ("fine", 1.5),
17968        ("okay", 1.0),
17969        ("best", 3.0),
17970        ("perfect", 3.0),
17971        ("beautiful", 2.5),
17972        ("delightful", 2.5),
17973        ("excited", 2.5),
17974        ("thrilled", 3.0),
17975        ("glad", 2.0),
17976        ("pleased", 2.0),
17977    ];
17978
17979    let negative_words: Vec<(&str, f64)> = vec![
17980        ("hate", 3.0),
17981        ("hated", 3.0),
17982        ("hating", 3.0),
17983        ("terrible", 3.0),
17984        ("horrible", 3.0),
17985        ("awful", 3.0),
17986        ("disgusting", 3.0),
17987        ("bad", 2.5),
17988        ("poor", 2.5),
17989        ("worst", 3.0),
17990        ("pathetic", 2.5),
17991        ("sad", 2.0),
17992        ("angry", 2.5),
17993        ("upset", 2.0),
17994        ("disappointed", 2.0),
17995        ("dislike", 1.5),
17996        ("annoying", 2.0),
17997        ("boring", 1.5),
17998        ("mediocre", 1.0),
17999        ("ugly", 2.5),
18000        ("stupid", 2.5),
18001        ("dumb", 2.0),
18002        ("useless", 2.5),
18003        ("painful", 2.5),
18004        ("miserable", 3.0),
18005        ("depressing", 2.5),
18006        ("frustrating", 2.0),
18007    ];
18008
18009    // Intensity modifiers
18010    let boosters = vec![
18011        "very",
18012        "really",
18013        "extremely",
18014        "absolutely",
18015        "incredibly",
18016        "totally",
18017        "so",
18018    ];
18019    let dampeners = vec![
18020        "somewhat", "slightly", "a bit", "kind of", "sort of", "barely",
18021    ];
18022
18023    let lower = s.to_lowercase();
18024    let words: Vec<&str> = lower.split_whitespace().collect();
18025
18026    let mut pos_score = 0.0;
18027    let mut neg_score = 0.0;
18028    let mut word_count = 0;
18029
18030    for (i, word) in words.iter().enumerate() {
18031        let mut modifier = 1.0;
18032
18033        // Check for boosters/dampeners before this word
18034        if i > 0 {
18035            if boosters.contains(&words[i - 1]) {
18036                modifier = 1.5;
18037            } else if dampeners.iter().any(|d| words[i - 1].contains(d)) {
18038                modifier = 0.5;
18039            }
18040        }
18041
18042        // Check for negation
18043        let negated = i > 0
18044            && [
18045                "not",
18046                "no",
18047                "never",
18048                "neither",
18049                "don't",
18050                "doesn't",
18051                "didn't",
18052                "won't",
18053                "wouldn't",
18054                "couldn't",
18055                "shouldn't",
18056            ]
18057            .contains(&words[i - 1]);
18058
18059        if let Some((_, score)) = positive_words.iter().find(|(w, _)| w == word) {
18060            if negated {
18061                neg_score += score * modifier;
18062            } else {
18063                pos_score += score * modifier;
18064            }
18065            word_count += 1;
18066        } else if let Some((_, score)) = negative_words.iter().find(|(w, _)| w == word) {
18067            if negated {
18068                pos_score += score * modifier * 0.5; // Negated negative is mildly positive
18069            } else {
18070                neg_score += score * modifier;
18071            }
18072            word_count += 1;
18073        }
18074    }
18075
18076    // Normalize scores
18077    let total = pos_score + neg_score;
18078    let (pos_norm, neg_norm) = if total > 0.0 {
18079        (pos_score / total, neg_score / total)
18080    } else {
18081        (0.0, 0.0)
18082    };
18083
18084    let neutral = 1.0 - pos_norm - neg_norm;
18085
18086    // Compound score: normalized to [-1, 1]
18087    let compound = if word_count > 0 {
18088        ((pos_score - neg_score) / (word_count as f64 * 3.0))
18089            .max(-1.0)
18090            .min(1.0)
18091    } else {
18092        0.0
18093    };
18094
18095    (pos_norm, neg_norm, neutral.max(0.0), compound)
18096}
18097
18098/// Detect specific emotions
18099fn compute_emotions(s: &str) -> HashMap<String, f64> {
18100    let emotion_words: Vec<(&str, &str)> = vec![
18101        // Joy
18102        ("happy", "joy"),
18103        ("joyful", "joy"),
18104        ("delighted", "joy"),
18105        ("cheerful", "joy"),
18106        ("excited", "joy"),
18107        ("thrilled", "joy"),
18108        ("ecstatic", "joy"),
18109        ("elated", "joy"),
18110        // Sadness
18111        ("sad", "sadness"),
18112        ("unhappy", "sadness"),
18113        ("depressed", "sadness"),
18114        ("miserable", "sadness"),
18115        ("gloomy", "sadness"),
18116        ("heartbroken", "sadness"),
18117        ("sorrowful", "sadness"),
18118        ("melancholy", "sadness"),
18119        // Anger
18120        ("angry", "anger"),
18121        ("furious", "anger"),
18122        ("enraged", "anger"),
18123        ("irritated", "anger"),
18124        ("annoyed", "anger"),
18125        ("outraged", "anger"),
18126        ("livid", "anger"),
18127        ("mad", "anger"),
18128        // Fear
18129        ("afraid", "fear"),
18130        ("scared", "fear"),
18131        ("terrified", "fear"),
18132        ("frightened", "fear"),
18133        ("anxious", "fear"),
18134        ("worried", "fear"),
18135        ("nervous", "fear"),
18136        ("panicked", "fear"),
18137        // Surprise
18138        ("surprised", "surprise"),
18139        ("amazed", "surprise"),
18140        ("astonished", "surprise"),
18141        ("shocked", "surprise"),
18142        ("stunned", "surprise"),
18143        ("startled", "surprise"),
18144        ("bewildered", "surprise"),
18145        // Disgust
18146        ("disgusted", "disgust"),
18147        ("revolted", "disgust"),
18148        ("repulsed", "disgust"),
18149        ("sickened", "disgust"),
18150        ("nauseated", "disgust"),
18151        ("appalled", "disgust"),
18152        // Trust
18153        ("trust", "trust"),
18154        ("confident", "trust"),
18155        ("secure", "trust"),
18156        ("reliable", "trust"),
18157        ("faithful", "trust"),
18158        ("loyal", "trust"),
18159        // Anticipation
18160        ("eager", "anticipation"),
18161        ("hopeful", "anticipation"),
18162        ("expectant", "anticipation"),
18163        ("looking forward", "anticipation"),
18164        ("excited", "anticipation"),
18165    ];
18166
18167    let lower = s.to_lowercase();
18168    let mut counts: HashMap<String, f64> = HashMap::new();
18169
18170    for (word, emotion) in emotion_words {
18171        if lower.contains(word) {
18172            *counts.entry(emotion.to_string()).or_insert(0.0) += 1.0;
18173        }
18174    }
18175
18176    // Normalize
18177    let total: f64 = counts.values().sum();
18178    if total > 0.0 {
18179        for v in counts.values_mut() {
18180            *v /= total;
18181        }
18182    }
18183
18184    counts
18185}
18186
18187/// Compute text intensity
18188fn compute_intensity(s: &str) -> f64 {
18189    let intensifiers = vec![
18190        ("very", 1.5),
18191        ("really", 1.5),
18192        ("extremely", 2.0),
18193        ("incredibly", 2.0),
18194        ("absolutely", 2.0),
18195        ("totally", 1.5),
18196        ("completely", 1.5),
18197        ("utterly", 2.0),
18198        ("so", 1.3),
18199        ("such", 1.3),
18200        ("quite", 1.2),
18201        ("rather", 1.1),
18202    ];
18203
18204    let exclamation_boost = 0.5;
18205    let caps_boost = 0.3;
18206
18207    let lower = s.to_lowercase();
18208    let mut score = 1.0;
18209
18210    for (word, boost) in intensifiers {
18211        if lower.contains(word) {
18212            score *= boost;
18213        }
18214    }
18215
18216    // Check for exclamation marks
18217    let exclamations = s.matches('!').count();
18218    score += exclamations as f64 * exclamation_boost;
18219
18220    // Check for ALL CAPS words
18221    let caps_words = s
18222        .split_whitespace()
18223        .filter(|w| w.len() > 2 && w.chars().all(|c| c.is_uppercase()))
18224        .count();
18225    score += caps_words as f64 * caps_boost;
18226
18227    score.min(5.0)
18228}
18229
18230/// Detect sarcasm markers
18231fn compute_sarcasm_score(s: &str) -> (f64, f64, Vec<String>) {
18232    let mut markers = Vec::new();
18233    let mut score: f64 = 0.0;
18234
18235    let lower = s.to_lowercase();
18236
18237    // Explicit sarcasm markers
18238    let explicit = vec![
18239        "/s",
18240        "not!",
18241        "yeah right",
18242        "sure thing",
18243        "oh really",
18244        "oh great",
18245        "wow, just wow",
18246        "thanks a lot",
18247        "how wonderful",
18248        "isn't that special",
18249        "clearly",
18250        "obviously",
18251        "shocking",
18252        "no way",
18253        "what a surprise",
18254    ];
18255
18256    for marker in &explicit {
18257        if lower.contains(marker) {
18258            markers.push(format!("explicit: {}", marker));
18259            score += 0.4;
18260        }
18261    }
18262
18263    // Hyperbolic expressions
18264    let hyperbolic = vec![
18265        "best thing ever",
18266        "worst thing ever",
18267        "literally dying",
18268        "absolutely perfect",
18269        "world's greatest",
18270        "totally awesome",
18271        "so much fun",
18272        "couldn't be happier",
18273    ];
18274
18275    for h in &hyperbolic {
18276        if lower.contains(h) {
18277            markers.push(format!("hyperbole: {}", h));
18278            score += 0.3;
18279        }
18280    }
18281
18282    // Positive-negative contradiction patterns
18283    let has_positive = ["great", "wonderful", "amazing", "love", "best", "awesome"]
18284        .iter()
18285        .any(|w| lower.contains(w));
18286    let has_negative_context = ["but", "however", "although", "except", "unfortunately"]
18287        .iter()
18288        .any(|w| lower.contains(w));
18289
18290    if has_positive && has_negative_context {
18291        markers.push("positive-negative contrast".to_string());
18292        score += 0.25;
18293    }
18294
18295    // Quotation marks around positive words (air quotes)
18296    let quote_pattern = Regex::new(r#"["'](\w+)["']"#).unwrap();
18297    for cap in quote_pattern.captures_iter(s) {
18298        if let Some(m) = cap.get(1) {
18299            let word = m.as_str().to_lowercase();
18300            if [
18301                "great",
18302                "wonderful",
18303                "helpful",
18304                "useful",
18305                "smart",
18306                "genius",
18307                "brilliant",
18308            ]
18309            .contains(&word.as_str())
18310            {
18311                markers.push(format!("air quotes: \"{}\"", word));
18312                score += 0.35;
18313            }
18314        }
18315    }
18316
18317    // Excessive punctuation
18318    if s.contains("...") || s.contains("!!!") || s.contains("???") {
18319        markers.push("excessive punctuation".to_string());
18320        score += 0.15;
18321    }
18322
18323    // Calculate confidence based on number of markers
18324    let confidence = if markers.is_empty() {
18325        0.0
18326    } else {
18327        (markers.len() as f64 * 0.25).min(1.0)
18328    };
18329
18330    (score.min(1.0), confidence, markers)
18331}
18332
18333/// Detect irony patterns
18334fn compute_irony_score(s: &str) -> f64 {
18335    let mut score: f64 = 0.0;
18336    let lower = s.to_lowercase();
18337
18338    // Situational irony markers
18339    let irony_phrases = vec![
18340        "of course",
18341        "as expected",
18342        "naturally",
18343        "predictably",
18344        "who would have thought",
18345        "surprise surprise",
18346        "go figure",
18347        "typical",
18348        "as usual",
18349        "yet again",
18350        "once again",
18351    ];
18352
18353    for phrase in irony_phrases {
18354        if lower.contains(phrase) {
18355            score += 0.2;
18356        }
18357    }
18358
18359    // Contrast indicators
18360    if lower.contains("but") || lower.contains("yet") || lower.contains("however") {
18361        score += 0.1;
18362    }
18363
18364    // Rhetorical questions
18365    if s.contains('?')
18366        && (lower.starts_with("isn't")
18367            || lower.starts_with("aren't")
18368            || lower.starts_with("doesn't")
18369            || lower.starts_with("don't")
18370            || lower.contains("right?")
18371            || lower.contains("isn't it"))
18372    {
18373        score += 0.25;
18374    }
18375
18376    score.min(1.0)
18377}
18378
18379/// Create hash-based vector for text
18380fn create_hash_vector(s: &str, dims: usize) -> Vec<f64> {
18381    let mut vector = vec![0.0f64; dims];
18382
18383    for word in s.to_lowercase().split_whitespace() {
18384        let hash = compute_hash(word, 0);
18385        let idx = (hash as usize) % dims;
18386        vector[idx] += 1.0;
18387    }
18388
18389    // Normalize
18390    let magnitude: f64 = vector.iter().map(|x| x * x).sum::<f64>().sqrt();
18391    if magnitude > 0.0 {
18392        for v in vector.iter_mut() {
18393            *v /= magnitude;
18394        }
18395    }
18396
18397    vector
18398}
18399
18400/// Count text statistics for readability
18401fn count_text_stats(s: &str) -> (usize, usize, usize) {
18402    let words: Vec<&str> = s.split_whitespace().collect();
18403    let word_count = words.len();
18404    let sentence_count = s
18405        .matches(|c| c == '.' || c == '!' || c == '?')
18406        .count()
18407        .max(1);
18408
18409    let mut syllable_count = 0;
18410    for word in &words {
18411        syllable_count += count_syllables(word);
18412    }
18413
18414    (word_count, sentence_count, syllable_count)
18415}
18416
18417/// Count syllables in a word (English approximation)
18418fn count_syllables(word: &str) -> usize {
18419    let word = word.to_lowercase();
18420    let vowels = ['a', 'e', 'i', 'o', 'u', 'y'];
18421    let mut count = 0;
18422    let mut prev_was_vowel = false;
18423
18424    for c in word.chars() {
18425        let is_vowel = vowels.contains(&c);
18426        if is_vowel && !prev_was_vowel {
18427            count += 1;
18428        }
18429        prev_was_vowel = is_vowel;
18430    }
18431
18432    // Adjust for silent e
18433    if word.ends_with('e') && count > 1 {
18434        count -= 1;
18435    }
18436
18437    count.max(1)
18438}
18439
18440/// Compute American Soundex encoding
18441fn compute_soundex(s: &str) -> String {
18442    if s.is_empty() {
18443        return "0000".to_string();
18444    }
18445
18446    let s = s.to_uppercase();
18447    let chars: Vec<char> = s.chars().filter(|c| c.is_ascii_alphabetic()).collect();
18448
18449    if chars.is_empty() {
18450        return "0000".to_string();
18451    }
18452
18453    let first = chars[0];
18454    let mut code = String::new();
18455    code.push(first);
18456
18457    let get_code = |c: char| -> char {
18458        match c {
18459            'B' | 'F' | 'P' | 'V' => '1',
18460            'C' | 'G' | 'J' | 'K' | 'Q' | 'S' | 'X' | 'Z' => '2',
18461            'D' | 'T' => '3',
18462            'L' => '4',
18463            'M' | 'N' => '5',
18464            'R' => '6',
18465            _ => '0',
18466        }
18467    };
18468
18469    let mut prev_code = get_code(first);
18470
18471    for &c in chars.iter().skip(1) {
18472        let curr_code = get_code(c);
18473        if curr_code != '0' && curr_code != prev_code {
18474            code.push(curr_code);
18475            if code.len() == 4 {
18476                break;
18477            }
18478        }
18479        prev_code = curr_code;
18480    }
18481
18482    while code.len() < 4 {
18483        code.push('0');
18484    }
18485
18486    code
18487}
18488
18489/// Compute Metaphone encoding
18490fn compute_metaphone(s: &str) -> String {
18491    let s = s.to_uppercase();
18492    let chars: Vec<char> = s.chars().filter(|c| c.is_ascii_alphabetic()).collect();
18493
18494    if chars.is_empty() {
18495        return String::new();
18496    }
18497
18498    let mut result = String::new();
18499    let mut i = 0;
18500
18501    // Skip initial KN, GN, PN, AE, WR
18502    if chars.len() >= 2 {
18503        let prefix: String = chars[0..2].iter().collect();
18504        if ["KN", "GN", "PN", "AE", "WR"].contains(&prefix.as_str()) {
18505            i = 1;
18506        }
18507    }
18508
18509    while i < chars.len() && result.len() < 6 {
18510        let c = chars[i];
18511        let prev = if i > 0 { Some(chars[i - 1]) } else { None };
18512        let next = chars.get(i + 1).copied();
18513
18514        let code = match c {
18515            'A' | 'E' | 'I' | 'O' | 'U' => {
18516                if i == 0 {
18517                    Some(c)
18518                } else {
18519                    None
18520                }
18521            }
18522            'B' => {
18523                if prev != Some('M') || i == chars.len() - 1 {
18524                    Some('B')
18525                } else {
18526                    None
18527                }
18528            }
18529            'C' => {
18530                if next == Some('H') {
18531                    Some('X')
18532                } else if matches!(next, Some('I') | Some('E') | Some('Y')) {
18533                    Some('S')
18534                } else {
18535                    Some('K')
18536                }
18537            }
18538            'D' => {
18539                if next == Some('G')
18540                    && matches!(chars.get(i + 2), Some('E') | Some('I') | Some('Y'))
18541                {
18542                    Some('J')
18543                } else {
18544                    Some('T')
18545                }
18546            }
18547            'F' => Some('F'),
18548            'G' => {
18549                if next == Some('H')
18550                    && !matches!(
18551                        chars.get(i + 2),
18552                        Some('A') | Some('E') | Some('I') | Some('O') | Some('U')
18553                    )
18554                {
18555                    None
18556                } else if matches!(next, Some('N') | Some('E') | Some('I') | Some('Y')) {
18557                    Some('J')
18558                } else {
18559                    Some('K')
18560                }
18561            }
18562            'H' => {
18563                if matches!(
18564                    prev,
18565                    Some('A') | Some('E') | Some('I') | Some('O') | Some('U')
18566                ) {
18567                    None
18568                } else if matches!(
18569                    next,
18570                    Some('A') | Some('E') | Some('I') | Some('O') | Some('U')
18571                ) {
18572                    Some('H')
18573                } else {
18574                    None
18575                }
18576            }
18577            'J' => Some('J'),
18578            'K' => {
18579                if prev != Some('C') {
18580                    Some('K')
18581                } else {
18582                    None
18583                }
18584            }
18585            'L' => Some('L'),
18586            'M' => Some('M'),
18587            'N' => Some('N'),
18588            'P' => {
18589                if next == Some('H') {
18590                    Some('F')
18591                } else {
18592                    Some('P')
18593                }
18594            }
18595            'Q' => Some('K'),
18596            'R' => Some('R'),
18597            'S' => {
18598                if next == Some('H') {
18599                    Some('X')
18600                } else {
18601                    Some('S')
18602                }
18603            }
18604            'T' => {
18605                if next == Some('H') {
18606                    Some('0') // TH sound
18607                } else if next == Some('I') && matches!(chars.get(i + 2), Some('O') | Some('A')) {
18608                    Some('X')
18609                } else {
18610                    Some('T')
18611                }
18612            }
18613            'V' => Some('F'),
18614            'W' | 'Y' => {
18615                if matches!(
18616                    next,
18617                    Some('A') | Some('E') | Some('I') | Some('O') | Some('U')
18618                ) {
18619                    Some(c)
18620                } else {
18621                    None
18622                }
18623            }
18624            'X' => {
18625                result.push('K');
18626                Some('S')
18627            }
18628            'Z' => Some('S'),
18629            _ => None,
18630        };
18631
18632        if let Some(ch) = code {
18633            result.push(ch);
18634        }
18635
18636        // Skip double letters
18637        if next == Some(c) {
18638            i += 1;
18639        }
18640        i += 1;
18641    }
18642
18643    result
18644}
18645
18646/// Compute Cologne phonetic encoding (for German)
18647fn compute_cologne(s: &str) -> String {
18648    let s = s.to_uppercase();
18649    let chars: Vec<char> = s.chars().filter(|c| c.is_ascii_alphabetic()).collect();
18650
18651    if chars.is_empty() {
18652        return String::new();
18653    }
18654
18655    let mut result = String::new();
18656
18657    for (i, &c) in chars.iter().enumerate() {
18658        let prev = if i > 0 { Some(chars[i - 1]) } else { None };
18659        let next = chars.get(i + 1).copied();
18660
18661        let code = match c {
18662            'A' | 'E' | 'I' | 'O' | 'U' | 'J' | 'Y' => '0',
18663            'H' => continue,
18664            'B' | 'P' => '1',
18665            'D' | 'T' => {
18666                if matches!(next, Some('C') | Some('S') | Some('Z')) {
18667                    '8'
18668                } else {
18669                    '2'
18670                }
18671            }
18672            'F' | 'V' | 'W' => '3',
18673            'G' | 'K' | 'Q' => '4',
18674            'C' => {
18675                if i == 0 {
18676                    if matches!(
18677                        next,
18678                        Some('A')
18679                            | Some('H')
18680                            | Some('K')
18681                            | Some('L')
18682                            | Some('O')
18683                            | Some('Q')
18684                            | Some('R')
18685                            | Some('U')
18686                            | Some('X')
18687                    ) {
18688                        '4'
18689                    } else {
18690                        '8'
18691                    }
18692                } else if matches!(prev, Some('S') | Some('Z')) {
18693                    '8'
18694                } else if matches!(
18695                    next,
18696                    Some('A')
18697                        | Some('H')
18698                        | Some('K')
18699                        | Some('O')
18700                        | Some('Q')
18701                        | Some('U')
18702                        | Some('X')
18703                ) {
18704                    '4'
18705                } else {
18706                    '8'
18707                }
18708            }
18709            'X' => {
18710                if matches!(prev, Some('C') | Some('K') | Some('Q')) {
18711                    '8'
18712                } else {
18713                    result.push('4');
18714                    '8'
18715                }
18716            }
18717            'L' => '5',
18718            'M' | 'N' => '6',
18719            'R' => '7',
18720            'S' | 'Z' => '8',
18721            _ => continue,
18722        };
18723
18724        result.push(code);
18725    }
18726
18727    // Remove consecutive duplicates
18728    let mut deduped = String::new();
18729    let mut prev = None;
18730    for c in result.chars() {
18731        if prev != Some(c) {
18732            deduped.push(c);
18733        }
18734        prev = Some(c);
18735    }
18736
18737    // Remove leading zeros (except if all zeros)
18738    let trimmed: String = deduped.trim_start_matches('0').to_string();
18739    if trimmed.is_empty() {
18740        "0".to_string()
18741    } else {
18742        trimmed
18743    }
18744}
18745
18746/// Get stopwords for a language
18747fn get_stopwords(lang: &str) -> Vec<&'static str> {
18748    match lang {
18749        "en" | "english" => vec![
18750            "a", "an", "the", "and", "or", "but", "in", "on", "at", "to", "for", "of", "with",
18751            "by", "from", "as", "is", "was", "are", "were", "been", "be", "have", "has", "had",
18752            "do", "does", "did", "will", "would", "could", "should", "may", "might", "must",
18753            "shall", "can", "need", "it", "its", "this", "that", "these", "those", "i", "you",
18754            "he", "she", "we", "they", "me", "him", "her", "us", "them", "my", "your", "his",
18755            "her", "our", "their", "what", "which", "who", "whom", "whose", "when", "where", "why",
18756            "how", "all", "each", "every", "both", "few", "more", "most", "other", "some", "such",
18757            "no", "nor", "not", "only", "own", "same", "so", "than", "too", "very", "just", "also",
18758            "now",
18759        ],
18760        "de" | "german" => vec![
18761            "der", "die", "das", "den", "dem", "des", "ein", "eine", "einer", "einem", "einen",
18762            "und", "oder", "aber", "in", "auf", "an", "zu", "für", "von", "mit", "bei", "als",
18763            "ist", "war", "sind", "waren", "sein", "haben", "hat", "hatte", "werden", "wird",
18764            "wurde", "kann", "können", "muss", "müssen", "soll", "sollen", "will", "wollen", "es",
18765            "sie", "er", "wir", "ihr", "ich", "du", "man", "sich", "nicht", "auch", "nur", "noch",
18766            "schon", "mehr", "sehr", "so",
18767        ],
18768        "fr" | "french" => vec![
18769            "le", "la", "les", "un", "une", "des", "et", "ou", "mais", "dans", "sur", "à", "de",
18770            "pour", "par", "avec", "ce", "cette", "ces", "est", "sont", "était", "être", "avoir",
18771            "a", "ont", "avait", "je", "tu", "il", "elle", "nous", "vous", "ils", "elles", "on",
18772            "ne", "pas", "plus", "moins", "très", "aussi", "que", "qui",
18773        ],
18774        "es" | "spanish" => vec![
18775            "el", "la", "los", "las", "un", "una", "unos", "unas", "y", "o", "pero", "en", "de",
18776            "a", "para", "por", "con", "es", "son", "era", "ser", "estar", "tiene", "tienen", "yo",
18777            "tú", "él", "ella", "nosotros", "ustedes", "ellos", "ellas", "no", "sí", "muy", "más",
18778            "menos", "también", "que", "quien", "cual", "como", "cuando",
18779        ],
18780        "it" | "italian" => vec![
18781            "il", "lo", "la", "i", "gli", "le", "un", "uno", "una", "e", "o", "ma", "in", "di",
18782            "a", "da", "per", "con", "su", "tra", "fra", "è", "sono", "era", "erano", "essere",
18783            "avere", "ha", "hanno", "io", "tu", "lui", "lei", "noi", "voi", "loro", "mi", "ti",
18784            "ci", "non", "più", "molto", "anche", "come", "che", "chi", "quale", "questo",
18785            "quello", "quando", "dove", "perché", "se", "però",
18786        ],
18787        "pt" | "portuguese" => vec![
18788            "o", "a", "os", "as", "um", "uma", "uns", "umas", "e", "ou", "mas", "em", "de", "para",
18789            "por", "com", "sem", "sob", "sobre", "é", "são", "era", "eram", "ser", "estar", "ter",
18790            "tem", "têm", "eu", "tu", "ele", "ela", "nós", "vós", "eles", "elas", "me", "te",
18791            "não", "mais", "muito", "também", "como", "que", "quem", "qual", "este", "esse",
18792            "aquele", "quando", "onde", "porque", "se", "já",
18793        ],
18794        "nl" | "dutch" => vec![
18795            "de", "het", "een", "en", "of", "maar", "in", "op", "aan", "van", "voor", "met", "bij",
18796            "naar", "om", "te", "tot", "uit", "over", "is", "zijn", "was", "waren", "worden",
18797            "wordt", "werd", "hebben", "ik", "je", "jij", "hij", "zij", "wij", "jullie", "ze",
18798            "mij", "jou", "niet", "geen", "meer", "ook", "als", "dat", "die", "wat", "wie", "dit",
18799            "deze", "wanneer", "waar", "waarom", "hoe", "dan", "nog",
18800        ],
18801        "ru" | "russian" => vec![
18802            "и",
18803            "в",
18804            "на",
18805            "с",
18806            "к",
18807            "по",
18808            "за",
18809            "из",
18810            "у",
18811            "о",
18812            "от",
18813            "до",
18814            "для",
18815            "при",
18816            "без",
18817            "под",
18818            "над",
18819            "между",
18820            "через",
18821            "после",
18822            "это",
18823            "то",
18824            "что",
18825            "как",
18826            "так",
18827            "но",
18828            "а",
18829            "или",
18830            "если",
18831            "же",
18832            "я",
18833            "ты",
18834            "он",
18835            "она",
18836            "мы",
18837            "вы",
18838            "они",
18839            "его",
18840            "её",
18841            "их",
18842            "не",
18843            "ни",
18844            "да",
18845            "нет",
18846            "был",
18847            "была",
18848            "были",
18849            "быть",
18850            "есть",
18851            "все",
18852            "всё",
18853            "весь",
18854            "этот",
18855            "тот",
18856            "который",
18857            "когда",
18858            "где",
18859        ],
18860        "ar" | "arabic" => vec![
18861            "في",
18862            "من",
18863            "إلى",
18864            "على",
18865            "عن",
18866            "مع",
18867            "هذا",
18868            "هذه",
18869            "ذلك",
18870            "تلك",
18871            "التي",
18872            "الذي",
18873            "اللذان",
18874            "اللتان",
18875            "الذين",
18876            "اللاتي",
18877            "اللواتي",
18878            "هو",
18879            "هي",
18880            "هم",
18881            "هن",
18882            "أنا",
18883            "أنت",
18884            "نحن",
18885            "أنتم",
18886            "أنتن",
18887            "كان",
18888            "كانت",
18889            "كانوا",
18890            "يكون",
18891            "تكون",
18892            "ليس",
18893            "ليست",
18894            "ليسوا",
18895            "و",
18896            "أو",
18897            "ثم",
18898            "لكن",
18899            "بل",
18900            "إن",
18901            "أن",
18902            "لأن",
18903            "كي",
18904            "حتى",
18905            "ما",
18906            "لا",
18907            "قد",
18908            "كل",
18909            "بعض",
18910            "غير",
18911            "أي",
18912            "كيف",
18913            "متى",
18914            "أين",
18915        ],
18916        "zh" | "chinese" => vec![
18917            "的", "了", "是", "在", "有", "和", "与", "或", "但", "而", "我", "你", "他", "她",
18918            "它", "我们", "你们", "他们", "她们", "这", "那", "这个", "那个", "这些", "那些",
18919            "什么", "哪", "哪个", "不", "没", "没有", "很", "也", "都", "就", "才", "只", "还",
18920            "把", "被", "给", "从", "到", "为", "以", "因为", "所以", "如果", "会", "能", "可以",
18921            "要", "想", "应该", "必须", "可能", "一", "个",
18922        ],
18923        "ja" | "japanese" => vec![
18924            "の",
18925            "に",
18926            "は",
18927            "を",
18928            "た",
18929            "が",
18930            "で",
18931            "て",
18932            "と",
18933            "し",
18934            "れ",
18935            "さ",
18936            "ある",
18937            "いる",
18938            "も",
18939            "する",
18940            "から",
18941            "な",
18942            "こと",
18943            "として",
18944            "い",
18945            "や",
18946            "など",
18947            "なっ",
18948            "ない",
18949            "この",
18950            "ため",
18951            "その",
18952            "あっ",
18953            "よう",
18954            "また",
18955            "もの",
18956            "という",
18957            "あり",
18958            "まで",
18959            "られ",
18960            "なる",
18961            "へ",
18962            "か",
18963            "だ",
18964            "これ",
18965            "によって",
18966            "により",
18967            "おり",
18968            "より",
18969            "による",
18970            "ず",
18971            "なり",
18972            "られる",
18973            "において",
18974        ],
18975        "ko" | "korean" => vec![
18976            "이",
18977            "그",
18978            "저",
18979            "것",
18980            "수",
18981            "등",
18982            "들",
18983            "및",
18984            "에",
18985            "의",
18986            "가",
18987            "을",
18988            "를",
18989            "은",
18990            "는",
18991            "로",
18992            "으로",
18993            "와",
18994            "과",
18995            "도",
18996            "에서",
18997            "까지",
18998            "부터",
18999            "만",
19000            "뿐",
19001            "처럼",
19002            "같이",
19003            "보다",
19004            "하다",
19005            "있다",
19006            "되다",
19007            "없다",
19008            "않다",
19009            "이다",
19010            "아니다",
19011            "나",
19012            "너",
19013            "우리",
19014            "그들",
19015            "이것",
19016            "그것",
19017            "저것",
19018            "무엇",
19019            "어디",
19020            "언제",
19021            "왜",
19022            "어떻게",
19023            "누구",
19024            "어느",
19025            "모든",
19026            "각",
19027        ],
19028        "hi" | "hindi" => vec![
19029            "का",
19030            "के",
19031            "की",
19032            "में",
19033            "है",
19034            "हैं",
19035            "को",
19036            "से",
19037            "पर",
19038            "था",
19039            "थे",
19040            "थी",
19041            "और",
19042            "या",
19043            "लेकिन",
19044            "अगर",
19045            "तो",
19046            "भी",
19047            "ही",
19048            "यह",
19049            "वह",
19050            "इस",
19051            "उस",
19052            "ये",
19053            "वे",
19054            "जो",
19055            "कि",
19056            "क्या",
19057            "कैसे",
19058            "मैं",
19059            "तुम",
19060            "आप",
19061            "हम",
19062            "वे",
19063            "उन्हें",
19064            "उनके",
19065            "अपने",
19066            "नहीं",
19067            "न",
19068            "कुछ",
19069            "कोई",
19070            "सब",
19071            "बहुत",
19072            "कम",
19073            "ज्यादा",
19074            "होना",
19075            "करना",
19076            "जाना",
19077            "आना",
19078            "देना",
19079            "लेना",
19080            "रहना",
19081            "सकना",
19082        ],
19083        "tr" | "turkish" => vec![
19084            "bir",
19085            "ve",
19086            "bu",
19087            "da",
19088            "de",
19089            "için",
19090            "ile",
19091            "mi",
19092            "ne",
19093            "o",
19094            "var",
19095            "ben",
19096            "sen",
19097            "biz",
19098            "siz",
19099            "onlar",
19100            "ki",
19101            "ama",
19102            "çok",
19103            "daha",
19104            "gibi",
19105            "kadar",
19106            "sonra",
19107            "şey",
19108            "kendi",
19109            "bütün",
19110            "her",
19111            "bazı",
19112            "olan",
19113            "olarak",
19114            "değil",
19115            "ya",
19116            "hem",
19117            "veya",
19118            "ancak",
19119            "ise",
19120            "göre",
19121            "rağmen",
19122            "dolayı",
19123            "üzere",
19124            "karşı",
19125            "arasında",
19126            "olan",
19127            "oldu",
19128            "olur",
19129            "olmak",
19130            "etmek",
19131            "yapmak",
19132            "demek",
19133        ],
19134        "pl" | "polish" => vec![
19135            "i",
19136            "w",
19137            "z",
19138            "na",
19139            "do",
19140            "o",
19141            "że",
19142            "to",
19143            "nie",
19144            "się",
19145            "jest",
19146            "tak",
19147            "jak",
19148            "ale",
19149            "po",
19150            "co",
19151            "czy",
19152            "lub",
19153            "oraz",
19154            "ja",
19155            "ty",
19156            "on",
19157            "ona",
19158            "my",
19159            "wy",
19160            "oni",
19161            "one",
19162            "pan",
19163            "pani",
19164            "ten",
19165            "ta",
19166            "te",
19167            "tego",
19168            "tej",
19169            "tym",
19170            "tych",
19171            "który",
19172            "która",
19173            "być",
19174            "mieć",
19175            "móc",
19176            "musieć",
19177            "chcieć",
19178            "wiedzieć",
19179            "mówić",
19180            "bardzo",
19181            "tylko",
19182            "już",
19183            "jeszcze",
19184            "też",
19185            "więc",
19186            "jednak",
19187        ],
19188        "sv" | "swedish" => vec![
19189            "och", "i", "att", "det", "som", "en", "på", "är", "av", "för", "med", "till", "den",
19190            "har", "de", "inte", "om", "ett", "men", "jag", "du", "han", "hon", "vi", "ni", "de",
19191            "dem", "sig", "sin", "var", "från", "eller", "när", "kan", "ska", "så", "än", "nu",
19192            "också", "bara", "mycket", "mer", "andra", "detta", "sedan", "hade", "varit", "skulle",
19193            "vara", "bli", "blev", "blir", "göra",
19194        ],
19195        _ => vec![
19196            "a", "an", "the", "and", "or", "but", "in", "on", "at", "to", "for",
19197        ],
19198    }
19199}
19200
19201/// Simple hash function for MinHash
19202fn compute_hash(s: &str, seed: u64) -> u64 {
19203    let mut hash: u64 = seed.wrapping_mul(0x517cc1b727220a95);
19204    for b in s.bytes() {
19205        hash = hash.wrapping_mul(31).wrapping_add(b as u64);
19206    }
19207    hash
19208}
19209
19210// ============================================================================
19211// EMOTIONAL HOLOGRAM: Multi-dimensional affective projection with cultural awareness
19212// ============================================================================
19213//
19214// The Emotional Hologram is a unique Sigil concept that projects affect onto a
19215// normalized coordinate space, enabling:
19216// - Emotional distance calculations
19217// - Cross-cultural emotion mappings
19218// - Emotional fingerprinting and cryptographic signing
19219// - Dissonance detection (e.g., positive + sarcastic)
19220//
19221// Dimensions:
19222//   Valence     (-1 to +1): Negative to Positive sentiment
19223//   Arousal     (0 to 1):   Low to High intensity
19224//   Dominance   (0 to 1):   Submissive to Dominant (formality)
19225//   Authenticity(-1 to +1): Sincere to Ironic
19226//   Certainty   (0 to 1):   Low to High confidence
19227//   Emotion     (0-6):      Discrete emotion index (or -1 for none)
19228
19229fn register_hologram(interp: &mut Interpreter) {
19230    use crate::interpreter::{
19231        RuntimeAffect, RuntimeConfidence, RuntimeEmotion, RuntimeFormality, RuntimeIntensity,
19232        RuntimeSentiment,
19233    };
19234
19235    // emotional_hologram - project affect onto normalized coordinate space
19236    // Returns a map: { valence, arousal, dominance, authenticity, certainty, emotion_index }
19237    define(interp, "emotional_hologram", Some(1), |_, args| {
19238        let affect = match &args[0] {
19239            Value::Affective { affect, .. } => affect.clone(),
19240            _ => RuntimeAffect {
19241                sentiment: None,
19242                sarcasm: false,
19243                intensity: None,
19244                formality: None,
19245                emotion: None,
19246                confidence: None,
19247            },
19248        };
19249
19250        let mut hologram = std::collections::HashMap::new();
19251
19252        // Valence: sentiment mapped to -1, 0, +1
19253        let valence = match affect.sentiment {
19254            Some(RuntimeSentiment::Positive) => 1.0,
19255            Some(RuntimeSentiment::Negative) => -1.0,
19256            Some(RuntimeSentiment::Neutral) | None => 0.0,
19257        };
19258        hologram.insert("valence".to_string(), Value::Float(valence));
19259
19260        // Arousal: intensity mapped to 0, 0.33, 0.66, 1.0
19261        let arousal = match affect.intensity {
19262            Some(RuntimeIntensity::Down) => 0.25,
19263            None => 0.5,
19264            Some(RuntimeIntensity::Up) => 0.75,
19265            Some(RuntimeIntensity::Max) => 1.0,
19266        };
19267        hologram.insert("arousal".to_string(), Value::Float(arousal));
19268
19269        // Dominance: formality mapped to 0 (informal/submissive) to 1 (formal/dominant)
19270        let dominance = match affect.formality {
19271            Some(RuntimeFormality::Informal) => 0.25,
19272            None => 0.5,
19273            Some(RuntimeFormality::Formal) => 0.85,
19274        };
19275        hologram.insert("dominance".to_string(), Value::Float(dominance));
19276
19277        // Authenticity: -1 (ironic/sarcastic) to +1 (sincere)
19278        let authenticity = if affect.sarcasm { -0.9 } else { 0.9 };
19279        hologram.insert("authenticity".to_string(), Value::Float(authenticity));
19280
19281        // Certainty: confidence mapped to 0, 0.5, 1.0
19282        let certainty = match affect.confidence {
19283            Some(RuntimeConfidence::Low) => 0.2,
19284            None | Some(RuntimeConfidence::Medium) => 0.5,
19285            Some(RuntimeConfidence::High) => 0.9,
19286        };
19287        hologram.insert("certainty".to_string(), Value::Float(certainty));
19288
19289        // Emotion index: 0=joy, 1=sadness, 2=anger, 3=fear, 4=surprise, 5=love, -1=none
19290        let emotion_index = match affect.emotion {
19291            Some(RuntimeEmotion::Joy) => 0,
19292            Some(RuntimeEmotion::Sadness) => 1,
19293            Some(RuntimeEmotion::Anger) => 2,
19294            Some(RuntimeEmotion::Fear) => 3,
19295            Some(RuntimeEmotion::Surprise) => 4,
19296            Some(RuntimeEmotion::Love) => 5,
19297            None => -1,
19298        };
19299        hologram.insert("emotion_index".to_string(), Value::Int(emotion_index));
19300
19301        // Emotion name
19302        let emotion_name = match affect.emotion {
19303            Some(RuntimeEmotion::Joy) => "joy",
19304            Some(RuntimeEmotion::Sadness) => "sadness",
19305            Some(RuntimeEmotion::Anger) => "anger",
19306            Some(RuntimeEmotion::Fear) => "fear",
19307            Some(RuntimeEmotion::Surprise) => "surprise",
19308            Some(RuntimeEmotion::Love) => "love",
19309            None => "none",
19310        };
19311        hologram.insert(
19312            "emotion".to_string(),
19313            Value::String(Rc::new(emotion_name.to_string())),
19314        );
19315
19316        Ok(Value::Map(Rc::new(RefCell::new(hologram))))
19317    });
19318
19319    // emotional_distance - Euclidean distance between two emotional holograms
19320    define(interp, "emotional_distance", Some(2), |interp, args| {
19321        // Get holograms for both values
19322        let h1 = get_hologram_values(&args[0], interp)?;
19323        let h2 = get_hologram_values(&args[1], interp)?;
19324
19325        // Calculate Euclidean distance across dimensions
19326        let dist = ((h1.0 - h2.0).powi(2) +    // valence
19327                    (h1.1 - h2.1).powi(2) +    // arousal
19328                    (h1.2 - h2.2).powi(2) +    // dominance
19329                    (h1.3 - h2.3).powi(2) +    // authenticity
19330                    (h1.4 - h2.4).powi(2)) // certainty
19331        .sqrt();
19332
19333        Ok(Value::Float(dist))
19334    });
19335
19336    // emotional_similarity - cosine similarity between emotional states (0 to 1)
19337    define(interp, "emotional_similarity", Some(2), |interp, args| {
19338        let h1 = get_hologram_values(&args[0], interp)?;
19339        let h2 = get_hologram_values(&args[1], interp)?;
19340
19341        let dot = h1.0 * h2.0 + h1.1 * h2.1 + h1.2 * h2.2 + h1.3 * h2.3 + h1.4 * h2.4;
19342        let mag1 =
19343            (h1.0.powi(2) + h1.1.powi(2) + h1.2.powi(2) + h1.3.powi(2) + h1.4.powi(2)).sqrt();
19344        let mag2 =
19345            (h2.0.powi(2) + h2.1.powi(2) + h2.2.powi(2) + h2.3.powi(2) + h2.4.powi(2)).sqrt();
19346
19347        let similarity = if mag1 > 0.0 && mag2 > 0.0 {
19348            (dot / (mag1 * mag2) + 1.0) / 2.0 // Normalize to 0-1
19349        } else {
19350            0.5
19351        };
19352
19353        Ok(Value::Float(similarity))
19354    });
19355
19356    // emotional_dissonance - detect internal contradictions in affect
19357    // Returns score from 0 (coherent) to 1 (highly dissonant)
19358    define(interp, "emotional_dissonance", Some(1), |_, args| {
19359        let affect = match &args[0] {
19360            Value::Affective { affect, .. } => affect.clone(),
19361            _ => return Ok(Value::Float(0.0)),
19362        };
19363
19364        let mut dissonance: f64 = 0.0;
19365
19366        // Positive sentiment + sarcasm = dissonant
19367        if matches!(affect.sentiment, Some(RuntimeSentiment::Positive)) && affect.sarcasm {
19368            dissonance += 0.4;
19369        }
19370
19371        // Negative sentiment + sarcasm = less dissonant (double negative)
19372        if matches!(affect.sentiment, Some(RuntimeSentiment::Negative)) && affect.sarcasm {
19373            dissonance += 0.1;
19374        }
19375
19376        // High confidence + low intensity = mildly dissonant
19377        if matches!(affect.confidence, Some(RuntimeConfidence::High))
19378            && matches!(affect.intensity, Some(RuntimeIntensity::Down))
19379        {
19380            dissonance += 0.2;
19381        }
19382
19383        // Formal + intense emotion = dissonant
19384        if matches!(affect.formality, Some(RuntimeFormality::Formal)) {
19385            if matches!(
19386                affect.emotion,
19387                Some(RuntimeEmotion::Anger) | Some(RuntimeEmotion::Fear)
19388            ) {
19389                dissonance += 0.3;
19390            }
19391        }
19392
19393        // Joy/Love + Sadness/Fear indicators (based on sarcasm with positive)
19394        if matches!(
19395            affect.emotion,
19396            Some(RuntimeEmotion::Joy) | Some(RuntimeEmotion::Love)
19397        ) && affect.sarcasm
19398        {
19399            dissonance += 0.3;
19400        }
19401
19402        Ok(Value::Float(dissonance.min(1.0)))
19403    });
19404
19405    // emotional_fingerprint - cryptographic hash of emotional state
19406    // Creates a unique identifier for this exact emotional configuration
19407    define(interp, "emotional_fingerprint", Some(1), |interp, args| {
19408        let h = get_hologram_values(&args[0], interp)?;
19409
19410        // Create deterministic string representation
19411        let repr = format!(
19412            "hologram:v{:.4}:a{:.4}:d{:.4}:auth{:.4}:c{:.4}",
19413            h.0, h.1, h.2, h.3, h.4
19414        );
19415
19416        // Hash using BLAKE3
19417        let hash = blake3::hash(repr.as_bytes());
19418        Ok(Value::String(Rc::new(hash.to_hex().to_string())))
19419    });
19420
19421    // emotional_morph - interpolate between two emotional states
19422    // t=0 returns first state, t=1 returns second state
19423    define(interp, "emotional_morph", Some(3), |interp, args| {
19424        let h1 = get_hologram_values(&args[0], interp)?;
19425        let h2 = get_hologram_values(&args[1], interp)?;
19426        let t = match &args[2] {
19427            Value::Float(f) => f.max(0.0).min(1.0),
19428            Value::Int(i) => (*i as f64).max(0.0).min(1.0),
19429            _ => {
19430                return Err(RuntimeError::new(
19431                    "emotional_morph() requires numeric t value",
19432                ))
19433            }
19434        };
19435
19436        let mut result = std::collections::HashMap::new();
19437        result.insert(
19438            "valence".to_string(),
19439            Value::Float(h1.0 + (h2.0 - h1.0) * t),
19440        );
19441        result.insert(
19442            "arousal".to_string(),
19443            Value::Float(h1.1 + (h2.1 - h1.1) * t),
19444        );
19445        result.insert(
19446            "dominance".to_string(),
19447            Value::Float(h1.2 + (h2.2 - h1.2) * t),
19448        );
19449        result.insert(
19450            "authenticity".to_string(),
19451            Value::Float(h1.3 + (h2.3 - h1.3) * t),
19452        );
19453        result.insert(
19454            "certainty".to_string(),
19455            Value::Float(h1.4 + (h2.4 - h1.4) * t),
19456        );
19457
19458        Ok(Value::Map(Rc::new(RefCell::new(result))))
19459    });
19460
19461    // === Cultural Emotion Mappings ===
19462    // Map Sigil emotions to culturally-specific concepts
19463
19464    // cultural_emotion - get cultural equivalent of an emotion
19465    // Supported cultures: japanese, portuguese, german, danish, arabic, korean, russian, hindi
19466    define(interp, "cultural_emotion", Some(2), |_, args| {
19467        let emotion = match &args[0] {
19468            Value::Affective { affect, .. } => affect.emotion.clone(),
19469            Value::String(s) => match s.as_str() {
19470                "joy" => Some(RuntimeEmotion::Joy),
19471                "sadness" => Some(RuntimeEmotion::Sadness),
19472                "anger" => Some(RuntimeEmotion::Anger),
19473                "fear" => Some(RuntimeEmotion::Fear),
19474                "surprise" => Some(RuntimeEmotion::Surprise),
19475                "love" => Some(RuntimeEmotion::Love),
19476                _ => None,
19477            },
19478            _ => None,
19479        };
19480
19481        let culture = match &args[1] {
19482            Value::String(s) => s.to_lowercase(),
19483            _ => {
19484                return Err(RuntimeError::new(
19485                    "cultural_emotion() requires string culture",
19486                ))
19487            }
19488        };
19489
19490        let result = match (emotion, culture.as_str()) {
19491            // Japanese concepts
19492            (Some(RuntimeEmotion::Joy), "japanese" | "ja") => create_cultural_entry(
19493                "木漏れ日",
19494                "komorebi",
19495                "sunlight filtering through leaves - peaceful joy",
19496            ),
19497            (Some(RuntimeEmotion::Sadness), "japanese" | "ja") => create_cultural_entry(
19498                "物の哀れ",
19499                "mono no aware",
19500                "the pathos of things - bittersweet awareness of impermanence",
19501            ),
19502            (Some(RuntimeEmotion::Love), "japanese" | "ja") => create_cultural_entry(
19503                "甘え",
19504                "amae",
19505                "indulgent dependence on another's benevolence",
19506            ),
19507            (Some(RuntimeEmotion::Fear), "japanese" | "ja") => create_cultural_entry(
19508                "空気を読む",
19509                "kuuki wo yomu",
19510                "anxiety about reading the room",
19511            ),
19512
19513            // Portuguese concepts
19514            (Some(RuntimeEmotion::Sadness), "portuguese" | "pt") => create_cultural_entry(
19515                "saudade",
19516                "saudade",
19517                "melancholic longing for something or someone absent",
19518            ),
19519            (Some(RuntimeEmotion::Joy), "portuguese" | "pt") => {
19520                create_cultural_entry("alegria", "alegria", "exuberant collective joy")
19521            }
19522
19523            // German concepts
19524            (Some(RuntimeEmotion::Joy), "german" | "de") => create_cultural_entry(
19525                "Schadenfreude",
19526                "schadenfreude",
19527                "pleasure derived from another's misfortune",
19528            ),
19529            (Some(RuntimeEmotion::Sadness), "german" | "de") => create_cultural_entry(
19530                "Weltschmerz",
19531                "weltschmerz",
19532                "world-weariness, melancholy about the world's state",
19533            ),
19534            (Some(RuntimeEmotion::Fear), "german" | "de") => create_cultural_entry(
19535                "Torschlusspanik",
19536                "torschlusspanik",
19537                "fear of diminishing opportunities with age",
19538            ),
19539
19540            // Danish concepts
19541            (Some(RuntimeEmotion::Joy), "danish" | "da") => {
19542                create_cultural_entry("hygge", "hygge", "cozy contentment and conviviality")
19543            }
19544
19545            // Arabic concepts
19546            (Some(RuntimeEmotion::Joy), "arabic" | "ar") => {
19547                create_cultural_entry("طرب", "tarab", "musical ecstasy, enchantment through art")
19548            }
19549            (Some(RuntimeEmotion::Love), "arabic" | "ar") => {
19550                create_cultural_entry("هوى", "hawa", "passionate, sometimes irrational love")
19551            }
19552
19553            // Korean concepts
19554            (Some(RuntimeEmotion::Sadness), "korean" | "ko") => create_cultural_entry(
19555                "한",
19556                "han",
19557                "collective grief and resentment from historical suffering",
19558            ),
19559            (Some(RuntimeEmotion::Joy), "korean" | "ko") => create_cultural_entry(
19560                "정",
19561                "jeong",
19562                "deep affection and attachment formed over time",
19563            ),
19564
19565            // Russian concepts
19566            (Some(RuntimeEmotion::Sadness), "russian" | "ru") => {
19567                create_cultural_entry("тоска", "toska", "spiritual anguish without specific cause")
19568            }
19569
19570            // Hindi concepts
19571            (Some(RuntimeEmotion::Love), "hindi" | "hi") => {
19572                create_cultural_entry("विरह", "viraha", "longing for an absent beloved")
19573            }
19574
19575            // Finnish concepts
19576            (Some(RuntimeEmotion::Anger), "finnish" | "fi") => {
19577                create_cultural_entry("sisu", "sisu", "stoic determination and grit in adversity")
19578            }
19579
19580            // Default: return the base emotion
19581            (Some(e), _) => {
19582                let name = match e {
19583                    RuntimeEmotion::Joy => "joy",
19584                    RuntimeEmotion::Sadness => "sadness",
19585                    RuntimeEmotion::Anger => "anger",
19586                    RuntimeEmotion::Fear => "fear",
19587                    RuntimeEmotion::Surprise => "surprise",
19588                    RuntimeEmotion::Love => "love",
19589                };
19590                create_cultural_entry(name, name, "universal emotion")
19591            }
19592            (None, _) => create_cultural_entry("none", "none", "no emotion"),
19593        };
19594
19595        Ok(result)
19596    });
19597
19598    // list_cultural_emotions - list all emotions for a culture
19599    define(interp, "list_cultural_emotions", Some(1), |_, args| {
19600        let culture = match &args[0] {
19601            Value::String(s) => s.to_lowercase(),
19602            _ => {
19603                return Err(RuntimeError::new(
19604                    "list_cultural_emotions() requires string culture",
19605                ))
19606            }
19607        };
19608
19609        let emotions: Vec<(&str, &str, &str)> = match culture.as_str() {
19610            "japanese" | "ja" => vec![
19611                ("木漏れ日", "komorebi", "sunlight through leaves"),
19612                ("物の哀れ", "mono no aware", "pathos of things"),
19613                ("甘え", "amae", "indulgent dependence"),
19614                ("侘寂", "wabi-sabi", "beauty in imperfection"),
19615                ("生きがい", "ikigai", "reason for being"),
19616            ],
19617            "german" | "de" => vec![
19618                ("Schadenfreude", "schadenfreude", "joy at misfortune"),
19619                ("Weltschmerz", "weltschmerz", "world-weariness"),
19620                ("Torschlusspanik", "torschlusspanik", "gate-closing panic"),
19621                ("Sehnsucht", "sehnsucht", "deep longing"),
19622                ("Wanderlust", "wanderlust", "desire to travel"),
19623            ],
19624            "portuguese" | "pt" => vec![
19625                ("saudade", "saudade", "melancholic longing"),
19626                ("alegria", "alegria", "exuberant joy"),
19627                ("desabafar", "desabafar", "emotional unburdening"),
19628            ],
19629            "danish" | "da" => vec![("hygge", "hygge", "cozy contentment")],
19630            "korean" | "ko" => vec![
19631                ("한", "han", "collective grief"),
19632                ("정", "jeong", "deep affection"),
19633                ("눈치", "nunchi", "situational awareness"),
19634            ],
19635            "arabic" | "ar" => vec![
19636                ("طرب", "tarab", "musical ecstasy"),
19637                ("هوى", "hawa", "passionate love"),
19638                ("صبر", "sabr", "patient perseverance"),
19639            ],
19640            "russian" | "ru" => vec![
19641                ("тоска", "toska", "spiritual anguish"),
19642                ("пошлость", "poshlost", "spiritual vulgarity"),
19643            ],
19644            "finnish" | "fi" => vec![("sisu", "sisu", "stoic determination")],
19645            "hindi" | "hi" => vec![
19646                ("विरह", "viraha", "longing for beloved"),
19647                ("जुगाड़", "jugaad", "creative improvisation"),
19648            ],
19649            _ => vec![
19650                ("joy", "joy", "universal happiness"),
19651                ("sadness", "sadness", "universal sorrow"),
19652                ("anger", "anger", "universal frustration"),
19653                ("fear", "fear", "universal anxiety"),
19654                ("surprise", "surprise", "universal amazement"),
19655                ("love", "love", "universal affection"),
19656            ],
19657        };
19658
19659        let result: Vec<Value> = emotions
19660            .iter()
19661            .map(|(native, romanized, meaning)| create_cultural_entry(native, romanized, meaning))
19662            .collect();
19663
19664        Ok(Value::Array(Rc::new(RefCell::new(result))))
19665    });
19666
19667    // hologram_info - get metadata about the hologram system
19668    define(interp, "hologram_info", Some(0), |_, _| {
19669        let mut info = std::collections::HashMap::new();
19670
19671        info.insert(
19672            "dimensions".to_string(),
19673            Value::Array(Rc::new(RefCell::new(vec![
19674                Value::String(Rc::new("valence".to_string())),
19675                Value::String(Rc::new("arousal".to_string())),
19676                Value::String(Rc::new("dominance".to_string())),
19677                Value::String(Rc::new("authenticity".to_string())),
19678                Value::String(Rc::new("certainty".to_string())),
19679                Value::String(Rc::new("emotion_index".to_string())),
19680            ]))),
19681        );
19682
19683        info.insert(
19684            "supported_cultures".to_string(),
19685            Value::Array(Rc::new(RefCell::new(vec![
19686                Value::String(Rc::new("japanese".to_string())),
19687                Value::String(Rc::new("german".to_string())),
19688                Value::String(Rc::new("portuguese".to_string())),
19689                Value::String(Rc::new("danish".to_string())),
19690                Value::String(Rc::new("korean".to_string())),
19691                Value::String(Rc::new("arabic".to_string())),
19692                Value::String(Rc::new("russian".to_string())),
19693                Value::String(Rc::new("finnish".to_string())),
19694                Value::String(Rc::new("hindi".to_string())),
19695            ]))),
19696        );
19697
19698        let funcs = vec![
19699            "emotional_hologram",
19700            "emotional_distance",
19701            "emotional_similarity",
19702            "emotional_dissonance",
19703            "emotional_fingerprint",
19704            "emotional_morph",
19705            "cultural_emotion",
19706            "list_cultural_emotions",
19707            "hologram_info",
19708        ];
19709        let func_values: Vec<Value> = funcs
19710            .iter()
19711            .map(|s| Value::String(Rc::new(s.to_string())))
19712            .collect();
19713        info.insert(
19714            "functions".to_string(),
19715            Value::Array(Rc::new(RefCell::new(func_values))),
19716        );
19717
19718        Ok(Value::Map(Rc::new(RefCell::new(info))))
19719    });
19720}
19721
19722/// Helper to extract hologram values from an affective value
19723fn get_hologram_values(
19724    val: &Value,
19725    _interp: &mut Interpreter,
19726) -> Result<(f64, f64, f64, f64, f64), RuntimeError> {
19727    use crate::interpreter::{
19728        RuntimeAffect, RuntimeConfidence, RuntimeFormality, RuntimeIntensity, RuntimeSentiment,
19729    };
19730
19731    let affect = match val {
19732        Value::Affective { affect, .. } => affect.clone(),
19733        Value::Map(m) => {
19734            // Already a hologram map
19735            let map = m.borrow();
19736            let v = extract_float(&map, "valence").unwrap_or(0.0);
19737            let a = extract_float(&map, "arousal").unwrap_or(0.5);
19738            let d = extract_float(&map, "dominance").unwrap_or(0.5);
19739            let auth = extract_float(&map, "authenticity").unwrap_or(0.9);
19740            let c = extract_float(&map, "certainty").unwrap_or(0.5);
19741            return Ok((v, a, d, auth, c));
19742        }
19743        _ => RuntimeAffect {
19744            sentiment: None,
19745            sarcasm: false,
19746            intensity: None,
19747            formality: None,
19748            emotion: None,
19749            confidence: None,
19750        },
19751    };
19752
19753    let v = match affect.sentiment {
19754        Some(RuntimeSentiment::Positive) => 1.0,
19755        Some(RuntimeSentiment::Negative) => -1.0,
19756        _ => 0.0,
19757    };
19758    let a = match affect.intensity {
19759        Some(RuntimeIntensity::Down) => 0.25,
19760        Some(RuntimeIntensity::Up) => 0.75,
19761        Some(RuntimeIntensity::Max) => 1.0,
19762        None => 0.5,
19763    };
19764    let d = match affect.formality {
19765        Some(RuntimeFormality::Informal) => 0.25,
19766        Some(RuntimeFormality::Formal) => 0.85,
19767        None => 0.5,
19768    };
19769    let auth = if affect.sarcasm { -0.9 } else { 0.9 };
19770    let c = match affect.confidence {
19771        Some(RuntimeConfidence::Low) => 0.2,
19772        Some(RuntimeConfidence::High) => 0.9,
19773        _ => 0.5,
19774    };
19775
19776    Ok((v, a, d, auth, c))
19777}
19778
19779fn extract_float(map: &std::collections::HashMap<String, Value>, key: &str) -> Option<f64> {
19780    match map.get(key) {
19781        Some(Value::Float(f)) => Some(*f),
19782        Some(Value::Int(i)) => Some(*i as f64),
19783        _ => None,
19784    }
19785}
19786
19787fn create_cultural_entry(native: &str, romanized: &str, meaning: &str) -> Value {
19788    let mut entry = std::collections::HashMap::new();
19789    entry.insert(
19790        "native".to_string(),
19791        Value::String(Rc::new(native.to_string())),
19792    );
19793    entry.insert(
19794        "romanized".to_string(),
19795        Value::String(Rc::new(romanized.to_string())),
19796    );
19797    entry.insert(
19798        "meaning".to_string(),
19799        Value::String(Rc::new(meaning.to_string())),
19800    );
19801    Value::Map(Rc::new(RefCell::new(entry)))
19802}
19803
19804// ============================================================================
19805// EXPERIMENTAL CRYPTOGRAPHY: Threshold crypto, commitments, and more
19806// ============================================================================
19807
19808fn register_experimental_crypto(interp: &mut Interpreter) {
19809    // === Commitment Schemes ===
19810    // Commit to a value without revealing it, verify later
19811
19812    // commit - create a cryptographic commitment to a value
19813    // Returns { commitment: hash, nonce: random_value }
19814    define(interp, "commit", Some(1), |_, args| {
19815        let value_str = match &args[0] {
19816            Value::String(s) => s.to_string(),
19817            other => format!("{:?}", other),
19818        };
19819
19820        // Generate random nonce
19821        let mut nonce = [0u8; 32];
19822        getrandom::getrandom(&mut nonce)
19823            .map_err(|e| RuntimeError::new(format!("commit() random failed: {}", e)))?;
19824        let nonce_hex = hex::encode(&nonce);
19825
19826        // Create commitment: H(value || nonce)
19827        let commitment_input = format!("{}:{}", value_str, nonce_hex);
19828        let commitment = blake3::hash(commitment_input.as_bytes());
19829
19830        let mut result = std::collections::HashMap::new();
19831        result.insert(
19832            "commitment".to_string(),
19833            Value::String(Rc::new(commitment.to_hex().to_string())),
19834        );
19835        result.insert("nonce".to_string(), Value::String(Rc::new(nonce_hex)));
19836        result.insert("value".to_string(), args[0].clone());
19837
19838        Ok(Value::Map(Rc::new(RefCell::new(result))))
19839    });
19840
19841    // verify_commitment - verify a commitment matches a revealed value
19842    define(interp, "verify_commitment", Some(3), |_, args| {
19843        let commitment = match &args[0] {
19844            Value::String(s) => s.to_string(),
19845            _ => {
19846                return Err(RuntimeError::new(
19847                    "verify_commitment() requires string commitment",
19848                ))
19849            }
19850        };
19851        let value_str = match &args[1] {
19852            Value::String(s) => s.to_string(),
19853            other => format!("{:?}", other),
19854        };
19855        let nonce = match &args[2] {
19856            Value::String(s) => s.to_string(),
19857            _ => {
19858                return Err(RuntimeError::new(
19859                    "verify_commitment() requires string nonce",
19860                ))
19861            }
19862        };
19863
19864        // Recompute commitment
19865        let commitment_input = format!("{}:{}", value_str, nonce);
19866        let computed = blake3::hash(commitment_input.as_bytes());
19867
19868        Ok(Value::Bool(computed.to_hex().to_string() == commitment))
19869    });
19870
19871    // === Threshold Cryptography (Shamir's Secret Sharing) ===
19872    // Split secrets into shares, requiring threshold to reconstruct
19873
19874    // secret_split - split a secret into n shares, requiring threshold to recover
19875    // Uses Shamir's Secret Sharing over GF(256)
19876    define(interp, "secret_split", Some(3), |_, args| {
19877        let secret = match &args[0] {
19878            Value::String(s) => s.as_bytes().to_vec(),
19879            Value::Array(arr) => {
19880                let borrowed = arr.borrow();
19881                borrowed
19882                    .iter()
19883                    .filter_map(|v| {
19884                        if let Value::Int(i) = v {
19885                            Some(*i as u8)
19886                        } else {
19887                            None
19888                        }
19889                    })
19890                    .collect()
19891            }
19892            _ => {
19893                return Err(RuntimeError::new(
19894                    "secret_split() requires string or byte array",
19895                ))
19896            }
19897        };
19898
19899        let threshold = match &args[1] {
19900            Value::Int(n) => *n as usize,
19901            _ => {
19902                return Err(RuntimeError::new(
19903                    "secret_split() requires integer threshold",
19904                ))
19905            }
19906        };
19907
19908        let num_shares = match &args[2] {
19909            Value::Int(n) => *n as usize,
19910            _ => {
19911                return Err(RuntimeError::new(
19912                    "secret_split() requires integer num_shares",
19913                ))
19914            }
19915        };
19916
19917        if threshold < 2 {
19918            return Err(RuntimeError::new("secret_split() threshold must be >= 2"));
19919        }
19920        if num_shares < threshold {
19921            return Err(RuntimeError::new(
19922                "secret_split() num_shares must be >= threshold",
19923            ));
19924        }
19925        if num_shares > 255 {
19926            return Err(RuntimeError::new("secret_split() max 255 shares"));
19927        }
19928
19929        // Simple implementation: split each byte independently using polynomial interpolation
19930        // For production, use vsss-rs properly, but this demonstrates the concept
19931        let mut rng = rand::thread_rng();
19932        let mut shares: Vec<Vec<u8>> = (0..num_shares)
19933            .map(|_| Vec::with_capacity(secret.len() + 1))
19934            .collect();
19935
19936        // Assign share indices (1-based to avoid zero)
19937        for (i, share) in shares.iter_mut().enumerate() {
19938            share.push((i + 1) as u8);
19939        }
19940
19941        // For each byte of the secret, create polynomial shares
19942        for &byte in &secret {
19943            // Generate random coefficients for polynomial of degree (threshold - 1)
19944            // a_0 = secret byte, a_1..a_{t-1} = random
19945            let mut coefficients: Vec<u8> = vec![byte];
19946            for _ in 1..threshold {
19947                coefficients.push(rng.gen());
19948            }
19949
19950            // Evaluate polynomial at each share index
19951            for (i, share) in shares.iter_mut().enumerate() {
19952                let x = (i + 1) as u8;
19953                let y = eval_polynomial_gf256(&coefficients, x);
19954                share.push(y);
19955            }
19956        }
19957
19958        // Convert shares to output format
19959        let share_values: Vec<Value> = shares
19960            .iter()
19961            .map(|share| {
19962                let hex = hex::encode(share);
19963                Value::String(Rc::new(hex))
19964            })
19965            .collect();
19966
19967        let mut result = std::collections::HashMap::new();
19968        result.insert(
19969            "shares".to_string(),
19970            Value::Array(Rc::new(RefCell::new(share_values))),
19971        );
19972        result.insert("threshold".to_string(), Value::Int(threshold as i64));
19973        result.insert("total".to_string(), Value::Int(num_shares as i64));
19974
19975        Ok(Value::Map(Rc::new(RefCell::new(result))))
19976    });
19977
19978    // secret_recover - recover secret from threshold shares
19979    define(interp, "secret_recover", Some(1), |_, args| {
19980        let shares: Vec<Vec<u8>> = match &args[0] {
19981            Value::Array(arr) => {
19982                let borrowed = arr.borrow();
19983                borrowed
19984                    .iter()
19985                    .filter_map(|v| {
19986                        if let Value::String(s) = v {
19987                            hex::decode(s.as_str()).ok()
19988                        } else {
19989                            None
19990                        }
19991                    })
19992                    .collect()
19993            }
19994            _ => {
19995                return Err(RuntimeError::new(
19996                    "secret_recover() requires array of share strings",
19997                ))
19998            }
19999        };
20000
20001        if shares.is_empty() {
20002            return Err(RuntimeError::new(
20003                "secret_recover() requires at least one share",
20004            ));
20005        }
20006
20007        let share_len = shares[0].len();
20008        if share_len < 2 {
20009            return Err(RuntimeError::new("secret_recover() invalid share format"));
20010        }
20011
20012        // Recover each byte using Lagrange interpolation
20013        let mut secret = Vec::with_capacity(share_len - 1);
20014
20015        for byte_idx in 1..share_len {
20016            // Collect (x, y) pairs for this byte position
20017            let points: Vec<(u8, u8)> = shares
20018                .iter()
20019                .map(|share| (share[0], share[byte_idx]))
20020                .collect();
20021
20022            // Lagrange interpolation at x=0 to recover the secret byte
20023            let recovered_byte = lagrange_interpolate_gf256(&points, 0);
20024            secret.push(recovered_byte);
20025        }
20026
20027        // Try to interpret as string
20028        match String::from_utf8(secret.clone()) {
20029            Ok(s) => Ok(Value::String(Rc::new(s))),
20030            Err(_) => {
20031                // Return as byte array
20032                let byte_values: Vec<Value> =
20033                    secret.iter().map(|&b| Value::Int(b as i64)).collect();
20034                Ok(Value::Array(Rc::new(RefCell::new(byte_values))))
20035            }
20036        }
20037    });
20038
20039    // === Cryptographic Ceremony Functions ===
20040    // Cultural trust models encoded in crypto
20041
20042    // council_split - split secret using Ubuntu (I am because we are) model
20043    // Requires majority consensus
20044    define(interp, "council_split", Some(2), |_, args| {
20045        let secret = match &args[0] {
20046            Value::String(s) => s.as_bytes().to_vec(),
20047            _ => return Err(RuntimeError::new("council_split() requires string secret")),
20048        };
20049
20050        let num_elders = match &args[1] {
20051            Value::Int(n) => *n as usize,
20052            _ => {
20053                return Err(RuntimeError::new(
20054                    "council_split() requires integer num_elders",
20055                ))
20056            }
20057        };
20058
20059        if num_elders < 3 {
20060            return Err(RuntimeError::new(
20061                "council_split() requires at least 3 elders",
20062            ));
20063        }
20064
20065        // Ubuntu model: majority required (n/2 + 1)
20066        let threshold = (num_elders / 2) + 1;
20067
20068        // Reuse secret_split logic
20069        let mut rng = rand::thread_rng();
20070        let mut shares: Vec<Vec<u8>> = (0..num_elders)
20071            .map(|_| Vec::with_capacity(secret.len() + 1))
20072            .collect();
20073
20074        for (i, share) in shares.iter_mut().enumerate() {
20075            share.push((i + 1) as u8);
20076        }
20077
20078        for &byte in &secret {
20079            let mut coefficients: Vec<u8> = vec![byte];
20080            for _ in 1..threshold {
20081                coefficients.push(rng.gen());
20082            }
20083
20084            for (i, share) in shares.iter_mut().enumerate() {
20085                let x = (i + 1) as u8;
20086                let y = eval_polynomial_gf256(&coefficients, x);
20087                share.push(y);
20088            }
20089        }
20090
20091        let share_values: Vec<Value> = shares
20092            .iter()
20093            .map(|share| Value::String(Rc::new(hex::encode(share))))
20094            .collect();
20095
20096        let mut result = std::collections::HashMap::new();
20097        result.insert(
20098            "shares".to_string(),
20099            Value::Array(Rc::new(RefCell::new(share_values))),
20100        );
20101        result.insert("threshold".to_string(), Value::Int(threshold as i64));
20102        result.insert("total".to_string(), Value::Int(num_elders as i64));
20103        result.insert(
20104            "model".to_string(),
20105            Value::String(Rc::new("ubuntu".to_string())),
20106        );
20107        result.insert(
20108            "philosophy".to_string(),
20109            Value::String(Rc::new(
20110                "I am because we are - majority consensus required".to_string(),
20111            )),
20112        );
20113
20114        Ok(Value::Map(Rc::new(RefCell::new(result))))
20115    });
20116
20117    // witness_chain - create a chain of witnesses (Middle Eastern oral tradition model)
20118    // Each witness signs the previous, creating a chain of trust
20119    define(interp, "witness_chain", Some(2), |_, args| {
20120        let statement = match &args[0] {
20121            Value::String(s) => s.to_string(),
20122            _ => {
20123                return Err(RuntimeError::new(
20124                    "witness_chain() requires string statement",
20125                ))
20126            }
20127        };
20128
20129        let witnesses: Vec<String> = match &args[1] {
20130            Value::Array(arr) => {
20131                let borrowed = arr.borrow();
20132                borrowed
20133                    .iter()
20134                    .filter_map(|v| {
20135                        if let Value::String(s) = v {
20136                            Some(s.to_string())
20137                        } else {
20138                            None
20139                        }
20140                    })
20141                    .collect()
20142            }
20143            _ => {
20144                return Err(RuntimeError::new(
20145                    "witness_chain() requires array of witness names",
20146                ))
20147            }
20148        };
20149
20150        if witnesses.is_empty() {
20151            return Err(RuntimeError::new(
20152                "witness_chain() requires at least one witness",
20153            ));
20154        }
20155
20156        // Build chain: each witness attests to the previous
20157        let mut chain = Vec::new();
20158        let mut prev_hash = blake3::hash(statement.as_bytes()).to_hex().to_string();
20159
20160        for (i, witness) in witnesses.iter().enumerate() {
20161            let attestation = format!("{}:attests:{}", witness, prev_hash);
20162            let hash = blake3::hash(attestation.as_bytes()).to_hex().to_string();
20163
20164            let mut link = std::collections::HashMap::new();
20165            link.insert(
20166                "witness".to_string(),
20167                Value::String(Rc::new(witness.clone())),
20168            );
20169            link.insert("position".to_string(), Value::Int((i + 1) as i64));
20170            link.insert(
20171                "attests_to".to_string(),
20172                Value::String(Rc::new(prev_hash.clone())),
20173            );
20174            link.insert(
20175                "signature".to_string(),
20176                Value::String(Rc::new(hash.clone())),
20177            );
20178
20179            chain.push(Value::Map(Rc::new(RefCell::new(link))));
20180            prev_hash = hash;
20181        }
20182
20183        let mut result = std::collections::HashMap::new();
20184        result.insert("statement".to_string(), Value::String(Rc::new(statement)));
20185        result.insert(
20186            "chain".to_string(),
20187            Value::Array(Rc::new(RefCell::new(chain))),
20188        );
20189        result.insert("final_seal".to_string(), Value::String(Rc::new(prev_hash)));
20190        result.insert(
20191            "model".to_string(),
20192            Value::String(Rc::new("isnad".to_string())),
20193        );
20194        result.insert(
20195            "philosophy".to_string(),
20196            Value::String(Rc::new(
20197                "Chain of reliable transmitters - each witness validates the previous".to_string(),
20198            )),
20199        );
20200
20201        Ok(Value::Map(Rc::new(RefCell::new(result))))
20202    });
20203
20204    // verify_witness_chain - verify a witness chain is intact
20205    define(interp, "verify_witness_chain", Some(1), |_, args| {
20206        let chain_map = match &args[0] {
20207            Value::Map(m) => m.borrow(),
20208            _ => {
20209                return Err(RuntimeError::new(
20210                    "verify_witness_chain() requires chain map",
20211                ))
20212            }
20213        };
20214
20215        let statement = match chain_map.get("statement") {
20216            Some(Value::String(s)) => s.to_string(),
20217            _ => {
20218                return Err(RuntimeError::new(
20219                    "verify_witness_chain() invalid chain format",
20220                ))
20221            }
20222        };
20223
20224        let chain = match chain_map.get("chain") {
20225            Some(Value::Array(arr)) => arr.borrow().clone(),
20226            _ => {
20227                return Err(RuntimeError::new(
20228                    "verify_witness_chain() invalid chain format",
20229                ))
20230            }
20231        };
20232
20233        let mut prev_hash = blake3::hash(statement.as_bytes()).to_hex().to_string();
20234
20235        for link_val in chain.iter() {
20236            if let Value::Map(link_map) = link_val {
20237                let link = link_map.borrow();
20238                let witness = match link.get("witness") {
20239                    Some(Value::String(s)) => s.to_string(),
20240                    _ => return Ok(Value::Bool(false)),
20241                };
20242                let attests_to = match link.get("attests_to") {
20243                    Some(Value::String(s)) => s.to_string(),
20244                    _ => return Ok(Value::Bool(false)),
20245                };
20246                let signature = match link.get("signature") {
20247                    Some(Value::String(s)) => s.to_string(),
20248                    _ => return Ok(Value::Bool(false)),
20249                };
20250
20251                // Verify attestation
20252                if attests_to != prev_hash {
20253                    return Ok(Value::Bool(false));
20254                }
20255
20256                let expected = format!("{}:attests:{}", witness, prev_hash);
20257                let computed = blake3::hash(expected.as_bytes()).to_hex().to_string();
20258
20259                if computed != signature {
20260                    return Ok(Value::Bool(false));
20261                }
20262
20263                prev_hash = signature;
20264            } else {
20265                return Ok(Value::Bool(false));
20266            }
20267        }
20268
20269        Ok(Value::Bool(true))
20270    });
20271
20272    // === Experimental Crypto Info ===
20273    define(interp, "experimental_crypto_info", Some(0), |_, _| {
20274        let mut info = std::collections::HashMap::new();
20275
20276        info.insert(
20277            "commitment_functions".to_string(),
20278            Value::Array(Rc::new(RefCell::new(vec![
20279                Value::String(Rc::new("commit".to_string())),
20280                Value::String(Rc::new("verify_commitment".to_string())),
20281            ]))),
20282        );
20283
20284        info.insert(
20285            "threshold_functions".to_string(),
20286            Value::Array(Rc::new(RefCell::new(vec![
20287                Value::String(Rc::new("secret_split".to_string())),
20288                Value::String(Rc::new("secret_recover".to_string())),
20289            ]))),
20290        );
20291
20292        info.insert(
20293            "cultural_ceremonies".to_string(),
20294            Value::Array(Rc::new(RefCell::new(vec![
20295                Value::String(Rc::new(
20296                    "council_split (Ubuntu - African consensus)".to_string(),
20297                )),
20298                Value::String(Rc::new(
20299                    "witness_chain (Isnad - Islamic transmission)".to_string(),
20300                )),
20301            ]))),
20302        );
20303
20304        Ok(Value::Map(Rc::new(RefCell::new(info))))
20305    });
20306}
20307
20308/// Evaluate polynomial in GF(256) at point x
20309fn eval_polynomial_gf256(coefficients: &[u8], x: u8) -> u8 {
20310    let mut result: u8 = 0;
20311    let mut x_power: u8 = 1;
20312
20313    for &coef in coefficients {
20314        result ^= gf256_mul(coef, x_power);
20315        x_power = gf256_mul(x_power, x);
20316    }
20317
20318    result
20319}
20320
20321/// Lagrange interpolation in GF(256) to find f(0)
20322fn lagrange_interpolate_gf256(points: &[(u8, u8)], _x: u8) -> u8 {
20323    let mut result: u8 = 0;
20324
20325    for (i, &(xi, yi)) in points.iter().enumerate() {
20326        let mut numerator: u8 = 1;
20327        let mut denominator: u8 = 1;
20328
20329        for (j, &(xj, _)) in points.iter().enumerate() {
20330            if i != j {
20331                // numerator *= (0 - xj) = xj (in GF256, subtraction is XOR)
20332                numerator = gf256_mul(numerator, xj);
20333                // denominator *= (xi - xj)
20334                denominator = gf256_mul(denominator, xi ^ xj);
20335            }
20336        }
20337
20338        // term = yi * numerator / denominator
20339        let term = gf256_mul(yi, gf256_mul(numerator, gf256_inv(denominator)));
20340        result ^= term;
20341    }
20342
20343    result
20344}
20345
20346/// GF(256) multiplication using Russian peasant algorithm
20347fn gf256_mul(mut a: u8, mut b: u8) -> u8 {
20348    let mut result: u8 = 0;
20349    let modulus: u16 = 0x11b; // x^8 + x^4 + x^3 + x + 1
20350
20351    while b != 0 {
20352        if b & 1 != 0 {
20353            result ^= a;
20354        }
20355        let high_bit = (a & 0x80) != 0;
20356        a <<= 1;
20357        if high_bit {
20358            a ^= (modulus & 0xff) as u8;
20359        }
20360        b >>= 1;
20361    }
20362
20363    result
20364}
20365
20366/// GF(256) multiplicative inverse using extended Euclidean algorithm
20367fn gf256_inv(a: u8) -> u8 {
20368    if a == 0 {
20369        return 0;
20370    }
20371
20372    // Use Fermat's little theorem: a^(-1) = a^(254) in GF(256)
20373    let mut result = a;
20374    for _ in 0..6 {
20375        result = gf256_mul(result, result);
20376        result = gf256_mul(result, a);
20377    }
20378    gf256_mul(result, result)
20379}
20380
20381// ============================================================================
20382// MULTI-BASE ENCODING: Polycultural numeral systems and crypto addresses
20383// ============================================================================
20384//
20385// Sigil supports multiple numeral bases reflecting different mathematical traditions:
20386//   Binary (2)      - 0b prefix - Modern computing
20387//   Octal (8)       - 0o prefix - Unix permissions
20388//   Decimal (10)    - Default   - Indo-Arabic (global standard)
20389//   Duodecimal (12) - 0z prefix - Dozen system (time, music)
20390//   Hexadecimal (16)- 0x prefix - Computing, colors
20391//   Vigesimal (20)  - 0v prefix - Mayan, Celtic, Basque
20392//   Sexagesimal (60)- 0s prefix - Babylonian (time, angles)
20393//
20394// Plus special encodings:
20395//   Base58  - Bitcoin addresses (no confusing 0/O/I/l)
20396//   Base32  - Case-insensitive, no confusing chars
20397//   Base36  - Alphanumeric only
20398
20399fn register_multibase(interp: &mut Interpreter) {
20400    // === Vigesimal (Base 20) - Mayan/Celtic ===
20401    // Digits: 0-9, A-J (or a-j)
20402
20403    define(interp, "to_vigesimal", Some(1), |_, args| {
20404        let n = match &args[0] {
20405            Value::Int(n) => *n,
20406            _ => return Err(RuntimeError::new("to_vigesimal() requires integer")),
20407        };
20408
20409        let result = to_base_string(n.unsigned_abs(), 20, false);
20410        let prefix = if n < 0 { "-0v" } else { "0v" };
20411        Ok(Value::String(Rc::new(format!("{}{}", prefix, result))))
20412    });
20413
20414    define(interp, "from_vigesimal", Some(1), |_, args| {
20415        let s = match &args[0] {
20416            Value::String(s) => s.to_string(),
20417            _ => return Err(RuntimeError::new("from_vigesimal() requires string")),
20418        };
20419
20420        let (negative, clean) = parse_base_prefix(&s, "0v");
20421        let value = from_base_string(&clean, 20)?;
20422        Ok(Value::Int(if negative {
20423            -(value as i64)
20424        } else {
20425            value as i64
20426        }))
20427    });
20428
20429    // === Sexagesimal (Base 60) - Babylonian ===
20430    // Uses colon-separated groups for readability: "1:30:45" = 1*3600 + 30*60 + 45
20431
20432    define(interp, "to_sexagesimal", Some(1), |_, args| {
20433        let n = match &args[0] {
20434            Value::Int(n) => *n,
20435            _ => return Err(RuntimeError::new("to_sexagesimal() requires integer")),
20436        };
20437
20438        let negative = n < 0;
20439        let mut value = n.unsigned_abs();
20440        let mut parts = Vec::new();
20441
20442        if value == 0 {
20443            parts.push("0".to_string());
20444        } else {
20445            while value > 0 {
20446                parts.push(format!("{}", value % 60));
20447                value /= 60;
20448            }
20449            parts.reverse();
20450        }
20451
20452        let prefix = if negative { "-0s" } else { "0s" };
20453        Ok(Value::String(Rc::new(format!(
20454            "{}[{}]",
20455            prefix,
20456            parts.join(":")
20457        ))))
20458    });
20459
20460    define(interp, "from_sexagesimal", Some(1), |_, args| {
20461        let s = match &args[0] {
20462            Value::String(s) => s.to_string(),
20463            _ => return Err(RuntimeError::new("from_sexagesimal() requires string")),
20464        };
20465
20466        let negative = s.starts_with('-');
20467        let clean = s
20468            .trim_start_matches('-')
20469            .trim_start_matches("0s")
20470            .trim_start_matches('[')
20471            .trim_end_matches(']');
20472
20473        let mut result: i64 = 0;
20474        for part in clean.split(':') {
20475            let digit: i64 = part
20476                .trim()
20477                .parse()
20478                .map_err(|_| RuntimeError::new(format!("Invalid sexagesimal digit: {}", part)))?;
20479            if digit < 0 || digit >= 60 {
20480                return Err(RuntimeError::new(format!(
20481                    "Sexagesimal digit out of range: {}",
20482                    digit
20483                )));
20484            }
20485            result = result * 60 + digit;
20486        }
20487
20488        Ok(Value::Int(if negative { -result } else { result }))
20489    });
20490
20491    // === Duodecimal (Base 12) - Dozen system ===
20492    // Digits: 0-9, X (10), E (11) - Dozenal Society convention
20493
20494    define(interp, "to_duodecimal", Some(1), |_, args| {
20495        let n = match &args[0] {
20496            Value::Int(n) => *n,
20497            _ => return Err(RuntimeError::new("to_duodecimal() requires integer")),
20498        };
20499
20500        let result = to_base_string_custom(n.unsigned_abs(), 12, "0123456789XE");
20501        let prefix = if n < 0 { "-0z" } else { "0z" };
20502        Ok(Value::String(Rc::new(format!("{}{}", prefix, result))))
20503    });
20504
20505    define(interp, "from_duodecimal", Some(1), |_, args| {
20506        let s = match &args[0] {
20507            Value::String(s) => s.to_string(),
20508            _ => return Err(RuntimeError::new("from_duodecimal() requires string")),
20509        };
20510
20511        let (negative, clean) = parse_base_prefix(&s, "0z");
20512        let value = from_base_string_custom(&clean.to_uppercase(), "0123456789XE")?;
20513        Ok(Value::Int(if negative {
20514            -(value as i64)
20515        } else {
20516            value as i64
20517        }))
20518    });
20519
20520    // === Generic Base Conversion ===
20521
20522    define(interp, "to_base", Some(2), |_, args| {
20523        let n = match &args[0] {
20524            Value::Int(n) => *n,
20525            _ => return Err(RuntimeError::new("to_base() requires integer")),
20526        };
20527        let base = match &args[1] {
20528            Value::Int(b) => *b as u64,
20529            _ => return Err(RuntimeError::new("to_base() requires integer base")),
20530        };
20531
20532        if base < 2 || base > 36 {
20533            return Err(RuntimeError::new("to_base() base must be 2-36"));
20534        }
20535
20536        let result = to_base_string(n.unsigned_abs(), base, false);
20537        let prefix = if n < 0 { "-" } else { "" };
20538        Ok(Value::String(Rc::new(format!("{}{}", prefix, result))))
20539    });
20540
20541    define(interp, "from_base", Some(2), |_, args| {
20542        let s = match &args[0] {
20543            Value::String(s) => s.to_string(),
20544            _ => return Err(RuntimeError::new("from_base() requires string")),
20545        };
20546        let base = match &args[1] {
20547            Value::Int(b) => *b as u64,
20548            _ => return Err(RuntimeError::new("from_base() requires integer base")),
20549        };
20550
20551        if base < 2 || base > 36 {
20552            return Err(RuntimeError::new("from_base() base must be 2-36"));
20553        }
20554
20555        let negative = s.starts_with('-');
20556        let clean = s.trim_start_matches('-');
20557        let value = from_base_string(clean, base)?;
20558        Ok(Value::Int(if negative {
20559            -(value as i64)
20560        } else {
20561            value as i64
20562        }))
20563    });
20564
20565    // === Base58 - Bitcoin/IPFS addresses ===
20566    // Alphabet: 123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz
20567    // Excludes: 0, O, I, l (confusing characters)
20568
20569    const BASE58_ALPHABET: &str = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
20570
20571    define(interp, "base58_encode", Some(1), |_, args| {
20572        let bytes: Vec<u8> = match &args[0] {
20573            Value::String(s) => s.as_bytes().to_vec(),
20574            Value::Array(arr) => arr
20575                .borrow()
20576                .iter()
20577                .filter_map(|v| {
20578                    if let Value::Int(i) = v {
20579                        Some(*i as u8)
20580                    } else {
20581                        None
20582                    }
20583                })
20584                .collect(),
20585            _ => {
20586                return Err(RuntimeError::new(
20587                    "base58_encode() requires string or byte array",
20588                ))
20589            }
20590        };
20591
20592        // Count leading zeros
20593        let leading_zeros = bytes.iter().take_while(|&&b| b == 0).count();
20594
20595        // Convert to big integer and then to base58
20596        let mut result = Vec::new();
20597        let mut num: Vec<u8> = bytes.clone();
20598
20599        while !num.is_empty() && !num.iter().all(|&b| b == 0) {
20600            let mut remainder = 0u32;
20601            let mut new_num = Vec::new();
20602
20603            for &byte in &num {
20604                let acc = (remainder << 8) + byte as u32;
20605                let digit = acc / 58;
20606                remainder = acc % 58;
20607
20608                if !new_num.is_empty() || digit > 0 {
20609                    new_num.push(digit as u8);
20610                }
20611            }
20612
20613            result.push(BASE58_ALPHABET.chars().nth(remainder as usize).unwrap());
20614            num = new_num;
20615        }
20616
20617        // Add '1' for each leading zero byte
20618        for _ in 0..leading_zeros {
20619            result.push('1');
20620        }
20621
20622        result.reverse();
20623        Ok(Value::String(Rc::new(result.into_iter().collect())))
20624    });
20625
20626    define(interp, "base58_decode", Some(1), |_, args| {
20627        let s = match &args[0] {
20628            Value::String(s) => s.to_string(),
20629            _ => return Err(RuntimeError::new("base58_decode() requires string")),
20630        };
20631
20632        // Count leading '1's
20633        let leading_ones = s.chars().take_while(|&c| c == '1').count();
20634
20635        // Convert from base58 to big integer
20636        let mut num: Vec<u8> = Vec::new();
20637
20638        for c in s.chars() {
20639            let digit = BASE58_ALPHABET
20640                .find(c)
20641                .ok_or_else(|| RuntimeError::new(format!("Invalid base58 character: {}", c)))?;
20642
20643            let mut carry = digit as u32;
20644            for byte in num.iter_mut().rev() {
20645                let acc = (*byte as u32) * 58 + carry;
20646                *byte = (acc & 0xff) as u8;
20647                carry = acc >> 8;
20648            }
20649
20650            while carry > 0 {
20651                num.insert(0, (carry & 0xff) as u8);
20652                carry >>= 8;
20653            }
20654        }
20655
20656        // Add leading zeros
20657        let mut result = vec![0u8; leading_ones];
20658        result.extend(num);
20659
20660        // Return as hex string for readability
20661        Ok(Value::String(Rc::new(hex::encode(&result))))
20662    });
20663
20664    // === Base32 - Case insensitive, no confusing chars ===
20665    // RFC 4648 alphabet: A-Z, 2-7
20666
20667    const BASE32_ALPHABET: &str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
20668
20669    define(interp, "base32_encode", Some(1), |_, args| {
20670        let bytes: Vec<u8> = match &args[0] {
20671            Value::String(s) => s.as_bytes().to_vec(),
20672            Value::Array(arr) => arr
20673                .borrow()
20674                .iter()
20675                .filter_map(|v| {
20676                    if let Value::Int(i) = v {
20677                        Some(*i as u8)
20678                    } else {
20679                        None
20680                    }
20681                })
20682                .collect(),
20683            _ => {
20684                return Err(RuntimeError::new(
20685                    "base32_encode() requires string or byte array",
20686                ))
20687            }
20688        };
20689
20690        let mut result = String::new();
20691        let mut buffer: u64 = 0;
20692        let mut bits = 0;
20693
20694        for byte in bytes {
20695            buffer = (buffer << 8) | byte as u64;
20696            bits += 8;
20697
20698            while bits >= 5 {
20699                bits -= 5;
20700                let idx = ((buffer >> bits) & 0x1f) as usize;
20701                result.push(BASE32_ALPHABET.chars().nth(idx).unwrap());
20702            }
20703        }
20704
20705        if bits > 0 {
20706            let idx = ((buffer << (5 - bits)) & 0x1f) as usize;
20707            result.push(BASE32_ALPHABET.chars().nth(idx).unwrap());
20708        }
20709
20710        // Padding
20711        while result.len() % 8 != 0 {
20712            result.push('=');
20713        }
20714
20715        Ok(Value::String(Rc::new(result)))
20716    });
20717
20718    define(interp, "base32_decode", Some(1), |_, args| {
20719        let s = match &args[0] {
20720            Value::String(s) => s.to_uppercase().replace('=', ""),
20721            _ => return Err(RuntimeError::new("base32_decode() requires string")),
20722        };
20723
20724        let mut result = Vec::new();
20725        let mut buffer: u64 = 0;
20726        let mut bits = 0;
20727
20728        for c in s.chars() {
20729            let digit = BASE32_ALPHABET
20730                .find(c)
20731                .ok_or_else(|| RuntimeError::new(format!("Invalid base32 character: {}", c)))?;
20732
20733            buffer = (buffer << 5) | digit as u64;
20734            bits += 5;
20735
20736            if bits >= 8 {
20737                bits -= 8;
20738                result.push((buffer >> bits) as u8);
20739                buffer &= (1 << bits) - 1;
20740            }
20741        }
20742
20743        Ok(Value::String(Rc::new(hex::encode(&result))))
20744    });
20745
20746    // === Cultural Numerology ===
20747
20748    // sacred_numbers - get sacred/significant numbers for a culture
20749    define(interp, "sacred_numbers", Some(1), |_, args| {
20750        let culture = match &args[0] {
20751            Value::String(s) => s.to_lowercase(),
20752            _ => {
20753                return Err(RuntimeError::new(
20754                    "sacred_numbers() requires string culture",
20755                ))
20756            }
20757        };
20758
20759        let numbers: Vec<(i64, &str)> = match culture.as_str() {
20760            "mayan" | "maya" => vec![
20761                (13, "Sacred cycle - Tzolkin calendar"),
20762                (20, "Base of vigesimal system - human digits"),
20763                (52, "Calendar round - 52 years"),
20764                (260, "Tzolkin sacred calendar days"),
20765                (365, "Haab solar calendar days"),
20766                (400, "Baktun - 20×20 years"),
20767            ],
20768            "babylonian" | "mesopotamian" => vec![
20769                (12, "Months, hours - celestial division"),
20770                (60, "Sexagesimal base - minutes, seconds, degrees"),
20771                (360, "Circle degrees - 6×60"),
20772                (3600, "Sar - 60×60, large count"),
20773                (7, "Planets visible to naked eye"),
20774            ],
20775            "chinese" | "zh" => vec![
20776                (8, "八 (bā) - prosperity, wealth (sounds like 發)"),
20777                (9, "九 (jiǔ) - longevity (sounds like 久)"),
20778                (6, "六 (liù) - smooth, flowing"),
20779                (2, "二 (èr) - pairs, harmony"),
20780                (4, "四 (sì) - AVOID - sounds like death (死)"),
20781                (5, "五 (wǔ) - five elements"),
20782                (12, "十二 - zodiac animals"),
20783            ],
20784            "japanese" | "ja" => vec![
20785                (7, "七 (nana) - lucky, seven gods of fortune"),
20786                (8, "八 (hachi) - prosperity, expansion"),
20787                (3, "三 (san) - completeness"),
20788                (5, "五 (go) - five elements"),
20789                (4, "四 (shi) - AVOID - sounds like death (死)"),
20790                (9, "九 (ku) - AVOID - sounds like suffering (苦)"),
20791            ],
20792            "hebrew" | "jewish" => vec![
20793                (7, "Shabbat, creation days, menorah branches"),
20794                (18, "Chai (חי) - life - gematria of ח(8) + י(10)"),
20795                (40, "Transformation - flood, Sinai, wilderness"),
20796                (12, "Tribes of Israel"),
20797                (613, "Mitzvot - commandments"),
20798                (26, "Gematria of YHWH"),
20799            ],
20800            "islamic" | "arabic" | "ar" => vec![
20801                (5, "Pillars of Islam, daily prayers"),
20802                (7, "Heavens, circumambulation of Kaaba"),
20803                (40, "Age of prophethood, days of repentance"),
20804                (99, "Names of Allah"),
20805                (786, "Abjad value of Bismillah"),
20806            ],
20807            "hindu" | "indian" | "hi" => vec![
20808                (108, "Sacred beads, Upanishads, sun's distance"),
20809                (7, "Chakras (main), rishis, sacred rivers"),
20810                (3, "Trimurti - Brahma, Vishnu, Shiva"),
20811                (4, "Vedas, yugas, varnas"),
20812                (9, "Planets (navagraha), durga forms"),
20813                (1008, "Names of Vishnu"),
20814            ],
20815            "greek" | "pythagorean" => vec![
20816                (1, "Monad - unity, source"),
20817                (2, "Dyad - duality, diversity"),
20818                (3, "Triad - harmony, completion"),
20819                (4, "Tetrad - solidity, earth"),
20820                (7, "Heptad - perfection"),
20821                (10, "Decad - tetractys, divine"),
20822                (12, "Olympian gods"),
20823            ],
20824            "celtic" | "irish" => vec![
20825                (3, "Triple goddess, triquetra"),
20826                (5, "Elements including spirit"),
20827                (9, "Triple threes - sacred completion"),
20828                (13, "Lunar months"),
20829                (17, "St. Patrick's Day"),
20830                (20, "Vigesimal counting"),
20831            ],
20832            _ => vec![
20833                (1, "Unity"),
20834                (7, "Widely considered lucky"),
20835                (12, "Dozen - practical division"),
20836                (13, "Often considered unlucky in West"),
20837            ],
20838        };
20839
20840        let result: Vec<Value> = numbers
20841            .iter()
20842            .map(|(n, meaning)| {
20843                let mut entry = std::collections::HashMap::new();
20844                entry.insert("number".to_string(), Value::Int(*n));
20845                entry.insert(
20846                    "meaning".to_string(),
20847                    Value::String(Rc::new(meaning.to_string())),
20848                );
20849                Value::Map(Rc::new(RefCell::new(entry)))
20850            })
20851            .collect();
20852
20853        Ok(Value::Array(Rc::new(RefCell::new(result))))
20854    });
20855
20856    // is_sacred - check if a number is sacred in a culture
20857    define(interp, "is_sacred", Some(2), |_, args| {
20858        let n = match &args[0] {
20859            Value::Int(n) => *n,
20860            _ => return Err(RuntimeError::new("is_sacred() requires integer")),
20861        };
20862        let culture = match &args[1] {
20863            Value::String(s) => s.to_lowercase(),
20864            _ => return Err(RuntimeError::new("is_sacred() requires string culture")),
20865        };
20866
20867        let sacred = match culture.as_str() {
20868            "mayan" | "maya" => vec![13, 20, 52, 260, 365, 400],
20869            "babylonian" | "mesopotamian" => vec![12, 60, 360, 3600, 7],
20870            "chinese" | "zh" => vec![8, 9, 6, 2, 5, 12],
20871            "japanese" | "ja" => vec![7, 8, 3, 5],
20872            "hebrew" | "jewish" => vec![7, 18, 40, 12, 613, 26],
20873            "islamic" | "arabic" | "ar" => vec![5, 7, 40, 99, 786],
20874            "hindu" | "indian" | "hi" => vec![108, 7, 3, 4, 9, 1008],
20875            "greek" | "pythagorean" => vec![1, 2, 3, 4, 7, 10, 12],
20876            "celtic" | "irish" => vec![3, 5, 9, 13, 17, 20],
20877            _ => vec![7, 12],
20878        };
20879
20880        Ok(Value::Bool(sacred.contains(&n)))
20881    });
20882
20883    // is_unlucky - check if a number is unlucky in a culture
20884    define(interp, "is_unlucky", Some(2), |_, args| {
20885        let n = match &args[0] {
20886            Value::Int(n) => *n,
20887            _ => return Err(RuntimeError::new("is_unlucky() requires integer")),
20888        };
20889        let culture = match &args[1] {
20890            Value::String(s) => s.to_lowercase(),
20891            _ => return Err(RuntimeError::new("is_unlucky() requires string culture")),
20892        };
20893
20894        let unlucky = match culture.as_str() {
20895            "chinese" | "zh" => vec![4],     // 四 sounds like 死 (death)
20896            "japanese" | "ja" => vec![4, 9], // 四=death, 九=suffering
20897            "western" | "en" => vec![13],    // Friday the 13th
20898            "italian" | "it" => vec![17],    // XVII = VIXI (I lived = I'm dead)
20899            _ => vec![],
20900        };
20901
20902        Ok(Value::Bool(unlucky.contains(&n)))
20903    });
20904
20905    // number_meaning - get the cultural meaning of a specific number
20906    define(interp, "number_meaning", Some(2), |_, args| {
20907        let n = match &args[0] {
20908            Value::Int(n) => *n,
20909            _ => return Err(RuntimeError::new("number_meaning() requires integer")),
20910        };
20911        let culture = match &args[1] {
20912            Value::String(s) => s.to_lowercase(),
20913            _ => {
20914                return Err(RuntimeError::new(
20915                    "number_meaning() requires string culture",
20916                ))
20917            }
20918        };
20919
20920        let meaning = match (n, culture.as_str()) {
20921            // Chinese
20922            (8, "chinese" | "zh") => "八 (bā) - Most auspicious, sounds like 發 (prosperity)",
20923            (4, "chinese" | "zh") => "四 (sì) - Unlucky, sounds like 死 (death)",
20924            (9, "chinese" | "zh") => "九 (jiǔ) - Longevity, sounds like 久 (long-lasting)",
20925            (6, "chinese" | "zh") => "六 (liù) - Smooth and well-off",
20926            (2, "chinese" | "zh") => "二 (èr) - Good things come in pairs",
20927
20928            // Japanese
20929            (7, "japanese" | "ja") => "七 (nana) - Lucky, seven gods of fortune",
20930            (8, "japanese" | "ja") => "八 (hachi) - Lucky, represents spreading prosperity",
20931            (4, "japanese" | "ja") => "四 (shi) - Unlucky, homophone of death",
20932            (9, "japanese" | "ja") => "九 (ku) - Unlucky, homophone of suffering",
20933
20934            // Hebrew
20935            (18, "hebrew" | "jewish") => "Chai (חי) - Life itself, most auspicious",
20936            (7, "hebrew" | "jewish") => "Divine completion - Shabbat, menorah, creation",
20937            (40, "hebrew" | "jewish") => "Transformation - flood, Sinai, wilderness years",
20938            (613, "hebrew" | "jewish") => "Taryag - total number of mitzvot (commandments)",
20939
20940            // Mayan
20941            (13, "mayan" | "maya") => "Sacred Tzolkin cycle, celestial layers",
20942            (20, "mayan" | "maya") => "Vigesimal base - fingers and toes, uinal",
20943            (260, "mayan" | "maya") => "Tzolkin calendar - 13 × 20 sacred days",
20944
20945            // Babylonian
20946            (60, "babylonian" | "mesopotamian") => {
20947                "Sexagesimal base - divisible by 2,3,4,5,6,10,12,15,20,30"
20948            }
20949            (360, "babylonian" | "mesopotamian") => "Circle degrees - celestial observation",
20950
20951            // Hindu
20952            (108, "hindu" | "indian" | "hi") => {
20953                "Sacred completeness - mala beads, Upanishads, sun ratio"
20954            }
20955            (3, "hindu" | "indian" | "hi") => "Trimurti - Brahma, Vishnu, Shiva",
20956            (9, "hindu" | "indian" | "hi") => "Navagraha (9 planets), Durga's 9 forms",
20957
20958            // Islamic
20959            (99, "islamic" | "arabic" | "ar") => "Asma ul-Husna - 99 names of Allah",
20960            (5, "islamic" | "arabic" | "ar") => "Five pillars of Islam",
20961            (786, "islamic" | "arabic" | "ar") => "Abjad numerology of Bismillah",
20962
20963            // Greek/Pythagorean
20964            (10, "greek" | "pythagorean") => "Tetractys - 1+2+3+4, perfect number",
20965            (7, "greek" | "pythagorean") => "Heptad - virgin number, Athena's number",
20966
20967            _ => "No specific cultural meaning recorded",
20968        };
20969
20970        let mut result = std::collections::HashMap::new();
20971        result.insert("number".to_string(), Value::Int(n));
20972        result.insert("culture".to_string(), Value::String(Rc::new(culture)));
20973        result.insert(
20974            "meaning".to_string(),
20975            Value::String(Rc::new(meaning.to_string())),
20976        );
20977
20978        Ok(Value::Map(Rc::new(RefCell::new(result))))
20979    });
20980
20981    // === Time encoding using Babylonian sexagesimal ===
20982
20983    // to_babylonian_time - convert seconds to Babylonian notation
20984    define(interp, "to_babylonian_time", Some(1), |_, args| {
20985        let seconds = match &args[0] {
20986            Value::Int(n) => *n,
20987            Value::Float(f) => *f as i64,
20988            _ => return Err(RuntimeError::new("to_babylonian_time() requires number")),
20989        };
20990
20991        let hours = seconds / 3600;
20992        let mins = (seconds % 3600) / 60;
20993        let secs = seconds % 60;
20994
20995        Ok(Value::String(Rc::new(format!(
20996            "0s[{}:{}:{}]",
20997            hours, mins, secs
20998        ))))
20999    });
21000
21001    // from_babylonian_time - convert Babylonian time to seconds
21002    define(interp, "from_babylonian_time", Some(1), |_, args| {
21003        let s = match &args[0] {
21004            Value::String(s) => s.to_string(),
21005            _ => return Err(RuntimeError::new("from_babylonian_time() requires string")),
21006        };
21007
21008        let clean = s
21009            .trim_start_matches("0s")
21010            .trim_start_matches('[')
21011            .trim_end_matches(']');
21012
21013        let parts: Vec<i64> = clean
21014            .split(':')
21015            .map(|p| p.trim().parse::<i64>().unwrap_or(0))
21016            .collect();
21017
21018        let seconds = match parts.len() {
21019            1 => parts[0],
21020            2 => parts[0] * 60 + parts[1],
21021            3 => parts[0] * 3600 + parts[1] * 60 + parts[2],
21022            _ => return Err(RuntimeError::new("Invalid Babylonian time format")),
21023        };
21024
21025        Ok(Value::Int(seconds))
21026    });
21027
21028    // === Multi-base secret sharing ===
21029
21030    // vigesimal_shares - split secret with shares in Mayan base-20
21031    define(interp, "vigesimal_shares", Some(3), |_, args| {
21032        let secret = match &args[0] {
21033            Value::String(s) => s.as_bytes().to_vec(),
21034            _ => {
21035                return Err(RuntimeError::new(
21036                    "vigesimal_shares() requires string secret",
21037                ))
21038            }
21039        };
21040
21041        let threshold = match &args[1] {
21042            Value::Int(n) => *n as usize,
21043            _ => {
21044                return Err(RuntimeError::new(
21045                    "vigesimal_shares() requires integer threshold",
21046                ))
21047            }
21048        };
21049
21050        let num_shares = match &args[2] {
21051            Value::Int(n) => *n as usize,
21052            _ => {
21053                return Err(RuntimeError::new(
21054                    "vigesimal_shares() requires integer num_shares",
21055                ))
21056            }
21057        };
21058
21059        if threshold < 2 || num_shares < threshold || num_shares > 20 {
21060            return Err(RuntimeError::new(
21061                "vigesimal_shares() requires 2 <= threshold <= num_shares <= 20 (Mayan limit)",
21062            ));
21063        }
21064
21065        // Generate shares using Shamir
21066        let mut rng = rand::thread_rng();
21067        let mut shares: Vec<Vec<u8>> = (0..num_shares)
21068            .map(|_| Vec::with_capacity(secret.len() + 1))
21069            .collect();
21070
21071        for (i, share) in shares.iter_mut().enumerate() {
21072            share.push((i + 1) as u8);
21073        }
21074
21075        for &byte in &secret {
21076            let mut coefficients: Vec<u8> = vec![byte];
21077            for _ in 1..threshold {
21078                coefficients.push(rng.gen());
21079            }
21080
21081            for (i, share) in shares.iter_mut().enumerate() {
21082                let x = (i + 1) as u8;
21083                let y = eval_polynomial_gf256(&coefficients, x);
21084                share.push(y);
21085            }
21086        }
21087
21088        // Encode shares in vigesimal
21089        let share_values: Vec<Value> = shares
21090            .iter()
21091            .enumerate()
21092            .map(|(i, share)| {
21093                let mut entry = std::collections::HashMap::new();
21094
21095                // Convert share bytes to vigesimal string
21096                let mut vig_parts: Vec<String> = Vec::new();
21097                for &byte in share {
21098                    vig_parts.push(to_base_string(byte as u64, 20, true));
21099                }
21100
21101                entry.insert("index".to_string(), Value::Int((i + 1) as i64));
21102                entry.insert(
21103                    "vigesimal".to_string(),
21104                    Value::String(Rc::new(format!("0v{}", vig_parts.join(".")))),
21105                );
21106                entry.insert(
21107                    "hex".to_string(),
21108                    Value::String(Rc::new(hex::encode(share))),
21109                );
21110
21111                Value::Map(Rc::new(RefCell::new(entry)))
21112            })
21113            .collect();
21114
21115        let mut result = std::collections::HashMap::new();
21116        result.insert(
21117            "shares".to_string(),
21118            Value::Array(Rc::new(RefCell::new(share_values))),
21119        );
21120        result.insert("threshold".to_string(), Value::Int(threshold as i64));
21121        result.insert("total".to_string(), Value::Int(num_shares as i64));
21122        result.insert(
21123            "base".to_string(),
21124            Value::String(Rc::new("vigesimal (Mayan base-20)".to_string())),
21125        );
21126
21127        Ok(Value::Map(Rc::new(RefCell::new(result))))
21128    });
21129
21130    // multibase_info - get information about supported bases
21131    define(interp, "multibase_info", Some(0), |_, _| {
21132        let mut info = std::collections::HashMap::new();
21133
21134        let bases = vec![
21135            ("binary", 2, "0b", "Modern computing"),
21136            ("octal", 8, "0o", "Unix, historical computing"),
21137            ("decimal", 10, "", "Indo-Arabic global standard"),
21138            (
21139                "duodecimal",
21140                12,
21141                "0z",
21142                "Dozen system - time, music, measurement",
21143            ),
21144            ("hexadecimal", 16, "0x", "Computing, colors, addresses"),
21145            (
21146                "vigesimal",
21147                20,
21148                "0v",
21149                "Mayan, Celtic, Basque - human digits",
21150            ),
21151            (
21152                "sexagesimal",
21153                60,
21154                "0s",
21155                "Babylonian - time, angles, astronomy",
21156            ),
21157        ];
21158
21159        let base_list: Vec<Value> = bases
21160            .iter()
21161            .map(|(name, base, prefix, desc)| {
21162                let mut entry = std::collections::HashMap::new();
21163                entry.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
21164                entry.insert("base".to_string(), Value::Int(*base as i64));
21165                entry.insert(
21166                    "prefix".to_string(),
21167                    Value::String(Rc::new(prefix.to_string())),
21168                );
21169                entry.insert(
21170                    "origin".to_string(),
21171                    Value::String(Rc::new(desc.to_string())),
21172                );
21173                Value::Map(Rc::new(RefCell::new(entry)))
21174            })
21175            .collect();
21176
21177        info.insert(
21178            "numeral_systems".to_string(),
21179            Value::Array(Rc::new(RefCell::new(base_list))),
21180        );
21181
21182        let encodings = vec!["base58 (Bitcoin)", "base32 (RFC 4648)", "base64 (standard)"];
21183        let enc_list: Vec<Value> = encodings
21184            .iter()
21185            .map(|s| Value::String(Rc::new(s.to_string())))
21186            .collect();
21187        info.insert(
21188            "special_encodings".to_string(),
21189            Value::Array(Rc::new(RefCell::new(enc_list))),
21190        );
21191
21192        let cultures = vec![
21193            "mayan",
21194            "babylonian",
21195            "chinese",
21196            "japanese",
21197            "hebrew",
21198            "islamic",
21199            "hindu",
21200            "greek",
21201            "celtic",
21202        ];
21203        let cult_list: Vec<Value> = cultures
21204            .iter()
21205            .map(|s| Value::String(Rc::new(s.to_string())))
21206            .collect();
21207        info.insert(
21208            "supported_cultures".to_string(),
21209            Value::Array(Rc::new(RefCell::new(cult_list))),
21210        );
21211
21212        Ok(Value::Map(Rc::new(RefCell::new(info))))
21213    });
21214}
21215
21216// Helper functions for base conversion
21217
21218fn to_base_string(mut n: u64, base: u64, pad_to_two: bool) -> String {
21219    const DIGITS: &[u8] = b"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
21220
21221    if n == 0 {
21222        return if pad_to_two {
21223            "00".to_string()
21224        } else {
21225            "0".to_string()
21226        };
21227    }
21228
21229    let mut result = Vec::new();
21230    while n > 0 {
21231        result.push(DIGITS[(n % base) as usize] as char);
21232        n /= base;
21233    }
21234
21235    if pad_to_two && result.len() < 2 {
21236        result.push('0');
21237    }
21238
21239    result.reverse();
21240    result.into_iter().collect()
21241}
21242
21243fn to_base_string_custom(mut n: u64, base: u64, digits: &str) -> String {
21244    if n == 0 {
21245        return digits.chars().next().unwrap().to_string();
21246    }
21247
21248    let mut result = Vec::new();
21249    let digit_chars: Vec<char> = digits.chars().collect();
21250
21251    while n > 0 {
21252        result.push(digit_chars[(n % base) as usize]);
21253        n /= base;
21254    }
21255
21256    result.reverse();
21257    result.into_iter().collect()
21258}
21259
21260fn from_base_string(s: &str, base: u64) -> Result<u64, RuntimeError> {
21261    let mut result: u64 = 0;
21262
21263    for c in s.chars() {
21264        let digit = match c {
21265            '0'..='9' => c as u64 - '0' as u64,
21266            'A'..='Z' => c as u64 - 'A' as u64 + 10,
21267            'a'..='z' => c as u64 - 'a' as u64 + 10,
21268            _ => return Err(RuntimeError::new(format!("Invalid digit: {}", c))),
21269        };
21270
21271        if digit >= base {
21272            return Err(RuntimeError::new(format!(
21273                "Digit {} out of range for base {}",
21274                c, base
21275            )));
21276        }
21277
21278        result = result
21279            .checked_mul(base)
21280            .and_then(|r| r.checked_add(digit))
21281            .ok_or_else(|| RuntimeError::new("Number overflow"))?;
21282    }
21283
21284    Ok(result)
21285}
21286
21287fn from_base_string_custom(s: &str, digits: &str) -> Result<u64, RuntimeError> {
21288    let base = digits.len() as u64;
21289    let mut result: u64 = 0;
21290
21291    for c in s.chars() {
21292        let digit = digits
21293            .find(c)
21294            .ok_or_else(|| RuntimeError::new(format!("Invalid digit: {}", c)))?
21295            as u64;
21296
21297        result = result
21298            .checked_mul(base)
21299            .and_then(|r| r.checked_add(digit))
21300            .ok_or_else(|| RuntimeError::new("Number overflow"))?;
21301    }
21302
21303    Ok(result)
21304}
21305
21306fn parse_base_prefix(s: &str, prefix: &str) -> (bool, String) {
21307    let negative = s.starts_with('-');
21308    let clean = s
21309        .trim_start_matches('-')
21310        .trim_start_matches(prefix)
21311        .to_string();
21312    (negative, clean)
21313}
21314
21315// ============================================================================
21316// POLYCULTURAL AUDIO: World tuning systems, sacred frequencies, synthesis
21317// ============================================================================
21318//
21319// Sigil's audio system respects that music is not universal - different cultures
21320// have fundamentally different relationships with pitch, scale, and meaning.
21321//
21322// Waveform Morphemes:
21323//   ∿  sine     - pure tone, fundamental
21324//   ⊓  square   - digital, odd harmonics
21325//   ⋀  sawtooth - bright, all harmonics
21326//   △  triangle - mellow, odd harmonics (weaker)
21327//
21328// Tuning Systems:
21329//   12-TET     - Western equal temperament (default)
21330//   24-TET     - Arabic maqam (quarter tones)
21331//   22-Shruti  - Indian classical (microtones)
21332//   Just       - Pure ratios (Pythagorean, etc.)
21333//   Gamelan    - Indonesian (pelog, slendro)
21334//   53-TET     - Turkish/Persian (commas)
21335//
21336// Sacred Frequencies:
21337//   ॐ Om       - 136.1 Hz (Earth year frequency)
21338//   Solfeggio  - 396, 417, 528, 639, 741, 852 Hz
21339//   Schumann   - 7.83 Hz (Earth resonance)
21340//   Planetary  - Kepler's music of the spheres
21341
21342fn register_audio(interp: &mut Interpreter) {
21343    // =========================================================================
21344    // TUNING SYSTEMS
21345    // =========================================================================
21346
21347    // tune - convert a note to frequency in a specific tuning system
21348    // Supports: "12tet", "24tet", "just", "pythagorean", "meantone", "gamelan_pelog", "gamelan_slendro"
21349    define(interp, "tune", Some(3), |_, args| {
21350        let note = match &args[0] {
21351            Value::Int(n) => *n as f64, // MIDI note number
21352            Value::Float(f) => *f,      // Fractional note
21353            Value::String(s) => parse_note_name(s)?,
21354            _ => return Err(RuntimeError::new("tune() requires note number or name")),
21355        };
21356
21357        let system = match &args[1] {
21358            Value::String(s) => s.to_lowercase(),
21359            _ => return Err(RuntimeError::new("tune() requires tuning system name")),
21360        };
21361
21362        let root_freq = match &args[2] {
21363            Value::Float(f) => *f,
21364            Value::Int(i) => *i as f64,
21365            _ => return Err(RuntimeError::new("tune() requires root frequency")),
21366        };
21367
21368        let freq = match system.as_str() {
21369            "12tet" | "equal" | "western" => {
21370                // Standard 12-tone equal temperament
21371                root_freq * 2.0_f64.powf((note - 69.0) / 12.0)
21372            }
21373            "24tet" | "quarter" | "arabic" | "maqam" => {
21374                // 24-tone equal temperament (quarter tones)
21375                root_freq * 2.0_f64.powf((note - 69.0) / 24.0)
21376            }
21377            "just" | "pure" => {
21378                // Just intonation ratios from root
21379                let interval = ((note - 69.0) % 12.0 + 12.0) % 12.0;
21380                let octave = ((note - 69.0) / 12.0).floor();
21381                let ratio = just_intonation_ratio(interval as i32);
21382                root_freq * ratio * 2.0_f64.powf(octave)
21383            }
21384            "pythagorean" => {
21385                // Pythagorean tuning (pure fifths)
21386                let interval = ((note - 69.0) % 12.0 + 12.0) % 12.0;
21387                let octave = ((note - 69.0) / 12.0).floor();
21388                let ratio = pythagorean_ratio(interval as i32);
21389                root_freq * ratio * 2.0_f64.powf(octave)
21390            }
21391            "meantone" | "quarter_comma" => {
21392                // Quarter-comma meantone
21393                let interval = ((note - 69.0) % 12.0 + 12.0) % 12.0;
21394                let octave = ((note - 69.0) / 12.0).floor();
21395                let ratio = meantone_ratio(interval as i32);
21396                root_freq * ratio * 2.0_f64.powf(octave)
21397            }
21398            "53tet" | "turkish" | "persian" | "comma" => {
21399                // 53-TET (Turkish/Persian music, approximates just intonation)
21400                root_freq * 2.0_f64.powf((note - 69.0) / 53.0)
21401            }
21402            "22shruti" | "shruti" | "indian" => {
21403                // Indian 22-shruti system
21404                let shruti = (note - 69.0) % 22.0;
21405                let octave = ((note - 69.0) / 22.0).floor();
21406                let ratio = shruti_ratio(shruti as i32);
21407                root_freq * ratio * 2.0_f64.powf(octave)
21408            }
21409            "gamelan_pelog" | "pelog" => {
21410                // Javanese pelog (7-note)
21411                let degree = ((note - 69.0) % 7.0 + 7.0) % 7.0;
21412                let octave = ((note - 69.0) / 7.0).floor();
21413                let ratio = pelog_ratio(degree as i32);
21414                root_freq * ratio * 2.0_f64.powf(octave)
21415            }
21416            "gamelan_slendro" | "slendro" => {
21417                // Javanese slendro (5-note, roughly equal)
21418                let degree = ((note - 69.0) % 5.0 + 5.0) % 5.0;
21419                let octave = ((note - 69.0) / 5.0).floor();
21420                let ratio = slendro_ratio(degree as i32);
21421                root_freq * ratio * 2.0_f64.powf(octave)
21422            }
21423            "bohlen_pierce" | "bp" => {
21424                // Bohlen-Pierce scale (tritave-based, 13 steps)
21425                root_freq * 3.0_f64.powf((note - 69.0) / 13.0)
21426            }
21427            _ => {
21428                return Err(RuntimeError::new(format!(
21429                    "Unknown tuning system: {}",
21430                    system
21431                )))
21432            }
21433        };
21434
21435        Ok(Value::Float(freq))
21436    });
21437
21438    // tuning_info - get information about a tuning system
21439    define(interp, "tuning_info", Some(1), |_, args| {
21440        let system = match &args[0] {
21441            Value::String(s) => s.to_lowercase(),
21442            _ => return Err(RuntimeError::new("tuning_info() requires string")),
21443        };
21444
21445        let (name, notes_per_octave, origin, description) = match system.as_str() {
21446            "12tet" | "equal" | "western" => (
21447                "12-TET", 12, "Western (18th century)",
21448                "Equal temperament - every semitone is exactly 2^(1/12). Universal but slightly impure."
21449            ),
21450            "24tet" | "quarter" | "arabic" | "maqam" => (
21451                "24-TET", 24, "Arabic/Turkish",
21452                "Quarter-tone system for maqam music. Enables neutral seconds and other microtones."
21453            ),
21454            "just" | "pure" => (
21455                "Just Intonation", 12, "Ancient (Ptolemy)",
21456                "Pure frequency ratios (3:2 fifth, 5:4 third). Beatless intervals but limited modulation."
21457            ),
21458            "pythagorean" => (
21459                "Pythagorean", 12, "Ancient Greece",
21460                "Built entirely from perfect fifths (3:2). Pure fifths but harsh thirds."
21461            ),
21462            "meantone" | "quarter_comma" => (
21463                "Quarter-Comma Meantone", 12, "Renaissance Europe",
21464                "Tempered fifths for pure major thirds. Beautiful in limited keys."
21465            ),
21466            "53tet" | "turkish" | "persian" | "comma" => (
21467                "53-TET", 53, "Turkish/Persian",
21468                "53 notes per octave. Closely approximates just intonation and allows maqam/dastgah."
21469            ),
21470            "22shruti" | "shruti" | "indian" => (
21471                "22-Shruti", 22, "Indian Classical",
21472                "Ancient Indian system. Each shruti is a 'microtone' - the smallest perceptible interval."
21473            ),
21474            "gamelan_pelog" | "pelog" => (
21475                "Pelog", 7, "Javanese Gamelan",
21476                "Heptatonic scale with unequal steps. Each gamelan has unique tuning - instruments are married."
21477            ),
21478            "gamelan_slendro" | "slendro" => (
21479                "Slendro", 5, "Javanese Gamelan",
21480                "Pentatonic scale, roughly equal steps (~240 cents). Each ensemble uniquely tuned."
21481            ),
21482            "bohlen_pierce" | "bp" => (
21483                "Bohlen-Pierce", 13, "Modern (1970s)",
21484                "Non-octave scale based on 3:1 tritave. Alien but mathematically beautiful."
21485            ),
21486            _ => return Err(RuntimeError::new(format!("Unknown tuning system: {}", system))),
21487        };
21488
21489        let mut info = std::collections::HashMap::new();
21490        info.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
21491        info.insert("notes_per_octave".to_string(), Value::Int(notes_per_octave));
21492        info.insert(
21493            "origin".to_string(),
21494            Value::String(Rc::new(origin.to_string())),
21495        );
21496        info.insert(
21497            "description".to_string(),
21498            Value::String(Rc::new(description.to_string())),
21499        );
21500
21501        Ok(Value::Map(Rc::new(RefCell::new(info))))
21502    });
21503
21504    // list_tuning_systems - list all available tuning systems
21505    define(interp, "list_tuning_systems", Some(0), |_, _| {
21506        let systems = vec![
21507            ("12tet", "Western equal temperament", 12),
21508            ("24tet", "Arabic/Turkish quarter-tones", 24),
21509            ("just", "Pure ratio just intonation", 12),
21510            ("pythagorean", "Ancient Greek pure fifths", 12),
21511            ("meantone", "Renaissance quarter-comma", 12),
21512            ("53tet", "Turkish/Persian comma system", 53),
21513            ("22shruti", "Indian microtonal", 22),
21514            ("pelog", "Javanese gamelan 7-note", 7),
21515            ("slendro", "Javanese gamelan 5-note", 5),
21516            ("bohlen_pierce", "Non-octave tritave scale", 13),
21517        ];
21518
21519        let result: Vec<Value> = systems
21520            .iter()
21521            .map(|(name, desc, notes)| {
21522                let mut entry = std::collections::HashMap::new();
21523                entry.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
21524                entry.insert(
21525                    "description".to_string(),
21526                    Value::String(Rc::new(desc.to_string())),
21527                );
21528                entry.insert("notes_per_octave".to_string(), Value::Int(*notes));
21529                Value::Map(Rc::new(RefCell::new(entry)))
21530            })
21531            .collect();
21532
21533        Ok(Value::Array(Rc::new(RefCell::new(result))))
21534    });
21535
21536    // =========================================================================
21537    // SACRED FREQUENCIES
21538    // =========================================================================
21539
21540    // sacred_freq - get sacred/spiritual frequency by name
21541    define(interp, "sacred_freq", Some(1), |_, args| {
21542        let name = match &args[0] {
21543            Value::String(s) => s.to_lowercase(),
21544            _ => return Err(RuntimeError::new("sacred_freq() requires string")),
21545        };
21546
21547        let (freq, description) = match name.as_str() {
21548            // Om and Earth frequencies
21549            "om" | "ॐ" | "aum" => (136.1, "Om - Earth year frequency (Cosmic Om)"),
21550            "earth_day" => (194.18, "Earth day - one rotation"),
21551            "earth_year" => (136.1, "Earth year - one orbit (Om frequency)"),
21552            "schumann" | "earth_resonance" => (
21553                7.83,
21554                "Schumann resonance - Earth's electromagnetic heartbeat",
21555            ),
21556
21557            // Solfeggio frequencies
21558            "ut" | "do" | "396" => (396.0, "UT/DO - Liberating guilt and fear"),
21559            "re" | "417" => (417.0, "RE - Undoing situations, facilitating change"),
21560            "mi" | "528" => (528.0, "MI - Transformation, miracles, DNA repair"),
21561            "fa" | "639" => (639.0, "FA - Connecting relationships"),
21562            "sol" | "741" => (741.0, "SOL - Awakening intuition"),
21563            "la" | "852" => (852.0, "LA - Returning to spiritual order"),
21564            "si" | "963" => (963.0, "SI - Divine consciousness, enlightenment"),
21565            "174" => (174.0, "Solfeggio foundation - pain relief"),
21566            "285" => (285.0, "Solfeggio - healing tissue"),
21567
21568            // Planetary frequencies (Kepler/Cousto)
21569            "sun" | "☉" => (126.22, "Sun - ego, vitality, leadership"),
21570            "moon" | "☽" | "☾" => (210.42, "Moon - emotion, intuition, cycles"),
21571            "mercury" | "☿" => (141.27, "Mercury - communication, intellect"),
21572            "venus" | "♀" => (221.23, "Venus - love, beauty, harmony"),
21573            "mars" | "♂" => (144.72, "Mars - energy, action, courage"),
21574            "jupiter" | "♃" => (183.58, "Jupiter - expansion, wisdom, luck"),
21575            "saturn" | "♄" => (147.85, "Saturn - discipline, structure, time"),
21576
21577            // Chakra frequencies
21578            "root" | "muladhara" => (256.0, "Root chakra - survival, grounding (C)"),
21579            "sacral" | "svadhisthana" => (288.0, "Sacral chakra - creativity, sexuality (D)"),
21580            "solar" | "manipura" => (320.0, "Solar plexus - will, power (E)"),
21581            "heart" | "anahata" => (341.3, "Heart chakra - love, compassion (F)"),
21582            "throat" | "vishuddha" => (384.0, "Throat chakra - expression, truth (G)"),
21583            "third_eye" | "ajna" => (426.7, "Third eye - intuition, insight (A)"),
21584            "crown" | "sahasrara" => (480.0, "Crown chakra - consciousness, unity (B)"),
21585
21586            // Concert pitch standards
21587            "a440" | "iso" => (440.0, "ISO standard concert pitch (1955)"),
21588            "a432" | "verdi" => (
21589                432.0,
21590                "Verdi pitch - 'mathematically consistent with universe'",
21591            ),
21592            "a415" | "baroque" => (415.0, "Baroque pitch - period instrument standard"),
21593            "a466" | "chorton" => (466.0, "Choir pitch - high Baroque German"),
21594
21595            // Binaural/brainwave
21596            "delta" => (2.0, "Delta waves - deep sleep, healing (0.5-4 Hz)"),
21597            "theta" => (6.0, "Theta waves - meditation, creativity (4-8 Hz)"),
21598            "alpha" => (10.0, "Alpha waves - relaxation, calm focus (8-13 Hz)"),
21599            "beta" => (20.0, "Beta waves - alertness, concentration (13-30 Hz)"),
21600            "gamma" => (40.0, "Gamma waves - insight, peak performance (30-100 Hz)"),
21601
21602            _ => {
21603                return Err(RuntimeError::new(format!(
21604                    "Unknown sacred frequency: {}",
21605                    name
21606                )))
21607            }
21608        };
21609
21610        let mut result = std::collections::HashMap::new();
21611        result.insert("frequency".to_string(), Value::Float(freq));
21612        result.insert("name".to_string(), Value::String(Rc::new(name)));
21613        result.insert(
21614            "meaning".to_string(),
21615            Value::String(Rc::new(description.to_string())),
21616        );
21617
21618        Ok(Value::Map(Rc::new(RefCell::new(result))))
21619    });
21620
21621    // solfeggio - get all solfeggio frequencies
21622    define(interp, "solfeggio", Some(0), |_, _| {
21623        let frequencies = vec![
21624            (174.0, "Foundation", "Pain relief, security"),
21625            (285.0, "Quantum", "Healing tissue, safety"),
21626            (396.0, "UT", "Liberating guilt and fear"),
21627            (417.0, "RE", "Undoing situations, change"),
21628            (528.0, "MI", "Transformation, DNA repair, miracles"),
21629            (639.0, "FA", "Connecting relationships"),
21630            (741.0, "SOL", "Awakening intuition"),
21631            (852.0, "LA", "Spiritual order"),
21632            (963.0, "SI", "Divine consciousness"),
21633        ];
21634
21635        let result: Vec<Value> = frequencies
21636            .iter()
21637            .map(|(freq, name, meaning)| {
21638                let mut entry = std::collections::HashMap::new();
21639                entry.insert("frequency".to_string(), Value::Float(*freq));
21640                entry.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
21641                entry.insert(
21642                    "meaning".to_string(),
21643                    Value::String(Rc::new(meaning.to_string())),
21644                );
21645                Value::Map(Rc::new(RefCell::new(entry)))
21646            })
21647            .collect();
21648
21649        Ok(Value::Array(Rc::new(RefCell::new(result))))
21650    });
21651
21652    // chakras - get all chakra frequencies
21653    define(interp, "chakras", Some(0), |_, _| {
21654        let chakras = vec![
21655            (
21656                256.0,
21657                "Muladhara",
21658                "Root",
21659                "Red",
21660                "Survival, grounding, stability",
21661            ),
21662            (
21663                288.0,
21664                "Svadhisthana",
21665                "Sacral",
21666                "Orange",
21667                "Creativity, sexuality, emotion",
21668            ),
21669            (
21670                320.0,
21671                "Manipura",
21672                "Solar Plexus",
21673                "Yellow",
21674                "Will, power, self-esteem",
21675            ),
21676            (
21677                341.3,
21678                "Anahata",
21679                "Heart",
21680                "Green",
21681                "Love, compassion, connection",
21682            ),
21683            (
21684                384.0,
21685                "Vishuddha",
21686                "Throat",
21687                "Blue",
21688                "Expression, truth, communication",
21689            ),
21690            (
21691                426.7,
21692                "Ajna",
21693                "Third Eye",
21694                "Indigo",
21695                "Intuition, insight, wisdom",
21696            ),
21697            (
21698                480.0,
21699                "Sahasrara",
21700                "Crown",
21701                "Violet",
21702                "Consciousness, unity, transcendence",
21703            ),
21704        ];
21705
21706        let result: Vec<Value> = chakras
21707            .iter()
21708            .map(|(freq, sanskrit, english, color, meaning)| {
21709                let mut entry = std::collections::HashMap::new();
21710                entry.insert("frequency".to_string(), Value::Float(*freq));
21711                entry.insert(
21712                    "sanskrit".to_string(),
21713                    Value::String(Rc::new(sanskrit.to_string())),
21714                );
21715                entry.insert(
21716                    "english".to_string(),
21717                    Value::String(Rc::new(english.to_string())),
21718                );
21719                entry.insert(
21720                    "color".to_string(),
21721                    Value::String(Rc::new(color.to_string())),
21722                );
21723                entry.insert(
21724                    "meaning".to_string(),
21725                    Value::String(Rc::new(meaning.to_string())),
21726                );
21727                Value::Map(Rc::new(RefCell::new(entry)))
21728            })
21729            .collect();
21730
21731        Ok(Value::Array(Rc::new(RefCell::new(result))))
21732    });
21733
21734    // =========================================================================
21735    // WAVEFORM GENERATION
21736    // =========================================================================
21737
21738    // Generate waveform samples - returns array of floats [-1.0, 1.0]
21739
21740    // sine - pure sine wave ∿
21741    define(interp, "sine", Some(3), |_, args| {
21742        generate_waveform(&args, |phase| phase.sin())
21743    });
21744
21745    // square - square wave ⊓
21746    define(interp, "square", Some(3), |_, args| {
21747        generate_waveform(&args, |phase| if phase.sin() >= 0.0 { 1.0 } else { -1.0 })
21748    });
21749
21750    // sawtooth - sawtooth wave ⋀
21751    define(interp, "sawtooth", Some(3), |_, args| {
21752        generate_waveform(&args, |phase| {
21753            let normalized = (phase / std::f64::consts::TAU).fract();
21754            2.0 * normalized - 1.0
21755        })
21756    });
21757
21758    // triangle - triangle wave △
21759    define(interp, "triangle", Some(3), |_, args| {
21760        generate_waveform(&args, |phase| {
21761            let normalized = (phase / std::f64::consts::TAU).fract();
21762            if normalized < 0.5 {
21763                4.0 * normalized - 1.0
21764            } else {
21765                3.0 - 4.0 * normalized
21766            }
21767        })
21768    });
21769
21770    // noise - white noise
21771    define(interp, "noise", Some(1), |_, args| {
21772        let samples = match &args[0] {
21773            Value::Int(n) => *n as usize,
21774            _ => return Err(RuntimeError::new("noise() requires integer sample count")),
21775        };
21776
21777        let mut rng = rand::thread_rng();
21778        let result: Vec<Value> = (0..samples)
21779            .map(|_| Value::Float(rng.gen::<f64>() * 2.0 - 1.0))
21780            .collect();
21781
21782        Ok(Value::Array(Rc::new(RefCell::new(result))))
21783    });
21784
21785    // =========================================================================
21786    // CULTURAL SCALES
21787    // =========================================================================
21788
21789    // scale - get scale degrees for a cultural scale
21790    define(interp, "scale", Some(1), |_, args| {
21791        let name = match &args[0] {
21792            Value::String(s) => s.to_lowercase(),
21793            _ => return Err(RuntimeError::new("scale() requires string")),
21794        };
21795
21796        let (intervals, origin, description) = match name.as_str() {
21797            // Western modes
21798            "major" | "ionian" => (
21799                vec![0, 2, 4, 5, 7, 9, 11],
21800                "Western",
21801                "Happy, bright, resolved",
21802            ),
21803            "minor" | "aeolian" => (
21804                vec![0, 2, 3, 5, 7, 8, 10],
21805                "Western",
21806                "Sad, dark, introspective",
21807            ),
21808            "dorian" => (
21809                vec![0, 2, 3, 5, 7, 9, 10],
21810                "Western/Jazz",
21811                "Minor with bright 6th",
21812            ),
21813            "phrygian" => (
21814                vec![0, 1, 3, 5, 7, 8, 10],
21815                "Western/Flamenco",
21816                "Spanish, exotic, tense",
21817            ),
21818            "lydian" => (
21819                vec![0, 2, 4, 6, 7, 9, 11],
21820                "Western",
21821                "Dreamy, floating, ethereal",
21822            ),
21823            "mixolydian" => (vec![0, 2, 4, 5, 7, 9, 10], "Western/Blues", "Bluesy major"),
21824            "locrian" => (vec![0, 1, 3, 5, 6, 8, 10], "Western", "Unstable, dissonant"),
21825
21826            // Pentatonic
21827            "pentatonic_major" => (vec![0, 2, 4, 7, 9], "Universal", "No dissonance, universal"),
21828            "pentatonic_minor" => (vec![0, 3, 5, 7, 10], "Universal", "Blues foundation"),
21829
21830            // Japanese
21831            "hirajoshi" => (vec![0, 2, 3, 7, 8], "Japanese", "Melancholic, mysterious"),
21832            "insen" => (vec![0, 1, 5, 7, 10], "Japanese", "Dark, zen, contemplative"),
21833            "iwato" => (vec![0, 1, 5, 6, 10], "Japanese", "Most dark and dissonant"),
21834            "kumoi" => (vec![0, 2, 3, 7, 9], "Japanese", "Gentle, peaceful"),
21835            "yo" => (vec![0, 2, 5, 7, 9], "Japanese", "Bright, folk, celebratory"),
21836
21837            // Arabic maqamat
21838            "hijaz" => (
21839                vec![0, 1, 4, 5, 7, 8, 11],
21840                "Arabic",
21841                "Exotic, Middle Eastern",
21842            ),
21843            "bayati" => (
21844                vec![0, 1.5 as i32, 3, 5, 7, 8, 10],
21845                "Arabic",
21846                "Quarter-tone, soulful",
21847            ),
21848            "rast" => (
21849                vec![0, 2, 3.5 as i32, 5, 7, 9, 10.5 as i32],
21850                "Arabic",
21851                "Foundation maqam",
21852            ),
21853            "saba" => (
21854                vec![0, 1.5 as i32, 3, 4, 5, 8, 10],
21855                "Arabic",
21856                "Sad, spiritual",
21857            ),
21858
21859            // Indian ragas (approximated to 12-TET)
21860            "bhairav" => (
21861                vec![0, 1, 4, 5, 7, 8, 11],
21862                "Indian",
21863                "Morning raga, devotional",
21864            ),
21865            "yaman" | "kalyan" => (vec![0, 2, 4, 6, 7, 9, 11], "Indian", "Evening, romantic"),
21866            "bhairavi" => (
21867                vec![0, 1, 3, 5, 7, 8, 10],
21868                "Indian",
21869                "Concluding raga, devotional",
21870            ),
21871            "todi" => (vec![0, 1, 3, 6, 7, 8, 11], "Indian", "Serious, pathos"),
21872            "marwa" => (vec![0, 1, 4, 6, 7, 9, 11], "Indian", "Evening, longing"),
21873
21874            // Blues
21875            "blues" => (vec![0, 3, 5, 6, 7, 10], "American", "Blue notes, soul"),
21876
21877            // Hungarian/Eastern European
21878            "hungarian_minor" => (vec![0, 2, 3, 6, 7, 8, 11], "Hungarian", "Gypsy, dramatic"),
21879            "romanian" => (vec![0, 2, 3, 6, 7, 9, 10], "Romanian", "Folk, energetic"),
21880
21881            // Jewish
21882            "ahava_raba" | "freygish" => (
21883                vec![0, 1, 4, 5, 7, 8, 10],
21884                "Jewish/Klezmer",
21885                "Cantorial, emotional",
21886            ),
21887            "mi_sheberach" => (vec![0, 2, 3, 6, 7, 9, 10], "Jewish", "Prayer mode"),
21888
21889            // Chinese
21890            "gong" => (vec![0, 2, 4, 7, 9], "Chinese", "Palace mode, major-like"),
21891            "shang" => (vec![0, 2, 5, 7, 9], "Chinese", "Merchant mode"),
21892            "jue" => (vec![0, 3, 5, 7, 10], "Chinese", "Angle mode"),
21893            "zhi" => (vec![0, 2, 5, 7, 10], "Chinese", "Emblem mode"),
21894            "yu" => (vec![0, 3, 5, 8, 10], "Chinese", "Wings mode, minor-like"),
21895
21896            // Indonesian
21897            "pelog" => (
21898                vec![0, 1, 3, 7, 8],
21899                "Javanese",
21900                "7-note unequal temperament",
21901            ),
21902            "slendro" => (vec![0, 2, 5, 7, 9], "Javanese", "5-note roughly equal"),
21903
21904            // Other
21905            "whole_tone" => (
21906                vec![0, 2, 4, 6, 8, 10],
21907                "Impressionist",
21908                "Dreamlike, no resolution",
21909            ),
21910            "chromatic" => (
21911                vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
21912                "Western",
21913                "All 12 notes",
21914            ),
21915            "diminished" => (vec![0, 2, 3, 5, 6, 8, 9, 11], "Jazz", "Symmetric, tense"),
21916            "augmented" => (vec![0, 3, 4, 7, 8, 11], "Jazz", "Symmetric, floating"),
21917
21918            _ => return Err(RuntimeError::new(format!("Unknown scale: {}", name))),
21919        };
21920
21921        let mut result = std::collections::HashMap::new();
21922        let intervals_values: Vec<Value> =
21923            intervals.iter().map(|&i| Value::Int(i as i64)).collect();
21924        result.insert(
21925            "intervals".to_string(),
21926            Value::Array(Rc::new(RefCell::new(intervals_values))),
21927        );
21928        result.insert(
21929            "origin".to_string(),
21930            Value::String(Rc::new(origin.to_string())),
21931        );
21932        result.insert(
21933            "character".to_string(),
21934            Value::String(Rc::new(description.to_string())),
21935        );
21936        result.insert("name".to_string(), Value::String(Rc::new(name)));
21937
21938        Ok(Value::Map(Rc::new(RefCell::new(result))))
21939    });
21940
21941    // list_scales - list all available scales grouped by culture
21942    define(interp, "list_scales", Some(0), |_, _| {
21943        let mut cultures = std::collections::HashMap::new();
21944
21945        cultures.insert(
21946            "western".to_string(),
21947            Value::Array(Rc::new(RefCell::new(vec![
21948                Value::String(Rc::new("major".to_string())),
21949                Value::String(Rc::new("minor".to_string())),
21950                Value::String(Rc::new("dorian".to_string())),
21951                Value::String(Rc::new("phrygian".to_string())),
21952                Value::String(Rc::new("lydian".to_string())),
21953                Value::String(Rc::new("mixolydian".to_string())),
21954                Value::String(Rc::new("locrian".to_string())),
21955            ]))),
21956        );
21957
21958        cultures.insert(
21959            "japanese".to_string(),
21960            Value::Array(Rc::new(RefCell::new(vec![
21961                Value::String(Rc::new("hirajoshi".to_string())),
21962                Value::String(Rc::new("insen".to_string())),
21963                Value::String(Rc::new("iwato".to_string())),
21964                Value::String(Rc::new("kumoi".to_string())),
21965                Value::String(Rc::new("yo".to_string())),
21966            ]))),
21967        );
21968
21969        cultures.insert(
21970            "arabic".to_string(),
21971            Value::Array(Rc::new(RefCell::new(vec![
21972                Value::String(Rc::new("hijaz".to_string())),
21973                Value::String(Rc::new("bayati".to_string())),
21974                Value::String(Rc::new("rast".to_string())),
21975                Value::String(Rc::new("saba".to_string())),
21976            ]))),
21977        );
21978
21979        cultures.insert(
21980            "indian".to_string(),
21981            Value::Array(Rc::new(RefCell::new(vec![
21982                Value::String(Rc::new("bhairav".to_string())),
21983                Value::String(Rc::new("yaman".to_string())),
21984                Value::String(Rc::new("bhairavi".to_string())),
21985                Value::String(Rc::new("todi".to_string())),
21986                Value::String(Rc::new("marwa".to_string())),
21987            ]))),
21988        );
21989
21990        cultures.insert(
21991            "chinese".to_string(),
21992            Value::Array(Rc::new(RefCell::new(vec![
21993                Value::String(Rc::new("gong".to_string())),
21994                Value::String(Rc::new("shang".to_string())),
21995                Value::String(Rc::new("jue".to_string())),
21996                Value::String(Rc::new("zhi".to_string())),
21997                Value::String(Rc::new("yu".to_string())),
21998            ]))),
21999        );
22000
22001        cultures.insert(
22002            "jewish".to_string(),
22003            Value::Array(Rc::new(RefCell::new(vec![
22004                Value::String(Rc::new("ahava_raba".to_string())),
22005                Value::String(Rc::new("mi_sheberach".to_string())),
22006            ]))),
22007        );
22008
22009        cultures.insert(
22010            "indonesian".to_string(),
22011            Value::Array(Rc::new(RefCell::new(vec![
22012                Value::String(Rc::new("pelog".to_string())),
22013                Value::String(Rc::new("slendro".to_string())),
22014            ]))),
22015        );
22016
22017        Ok(Value::Map(Rc::new(RefCell::new(cultures))))
22018    });
22019
22020    // =========================================================================
22021    // INTERVALS AND HARMONY
22022    // =========================================================================
22023
22024    // interval_ratio - get the frequency ratio for an interval
22025    define(interp, "interval_ratio", Some(2), |_, args| {
22026        let semitones = match &args[0] {
22027            Value::Int(n) => *n as f64,
22028            Value::Float(f) => *f,
22029            _ => return Err(RuntimeError::new("interval_ratio() requires number")),
22030        };
22031
22032        let tuning = match &args[1] {
22033            Value::String(s) => s.to_lowercase(),
22034            _ => return Err(RuntimeError::new("interval_ratio() requires tuning system")),
22035        };
22036
22037        let ratio = match tuning.as_str() {
22038            "12tet" | "equal" => 2.0_f64.powf(semitones / 12.0),
22039            "just" => just_intonation_ratio(semitones as i32),
22040            "pythagorean" => pythagorean_ratio(semitones as i32),
22041            _ => 2.0_f64.powf(semitones / 12.0),
22042        };
22043
22044        Ok(Value::Float(ratio))
22045    });
22046
22047    // cents_between - calculate cents between two frequencies
22048    define(interp, "cents_between", Some(2), |_, args| {
22049        let f1 = match &args[0] {
22050            Value::Float(f) => *f,
22051            Value::Int(i) => *i as f64,
22052            _ => return Err(RuntimeError::new("cents_between() requires numbers")),
22053        };
22054        let f2 = match &args[1] {
22055            Value::Float(f) => *f,
22056            Value::Int(i) => *i as f64,
22057            _ => return Err(RuntimeError::new("cents_between() requires numbers")),
22058        };
22059
22060        let cents = 1200.0 * (f2 / f1).log2();
22061        Ok(Value::Float(cents))
22062    });
22063
22064    // harmonic_series - generate harmonic series from fundamental
22065    define(interp, "harmonic_series", Some(2), |_, args| {
22066        let fundamental = match &args[0] {
22067            Value::Float(f) => *f,
22068            Value::Int(i) => *i as f64,
22069            _ => return Err(RuntimeError::new("harmonic_series() requires frequency")),
22070        };
22071        let count = match &args[1] {
22072            Value::Int(n) => *n as usize,
22073            _ => return Err(RuntimeError::new("harmonic_series() requires count")),
22074        };
22075
22076        let harmonics: Vec<Value> = (1..=count)
22077            .map(|n| {
22078                let mut entry = std::collections::HashMap::new();
22079                entry.insert("harmonic".to_string(), Value::Int(n as i64));
22080                entry.insert(
22081                    "frequency".to_string(),
22082                    Value::Float(fundamental * n as f64),
22083                );
22084                entry.insert(
22085                    "cents_from_root".to_string(),
22086                    Value::Float(1200.0 * (n as f64).log2()),
22087                );
22088                Value::Map(Rc::new(RefCell::new(entry)))
22089            })
22090            .collect();
22091
22092        Ok(Value::Array(Rc::new(RefCell::new(harmonics))))
22093    });
22094
22095    // =========================================================================
22096    // AUDIO INFO
22097    // =========================================================================
22098
22099    define(interp, "audio_info", Some(0), |_, _| {
22100        let mut info = std::collections::HashMap::new();
22101
22102        info.insert(
22103            "tuning_systems".to_string(),
22104            Value::Array(Rc::new(RefCell::new(vec![
22105                Value::String(Rc::new(
22106                    "12tet, 24tet, just, pythagorean, meantone".to_string(),
22107                )),
22108                Value::String(Rc::new(
22109                    "53tet, 22shruti, pelog, slendro, bohlen_pierce".to_string(),
22110                )),
22111            ]))),
22112        );
22113
22114        info.insert(
22115            "waveforms".to_string(),
22116            Value::Array(Rc::new(RefCell::new(vec![
22117                Value::String(Rc::new("sine (∿)".to_string())),
22118                Value::String(Rc::new("square (⊓)".to_string())),
22119                Value::String(Rc::new("sawtooth (⋀)".to_string())),
22120                Value::String(Rc::new("triangle (△)".to_string())),
22121                Value::String(Rc::new("noise".to_string())),
22122            ]))),
22123        );
22124
22125        info.insert(
22126            "sacred_frequencies".to_string(),
22127            Value::Array(Rc::new(RefCell::new(vec![
22128                Value::String(Rc::new("om, solfeggio, chakras, planets".to_string())),
22129                Value::String(Rc::new(
22130                    "schumann, brainwaves (delta/theta/alpha/beta/gamma)".to_string(),
22131                )),
22132            ]))),
22133        );
22134
22135        info.insert(
22136            "scale_cultures".to_string(),
22137            Value::Array(Rc::new(RefCell::new(vec![
22138                Value::String(Rc::new("western, japanese, arabic, indian".to_string())),
22139                Value::String(Rc::new("chinese, jewish, indonesian".to_string())),
22140            ]))),
22141        );
22142
22143        Ok(Value::Map(Rc::new(RefCell::new(info))))
22144    });
22145}
22146
22147// Helper functions for tuning systems
22148
22149fn parse_note_name(s: &str) -> Result<f64, RuntimeError> {
22150    let s = s.trim().to_uppercase();
22151    let (note, octave_offset) = if s.ends_with(|c: char| c.is_ascii_digit()) {
22152        let octave: i32 = s.chars().last().unwrap().to_digit(10).unwrap() as i32;
22153        let note_part = &s[..s.len() - 1];
22154        (note_part, (octave - 4) * 12) // Octave 4 = MIDI 60 area
22155    } else {
22156        (&s[..], 0)
22157    };
22158
22159    let semitone = match note {
22160        "C" => 0,
22161        "C#" | "DB" => 1,
22162        "D" => 2,
22163        "D#" | "EB" => 3,
22164        "E" => 4,
22165        "F" => 5,
22166        "F#" | "GB" => 6,
22167        "G" => 7,
22168        "G#" | "AB" => 8,
22169        "A" => 9,
22170        "A#" | "BB" => 10,
22171        "B" => 11,
22172        _ => return Err(RuntimeError::new(format!("Unknown note: {}", s))),
22173    };
22174
22175    Ok(69.0 + semitone as f64 - 9.0 + octave_offset as f64) // A4 = 69
22176}
22177
22178fn just_intonation_ratio(semitones: i32) -> f64 {
22179    // Classic 5-limit just intonation ratios
22180    match semitones.rem_euclid(12) {
22181        0 => 1.0,         // Unison
22182        1 => 16.0 / 15.0, // Minor second
22183        2 => 9.0 / 8.0,   // Major second
22184        3 => 6.0 / 5.0,   // Minor third
22185        4 => 5.0 / 4.0,   // Major third
22186        5 => 4.0 / 3.0,   // Perfect fourth
22187        6 => 45.0 / 32.0, // Tritone
22188        7 => 3.0 / 2.0,   // Perfect fifth
22189        8 => 8.0 / 5.0,   // Minor sixth
22190        9 => 5.0 / 3.0,   // Major sixth
22191        10 => 9.0 / 5.0,  // Minor seventh
22192        11 => 15.0 / 8.0, // Major seventh
22193        _ => 1.0,
22194    }
22195}
22196
22197fn pythagorean_ratio(semitones: i32) -> f64 {
22198    // Pythagorean tuning (pure fifths, 3:2 ratio)
22199    match semitones.rem_euclid(12) {
22200        0 => 1.0,
22201        1 => 256.0 / 243.0,
22202        2 => 9.0 / 8.0,
22203        3 => 32.0 / 27.0,
22204        4 => 81.0 / 64.0,
22205        5 => 4.0 / 3.0,
22206        6 => 729.0 / 512.0,
22207        7 => 3.0 / 2.0,
22208        8 => 128.0 / 81.0,
22209        9 => 27.0 / 16.0,
22210        10 => 16.0 / 9.0,
22211        11 => 243.0 / 128.0,
22212        _ => 1.0,
22213    }
22214}
22215
22216fn meantone_ratio(semitones: i32) -> f64 {
22217    // Quarter-comma meantone - fifths narrowed by 1/4 syntonic comma
22218    let fifth = 5.0_f64.powf(0.25); // Pure major third, tempered fifth
22219    match semitones.rem_euclid(12) {
22220        0 => 1.0,
22221        1 => 8.0 / (fifth.powi(5)),
22222        2 => fifth.powi(2) / 2.0,
22223        3 => 4.0 / (fifth.powi(3)),
22224        4 => fifth.powi(4) / 4.0,
22225        5 => 2.0 / fifth,
22226        6 => fifth.powi(6) / 8.0,
22227        7 => fifth,
22228        8 => 8.0 / (fifth.powi(4)),
22229        9 => fifth.powi(3) / 2.0,
22230        10 => 4.0 / (fifth.powi(2)),
22231        11 => fifth.powi(5) / 4.0,
22232        _ => 1.0,
22233    }
22234}
22235
22236fn shruti_ratio(shruti: i32) -> f64 {
22237    // 22 shruti ratios (traditional Indian)
22238    let ratios = [
22239        1.0,
22240        256.0 / 243.0,
22241        16.0 / 15.0,
22242        10.0 / 9.0,
22243        9.0 / 8.0,
22244        32.0 / 27.0,
22245        6.0 / 5.0,
22246        5.0 / 4.0,
22247        81.0 / 64.0,
22248        4.0 / 3.0,
22249        27.0 / 20.0,
22250        45.0 / 32.0,
22251        729.0 / 512.0,
22252        3.0 / 2.0,
22253        128.0 / 81.0,
22254        8.0 / 5.0,
22255        5.0 / 3.0,
22256        27.0 / 16.0,
22257        16.0 / 9.0,
22258        9.0 / 5.0,
22259        15.0 / 8.0,
22260        243.0 / 128.0,
22261    ];
22262    ratios[shruti.rem_euclid(22) as usize]
22263}
22264
22265fn pelog_ratio(degree: i32) -> f64 {
22266    // Approximate pelog ratios (varies by gamelan)
22267    let ratios = [1.0, 1.12, 1.26, 1.5, 1.68, 1.89, 2.12];
22268    ratios[degree.rem_euclid(7) as usize]
22269}
22270
22271fn slendro_ratio(degree: i32) -> f64 {
22272    // Approximate slendro ratios (roughly equal ~240 cents)
22273    let ratios = [1.0, 1.148, 1.318, 1.516, 1.741];
22274    ratios[degree.rem_euclid(5) as usize]
22275}
22276
22277fn generate_waveform(args: &[Value], wave_fn: fn(f64) -> f64) -> Result<Value, RuntimeError> {
22278    let freq = match &args[0] {
22279        Value::Float(f) => *f,
22280        Value::Int(i) => *i as f64,
22281        _ => return Err(RuntimeError::new("Waveform requires frequency")),
22282    };
22283    let sample_rate = match &args[1] {
22284        Value::Float(f) => *f as usize,
22285        Value::Int(i) => *i as usize,
22286        _ => return Err(RuntimeError::new("Waveform requires sample rate")),
22287    };
22288    let duration = match &args[2] {
22289        Value::Float(f) => *f,
22290        Value::Int(i) => *i as f64,
22291        _ => return Err(RuntimeError::new("Waveform requires duration")),
22292    };
22293
22294    let num_samples = (sample_rate as f64 * duration) as usize;
22295    let samples: Vec<Value> = (0..num_samples)
22296        .map(|i| {
22297            let t = i as f64 / sample_rate as f64;
22298            let phase = 2.0 * std::f64::consts::PI * freq * t;
22299            Value::Float(wave_fn(phase))
22300        })
22301        .collect();
22302
22303    Ok(Value::Array(Rc::new(RefCell::new(samples))))
22304}
22305
22306// ============================================================================
22307// SPIRITUALITY: Divination, sacred geometry, gematria, archetypes
22308// ============================================================================
22309//
22310// This module treats computation as potentially sacred - numbers have meaning,
22311// patterns have significance, and randomness can be oracle.
22312//
22313// I Ching Trigrams:
22314//   ☰ Heaven (乾)  ☱ Lake (兌)   ☲ Fire (離)   ☳ Thunder (震)
22315//   ☴ Wind (巽)    ☵ Water (坎)  ☶ Mountain (艮) ☷ Earth (坤)
22316//
22317// Sacred Geometry:
22318//   φ = 1.618033... (Golden Ratio)
22319//   √φ, φ², 1/φ (related constants)
22320//   Fibonacci sequence
22321//   Platonic solid relationships
22322//
22323// Gematria Systems:
22324//   Hebrew (Kabbalah), Greek (Isopsephy), Arabic (Abjad)
22325//   Each letter is a number; words have numerical souls
22326
22327fn register_spirituality(interp: &mut Interpreter) {
22328    // =========================================================================
22329    // I CHING - Book of Changes
22330    // =========================================================================
22331
22332    // The 8 trigrams
22333    const TRIGRAMS: [(&str, &str, &str, &str, &str); 8] = [
22334        (
22335            "☰",
22336            "乾",
22337            "Heaven",
22338            "Creative",
22339            "strong, initiating, persisting",
22340        ),
22341        (
22342            "☱",
22343            "兌",
22344            "Lake",
22345            "Joyous",
22346            "pleasure, satisfaction, openness",
22347        ),
22348        (
22349            "☲",
22350            "離",
22351            "Fire",
22352            "Clinging",
22353            "clarity, awareness, dependence",
22354        ),
22355        (
22356            "☳",
22357            "震",
22358            "Thunder",
22359            "Arousing",
22360            "movement, initiative, action",
22361        ),
22362        (
22363            "☴",
22364            "巽",
22365            "Wind",
22366            "Gentle",
22367            "penetrating, following, flexible",
22368        ),
22369        ("☵", "坎", "Water", "Abysmal", "danger, flowing, depth"),
22370        (
22371            "☶",
22372            "艮",
22373            "Mountain",
22374            "Keeping Still",
22375            "stopping, resting, meditation",
22376        ),
22377        (
22378            "☷",
22379            "坤",
22380            "Earth",
22381            "Receptive",
22382            "yielding, nurturing, devoted",
22383        ),
22384    ];
22385
22386    // trigram - get trigram information
22387    define(interp, "trigram", Some(1), |_, args| {
22388        let input = match &args[0] {
22389            Value::Int(n) => (*n as usize).min(7),
22390            Value::String(s) => match s.as_str() {
22391                "☰" | "heaven" | "qian" | "乾" => 0,
22392                "☱" | "lake" | "dui" | "兌" => 1,
22393                "☲" | "fire" | "li" | "離" => 2,
22394                "☳" | "thunder" | "zhen" | "震" => 3,
22395                "☴" | "wind" | "xun" | "巽" => 4,
22396                "☵" | "water" | "kan" | "坎" => 5,
22397                "☶" | "mountain" | "gen" | "艮" => 6,
22398                "☷" | "earth" | "kun" | "坤" => 7,
22399                _ => return Err(RuntimeError::new(format!("Unknown trigram: {}", s))),
22400            },
22401            _ => return Err(RuntimeError::new("trigram() requires number or name")),
22402        };
22403
22404        let (symbol, chinese, english, name, meaning) = TRIGRAMS[input];
22405
22406        let mut result = std::collections::HashMap::new();
22407        result.insert("number".to_string(), Value::Int(input as i64));
22408        result.insert(
22409            "symbol".to_string(),
22410            Value::String(Rc::new(symbol.to_string())),
22411        );
22412        result.insert(
22413            "chinese".to_string(),
22414            Value::String(Rc::new(chinese.to_string())),
22415        );
22416        result.insert(
22417            "english".to_string(),
22418            Value::String(Rc::new(english.to_string())),
22419        );
22420        result.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
22421        result.insert(
22422            "meaning".to_string(),
22423            Value::String(Rc::new(meaning.to_string())),
22424        );
22425
22426        // Binary representation (yang=1, yin=0)
22427        let binary = match input {
22428            0 => "111", // ☰
22429            1 => "110", // ☱
22430            2 => "101", // ☲
22431            3 => "100", // ☳
22432            4 => "011", // ☴
22433            5 => "010", // ☵
22434            6 => "001", // ☶
22435            7 => "000", // ☷
22436            _ => "000",
22437        };
22438        result.insert(
22439            "binary".to_string(),
22440            Value::String(Rc::new(binary.to_string())),
22441        );
22442
22443        Ok(Value::Map(Rc::new(RefCell::new(result))))
22444    });
22445
22446    // hexagram - get one of 64 I Ching hexagrams
22447    define(interp, "hexagram", Some(1), |_, args| {
22448        let num = match &args[0] {
22449            Value::Int(n) => ((*n - 1) as usize).min(63),
22450            _ => return Err(RuntimeError::new("hexagram() requires number 1-64")),
22451        };
22452
22453        let hex = &HEXAGRAMS[num];
22454
22455        let mut result = std::collections::HashMap::new();
22456        result.insert("number".to_string(), Value::Int((num + 1) as i64));
22457        result.insert(
22458            "chinese".to_string(),
22459            Value::String(Rc::new(hex.0.to_string())),
22460        );
22461        result.insert(
22462            "pinyin".to_string(),
22463            Value::String(Rc::new(hex.1.to_string())),
22464        );
22465        result.insert(
22466            "english".to_string(),
22467            Value::String(Rc::new(hex.2.to_string())),
22468        );
22469        result.insert(
22470            "judgment".to_string(),
22471            Value::String(Rc::new(hex.3.to_string())),
22472        );
22473        result.insert(
22474            "upper_trigram".to_string(),
22475            Value::String(Rc::new(hex.4.to_string())),
22476        );
22477        result.insert(
22478            "lower_trigram".to_string(),
22479            Value::String(Rc::new(hex.5.to_string())),
22480        );
22481
22482        Ok(Value::Map(Rc::new(RefCell::new(result))))
22483    });
22484
22485    // cast_iching - divine using I Ching (uses randomness as oracle)
22486    define(interp, "cast_iching", Some(0), |_, _| {
22487        let mut rng = rand::thread_rng();
22488
22489        // Traditional yarrow stalk method produces numbers 6,7,8,9
22490        // 6 = old yin (changing), 7 = young yang, 8 = young yin, 9 = old yang (changing)
22491        let mut lines = Vec::new();
22492        let mut hexagram_num = 0u8;
22493        let mut changing_lines = Vec::new();
22494
22495        for i in 0..6 {
22496            // Simulate yarrow stalk probabilities
22497            let r: f64 = rng.gen();
22498            let line = if r < 0.0625 {
22499                6
22500            }
22501            // 1/16 - old yin
22502            else if r < 0.3125 {
22503                7
22504            }
22505            // 5/16 - young yang
22506            else if r < 0.5625 {
22507                8
22508            }
22509            // 5/16 - young yin
22510            else {
22511                9
22512            }; // 5/16 - old yang
22513
22514            let is_yang = line == 7 || line == 9;
22515            if is_yang {
22516                hexagram_num |= 1 << i;
22517            }
22518
22519            if line == 6 || line == 9 {
22520                changing_lines.push(i + 1);
22521            }
22522
22523            lines.push(Value::Int(line));
22524        }
22525
22526        // Convert to King Wen sequence
22527        let king_wen_num = binary_to_king_wen(hexagram_num) + 1;
22528        let hex = &HEXAGRAMS[(king_wen_num - 1) as usize];
22529
22530        let mut result = std::collections::HashMap::new();
22531        result.insert("hexagram".to_string(), Value::Int(king_wen_num as i64));
22532        result.insert(
22533            "chinese".to_string(),
22534            Value::String(Rc::new(hex.0.to_string())),
22535        );
22536        result.insert(
22537            "english".to_string(),
22538            Value::String(Rc::new(hex.2.to_string())),
22539        );
22540        result.insert(
22541            "judgment".to_string(),
22542            Value::String(Rc::new(hex.3.to_string())),
22543        );
22544        result.insert(
22545            "lines".to_string(),
22546            Value::Array(Rc::new(RefCell::new(lines))),
22547        );
22548
22549        let changing: Vec<Value> = changing_lines.iter().map(|&n| Value::Int(n)).collect();
22550        result.insert(
22551            "changing_lines".to_string(),
22552            Value::Array(Rc::new(RefCell::new(changing))),
22553        );
22554
22555        // Calculate resulting hexagram if there are changing lines
22556        if !changing_lines.is_empty() {
22557            let mut result_hex = hexagram_num;
22558            for &line in &changing_lines {
22559                result_hex ^= 1 << (line - 1); // Flip the changing lines
22560            }
22561            let result_king_wen = binary_to_king_wen(result_hex) + 1;
22562            result.insert(
22563                "transforms_to".to_string(),
22564                Value::Int(result_king_wen as i64),
22565            );
22566        }
22567
22568        Ok(Value::Map(Rc::new(RefCell::new(result))))
22569    });
22570
22571    // =========================================================================
22572    // SACRED GEOMETRY
22573    // =========================================================================
22574
22575    // phi - Golden Ratio
22576    define(interp, "phi", Some(0), |_, _| {
22577        Ok(Value::Float((1.0 + 5.0_f64.sqrt()) / 2.0))
22578    });
22579
22580    // sacred_ratio - get various sacred ratios
22581    define(interp, "sacred_ratio", Some(1), |_, args| {
22582        let name = match &args[0] {
22583            Value::String(s) => s.to_lowercase(),
22584            _ => return Err(RuntimeError::new("sacred_ratio() requires string")),
22585        };
22586
22587        let (value, symbol, meaning) = match name.as_str() {
22588            "phi" | "φ" | "golden" => (
22589                (1.0 + 5.0_f64.sqrt()) / 2.0,
22590                "φ",
22591                "Golden Ratio - divine proportion found in nature, art, architecture",
22592            ),
22593            "phi_conjugate" | "1/phi" => (
22594                2.0 / (1.0 + 5.0_f64.sqrt()),
22595                "1/φ",
22596                "Golden Ratio conjugate - φ - 1 = 1/φ",
22597            ),
22598            "phi_squared" | "phi2" => (
22599                ((1.0 + 5.0_f64.sqrt()) / 2.0).powi(2),
22600                "φ²",
22601                "Golden Ratio squared - φ + 1 = φ²",
22602            ),
22603            "sqrt_phi" => (
22604                ((1.0 + 5.0_f64.sqrt()) / 2.0).sqrt(),
22605                "√φ",
22606                "Square root of Golden Ratio",
22607            ),
22608            "pi" | "π" => (
22609                std::f64::consts::PI,
22610                "π",
22611                "Circle constant - circumference/diameter, transcendental",
22612            ),
22613            "tau" | "τ" => (
22614                std::f64::consts::TAU,
22615                "τ",
22616                "Full circle constant - 2π, one complete revolution",
22617            ),
22618            "e" | "euler" => (
22619                std::f64::consts::E,
22620                "e",
22621                "Euler's number - natural growth, compound interest",
22622            ),
22623            "sqrt2" | "√2" | "pythagoras" => (
22624                std::f64::consts::SQRT_2,
22625                "√2",
22626                "Pythagorean constant - diagonal of unit square",
22627            ),
22628            "sqrt3" | "√3" | "vesica" => (
22629                3.0_f64.sqrt(),
22630                "√3",
22631                "Vesica Piscis ratio - sacred geometry foundation",
22632            ),
22633            "sqrt5" | "√5" => (
22634                5.0_f64.sqrt(),
22635                "√5",
22636                "Related to Golden Ratio: φ = (1 + √5) / 2",
22637            ),
22638            "silver" | "δs" => (
22639                1.0 + 2.0_f64.sqrt(),
22640                "δs",
22641                "Silver Ratio - related to octagon",
22642            ),
22643            "plastic" | "ρ" => (
22644                1.324717957244746,
22645                "ρ",
22646                "Plastic Number - smallest Pisot number",
22647            ),
22648            "feigenbaum" | "δ" => (
22649                4.669201609102990,
22650                "δ",
22651                "Feigenbaum constant - chaos theory, period doubling",
22652            ),
22653            _ => return Err(RuntimeError::new(format!("Unknown sacred ratio: {}", name))),
22654        };
22655
22656        let mut result = std::collections::HashMap::new();
22657        result.insert("value".to_string(), Value::Float(value));
22658        result.insert(
22659            "symbol".to_string(),
22660            Value::String(Rc::new(symbol.to_string())),
22661        );
22662        result.insert(
22663            "meaning".to_string(),
22664            Value::String(Rc::new(meaning.to_string())),
22665        );
22666
22667        Ok(Value::Map(Rc::new(RefCell::new(result))))
22668    });
22669
22670    // fibonacci - generate Fibonacci sequence
22671    define(interp, "fibonacci", Some(1), |_, args| {
22672        let count = match &args[0] {
22673            Value::Int(n) => *n as usize,
22674            _ => return Err(RuntimeError::new("fibonacci() requires count")),
22675        };
22676
22677        let mut seq = Vec::with_capacity(count);
22678        let (mut a, mut b) = (0i64, 1i64);
22679
22680        for _ in 0..count {
22681            seq.push(Value::Int(a));
22682            let next = a.saturating_add(b);
22683            a = b;
22684            b = next;
22685        }
22686
22687        Ok(Value::Array(Rc::new(RefCell::new(seq))))
22688    });
22689
22690    // is_fibonacci - check if a number is in the Fibonacci sequence
22691    define(interp, "is_fibonacci", Some(1), |_, args| {
22692        let n = match &args[0] {
22693            Value::Int(n) => *n,
22694            _ => return Err(RuntimeError::new("is_fibonacci() requires integer")),
22695        };
22696
22697        // A number is Fibonacci iff one of (5n² + 4) or (5n² - 4) is a perfect square
22698        fn is_perfect_square(n: i64) -> bool {
22699            if n < 0 {
22700                return false;
22701            }
22702            let root = (n as f64).sqrt() as i64;
22703            root * root == n
22704        }
22705
22706        let n_sq = n.saturating_mul(n);
22707        let test1 = 5i64.saturating_mul(n_sq).saturating_add(4);
22708        let test2 = 5i64.saturating_mul(n_sq).saturating_sub(4);
22709
22710        Ok(Value::Bool(
22711            is_perfect_square(test1) || is_perfect_square(test2),
22712        ))
22713    });
22714
22715    // platonic_solid - get information about Platonic solids
22716    define(interp, "platonic_solid", Some(1), |_, args| {
22717        let name = match &args[0] {
22718            Value::String(s) => s.to_lowercase(),
22719            _ => return Err(RuntimeError::new("platonic_solid() requires string")),
22720        };
22721
22722        let (faces, vertices, edges, face_shape, element, meaning) = match name.as_str() {
22723            "tetrahedron" | "fire" => (
22724                4,
22725                4,
22726                6,
22727                "triangle",
22728                "Fire",
22729                "Sharpness, heat, transformation",
22730            ),
22731            "cube" | "hexahedron" | "earth" => (
22732                6,
22733                8,
22734                12,
22735                "square",
22736                "Earth",
22737                "Stability, grounding, material",
22738            ),
22739            "octahedron" | "air" => (
22740                8,
22741                6,
22742                12,
22743                "triangle",
22744                "Air",
22745                "Balance, intellect, communication",
22746            ),
22747            "dodecahedron" | "aether" | "spirit" => (
22748                12,
22749                20,
22750                30,
22751                "pentagon",
22752                "Aether/Spirit",
22753                "The cosmos, divine thought",
22754            ),
22755            "icosahedron" | "water" => (
22756                20,
22757                12,
22758                30,
22759                "triangle",
22760                "Water",
22761                "Flow, emotion, adaptability",
22762            ),
22763            _ => {
22764                return Err(RuntimeError::new(format!(
22765                    "Unknown Platonic solid: {}",
22766                    name
22767                )))
22768            }
22769        };
22770
22771        let mut result = std::collections::HashMap::new();
22772        result.insert("name".to_string(), Value::String(Rc::new(name)));
22773        result.insert("faces".to_string(), Value::Int(faces));
22774        result.insert("vertices".to_string(), Value::Int(vertices));
22775        result.insert("edges".to_string(), Value::Int(edges));
22776        result.insert(
22777            "face_shape".to_string(),
22778            Value::String(Rc::new(face_shape.to_string())),
22779        );
22780        result.insert(
22781            "element".to_string(),
22782            Value::String(Rc::new(element.to_string())),
22783        );
22784        result.insert(
22785            "meaning".to_string(),
22786            Value::String(Rc::new(meaning.to_string())),
22787        );
22788
22789        // Euler's formula: V - E + F = 2
22790        result.insert("euler_characteristic".to_string(), Value::Int(2));
22791
22792        Ok(Value::Map(Rc::new(RefCell::new(result))))
22793    });
22794
22795    // =========================================================================
22796    // GEMATRIA - Letter-Number Correspondences
22797    // =========================================================================
22798
22799    // gematria - calculate numerical value of text
22800    define(interp, "gematria", Some(2), |_, args| {
22801        let text = match &args[0] {
22802            Value::String(s) => s.to_string(),
22803            _ => return Err(RuntimeError::new("gematria() requires string")),
22804        };
22805
22806        let system = match &args[1] {
22807            Value::String(s) => s.to_lowercase(),
22808            _ => return Err(RuntimeError::new("gematria() requires system name")),
22809        };
22810
22811        let total: i64 = match system.as_str() {
22812            "hebrew" | "kabbalah" => text.chars().map(|c| hebrew_gematria(c)).sum(),
22813            "greek" | "isopsephy" => text.chars().map(|c| greek_isopsephy(c)).sum(),
22814            "arabic" | "abjad" => text.chars().map(|c| arabic_abjad(c)).sum(),
22815            "english" | "simple" => {
22816                // Simple English: A=1, B=2, ... Z=26
22817                text.to_uppercase()
22818                    .chars()
22819                    .filter_map(|c| {
22820                        if c.is_ascii_alphabetic() {
22821                            Some((c as i64) - ('A' as i64) + 1)
22822                        } else {
22823                            None
22824                        }
22825                    })
22826                    .sum()
22827            }
22828            "english_ordinal" => {
22829                // Same as simple
22830                text.to_uppercase()
22831                    .chars()
22832                    .filter_map(|c| {
22833                        if c.is_ascii_alphabetic() {
22834                            Some((c as i64) - ('A' as i64) + 1)
22835                        } else {
22836                            None
22837                        }
22838                    })
22839                    .sum()
22840            }
22841            "english_reduction" => {
22842                // Reduce each letter: A=1, B=2, ... I=9, J=1, K=2, etc.
22843                text.to_uppercase()
22844                    .chars()
22845                    .filter_map(|c| {
22846                        if c.is_ascii_alphabetic() {
22847                            let val = ((c as i64) - ('A' as i64)) % 9 + 1;
22848                            Some(val)
22849                        } else {
22850                            None
22851                        }
22852                    })
22853                    .sum()
22854            }
22855            _ => {
22856                return Err(RuntimeError::new(format!(
22857                    "Unknown gematria system: {}",
22858                    system
22859                )))
22860            }
22861        };
22862
22863        let mut result = std::collections::HashMap::new();
22864        result.insert("text".to_string(), Value::String(Rc::new(text)));
22865        result.insert("system".to_string(), Value::String(Rc::new(system)));
22866        result.insert("value".to_string(), Value::Int(total));
22867
22868        // Digital root (reduce to single digit)
22869        let mut digital_root = total;
22870        while digital_root > 9 {
22871            digital_root = digital_root
22872                .to_string()
22873                .chars()
22874                .filter_map(|c| c.to_digit(10))
22875                .map(|d| d as i64)
22876                .sum();
22877        }
22878        result.insert("digital_root".to_string(), Value::Int(digital_root));
22879
22880        Ok(Value::Map(Rc::new(RefCell::new(result))))
22881    });
22882
22883    // gematria_match - find words with same gematria value
22884    define(interp, "gematria_match", Some(2), |_, args| {
22885        let value = match &args[0] {
22886            Value::Int(n) => *n,
22887            _ => return Err(RuntimeError::new("gematria_match() requires integer value")),
22888        };
22889
22890        let system = match &args[1] {
22891            Value::String(s) => s.to_lowercase(),
22892            _ => return Err(RuntimeError::new("gematria_match() requires system name")),
22893        };
22894
22895        // Return known significant matches for common values
22896        let matches = match (value, system.as_str()) {
22897            (26, "hebrew") => vec!["יהוה (YHWH - Tetragrammaton)"],
22898            (18, "hebrew") => vec!["חי (Chai - Life)"],
22899            (86, "hebrew") => vec!["אלהים (Elohim - God)"],
22900            (72, "hebrew") => vec!["חסד (Chesed - Loving-kindness)"],
22901            (93, "english") => vec!["Love", "Will", "Thelema"],
22902            (666, "greek") => vec!["Nero Caesar (in Hebrew letters)"],
22903            (888, "greek") => vec!["Ἰησοῦς (Jesus)"],
22904            _ => vec![],
22905        };
22906
22907        let match_values: Vec<Value> = matches
22908            .iter()
22909            .map(|s| Value::String(Rc::new(s.to_string())))
22910            .collect();
22911
22912        Ok(Value::Array(Rc::new(RefCell::new(match_values))))
22913    });
22914
22915    // =========================================================================
22916    // ARCHETYPES (Jung)
22917    // =========================================================================
22918
22919    // archetype - get information about Jungian archetypes
22920    define(interp, "archetype", Some(1), |_, args| {
22921        let name = match &args[0] {
22922            Value::String(s) => s.to_lowercase(),
22923            _ => return Err(RuntimeError::new("archetype() requires string")),
22924        };
22925
22926        let (description, shadow, gift, challenge) = match name.as_str() {
22927            // Core archetypes
22928            "self" => (
22929                "The unified conscious and unconscious, the goal of individuation",
22930                "Inflation or deflation of ego",
22931                "Wholeness, integration, meaning",
22932                "Integrating all aspects of psyche",
22933            ),
22934            "shadow" => (
22935                "The unconscious aspect containing repressed weaknesses and instincts",
22936                "Projection onto others, denial",
22937                "Creativity, spontaneity, insight",
22938                "Acknowledging and integrating darkness",
22939            ),
22940            "anima" => (
22941                "The feminine inner personality in a man's unconscious",
22942                "Moodiness, seduction, possession",
22943                "Relatedness, creativity, soul connection",
22944                "Developing emotional intelligence",
22945            ),
22946            "animus" => (
22947                "The masculine inner personality in a woman's unconscious",
22948                "Brutality, reckless action, opinionation",
22949                "Courage, initiative, spiritual depth",
22950                "Developing assertiveness with wisdom",
22951            ),
22952            "persona" => (
22953                "The social mask, the face we present to the world",
22954                "Over-identification, inauthenticity",
22955                "Social adaptation, professional competence",
22956                "Maintaining authenticity within role",
22957            ),
22958
22959            // Major archetypes
22960            "hero" => (
22961                "The courageous one who overcomes obstacles and achieves great deeds",
22962                "Arrogance, ruthlessness, eternal battle",
22963                "Courage, perseverance, accomplishment",
22964                "Knowing when to fight and when to surrender",
22965            ),
22966            "sage" | "wise_old_man" => (
22967                "The wise figure who offers guidance and insight",
22968                "Dogmatism, disconnection, ivory tower",
22969                "Wisdom, knowledge, truth-seeking",
22970                "Applying wisdom practically",
22971            ),
22972            "magician" | "wizard" => (
22973                "The transformer who makes things happen through understanding laws",
22974                "Manipulation, disconnection from ethics",
22975                "Transformation, vision, manifestation",
22976                "Using power responsibly",
22977            ),
22978            "lover" => (
22979                "The one who pursues connection, beauty, and passion",
22980                "Obsession, jealousy, loss of identity",
22981                "Passion, commitment, appreciation",
22982                "Maintaining boundaries while connecting deeply",
22983            ),
22984            "caregiver" | "mother" => (
22985                "The nurturing one who protects and provides",
22986                "Martyrdom, enabling, smothering",
22987                "Compassion, generosity, nurturing",
22988                "Caring for self while caring for others",
22989            ),
22990            "ruler" | "king" | "queen" => (
22991                "The one who takes responsibility for the realm",
22992                "Tyranny, authoritarianism, being overthrown",
22993                "Order, leadership, prosperity",
22994                "Serving the greater good, not just power",
22995            ),
22996            "creator" | "artist" => (
22997                "The one who brings new things into being",
22998                "Perfectionism, self-indulgence, drama",
22999                "Creativity, imagination, expression",
23000                "Completing projects, accepting imperfection",
23001            ),
23002            "innocent" | "child" => (
23003                "The pure one with faith and optimism",
23004                "Naivety, denial, dependence",
23005                "Faith, optimism, loyalty",
23006                "Growing without becoming cynical",
23007            ),
23008            "explorer" | "seeker" => (
23009                "The one who seeks new experiences and self-discovery",
23010                "Aimless wandering, inability to commit",
23011                "Autonomy, ambition, authenticity",
23012                "Finding what you seek",
23013            ),
23014            "rebel" | "outlaw" => (
23015                "The one who breaks rules and challenges the status quo",
23016                "Crime, self-destruction, alienation",
23017                "Liberation, revolution, radical freedom",
23018                "Channeling rebellion constructively",
23019            ),
23020            "jester" | "fool" | "trickster" => (
23021                "The one who uses humor and playfulness",
23022                "Cruelty, debauchery, irresponsibility",
23023                "Joy, freedom, living in the moment",
23024                "Knowing when to be serious",
23025            ),
23026            "everyman" | "orphan" => (
23027                "The regular person who wants belonging",
23028                "Victim mentality, losing self in group",
23029                "Realism, empathy, connection",
23030                "Standing out when necessary",
23031            ),
23032            _ => return Err(RuntimeError::new(format!("Unknown archetype: {}", name))),
23033        };
23034
23035        let mut result = std::collections::HashMap::new();
23036        result.insert("name".to_string(), Value::String(Rc::new(name)));
23037        result.insert(
23038            "description".to_string(),
23039            Value::String(Rc::new(description.to_string())),
23040        );
23041        result.insert(
23042            "shadow".to_string(),
23043            Value::String(Rc::new(shadow.to_string())),
23044        );
23045        result.insert("gift".to_string(), Value::String(Rc::new(gift.to_string())));
23046        result.insert(
23047            "challenge".to_string(),
23048            Value::String(Rc::new(challenge.to_string())),
23049        );
23050
23051        Ok(Value::Map(Rc::new(RefCell::new(result))))
23052    });
23053
23054    // =========================================================================
23055    // ASTROLOGY
23056    // =========================================================================
23057
23058    // zodiac - get zodiac sign information
23059    define(interp, "zodiac", Some(1), |_, args| {
23060        let input = match &args[0] {
23061            Value::Int(n) => (*n as usize - 1).min(11),
23062            Value::String(s) => match s.to_lowercase().as_str() {
23063                "aries" | "♈" => 0,
23064                "taurus" | "♉" => 1,
23065                "gemini" | "♊" => 2,
23066                "cancer" | "♋" => 3,
23067                "leo" | "♌" => 4,
23068                "virgo" | "♍" => 5,
23069                "libra" | "♎" => 6,
23070                "scorpio" | "♏" => 7,
23071                "sagittarius" | "♐" => 8,
23072                "capricorn" | "♑" => 9,
23073                "aquarius" | "♒" => 10,
23074                "pisces" | "♓" => 11,
23075                _ => return Err(RuntimeError::new(format!("Unknown sign: {}", s))),
23076            },
23077            _ => return Err(RuntimeError::new("zodiac() requires number or name")),
23078        };
23079
23080        let signs = [
23081            (
23082                "♈",
23083                "Aries",
23084                "Fire",
23085                "Cardinal",
23086                "Mars",
23087                "I Am",
23088                "Mar 21 - Apr 19",
23089            ),
23090            (
23091                "♉",
23092                "Taurus",
23093                "Earth",
23094                "Fixed",
23095                "Venus",
23096                "I Have",
23097                "Apr 20 - May 20",
23098            ),
23099            (
23100                "♊",
23101                "Gemini",
23102                "Air",
23103                "Mutable",
23104                "Mercury",
23105                "I Think",
23106                "May 21 - Jun 20",
23107            ),
23108            (
23109                "♋",
23110                "Cancer",
23111                "Water",
23112                "Cardinal",
23113                "Moon",
23114                "I Feel",
23115                "Jun 21 - Jul 22",
23116            ),
23117            (
23118                "♌",
23119                "Leo",
23120                "Fire",
23121                "Fixed",
23122                "Sun",
23123                "I Will",
23124                "Jul 23 - Aug 22",
23125            ),
23126            (
23127                "♍",
23128                "Virgo",
23129                "Earth",
23130                "Mutable",
23131                "Mercury",
23132                "I Analyze",
23133                "Aug 23 - Sep 22",
23134            ),
23135            (
23136                "♎",
23137                "Libra",
23138                "Air",
23139                "Cardinal",
23140                "Venus",
23141                "I Balance",
23142                "Sep 23 - Oct 22",
23143            ),
23144            (
23145                "♏",
23146                "Scorpio",
23147                "Water",
23148                "Fixed",
23149                "Pluto/Mars",
23150                "I Transform",
23151                "Oct 23 - Nov 21",
23152            ),
23153            (
23154                "♐",
23155                "Sagittarius",
23156                "Fire",
23157                "Mutable",
23158                "Jupiter",
23159                "I Seek",
23160                "Nov 22 - Dec 21",
23161            ),
23162            (
23163                "♑",
23164                "Capricorn",
23165                "Earth",
23166                "Cardinal",
23167                "Saturn",
23168                "I Use",
23169                "Dec 22 - Jan 19",
23170            ),
23171            (
23172                "♒",
23173                "Aquarius",
23174                "Air",
23175                "Fixed",
23176                "Uranus/Saturn",
23177                "I Know",
23178                "Jan 20 - Feb 18",
23179            ),
23180            (
23181                "♓",
23182                "Pisces",
23183                "Water",
23184                "Mutable",
23185                "Neptune/Jupiter",
23186                "I Believe",
23187                "Feb 19 - Mar 20",
23188            ),
23189        ];
23190
23191        let (symbol, name, element, modality, ruler, motto, dates) = signs[input];
23192
23193        let mut result = std::collections::HashMap::new();
23194        result.insert("number".to_string(), Value::Int((input + 1) as i64));
23195        result.insert(
23196            "symbol".to_string(),
23197            Value::String(Rc::new(symbol.to_string())),
23198        );
23199        result.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
23200        result.insert(
23201            "element".to_string(),
23202            Value::String(Rc::new(element.to_string())),
23203        );
23204        result.insert(
23205            "modality".to_string(),
23206            Value::String(Rc::new(modality.to_string())),
23207        );
23208        result.insert(
23209            "ruler".to_string(),
23210            Value::String(Rc::new(ruler.to_string())),
23211        );
23212        result.insert(
23213            "motto".to_string(),
23214            Value::String(Rc::new(motto.to_string())),
23215        );
23216        result.insert(
23217            "dates".to_string(),
23218            Value::String(Rc::new(dates.to_string())),
23219        );
23220
23221        Ok(Value::Map(Rc::new(RefCell::new(result))))
23222    });
23223
23224    // tarot_major - Major Arcana information
23225    define(interp, "tarot_major", Some(1), |_, args| {
23226        let num = match &args[0] {
23227            Value::Int(n) => (*n as usize).min(21),
23228            Value::String(s) => match s.to_lowercase().as_str() {
23229                "fool" => 0,
23230                "magician" => 1,
23231                "high_priestess" | "priestess" => 2,
23232                "empress" => 3,
23233                "emperor" => 4,
23234                "hierophant" | "pope" => 5,
23235                "lovers" => 6,
23236                "chariot" => 7,
23237                "strength" => 8,
23238                "hermit" => 9,
23239                "wheel" | "fortune" => 10,
23240                "justice" => 11,
23241                "hanged_man" | "hanged" => 12,
23242                "death" => 13,
23243                "temperance" => 14,
23244                "devil" => 15,
23245                "tower" => 16,
23246                "star" => 17,
23247                "moon" => 18,
23248                "sun" => 19,
23249                "judgement" | "judgment" => 20,
23250                "world" => 21,
23251                _ => return Err(RuntimeError::new(format!("Unknown card: {}", s))),
23252            },
23253            _ => return Err(RuntimeError::new("tarot_major() requires number or name")),
23254        };
23255
23256        let cards = [
23257            (
23258                "The Fool",
23259                "New beginnings, innocence, spontaneity",
23260                "Naivety, recklessness, risk-taking",
23261            ),
23262            (
23263                "The Magician",
23264                "Willpower, creation, manifestation",
23265                "Manipulation, trickery, unused talent",
23266            ),
23267            (
23268                "The High Priestess",
23269                "Intuition, mystery, inner knowledge",
23270                "Secrets, withdrawal, silence",
23271            ),
23272            (
23273                "The Empress",
23274                "Abundance, nurturing, fertility",
23275                "Dependence, smothering, emptiness",
23276            ),
23277            (
23278                "The Emperor",
23279                "Authority, structure, control",
23280                "Tyranny, rigidity, coldness",
23281            ),
23282            (
23283                "The Hierophant",
23284                "Tradition, conformity, spirituality",
23285                "Dogma, restriction, challenging status quo",
23286            ),
23287            (
23288                "The Lovers",
23289                "Love, harmony, relationships, choices",
23290                "Disharmony, imbalance, misalignment",
23291            ),
23292            (
23293                "The Chariot",
23294                "Direction, willpower, victory",
23295                "Aggression, lack of direction, obstacles",
23296            ),
23297            (
23298                "Strength",
23299                "Courage, patience, inner power",
23300                "Self-doubt, weakness, insecurity",
23301            ),
23302            (
23303                "The Hermit",
23304                "Contemplation, search for truth, inner guidance",
23305                "Isolation, loneliness, withdrawal",
23306            ),
23307            (
23308                "Wheel of Fortune",
23309                "Change, cycles, fate, destiny",
23310                "Resistance to change, bad luck, setbacks",
23311            ),
23312            (
23313                "Justice",
23314                "Truth, fairness, law, cause and effect",
23315                "Unfairness, dishonesty, lack of accountability",
23316            ),
23317            (
23318                "The Hanged Man",
23319                "Surrender, letting go, new perspective",
23320                "Stalling, resistance, indecision",
23321            ),
23322            (
23323                "Death",
23324                "Endings, transformation, transition",
23325                "Fear of change, stagnation, decay",
23326            ),
23327            (
23328                "Temperance",
23329                "Balance, moderation, patience",
23330                "Imbalance, excess, lack of purpose",
23331            ),
23332            (
23333                "The Devil",
23334                "Bondage, materialism, shadow self",
23335                "Freedom, release, exploring dark side",
23336            ),
23337            (
23338                "The Tower",
23339                "Sudden change, upheaval, revelation",
23340                "Disaster averted, fear of change, prolonged pain",
23341            ),
23342            (
23343                "The Star",
23344                "Hope, faith, renewal, inspiration",
23345                "Despair, disconnection, lack of faith",
23346            ),
23347            (
23348                "The Moon",
23349                "Illusion, intuition, the unconscious",
23350                "Fear, confusion, misinterpretation",
23351            ),
23352            (
23353                "The Sun",
23354                "Joy, success, vitality, positivity",
23355                "Negativity, depression, sadness",
23356            ),
23357            (
23358                "Judgement",
23359                "Rebirth, inner calling, absolution",
23360                "Self-doubt, refusal of self-examination",
23361            ),
23362            (
23363                "The World",
23364                "Completion, accomplishment, wholeness",
23365                "Incompletion, lack of closure, emptiness",
23366            ),
23367        ];
23368
23369        let (name, upright, reversed) = cards[num];
23370
23371        let mut result = std::collections::HashMap::new();
23372        result.insert("number".to_string(), Value::Int(num as i64));
23373        result.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
23374        result.insert(
23375            "upright".to_string(),
23376            Value::String(Rc::new(upright.to_string())),
23377        );
23378        result.insert(
23379            "reversed".to_string(),
23380            Value::String(Rc::new(reversed.to_string())),
23381        );
23382
23383        Ok(Value::Map(Rc::new(RefCell::new(result))))
23384    });
23385
23386    // draw_tarot - draw random tarot card
23387    define(interp, "draw_tarot", Some(0), |_, _| {
23388        let mut rng = rand::thread_rng();
23389        let card: usize = rng.gen_range(0..22);
23390        let reversed: bool = rng.gen();
23391
23392        let cards = [
23393            "The Fool",
23394            "The Magician",
23395            "The High Priestess",
23396            "The Empress",
23397            "The Emperor",
23398            "The Hierophant",
23399            "The Lovers",
23400            "The Chariot",
23401            "Strength",
23402            "The Hermit",
23403            "Wheel of Fortune",
23404            "Justice",
23405            "The Hanged Man",
23406            "Death",
23407            "Temperance",
23408            "The Devil",
23409            "The Tower",
23410            "The Star",
23411            "The Moon",
23412            "The Sun",
23413            "Judgement",
23414            "The World",
23415        ];
23416
23417        let mut result = std::collections::HashMap::new();
23418        result.insert("number".to_string(), Value::Int(card as i64));
23419        result.insert(
23420            "name".to_string(),
23421            Value::String(Rc::new(cards[card].to_string())),
23422        );
23423        result.insert("reversed".to_string(), Value::Bool(reversed));
23424        result.insert(
23425            "orientation".to_string(),
23426            Value::String(Rc::new(
23427                if reversed { "reversed" } else { "upright" }.to_string(),
23428            )),
23429        );
23430
23431        Ok(Value::Map(Rc::new(RefCell::new(result))))
23432    });
23433
23434    // =========================================================================
23435    // SYNCHRONICITY
23436    // =========================================================================
23437
23438    // synchronicity_score - calculate "meaningful coincidence" between values
23439    define(interp, "synchronicity_score", Some(2), |_, args| {
23440        // This is intentionally mysterious - combining multiple systems
23441        let a = match &args[0] {
23442            Value::String(s) => s.to_string(),
23443            Value::Int(n) => n.to_string(),
23444            _ => {
23445                return Err(RuntimeError::new(
23446                    "synchronicity_score() requires string or int",
23447                ))
23448            }
23449        };
23450
23451        let b = match &args[1] {
23452            Value::String(s) => s.to_string(),
23453            Value::Int(n) => n.to_string(),
23454            _ => {
23455                return Err(RuntimeError::new(
23456                    "synchronicity_score() requires string or int",
23457                ))
23458            }
23459        };
23460
23461        // Calculate gematria values (simple English)
23462        let val_a: i64 = a
23463            .to_uppercase()
23464            .chars()
23465            .filter_map(|c| {
23466                if c.is_ascii_alphabetic() {
23467                    Some((c as i64) - ('A' as i64) + 1)
23468                } else if c.is_ascii_digit() {
23469                    c.to_digit(10).map(|d| d as i64)
23470                } else {
23471                    None
23472                }
23473            })
23474            .sum();
23475
23476        let val_b: i64 = b
23477            .to_uppercase()
23478            .chars()
23479            .filter_map(|c| {
23480                if c.is_ascii_alphabetic() {
23481                    Some((c as i64) - ('A' as i64) + 1)
23482                } else if c.is_ascii_digit() {
23483                    c.to_digit(10).map(|d| d as i64)
23484                } else {
23485                    None
23486                }
23487            })
23488            .sum();
23489
23490        // Multiple synchronicity factors
23491        let mut factors = Vec::new();
23492
23493        // Same value
23494        if val_a == val_b {
23495            factors.push("identical_gematria".to_string());
23496        }
23497
23498        // One divides the other
23499        if val_a > 0 && val_b > 0 && (val_a % val_b == 0 || val_b % val_a == 0) {
23500            factors.push("divisibility".to_string());
23501        }
23502
23503        // Fibonacci relationship
23504        let fib_set: std::collections::HashSet<i64> =
23505            [1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987]
23506                .iter()
23507                .cloned()
23508                .collect();
23509        if fib_set.contains(&val_a) && fib_set.contains(&val_b) {
23510            factors.push("both_fibonacci".to_string());
23511        }
23512
23513        // Digital root match
23514        fn digital_root(mut n: i64) -> i64 {
23515            while n > 9 {
23516                n = n
23517                    .to_string()
23518                    .chars()
23519                    .filter_map(|c| c.to_digit(10))
23520                    .map(|d| d as i64)
23521                    .sum();
23522            }
23523            n
23524        }
23525        if digital_root(val_a) == digital_root(val_b) {
23526            factors.push("same_digital_root".to_string());
23527        }
23528
23529        // Golden ratio relationship (within 1%)
23530        let phi = (1.0 + 5.0_f64.sqrt()) / 2.0;
23531        let ratio = if val_a > 0 && val_b > 0 {
23532            (val_a as f64 / val_b as f64).max(val_b as f64 / val_a as f64)
23533        } else {
23534            0.0
23535        };
23536        if (ratio - phi).abs() < 0.02 || (ratio - 1.0 / phi).abs() < 0.02 {
23537            factors.push("golden_ratio".to_string());
23538        }
23539
23540        let score = (factors.len() as f64 / 5.0).min(1.0);
23541
23542        let mut result = std::collections::HashMap::new();
23543        result.insert("score".to_string(), Value::Float(score));
23544        result.insert("value_a".to_string(), Value::Int(val_a));
23545        result.insert("value_b".to_string(), Value::Int(val_b));
23546        let factor_values: Vec<Value> = factors
23547            .iter()
23548            .map(|s| Value::String(Rc::new(s.clone())))
23549            .collect();
23550        result.insert(
23551            "factors".to_string(),
23552            Value::Array(Rc::new(RefCell::new(factor_values))),
23553        );
23554
23555        Ok(Value::Map(Rc::new(RefCell::new(result))))
23556    });
23557
23558    // spirituality_info
23559    define(interp, "spirituality_info", Some(0), |_, _| {
23560        let mut info = std::collections::HashMap::new();
23561
23562        info.insert(
23563            "i_ching".to_string(),
23564            Value::String(Rc::new(
23565                "trigram(), hexagram(), cast_iching() - 64 hexagrams of change".to_string(),
23566            )),
23567        );
23568        info.insert(
23569            "sacred_geometry".to_string(),
23570            Value::String(Rc::new(
23571                "phi(), sacred_ratio(), fibonacci(), platonic_solid()".to_string(),
23572            )),
23573        );
23574        info.insert(
23575            "gematria".to_string(),
23576            Value::String(Rc::new(
23577                "Hebrew, Greek, Arabic, English letter-number systems".to_string(),
23578            )),
23579        );
23580        info.insert(
23581            "archetypes".to_string(),
23582            Value::String(Rc::new(
23583                "17 Jungian archetypes with shadow and gift".to_string(),
23584            )),
23585        );
23586        info.insert(
23587            "astrology".to_string(),
23588            Value::String(Rc::new(
23589                "zodiac() - 12 signs with elements and modalities".to_string(),
23590            )),
23591        );
23592        info.insert(
23593            "tarot".to_string(),
23594            Value::String(Rc::new(
23595                "tarot_major(), draw_tarot() - 22 Major Arcana".to_string(),
23596            )),
23597        );
23598
23599        Ok(Value::Map(Rc::new(RefCell::new(info))))
23600    });
23601}
23602
23603// I Ching hexagram data (64 hexagrams in King Wen sequence)
23604const HEXAGRAMS: [(&str, &str, &str, &str, &str, &str); 64] = [
23605    (
23606        "乾",
23607        "Qián",
23608        "The Creative",
23609        "Sublime success through perseverance",
23610        "Heaven",
23611        "Heaven",
23612    ),
23613    (
23614        "坤",
23615        "Kūn",
23616        "The Receptive",
23617        "Devoted success through the mare's perseverance",
23618        "Earth",
23619        "Earth",
23620    ),
23621    (
23622        "屯",
23623        "Zhūn",
23624        "Difficulty at the Beginning",
23625        "Persevere, seek helpers, don't act alone",
23626        "Water",
23627        "Thunder",
23628    ),
23629    (
23630        "蒙",
23631        "Méng",
23632        "Youthful Folly",
23633        "Success through education and guidance",
23634        "Mountain",
23635        "Water",
23636    ),
23637    (
23638        "需",
23639        "Xū",
23640        "Waiting",
23641        "Sincerity brings success; cross the great water",
23642        "Water",
23643        "Heaven",
23644    ),
23645    (
23646        "訟",
23647        "Sòng",
23648        "Conflict",
23649        "Seek counsel; don't cross the great water",
23650        "Heaven",
23651        "Water",
23652    ),
23653    (
23654        "師",
23655        "Shī",
23656        "The Army",
23657        "Perseverance and an experienced leader bring success",
23658        "Earth",
23659        "Water",
23660    ),
23661    (
23662        "比",
23663        "Bǐ",
23664        "Holding Together",
23665        "Through perseverance, those who hesitate should reflect",
23666        "Water",
23667        "Earth",
23668    ),
23669    (
23670        "小畜",
23671        "Xiǎo Chù",
23672        "Small Taming",
23673        "Success; dense clouds but no rain",
23674        "Wind",
23675        "Heaven",
23676    ),
23677    (
23678        "履",
23679        "Lǚ",
23680        "Treading",
23681        "Tread on the tiger's tail carefully; success",
23682        "Heaven",
23683        "Lake",
23684    ),
23685    (
23686        "泰",
23687        "Tài",
23688        "Peace",
23689        "The small departs, the great approaches; success",
23690        "Earth",
23691        "Heaven",
23692    ),
23693    (
23694        "否",
23695        "Pǐ",
23696        "Standstill",
23697        "The great departs, the small approaches; persevere",
23698        "Heaven",
23699        "Earth",
23700    ),
23701    (
23702        "同人",
23703        "Tóng Rén",
23704        "Fellowship",
23705        "Success in the open; cross the great water",
23706        "Heaven",
23707        "Fire",
23708    ),
23709    (
23710        "大有",
23711        "Dà Yǒu",
23712        "Great Possession",
23713        "Supreme success",
23714        "Fire",
23715        "Heaven",
23716    ),
23717    (
23718        "謙",
23719        "Qiān",
23720        "Modesty",
23721        "Success; the superior person carries things through",
23722        "Earth",
23723        "Mountain",
23724    ),
23725    (
23726        "豫",
23727        "Yù",
23728        "Enthusiasm",
23729        "Appoint helpers and set armies marching",
23730        "Thunder",
23731        "Earth",
23732    ),
23733    (
23734        "隨",
23735        "Suí",
23736        "Following",
23737        "Supreme success through perseverance",
23738        "Lake",
23739        "Thunder",
23740    ),
23741    (
23742        "蠱",
23743        "Gǔ",
23744        "Work on the Decayed",
23745        "Success; cross the great water; three days before and after",
23746        "Mountain",
23747        "Wind",
23748    ),
23749    (
23750        "臨",
23751        "Lín",
23752        "Approach",
23753        "Great success through perseverance; misfortune in eighth month",
23754        "Earth",
23755        "Lake",
23756    ),
23757    (
23758        "觀",
23759        "Guān",
23760        "Contemplation",
23761        "Ablution, but not yet sacrifice; confidence inspires",
23762        "Wind",
23763        "Earth",
23764    ),
23765    (
23766        "噬嗑",
23767        "Shì Kè",
23768        "Biting Through",
23769        "Success; favorable for legal matters",
23770        "Fire",
23771        "Thunder",
23772    ),
23773    (
23774        "賁",
23775        "Bì",
23776        "Grace",
23777        "Success in small matters",
23778        "Mountain",
23779        "Fire",
23780    ),
23781    (
23782        "剝",
23783        "Bō",
23784        "Splitting Apart",
23785        "Unfavorable to go anywhere",
23786        "Mountain",
23787        "Earth",
23788    ),
23789    (
23790        "復",
23791        "Fù",
23792        "Return",
23793        "Success; going out and coming in without error",
23794        "Earth",
23795        "Thunder",
23796    ),
23797    (
23798        "無妄",
23799        "Wú Wàng",
23800        "Innocence",
23801        "Supreme success through perseverance",
23802        "Heaven",
23803        "Thunder",
23804    ),
23805    (
23806        "大畜",
23807        "Dà Chù",
23808        "Great Taming",
23809        "Perseverance; eat away from home",
23810        "Mountain",
23811        "Heaven",
23812    ),
23813    (
23814        "頤",
23815        "Yí",
23816        "Nourishment",
23817        "Perseverance; watch what you nurture",
23818        "Mountain",
23819        "Thunder",
23820    ),
23821    (
23822        "大過",
23823        "Dà Guò",
23824        "Great Exceeding",
23825        "The ridgepole sags; favorable to have somewhere to go",
23826        "Lake",
23827        "Wind",
23828    ),
23829    (
23830        "坎",
23831        "Kǎn",
23832        "The Abysmal",
23833        "Sincerity brings success of the heart",
23834        "Water",
23835        "Water",
23836    ),
23837    (
23838        "離",
23839        "Lí",
23840        "The Clinging",
23841        "Perseverance; success; care for the cow",
23842        "Fire",
23843        "Fire",
23844    ),
23845    (
23846        "咸",
23847        "Xián",
23848        "Influence",
23849        "Success; perseverance; taking a maiden brings fortune",
23850        "Lake",
23851        "Mountain",
23852    ),
23853    (
23854        "恆",
23855        "Héng",
23856        "Duration",
23857        "Success without blame; perseverance; favorable to have somewhere to go",
23858        "Thunder",
23859        "Wind",
23860    ),
23861    (
23862        "遯",
23863        "Dùn",
23864        "Retreat",
23865        "Success; small perseverance",
23866        "Heaven",
23867        "Mountain",
23868    ),
23869    (
23870        "大壯",
23871        "Dà Zhuàng",
23872        "Great Power",
23873        "Perseverance",
23874        "Thunder",
23875        "Heaven",
23876    ),
23877    (
23878        "晉",
23879        "Jìn",
23880        "Progress",
23881        "The powerful prince is honored with horses",
23882        "Fire",
23883        "Earth",
23884    ),
23885    (
23886        "明夷",
23887        "Míng Yí",
23888        "Darkening of the Light",
23889        "Perseverance in adversity",
23890        "Earth",
23891        "Fire",
23892    ),
23893    (
23894        "家人",
23895        "Jiā Rén",
23896        "The Family",
23897        "Perseverance of the woman",
23898        "Wind",
23899        "Fire",
23900    ),
23901    (
23902        "睽",
23903        "Kuí",
23904        "Opposition",
23905        "Good fortune in small matters",
23906        "Fire",
23907        "Lake",
23908    ),
23909    (
23910        "蹇",
23911        "Jiǎn",
23912        "Obstruction",
23913        "Southwest favorable; northeast unfavorable; see the great person",
23914        "Water",
23915        "Mountain",
23916    ),
23917    (
23918        "解",
23919        "Xiè",
23920        "Deliverance",
23921        "Southwest favorable; return brings fortune; haste brings fortune",
23922        "Thunder",
23923        "Water",
23924    ),
23925    (
23926        "損",
23927        "Sǔn",
23928        "Decrease",
23929        "Sincerity; supreme fortune; persistence; favorable to undertake",
23930        "Mountain",
23931        "Lake",
23932    ),
23933    (
23934        "益",
23935        "Yì",
23936        "Increase",
23937        "Favorable to undertake and cross the great water",
23938        "Wind",
23939        "Thunder",
23940    ),
23941    (
23942        "夬",
23943        "Guài",
23944        "Breakthrough",
23945        "Proclaim at the king's court; sincerity in danger",
23946        "Lake",
23947        "Heaven",
23948    ),
23949    (
23950        "姤",
23951        "Gòu",
23952        "Coming to Meet",
23953        "The maiden is powerful; don't marry such a maiden",
23954        "Heaven",
23955        "Wind",
23956    ),
23957    (
23958        "萃",
23959        "Cuì",
23960        "Gathering",
23961        "Success; the king approaches his temple; see the great person",
23962        "Lake",
23963        "Earth",
23964    ),
23965    (
23966        "升",
23967        "Shēng",
23968        "Pushing Upward",
23969        "Supreme success; see the great person; don't worry",
23970        "Earth",
23971        "Wind",
23972    ),
23973    (
23974        "困",
23975        "Kùn",
23976        "Oppression",
23977        "Success; perseverance of the great person; no blame",
23978        "Lake",
23979        "Water",
23980    ),
23981    (
23982        "井",
23983        "Jǐng",
23984        "The Well",
23985        "The town may change but not the well",
23986        "Water",
23987        "Wind",
23988    ),
23989    (
23990        "革",
23991        "Gé",
23992        "Revolution",
23993        "On your own day you are believed; great success",
23994        "Lake",
23995        "Fire",
23996    ),
23997    (
23998        "鼎",
23999        "Dǐng",
24000        "The Cauldron",
24001        "Supreme good fortune; success",
24002        "Fire",
24003        "Wind",
24004    ),
24005    (
24006        "震",
24007        "Zhèn",
24008        "The Arousing",
24009        "Success; thunder comes with fright; laughing and talking after",
24010        "Thunder",
24011        "Thunder",
24012    ),
24013    (
24014        "艮",
24015        "Gèn",
24016        "Keeping Still",
24017        "Keep your back still; go into the courtyard without seeing anyone",
24018        "Mountain",
24019        "Mountain",
24020    ),
24021    (
24022        "漸",
24023        "Jiàn",
24024        "Development",
24025        "The maiden is given in marriage; good fortune; perseverance",
24026        "Wind",
24027        "Mountain",
24028    ),
24029    (
24030        "歸妹",
24031        "Guī Mèi",
24032        "The Marrying Maiden",
24033        "Undertakings bring misfortune",
24034        "Thunder",
24035        "Lake",
24036    ),
24037    (
24038        "豐",
24039        "Fēng",
24040        "Abundance",
24041        "Success; the king attains it; don't worry; be like the sun at noon",
24042        "Thunder",
24043        "Fire",
24044    ),
24045    (
24046        "旅",
24047        "Lǚ",
24048        "The Wanderer",
24049        "Success through smallness; perseverance brings fortune",
24050        "Fire",
24051        "Mountain",
24052    ),
24053    (
24054        "巽",
24055        "Xùn",
24056        "The Gentle",
24057        "Success through small things; favorable to have somewhere to go",
24058        "Wind",
24059        "Wind",
24060    ),
24061    (
24062        "兌",
24063        "Duì",
24064        "The Joyous",
24065        "Success; perseverance",
24066        "Lake",
24067        "Lake",
24068    ),
24069    (
24070        "渙",
24071        "Huàn",
24072        "Dispersion",
24073        "Success; the king approaches his temple; cross the great water",
24074        "Wind",
24075        "Water",
24076    ),
24077    (
24078        "節",
24079        "Jié",
24080        "Limitation",
24081        "Success; bitter limitation should not be persevered in",
24082        "Water",
24083        "Lake",
24084    ),
24085    (
24086        "中孚",
24087        "Zhōng Fú",
24088        "Inner Truth",
24089        "Pigs and fishes; good fortune; cross the great water",
24090        "Wind",
24091        "Lake",
24092    ),
24093    (
24094        "小過",
24095        "Xiǎo Guò",
24096        "Small Exceeding",
24097        "Success; perseverance; small things yes, great things no",
24098        "Thunder",
24099        "Mountain",
24100    ),
24101    (
24102        "既濟",
24103        "Jì Jì",
24104        "After Completion",
24105        "Success in small matters; perseverance; good at start, disorder at end",
24106        "Water",
24107        "Fire",
24108    ),
24109    (
24110        "未濟",
24111        "Wèi Jì",
24112        "Before Completion",
24113        "Success; the young fox almost across; tail gets wet; no goal",
24114        "Fire",
24115        "Water",
24116    ),
24117];
24118
24119fn binary_to_king_wen(binary: u8) -> u8 {
24120    // Maps binary hexagram representation to King Wen sequence number
24121    // This is a complex mapping based on traditional ordering
24122    const KING_WEN_ORDER: [u8; 64] = [
24123        1, 43, 14, 34, 9, 5, 26, 11, 10, 58, 38, 54, 61, 60, 41, 19, 13, 49, 30, 55, 37, 63, 22,
24124        36, 25, 17, 21, 51, 42, 3, 27, 24, 44, 28, 50, 32, 57, 48, 18, 46, 6, 47, 64, 40, 59, 29,
24125        4, 7, 33, 31, 56, 62, 53, 39, 52, 15, 12, 45, 35, 16, 20, 8, 23, 2,
24126    ];
24127    KING_WEN_ORDER[binary as usize] - 1
24128}
24129
24130fn hebrew_gematria(c: char) -> i64 {
24131    match c {
24132        'א' | 'A' | 'a' => 1,
24133        'ב' | 'B' | 'b' => 2,
24134        'ג' | 'G' | 'g' => 3,
24135        'ד' | 'D' | 'd' => 4,
24136        'ה' | 'H' | 'h' => 5,
24137        'ו' | 'V' | 'v' | 'W' | 'w' => 6,
24138        'ז' | 'Z' | 'z' => 7,
24139        'ח' => 8,
24140        'ט' => 9,
24141        'י' | 'Y' | 'y' | 'I' | 'i' | 'J' | 'j' => 10,
24142        'כ' | 'K' | 'k' => 20,
24143        'ל' | 'L' | 'l' => 30,
24144        'מ' | 'M' | 'm' => 40,
24145        'נ' | 'N' | 'n' => 50,
24146        'ס' | 'S' | 's' | 'X' | 'x' => 60,
24147        'ע' | 'O' | 'o' => 70,
24148        'פ' | 'P' | 'p' | 'F' | 'f' => 80,
24149        'צ' => 90,
24150        'ק' | 'Q' | 'q' => 100,
24151        'ר' | 'R' | 'r' => 200,
24152        'ש' => 300,
24153        'ת' | 'T' | 't' => 400,
24154        'ך' => 500,             // Final kaph
24155        'ם' => 600,             // Final mem
24156        'ן' => 700,             // Final nun
24157        'ף' => 800,             // Final pe
24158        'ץ' | 'C' | 'c' => 900, // Final tzadi / C approximation
24159        'E' | 'e' => 5,         // Map to He
24160        'U' | 'u' => 6,         // Map to Vav
24161        _ => 0,
24162    }
24163}
24164
24165fn greek_isopsephy(c: char) -> i64 {
24166    match c {
24167        'Α' | 'α' | 'A' | 'a' => 1,
24168        'Β' | 'β' | 'B' | 'b' => 2,
24169        'Γ' | 'γ' | 'G' | 'g' => 3,
24170        'Δ' | 'δ' | 'D' | 'd' => 4,
24171        'Ε' | 'ε' | 'E' | 'e' => 5,
24172        'Ϛ' | 'ϛ' => 6, // Stigma (archaic)
24173        'Ζ' | 'ζ' | 'Z' | 'z' => 7,
24174        'Η' | 'η' | 'H' | 'h' => 8,
24175        'Θ' | 'θ' => 9,
24176        'Ι' | 'ι' | 'I' | 'i' => 10,
24177        'Κ' | 'κ' | 'K' | 'k' => 20,
24178        'Λ' | 'λ' | 'L' | 'l' => 30,
24179        'Μ' | 'μ' | 'M' | 'm' => 40,
24180        'Ν' | 'ν' | 'N' | 'n' => 50,
24181        'Ξ' | 'ξ' | 'X' | 'x' => 60,
24182        'Ο' | 'ο' | 'O' | 'o' => 70,
24183        'Π' | 'π' | 'P' | 'p' => 80,
24184        'Ϙ' | 'ϙ' | 'Q' | 'q' => 90, // Qoppa
24185        'Ρ' | 'ρ' | 'R' | 'r' => 100,
24186        'Σ' | 'σ' | 'ς' | 'S' | 's' => 200,
24187        'Τ' | 'τ' | 'T' | 't' => 300,
24188        'Υ' | 'υ' | 'U' | 'u' | 'Y' | 'y' => 400,
24189        'Φ' | 'φ' | 'F' | 'f' => 500,
24190        'Χ' | 'χ' | 'C' | 'c' => 600,
24191        'Ψ' | 'ψ' => 700,
24192        'Ω' | 'ω' | 'W' | 'w' => 800,
24193        'Ϡ' | 'ϡ' => 900, // Sampi
24194        'J' | 'j' => 10,  // Map to Iota
24195        'V' | 'v' => 400, // Map to Upsilon
24196        _ => 0,
24197    }
24198}
24199
24200fn arabic_abjad(c: char) -> i64 {
24201    match c {
24202        'ا' | 'أ' | 'إ' | 'آ' | 'A' | 'a' => 1,
24203        'ب' | 'B' | 'b' => 2,
24204        'ج' | 'J' | 'j' | 'G' | 'g' => 3,
24205        'د' | 'D' | 'd' => 4,
24206        'ه' | 'H' | 'h' => 5,
24207        'و' | 'W' | 'w' | 'V' | 'v' => 6,
24208        'ز' | 'Z' | 'z' => 7,
24209        'ح' => 8,
24210        'ط' => 9,
24211        'ي' | 'Y' | 'y' | 'I' | 'i' => 10,
24212        'ك' | 'K' | 'k' => 20,
24213        'ل' | 'L' | 'l' => 30,
24214        'م' | 'M' | 'm' => 40,
24215        'ن' | 'N' | 'n' => 50,
24216        'س' | 'S' | 's' => 60,
24217        'ع' | 'E' | 'e' => 70,
24218        'ف' | 'F' | 'f' => 80,
24219        'ص' => 90,
24220        'ق' | 'Q' | 'q' => 100,
24221        'ر' | 'R' | 'r' => 200,
24222        'ش' => 300,
24223        'ت' | 'T' | 't' => 400,
24224        'ث' => 500,
24225        'خ' | 'X' | 'x' => 600,
24226        'ذ' => 700,
24227        'ض' => 800,
24228        'ظ' => 900,
24229        'غ' => 1000,
24230        'C' | 'c' => 600, // Map to خ
24231        'O' | 'o' => 70,  // Map to ع
24232        'P' | 'p' => 80,  // Map to ف
24233        'U' | 'u' => 6,   // Map to و
24234        _ => 0,
24235    }
24236}
24237
24238// =============================================================================
24239// Phase 16: Polycultural Color System
24240// =============================================================================
24241// Color meaning varies radically across cultures. This module provides mathematical
24242// color spaces + cultural color systems from around the world.
24243
24244fn register_color(interp: &mut Interpreter) {
24245    // =========================================================================
24246    // COLOR SPACE CONVERSIONS
24247    // =========================================================================
24248
24249    // rgb(r, g, b) - Create RGB color (0-255)
24250    define(interp, "rgb", Some(3), |_, args| {
24251        let r = match &args[0] {
24252            Value::Int(n) => (*n).clamp(0, 255) as u8,
24253            Value::Float(f) => (*f as i64).clamp(0, 255) as u8,
24254            _ => return Err(RuntimeError::new("rgb() requires numbers")),
24255        };
24256        let g = match &args[1] {
24257            Value::Int(n) => (*n).clamp(0, 255) as u8,
24258            Value::Float(f) => (*f as i64).clamp(0, 255) as u8,
24259            _ => return Err(RuntimeError::new("rgb() requires numbers")),
24260        };
24261        let b = match &args[2] {
24262            Value::Int(n) => (*n).clamp(0, 255) as u8,
24263            Value::Float(f) => (*f as i64).clamp(0, 255) as u8,
24264            _ => return Err(RuntimeError::new("rgb() requires numbers")),
24265        };
24266        let mut map = std::collections::HashMap::new();
24267        map.insert("r".to_string(), Value::Int(r as i64));
24268        map.insert("g".to_string(), Value::Int(g as i64));
24269        map.insert("b".to_string(), Value::Int(b as i64));
24270        map.insert(
24271            "hex".to_string(),
24272            Value::String(Rc::new(format!("#{:02X}{:02X}{:02X}", r, g, b))),
24273        );
24274        Ok(Value::Map(Rc::new(RefCell::new(map))))
24275    });
24276
24277    // hex_to_rgb(hex) - Parse hex color string
24278    define(interp, "hex_to_rgb", Some(1), |_, args| {
24279        let hex = match &args[0] {
24280            Value::String(s) => s.to_string(),
24281            _ => return Err(RuntimeError::new("hex_to_rgb requires string")),
24282        };
24283        let hex = hex.trim_start_matches('#');
24284        if hex.len() != 6 {
24285            return Err(RuntimeError::new("hex_to_rgb requires 6 character hex"));
24286        }
24287        let r = u8::from_str_radix(&hex[0..2], 16).map_err(|_| RuntimeError::new("Invalid hex"))?;
24288        let g = u8::from_str_radix(&hex[2..4], 16).map_err(|_| RuntimeError::new("Invalid hex"))?;
24289        let b = u8::from_str_radix(&hex[4..6], 16).map_err(|_| RuntimeError::new("Invalid hex"))?;
24290        let mut map = std::collections::HashMap::new();
24291        map.insert("r".to_string(), Value::Int(r as i64));
24292        map.insert("g".to_string(), Value::Int(g as i64));
24293        map.insert("b".to_string(), Value::Int(b as i64));
24294        Ok(Value::Map(Rc::new(RefCell::new(map))))
24295    });
24296
24297    // rgb_to_hsl(r, g, b) - Convert RGB to HSL
24298    define(interp, "rgb_to_hsl", Some(3), |_, args| {
24299        let r = match &args[0] {
24300            Value::Int(n) => *n as f64 / 255.0,
24301            Value::Float(f) => *f / 255.0,
24302            _ => return Err(RuntimeError::new("requires numbers")),
24303        };
24304        let g = match &args[1] {
24305            Value::Int(n) => *n as f64 / 255.0,
24306            Value::Float(f) => *f / 255.0,
24307            _ => return Err(RuntimeError::new("requires numbers")),
24308        };
24309        let b = match &args[2] {
24310            Value::Int(n) => *n as f64 / 255.0,
24311            Value::Float(f) => *f / 255.0,
24312            _ => return Err(RuntimeError::new("requires numbers")),
24313        };
24314        let max = r.max(g).max(b);
24315        let min = r.min(g).min(b);
24316        let l = (max + min) / 2.0;
24317        let (h, s) = if max == min {
24318            (0.0, 0.0)
24319        } else {
24320            let d = max - min;
24321            let s = if l > 0.5 {
24322                d / (2.0 - max - min)
24323            } else {
24324                d / (max + min)
24325            };
24326            let h = if max == r {
24327                (g - b) / d + if g < b { 6.0 } else { 0.0 }
24328            } else if max == g {
24329                (b - r) / d + 2.0
24330            } else {
24331                (r - g) / d + 4.0
24332            };
24333            (h * 60.0, s)
24334        };
24335        let mut map = std::collections::HashMap::new();
24336        map.insert("h".to_string(), Value::Float(h));
24337        map.insert("s".to_string(), Value::Float(s));
24338        map.insert("l".to_string(), Value::Float(l));
24339        Ok(Value::Map(Rc::new(RefCell::new(map))))
24340    });
24341
24342    // complementary(r, g, b) - Opposite on color wheel
24343    define(interp, "complementary", Some(3), |_, args| {
24344        let r = match &args[0] {
24345            Value::Int(n) => *n as u8,
24346            _ => return Err(RuntimeError::new("requires int")),
24347        };
24348        let g = match &args[1] {
24349            Value::Int(n) => *n as u8,
24350            _ => return Err(RuntimeError::new("requires int")),
24351        };
24352        let b = match &args[2] {
24353            Value::Int(n) => *n as u8,
24354            _ => return Err(RuntimeError::new("requires int")),
24355        };
24356        let mut map = std::collections::HashMap::new();
24357        map.insert("r".to_string(), Value::Int(255 - r as i64));
24358        map.insert("g".to_string(), Value::Int(255 - g as i64));
24359        map.insert("b".to_string(), Value::Int(255 - b as i64));
24360        Ok(Value::Map(Rc::new(RefCell::new(map))))
24361    });
24362
24363    // =========================================================================
24364    // WU XING (五行) - CHINESE FIVE ELEMENTS
24365    // =========================================================================
24366    define(interp, "wu_xing", Some(1), |_, args| {
24367        let element = match &args[0] {
24368            Value::String(s) => s.to_lowercase(),
24369            _ => return Err(RuntimeError::new("wu_xing requires string")),
24370        };
24371        let (name, chinese, color, hex, direction, season, organ, emotion, planet, animal) =
24372            match element.as_str() {
24373                "wood" | "mu" | "木" => (
24374                    "Wood",
24375                    "木 (Mù)",
24376                    "Green/Azure",
24377                    "#228B22",
24378                    "East",
24379                    "Spring",
24380                    "Liver",
24381                    "Anger",
24382                    "Jupiter",
24383                    "Azure Dragon",
24384                ),
24385                "fire" | "huo" | "火" => (
24386                    "Fire",
24387                    "火 (Huǒ)",
24388                    "Red",
24389                    "#FF0000",
24390                    "South",
24391                    "Summer",
24392                    "Heart",
24393                    "Joy",
24394                    "Mars",
24395                    "Vermilion Bird",
24396                ),
24397                "earth" | "tu" | "土" => (
24398                    "Earth",
24399                    "土 (Tǔ)",
24400                    "Yellow",
24401                    "#FFDB58",
24402                    "Center",
24403                    "Late Summer",
24404                    "Spleen",
24405                    "Worry",
24406                    "Saturn",
24407                    "Yellow Dragon",
24408                ),
24409                "metal" | "jin" | "金" => (
24410                    "Metal",
24411                    "金 (Jīn)",
24412                    "White/Gold",
24413                    "#FFD700",
24414                    "West",
24415                    "Autumn",
24416                    "Lung",
24417                    "Grief",
24418                    "Venus",
24419                    "White Tiger",
24420                ),
24421                "water" | "shui" | "水" => (
24422                    "Water",
24423                    "水 (Shuǐ)",
24424                    "Black/Blue",
24425                    "#000080",
24426                    "North",
24427                    "Winter",
24428                    "Kidney",
24429                    "Fear",
24430                    "Mercury",
24431                    "Black Tortoise",
24432                ),
24433                _ => {
24434                    return Err(RuntimeError::new(
24435                        "Unknown element. Use wood/fire/earth/metal/water",
24436                    ))
24437                }
24438            };
24439        let mut map = std::collections::HashMap::new();
24440        map.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
24441        map.insert(
24442            "chinese".to_string(),
24443            Value::String(Rc::new(chinese.to_string())),
24444        );
24445        map.insert(
24446            "color".to_string(),
24447            Value::String(Rc::new(color.to_string())),
24448        );
24449        map.insert("hex".to_string(), Value::String(Rc::new(hex.to_string())));
24450        map.insert(
24451            "direction".to_string(),
24452            Value::String(Rc::new(direction.to_string())),
24453        );
24454        map.insert(
24455            "season".to_string(),
24456            Value::String(Rc::new(season.to_string())),
24457        );
24458        map.insert(
24459            "organ".to_string(),
24460            Value::String(Rc::new(organ.to_string())),
24461        );
24462        map.insert(
24463            "emotion".to_string(),
24464            Value::String(Rc::new(emotion.to_string())),
24465        );
24466        map.insert(
24467            "planet".to_string(),
24468            Value::String(Rc::new(planet.to_string())),
24469        );
24470        map.insert(
24471            "guardian".to_string(),
24472            Value::String(Rc::new(animal.to_string())),
24473        );
24474        Ok(Value::Map(Rc::new(RefCell::new(map))))
24475    });
24476
24477    // =========================================================================
24478    // CHAKRA COLORS (Ayurveda/Hindu)
24479    // =========================================================================
24480    define(interp, "chakra_color", Some(1), |_, args| {
24481        let chakra = match &args[0] {
24482            Value::String(s) => s.to_lowercase(),
24483            Value::Int(n) => n.to_string(),
24484            _ => return Err(RuntimeError::new("chakra_color requires string or number")),
24485        };
24486        let (name, sanskrit, color, hex, location, freq, element, mantra) = match chakra.as_str() {
24487            "root" | "muladhara" | "1" => (
24488                "Root",
24489                "मूलाधार",
24490                "Red",
24491                "#FF0000",
24492                "Base of spine",
24493                396.0,
24494                "Earth",
24495                "LAM",
24496            ),
24497            "sacral" | "svadhisthana" | "2" => (
24498                "Sacral",
24499                "स्वाधिष्ठान",
24500                "Orange",
24501                "#FF7F00",
24502                "Below navel",
24503                417.0,
24504                "Water",
24505                "VAM",
24506            ),
24507            "solar" | "manipura" | "3" => (
24508                "Solar Plexus",
24509                "मणिपूर",
24510                "Yellow",
24511                "#FFFF00",
24512                "Stomach",
24513                528.0,
24514                "Fire",
24515                "RAM",
24516            ),
24517            "heart" | "anahata" | "4" => (
24518                "Heart",
24519                "अनाहत",
24520                "Green",
24521                "#00FF00",
24522                "Chest",
24523                639.0,
24524                "Air",
24525                "YAM",
24526            ),
24527            "throat" | "vishuddha" | "5" => (
24528                "Throat",
24529                "विशुद्ध",
24530                "Blue",
24531                "#00BFFF",
24532                "Throat",
24533                741.0,
24534                "Ether",
24535                "HAM",
24536            ),
24537            "third_eye" | "ajna" | "6" => (
24538                "Third Eye",
24539                "आज्ञा",
24540                "Indigo",
24541                "#4B0082",
24542                "Forehead",
24543                852.0,
24544                "Light",
24545                "OM",
24546            ),
24547            "crown" | "sahasrara" | "7" => (
24548                "Crown",
24549                "सहस्रार",
24550                "Violet",
24551                "#8B00FF",
24552                "Top of head",
24553                963.0,
24554                "Thought",
24555                "Silence",
24556            ),
24557            _ => {
24558                return Err(RuntimeError::new(
24559                    "Unknown chakra. Use root/sacral/solar/heart/throat/third_eye/crown or 1-7",
24560                ))
24561            }
24562        };
24563        let mut map = std::collections::HashMap::new();
24564        map.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
24565        map.insert(
24566            "sanskrit".to_string(),
24567            Value::String(Rc::new(sanskrit.to_string())),
24568        );
24569        map.insert(
24570            "color".to_string(),
24571            Value::String(Rc::new(color.to_string())),
24572        );
24573        map.insert("hex".to_string(), Value::String(Rc::new(hex.to_string())));
24574        map.insert(
24575            "location".to_string(),
24576            Value::String(Rc::new(location.to_string())),
24577        );
24578        map.insert("frequency_hz".to_string(), Value::Float(freq));
24579        map.insert(
24580            "element".to_string(),
24581            Value::String(Rc::new(element.to_string())),
24582        );
24583        map.insert(
24584            "mantra".to_string(),
24585            Value::String(Rc::new(mantra.to_string())),
24586        );
24587        Ok(Value::Map(Rc::new(RefCell::new(map))))
24588    });
24589
24590    // =========================================================================
24591    // MAYAN DIRECTIONAL COLORS
24592    // =========================================================================
24593    define(interp, "maya_direction", Some(1), |_, args| {
24594        let dir = match &args[0] {
24595            Value::String(s) => s.to_lowercase(),
24596            _ => return Err(RuntimeError::new("requires string")),
24597        };
24598        let (direction, yucatec, color, hex, deity, meaning) = match dir.as_str() {
24599            "east" | "lakin" => (
24600                "East",
24601                "Lak'in",
24602                "Red",
24603                "#FF0000",
24604                "Chac (Red)",
24605                "Sunrise, new beginnings",
24606            ),
24607            "north" | "xaman" => (
24608                "North",
24609                "Xaman",
24610                "White",
24611                "#FFFFFF",
24612                "Chac (White)",
24613                "Ancestors, death",
24614            ),
24615            "west" | "chikin" => (
24616                "West",
24617                "Chik'in",
24618                "Black",
24619                "#000000",
24620                "Chac (Black)",
24621                "Sunset, completion",
24622            ),
24623            "south" | "nohol" => (
24624                "South",
24625                "Nohol",
24626                "Yellow",
24627                "#FFFF00",
24628                "Chac (Yellow)",
24629                "Maize, abundance",
24630            ),
24631            "center" | "yax" => (
24632                "Center",
24633                "Yax",
24634                "Green/Blue",
24635                "#00CED1",
24636                "World Tree",
24637                "Balance",
24638            ),
24639            _ => {
24640                return Err(RuntimeError::new(
24641                    "Unknown direction. Use east/north/west/south/center",
24642                ))
24643            }
24644        };
24645        let mut map = std::collections::HashMap::new();
24646        map.insert(
24647            "direction".to_string(),
24648            Value::String(Rc::new(direction.to_string())),
24649        );
24650        map.insert(
24651            "yucatec".to_string(),
24652            Value::String(Rc::new(yucatec.to_string())),
24653        );
24654        map.insert(
24655            "color".to_string(),
24656            Value::String(Rc::new(color.to_string())),
24657        );
24658        map.insert("hex".to_string(), Value::String(Rc::new(hex.to_string())));
24659        map.insert(
24660            "deity".to_string(),
24661            Value::String(Rc::new(deity.to_string())),
24662        );
24663        map.insert(
24664            "meaning".to_string(),
24665            Value::String(Rc::new(meaning.to_string())),
24666        );
24667        Ok(Value::Map(Rc::new(RefCell::new(map))))
24668    });
24669
24670    // =========================================================================
24671    // ORISHA COLORS (Yoruba/African)
24672    // =========================================================================
24673    define(interp, "orisha_color", Some(1), |_, args| {
24674        let orisha = match &args[0] {
24675            Value::String(s) => s.to_lowercase(),
24676            _ => return Err(RuntimeError::new("requires string")),
24677        };
24678        let (name, colors, hex, domain, day, number) = match orisha.as_str() {
24679            "obatala" | "oxala" => (
24680                "Obatalá",
24681                "White, silver",
24682                "#FFFFFF",
24683                "Creation, purity, wisdom",
24684                "Sunday",
24685                8,
24686            ),
24687            "yemoja" | "yemanja" => (
24688                "Yemọja",
24689                "Blue, white",
24690                "#4169E1",
24691                "Ocean, motherhood",
24692                "Saturday",
24693                7,
24694            ),
24695            "oshun" | "oxum" => (
24696                "Ọṣun",
24697                "Yellow, gold",
24698                "#FFD700",
24699                "Rivers, love, fertility",
24700                "Saturday",
24701                5,
24702            ),
24703            "shango" | "xango" => (
24704                "Ṣàngó",
24705                "Red, white",
24706                "#FF0000",
24707                "Thunder, fire, justice",
24708                "Wednesday",
24709                6,
24710            ),
24711            "ogun" | "ogum" => (
24712                "Ògún",
24713                "Green, black",
24714                "#006400",
24715                "Iron, war, labor",
24716                "Tuesday",
24717                7,
24718            ),
24719            "oya" | "iansa" => (
24720                "Ọya",
24721                "Brown, purple",
24722                "#800020",
24723                "Wind, storms, change",
24724                "Wednesday",
24725                9,
24726            ),
24727            "eshu" | "exu" => (
24728                "Èṣù",
24729                "Red, black",
24730                "#8B0000",
24731                "Crossroads, messages",
24732                "Monday",
24733                3,
24734            ),
24735            _ => {
24736                return Err(RuntimeError::new(
24737                    "Unknown Orisha. Use obatala/yemoja/oshun/shango/ogun/oya/eshu",
24738                ))
24739            }
24740        };
24741        let mut map = std::collections::HashMap::new();
24742        map.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
24743        map.insert(
24744            "colors".to_string(),
24745            Value::String(Rc::new(colors.to_string())),
24746        );
24747        map.insert("hex".to_string(), Value::String(Rc::new(hex.to_string())));
24748        map.insert(
24749            "domain".to_string(),
24750            Value::String(Rc::new(domain.to_string())),
24751        );
24752        map.insert("day".to_string(), Value::String(Rc::new(day.to_string())));
24753        map.insert("number".to_string(), Value::Int(number));
24754        Ok(Value::Map(Rc::new(RefCell::new(map))))
24755    });
24756
24757    // =========================================================================
24758    // JAPANESE TRADITIONAL COLORS (nihon_iro)
24759    // =========================================================================
24760    define(interp, "nihon_iro", Some(1), |_, args| {
24761        let color = match &args[0] {
24762            Value::String(s) => s.to_lowercase(),
24763            _ => return Err(RuntimeError::new("requires string")),
24764        };
24765        let (name, japanese, hex, meaning, season) = match color.as_str() {
24766            "sakura" => (
24767                "Sakura Pink",
24768                "桜色",
24769                "#FFB7C5",
24770                "Cherry blossoms, transience",
24771                "Spring",
24772            ),
24773            "fuji" => (
24774                "Wisteria",
24775                "藤色",
24776                "#C9A0DC",
24777                "Elegance, nobility",
24778                "Spring",
24779            ),
24780            "moegi" => (
24781                "Young Green",
24782                "萌黄",
24783                "#AACF53",
24784                "New growth, freshness",
24785                "Spring",
24786            ),
24787            "ai" => ("Indigo", "藍色", "#004D99", "Protection, depth", "All"),
24788            "akane" => ("Madder Red", "茜色", "#CF3A24", "Sunset, passion", "Autumn"),
24789            "shiro" => ("White", "白", "#FFFFFF", "Purity, death, sacred", "Winter"),
24790            "kuro" => ("Black", "黒", "#000000", "Formality, mystery", "All"),
24791            "aka" => ("Red", "赤", "#D7003A", "Life force, celebration", "All"),
24792            "murasaki" => ("Purple", "紫", "#884898", "Nobility, spirituality", "All"),
24793            _ => {
24794                return Err(RuntimeError::new(
24795                    "Unknown color. Try: sakura/fuji/moegi/ai/akane/shiro/kuro/aka/murasaki",
24796                ))
24797            }
24798        };
24799        let mut map = std::collections::HashMap::new();
24800        map.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
24801        map.insert(
24802            "japanese".to_string(),
24803            Value::String(Rc::new(japanese.to_string())),
24804        );
24805        map.insert("hex".to_string(), Value::String(Rc::new(hex.to_string())));
24806        map.insert(
24807            "meaning".to_string(),
24808            Value::String(Rc::new(meaning.to_string())),
24809        );
24810        map.insert(
24811            "season".to_string(),
24812            Value::String(Rc::new(season.to_string())),
24813        );
24814        Ok(Value::Map(Rc::new(RefCell::new(map))))
24815    });
24816
24817    // =========================================================================
24818    // ISLAMIC COLOR SYMBOLISM
24819    // =========================================================================
24820    define(interp, "islamic_color", Some(1), |_, args| {
24821        let color = match &args[0] {
24822            Value::String(s) => s.to_lowercase(),
24823            _ => return Err(RuntimeError::new("requires string")),
24824        };
24825        let (name, arabic, hex, meaning, usage) = match color.as_str() {
24826            "green" | "akhdar" => (
24827                "Green",
24828                "أخضر",
24829                "#00FF00",
24830                "Paradise, Prophet, life",
24831                "Mosques, Quran, flags",
24832            ),
24833            "white" | "abyad" => (
24834                "White",
24835                "أبيض",
24836                "#FFFFFF",
24837                "Purity, peace, ihram",
24838                "Pilgrimage, burial",
24839            ),
24840            "black" | "aswad" => (
24841                "Black",
24842                "أسود",
24843                "#000000",
24844                "Modesty, Kaaba",
24845                "Kiswah, abaya",
24846            ),
24847            "gold" | "dhahabi" => (
24848                "Gold",
24849                "ذهبي",
24850                "#FFD700",
24851                "Paradise, divine light",
24852                "Calligraphy, decoration",
24853            ),
24854            "blue" | "azraq" => (
24855                "Blue",
24856                "أزرق",
24857                "#0000CD",
24858                "Protection, heaven",
24859                "Tiles, evil eye",
24860            ),
24861            _ => {
24862                return Err(RuntimeError::new(
24863                    "Unknown color. Use green/white/black/gold/blue",
24864                ))
24865            }
24866        };
24867        let mut map = std::collections::HashMap::new();
24868        map.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
24869        map.insert(
24870            "arabic".to_string(),
24871            Value::String(Rc::new(arabic.to_string())),
24872        );
24873        map.insert("hex".to_string(), Value::String(Rc::new(hex.to_string())));
24874        map.insert(
24875            "meaning".to_string(),
24876            Value::String(Rc::new(meaning.to_string())),
24877        );
24878        map.insert(
24879            "usage".to_string(),
24880            Value::String(Rc::new(usage.to_string())),
24881        );
24882        Ok(Value::Map(Rc::new(RefCell::new(map))))
24883    });
24884
24885    // =========================================================================
24886    // THAI DAY COLORS
24887    // =========================================================================
24888    define(interp, "thai_day_color", Some(1), |_, args| {
24889        let day = match &args[0] {
24890            Value::String(s) => s.to_lowercase(),
24891            Value::Int(n) => n.to_string(),
24892            _ => return Err(RuntimeError::new("requires string or number")),
24893        };
24894        let (day_name, thai, color, hex, deity) = match day.as_str() {
24895            "sunday" | "0" => ("Sunday", "วันอาทิตย์", "Red", "#FF0000", "Surya"),
24896            "monday" | "1" => ("Monday", "วันจันทร์", "Yellow", "#FFFF00", "Chandra"),
24897            "tuesday" | "2" => ("Tuesday", "วันอังคาร", "Pink", "#FFC0CB", "Mangala"),
24898            "wednesday" | "3" => ("Wednesday", "วันพุธ", "Green", "#00FF00", "Budha"),
24899            "thursday" | "4" => ("Thursday", "วันพฤหัสบดี", "Orange", "#FFA500", "Brihaspati"),
24900            "friday" | "5" => ("Friday", "วันศุกร์", "Blue", "#00BFFF", "Shukra"),
24901            "saturday" | "6" => ("Saturday", "วันเสาร์", "Purple", "#800080", "Shani"),
24902            _ => return Err(RuntimeError::new("Unknown day. Use sunday-saturday or 0-6")),
24903        };
24904        let mut map = std::collections::HashMap::new();
24905        map.insert(
24906            "day".to_string(),
24907            Value::String(Rc::new(day_name.to_string())),
24908        );
24909        map.insert("thai".to_string(), Value::String(Rc::new(thai.to_string())));
24910        map.insert(
24911            "color".to_string(),
24912            Value::String(Rc::new(color.to_string())),
24913        );
24914        map.insert("hex".to_string(), Value::String(Rc::new(hex.to_string())));
24915        map.insert(
24916            "deity".to_string(),
24917            Value::String(Rc::new(deity.to_string())),
24918        );
24919        Ok(Value::Map(Rc::new(RefCell::new(map))))
24920    });
24921
24922    // =========================================================================
24923    // ABORIGINAL AUSTRALIAN COLORS
24924    // =========================================================================
24925    define(interp, "aboriginal_color", Some(1), |_, args| {
24926        let color = match &args[0] {
24927            Value::String(s) => s.to_lowercase(),
24928            _ => return Err(RuntimeError::new("requires string")),
24929        };
24930        let (name, hex, meaning, source, dreamtime) = match color.as_str() {
24931            "red" | "ochre" => (
24932                "Red Ochre",
24933                "#CC5500",
24934                "Earth, blood, ceremony",
24935                "Hematite",
24936                "Ancestral beings",
24937            ),
24938            "yellow" => (
24939                "Yellow Ochre",
24940                "#D4A017",
24941                "Sun, healing",
24942                "Limonite",
24943                "Sun's journey",
24944            ),
24945            "white" => (
24946                "White",
24947                "#FFFFFF",
24948                "Sky, spirits, mourning",
24949                "Kaolin",
24950                "Sky beings",
24951            ),
24952            "black" => (
24953                "Black",
24954                "#000000",
24955                "Night, formality",
24956                "Charcoal",
24957                "Night, men's business",
24958            ),
24959            "brown" => (
24960                "Brown",
24961                "#8B4513",
24962                "Earth, land",
24963                "Earth pigments",
24964                "Country, connection",
24965            ),
24966            _ => {
24967                return Err(RuntimeError::new(
24968                    "Unknown color. Use red/yellow/white/black/brown",
24969                ))
24970            }
24971        };
24972        let mut map = std::collections::HashMap::new();
24973        map.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
24974        map.insert("hex".to_string(), Value::String(Rc::new(hex.to_string())));
24975        map.insert(
24976            "meaning".to_string(),
24977            Value::String(Rc::new(meaning.to_string())),
24978        );
24979        map.insert(
24980            "source".to_string(),
24981            Value::String(Rc::new(source.to_string())),
24982        );
24983        map.insert(
24984            "dreamtime".to_string(),
24985            Value::String(Rc::new(dreamtime.to_string())),
24986        );
24987        Ok(Value::Map(Rc::new(RefCell::new(map))))
24988    });
24989
24990    // =========================================================================
24991    // CELTIC COLORS
24992    // =========================================================================
24993    define(interp, "celtic_color", Some(1), |_, args| {
24994        let color = match &args[0] {
24995            Value::String(s) => s.to_lowercase(),
24996            _ => return Err(RuntimeError::new("requires string")),
24997        };
24998        let (name, gaelic, hex, meaning, element) = match color.as_str() {
24999            "green" => (
25000                "Green",
25001                "Glas",
25002                "#228B22",
25003                "Nature, fairies, Otherworld",
25004                "Earth",
25005            ),
25006            "white" => ("White", "Bán", "#FFFFFF", "Purity, spirits", "Air"),
25007            "red" => ("Red", "Dearg", "#FF0000", "War, courage, blood", "Fire"),
25008            "black" => (
25009                "Black",
25010                "Dubh",
25011                "#000000",
25012                "Otherworld, death, rebirth",
25013                "Water",
25014            ),
25015            "gold" => ("Gold", "Órga", "#FFD700", "Sun, sovereignty, Lugh", "Fire"),
25016            "silver" => (
25017                "Silver",
25018                "Airgid",
25019                "#C0C0C0",
25020                "Moon, feminine, intuition",
25021                "Water",
25022            ),
25023            _ => {
25024                return Err(RuntimeError::new(
25025                    "Unknown color. Use green/white/red/black/gold/silver",
25026                ))
25027            }
25028        };
25029        let mut map = std::collections::HashMap::new();
25030        map.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
25031        map.insert(
25032            "gaelic".to_string(),
25033            Value::String(Rc::new(gaelic.to_string())),
25034        );
25035        map.insert("hex".to_string(), Value::String(Rc::new(hex.to_string())));
25036        map.insert(
25037            "meaning".to_string(),
25038            Value::String(Rc::new(meaning.to_string())),
25039        );
25040        map.insert(
25041            "element".to_string(),
25042            Value::String(Rc::new(element.to_string())),
25043        );
25044        Ok(Value::Map(Rc::new(RefCell::new(map))))
25045    });
25046
25047    // =========================================================================
25048    // KENTE CLOTH COLORS (Ghana)
25049    // =========================================================================
25050    define(interp, "kente_color", Some(1), |_, args| {
25051        let color = match &args[0] {
25052            Value::String(s) => s.to_lowercase(),
25053            _ => return Err(RuntimeError::new("requires string")),
25054        };
25055        let (name, twi, hex, meaning) = match color.as_str() {
25056            "gold" | "yellow" => ("Gold", "Sika Kɔkɔɔ", "#FFD700", "Royalty, wealth, glory"),
25057            "green" => ("Green", "Ahabammono", "#228B22", "Growth, renewal, harvest"),
25058            "blue" => ("Blue", "Bruu", "#0000CD", "Peace, harmony, love"),
25059            "red" => ("Red", "Kɔkɔɔ", "#FF0000", "Blood, sacrifice, power"),
25060            "black" => ("Black", "Tuntum", "#000000", "Maturation, ancestors"),
25061            "white" => ("White", "Fitaa", "#FFFFFF", "Purification, virtue, joy"),
25062            "maroon" => ("Maroon", "Borɔnɔ", "#800000", "Earth, healing, protection"),
25063            _ => {
25064                return Err(RuntimeError::new(
25065                    "Unknown color. Use gold/green/blue/red/black/white/maroon",
25066                ))
25067            }
25068        };
25069        let mut map = std::collections::HashMap::new();
25070        map.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
25071        map.insert("twi".to_string(), Value::String(Rc::new(twi.to_string())));
25072        map.insert("hex".to_string(), Value::String(Rc::new(hex.to_string())));
25073        map.insert(
25074            "meaning".to_string(),
25075            Value::String(Rc::new(meaning.to_string())),
25076        );
25077        Ok(Value::Map(Rc::new(RefCell::new(map))))
25078    });
25079
25080    // =========================================================================
25081    // HINDU COLOR SYMBOLISM
25082    // =========================================================================
25083    define(interp, "hindu_color", Some(1), |_, args| {
25084        let color = match &args[0] {
25085            Value::String(s) => s.to_lowercase(),
25086            _ => return Err(RuntimeError::new("requires string")),
25087        };
25088        let (name, hindi, hex, meaning, deities) = match color.as_str() {
25089            "red" | "lal" => (
25090                "Red",
25091                "लाल",
25092                "#FF0000",
25093                "Purity, fertility, love",
25094                "Durga, Lakshmi",
25095            ),
25096            "orange" | "saffron" => (
25097                "Saffron",
25098                "केसरी",
25099                "#FF6600",
25100                "Sacred, renunciation",
25101                "Hanuman",
25102            ),
25103            "yellow" => (
25104                "Yellow",
25105                "पीला",
25106                "#FFFF00",
25107                "Knowledge, learning",
25108                "Vishnu, Saraswati",
25109            ),
25110            "green" => ("Green", "हरा", "#008000", "Life, happiness", "Krishna"),
25111            "white" => (
25112                "White",
25113                "सफ़ेद",
25114                "#FFFFFF",
25115                "Purity, mourning",
25116                "Saraswati, Shiva",
25117            ),
25118            "blue" => (
25119                "Blue",
25120                "नीला",
25121                "#0000FF",
25122                "Divinity, infinity",
25123                "Krishna, Vishnu",
25124            ),
25125            "black" => (
25126                "Black",
25127                "काला",
25128                "#000000",
25129                "Protection from evil",
25130                "Kali, Shani",
25131            ),
25132            _ => {
25133                return Err(RuntimeError::new(
25134                    "Unknown color. Use red/orange/yellow/green/white/blue/black",
25135                ))
25136            }
25137        };
25138        let mut map = std::collections::HashMap::new();
25139        map.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
25140        map.insert(
25141            "hindi".to_string(),
25142            Value::String(Rc::new(hindi.to_string())),
25143        );
25144        map.insert("hex".to_string(), Value::String(Rc::new(hex.to_string())));
25145        map.insert(
25146            "meaning".to_string(),
25147            Value::String(Rc::new(meaning.to_string())),
25148        );
25149        map.insert(
25150            "deities".to_string(),
25151            Value::String(Rc::new(deities.to_string())),
25152        );
25153        Ok(Value::Map(Rc::new(RefCell::new(map))))
25154    });
25155
25156    // =========================================================================
25157    // SYNESTHESIA - CROSS-MODAL MAPPING WITH CULTURAL CONTEXT
25158    // =========================================================================
25159    define(interp, "emotion_color", Some(2), |_, args| {
25160        let emotion = match &args[0] {
25161            Value::String(s) => s.to_lowercase(),
25162            _ => return Err(RuntimeError::new("requires string")),
25163        };
25164        let culture = match &args[1] {
25165            Value::String(s) => s.to_lowercase(),
25166            _ => return Err(RuntimeError::new("requires string")),
25167        };
25168        let (hex, name, reasoning) = match (emotion.as_str(), culture.as_str()) {
25169            ("joy", "western") | ("happy", "western") => {
25170                ("#FFD700", "Gold", "Sunshine = happiness")
25171            }
25172            ("joy", "chinese") | ("happy", "chinese") => ("#FF0000", "Red", "红 = luck, joy"),
25173            ("joy", "japanese") => ("#FFB7C5", "Sakura", "Cherry blossom = fleeting joy"),
25174            ("sadness", "western") | ("sad", "western") => ("#0000CD", "Blue", "'Feeling blue'"),
25175            ("sadness", "chinese") | ("sad", "chinese") => ("#FFFFFF", "White", "白 = mourning"),
25176            ("sadness", "indian") => ("#FFFFFF", "White", "सफ़ेद = mourning"),
25177            ("anger", _) => ("#FF0000", "Red", "Universal heat/fire"),
25178            ("love", "western") => ("#FF69B4", "Pink", "Valentine's hearts"),
25179            ("love", "chinese") | ("love", "indian") => ("#FF0000", "Red", "Red = marriage, love"),
25180            ("peace", "western") => ("#ADD8E6", "Light Blue", "Sky, serenity"),
25181            ("peace", "islamic") => ("#00FF00", "Green", "السلام = paradise"),
25182            ("fear", _) => ("#4B0082", "Indigo", "Deep, mysterious"),
25183            (_, _) => ("#808080", "Grey", "Neutral"),
25184        };
25185        let r = u8::from_str_radix(&hex[1..3], 16).unwrap_or(128);
25186        let g = u8::from_str_radix(&hex[3..5], 16).unwrap_or(128);
25187        let b = u8::from_str_radix(&hex[5..7], 16).unwrap_or(128);
25188        let mut map = std::collections::HashMap::new();
25189        map.insert("hex".to_string(), Value::String(Rc::new(hex.to_string())));
25190        map.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
25191        map.insert("r".to_string(), Value::Int(r as i64));
25192        map.insert("g".to_string(), Value::Int(g as i64));
25193        map.insert("b".to_string(), Value::Int(b as i64));
25194        map.insert(
25195            "reasoning".to_string(),
25196            Value::String(Rc::new(reasoning.to_string())),
25197        );
25198        Ok(Value::Map(Rc::new(RefCell::new(map))))
25199    });
25200
25201    // synesthesia - full cross-modal with cultural awareness
25202    define(interp, "synesthesia", Some(2), |_, args| {
25203        let culture = match &args[1] {
25204            Value::String(s) => s.to_lowercase(),
25205            _ => return Err(RuntimeError::new("requires culture string")),
25206        };
25207        let (r, g, b, emotion, freq) = match &args[0] {
25208            Value::String(s) => match s.to_lowercase().as_str() {
25209                "joy" | "happy" => (255u8, 215u8, 0u8, "joy", 528.0),
25210                "sadness" | "sad" => (0, 0, 139, "sadness", 396.0),
25211                "anger" => (255, 0, 0, "anger", 417.0),
25212                "fear" => (75, 0, 130, "fear", 369.0),
25213                "love" => (255, 105, 180, "love", 639.0),
25214                "peace" => (135, 206, 235, "peace", 741.0),
25215                _ => (128, 128, 128, "neutral", 432.0),
25216            },
25217            Value::Int(n) => (128, 128, 255, "resonance", *n as f64),
25218            Value::Float(f) => (128, 128, 255, "resonance", *f),
25219            _ => (128, 128, 128, "neutral", 432.0),
25220        };
25221        let cultural_meaning = match culture.as_str() {
25222            "chinese" if r > 200 && g < 100 => "luck/joy (红)",
25223            "japanese" if r > 200 && g < 100 => "vitality (赤)",
25224            "indian" if r > 200 && g < 100 => "shakti/auspicious",
25225            _ => "universal resonance",
25226        };
25227        let chakra = if r > 200 && g < 100 {
25228            "Root"
25229        } else if g > 200 {
25230            "Heart"
25231        } else if b > 200 {
25232            "Throat"
25233        } else {
25234            "Crown"
25235        };
25236        let wu_xing = if r > 200 && g < 100 {
25237            "Fire (火)"
25238        } else if g > 200 {
25239            "Wood (木)"
25240        } else if b > 200 {
25241            "Water (水)"
25242        } else {
25243            "Metal (金)"
25244        };
25245        let mut map = std::collections::HashMap::new();
25246        let mut color_map = std::collections::HashMap::new();
25247        color_map.insert("r".to_string(), Value::Int(r as i64));
25248        color_map.insert("g".to_string(), Value::Int(g as i64));
25249        color_map.insert("b".to_string(), Value::Int(b as i64));
25250        color_map.insert(
25251            "hex".to_string(),
25252            Value::String(Rc::new(format!("#{:02X}{:02X}{:02X}", r, g, b))),
25253        );
25254        map.insert(
25255            "color".to_string(),
25256            Value::Map(Rc::new(RefCell::new(color_map))),
25257        );
25258        map.insert(
25259            "emotion".to_string(),
25260            Value::String(Rc::new(emotion.to_string())),
25261        );
25262        map.insert("frequency".to_string(), Value::Float(freq));
25263        map.insert(
25264            "cultural_meaning".to_string(),
25265            Value::String(Rc::new(cultural_meaning.to_string())),
25266        );
25267        map.insert(
25268            "chakra".to_string(),
25269            Value::String(Rc::new(chakra.to_string())),
25270        );
25271        map.insert(
25272            "wu_xing".to_string(),
25273            Value::String(Rc::new(wu_xing.to_string())),
25274        );
25275        Ok(Value::Map(Rc::new(RefCell::new(map))))
25276    });
25277
25278    // color_to_sound - Scriabin-inspired mapping
25279    define(interp, "color_to_sound", Some(3), |_, args| {
25280        let r = match &args[0] {
25281            Value::Int(n) => *n as f64 / 255.0,
25282            Value::Float(f) => *f / 255.0,
25283            _ => return Err(RuntimeError::new("requires numbers")),
25284        };
25285        let g = match &args[1] {
25286            Value::Int(n) => *n as f64 / 255.0,
25287            Value::Float(f) => *f / 255.0,
25288            _ => return Err(RuntimeError::new("requires numbers")),
25289        };
25290        let b = match &args[2] {
25291            Value::Int(n) => *n as f64 / 255.0,
25292            Value::Float(f) => *f / 255.0,
25293            _ => return Err(RuntimeError::new("requires numbers")),
25294        };
25295        let max = r.max(g).max(b);
25296        let min = r.min(g).min(b);
25297        let l = (max + min) / 2.0;
25298        let h = if max == min {
25299            0.0
25300        } else {
25301            let d = max - min;
25302            if max == r {
25303                (g - b) / d + if g < b { 6.0 } else { 0.0 }
25304            } else if max == g {
25305                (b - r) / d + 2.0
25306            } else {
25307                (r - g) / d + 4.0
25308            }
25309        } * 60.0;
25310        let (note, freq) = if h < 30.0 {
25311            ("C", 261.63)
25312        } else if h < 60.0 {
25313            ("G", 392.00)
25314        } else if h < 90.0 {
25315            ("D", 293.66)
25316        } else if h < 120.0 {
25317            ("A", 440.00)
25318        } else if h < 150.0 {
25319            ("E", 329.63)
25320        } else if h < 180.0 {
25321            ("B", 493.88)
25322        } else if h < 210.0 {
25323            ("F#", 369.99)
25324        } else if h < 240.0 {
25325            ("Db", 277.18)
25326        } else if h < 270.0 {
25327            ("Ab", 415.30)
25328        } else if h < 300.0 {
25329            ("Eb", 311.13)
25330        } else if h < 330.0 {
25331            ("Bb", 466.16)
25332        } else {
25333            ("F", 349.23)
25334        };
25335        let octave_shift = ((l - 0.5) * 4.0).round() as i32;
25336        let adjusted_freq = freq * 2.0_f64.powi(octave_shift);
25337        let mut map = std::collections::HashMap::new();
25338        map.insert("note".to_string(), Value::String(Rc::new(note.to_string())));
25339        map.insert("frequency".to_string(), Value::Float(adjusted_freq));
25340        map.insert("hue".to_string(), Value::Float(h));
25341        Ok(Value::Map(Rc::new(RefCell::new(map))))
25342    });
25343
25344    // contrast_ratio - WCAG accessibility
25345    define(interp, "contrast_ratio", Some(6), |_, args| {
25346        fn lum(r: f64, g: f64, b: f64) -> f64 {
25347            fn ch(c: f64) -> f64 {
25348                let c = c / 255.0;
25349                if c <= 0.03928 {
25350                    c / 12.92
25351                } else {
25352                    ((c + 0.055) / 1.055).powf(2.4)
25353                }
25354            }
25355            0.2126 * ch(r) + 0.7152 * ch(g) + 0.0722 * ch(b)
25356        }
25357        let r1 = match &args[0] {
25358            Value::Int(n) => *n as f64,
25359            Value::Float(f) => *f,
25360            _ => return Err(RuntimeError::new("requires numbers")),
25361        };
25362        let g1 = match &args[1] {
25363            Value::Int(n) => *n as f64,
25364            Value::Float(f) => *f,
25365            _ => return Err(RuntimeError::new("requires numbers")),
25366        };
25367        let b1 = match &args[2] {
25368            Value::Int(n) => *n as f64,
25369            Value::Float(f) => *f,
25370            _ => return Err(RuntimeError::new("requires numbers")),
25371        };
25372        let r2 = match &args[3] {
25373            Value::Int(n) => *n as f64,
25374            Value::Float(f) => *f,
25375            _ => return Err(RuntimeError::new("requires numbers")),
25376        };
25377        let g2 = match &args[4] {
25378            Value::Int(n) => *n as f64,
25379            Value::Float(f) => *f,
25380            _ => return Err(RuntimeError::new("requires numbers")),
25381        };
25382        let b2 = match &args[5] {
25383            Value::Int(n) => *n as f64,
25384            Value::Float(f) => *f,
25385            _ => return Err(RuntimeError::new("requires numbers")),
25386        };
25387        let l1 = lum(r1, g1, b1);
25388        let l2 = lum(r2, g2, b2);
25389        let ratio = if l1 > l2 {
25390            (l1 + 0.05) / (l2 + 0.05)
25391        } else {
25392            (l2 + 0.05) / (l1 + 0.05)
25393        };
25394        let mut map = std::collections::HashMap::new();
25395        map.insert("ratio".to_string(), Value::Float(ratio));
25396        map.insert("aa_normal".to_string(), Value::Bool(ratio >= 4.5));
25397        map.insert("aa_large".to_string(), Value::Bool(ratio >= 3.0));
25398        map.insert("aaa_normal".to_string(), Value::Bool(ratio >= 7.0));
25399        Ok(Value::Map(Rc::new(RefCell::new(map))))
25400    });
25401}
25402
25403// ============================================================================
25404// PROTOCOL FUNCTIONS (Phase 17)
25405// ============================================================================
25406
25407/// Register protocol functions for HTTP, gRPC, WebSocket, Kafka, AMQP, GraphQL
25408/// Note: Actual async network operations require runtime support.
25409/// These functions provide protocol information and synchronous utilities.
25410fn register_protocol(interp: &mut Interpreter) {
25411    // protocol_info - Get information about supported protocols
25412    define(interp, "protocol_info", Some(0), |_, _args| {
25413        let mut map = std::collections::HashMap::new();
25414        map.insert(
25415            "http".to_string(),
25416            Value::Map(Rc::new(RefCell::new({
25417                let mut m = std::collections::HashMap::new();
25418                m.insert(
25419                    "name".to_string(),
25420                    Value::String(Rc::new("HTTP".to_string())),
25421                );
25422                m.insert(
25423                    "versions".to_string(),
25424                    Value::Array(Rc::new(RefCell::new(vec![
25425                        Value::String(Rc::new("1.1".to_string())),
25426                        Value::String(Rc::new("2".to_string())),
25427                    ]))),
25428                );
25429                m.insert(
25430                    "methods".to_string(),
25431                    Value::Array(Rc::new(RefCell::new(vec![
25432                        Value::String(Rc::new("GET".to_string())),
25433                        Value::String(Rc::new("POST".to_string())),
25434                        Value::String(Rc::new("PUT".to_string())),
25435                        Value::String(Rc::new("DELETE".to_string())),
25436                        Value::String(Rc::new("PATCH".to_string())),
25437                        Value::String(Rc::new("HEAD".to_string())),
25438                        Value::String(Rc::new("OPTIONS".to_string())),
25439                    ]))),
25440                );
25441                m
25442            }))),
25443        );
25444        map.insert(
25445            "grpc".to_string(),
25446            Value::Map(Rc::new(RefCell::new({
25447                let mut m = std::collections::HashMap::new();
25448                m.insert(
25449                    "name".to_string(),
25450                    Value::String(Rc::new("gRPC".to_string())),
25451                );
25452                m.insert(
25453                    "streaming_modes".to_string(),
25454                    Value::Array(Rc::new(RefCell::new(vec![
25455                        Value::String(Rc::new("unary".to_string())),
25456                        Value::String(Rc::new("server_streaming".to_string())),
25457                        Value::String(Rc::new("client_streaming".to_string())),
25458                        Value::String(Rc::new("bidirectional".to_string())),
25459                    ]))),
25460                );
25461                m
25462            }))),
25463        );
25464        map.insert(
25465            "websocket".to_string(),
25466            Value::Map(Rc::new(RefCell::new({
25467                let mut m = std::collections::HashMap::new();
25468                m.insert(
25469                    "name".to_string(),
25470                    Value::String(Rc::new("WebSocket".to_string())),
25471                );
25472                m.insert(
25473                    "message_types".to_string(),
25474                    Value::Array(Rc::new(RefCell::new(vec![
25475                        Value::String(Rc::new("text".to_string())),
25476                        Value::String(Rc::new("binary".to_string())),
25477                        Value::String(Rc::new("ping".to_string())),
25478                        Value::String(Rc::new("pong".to_string())),
25479                        Value::String(Rc::new("close".to_string())),
25480                    ]))),
25481                );
25482                m
25483            }))),
25484        );
25485        map.insert(
25486            "kafka".to_string(),
25487            Value::Map(Rc::new(RefCell::new({
25488                let mut m = std::collections::HashMap::new();
25489                m.insert(
25490                    "name".to_string(),
25491                    Value::String(Rc::new("Apache Kafka".to_string())),
25492                );
25493                m.insert(
25494                    "acks".to_string(),
25495                    Value::Array(Rc::new(RefCell::new(vec![
25496                        Value::String(Rc::new("none".to_string())),
25497                        Value::String(Rc::new("leader".to_string())),
25498                        Value::String(Rc::new("all".to_string())),
25499                    ]))),
25500                );
25501                m
25502            }))),
25503        );
25504        map.insert(
25505            "amqp".to_string(),
25506            Value::Map(Rc::new(RefCell::new({
25507                let mut m = std::collections::HashMap::new();
25508                m.insert(
25509                    "name".to_string(),
25510                    Value::String(Rc::new("AMQP".to_string())),
25511                );
25512                m.insert(
25513                    "exchange_types".to_string(),
25514                    Value::Array(Rc::new(RefCell::new(vec![
25515                        Value::String(Rc::new("direct".to_string())),
25516                        Value::String(Rc::new("fanout".to_string())),
25517                        Value::String(Rc::new("topic".to_string())),
25518                        Value::String(Rc::new("headers".to_string())),
25519                    ]))),
25520                );
25521                m
25522            }))),
25523        );
25524        map.insert(
25525            "graphql".to_string(),
25526            Value::Map(Rc::new(RefCell::new({
25527                let mut m = std::collections::HashMap::new();
25528                m.insert(
25529                    "name".to_string(),
25530                    Value::String(Rc::new("GraphQL".to_string())),
25531                );
25532                m.insert(
25533                    "operations".to_string(),
25534                    Value::Array(Rc::new(RefCell::new(vec![
25535                        Value::String(Rc::new("query".to_string())),
25536                        Value::String(Rc::new("mutation".to_string())),
25537                        Value::String(Rc::new("subscription".to_string())),
25538                    ]))),
25539                );
25540                m
25541            }))),
25542        );
25543        Ok(Value::Map(Rc::new(RefCell::new(map))))
25544    });
25545
25546    // http_status_text - Get status text for HTTP status code
25547    define(interp, "http_status_text", Some(1), |_, args| {
25548        let code = match &args[0] {
25549            Value::Int(n) => *n,
25550            _ => {
25551                return Err(RuntimeError::new(
25552                    "http_status_text requires integer status code",
25553                ))
25554            }
25555        };
25556        let text = match code {
25557            100 => "Continue",
25558            101 => "Switching Protocols",
25559            200 => "OK",
25560            201 => "Created",
25561            202 => "Accepted",
25562            204 => "No Content",
25563            301 => "Moved Permanently",
25564            302 => "Found",
25565            304 => "Not Modified",
25566            307 => "Temporary Redirect",
25567            308 => "Permanent Redirect",
25568            400 => "Bad Request",
25569            401 => "Unauthorized",
25570            403 => "Forbidden",
25571            404 => "Not Found",
25572            405 => "Method Not Allowed",
25573            409 => "Conflict",
25574            422 => "Unprocessable Entity",
25575            429 => "Too Many Requests",
25576            500 => "Internal Server Error",
25577            502 => "Bad Gateway",
25578            503 => "Service Unavailable",
25579            504 => "Gateway Timeout",
25580            _ => "Unknown",
25581        };
25582        Ok(Value::String(Rc::new(text.to_string())))
25583    });
25584
25585    // http_status_type - Get status type (informational, success, redirect, client_error, server_error)
25586    define(interp, "http_status_type", Some(1), |_, args| {
25587        let code = match &args[0] {
25588            Value::Int(n) => *n,
25589            _ => {
25590                return Err(RuntimeError::new(
25591                    "http_status_type requires integer status code",
25592                ))
25593            }
25594        };
25595        let status_type = match code {
25596            100..=199 => "informational",
25597            200..=299 => "success",
25598            300..=399 => "redirect",
25599            400..=499 => "client_error",
25600            500..=599 => "server_error",
25601            _ => "unknown",
25602        };
25603        Ok(Value::String(Rc::new(status_type.to_string())))
25604    });
25605
25606    // grpc_status_text - Get status text for gRPC status code
25607    define(interp, "grpc_status_text", Some(1), |_, args| {
25608        let code = match &args[0] {
25609            Value::Int(n) => *n,
25610            _ => {
25611                return Err(RuntimeError::new(
25612                    "grpc_status_text requires integer status code",
25613                ))
25614            }
25615        };
25616        let text = match code {
25617            0 => "OK",
25618            1 => "CANCELLED",
25619            2 => "UNKNOWN",
25620            3 => "INVALID_ARGUMENT",
25621            4 => "DEADLINE_EXCEEDED",
25622            5 => "NOT_FOUND",
25623            6 => "ALREADY_EXISTS",
25624            7 => "PERMISSION_DENIED",
25625            8 => "RESOURCE_EXHAUSTED",
25626            9 => "FAILED_PRECONDITION",
25627            10 => "ABORTED",
25628            11 => "OUT_OF_RANGE",
25629            12 => "UNIMPLEMENTED",
25630            13 => "INTERNAL",
25631            14 => "UNAVAILABLE",
25632            15 => "DATA_LOSS",
25633            16 => "UNAUTHENTICATED",
25634            _ => "UNKNOWN",
25635        };
25636        Ok(Value::String(Rc::new(text.to_string())))
25637    });
25638
25639    // url_parse - Parse a URL into components
25640    define(interp, "url_parse", Some(1), |_, args| {
25641        let url_str = match &args[0] {
25642            Value::String(s) => s.as_str().to_string(),
25643            _ => return Err(RuntimeError::new("url_parse requires string URL")),
25644        };
25645
25646        // Simple URL parsing
25647        let mut map = std::collections::HashMap::new();
25648
25649        // Parse scheme
25650        let (scheme, rest) = if let Some(pos) = url_str.find("://") {
25651            (url_str[..pos].to_string(), &url_str[pos + 3..])
25652        } else {
25653            return Err(RuntimeError::new("Invalid URL: missing scheme"));
25654        };
25655        map.insert("scheme".to_string(), Value::String(Rc::new(scheme)));
25656
25657        // Parse host and path
25658        let (authority, path_and_rest) = if let Some(pos) = rest.find('/') {
25659            (&rest[..pos], &rest[pos..])
25660        } else {
25661            (rest, "/")
25662        };
25663
25664        // Parse host and port
25665        let (host, port) = if let Some(pos) = authority.rfind(':') {
25666            if let Ok(p) = authority[pos + 1..].parse::<i64>() {
25667                (authority[..pos].to_string(), Some(p))
25668            } else {
25669                (authority.to_string(), None)
25670            }
25671        } else {
25672            (authority.to_string(), None)
25673        };
25674        map.insert("host".to_string(), Value::String(Rc::new(host)));
25675        map.insert(
25676            "port".to_string(),
25677            port.map(Value::Int).unwrap_or(Value::Null),
25678        );
25679
25680        // Parse path and query
25681        let (path, query) = if let Some(pos) = path_and_rest.find('?') {
25682            (&path_and_rest[..pos], Some(&path_and_rest[pos + 1..]))
25683        } else {
25684            (path_and_rest, None)
25685        };
25686        map.insert("path".to_string(), Value::String(Rc::new(path.to_string())));
25687        map.insert(
25688            "query".to_string(),
25689            query
25690                .map(|q| Value::String(Rc::new(q.to_string())))
25691                .unwrap_or(Value::Null),
25692        );
25693
25694        Ok(Value::Map(Rc::new(RefCell::new(map))))
25695    });
25696
25697    // url_encode - URL-encode a string
25698    define(interp, "url_encode", Some(1), |_, args| {
25699        let s = match &args[0] {
25700            Value::String(s) => s.as_str(),
25701            _ => return Err(RuntimeError::new("url_encode requires string")),
25702        };
25703        let mut result = String::new();
25704        for c in s.chars() {
25705            match c {
25706                'a'..='z' | 'A'..='Z' | '0'..='9' | '-' | '_' | '.' | '~' => {
25707                    result.push(c);
25708                }
25709                ' ' => result.push_str("%20"),
25710                _ => {
25711                    for b in c.to_string().as_bytes() {
25712                        result.push_str(&format!("%{:02X}", b));
25713                    }
25714                }
25715            }
25716        }
25717        Ok(Value::String(Rc::new(result)))
25718    });
25719
25720    // url_decode - URL-decode a string
25721    define(interp, "url_decode", Some(1), |_, args| {
25722        let s = match &args[0] {
25723            Value::String(s) => s.as_str().to_string(),
25724            _ => return Err(RuntimeError::new("url_decode requires string")),
25725        };
25726        let mut result = Vec::new();
25727        let bytes = s.as_bytes();
25728        let mut i = 0;
25729        while i < bytes.len() {
25730            if bytes[i] == b'%' && i + 2 < bytes.len() {
25731                if let Ok(b) =
25732                    u8::from_str_radix(&String::from_utf8_lossy(&bytes[i + 1..i + 3]), 16)
25733                {
25734                    result.push(b);
25735                    i += 3;
25736                    continue;
25737                }
25738            } else if bytes[i] == b'+' {
25739                result.push(b' ');
25740                i += 1;
25741                continue;
25742            }
25743            result.push(bytes[i]);
25744            i += 1;
25745        }
25746        Ok(Value::String(Rc::new(
25747            String::from_utf8_lossy(&result).to_string(),
25748        )))
25749    });
25750
25751    // ws_close_code_text - Get text for WebSocket close code
25752    define(interp, "ws_close_code_text", Some(1), |_, args| {
25753        let code = match &args[0] {
25754            Value::Int(n) => *n,
25755            _ => {
25756                return Err(RuntimeError::new(
25757                    "ws_close_code_text requires integer code",
25758                ))
25759            }
25760        };
25761        let text = match code {
25762            1000 => "Normal Closure",
25763            1001 => "Going Away",
25764            1002 => "Protocol Error",
25765            1003 => "Unsupported Data",
25766            1005 => "No Status Received",
25767            1006 => "Abnormal Closure",
25768            1007 => "Invalid Payload Data",
25769            1008 => "Policy Violation",
25770            1009 => "Message Too Big",
25771            1010 => "Missing Extension",
25772            1011 => "Internal Error",
25773            1015 => "TLS Handshake Failure",
25774            _ => "Unknown",
25775        };
25776        Ok(Value::String(Rc::new(text.to_string())))
25777    });
25778
25779    // mime_type - Get MIME type for file extension
25780    define(interp, "mime_type", Some(1), |_, args| {
25781        let ext = match &args[0] {
25782            Value::String(s) => s.as_str().to_lowercase(),
25783            _ => return Err(RuntimeError::new("mime_type requires string extension")),
25784        };
25785        let ext = ext.trim_start_matches('.');
25786        let mime = match ext {
25787            "html" | "htm" => "text/html",
25788            "css" => "text/css",
25789            "js" | "mjs" => "text/javascript",
25790            "json" => "application/json",
25791            "xml" => "application/xml",
25792            "txt" => "text/plain",
25793            "csv" => "text/csv",
25794            "png" => "image/png",
25795            "jpg" | "jpeg" => "image/jpeg",
25796            "gif" => "image/gif",
25797            "svg" => "image/svg+xml",
25798            "webp" => "image/webp",
25799            "ico" => "image/x-icon",
25800            "pdf" => "application/pdf",
25801            "zip" => "application/zip",
25802            "gz" | "gzip" => "application/gzip",
25803            "mp3" => "audio/mpeg",
25804            "mp4" => "video/mp4",
25805            "webm" => "video/webm",
25806            "woff" => "font/woff",
25807            "woff2" => "font/woff2",
25808            "ttf" => "font/ttf",
25809            "otf" => "font/otf",
25810            "wasm" => "application/wasm",
25811            "proto" => "application/protobuf",
25812            _ => "application/octet-stream",
25813        };
25814        Ok(Value::String(Rc::new(mime.to_string())))
25815    });
25816
25817    // content_type_parse - Parse Content-Type header
25818    define(interp, "content_type_parse", Some(1), |_, args| {
25819        let ct = match &args[0] {
25820            Value::String(s) => s.as_str().to_string(),
25821            _ => return Err(RuntimeError::new("content_type_parse requires string")),
25822        };
25823        let mut map = std::collections::HashMap::new();
25824        let parts: Vec<&str> = ct.split(';').collect();
25825        map.insert(
25826            "media_type".to_string(),
25827            Value::String(Rc::new(parts[0].trim().to_string())),
25828        );
25829
25830        let mut params = std::collections::HashMap::new();
25831        for part in parts.iter().skip(1) {
25832            let kv: Vec<&str> = part.splitn(2, '=').collect();
25833            if kv.len() == 2 {
25834                let key = kv[0].trim().to_lowercase();
25835                let value = kv[1].trim().trim_matches('"').to_string();
25836                params.insert(key, Value::String(Rc::new(value)));
25837            }
25838        }
25839        map.insert(
25840            "params".to_string(),
25841            Value::Map(Rc::new(RefCell::new(params))),
25842        );
25843        Ok(Value::Map(Rc::new(RefCell::new(map))))
25844    });
25845}
25846
25847// ============================================================================
25848// PHASE 18: AI AGENT INFRASTRUCTURE
25849// ============================================================================
25850// Tools for building AI agents with:
25851// - Tool registry for introspectable function definitions
25852// - LLM client for model calls (OpenAI, Claude, local)
25853// - Agent memory for context and session persistence
25854// - Planning framework for state machines and goal tracking
25855// - Vector operations for embeddings and similarity search
25856
25857/// Global tool registry for agent introspection
25858thread_local! {
25859    static TOOL_REGISTRY: RefCell<HashMap<String, ToolDefinition>> = RefCell::new(HashMap::new());
25860    static AGENT_MEMORY: RefCell<HashMap<String, AgentSession>> = RefCell::new(HashMap::new());
25861    static STATE_MACHINES: RefCell<HashMap<String, StateMachine>> = RefCell::new(HashMap::new());
25862}
25863
25864/// Tool definition for LLM function calling
25865#[derive(Clone)]
25866struct ToolDefinition {
25867    name: String,
25868    description: String,
25869    parameters: Vec<ToolParameter>,
25870    returns: String,
25871    evidence_in: Evidence,
25872    evidence_out: Evidence,
25873    handler: Option<Rc<Function>>,
25874}
25875
25876#[derive(Clone)]
25877struct ToolParameter {
25878    name: String,
25879    param_type: String,
25880    description: String,
25881    required: bool,
25882    evidence: Evidence,
25883}
25884
25885/// Agent session for memory persistence
25886#[derive(Clone)]
25887struct AgentSession {
25888    id: String,
25889    context: HashMap<String, Value>,
25890    history: Vec<(String, String)>, // (role, content)
25891    created_at: u64,
25892    last_accessed: u64,
25893}
25894
25895/// State machine for planning
25896#[derive(Clone)]
25897struct StateMachine {
25898    name: String,
25899    current_state: String,
25900    states: Vec<String>,
25901    transitions: HashMap<String, Vec<(String, String)>>, // from -> [(to, condition)]
25902    history: Vec<(String, u64)>,                         // (state, timestamp)
25903}
25904
25905// ============================================================================
25906// TOOL REGISTRY - Introspectable function definitions for LLM tool_choice
25907// ============================================================================
25908
25909fn register_agent_tools(interp: &mut Interpreter) {
25910    // tool_define - Define a tool with metadata for LLM introspection
25911    // tool_define(name, description, params, returns, handler?)
25912    define(interp, "tool_define", None, |_interp, args| {
25913        if args.len() < 4 {
25914            return Err(RuntimeError::new(
25915                "tool_define requires at least 4 arguments: name, description, params, returns",
25916            ));
25917        }
25918
25919        let name = match &args[0] {
25920            Value::String(s) => s.as_str().to_string(),
25921            _ => return Err(RuntimeError::new("tool name must be a string")),
25922        };
25923
25924        let description = match &args[1] {
25925            Value::String(s) => s.as_str().to_string(),
25926            _ => return Err(RuntimeError::new("tool description must be a string")),
25927        };
25928
25929        // Parse parameters array
25930        let params = match &args[2] {
25931            Value::Array(arr) => {
25932                let arr = arr.borrow();
25933                let mut params = Vec::new();
25934                for param in arr.iter() {
25935                    if let Value::Map(map) = param {
25936                        let map = map.borrow();
25937                        let param_name = map
25938                            .get("name")
25939                            .and_then(|v| {
25940                                if let Value::String(s) = v {
25941                                    Some(s.as_str().to_string())
25942                                } else {
25943                                    None
25944                                }
25945                            })
25946                            .unwrap_or_default();
25947                        let param_type = map
25948                            .get("type")
25949                            .and_then(|v| {
25950                                if let Value::String(s) = v {
25951                                    Some(s.as_str().to_string())
25952                                } else {
25953                                    None
25954                                }
25955                            })
25956                            .unwrap_or_else(|| "any".to_string());
25957                        let param_desc = map
25958                            .get("description")
25959                            .and_then(|v| {
25960                                if let Value::String(s) = v {
25961                                    Some(s.as_str().to_string())
25962                                } else {
25963                                    None
25964                                }
25965                            })
25966                            .unwrap_or_default();
25967                        let required = map
25968                            .get("required")
25969                            .and_then(|v| {
25970                                if let Value::Bool(b) = v {
25971                                    Some(*b)
25972                                } else {
25973                                    None
25974                                }
25975                            })
25976                            .unwrap_or(true);
25977                        let evidence_str = map
25978                            .get("evidence")
25979                            .and_then(|v| {
25980                                if let Value::String(s) = v {
25981                                    Some(s.as_str())
25982                                } else {
25983                                    None
25984                                }
25985                            })
25986                            .unwrap_or("~");
25987                        let evidence = match evidence_str {
25988                            "!" => Evidence::Known,
25989                            "?" => Evidence::Uncertain,
25990                            "~" => Evidence::Reported,
25991                            "‽" => Evidence::Paradox,
25992                            _ => Evidence::Reported,
25993                        };
25994                        params.push(ToolParameter {
25995                            name: param_name,
25996                            param_type,
25997                            description: param_desc,
25998                            required,
25999                            evidence,
26000                        });
26001                    }
26002                }
26003                params
26004            }
26005            _ => Vec::new(),
26006        };
26007
26008        let returns = match &args[3] {
26009            Value::String(s) => s.as_str().to_string(),
26010            _ => "any".to_string(),
26011        };
26012
26013        let handler = if args.len() > 4 {
26014            match &args[4] {
26015                Value::Function(f) => Some(f.clone()),
26016                _ => None,
26017            }
26018        } else {
26019            None
26020        };
26021
26022        let tool = ToolDefinition {
26023            name: name.clone(),
26024            description,
26025            parameters: params,
26026            returns,
26027            evidence_in: Evidence::Reported,
26028            evidence_out: Evidence::Reported,
26029            handler,
26030        };
26031
26032        TOOL_REGISTRY.with(|registry| {
26033            registry.borrow_mut().insert(name.clone(), tool);
26034        });
26035
26036        Ok(Value::String(Rc::new(name)))
26037    });
26038
26039    // tool_list - List all registered tools
26040    define(interp, "tool_list", Some(0), |_, _args| {
26041        let tools: Vec<Value> = TOOL_REGISTRY.with(|registry| {
26042            registry
26043                .borrow()
26044                .keys()
26045                .map(|k| Value::String(Rc::new(k.clone())))
26046                .collect()
26047        });
26048        Ok(Value::Array(Rc::new(RefCell::new(tools))))
26049    });
26050
26051    // tool_get - Get tool definition by name
26052    define(interp, "tool_get", Some(1), |_, args| {
26053        let name = match &args[0] {
26054            Value::String(s) => s.as_str().to_string(),
26055            _ => return Err(RuntimeError::new("tool_get requires string name")),
26056        };
26057
26058        TOOL_REGISTRY.with(|registry| {
26059            if let Some(tool) = registry.borrow().get(&name) {
26060                let mut map = HashMap::new();
26061                map.insert(
26062                    "name".to_string(),
26063                    Value::String(Rc::new(tool.name.clone())),
26064                );
26065                map.insert(
26066                    "description".to_string(),
26067                    Value::String(Rc::new(tool.description.clone())),
26068                );
26069                map.insert(
26070                    "returns".to_string(),
26071                    Value::String(Rc::new(tool.returns.clone())),
26072                );
26073
26074                let params: Vec<Value> = tool
26075                    .parameters
26076                    .iter()
26077                    .map(|p| {
26078                        let mut pmap = HashMap::new();
26079                        pmap.insert("name".to_string(), Value::String(Rc::new(p.name.clone())));
26080                        pmap.insert(
26081                            "type".to_string(),
26082                            Value::String(Rc::new(p.param_type.clone())),
26083                        );
26084                        pmap.insert(
26085                            "description".to_string(),
26086                            Value::String(Rc::new(p.description.clone())),
26087                        );
26088                        pmap.insert("required".to_string(), Value::Bool(p.required));
26089                        Value::Map(Rc::new(RefCell::new(pmap)))
26090                    })
26091                    .collect();
26092                map.insert(
26093                    "parameters".to_string(),
26094                    Value::Array(Rc::new(RefCell::new(params))),
26095                );
26096
26097                Ok(Value::Map(Rc::new(RefCell::new(map))))
26098            } else {
26099                Ok(Value::Null)
26100            }
26101        })
26102    });
26103
26104    // tool_schema - Generate OpenAI/Claude compatible tool schema
26105    define(interp, "tool_schema", Some(1), |_, args| {
26106        let name = match &args[0] {
26107            Value::String(s) => s.as_str().to_string(),
26108            _ => return Err(RuntimeError::new("tool_schema requires string name")),
26109        };
26110
26111        TOOL_REGISTRY.with(|registry| {
26112            if let Some(tool) = registry.borrow().get(&name) {
26113                // Generate OpenAI function calling schema
26114                let mut schema = HashMap::new();
26115                schema.insert(
26116                    "type".to_string(),
26117                    Value::String(Rc::new("function".to_string())),
26118                );
26119
26120                let mut function = HashMap::new();
26121                function.insert(
26122                    "name".to_string(),
26123                    Value::String(Rc::new(tool.name.clone())),
26124                );
26125                function.insert(
26126                    "description".to_string(),
26127                    Value::String(Rc::new(tool.description.clone())),
26128                );
26129
26130                // Build parameters schema (JSON Schema format)
26131                let mut params_schema = HashMap::new();
26132                params_schema.insert(
26133                    "type".to_string(),
26134                    Value::String(Rc::new("object".to_string())),
26135                );
26136
26137                let mut properties = HashMap::new();
26138                let mut required: Vec<Value> = Vec::new();
26139
26140                for param in &tool.parameters {
26141                    let mut prop = HashMap::new();
26142                    let json_type = match param.param_type.as_str() {
26143                        "int" | "i64" | "i32" => "integer",
26144                        "float" | "f64" | "f32" => "number",
26145                        "bool" => "boolean",
26146                        "string" | "str" => "string",
26147                        "array" | "list" => "array",
26148                        "map" | "object" => "object",
26149                        _ => "string",
26150                    };
26151                    prop.insert(
26152                        "type".to_string(),
26153                        Value::String(Rc::new(json_type.to_string())),
26154                    );
26155                    prop.insert(
26156                        "description".to_string(),
26157                        Value::String(Rc::new(param.description.clone())),
26158                    );
26159                    properties.insert(param.name.clone(), Value::Map(Rc::new(RefCell::new(prop))));
26160
26161                    if param.required {
26162                        required.push(Value::String(Rc::new(param.name.clone())));
26163                    }
26164                }
26165
26166                params_schema.insert(
26167                    "properties".to_string(),
26168                    Value::Map(Rc::new(RefCell::new(properties))),
26169                );
26170                params_schema.insert(
26171                    "required".to_string(),
26172                    Value::Array(Rc::new(RefCell::new(required))),
26173                );
26174
26175                function.insert(
26176                    "parameters".to_string(),
26177                    Value::Map(Rc::new(RefCell::new(params_schema))),
26178                );
26179                schema.insert(
26180                    "function".to_string(),
26181                    Value::Map(Rc::new(RefCell::new(function))),
26182                );
26183
26184                Ok(Value::Map(Rc::new(RefCell::new(schema))))
26185            } else {
26186                Err(RuntimeError::new(format!("Tool '{}' not found", name)))
26187            }
26188        })
26189    });
26190
26191    // tool_schemas_all - Get all tool schemas for LLM
26192    define(interp, "tool_schemas_all", Some(0), |_, _args| {
26193        let schemas: Vec<Value> = TOOL_REGISTRY.with(|registry| {
26194            registry
26195                .borrow()
26196                .values()
26197                .map(|tool| {
26198                    let mut schema = HashMap::new();
26199                    schema.insert(
26200                        "type".to_string(),
26201                        Value::String(Rc::new("function".to_string())),
26202                    );
26203
26204                    let mut function = HashMap::new();
26205                    function.insert(
26206                        "name".to_string(),
26207                        Value::String(Rc::new(tool.name.clone())),
26208                    );
26209                    function.insert(
26210                        "description".to_string(),
26211                        Value::String(Rc::new(tool.description.clone())),
26212                    );
26213
26214                    let mut params_schema = HashMap::new();
26215                    params_schema.insert(
26216                        "type".to_string(),
26217                        Value::String(Rc::new("object".to_string())),
26218                    );
26219
26220                    let mut properties = HashMap::new();
26221                    let mut required: Vec<Value> = Vec::new();
26222
26223                    for param in &tool.parameters {
26224                        let mut prop = HashMap::new();
26225                        let json_type = match param.param_type.as_str() {
26226                            "int" | "i64" | "i32" => "integer",
26227                            "float" | "f64" | "f32" => "number",
26228                            "bool" => "boolean",
26229                            _ => "string",
26230                        };
26231                        prop.insert(
26232                            "type".to_string(),
26233                            Value::String(Rc::new(json_type.to_string())),
26234                        );
26235                        prop.insert(
26236                            "description".to_string(),
26237                            Value::String(Rc::new(param.description.clone())),
26238                        );
26239                        properties
26240                            .insert(param.name.clone(), Value::Map(Rc::new(RefCell::new(prop))));
26241                        if param.required {
26242                            required.push(Value::String(Rc::new(param.name.clone())));
26243                        }
26244                    }
26245
26246                    params_schema.insert(
26247                        "properties".to_string(),
26248                        Value::Map(Rc::new(RefCell::new(properties))),
26249                    );
26250                    params_schema.insert(
26251                        "required".to_string(),
26252                        Value::Array(Rc::new(RefCell::new(required))),
26253                    );
26254                    function.insert(
26255                        "parameters".to_string(),
26256                        Value::Map(Rc::new(RefCell::new(params_schema))),
26257                    );
26258                    schema.insert(
26259                        "function".to_string(),
26260                        Value::Map(Rc::new(RefCell::new(function))),
26261                    );
26262
26263                    Value::Map(Rc::new(RefCell::new(schema)))
26264                })
26265                .collect()
26266        });
26267        Ok(Value::Array(Rc::new(RefCell::new(schemas))))
26268    });
26269
26270    // tool_call - Execute a registered tool by name
26271    define(interp, "tool_call", None, |interp, args| {
26272        if args.is_empty() {
26273            return Err(RuntimeError::new("tool_call requires at least tool name"));
26274        }
26275
26276        let name = match &args[0] {
26277            Value::String(s) => s.as_str().to_string(),
26278            _ => {
26279                return Err(RuntimeError::new(
26280                    "tool_call first argument must be tool name",
26281                ))
26282            }
26283        };
26284
26285        let tool_args: Vec<Value> = args.into_iter().skip(1).collect();
26286
26287        TOOL_REGISTRY.with(|registry| {
26288            if let Some(tool) = registry.borrow().get(&name) {
26289                if let Some(handler) = &tool.handler {
26290                    // Execute the handler function
26291                    let result = interp.call_function(handler.as_ref(), tool_args)?;
26292                    // Wrap result with reported evidence (external call)
26293                    Ok(Value::Evidential {
26294                        value: Box::new(result),
26295                        evidence: Evidence::Reported,
26296                    })
26297                } else {
26298                    Err(RuntimeError::new(format!("Tool '{}' has no handler", name)))
26299                }
26300            } else {
26301                Err(RuntimeError::new(format!("Tool '{}' not found", name)))
26302            }
26303        })
26304    });
26305
26306    // tool_remove - Remove a tool from registry
26307    define(interp, "tool_remove", Some(1), |_, args| {
26308        let name = match &args[0] {
26309            Value::String(s) => s.as_str().to_string(),
26310            _ => return Err(RuntimeError::new("tool_remove requires string name")),
26311        };
26312
26313        TOOL_REGISTRY.with(|registry| {
26314            let removed = registry.borrow_mut().remove(&name).is_some();
26315            Ok(Value::Bool(removed))
26316        })
26317    });
26318
26319    // tool_clear - Clear all registered tools
26320    define(interp, "tool_clear", Some(0), |_, _args| {
26321        TOOL_REGISTRY.with(|registry| {
26322            registry.borrow_mut().clear();
26323        });
26324        Ok(Value::Null)
26325    });
26326}
26327
26328// ============================================================================
26329// LLM CLIENT - AI model interaction with evidentiality
26330// ============================================================================
26331
26332fn register_agent_llm(interp: &mut Interpreter) {
26333    // llm_message - Create a chat message
26334    define(interp, "llm_message", Some(2), |_, args| {
26335        let role = match &args[0] {
26336            Value::String(s) => s.as_str().to_string(),
26337            _ => return Err(RuntimeError::new("llm_message role must be string")),
26338        };
26339        let content = match &args[1] {
26340            Value::String(s) => s.as_str().to_string(),
26341            _ => return Err(RuntimeError::new("llm_message content must be string")),
26342        };
26343
26344        let mut map = HashMap::new();
26345        map.insert("role".to_string(), Value::String(Rc::new(role)));
26346        map.insert("content".to_string(), Value::String(Rc::new(content)));
26347        Ok(Value::Map(Rc::new(RefCell::new(map))))
26348    });
26349
26350    // llm_messages - Create a messages array
26351    define(interp, "llm_messages", None, |_, args| {
26352        let messages: Vec<Value> = args.into_iter().collect();
26353        Ok(Value::Array(Rc::new(RefCell::new(messages))))
26354    });
26355
26356    // llm_request - Build an LLM API request (returns reported~ since it's external)
26357    define(interp, "llm_request", None, |_, args| {
26358        if args.is_empty() {
26359            return Err(RuntimeError::new("llm_request requires provider"));
26360        }
26361
26362        let provider = match &args[0] {
26363            Value::String(s) => s.as_str().to_string(),
26364            _ => return Err(RuntimeError::new("provider must be string")),
26365        };
26366
26367        let mut request = HashMap::new();
26368        request.insert(
26369            "provider".to_string(),
26370            Value::String(Rc::new(provider.clone())),
26371        );
26372
26373        // Default models per provider
26374        let default_model = match provider.as_str() {
26375            "openai" => "gpt-4-turbo-preview",
26376            "anthropic" | "claude" => "claude-3-opus-20240229",
26377            "google" | "gemini" => "gemini-pro",
26378            "mistral" => "mistral-large-latest",
26379            "ollama" | "local" => "llama2",
26380            _ => "gpt-4",
26381        };
26382        request.insert(
26383            "model".to_string(),
26384            Value::String(Rc::new(default_model.to_string())),
26385        );
26386
26387        // Parse optional arguments
26388        for (i, arg) in args.iter().enumerate().skip(1) {
26389            if let Value::Map(map) = arg {
26390                let map = map.borrow();
26391                for (k, v) in map.iter() {
26392                    request.insert(k.clone(), v.clone());
26393                }
26394            } else if i == 1 {
26395                // Second arg is model
26396                if let Value::String(s) = arg {
26397                    request.insert("model".to_string(), Value::String(s.clone()));
26398                }
26399            }
26400        }
26401
26402        // Default values
26403        if !request.contains_key("temperature") {
26404            request.insert("temperature".to_string(), Value::Float(0.7));
26405        }
26406        if !request.contains_key("max_tokens") {
26407            request.insert("max_tokens".to_string(), Value::Int(4096));
26408        }
26409
26410        Ok(Value::Map(Rc::new(RefCell::new(request))))
26411    });
26412
26413    // llm_with_tools - Add tools to a request
26414    define(interp, "llm_with_tools", Some(2), |_, args| {
26415        let request = match &args[0] {
26416            Value::Map(m) => m.clone(),
26417            _ => {
26418                return Err(RuntimeError::new(
26419                    "llm_with_tools first arg must be request map",
26420                ))
26421            }
26422        };
26423
26424        let tools = match &args[1] {
26425            Value::Array(arr) => arr.clone(),
26426            _ => {
26427                return Err(RuntimeError::new(
26428                    "llm_with_tools second arg must be tools array",
26429                ))
26430            }
26431        };
26432
26433        request
26434            .borrow_mut()
26435            .insert("tools".to_string(), Value::Array(tools));
26436        request.borrow_mut().insert(
26437            "tool_choice".to_string(),
26438            Value::String(Rc::new("auto".to_string())),
26439        );
26440
26441        Ok(Value::Map(request))
26442    });
26443
26444    // llm_with_system - Add system prompt to request
26445    define(interp, "llm_with_system", Some(2), |_, args| {
26446        let request = match &args[0] {
26447            Value::Map(m) => m.clone(),
26448            _ => {
26449                return Err(RuntimeError::new(
26450                    "llm_with_system first arg must be request map",
26451                ))
26452            }
26453        };
26454
26455        let system = match &args[1] {
26456            Value::String(s) => s.clone(),
26457            _ => {
26458                return Err(RuntimeError::new(
26459                    "llm_with_system second arg must be string",
26460                ))
26461            }
26462        };
26463
26464        request
26465            .borrow_mut()
26466            .insert("system".to_string(), Value::String(system));
26467        Ok(Value::Map(request))
26468    });
26469
26470    // llm_with_messages - Add messages to request
26471    define(interp, "llm_with_messages", Some(2), |_, args| {
26472        let request = match &args[0] {
26473            Value::Map(m) => m.clone(),
26474            _ => {
26475                return Err(RuntimeError::new(
26476                    "llm_with_messages first arg must be request map",
26477                ))
26478            }
26479        };
26480
26481        let messages = match &args[1] {
26482            Value::Array(arr) => arr.clone(),
26483            _ => {
26484                return Err(RuntimeError::new(
26485                    "llm_with_messages second arg must be messages array",
26486                ))
26487            }
26488        };
26489
26490        request
26491            .borrow_mut()
26492            .insert("messages".to_string(), Value::Array(messages));
26493        Ok(Value::Map(request))
26494    });
26495
26496    // llm_send - Send request (simulated - returns reported~ data)
26497    // In production, this would make actual HTTP calls
26498    define(interp, "llm_send", Some(1), |_, args| {
26499        let request = match &args[0] {
26500            Value::Map(m) => m.borrow().clone(),
26501            _ => return Err(RuntimeError::new("llm_send requires request map")),
26502        };
26503
26504        let provider = request
26505            .get("provider")
26506            .and_then(|v| {
26507                if let Value::String(s) = v {
26508                    Some(s.as_str().to_string())
26509                } else {
26510                    None
26511                }
26512            })
26513            .unwrap_or_else(|| "unknown".to_string());
26514
26515        let model = request
26516            .get("model")
26517            .and_then(|v| {
26518                if let Value::String(s) = v {
26519                    Some(s.as_str().to_string())
26520                } else {
26521                    None
26522                }
26523            })
26524            .unwrap_or_else(|| "unknown".to_string());
26525
26526        // Build response structure (simulated)
26527        let mut response = HashMap::new();
26528        response.insert(
26529            "id".to_string(),
26530            Value::String(Rc::new(format!("msg_{}", Uuid::new_v4()))),
26531        );
26532        response.insert("provider".to_string(), Value::String(Rc::new(provider)));
26533        response.insert("model".to_string(), Value::String(Rc::new(model)));
26534        response.insert(
26535            "created".to_string(),
26536            Value::Int(
26537                std::time::SystemTime::now()
26538                    .duration_since(std::time::UNIX_EPOCH)
26539                    .unwrap_or_default()
26540                    .as_secs() as i64,
26541            ),
26542        );
26543
26544        // Check if this would be a tool call
26545        if request.contains_key("tools") {
26546            response.insert(
26547                "type".to_string(),
26548                Value::String(Rc::new("tool_use".to_string())),
26549            );
26550            response.insert(
26551                "tool_name".to_string(),
26552                Value::String(Rc::new("pending".to_string())),
26553            );
26554            response.insert(
26555                "tool_input".to_string(),
26556                Value::Map(Rc::new(RefCell::new(HashMap::new()))),
26557            );
26558        } else {
26559            response.insert(
26560                "type".to_string(),
26561                Value::String(Rc::new("text".to_string())),
26562            );
26563            response.insert(
26564                "content".to_string(),
26565                Value::String(Rc::new(
26566                    "[LLM Response - Connect to actual API for real responses]".to_string(),
26567                )),
26568            );
26569        }
26570
26571        // Usage stats (simulated)
26572        let mut usage = HashMap::new();
26573        usage.insert("input_tokens".to_string(), Value::Int(0));
26574        usage.insert("output_tokens".to_string(), Value::Int(0));
26575        response.insert(
26576            "usage".to_string(),
26577            Value::Map(Rc::new(RefCell::new(usage))),
26578        );
26579
26580        // Return as reported evidence (external data)
26581        Ok(Value::Evidential {
26582            value: Box::new(Value::Map(Rc::new(RefCell::new(response)))),
26583            evidence: Evidence::Reported,
26584        })
26585    });
26586
26587    // llm_parse_tool_call - Parse tool call from LLM response
26588    define(interp, "llm_parse_tool_call", Some(1), |_, args| {
26589        let response = match &args[0] {
26590            Value::Map(m) => m.borrow().clone(),
26591            Value::Evidential { value, .. } => {
26592                if let Value::Map(m) = value.as_ref() {
26593                    m.borrow().clone()
26594                } else {
26595                    return Err(RuntimeError::new(
26596                        "llm_parse_tool_call requires map response",
26597                    ));
26598                }
26599            }
26600            _ => {
26601                return Err(RuntimeError::new(
26602                    "llm_parse_tool_call requires response map",
26603                ))
26604            }
26605        };
26606
26607        let resp_type = response
26608            .get("type")
26609            .and_then(|v| {
26610                if let Value::String(s) = v {
26611                    Some(s.as_str().to_string())
26612                } else {
26613                    None
26614                }
26615            })
26616            .unwrap_or_default();
26617
26618        if resp_type == "tool_use" {
26619            let tool_name = response
26620                .get("tool_name")
26621                .and_then(|v| {
26622                    if let Value::String(s) = v {
26623                        Some(s.as_str().to_string())
26624                    } else {
26625                        None
26626                    }
26627                })
26628                .unwrap_or_default();
26629
26630            let tool_input = response.get("tool_input").cloned().unwrap_or(Value::Null);
26631
26632            let mut result = HashMap::new();
26633            result.insert("is_tool_call".to_string(), Value::Bool(true));
26634            result.insert("tool_name".to_string(), Value::String(Rc::new(tool_name)));
26635            result.insert("tool_input".to_string(), tool_input);
26636            Ok(Value::Map(Rc::new(RefCell::new(result))))
26637        } else {
26638            let mut result = HashMap::new();
26639            result.insert("is_tool_call".to_string(), Value::Bool(false));
26640            result.insert(
26641                "content".to_string(),
26642                response.get("content").cloned().unwrap_or(Value::Null),
26643            );
26644            Ok(Value::Map(Rc::new(RefCell::new(result))))
26645        }
26646    });
26647
26648    // llm_extract - Extract structured data (returns uncertain? - needs validation)
26649    define(interp, "llm_extract", Some(2), |_, args| {
26650        let _response = match &args[0] {
26651            Value::Map(m) => m.borrow().clone(),
26652            Value::Evidential { value, .. } => {
26653                if let Value::Map(m) = value.as_ref() {
26654                    m.borrow().clone()
26655                } else {
26656                    return Err(RuntimeError::new("llm_extract requires response"));
26657                }
26658            }
26659            _ => return Err(RuntimeError::new("llm_extract requires response")),
26660        };
26661
26662        let _schema = match &args[1] {
26663            Value::Map(m) => m.borrow().clone(),
26664            _ => return Err(RuntimeError::new("llm_extract requires schema map")),
26665        };
26666
26667        // In production, this would parse the LLM output against the schema
26668        // For now, return uncertain evidence since extraction may fail
26669        let mut result = HashMap::new();
26670        result.insert("success".to_string(), Value::Bool(true));
26671        result.insert("data".to_string(), Value::Null);
26672        result.insert(
26673            "errors".to_string(),
26674            Value::Array(Rc::new(RefCell::new(Vec::new()))),
26675        );
26676
26677        Ok(Value::Evidential {
26678            value: Box::new(Value::Map(Rc::new(RefCell::new(result)))),
26679            evidence: Evidence::Uncertain,
26680        })
26681    });
26682
26683    // prompt_template - Create a prompt template with variable substitution
26684    define(interp, "prompt_template", Some(1), |_, args| {
26685        let template = match &args[0] {
26686            Value::String(s) => s.as_str().to_string(),
26687            _ => return Err(RuntimeError::new("prompt_template requires string")),
26688        };
26689
26690        // Parse template to extract variable names
26691        let mut variables = Vec::new();
26692        let mut in_var = false;
26693        let mut var_name = String::new();
26694
26695        for c in template.chars() {
26696            match c {
26697                '{' if !in_var => {
26698                    in_var = true;
26699                    var_name.clear();
26700                }
26701                '}' if in_var => {
26702                    if !var_name.is_empty() {
26703                        variables.push(Value::String(Rc::new(var_name.clone())));
26704                    }
26705                    in_var = false;
26706                }
26707                _ if in_var => {
26708                    var_name.push(c);
26709                }
26710                _ => {}
26711            }
26712        }
26713
26714        let mut result = HashMap::new();
26715        result.insert("template".to_string(), Value::String(Rc::new(template)));
26716        result.insert(
26717            "variables".to_string(),
26718            Value::Array(Rc::new(RefCell::new(variables))),
26719        );
26720        Ok(Value::Map(Rc::new(RefCell::new(result))))
26721    });
26722
26723    // prompt_render - Render a template with values
26724    define(interp, "prompt_render", Some(2), |_, args| {
26725        let template_obj = match &args[0] {
26726            Value::Map(m) => m.borrow().clone(),
26727            Value::String(s) => {
26728                let mut m = HashMap::new();
26729                m.insert("template".to_string(), Value::String(s.clone()));
26730                m
26731            }
26732            _ => return Err(RuntimeError::new("prompt_render requires template")),
26733        };
26734
26735        let values = match &args[1] {
26736            Value::Map(m) => m.borrow().clone(),
26737            _ => return Err(RuntimeError::new("prompt_render requires values map")),
26738        };
26739
26740        let template = template_obj
26741            .get("template")
26742            .and_then(|v| {
26743                if let Value::String(s) = v {
26744                    Some(s.as_str().to_string())
26745                } else {
26746                    None
26747                }
26748            })
26749            .unwrap_or_default();
26750
26751        let mut result = template;
26752        for (key, value) in values.iter() {
26753            let value_str = match value {
26754                Value::String(s) => s.as_str().to_string(),
26755                Value::Int(n) => n.to_string(),
26756                Value::Float(f) => f.to_string(),
26757                Value::Bool(b) => b.to_string(),
26758                _ => format!("{}", value),
26759            };
26760            result = result.replace(&format!("{{{}}}", key), &value_str);
26761        }
26762
26763        Ok(Value::String(Rc::new(result)))
26764    });
26765}
26766
26767// ============================================================================
26768// AGENT MEMORY - Session and context persistence
26769// ============================================================================
26770
26771fn register_agent_memory(interp: &mut Interpreter) {
26772    // memory_session - Create or get a session
26773    define(interp, "memory_session", Some(1), |_, args| {
26774        let session_id = match &args[0] {
26775            Value::String(s) => s.as_str().to_string(),
26776            _ => return Err(RuntimeError::new("memory_session requires string id")),
26777        };
26778
26779        let now = std::time::SystemTime::now()
26780            .duration_since(std::time::UNIX_EPOCH)
26781            .unwrap_or_default()
26782            .as_secs();
26783
26784        AGENT_MEMORY.with(|memory| {
26785            let mut mem = memory.borrow_mut();
26786            if !mem.contains_key(&session_id) {
26787                mem.insert(
26788                    session_id.clone(),
26789                    AgentSession {
26790                        id: session_id.clone(),
26791                        context: HashMap::new(),
26792                        history: Vec::new(),
26793                        created_at: now,
26794                        last_accessed: now,
26795                    },
26796                );
26797            } else if let Some(session) = mem.get_mut(&session_id) {
26798                session.last_accessed = now;
26799            }
26800        });
26801
26802        let mut result = HashMap::new();
26803        result.insert("id".to_string(), Value::String(Rc::new(session_id)));
26804        result.insert("created_at".to_string(), Value::Int(now as i64));
26805        Ok(Value::Map(Rc::new(RefCell::new(result))))
26806    });
26807
26808    // memory_set - Store a value in session context
26809    define(interp, "memory_set", Some(3), |_, args| {
26810        let session_id = match &args[0] {
26811            Value::String(s) => s.as_str().to_string(),
26812            Value::Map(m) => m
26813                .borrow()
26814                .get("id")
26815                .and_then(|v| {
26816                    if let Value::String(s) = v {
26817                        Some(s.as_str().to_string())
26818                    } else {
26819                        None
26820                    }
26821                })
26822                .ok_or_else(|| RuntimeError::new("Invalid session"))?,
26823            _ => return Err(RuntimeError::new("memory_set requires session")),
26824        };
26825
26826        let key = match &args[1] {
26827            Value::String(s) => s.as_str().to_string(),
26828            _ => return Err(RuntimeError::new("memory_set key must be string")),
26829        };
26830
26831        let value = args[2].clone();
26832
26833        AGENT_MEMORY.with(|memory| {
26834            if let Some(session) = memory.borrow_mut().get_mut(&session_id) {
26835                session.context.insert(key, value);
26836                session.last_accessed = std::time::SystemTime::now()
26837                    .duration_since(std::time::UNIX_EPOCH)
26838                    .unwrap_or_default()
26839                    .as_secs();
26840                Ok(Value::Bool(true))
26841            } else {
26842                Err(RuntimeError::new(format!(
26843                    "Session '{}' not found",
26844                    session_id
26845                )))
26846            }
26847        })
26848    });
26849
26850    // memory_get - Retrieve a value from session context
26851    define(interp, "memory_get", Some(2), |_, args| {
26852        let session_id = match &args[0] {
26853            Value::String(s) => s.as_str().to_string(),
26854            Value::Map(m) => m
26855                .borrow()
26856                .get("id")
26857                .and_then(|v| {
26858                    if let Value::String(s) = v {
26859                        Some(s.as_str().to_string())
26860                    } else {
26861                        None
26862                    }
26863                })
26864                .ok_or_else(|| RuntimeError::new("Invalid session"))?,
26865            _ => return Err(RuntimeError::new("memory_get requires session")),
26866        };
26867
26868        let key = match &args[1] {
26869            Value::String(s) => s.as_str().to_string(),
26870            _ => return Err(RuntimeError::new("memory_get key must be string")),
26871        };
26872
26873        AGENT_MEMORY.with(|memory| {
26874            if let Some(session) = memory.borrow().get(&session_id) {
26875                Ok(session.context.get(&key).cloned().unwrap_or(Value::Null))
26876            } else {
26877                Ok(Value::Null)
26878            }
26879        })
26880    });
26881
26882    // memory_history_add - Add to conversation history
26883    define(interp, "memory_history_add", Some(3), |_, args| {
26884        let session_id = match &args[0] {
26885            Value::String(s) => s.as_str().to_string(),
26886            Value::Map(m) => m
26887                .borrow()
26888                .get("id")
26889                .and_then(|v| {
26890                    if let Value::String(s) = v {
26891                        Some(s.as_str().to_string())
26892                    } else {
26893                        None
26894                    }
26895                })
26896                .ok_or_else(|| RuntimeError::new("Invalid session"))?,
26897            _ => return Err(RuntimeError::new("memory_history_add requires session")),
26898        };
26899
26900        let role = match &args[1] {
26901            Value::String(s) => s.as_str().to_string(),
26902            _ => return Err(RuntimeError::new("role must be string")),
26903        };
26904
26905        let content = match &args[2] {
26906            Value::String(s) => s.as_str().to_string(),
26907            _ => return Err(RuntimeError::new("content must be string")),
26908        };
26909
26910        AGENT_MEMORY.with(|memory| {
26911            if let Some(session) = memory.borrow_mut().get_mut(&session_id) {
26912                session.history.push((role, content));
26913                session.last_accessed = std::time::SystemTime::now()
26914                    .duration_since(std::time::UNIX_EPOCH)
26915                    .unwrap_or_default()
26916                    .as_secs();
26917                Ok(Value::Int(session.history.len() as i64))
26918            } else {
26919                Err(RuntimeError::new(format!(
26920                    "Session '{}' not found",
26921                    session_id
26922                )))
26923            }
26924        })
26925    });
26926
26927    // memory_history_get - Get conversation history
26928    define(interp, "memory_history_get", None, |_, args| {
26929        if args.is_empty() {
26930            return Err(RuntimeError::new("memory_history_get requires session"));
26931        }
26932
26933        let session_id = match &args[0] {
26934            Value::String(s) => s.as_str().to_string(),
26935            Value::Map(m) => m
26936                .borrow()
26937                .get("id")
26938                .and_then(|v| {
26939                    if let Value::String(s) = v {
26940                        Some(s.as_str().to_string())
26941                    } else {
26942                        None
26943                    }
26944                })
26945                .ok_or_else(|| RuntimeError::new("Invalid session"))?,
26946            _ => return Err(RuntimeError::new("memory_history_get requires session")),
26947        };
26948
26949        let limit = if args.len() > 1 {
26950            match &args[1] {
26951                Value::Int(n) => Some(*n as usize),
26952                _ => None,
26953            }
26954        } else {
26955            None
26956        };
26957
26958        AGENT_MEMORY.with(|memory| {
26959            if let Some(session) = memory.borrow().get(&session_id) {
26960                let history: Vec<Value> = session
26961                    .history
26962                    .iter()
26963                    .rev()
26964                    .take(limit.unwrap_or(usize::MAX))
26965                    .rev()
26966                    .map(|(role, content)| {
26967                        let mut msg = HashMap::new();
26968                        msg.insert("role".to_string(), Value::String(Rc::new(role.clone())));
26969                        msg.insert(
26970                            "content".to_string(),
26971                            Value::String(Rc::new(content.clone())),
26972                        );
26973                        Value::Map(Rc::new(RefCell::new(msg)))
26974                    })
26975                    .collect();
26976                Ok(Value::Array(Rc::new(RefCell::new(history))))
26977            } else {
26978                Ok(Value::Array(Rc::new(RefCell::new(Vec::new()))))
26979            }
26980        })
26981    });
26982
26983    // memory_context_all - Get all context for a session
26984    define(interp, "memory_context_all", Some(1), |_, args| {
26985        let session_id = match &args[0] {
26986            Value::String(s) => s.as_str().to_string(),
26987            Value::Map(m) => m
26988                .borrow()
26989                .get("id")
26990                .and_then(|v| {
26991                    if let Value::String(s) = v {
26992                        Some(s.as_str().to_string())
26993                    } else {
26994                        None
26995                    }
26996                })
26997                .ok_or_else(|| RuntimeError::new("Invalid session"))?,
26998            _ => return Err(RuntimeError::new("memory_context_all requires session")),
26999        };
27000
27001        AGENT_MEMORY.with(|memory| {
27002            if let Some(session) = memory.borrow().get(&session_id) {
27003                let context: HashMap<String, Value> = session.context.clone();
27004                Ok(Value::Map(Rc::new(RefCell::new(context))))
27005            } else {
27006                Ok(Value::Map(Rc::new(RefCell::new(HashMap::new()))))
27007            }
27008        })
27009    });
27010
27011    // memory_clear - Clear session data
27012    define(interp, "memory_clear", Some(1), |_, args| {
27013        let session_id = match &args[0] {
27014            Value::String(s) => s.as_str().to_string(),
27015            Value::Map(m) => m
27016                .borrow()
27017                .get("id")
27018                .and_then(|v| {
27019                    if let Value::String(s) = v {
27020                        Some(s.as_str().to_string())
27021                    } else {
27022                        None
27023                    }
27024                })
27025                .ok_or_else(|| RuntimeError::new("Invalid session"))?,
27026            _ => return Err(RuntimeError::new("memory_clear requires session")),
27027        };
27028
27029        AGENT_MEMORY.with(|memory| {
27030            let removed = memory.borrow_mut().remove(&session_id).is_some();
27031            Ok(Value::Bool(removed))
27032        })
27033    });
27034
27035    // memory_sessions_list - List all active sessions
27036    define(interp, "memory_sessions_list", Some(0), |_, _args| {
27037        let sessions: Vec<Value> = AGENT_MEMORY.with(|memory| {
27038            memory
27039                .borrow()
27040                .values()
27041                .map(|session| {
27042                    let mut info = HashMap::new();
27043                    info.insert("id".to_string(), Value::String(Rc::new(session.id.clone())));
27044                    info.insert(
27045                        "created_at".to_string(),
27046                        Value::Int(session.created_at as i64),
27047                    );
27048                    info.insert(
27049                        "last_accessed".to_string(),
27050                        Value::Int(session.last_accessed as i64),
27051                    );
27052                    info.insert(
27053                        "context_keys".to_string(),
27054                        Value::Int(session.context.len() as i64),
27055                    );
27056                    info.insert(
27057                        "history_length".to_string(),
27058                        Value::Int(session.history.len() as i64),
27059                    );
27060                    Value::Map(Rc::new(RefCell::new(info)))
27061                })
27062                .collect()
27063        });
27064        Ok(Value::Array(Rc::new(RefCell::new(sessions))))
27065    });
27066}
27067
27068// ============================================================================
27069// PLANNING FRAMEWORK - State machines and goal tracking
27070// ============================================================================
27071
27072fn register_agent_planning(interp: &mut Interpreter) {
27073    // plan_state_machine - Create a new state machine
27074    define(interp, "plan_state_machine", Some(2), |_, args| {
27075        let name = match &args[0] {
27076            Value::String(s) => s.as_str().to_string(),
27077            _ => return Err(RuntimeError::new("plan_state_machine name must be string")),
27078        };
27079
27080        let states = match &args[1] {
27081            Value::Array(arr) => arr
27082                .borrow()
27083                .iter()
27084                .filter_map(|v| {
27085                    if let Value::String(s) = v {
27086                        Some(s.as_str().to_string())
27087                    } else {
27088                        None
27089                    }
27090                })
27091                .collect::<Vec<_>>(),
27092            _ => return Err(RuntimeError::new("plan_state_machine states must be array")),
27093        };
27094
27095        if states.is_empty() {
27096            return Err(RuntimeError::new(
27097                "State machine must have at least one state",
27098            ));
27099        }
27100
27101        let initial_state = states[0].clone();
27102        let now = std::time::SystemTime::now()
27103            .duration_since(std::time::UNIX_EPOCH)
27104            .unwrap_or_default()
27105            .as_secs();
27106
27107        let machine = StateMachine {
27108            name: name.clone(),
27109            current_state: initial_state.clone(),
27110            states,
27111            transitions: HashMap::new(),
27112            history: vec![(initial_state, now)],
27113        };
27114
27115        STATE_MACHINES.with(|machines| {
27116            machines.borrow_mut().insert(name.clone(), machine);
27117        });
27118
27119        let mut result = HashMap::new();
27120        result.insert("name".to_string(), Value::String(Rc::new(name)));
27121        result.insert(
27122            "type".to_string(),
27123            Value::String(Rc::new("state_machine".to_string())),
27124        );
27125        Ok(Value::Map(Rc::new(RefCell::new(result))))
27126    });
27127
27128    // plan_add_transition - Add a transition rule
27129    define(interp, "plan_add_transition", Some(3), |_, args| {
27130        let machine_name = match &args[0] {
27131            Value::String(s) => s.as_str().to_string(),
27132            Value::Map(m) => m
27133                .borrow()
27134                .get("name")
27135                .and_then(|v| {
27136                    if let Value::String(s) = v {
27137                        Some(s.as_str().to_string())
27138                    } else {
27139                        None
27140                    }
27141                })
27142                .ok_or_else(|| RuntimeError::new("Invalid state machine"))?,
27143            _ => return Err(RuntimeError::new("plan_add_transition requires machine")),
27144        };
27145
27146        let from_state = match &args[1] {
27147            Value::String(s) => s.as_str().to_string(),
27148            _ => return Err(RuntimeError::new("from_state must be string")),
27149        };
27150
27151        let to_state = match &args[2] {
27152            Value::String(s) => s.as_str().to_string(),
27153            _ => return Err(RuntimeError::new("to_state must be string")),
27154        };
27155
27156        STATE_MACHINES.with(|machines| {
27157            if let Some(machine) = machines.borrow_mut().get_mut(&machine_name) {
27158                // Validate states exist
27159                if !machine.states.contains(&from_state) {
27160                    return Err(RuntimeError::new(format!(
27161                        "State '{}' not in machine",
27162                        from_state
27163                    )));
27164                }
27165                if !machine.states.contains(&to_state) {
27166                    return Err(RuntimeError::new(format!(
27167                        "State '{}' not in machine",
27168                        to_state
27169                    )));
27170                }
27171
27172                machine
27173                    .transitions
27174                    .entry(from_state)
27175                    .or_insert_with(Vec::new)
27176                    .push((to_state, "".to_string()));
27177
27178                Ok(Value::Bool(true))
27179            } else {
27180                Err(RuntimeError::new(format!(
27181                    "State machine '{}' not found",
27182                    machine_name
27183                )))
27184            }
27185        })
27186    });
27187
27188    // plan_current_state - Get current state
27189    define(interp, "plan_current_state", Some(1), |_, args| {
27190        let machine_name = match &args[0] {
27191            Value::String(s) => s.as_str().to_string(),
27192            Value::Map(m) => m
27193                .borrow()
27194                .get("name")
27195                .and_then(|v| {
27196                    if let Value::String(s) = v {
27197                        Some(s.as_str().to_string())
27198                    } else {
27199                        None
27200                    }
27201                })
27202                .ok_or_else(|| RuntimeError::new("Invalid state machine"))?,
27203            _ => return Err(RuntimeError::new("plan_current_state requires machine")),
27204        };
27205
27206        STATE_MACHINES.with(|machines| {
27207            if let Some(machine) = machines.borrow().get(&machine_name) {
27208                Ok(Value::String(Rc::new(machine.current_state.clone())))
27209            } else {
27210                Err(RuntimeError::new(format!(
27211                    "State machine '{}' not found",
27212                    machine_name
27213                )))
27214            }
27215        })
27216    });
27217
27218    // plan_transition - Execute a state transition
27219    define(interp, "plan_transition", Some(2), |_, args| {
27220        let machine_name = match &args[0] {
27221            Value::String(s) => s.as_str().to_string(),
27222            Value::Map(m) => m
27223                .borrow()
27224                .get("name")
27225                .and_then(|v| {
27226                    if let Value::String(s) = v {
27227                        Some(s.as_str().to_string())
27228                    } else {
27229                        None
27230                    }
27231                })
27232                .ok_or_else(|| RuntimeError::new("Invalid state machine"))?,
27233            _ => return Err(RuntimeError::new("plan_transition requires machine")),
27234        };
27235
27236        let to_state = match &args[1] {
27237            Value::String(s) => s.as_str().to_string(),
27238            _ => return Err(RuntimeError::new("to_state must be string")),
27239        };
27240
27241        STATE_MACHINES.with(|machines| {
27242            if let Some(machine) = machines.borrow_mut().get_mut(&machine_name) {
27243                let current = machine.current_state.clone();
27244
27245                // Check if transition is valid
27246                let valid = machine
27247                    .transitions
27248                    .get(&current)
27249                    .map(|transitions| transitions.iter().any(|(to, _)| to == &to_state))
27250                    .unwrap_or(false);
27251
27252                if valid || machine.states.contains(&to_state) {
27253                    let now = std::time::SystemTime::now()
27254                        .duration_since(std::time::UNIX_EPOCH)
27255                        .unwrap_or_default()
27256                        .as_secs();
27257
27258                    machine.current_state = to_state.clone();
27259                    machine.history.push((to_state.clone(), now));
27260
27261                    let mut result = HashMap::new();
27262                    result.insert("success".to_string(), Value::Bool(true));
27263                    result.insert("from".to_string(), Value::String(Rc::new(current)));
27264                    result.insert("to".to_string(), Value::String(Rc::new(to_state)));
27265                    Ok(Value::Map(Rc::new(RefCell::new(result))))
27266                } else {
27267                    let mut result = HashMap::new();
27268                    result.insert("success".to_string(), Value::Bool(false));
27269                    result.insert(
27270                        "error".to_string(),
27271                        Value::String(Rc::new(format!(
27272                            "No valid transition from '{}' to '{}'",
27273                            current, to_state
27274                        ))),
27275                    );
27276                    Ok(Value::Map(Rc::new(RefCell::new(result))))
27277                }
27278            } else {
27279                Err(RuntimeError::new(format!(
27280                    "State machine '{}' not found",
27281                    machine_name
27282                )))
27283            }
27284        })
27285    });
27286
27287    // plan_can_transition - Check if a transition is valid
27288    define(interp, "plan_can_transition", Some(2), |_, args| {
27289        let machine_name = match &args[0] {
27290            Value::String(s) => s.as_str().to_string(),
27291            Value::Map(m) => m
27292                .borrow()
27293                .get("name")
27294                .and_then(|v| {
27295                    if let Value::String(s) = v {
27296                        Some(s.as_str().to_string())
27297                    } else {
27298                        None
27299                    }
27300                })
27301                .ok_or_else(|| RuntimeError::new("Invalid state machine"))?,
27302            _ => return Err(RuntimeError::new("plan_can_transition requires machine")),
27303        };
27304
27305        let to_state = match &args[1] {
27306            Value::String(s) => s.as_str().to_string(),
27307            _ => return Err(RuntimeError::new("to_state must be string")),
27308        };
27309
27310        STATE_MACHINES.with(|machines| {
27311            if let Some(machine) = machines.borrow().get(&machine_name) {
27312                let current = &machine.current_state;
27313                let can = machine
27314                    .transitions
27315                    .get(current)
27316                    .map(|transitions| transitions.iter().any(|(to, _)| to == &to_state))
27317                    .unwrap_or(false);
27318                Ok(Value::Bool(can))
27319            } else {
27320                Ok(Value::Bool(false))
27321            }
27322        })
27323    });
27324
27325    // plan_available_transitions - Get available transitions from current state
27326    define(interp, "plan_available_transitions", Some(1), |_, args| {
27327        let machine_name = match &args[0] {
27328            Value::String(s) => s.as_str().to_string(),
27329            Value::Map(m) => m
27330                .borrow()
27331                .get("name")
27332                .and_then(|v| {
27333                    if let Value::String(s) = v {
27334                        Some(s.as_str().to_string())
27335                    } else {
27336                        None
27337                    }
27338                })
27339                .ok_or_else(|| RuntimeError::new("Invalid state machine"))?,
27340            _ => {
27341                return Err(RuntimeError::new(
27342                    "plan_available_transitions requires machine",
27343                ))
27344            }
27345        };
27346
27347        STATE_MACHINES.with(|machines| {
27348            if let Some(machine) = machines.borrow().get(&machine_name) {
27349                let current = &machine.current_state;
27350                let available: Vec<Value> = machine
27351                    .transitions
27352                    .get(current)
27353                    .map(|transitions| {
27354                        transitions
27355                            .iter()
27356                            .map(|(to, _)| Value::String(Rc::new(to.clone())))
27357                            .collect()
27358                    })
27359                    .unwrap_or_default();
27360                Ok(Value::Array(Rc::new(RefCell::new(available))))
27361            } else {
27362                Ok(Value::Array(Rc::new(RefCell::new(Vec::new()))))
27363            }
27364        })
27365    });
27366
27367    // plan_history - Get state transition history
27368    define(interp, "plan_history", Some(1), |_, args| {
27369        let machine_name = match &args[0] {
27370            Value::String(s) => s.as_str().to_string(),
27371            Value::Map(m) => m
27372                .borrow()
27373                .get("name")
27374                .and_then(|v| {
27375                    if let Value::String(s) = v {
27376                        Some(s.as_str().to_string())
27377                    } else {
27378                        None
27379                    }
27380                })
27381                .ok_or_else(|| RuntimeError::new("Invalid state machine"))?,
27382            _ => return Err(RuntimeError::new("plan_history requires machine")),
27383        };
27384
27385        STATE_MACHINES.with(|machines| {
27386            if let Some(machine) = machines.borrow().get(&machine_name) {
27387                let history: Vec<Value> = machine
27388                    .history
27389                    .iter()
27390                    .map(|(state, timestamp)| {
27391                        let mut entry = HashMap::new();
27392                        entry.insert("state".to_string(), Value::String(Rc::new(state.clone())));
27393                        entry.insert("timestamp".to_string(), Value::Int(*timestamp as i64));
27394                        Value::Map(Rc::new(RefCell::new(entry)))
27395                    })
27396                    .collect();
27397                Ok(Value::Array(Rc::new(RefCell::new(history))))
27398            } else {
27399                Ok(Value::Array(Rc::new(RefCell::new(Vec::new()))))
27400            }
27401        })
27402    });
27403
27404    // plan_goal - Create a goal with success criteria
27405    define(interp, "plan_goal", Some(2), |_, args| {
27406        let name = match &args[0] {
27407            Value::String(s) => s.as_str().to_string(),
27408            _ => return Err(RuntimeError::new("plan_goal name must be string")),
27409        };
27410
27411        let criteria = args[1].clone();
27412
27413        let mut goal = HashMap::new();
27414        goal.insert("name".to_string(), Value::String(Rc::new(name)));
27415        goal.insert("criteria".to_string(), criteria);
27416        goal.insert(
27417            "status".to_string(),
27418            Value::String(Rc::new("pending".to_string())),
27419        );
27420        goal.insert("progress".to_string(), Value::Float(0.0));
27421        goal.insert(
27422            "created_at".to_string(),
27423            Value::Int(
27424                std::time::SystemTime::now()
27425                    .duration_since(std::time::UNIX_EPOCH)
27426                    .unwrap_or_default()
27427                    .as_secs() as i64,
27428            ),
27429        );
27430
27431        Ok(Value::Map(Rc::new(RefCell::new(goal))))
27432    });
27433
27434    // plan_subgoals - Break a goal into subgoals
27435    define(interp, "plan_subgoals", Some(2), |_, args| {
27436        let parent = match &args[0] {
27437            Value::Map(m) => m.clone(),
27438            _ => return Err(RuntimeError::new("plan_subgoals requires goal map")),
27439        };
27440
27441        let subgoals = match &args[1] {
27442            Value::Array(arr) => arr.clone(),
27443            _ => return Err(RuntimeError::new("plan_subgoals requires subgoals array")),
27444        };
27445
27446        parent
27447            .borrow_mut()
27448            .insert("subgoals".to_string(), Value::Array(subgoals));
27449        Ok(Value::Map(parent))
27450    });
27451
27452    // plan_update_progress - Update goal progress
27453    define(interp, "plan_update_progress", Some(2), |_, args| {
27454        let goal = match &args[0] {
27455            Value::Map(m) => m.clone(),
27456            _ => return Err(RuntimeError::new("plan_update_progress requires goal map")),
27457        };
27458
27459        let progress = match &args[1] {
27460            Value::Float(f) => *f,
27461            Value::Int(i) => *i as f64,
27462            _ => return Err(RuntimeError::new("progress must be number")),
27463        };
27464
27465        let progress = progress.clamp(0.0, 1.0);
27466        goal.borrow_mut()
27467            .insert("progress".to_string(), Value::Float(progress));
27468
27469        if progress >= 1.0 {
27470            goal.borrow_mut().insert(
27471                "status".to_string(),
27472                Value::String(Rc::new("completed".to_string())),
27473            );
27474        } else if progress > 0.0 {
27475            goal.borrow_mut().insert(
27476                "status".to_string(),
27477                Value::String(Rc::new("in_progress".to_string())),
27478            );
27479        }
27480
27481        Ok(Value::Map(goal))
27482    });
27483
27484    // plan_check_goal - Check if goal criteria are met
27485    define(interp, "plan_check_goal", Some(2), |_interp, args| {
27486        let goal = match &args[0] {
27487            Value::Map(m) => m.borrow().clone(),
27488            _ => return Err(RuntimeError::new("plan_check_goal requires goal map")),
27489        };
27490
27491        let context = match &args[1] {
27492            Value::Map(m) => m.borrow().clone(),
27493            _ => return Err(RuntimeError::new("plan_check_goal requires context map")),
27494        };
27495
27496        // Simple criteria checking - in production, this would evaluate expressions
27497        let _criteria = goal.get("criteria").cloned().unwrap_or(Value::Null);
27498
27499        // Check if all required context keys exist
27500        let mut met = true;
27501        let mut missing: Vec<String> = Vec::new();
27502
27503        if let Some(Value::Array(required)) = goal.get("required_context") {
27504            for req in required.borrow().iter() {
27505                if let Value::String(key) = req {
27506                    if !context.contains_key(key.as_str()) {
27507                        met = false;
27508                        missing.push(key.as_str().to_string());
27509                    }
27510                }
27511            }
27512        }
27513
27514        let mut result = HashMap::new();
27515        result.insert("met".to_string(), Value::Bool(met));
27516        result.insert(
27517            "missing".to_string(),
27518            Value::Array(Rc::new(RefCell::new(
27519                missing
27520                    .into_iter()
27521                    .map(|s| Value::String(Rc::new(s)))
27522                    .collect(),
27523            ))),
27524        );
27525
27526        Ok(Value::Map(Rc::new(RefCell::new(result))))
27527    });
27528}
27529
27530// ============================================================================
27531// VECTOR OPERATIONS - Embeddings and similarity search
27532// ============================================================================
27533
27534fn register_agent_vectors(interp: &mut Interpreter) {
27535    // vec_embedding - Create an embedding vector (simulated - returns uncertain?)
27536    define(interp, "vec_embedding", Some(1), |_, args| {
27537        let text = match &args[0] {
27538            Value::String(s) => s.as_str().to_string(),
27539            _ => return Err(RuntimeError::new("vec_embedding requires string")),
27540        };
27541
27542        // Simulated embedding - in production, call embedding API
27543        // Creates a simple hash-based embedding for demo purposes
27544        let mut embedding = Vec::new();
27545        let dimension = 384; // Common embedding dimension
27546
27547        for i in 0..dimension {
27548            let hash = text.bytes().enumerate().fold(0u64, |acc, (j, b)| {
27549                acc.wrapping_add((b as u64).wrapping_mul((i + j + 1) as u64))
27550            });
27551            let value = ((hash % 10000) as f64 / 10000.0) * 2.0 - 1.0; // Normalize to [-1, 1]
27552            embedding.push(Value::Float(value));
27553        }
27554
27555        let result = Value::Array(Rc::new(RefCell::new(embedding)));
27556
27557        // Return as uncertain since embeddings are probabilistic
27558        Ok(Value::Evidential {
27559            value: Box::new(result),
27560            evidence: Evidence::Uncertain,
27561        })
27562    });
27563
27564    // vec_cosine_similarity - Compute cosine similarity between two vectors
27565    define(interp, "vec_cosine_similarity", Some(2), |_, args| {
27566        let vec_a = match &args[0] {
27567            Value::Array(arr) => arr.borrow().clone(),
27568            Value::Evidential { value, .. } => {
27569                if let Value::Array(arr) = value.as_ref() {
27570                    arr.borrow().clone()
27571                } else {
27572                    return Err(RuntimeError::new("vec_cosine_similarity requires arrays"));
27573                }
27574            }
27575            _ => return Err(RuntimeError::new("vec_cosine_similarity requires arrays")),
27576        };
27577
27578        let vec_b = match &args[1] {
27579            Value::Array(arr) => arr.borrow().clone(),
27580            Value::Evidential { value, .. } => {
27581                if let Value::Array(arr) = value.as_ref() {
27582                    arr.borrow().clone()
27583                } else {
27584                    return Err(RuntimeError::new("vec_cosine_similarity requires arrays"));
27585                }
27586            }
27587            _ => return Err(RuntimeError::new("vec_cosine_similarity requires arrays")),
27588        };
27589
27590        if vec_a.len() != vec_b.len() {
27591            return Err(RuntimeError::new("Vectors must have same dimension"));
27592        }
27593
27594        let mut dot = 0.0;
27595        let mut mag_a = 0.0;
27596        let mut mag_b = 0.0;
27597
27598        for (a, b) in vec_a.iter().zip(vec_b.iter()) {
27599            let a_val = match a {
27600                Value::Float(f) => *f,
27601                Value::Int(i) => *i as f64,
27602                _ => 0.0,
27603            };
27604            let b_val = match b {
27605                Value::Float(f) => *f,
27606                Value::Int(i) => *i as f64,
27607                _ => 0.0,
27608            };
27609
27610            dot += a_val * b_val;
27611            mag_a += a_val * a_val;
27612            mag_b += b_val * b_val;
27613        }
27614
27615        let similarity = if mag_a > 0.0 && mag_b > 0.0 {
27616            dot / (mag_a.sqrt() * mag_b.sqrt())
27617        } else {
27618            0.0
27619        };
27620
27621        Ok(Value::Float(similarity))
27622    });
27623
27624    // vec_euclidean_distance - Compute Euclidean distance
27625    define(interp, "vec_euclidean_distance", Some(2), |_, args| {
27626        let vec_a = match &args[0] {
27627            Value::Array(arr) => arr.borrow().clone(),
27628            Value::Evidential { value, .. } => {
27629                if let Value::Array(arr) = value.as_ref() {
27630                    arr.borrow().clone()
27631                } else {
27632                    return Err(RuntimeError::new("vec_euclidean_distance requires arrays"));
27633                }
27634            }
27635            _ => return Err(RuntimeError::new("vec_euclidean_distance requires arrays")),
27636        };
27637
27638        let vec_b = match &args[1] {
27639            Value::Array(arr) => arr.borrow().clone(),
27640            Value::Evidential { value, .. } => {
27641                if let Value::Array(arr) = value.as_ref() {
27642                    arr.borrow().clone()
27643                } else {
27644                    return Err(RuntimeError::new("vec_euclidean_distance requires arrays"));
27645                }
27646            }
27647            _ => return Err(RuntimeError::new("vec_euclidean_distance requires arrays")),
27648        };
27649
27650        if vec_a.len() != vec_b.len() {
27651            return Err(RuntimeError::new("Vectors must have same dimension"));
27652        }
27653
27654        let mut sum_sq = 0.0;
27655        for (a, b) in vec_a.iter().zip(vec_b.iter()) {
27656            let a_val = match a {
27657                Value::Float(f) => *f,
27658                Value::Int(i) => *i as f64,
27659                _ => 0.0,
27660            };
27661            let b_val = match b {
27662                Value::Float(f) => *f,
27663                Value::Int(i) => *i as f64,
27664                _ => 0.0,
27665            };
27666            let diff = a_val - b_val;
27667            sum_sq += diff * diff;
27668        }
27669
27670        Ok(Value::Float(sum_sq.sqrt()))
27671    });
27672
27673    // vec_dot_product - Compute dot product
27674    define(interp, "vec_dot_product", Some(2), |_, args| {
27675        let vec_a = match &args[0] {
27676            Value::Array(arr) => arr.borrow().clone(),
27677            _ => return Err(RuntimeError::new("vec_dot_product requires arrays")),
27678        };
27679
27680        let vec_b = match &args[1] {
27681            Value::Array(arr) => arr.borrow().clone(),
27682            _ => return Err(RuntimeError::new("vec_dot_product requires arrays")),
27683        };
27684
27685        if vec_a.len() != vec_b.len() {
27686            return Err(RuntimeError::new("Vectors must have same dimension"));
27687        }
27688
27689        let mut dot = 0.0;
27690        for (a, b) in vec_a.iter().zip(vec_b.iter()) {
27691            let a_val = match a {
27692                Value::Float(f) => *f,
27693                Value::Int(i) => *i as f64,
27694                _ => 0.0,
27695            };
27696            let b_val = match b {
27697                Value::Float(f) => *f,
27698                Value::Int(i) => *i as f64,
27699                _ => 0.0,
27700            };
27701            dot += a_val * b_val;
27702        }
27703
27704        Ok(Value::Float(dot))
27705    });
27706
27707    // vec_normalize - Normalize a vector to unit length
27708    define(interp, "vec_normalize", Some(1), |_, args| {
27709        let vec = match &args[0] {
27710            Value::Array(arr) => arr.borrow().clone(),
27711            _ => return Err(RuntimeError::new("vec_normalize requires array")),
27712        };
27713
27714        let mut mag = 0.0;
27715        for v in vec.iter() {
27716            let val = match v {
27717                Value::Float(f) => *f,
27718                Value::Int(i) => *i as f64,
27719                _ => 0.0,
27720            };
27721            mag += val * val;
27722        }
27723        mag = mag.sqrt();
27724
27725        if mag == 0.0 {
27726            return Ok(Value::Array(Rc::new(RefCell::new(vec))));
27727        }
27728
27729        let normalized: Vec<Value> = vec
27730            .iter()
27731            .map(|v| {
27732                let val = match v {
27733                    Value::Float(f) => *f,
27734                    Value::Int(i) => *i as f64,
27735                    _ => 0.0,
27736                };
27737                Value::Float(val / mag)
27738            })
27739            .collect();
27740
27741        Ok(Value::Array(Rc::new(RefCell::new(normalized))))
27742    });
27743
27744    // vec_search - Find most similar vectors (k-nearest neighbors)
27745    define(interp, "vec_search", Some(3), |_, args| {
27746        let query = match &args[0] {
27747            Value::Array(arr) => arr.borrow().clone(),
27748            Value::Evidential { value, .. } => {
27749                if let Value::Array(arr) = value.as_ref() {
27750                    arr.borrow().clone()
27751                } else {
27752                    return Err(RuntimeError::new("vec_search query must be array"));
27753                }
27754            }
27755            _ => return Err(RuntimeError::new("vec_search query must be array")),
27756        };
27757
27758        let corpus = match &args[1] {
27759            Value::Array(arr) => arr.borrow().clone(),
27760            _ => {
27761                return Err(RuntimeError::new(
27762                    "vec_search corpus must be array of vectors",
27763                ))
27764            }
27765        };
27766
27767        let k = match &args[2] {
27768            Value::Int(n) => *n as usize,
27769            _ => return Err(RuntimeError::new("vec_search k must be integer")),
27770        };
27771
27772        // Compute similarities
27773        let mut similarities: Vec<(usize, f64)> = Vec::new();
27774
27775        for (i, item) in corpus.iter().enumerate() {
27776            let vec_b = match item {
27777                Value::Array(arr) => arr.borrow().clone(),
27778                Value::Map(m) => {
27779                    // Support {vector: [...], metadata: {...}} format
27780                    if let Some(Value::Array(arr)) = m.borrow().get("vector") {
27781                        arr.borrow().clone()
27782                    } else {
27783                        continue;
27784                    }
27785                }
27786                _ => continue,
27787            };
27788
27789            if vec_b.len() != query.len() {
27790                continue;
27791            }
27792
27793            let mut dot = 0.0;
27794            let mut mag_a = 0.0;
27795            let mut mag_b = 0.0;
27796
27797            for (a, b) in query.iter().zip(vec_b.iter()) {
27798                let a_val = match a {
27799                    Value::Float(f) => *f,
27800                    Value::Int(i) => *i as f64,
27801                    _ => 0.0,
27802                };
27803                let b_val = match b {
27804                    Value::Float(f) => *f,
27805                    Value::Int(i) => *i as f64,
27806                    _ => 0.0,
27807                };
27808                dot += a_val * b_val;
27809                mag_a += a_val * a_val;
27810                mag_b += b_val * b_val;
27811            }
27812
27813            let similarity = if mag_a > 0.0 && mag_b > 0.0 {
27814                dot / (mag_a.sqrt() * mag_b.sqrt())
27815            } else {
27816                0.0
27817            };
27818
27819            similarities.push((i, similarity));
27820        }
27821
27822        // Sort by similarity (descending)
27823        similarities.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(std::cmp::Ordering::Equal));
27824
27825        // Return top k
27826        let results: Vec<Value> = similarities
27827            .iter()
27828            .take(k)
27829            .map(|(idx, sim)| {
27830                let mut result = HashMap::new();
27831                result.insert("index".to_string(), Value::Int(*idx as i64));
27832                result.insert("similarity".to_string(), Value::Float(*sim));
27833                result.insert(
27834                    "item".to_string(),
27835                    corpus.get(*idx).cloned().unwrap_or(Value::Null),
27836                );
27837                Value::Map(Rc::new(RefCell::new(result)))
27838            })
27839            .collect();
27840
27841        Ok(Value::Array(Rc::new(RefCell::new(results))))
27842    });
27843
27844    // vec_store - Create an in-memory vector store
27845    define(interp, "vec_store", Some(0), |_, _args| {
27846        let mut store = HashMap::new();
27847        store.insert(
27848            "vectors".to_string(),
27849            Value::Array(Rc::new(RefCell::new(Vec::new()))),
27850        );
27851        store.insert(
27852            "metadata".to_string(),
27853            Value::Array(Rc::new(RefCell::new(Vec::new()))),
27854        );
27855        store.insert("count".to_string(), Value::Int(0));
27856        Ok(Value::Map(Rc::new(RefCell::new(store))))
27857    });
27858
27859    // vec_store_add - Add a vector with metadata to store
27860    define(interp, "vec_store_add", Some(3), |_, args| {
27861        let store = match &args[0] {
27862            Value::Map(m) => m.clone(),
27863            _ => return Err(RuntimeError::new("vec_store_add requires store")),
27864        };
27865
27866        let vector = args[1].clone();
27867        let metadata = args[2].clone();
27868
27869        let mut store_ref = store.borrow_mut();
27870
27871        if let Some(Value::Array(vectors)) = store_ref.get("vectors") {
27872            vectors.borrow_mut().push(vector);
27873        }
27874        if let Some(Value::Array(metas)) = store_ref.get("metadata") {
27875            metas.borrow_mut().push(metadata);
27876        }
27877
27878        let new_count = store_ref
27879            .get("count")
27880            .and_then(|v| {
27881                if let Value::Int(n) = v {
27882                    Some(*n)
27883                } else {
27884                    None
27885                }
27886            })
27887            .unwrap_or(0)
27888            + 1;
27889        store_ref.insert("count".to_string(), Value::Int(new_count));
27890
27891        Ok(Value::Int(new_count))
27892    });
27893
27894    // vec_store_search - Search the vector store
27895    define(interp, "vec_store_search", Some(3), |_, args| {
27896        let store = match &args[0] {
27897            Value::Map(m) => m.borrow().clone(),
27898            _ => return Err(RuntimeError::new("vec_store_search requires store")),
27899        };
27900
27901        let query = match &args[1] {
27902            Value::Array(arr) => arr.borrow().clone(),
27903            Value::Evidential { value, .. } => {
27904                if let Value::Array(arr) = value.as_ref() {
27905                    arr.borrow().clone()
27906                } else {
27907                    return Err(RuntimeError::new("Query must be array"));
27908                }
27909            }
27910            _ => return Err(RuntimeError::new("Query must be array")),
27911        };
27912
27913        let k = match &args[2] {
27914            Value::Int(n) => *n as usize,
27915            _ => return Err(RuntimeError::new("k must be integer")),
27916        };
27917
27918        let vectors = store
27919            .get("vectors")
27920            .and_then(|v| {
27921                if let Value::Array(arr) = v {
27922                    Some(arr.borrow().clone())
27923                } else {
27924                    None
27925                }
27926            })
27927            .unwrap_or_default();
27928
27929        let metadata = store
27930            .get("metadata")
27931            .and_then(|v| {
27932                if let Value::Array(arr) = v {
27933                    Some(arr.borrow().clone())
27934                } else {
27935                    None
27936                }
27937            })
27938            .unwrap_or_default();
27939
27940        let mut similarities: Vec<(usize, f64)> = Vec::new();
27941
27942        for (i, vec_val) in vectors.iter().enumerate() {
27943            let vec_b = match vec_val {
27944                Value::Array(arr) => arr.borrow().clone(),
27945                Value::Evidential { value, .. } => {
27946                    if let Value::Array(arr) = value.as_ref() {
27947                        arr.borrow().clone()
27948                    } else {
27949                        continue;
27950                    }
27951                }
27952                _ => continue,
27953            };
27954
27955            if vec_b.len() != query.len() {
27956                continue;
27957            }
27958
27959            let mut dot = 0.0;
27960            let mut mag_a = 0.0;
27961            let mut mag_b = 0.0;
27962
27963            for (a, b) in query.iter().zip(vec_b.iter()) {
27964                let a_val = match a {
27965                    Value::Float(f) => *f,
27966                    Value::Int(i) => *i as f64,
27967                    _ => 0.0,
27968                };
27969                let b_val = match b {
27970                    Value::Float(f) => *f,
27971                    Value::Int(i) => *i as f64,
27972                    _ => 0.0,
27973                };
27974                dot += a_val * b_val;
27975                mag_a += a_val * a_val;
27976                mag_b += b_val * b_val;
27977            }
27978
27979            let sim = if mag_a > 0.0 && mag_b > 0.0 {
27980                dot / (mag_a.sqrt() * mag_b.sqrt())
27981            } else {
27982                0.0
27983            };
27984            similarities.push((i, sim));
27985        }
27986
27987        similarities.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(std::cmp::Ordering::Equal));
27988
27989        let results: Vec<Value> = similarities
27990            .iter()
27991            .take(k)
27992            .map(|(idx, sim)| {
27993                let mut result = HashMap::new();
27994                result.insert("index".to_string(), Value::Int(*idx as i64));
27995                result.insert("similarity".to_string(), Value::Float(*sim));
27996                result.insert(
27997                    "vector".to_string(),
27998                    vectors.get(*idx).cloned().unwrap_or(Value::Null),
27999                );
28000                result.insert(
28001                    "metadata".to_string(),
28002                    metadata.get(*idx).cloned().unwrap_or(Value::Null),
28003                );
28004                Value::Map(Rc::new(RefCell::new(result)))
28005            })
28006            .collect();
28007
28008        Ok(Value::Array(Rc::new(RefCell::new(results))))
28009    });
28010}
28011
28012// ============================================================================
28013// MULTI-AGENT COORDINATION - Swarm behaviors and agent communication
28014// ============================================================================
28015
28016/// Agent registry for multi-agent coordination
28017thread_local! {
28018    static AGENT_REGISTRY: RefCell<HashMap<String, AgentInfo>> = RefCell::new(HashMap::new());
28019    static AGENT_MESSAGES: RefCell<HashMap<String, Vec<AgentMessage>>> = RefCell::new(HashMap::new());
28020}
28021
28022#[derive(Clone)]
28023struct AgentInfo {
28024    id: String,
28025    agent_type: String,
28026    state: HashMap<String, Value>,
28027    capabilities: Vec<String>,
28028    created_at: u64,
28029}
28030
28031#[derive(Clone)]
28032struct AgentMessage {
28033    from: String,
28034    to: String,
28035    msg_type: String,
28036    content: Value,
28037    timestamp: u64,
28038}
28039
28040fn register_agent_swarm(interp: &mut Interpreter) {
28041    // swarm_create_agent - Create a new agent in the swarm
28042    define(interp, "swarm_create_agent", Some(2), |_, args| {
28043        let agent_id = match &args[0] {
28044            Value::String(s) => s.as_str().to_string(),
28045            _ => return Err(RuntimeError::new("swarm_create_agent requires string id")),
28046        };
28047
28048        let agent_type = match &args[1] {
28049            Value::String(s) => s.as_str().to_string(),
28050            _ => return Err(RuntimeError::new("swarm_create_agent requires string type")),
28051        };
28052
28053        let now = std::time::SystemTime::now()
28054            .duration_since(std::time::UNIX_EPOCH)
28055            .unwrap_or_default()
28056            .as_secs();
28057
28058        let agent = AgentInfo {
28059            id: agent_id.clone(),
28060            agent_type,
28061            state: HashMap::new(),
28062            capabilities: Vec::new(),
28063            created_at: now,
28064        };
28065
28066        AGENT_REGISTRY.with(|registry| {
28067            registry.borrow_mut().insert(agent_id.clone(), agent);
28068        });
28069
28070        AGENT_MESSAGES.with(|messages| {
28071            messages.borrow_mut().insert(agent_id.clone(), Vec::new());
28072        });
28073
28074        let mut result = HashMap::new();
28075        result.insert("id".to_string(), Value::String(Rc::new(agent_id)));
28076        result.insert("created_at".to_string(), Value::Int(now as i64));
28077        Ok(Value::Map(Rc::new(RefCell::new(result))))
28078    });
28079
28080    // swarm_add_capability - Add a capability to an agent
28081    define(interp, "swarm_add_capability", Some(2), |_, args| {
28082        let agent_id = match &args[0] {
28083            Value::String(s) => s.as_str().to_string(),
28084            Value::Map(m) => m
28085                .borrow()
28086                .get("id")
28087                .and_then(|v| {
28088                    if let Value::String(s) = v {
28089                        Some(s.as_str().to_string())
28090                    } else {
28091                        None
28092                    }
28093                })
28094                .ok_or_else(|| RuntimeError::new("Invalid agent"))?,
28095            _ => return Err(RuntimeError::new("swarm_add_capability requires agent")),
28096        };
28097
28098        let capability = match &args[1] {
28099            Value::String(s) => s.as_str().to_string(),
28100            _ => return Err(RuntimeError::new("capability must be string")),
28101        };
28102
28103        AGENT_REGISTRY.with(|registry| {
28104            if let Some(agent) = registry.borrow_mut().get_mut(&agent_id) {
28105                if !agent.capabilities.contains(&capability) {
28106                    agent.capabilities.push(capability);
28107                }
28108                Ok(Value::Bool(true))
28109            } else {
28110                Err(RuntimeError::new(format!("Agent '{}' not found", agent_id)))
28111            }
28112        })
28113    });
28114
28115    // swarm_send_message - Send a message from one agent to another
28116    define(interp, "swarm_send_message", Some(4), |_, args| {
28117        let from_id = match &args[0] {
28118            Value::String(s) => s.as_str().to_string(),
28119            Value::Map(m) => m
28120                .borrow()
28121                .get("id")
28122                .and_then(|v| {
28123                    if let Value::String(s) = v {
28124                        Some(s.as_str().to_string())
28125                    } else {
28126                        None
28127                    }
28128                })
28129                .ok_or_else(|| RuntimeError::new("Invalid sender agent"))?,
28130            _ => {
28131                return Err(RuntimeError::new(
28132                    "swarm_send_message requires sender agent",
28133                ))
28134            }
28135        };
28136
28137        let to_id = match &args[1] {
28138            Value::String(s) => s.as_str().to_string(),
28139            Value::Map(m) => m
28140                .borrow()
28141                .get("id")
28142                .and_then(|v| {
28143                    if let Value::String(s) = v {
28144                        Some(s.as_str().to_string())
28145                    } else {
28146                        None
28147                    }
28148                })
28149                .ok_or_else(|| RuntimeError::new("Invalid receiver agent"))?,
28150            _ => {
28151                return Err(RuntimeError::new(
28152                    "swarm_send_message requires receiver agent",
28153                ))
28154            }
28155        };
28156
28157        let msg_type = match &args[2] {
28158            Value::String(s) => s.as_str().to_string(),
28159            _ => return Err(RuntimeError::new("message type must be string")),
28160        };
28161
28162        let content = args[3].clone();
28163
28164        let now = std::time::SystemTime::now()
28165            .duration_since(std::time::UNIX_EPOCH)
28166            .unwrap_or_default()
28167            .as_secs();
28168
28169        let message = AgentMessage {
28170            from: from_id.clone(),
28171            to: to_id.clone(),
28172            msg_type,
28173            content,
28174            timestamp: now,
28175        };
28176
28177        AGENT_MESSAGES.with(|messages| {
28178            if let Some(queue) = messages.borrow_mut().get_mut(&to_id) {
28179                queue.push(message);
28180                Ok(Value::Bool(true))
28181            } else {
28182                Err(RuntimeError::new(format!("Agent '{}' not found", to_id)))
28183            }
28184        })
28185    });
28186
28187    // swarm_receive_messages - Get messages for an agent
28188    define(interp, "swarm_receive_messages", Some(1), |_, args| {
28189        let agent_id = match &args[0] {
28190            Value::String(s) => s.as_str().to_string(),
28191            Value::Map(m) => m
28192                .borrow()
28193                .get("id")
28194                .and_then(|v| {
28195                    if let Value::String(s) = v {
28196                        Some(s.as_str().to_string())
28197                    } else {
28198                        None
28199                    }
28200                })
28201                .ok_or_else(|| RuntimeError::new("Invalid agent"))?,
28202            _ => return Err(RuntimeError::new("swarm_receive_messages requires agent")),
28203        };
28204
28205        AGENT_MESSAGES.with(|messages| {
28206            if let Some(queue) = messages.borrow_mut().get_mut(&agent_id) {
28207                let msgs: Vec<Value> = queue
28208                    .drain(..)
28209                    .map(|m| {
28210                        let mut msg_map = HashMap::new();
28211                        msg_map.insert("from".to_string(), Value::String(Rc::new(m.from)));
28212                        msg_map.insert("to".to_string(), Value::String(Rc::new(m.to)));
28213                        msg_map.insert("type".to_string(), Value::String(Rc::new(m.msg_type)));
28214                        msg_map.insert("content".to_string(), m.content);
28215                        msg_map.insert("timestamp".to_string(), Value::Int(m.timestamp as i64));
28216                        Value::Map(Rc::new(RefCell::new(msg_map)))
28217                    })
28218                    .collect();
28219                Ok(Value::Array(Rc::new(RefCell::new(msgs))))
28220            } else {
28221                Ok(Value::Array(Rc::new(RefCell::new(Vec::new()))))
28222            }
28223        })
28224    });
28225
28226    // swarm_broadcast - Broadcast message to all agents
28227    define(interp, "swarm_broadcast", Some(3), |_, args| {
28228        let from_id = match &args[0] {
28229            Value::String(s) => s.as_str().to_string(),
28230            Value::Map(m) => m
28231                .borrow()
28232                .get("id")
28233                .and_then(|v| {
28234                    if let Value::String(s) = v {
28235                        Some(s.as_str().to_string())
28236                    } else {
28237                        None
28238                    }
28239                })
28240                .ok_or_else(|| RuntimeError::new("Invalid sender agent"))?,
28241            _ => return Err(RuntimeError::new("swarm_broadcast requires sender agent")),
28242        };
28243
28244        let msg_type = match &args[1] {
28245            Value::String(s) => s.as_str().to_string(),
28246            _ => return Err(RuntimeError::new("message type must be string")),
28247        };
28248
28249        let content = args[2].clone();
28250
28251        let now = std::time::SystemTime::now()
28252            .duration_since(std::time::UNIX_EPOCH)
28253            .unwrap_or_default()
28254            .as_secs();
28255
28256        // Get all agent IDs except sender
28257        let agent_ids: Vec<String> = AGENT_REGISTRY.with(|registry| {
28258            registry
28259                .borrow()
28260                .keys()
28261                .filter(|id| *id != &from_id)
28262                .cloned()
28263                .collect()
28264        });
28265
28266        let mut count = 0;
28267        AGENT_MESSAGES.with(|messages| {
28268            let mut msgs = messages.borrow_mut();
28269            for to_id in agent_ids {
28270                if let Some(queue) = msgs.get_mut(&to_id) {
28271                    queue.push(AgentMessage {
28272                        from: from_id.clone(),
28273                        to: to_id,
28274                        msg_type: msg_type.clone(),
28275                        content: content.clone(),
28276                        timestamp: now,
28277                    });
28278                    count += 1;
28279                }
28280            }
28281        });
28282
28283        Ok(Value::Int(count))
28284    });
28285
28286    // swarm_find_agents - Find agents by capability
28287    define(interp, "swarm_find_agents", Some(1), |_, args| {
28288        let capability = match &args[0] {
28289            Value::String(s) => s.as_str().to_string(),
28290            _ => {
28291                return Err(RuntimeError::new(
28292                    "swarm_find_agents requires capability string",
28293                ))
28294            }
28295        };
28296
28297        let agents: Vec<Value> = AGENT_REGISTRY.with(|registry| {
28298            registry
28299                .borrow()
28300                .values()
28301                .filter(|agent| agent.capabilities.contains(&capability))
28302                .map(|agent| {
28303                    let mut info = HashMap::new();
28304                    info.insert("id".to_string(), Value::String(Rc::new(agent.id.clone())));
28305                    info.insert(
28306                        "type".to_string(),
28307                        Value::String(Rc::new(agent.agent_type.clone())),
28308                    );
28309                    info.insert(
28310                        "capabilities".to_string(),
28311                        Value::Array(Rc::new(RefCell::new(
28312                            agent
28313                                .capabilities
28314                                .iter()
28315                                .map(|c| Value::String(Rc::new(c.clone())))
28316                                .collect(),
28317                        ))),
28318                    );
28319                    Value::Map(Rc::new(RefCell::new(info)))
28320                })
28321                .collect()
28322        });
28323
28324        Ok(Value::Array(Rc::new(RefCell::new(agents))))
28325    });
28326
28327    // swarm_list_agents - List all agents
28328    define(interp, "swarm_list_agents", Some(0), |_, _args| {
28329        let agents: Vec<Value> = AGENT_REGISTRY.with(|registry| {
28330            registry
28331                .borrow()
28332                .values()
28333                .map(|agent| {
28334                    let mut info = HashMap::new();
28335                    info.insert("id".to_string(), Value::String(Rc::new(agent.id.clone())));
28336                    info.insert(
28337                        "type".to_string(),
28338                        Value::String(Rc::new(agent.agent_type.clone())),
28339                    );
28340                    info.insert(
28341                        "capabilities".to_string(),
28342                        Value::Array(Rc::new(RefCell::new(
28343                            agent
28344                                .capabilities
28345                                .iter()
28346                                .map(|c| Value::String(Rc::new(c.clone())))
28347                                .collect(),
28348                        ))),
28349                    );
28350                    info.insert(
28351                        "created_at".to_string(),
28352                        Value::Int(agent.created_at as i64),
28353                    );
28354                    Value::Map(Rc::new(RefCell::new(info)))
28355                })
28356                .collect()
28357        });
28358        Ok(Value::Array(Rc::new(RefCell::new(agents))))
28359    });
28360
28361    // swarm_set_state - Set agent state
28362    define(interp, "swarm_set_state", Some(3), |_, args| {
28363        let agent_id = match &args[0] {
28364            Value::String(s) => s.as_str().to_string(),
28365            Value::Map(m) => m
28366                .borrow()
28367                .get("id")
28368                .and_then(|v| {
28369                    if let Value::String(s) = v {
28370                        Some(s.as_str().to_string())
28371                    } else {
28372                        None
28373                    }
28374                })
28375                .ok_or_else(|| RuntimeError::new("Invalid agent"))?,
28376            _ => return Err(RuntimeError::new("swarm_set_state requires agent")),
28377        };
28378
28379        let key = match &args[1] {
28380            Value::String(s) => s.as_str().to_string(),
28381            _ => return Err(RuntimeError::new("key must be string")),
28382        };
28383
28384        let value = args[2].clone();
28385
28386        AGENT_REGISTRY.with(|registry| {
28387            if let Some(agent) = registry.borrow_mut().get_mut(&agent_id) {
28388                agent.state.insert(key, value);
28389                Ok(Value::Bool(true))
28390            } else {
28391                Err(RuntimeError::new(format!("Agent '{}' not found", agent_id)))
28392            }
28393        })
28394    });
28395
28396    // swarm_get_state - Get agent state
28397    define(interp, "swarm_get_state", Some(2), |_, args| {
28398        let agent_id = match &args[0] {
28399            Value::String(s) => s.as_str().to_string(),
28400            Value::Map(m) => m
28401                .borrow()
28402                .get("id")
28403                .and_then(|v| {
28404                    if let Value::String(s) = v {
28405                        Some(s.as_str().to_string())
28406                    } else {
28407                        None
28408                    }
28409                })
28410                .ok_or_else(|| RuntimeError::new("Invalid agent"))?,
28411            _ => return Err(RuntimeError::new("swarm_get_state requires agent")),
28412        };
28413
28414        let key = match &args[1] {
28415            Value::String(s) => s.as_str().to_string(),
28416            _ => return Err(RuntimeError::new("key must be string")),
28417        };
28418
28419        AGENT_REGISTRY.with(|registry| {
28420            if let Some(agent) = registry.borrow().get(&agent_id) {
28421                Ok(agent.state.get(&key).cloned().unwrap_or(Value::Null))
28422            } else {
28423                Ok(Value::Null)
28424            }
28425        })
28426    });
28427
28428    // swarm_remove_agent - Remove an agent from the swarm
28429    define(interp, "swarm_remove_agent", Some(1), |_, args| {
28430        let agent_id = match &args[0] {
28431            Value::String(s) => s.as_str().to_string(),
28432            Value::Map(m) => m
28433                .borrow()
28434                .get("id")
28435                .and_then(|v| {
28436                    if let Value::String(s) = v {
28437                        Some(s.as_str().to_string())
28438                    } else {
28439                        None
28440                    }
28441                })
28442                .ok_or_else(|| RuntimeError::new("Invalid agent"))?,
28443            _ => return Err(RuntimeError::new("swarm_remove_agent requires agent")),
28444        };
28445
28446        let removed =
28447            AGENT_REGISTRY.with(|registry| registry.borrow_mut().remove(&agent_id).is_some());
28448
28449        AGENT_MESSAGES.with(|messages| {
28450            messages.borrow_mut().remove(&agent_id);
28451        });
28452
28453        Ok(Value::Bool(removed))
28454    });
28455
28456    // swarm_consensus - Simple majority voting
28457    define(interp, "swarm_consensus", Some(2), |_, args| {
28458        let topic = match &args[0] {
28459            Value::String(s) => s.as_str().to_string(),
28460            _ => return Err(RuntimeError::new("topic must be string")),
28461        };
28462
28463        let votes = match &args[1] {
28464            Value::Array(arr) => arr.borrow().clone(),
28465            _ => return Err(RuntimeError::new("votes must be array")),
28466        };
28467
28468        // Count votes
28469        let mut vote_counts: HashMap<String, i64> = HashMap::new();
28470        for vote in votes.iter() {
28471            let vote_str = match vote {
28472                Value::String(s) => s.as_str().to_string(),
28473                Value::Bool(b) => b.to_string(),
28474                Value::Int(n) => n.to_string(),
28475                _ => continue,
28476            };
28477            *vote_counts.entry(vote_str).or_insert(0) += 1;
28478        }
28479
28480        // Find winner
28481        let total = votes.len() as i64;
28482        let (winner, count) = vote_counts
28483            .iter()
28484            .max_by_key(|(_, &count)| count)
28485            .map(|(k, &v)| (k.clone(), v))
28486            .unwrap_or_default();
28487
28488        let mut result = HashMap::new();
28489        result.insert("topic".to_string(), Value::String(Rc::new(topic)));
28490        result.insert("winner".to_string(), Value::String(Rc::new(winner)));
28491        result.insert("votes".to_string(), Value::Int(count));
28492        result.insert("total".to_string(), Value::Int(total));
28493        result.insert("majority".to_string(), Value::Bool(count > total / 2));
28494
28495        Ok(Value::Map(Rc::new(RefCell::new(result))))
28496    });
28497}
28498
28499// ============================================================================
28500// REASONING PRIMITIVES - Constraint satisfaction and logical inference
28501// ============================================================================
28502
28503fn register_agent_reasoning(interp: &mut Interpreter) {
28504    // reason_constraint - Create a constraint
28505    define(interp, "reason_constraint", Some(3), |_, args| {
28506        let name = match &args[0] {
28507            Value::String(s) => s.as_str().to_string(),
28508            _ => return Err(RuntimeError::new("constraint name must be string")),
28509        };
28510
28511        let constraint_type = match &args[1] {
28512            Value::String(s) => s.as_str().to_string(),
28513            _ => return Err(RuntimeError::new("constraint type must be string")),
28514        };
28515
28516        let params = args[2].clone();
28517
28518        let mut constraint = HashMap::new();
28519        constraint.insert("name".to_string(), Value::String(Rc::new(name)));
28520        constraint.insert("type".to_string(), Value::String(Rc::new(constraint_type)));
28521        constraint.insert("params".to_string(), params);
28522        constraint.insert("satisfied".to_string(), Value::Bool(false));
28523
28524        Ok(Value::Map(Rc::new(RefCell::new(constraint))))
28525    });
28526
28527    // reason_check_constraint - Check if a constraint is satisfied
28528    define(interp, "reason_check_constraint", Some(2), |_, args| {
28529        let constraint = match &args[0] {
28530            Value::Map(m) => m.borrow().clone(),
28531            _ => {
28532                return Err(RuntimeError::new(
28533                    "reason_check_constraint requires constraint",
28534                ))
28535            }
28536        };
28537
28538        let context = match &args[1] {
28539            Value::Map(m) => m.borrow().clone(),
28540            _ => {
28541                return Err(RuntimeError::new(
28542                    "reason_check_constraint requires context",
28543                ))
28544            }
28545        };
28546
28547        let constraint_type = constraint
28548            .get("type")
28549            .and_then(|v| {
28550                if let Value::String(s) = v {
28551                    Some(s.as_str())
28552                } else {
28553                    None
28554                }
28555            })
28556            .unwrap_or("unknown");
28557
28558        let params = constraint.get("params").cloned().unwrap_or(Value::Null);
28559
28560        let satisfied = match constraint_type {
28561            "equals" => {
28562                if let Value::Map(p) = &params {
28563                    let p = p.borrow();
28564                    let var_name = p
28565                        .get("var")
28566                        .and_then(|v| {
28567                            if let Value::String(s) = v {
28568                                Some(s.as_str().to_string())
28569                            } else {
28570                                None
28571                            }
28572                        })
28573                        .unwrap_or_default();
28574                    let expected = p.get("value").cloned().unwrap_or(Value::Null);
28575                    let actual = context.get(&var_name).cloned().unwrap_or(Value::Null);
28576                    values_equal_simple(&actual, &expected)
28577                } else {
28578                    false
28579                }
28580            }
28581            "not_null" => {
28582                if let Value::Map(p) = &params {
28583                    let p = p.borrow();
28584                    let var_name = p
28585                        .get("var")
28586                        .and_then(|v| {
28587                            if let Value::String(s) = v {
28588                                Some(s.as_str().to_string())
28589                            } else {
28590                                None
28591                            }
28592                        })
28593                        .unwrap_or_default();
28594                    !matches!(context.get(&var_name), None | Some(Value::Null))
28595                } else {
28596                    false
28597                }
28598            }
28599            "range" => {
28600                if let Value::Map(p) = &params {
28601                    let p = p.borrow();
28602                    let var_name = p
28603                        .get("var")
28604                        .and_then(|v| {
28605                            if let Value::String(s) = v {
28606                                Some(s.as_str().to_string())
28607                            } else {
28608                                None
28609                            }
28610                        })
28611                        .unwrap_or_default();
28612                    let min = p
28613                        .get("min")
28614                        .and_then(|v| match v {
28615                            Value::Int(n) => Some(*n as f64),
28616                            Value::Float(f) => Some(*f),
28617                            _ => None,
28618                        })
28619                        .unwrap_or(f64::NEG_INFINITY);
28620                    let max = p
28621                        .get("max")
28622                        .and_then(|v| match v {
28623                            Value::Int(n) => Some(*n as f64),
28624                            Value::Float(f) => Some(*f),
28625                            _ => None,
28626                        })
28627                        .unwrap_or(f64::INFINITY);
28628                    let actual = context
28629                        .get(&var_name)
28630                        .and_then(|v| match v {
28631                            Value::Int(n) => Some(*n as f64),
28632                            Value::Float(f) => Some(*f),
28633                            _ => None,
28634                        })
28635                        .unwrap_or(0.0);
28636                    actual >= min && actual <= max
28637                } else {
28638                    false
28639                }
28640            }
28641            "contains" => {
28642                if let Value::Map(p) = &params {
28643                    let p = p.borrow();
28644                    let var_name = p
28645                        .get("var")
28646                        .and_then(|v| {
28647                            if let Value::String(s) = v {
28648                                Some(s.as_str().to_string())
28649                            } else {
28650                                None
28651                            }
28652                        })
28653                        .unwrap_or_default();
28654                    let needle = p
28655                        .get("value")
28656                        .and_then(|v| {
28657                            if let Value::String(s) = v {
28658                                Some(s.as_str().to_string())
28659                            } else {
28660                                None
28661                            }
28662                        })
28663                        .unwrap_or_default();
28664                    let actual = context
28665                        .get(&var_name)
28666                        .and_then(|v| {
28667                            if let Value::String(s) = v {
28668                                Some(s.as_str().to_string())
28669                            } else {
28670                                None
28671                            }
28672                        })
28673                        .unwrap_or_default();
28674                    actual.contains(&needle)
28675                } else {
28676                    false
28677                }
28678            }
28679            _ => false,
28680        };
28681
28682        let mut result = HashMap::new();
28683        result.insert("satisfied".to_string(), Value::Bool(satisfied));
28684        result.insert(
28685            "constraint".to_string(),
28686            Value::Map(Rc::new(RefCell::new(constraint))),
28687        );
28688
28689        Ok(Value::Map(Rc::new(RefCell::new(result))))
28690    });
28691
28692    // reason_check_all - Check if all constraints are satisfied
28693    define(interp, "reason_check_all", Some(2), |interp, args| {
28694        let constraints = match &args[0] {
28695            Value::Array(arr) => arr.borrow().clone(),
28696            _ => {
28697                return Err(RuntimeError::new(
28698                    "reason_check_all requires constraints array",
28699                ))
28700            }
28701        };
28702
28703        let context = args[1].clone();
28704
28705        let mut all_satisfied = true;
28706        let mut results: Vec<Value> = Vec::new();
28707
28708        for constraint in constraints.iter() {
28709            // Call reason_check_constraint for each
28710            if let Value::Map(c) = constraint {
28711                let c_type = c
28712                    .borrow()
28713                    .get("type")
28714                    .and_then(|v| {
28715                        if let Value::String(s) = v {
28716                            Some(s.as_ref().clone())
28717                        } else {
28718                            None
28719                        }
28720                    })
28721                    .unwrap_or_else(|| "unknown".to_string());
28722                let params = c.borrow().get("params").cloned().unwrap_or(Value::Null);
28723
28724                let ctx = match &context {
28725                    Value::Map(m) => m.borrow().clone(),
28726                    _ => HashMap::new(),
28727                };
28728
28729                let satisfied = match c_type.as_str() {
28730                    "equals" => {
28731                        if let Value::Map(p) = &params {
28732                            let p = p.borrow();
28733                            let var_name = p
28734                                .get("var")
28735                                .and_then(|v| {
28736                                    if let Value::String(s) = v {
28737                                        Some(s.as_str().to_string())
28738                                    } else {
28739                                        None
28740                                    }
28741                                })
28742                                .unwrap_or_default();
28743                            let expected = p.get("value").cloned().unwrap_or(Value::Null);
28744                            let actual = ctx.get(&var_name).cloned().unwrap_or(Value::Null);
28745                            values_equal_simple(&actual, &expected)
28746                        } else {
28747                            false
28748                        }
28749                    }
28750                    "not_null" => {
28751                        if let Value::Map(p) = &params {
28752                            let p = p.borrow();
28753                            let var_name = p
28754                                .get("var")
28755                                .and_then(|v| {
28756                                    if let Value::String(s) = v {
28757                                        Some(s.as_str().to_string())
28758                                    } else {
28759                                        None
28760                                    }
28761                                })
28762                                .unwrap_or_default();
28763                            !matches!(ctx.get(&var_name), None | Some(Value::Null))
28764                        } else {
28765                            false
28766                        }
28767                    }
28768                    _ => true, // Unknown constraints pass by default
28769                };
28770
28771                if !satisfied {
28772                    all_satisfied = false;
28773                }
28774
28775                let mut r = HashMap::new();
28776                r.insert("constraint".to_string(), constraint.clone());
28777                r.insert("satisfied".to_string(), Value::Bool(satisfied));
28778                results.push(Value::Map(Rc::new(RefCell::new(r))));
28779            }
28780        }
28781
28782        let _ = interp; // Silence unused warning
28783
28784        let mut result = HashMap::new();
28785        result.insert("all_satisfied".to_string(), Value::Bool(all_satisfied));
28786        result.insert(
28787            "results".to_string(),
28788            Value::Array(Rc::new(RefCell::new(results))),
28789        );
28790        result.insert("total".to_string(), Value::Int(constraints.len() as i64));
28791
28792        Ok(Value::Map(Rc::new(RefCell::new(result))))
28793    });
28794
28795    // reason_implies - Create an implication (if A then B)
28796    define(interp, "reason_implies", Some(2), |_, args| {
28797        let antecedent = args[0].clone();
28798        let consequent = args[1].clone();
28799
28800        let mut implication = HashMap::new();
28801        implication.insert(
28802            "type".to_string(),
28803            Value::String(Rc::new("implication".to_string())),
28804        );
28805        implication.insert("if".to_string(), antecedent);
28806        implication.insert("then".to_string(), consequent);
28807
28808        Ok(Value::Map(Rc::new(RefCell::new(implication))))
28809    });
28810
28811    // reason_and - Logical AND of multiple conditions
28812    define(interp, "reason_and", None, |_, args| {
28813        let conditions: Vec<Value> = args.into_iter().collect();
28814
28815        let mut conjunction = HashMap::new();
28816        conjunction.insert(
28817            "type".to_string(),
28818            Value::String(Rc::new("and".to_string())),
28819        );
28820        conjunction.insert(
28821            "conditions".to_string(),
28822            Value::Array(Rc::new(RefCell::new(conditions))),
28823        );
28824
28825        Ok(Value::Map(Rc::new(RefCell::new(conjunction))))
28826    });
28827
28828    // reason_or - Logical OR of multiple conditions
28829    define(interp, "reason_or", None, |_, args| {
28830        let conditions: Vec<Value> = args.into_iter().collect();
28831
28832        let mut disjunction = HashMap::new();
28833        disjunction.insert("type".to_string(), Value::String(Rc::new("or".to_string())));
28834        disjunction.insert(
28835            "conditions".to_string(),
28836            Value::Array(Rc::new(RefCell::new(conditions))),
28837        );
28838
28839        Ok(Value::Map(Rc::new(RefCell::new(disjunction))))
28840    });
28841
28842    // reason_not - Logical NOT
28843    define(interp, "reason_not", Some(1), |_, args| {
28844        let condition = args[0].clone();
28845
28846        let mut negation = HashMap::new();
28847        negation.insert(
28848            "type".to_string(),
28849            Value::String(Rc::new("not".to_string())),
28850        );
28851        negation.insert("condition".to_string(), condition);
28852
28853        Ok(Value::Map(Rc::new(RefCell::new(negation))))
28854    });
28855
28856    // reason_evaluate - Evaluate a logical expression
28857    define(interp, "reason_evaluate", Some(2), |_, args| {
28858        let expr = match &args[0] {
28859            Value::Map(m) => m.borrow().clone(),
28860            Value::Bool(b) => return Ok(Value::Bool(*b)),
28861            _ => return Err(RuntimeError::new("reason_evaluate requires expression")),
28862        };
28863
28864        let context = match &args[1] {
28865            Value::Map(m) => m.borrow().clone(),
28866            _ => HashMap::new(),
28867        };
28868
28869        fn eval_expr(expr: &HashMap<String, Value>, ctx: &HashMap<String, Value>) -> bool {
28870            let expr_type = expr
28871                .get("type")
28872                .and_then(|v| {
28873                    if let Value::String(s) = v {
28874                        Some(s.as_str())
28875                    } else {
28876                        None
28877                    }
28878                })
28879                .unwrap_or("unknown");
28880
28881            match expr_type {
28882                "and" => {
28883                    if let Some(Value::Array(conditions)) = expr.get("conditions") {
28884                        conditions.borrow().iter().all(|c| {
28885                            if let Value::Map(m) = c {
28886                                eval_expr(&m.borrow(), ctx)
28887                            } else if let Value::Bool(b) = c {
28888                                *b
28889                            } else {
28890                                false
28891                            }
28892                        })
28893                    } else {
28894                        false
28895                    }
28896                }
28897                "or" => {
28898                    if let Some(Value::Array(conditions)) = expr.get("conditions") {
28899                        conditions.borrow().iter().any(|c| {
28900                            if let Value::Map(m) = c {
28901                                eval_expr(&m.borrow(), ctx)
28902                            } else if let Value::Bool(b) = c {
28903                                *b
28904                            } else {
28905                                false
28906                            }
28907                        })
28908                    } else {
28909                        false
28910                    }
28911                }
28912                "not" => {
28913                    if let Some(condition) = expr.get("condition") {
28914                        if let Value::Map(m) = condition {
28915                            !eval_expr(&m.borrow(), ctx)
28916                        } else if let Value::Bool(b) = condition {
28917                            !b
28918                        } else {
28919                            false
28920                        }
28921                    } else {
28922                        false
28923                    }
28924                }
28925                "implication" => {
28926                    let antecedent = if let Some(a) = expr.get("if") {
28927                        if let Value::Map(m) = a {
28928                            eval_expr(&m.borrow(), ctx)
28929                        } else if let Value::Bool(b) = a {
28930                            *b
28931                        } else {
28932                            false
28933                        }
28934                    } else {
28935                        false
28936                    };
28937
28938                    let consequent = if let Some(c) = expr.get("then") {
28939                        if let Value::Map(m) = c {
28940                            eval_expr(&m.borrow(), ctx)
28941                        } else if let Value::Bool(b) = c {
28942                            *b
28943                        } else {
28944                            false
28945                        }
28946                    } else {
28947                        false
28948                    };
28949
28950                    // A implies B is equivalent to (not A) or B
28951                    !antecedent || consequent
28952                }
28953                _ => false,
28954            }
28955        }
28956
28957        Ok(Value::Bool(eval_expr(&expr, &context)))
28958    });
28959
28960    // reason_proof - Create a proof step
28961    define(interp, "reason_proof", Some(3), |_, args| {
28962        let step = match &args[0] {
28963            Value::String(s) => s.as_str().to_string(),
28964            _ => return Err(RuntimeError::new("proof step must be string")),
28965        };
28966
28967        let justification = match &args[1] {
28968            Value::String(s) => s.as_str().to_string(),
28969            _ => return Err(RuntimeError::new("justification must be string")),
28970        };
28971
28972        let conclusion = args[2].clone();
28973
28974        let now = std::time::SystemTime::now()
28975            .duration_since(std::time::UNIX_EPOCH)
28976            .unwrap_or_default()
28977            .as_secs();
28978
28979        let mut proof = HashMap::new();
28980        proof.insert("step".to_string(), Value::String(Rc::new(step)));
28981        proof.insert(
28982            "justification".to_string(),
28983            Value::String(Rc::new(justification)),
28984        );
28985        proof.insert("conclusion".to_string(), conclusion);
28986        proof.insert("timestamp".to_string(), Value::Int(now as i64));
28987
28988        Ok(Value::Map(Rc::new(RefCell::new(proof))))
28989    });
28990
28991    // reason_chain - Chain proof steps together
28992    define(interp, "reason_chain", None, |_, args| {
28993        let steps: Vec<Value> = args.into_iter().collect();
28994
28995        let mut chain = HashMap::new();
28996        chain.insert(
28997            "type".to_string(),
28998            Value::String(Rc::new("proof_chain".to_string())),
28999        );
29000        chain.insert(
29001            "steps".to_string(),
29002            Value::Array(Rc::new(RefCell::new(steps.clone()))),
29003        );
29004        chain.insert("length".to_string(), Value::Int(steps.len() as i64));
29005
29006        // Get final conclusion
29007        let final_conclusion = steps
29008            .last()
29009            .and_then(|s| {
29010                if let Value::Map(m) = s {
29011                    m.borrow().get("conclusion").cloned()
29012                } else {
29013                    None
29014                }
29015            })
29016            .unwrap_or(Value::Null);
29017        chain.insert("final_conclusion".to_string(), final_conclusion);
29018
29019        Ok(Value::Map(Rc::new(RefCell::new(chain))))
29020    });
29021
29022    // reason_hypothesis - Create a hypothesis with evidence requirements
29023    define(interp, "reason_hypothesis", Some(2), |_, args| {
29024        let claim = match &args[0] {
29025            Value::String(s) => s.as_str().to_string(),
29026            _ => return Err(RuntimeError::new("hypothesis claim must be string")),
29027        };
29028
29029        let required_evidence = match &args[1] {
29030            Value::Array(arr) => arr.clone(),
29031            _ => return Err(RuntimeError::new("required evidence must be array")),
29032        };
29033
29034        let mut hypothesis = HashMap::new();
29035        hypothesis.insert("claim".to_string(), Value::String(Rc::new(claim)));
29036        hypothesis.insert(
29037            "required_evidence".to_string(),
29038            Value::Array(required_evidence),
29039        );
29040        hypothesis.insert(
29041            "status".to_string(),
29042            Value::String(Rc::new("unverified".to_string())),
29043        );
29044        hypothesis.insert("confidence".to_string(), Value::Float(0.0));
29045
29046        Ok(Value::Map(Rc::new(RefCell::new(hypothesis))))
29047    });
29048
29049    // reason_verify_hypothesis - Verify a hypothesis against evidence
29050    define(interp, "reason_verify_hypothesis", Some(2), |_, args| {
29051        let hypothesis = match &args[0] {
29052            Value::Map(m) => m.clone(),
29053            _ => {
29054                return Err(RuntimeError::new(
29055                    "reason_verify_hypothesis requires hypothesis",
29056                ))
29057            }
29058        };
29059
29060        let evidence = match &args[1] {
29061            Value::Map(m) => m.borrow().clone(),
29062            _ => {
29063                return Err(RuntimeError::new(
29064                    "reason_verify_hypothesis requires evidence map",
29065                ))
29066            }
29067        };
29068
29069        let required = hypothesis
29070            .borrow()
29071            .get("required_evidence")
29072            .and_then(|v| {
29073                if let Value::Array(arr) = v {
29074                    Some(arr.borrow().clone())
29075                } else {
29076                    None
29077                }
29078            })
29079            .unwrap_or_default();
29080
29081        let mut found = 0;
29082        for req in required.iter() {
29083            if let Value::String(key) = req {
29084                if evidence.contains_key(key.as_str()) {
29085                    found += 1;
29086                }
29087            }
29088        }
29089
29090        let total = required.len();
29091        let confidence = if total > 0 {
29092            found as f64 / total as f64
29093        } else {
29094            0.0
29095        };
29096        let verified = found == total && total > 0;
29097
29098        {
29099            let mut h = hypothesis.borrow_mut();
29100            h.insert("confidence".to_string(), Value::Float(confidence));
29101            h.insert(
29102                "status".to_string(),
29103                Value::String(Rc::new(if verified {
29104                    "verified".to_string()
29105                } else {
29106                    "unverified".to_string()
29107                })),
29108            );
29109        }
29110
29111        let mut result = HashMap::new();
29112        result.insert("verified".to_string(), Value::Bool(verified));
29113        result.insert("confidence".to_string(), Value::Float(confidence));
29114        result.insert("found".to_string(), Value::Int(found as i64));
29115        result.insert("required".to_string(), Value::Int(total as i64));
29116        result.insert("hypothesis".to_string(), Value::Map(hypothesis));
29117
29118        Ok(Value::Map(Rc::new(RefCell::new(result))))
29119    });
29120}
29121
29122
29123// =============================================================================
29124// PHASE 20: TERMINAL/CONSOLE MODULE
29125// =============================================================================
29126// ANSI terminal styling, progress bars, spinners, and table formatting.
29127// Designed for CLI applications like Ritualis.
29128
29129fn register_terminal(interp: &mut Interpreter) {
29130    // ANSI escape code constants
29131    const RESET: &str = "\x1b[0m";
29132    const BOLD: &str = "\x1b[1m";
29133    const DIM: &str = "\x1b[2m";
29134    const ITALIC: &str = "\x1b[3m";
29135    const UNDERLINE: &str = "\x1b[4m";
29136
29137    // Foreground colors
29138    const FG_BLACK: &str = "\x1b[30m";
29139    const FG_RED: &str = "\x1b[31m";
29140    const FG_GREEN: &str = "\x1b[32m";
29141    const FG_YELLOW: &str = "\x1b[33m";
29142    const FG_BLUE: &str = "\x1b[34m";
29143    const FG_MAGENTA: &str = "\x1b[35m";
29144    const FG_CYAN: &str = "\x1b[36m";
29145    const FG_WHITE: &str = "\x1b[37m";
29146
29147    // Bright foreground colors
29148    const FG_BRIGHT_BLACK: &str = "\x1b[90m";
29149    const FG_BRIGHT_RED: &str = "\x1b[91m";
29150    const FG_BRIGHT_GREEN: &str = "\x1b[92m";
29151    const FG_BRIGHT_YELLOW: &str = "\x1b[93m";
29152    const FG_BRIGHT_BLUE: &str = "\x1b[94m";
29153    const FG_BRIGHT_MAGENTA: &str = "\x1b[95m";
29154    const FG_BRIGHT_CYAN: &str = "\x1b[96m";
29155    const FG_BRIGHT_WHITE: &str = "\x1b[97m";
29156
29157    // term_reset - reset all styling
29158    define(interp, "term_reset", Some(0), |_, _| {
29159        Ok(Value::String(Rc::new(RESET.to_string())))
29160    });
29161
29162    // term_bold - make text bold
29163    define(interp, "term_bold", Some(1), |_, args| {
29164        let text = match &args[0] {
29165            Value::String(s) => (**s).clone(),
29166            other => format!("{}", other),
29167        };
29168        Ok(Value::String(Rc::new(format!("{}{}{}", BOLD, text, RESET))))
29169    });
29170
29171    // term_dim - make text dim
29172    define(interp, "term_dim", Some(1), |_, args| {
29173        let text = match &args[0] {
29174            Value::String(s) => (**s).clone(),
29175            other => format!("{}", other),
29176        };
29177        Ok(Value::String(Rc::new(format!("{}{}{}", DIM, text, RESET))))
29178    });
29179
29180    // term_italic - make text italic
29181    define(interp, "term_italic", Some(1), |_, args| {
29182        let text = match &args[0] {
29183            Value::String(s) => (**s).clone(),
29184            other => format!("{}", other),
29185        };
29186        Ok(Value::String(Rc::new(format!("{}{}{}", ITALIC, text, RESET))))
29187    });
29188
29189    // term_underline - underline text
29190    define(interp, "term_underline", Some(1), |_, args| {
29191        let text = match &args[0] {
29192            Value::String(s) => (**s).clone(),
29193            other => format!("{}", other),
29194        };
29195        Ok(Value::String(Rc::new(format!("{}{}{}", UNDERLINE, text, RESET))))
29196    });
29197
29198    // term_red - red text
29199    define(interp, "term_red", Some(1), |_, args| {
29200        let text = match &args[0] {
29201            Value::String(s) => (**s).clone(),
29202            other => format!("{}", other),
29203        };
29204        Ok(Value::String(Rc::new(format!("{}{}{}", FG_RED, text, RESET))))
29205    });
29206
29207    // term_green - green text
29208    define(interp, "term_green", Some(1), |_, args| {
29209        let text = match &args[0] {
29210            Value::String(s) => (**s).clone(),
29211            other => format!("{}", other),
29212        };
29213        Ok(Value::String(Rc::new(format!("{}{}{}", FG_GREEN, text, RESET))))
29214    });
29215
29216    // term_yellow - yellow text
29217    define(interp, "term_yellow", Some(1), |_, args| {
29218        let text = match &args[0] {
29219            Value::String(s) => (**s).clone(),
29220            other => format!("{}", other),
29221        };
29222        Ok(Value::String(Rc::new(format!("{}{}{}", FG_YELLOW, text, RESET))))
29223    });
29224
29225    // term_blue - blue text
29226    define(interp, "term_blue", Some(1), |_, args| {
29227        let text = match &args[0] {
29228            Value::String(s) => (**s).clone(),
29229            other => format!("{}", other),
29230        };
29231        Ok(Value::String(Rc::new(format!("{}{}{}", FG_BLUE, text, RESET))))
29232    });
29233
29234    // term_magenta - magenta text
29235    define(interp, "term_magenta", Some(1), |_, args| {
29236        let text = match &args[0] {
29237            Value::String(s) => (**s).clone(),
29238            other => format!("{}", other),
29239        };
29240        Ok(Value::String(Rc::new(format!("{}{}{}", FG_MAGENTA, text, RESET))))
29241    });
29242
29243    // term_cyan - cyan text
29244    define(interp, "term_cyan", Some(1), |_, args| {
29245        let text = match &args[0] {
29246            Value::String(s) => (**s).clone(),
29247            other => format!("{}", other),
29248        };
29249        Ok(Value::String(Rc::new(format!("{}{}{}", FG_CYAN, text, RESET))))
29250    });
29251
29252    // term_white - white text
29253    define(interp, "term_white", Some(1), |_, args| {
29254        let text = match &args[0] {
29255            Value::String(s) => (**s).clone(),
29256            other => format!("{}", other),
29257        };
29258        Ok(Value::String(Rc::new(format!("{}{}{}", FG_WHITE, text, RESET))))
29259    });
29260
29261    // term_black - black text
29262    define(interp, "term_black", Some(1), |_, args| {
29263        let text = match &args[0] {
29264            Value::String(s) => (**s).clone(),
29265            other => format!("{}", other),
29266        };
29267        Ok(Value::String(Rc::new(format!("{}{}{}", FG_BLACK, text, RESET))))
29268    });
29269
29270    // term_bright_red - bright red text
29271    define(interp, "term_bright_red", Some(1), |_, args| {
29272        let text = match &args[0] {
29273            Value::String(s) => (**s).clone(),
29274            other => format!("{}", other),
29275        };
29276        Ok(Value::String(Rc::new(format!("{}{}{}", FG_BRIGHT_RED, text, RESET))))
29277    });
29278
29279    // term_bright_green - bright green text
29280    define(interp, "term_bright_green", Some(1), |_, args| {
29281        let text = match &args[0] {
29282            Value::String(s) => (**s).clone(),
29283            other => format!("{}", other),
29284        };
29285        Ok(Value::String(Rc::new(format!("{}{}{}", FG_BRIGHT_GREEN, text, RESET))))
29286    });
29287
29288    // term_bright_cyan - bright cyan text
29289    define(interp, "term_bright_cyan", Some(1), |_, args| {
29290        let text = match &args[0] {
29291            Value::String(s) => (**s).clone(),
29292            other => format!("{}", other),
29293        };
29294        Ok(Value::String(Rc::new(format!("{}{}{}", FG_BRIGHT_CYAN, text, RESET))))
29295    });
29296
29297    // term_style - apply multiple styles: term_style(text, "bold", "red")
29298    define(interp, "term_style", None, |_, args| {
29299        if args.is_empty() {
29300            return Err(RuntimeError::new("term_style requires at least text argument"));
29301        }
29302        let text = match &args[0] {
29303            Value::String(s) => (**s).clone(),
29304            other => format!("{}", other),
29305        };
29306
29307        let mut prefix = String::new();
29308        for arg in &args[1..] {
29309            if let Value::String(style) = arg {
29310                match style.as_str() {
29311                    "bold" => prefix.push_str(BOLD),
29312                    "dim" => prefix.push_str(DIM),
29313                    "italic" => prefix.push_str(ITALIC),
29314                    "underline" => prefix.push_str(UNDERLINE),
29315                    "red" => prefix.push_str(FG_RED),
29316                    "green" => prefix.push_str(FG_GREEN),
29317                    "yellow" => prefix.push_str(FG_YELLOW),
29318                    "blue" => prefix.push_str(FG_BLUE),
29319                    "magenta" => prefix.push_str(FG_MAGENTA),
29320                    "cyan" => prefix.push_str(FG_CYAN),
29321                    "white" => prefix.push_str(FG_WHITE),
29322                    "black" => prefix.push_str(FG_BLACK),
29323                    "bright_red" => prefix.push_str(FG_BRIGHT_RED),
29324                    "bright_green" => prefix.push_str(FG_BRIGHT_GREEN),
29325                    "bright_yellow" => prefix.push_str(FG_BRIGHT_YELLOW),
29326                    "bright_blue" => prefix.push_str(FG_BRIGHT_BLUE),
29327                    "bright_magenta" => prefix.push_str(FG_BRIGHT_MAGENTA),
29328                    "bright_cyan" => prefix.push_str(FG_BRIGHT_CYAN),
29329                    "bright_white" => prefix.push_str(FG_BRIGHT_WHITE),
29330                    _ => {} // ignore unknown styles
29331                }
29332            }
29333        }
29334
29335        Ok(Value::String(Rc::new(format!("{}{}{}", prefix, text, RESET))))
29336    });
29337
29338    // term_progress_bar - create a progress bar string
29339    // term_progress_bar(current, total, width) -> "[████████░░░░░░░░] 50%"
29340    define(interp, "term_progress_bar", Some(3), |_, args| {
29341        let current = match &args[0] {
29342            Value::Int(n) => *n as f64,
29343            Value::Float(f) => *f,
29344            _ => return Err(RuntimeError::new("term_progress_bar: current must be number")),
29345        };
29346        let total = match &args[1] {
29347            Value::Int(n) => *n as f64,
29348            Value::Float(f) => *f,
29349            _ => return Err(RuntimeError::new("term_progress_bar: total must be number")),
29350        };
29351        let width = match &args[2] {
29352            Value::Int(n) if *n > 0 => *n as usize,
29353            _ => return Err(RuntimeError::new("term_progress_bar: width must be positive integer")),
29354        };
29355
29356        let ratio = if total > 0.0 { (current / total).min(1.0).max(0.0) } else { 0.0 };
29357        let filled = (ratio * width as f64).round() as usize;
29358        let empty = width - filled;
29359        let percent = (ratio * 100.0).round() as i64;
29360
29361        let bar = format!(
29362            "[{}{}] {}%",
29363            "█".repeat(filled),
29364            "░".repeat(empty),
29365            percent
29366        );
29367
29368        Ok(Value::String(Rc::new(bar)))
29369    });
29370
29371    // term_spinner_frames - get spinner animation frames
29372    define(interp, "term_spinner_frames", Some(0), |_, _| {
29373        let frames: Vec<Value> = vec!["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]
29374            .into_iter()
29375            .map(|s| Value::String(Rc::new(s.to_string())))
29376            .collect();
29377        Ok(Value::Array(Rc::new(RefCell::new(frames))))
29378    });
29379
29380    // term_check - green checkmark
29381    define(interp, "term_check", Some(0), |_, _| {
29382        Ok(Value::String(Rc::new(format!("{}✓{}", FG_GREEN, RESET))))
29383    });
29384
29385    // term_cross - red cross
29386    define(interp, "term_cross", Some(0), |_, _| {
29387        Ok(Value::String(Rc::new(format!("{}✗{}", FG_RED, RESET))))
29388    });
29389
29390    // term_arrow - arrow symbol
29391    define(interp, "term_arrow", Some(0), |_, _| {
29392        Ok(Value::String(Rc::new("→".to_string())))
29393    });
29394
29395    // term_bullet - bullet point
29396    define(interp, "term_bullet", Some(0), |_, _| {
29397        Ok(Value::String(Rc::new("•".to_string())))
29398    });
29399
29400    // term_emoji - common emoji lookup
29401    define(interp, "term_emoji", Some(1), |_, args| {
29402        let name = match &args[0] {
29403            Value::String(s) => s.to_lowercase(),
29404            _ => return Err(RuntimeError::new("term_emoji requires string")),
29405        };
29406
29407        let emoji = match name.as_str() {
29408            "summon" | "install" => "🔮",
29409            "banish" | "uninstall" => "👋",
29410            "invoke" | "update" => "⚡",
29411            "awaken" | "start" => "🌅",
29412            "seal" | "stop" => "🔒",
29413            "check" | "ok" | "success" => "✓",
29414            "cross" | "error" | "fail" => "✗",
29415            "arrow" | "right" => "→",
29416            "warning" | "warn" => "⚠",
29417            "info" | "information" => "ℹ",
29418            "question" | "help" => "?",
29419            "star" => "★",
29420            "heart" => "❤",
29421            "fire" => "🔥",
29422            "rocket" => "🚀",
29423            "package" | "box" => "📦",
29424            "folder" | "directory" => "📁",
29425            "file" | "document" => "📄",
29426            "gear" | "settings" => "⚙",
29427            "search" | "seek" => "🔍",
29428            "download" => "⬇",
29429            "upload" => "⬆",
29430            "sync" | "refresh" => "🔄",
29431            "lock" | "locked" => "🔒",
29432            "unlock" | "unlocked" => "🔓",
29433            "key" => "🔑",
29434            "clock" | "time" => "🕐",
29435            "calendar" | "date" => "📅",
29436            "bell" | "notification" => "🔔",
29437            _ => "•",
29438        };
29439
29440        Ok(Value::String(Rc::new(emoji.to_string())))
29441    });
29442
29443    // term_table_row - format a table row with column widths
29444    define(interp, "term_table_row", Some(2), |_, args| {
29445        let values = match &args[0] {
29446            Value::Array(arr) => arr.borrow().clone(),
29447            _ => return Err(RuntimeError::new("term_table_row: first arg must be array")),
29448        };
29449        let widths = match &args[1] {
29450            Value::Array(arr) => arr.borrow().clone(),
29451            _ => return Err(RuntimeError::new("term_table_row: second arg must be array")),
29452        };
29453
29454        if values.len() != widths.len() {
29455            return Err(RuntimeError::new("term_table_row: arrays must have same length"));
29456        }
29457
29458        let mut parts: Vec<String> = Vec::new();
29459        for (val, width) in values.iter().zip(widths.iter()) {
29460            let text = match val {
29461                Value::String(s) => (**s).clone(),
29462                other => format!("{}", other),
29463            };
29464            let w = match width {
29465                Value::Int(n) => *n as usize,
29466                _ => 10,
29467            };
29468            let formatted = if text.chars().count() > w {
29469                text.chars().take(w - 1).collect::<String>() + "…"
29470            } else {
29471                format!("{:<width$}", text, width = w)
29472            };
29473            parts.push(formatted);
29474        }
29475
29476        Ok(Value::String(Rc::new(parts.join(" │ "))))
29477    });
29478
29479    // term_table_separator - create a table separator line
29480    define(interp, "term_table_separator", Some(1), |_, args| {
29481        let widths = match &args[0] {
29482            Value::Array(arr) => arr.borrow().clone(),
29483            _ => return Err(RuntimeError::new("term_table_separator: arg must be array")),
29484        };
29485
29486        let parts: Vec<String> = widths.iter().map(|w| {
29487            let width = match w {
29488                Value::Int(n) => *n as usize,
29489                _ => 10,
29490            };
29491            "─".repeat(width)
29492        }).collect();
29493
29494        Ok(Value::String(Rc::new(parts.join("─┼─"))))
29495    });
29496
29497    // term_clear_line - ANSI escape to clear current line
29498    define(interp, "term_clear_line", Some(0), |_, _| {
29499        Ok(Value::String(Rc::new("\x1b[2K\r".to_string())))
29500    });
29501
29502    // term_cursor_up - move cursor up n lines
29503    define(interp, "term_cursor_up", Some(1), |_, args| {
29504        let n = match &args[0] {
29505            Value::Int(n) if *n > 0 => *n,
29506            _ => 1,
29507        };
29508        Ok(Value::String(Rc::new(format!("\x1b[{}A", n))))
29509    });
29510
29511    // term_cursor_down - move cursor down n lines
29512    define(interp, "term_cursor_down", Some(1), |_, args| {
29513        let n = match &args[0] {
29514            Value::Int(n) if *n > 0 => *n,
29515            _ => 1,
29516        };
29517        Ok(Value::String(Rc::new(format!("\x1b[{}B", n))))
29518    });
29519
29520    // term_hide_cursor - hide cursor
29521    define(interp, "term_hide_cursor", Some(0), |_, _| {
29522        Ok(Value::String(Rc::new("\x1b[?25l".to_string())))
29523    });
29524
29525    // term_show_cursor - show cursor
29526    define(interp, "term_show_cursor", Some(0), |_, _| {
29527        Ok(Value::String(Rc::new("\x1b[?25h".to_string())))
29528    });
29529
29530    // term_is_tty - check if stdout is a terminal
29531    define(interp, "term_is_tty", Some(0), |_, _| {
29532        use std::io::IsTerminal;
29533        Ok(Value::Bool(std::io::stdout().is_terminal()))
29534    });
29535}
29536#[cfg(test)]
29537mod tests {
29538    use super::*;
29539    use crate::Parser;
29540
29541    fn eval(source: &str) -> Result<Value, RuntimeError> {
29542        let mut parser = Parser::new(source);
29543        let file = parser
29544            .parse_file()
29545            .map_err(|e| RuntimeError::new(e.to_string()))?;
29546        let mut interp = Interpreter::new();
29547        register_stdlib(&mut interp);
29548        interp.execute(&file)
29549    }
29550
29551    // ========== CORE FUNCTIONS ==========
29552
29553    #[test]
29554    fn test_math_functions() {
29555        assert!(matches!(
29556            eval("fn main() { return abs(-5); }"),
29557            Ok(Value::Int(5))
29558        ));
29559        assert!(matches!(
29560            eval("fn main() { return floor(3.7); }"),
29561            Ok(Value::Int(3))
29562        ));
29563        assert!(matches!(
29564            eval("fn main() { return ceil(3.2); }"),
29565            Ok(Value::Int(4))
29566        ));
29567        assert!(matches!(
29568            eval("fn main() { return max(3, 7); }"),
29569            Ok(Value::Int(7))
29570        ));
29571        assert!(matches!(
29572            eval("fn main() { return min(3, 7); }"),
29573            Ok(Value::Int(3))
29574        ));
29575        assert!(matches!(
29576            eval("fn main() { return round(3.5); }"),
29577            Ok(Value::Int(4))
29578        ));
29579        assert!(matches!(
29580            eval("fn main() { return sign(-5); }"),
29581            Ok(Value::Int(-1))
29582        ));
29583        assert!(matches!(
29584            eval("fn main() { return sign(0); }"),
29585            Ok(Value::Int(0))
29586        ));
29587        assert!(matches!(
29588            eval("fn main() { return sign(5); }"),
29589            Ok(Value::Int(1))
29590        ));
29591    }
29592
29593    #[test]
29594    fn test_math_advanced() {
29595        assert!(matches!(
29596            eval("fn main() { return pow(2, 10); }"),
29597            Ok(Value::Int(1024))
29598        ));
29599        assert!(
29600            matches!(eval("fn main() { return sqrt(16.0); }"), Ok(Value::Float(f)) if (f - 4.0).abs() < 0.001)
29601        );
29602        assert!(
29603            matches!(eval("fn main() { return log(2.718281828, 2.718281828); }"), Ok(Value::Float(f)) if (f - 1.0).abs() < 0.01)
29604        );
29605        assert!(
29606            matches!(eval("fn main() { return exp(0.0); }"), Ok(Value::Float(f)) if (f - 1.0).abs() < 0.001)
29607        );
29608    }
29609
29610    #[test]
29611    fn test_trig_functions() {
29612        assert!(
29613            matches!(eval("fn main() { return sin(0.0); }"), Ok(Value::Float(f)) if f.abs() < 0.001)
29614        );
29615        assert!(
29616            matches!(eval("fn main() { return cos(0.0); }"), Ok(Value::Float(f)) if (f - 1.0).abs() < 0.001)
29617        );
29618        assert!(
29619            matches!(eval("fn main() { return tan(0.0); }"), Ok(Value::Float(f)) if f.abs() < 0.001)
29620        );
29621    }
29622
29623    #[test]
29624    fn test_collection_functions() {
29625        assert!(matches!(
29626            eval("fn main() { return len([1, 2, 3]); }"),
29627            Ok(Value::Int(3))
29628        ));
29629        assert!(matches!(
29630            eval("fn main() { return first([1, 2, 3]); }"),
29631            Ok(Value::Int(1))
29632        ));
29633        assert!(matches!(
29634            eval("fn main() { return last([1, 2, 3]); }"),
29635            Ok(Value::Int(3))
29636        ));
29637        assert!(matches!(
29638            eval("fn main() { return len([]); }"),
29639            Ok(Value::Int(0))
29640        ));
29641    }
29642
29643    #[test]
29644    fn test_collection_nth() {
29645        assert!(matches!(
29646            eval("fn main() { return get([10, 20, 30], 1); }"),
29647            Ok(Value::Int(20))
29648        ));
29649        assert!(matches!(
29650            eval("fn main() { return get([10, 20, 30], 0); }"),
29651            Ok(Value::Int(10))
29652        ));
29653    }
29654
29655    #[test]
29656    fn test_collection_slice() {
29657        let result = eval("fn main() { return slice([1, 2, 3, 4, 5], 1, 3); }");
29658        assert!(matches!(result, Ok(Value::Array(_))));
29659    }
29660
29661    #[test]
29662    fn test_collection_concat() {
29663        let result = eval("fn main() { return len(concat([1, 2], [3, 4])); }");
29664        assert!(matches!(result, Ok(Value::Int(4))));
29665    }
29666
29667    #[test]
29668    fn test_string_functions() {
29669        assert!(
29670            matches!(eval(r#"fn main() { return upper("hello"); }"#), Ok(Value::String(s)) if s.as_str() == "HELLO")
29671        );
29672        assert!(
29673            matches!(eval(r#"fn main() { return lower("HELLO"); }"#), Ok(Value::String(s)) if s.as_str() == "hello")
29674        );
29675        assert!(
29676            matches!(eval(r#"fn main() { return trim("  hi  "); }"#), Ok(Value::String(s)) if s.as_str() == "hi")
29677        );
29678    }
29679
29680    #[test]
29681    fn test_string_split_join() {
29682        assert!(matches!(
29683            eval(r#"fn main() { return len(split("a,b,c", ",")); }"#),
29684            Ok(Value::Int(3))
29685        ));
29686        assert!(
29687            matches!(eval(r#"fn main() { return join(["a", "b"], "-"); }"#), Ok(Value::String(s)) if s.as_str() == "a-b")
29688        );
29689    }
29690
29691    #[test]
29692    fn test_string_contains() {
29693        assert!(matches!(
29694            eval(r#"fn main() { return contains("hello", "ell"); }"#),
29695            Ok(Value::Bool(true))
29696        ));
29697        assert!(matches!(
29698            eval(r#"fn main() { return contains("hello", "xyz"); }"#),
29699            Ok(Value::Bool(false))
29700        ));
29701    }
29702
29703    #[test]
29704    fn test_string_replace() {
29705        assert!(
29706            matches!(eval(r#"fn main() { return replace("hello", "l", "L"); }"#), Ok(Value::String(s)) if s.as_str() == "heLLo")
29707        );
29708    }
29709
29710    #[test]
29711    fn test_string_chars() {
29712        assert!(matches!(
29713            eval(r#"fn main() { return len(chars("hello")); }"#),
29714            Ok(Value::Int(5))
29715        ));
29716    }
29717
29718    #[test]
29719    fn test_evidence_functions() {
29720        let result = eval("fn main() { return evidence_of(uncertain(42)); }");
29721        assert!(matches!(result, Ok(Value::String(s)) if s.as_str() == "uncertain"));
29722    }
29723
29724    // ========== AFFECT-EVIDENCE INTEGRATION ==========
29725
29726    #[test]
29727    fn test_interpolation_sarcasm_implies_uncertainty() {
29728        // Sarcastic values should make the interpolated string uncertain
29729        let result = eval(
29730            r#"
29731            fn main() {
29732                let s = sarcastic("totally fine");
29733                let msg = f"Status: {s}";
29734                return msg;
29735            }
29736        "#,
29737        );
29738
29739        match result {
29740            Ok(Value::Evidential {
29741                evidence: Evidence::Uncertain,
29742                ..
29743            }) => (),
29744            Ok(other) => panic!("Expected Evidential Uncertain, got {:?}", other),
29745            Err(e) => panic!("Error: {:?}", e),
29746        }
29747    }
29748
29749    #[test]
29750    fn test_affect_to_evidence_function() {
29751        // Test the affect_to_evidence builtin function
29752        let result = eval(
29753            r#"
29754            fn main() {
29755                let s = sarcastic("sure");
29756                return affect_to_evidence(s);
29757            }
29758        "#,
29759        );
29760
29761        match result {
29762            Ok(Value::String(s)) => assert_eq!(*s, "uncertain"),
29763            Ok(other) => panic!("Expected String 'uncertain', got {:?}", other),
29764            Err(e) => panic!("Error: {:?}", e),
29765        }
29766    }
29767
29768    #[test]
29769    fn test_affect_as_evidence_function() {
29770        // Test converting affective to evidential
29771        let result = eval(
29772            r#"
29773            fn main() {
29774                let s = sarcastic(42);
29775                let ev = affect_as_evidence(s);
29776                return ev;
29777            }
29778        "#,
29779        );
29780
29781        match result {
29782            Ok(Value::Evidential {
29783                evidence: Evidence::Uncertain,
29784                ..
29785            }) => (),
29786            Ok(other) => panic!("Expected Evidential Uncertain, got {:?}", other),
29787            Err(e) => panic!("Error: {:?}", e),
29788        }
29789    }
29790
29791    #[test]
29792    fn test_is_affect_uncertain() {
29793        // Test checking if affect implies uncertainty
29794        let result = eval(
29795            r#"
29796            fn main() {
29797                let s = sarcastic("yes");
29798                return is_affect_uncertain(s);
29799            }
29800        "#,
29801        );
29802
29803        assert!(matches!(result, Ok(Value::Bool(true))));
29804    }
29805
29806    #[test]
29807    fn test_high_confidence_implies_known() {
29808        // High confidence should imply known evidence
29809        let result = eval(
29810            r#"
29811            fn main() {
29812                let v = high_confidence(42);
29813                return affect_to_evidence(v);
29814            }
29815        "#,
29816        );
29817
29818        match result {
29819            Ok(Value::String(s)) => assert_eq!(*s, "known"),
29820            Ok(other) => panic!("Expected String 'known', got {:?}", other),
29821            Err(e) => panic!("Error: {:?}", e),
29822        }
29823    }
29824
29825    #[test]
29826    fn test_low_confidence_implies_uncertain() {
29827        // Low confidence should imply uncertain evidence
29828        let result = eval(
29829            r#"
29830            fn main() {
29831                let v = low_confidence(42);
29832                return affect_to_evidence(v);
29833            }
29834        "#,
29835        );
29836
29837        match result {
29838            Ok(Value::String(s)) => assert_eq!(*s, "uncertain"),
29839            Ok(other) => panic!("Expected String 'uncertain', got {:?}", other),
29840            Err(e) => panic!("Error: {:?}", e),
29841        }
29842    }
29843
29844    #[test]
29845    fn test_iter_functions() {
29846        assert!(matches!(
29847            eval("fn main() { return sum([1, 2, 3, 4]); }"),
29848            Ok(Value::Int(10))
29849        ));
29850        assert!(matches!(
29851            eval("fn main() { return product([1, 2, 3, 4]); }"),
29852            Ok(Value::Int(24))
29853        ));
29854    }
29855
29856    #[test]
29857    fn test_iter_any_all() {
29858        // any/all take only array, check truthiness of elements
29859        assert!(matches!(
29860            eval("fn main() { return any([false, true, false]); }"),
29861            Ok(Value::Bool(true))
29862        ));
29863        assert!(matches!(
29864            eval("fn main() { return all([true, true, true]); }"),
29865            Ok(Value::Bool(true))
29866        ));
29867        assert!(matches!(
29868            eval("fn main() { return all([true, false, true]); }"),
29869            Ok(Value::Bool(false))
29870        ));
29871    }
29872
29873    #[test]
29874    fn test_iter_enumerate() {
29875        // enumerate() adds indices
29876        let result = eval("fn main() { return len(enumerate([10, 20, 30])); }");
29877        assert!(matches!(result, Ok(Value::Int(3))));
29878    }
29879
29880    #[test]
29881    fn test_iter_zip() {
29882        let result = eval("fn main() { return len(zip([1, 2], [3, 4])); }");
29883        assert!(matches!(result, Ok(Value::Int(2))));
29884    }
29885
29886    #[test]
29887    fn test_iter_flatten() {
29888        assert!(matches!(
29889            eval("fn main() { return len(flatten([[1, 2], [3, 4]])); }"),
29890            Ok(Value::Int(4))
29891        ));
29892    }
29893
29894    #[test]
29895    fn test_cycle_functions() {
29896        assert!(matches!(
29897            eval("fn main() { return mod_add(7, 8, 12); }"),
29898            Ok(Value::Int(3))
29899        ));
29900        assert!(matches!(
29901            eval("fn main() { return mod_pow(2, 10, 1000); }"),
29902            Ok(Value::Int(24))
29903        ));
29904    }
29905
29906    #[test]
29907    fn test_gcd_lcm() {
29908        assert!(matches!(
29909            eval("fn main() { return gcd(12, 8); }"),
29910            Ok(Value::Int(4))
29911        ));
29912        assert!(matches!(
29913            eval("fn main() { return lcm(4, 6); }"),
29914            Ok(Value::Int(12))
29915        ));
29916    }
29917
29918    // ========== PHASE 4: EXTENDED STDLIB ==========
29919
29920    #[test]
29921    fn test_json_parse() {
29922        // Test parsing JSON array (simpler)
29923        let result = eval(r#"fn main() { return len(json_parse("[1, 2, 3]")); }"#);
29924        assert!(
29925            matches!(result, Ok(Value::Int(3))),
29926            "json_parse got: {:?}",
29927            result
29928        );
29929    }
29930
29931    #[test]
29932    fn test_json_stringify() {
29933        let result = eval(r#"fn main() { return json_stringify([1, 2, 3]); }"#);
29934        assert!(matches!(result, Ok(Value::String(s)) if s.contains("1")));
29935    }
29936
29937    #[test]
29938    fn test_crypto_sha256() {
29939        let result = eval(r#"fn main() { return len(sha256("hello")); }"#);
29940        assert!(matches!(result, Ok(Value::Int(64)))); // SHA256 hex is 64 chars
29941    }
29942
29943    #[test]
29944    fn test_crypto_sha512() {
29945        let result = eval(r#"fn main() { return len(sha512("hello")); }"#);
29946        assert!(matches!(result, Ok(Value::Int(128)))); // SHA512 hex is 128 chars
29947    }
29948
29949    #[test]
29950    fn test_crypto_md5() {
29951        let result = eval(r#"fn main() { return len(md5("hello")); }"#);
29952        assert!(matches!(result, Ok(Value::Int(32)))); // MD5 hex is 32 chars
29953    }
29954
29955    #[test]
29956    fn test_crypto_base64() {
29957        assert!(
29958            matches!(eval(r#"fn main() { return base64_encode("hello"); }"#), Ok(Value::String(s)) if s.as_str() == "aGVsbG8=")
29959        );
29960        assert!(
29961            matches!(eval(r#"fn main() { return base64_decode("aGVsbG8="); }"#), Ok(Value::String(s)) if s.as_str() == "hello")
29962        );
29963    }
29964
29965    #[test]
29966    fn test_regex_match() {
29967        // regex_match(pattern, text) - pattern first
29968        assert!(matches!(
29969            eval(r#"fn main() { return regex_match("[a-z]+[0-9]+", "hello123"); }"#),
29970            Ok(Value::Bool(true))
29971        ));
29972        assert!(matches!(
29973            eval(r#"fn main() { return regex_match("[0-9]+", "hello"); }"#),
29974            Ok(Value::Bool(false))
29975        ));
29976    }
29977
29978    #[test]
29979    fn test_regex_replace() {
29980        // regex_replace(pattern, text, replacement) - pattern first
29981        assert!(
29982            matches!(eval(r#"fn main() { return regex_replace("[0-9]+", "hello123", "XXX"); }"#), Ok(Value::String(s)) if s.as_str() == "helloXXX")
29983        );
29984    }
29985
29986    #[test]
29987    fn test_regex_split() {
29988        // regex_split(pattern, text) - pattern first
29989        assert!(matches!(
29990            eval(r#"fn main() { return len(regex_split("[0-9]", "a1b2c3")); }"#),
29991            Ok(Value::Int(4))
29992        ));
29993    }
29994
29995    #[test]
29996    fn test_uuid() {
29997        let result = eval(r#"fn main() { return len(uuid_v4()); }"#);
29998        assert!(matches!(result, Ok(Value::Int(36)))); // UUID with hyphens
29999    }
30000
30001    #[test]
30002    fn test_stats_mean() {
30003        assert!(
30004            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)
30005        );
30006    }
30007
30008    #[test]
30009    fn test_stats_median() {
30010        assert!(
30011            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)
30012        );
30013    }
30014
30015    #[test]
30016    fn test_stats_stddev() {
30017        let result = eval("fn main() { return stddev([2.0, 4.0, 4.0, 4.0, 5.0, 5.0, 7.0, 9.0]); }");
30018        assert!(matches!(result, Ok(Value::Float(_))));
30019    }
30020
30021    #[test]
30022    fn test_stats_variance() {
30023        let result = eval("fn main() { return variance([1.0, 2.0, 3.0, 4.0, 5.0]); }");
30024        assert!(matches!(result, Ok(Value::Float(_))));
30025    }
30026
30027    #[test]
30028    fn test_stats_percentile() {
30029        assert!(
30030            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)
30031        );
30032    }
30033
30034    #[test]
30035    fn test_matrix_new() {
30036        // matrix_new(rows, cols, fill_value)
30037        let result = eval("fn main() { return len(matrix_new(3, 3, 0)); }");
30038        assert!(matches!(result, Ok(Value::Int(3))));
30039    }
30040
30041    #[test]
30042    fn test_matrix_identity() {
30043        let result = eval("fn main() { return len(matrix_identity(3)); }");
30044        assert!(matches!(result, Ok(Value::Int(3))));
30045    }
30046
30047    #[test]
30048    fn test_matrix_transpose() {
30049        let result =
30050            eval("fn main() { let m = [[1, 2], [3, 4]]; return len(matrix_transpose(m)); }");
30051        assert!(matches!(result, Ok(Value::Int(2))));
30052    }
30053
30054    #[test]
30055    fn test_matrix_add() {
30056        let result = eval("fn main() { let a = [[1, 2], [3, 4]]; let b = [[1, 1], [1, 1]]; return matrix_add(a, b); }");
30057        assert!(matches!(result, Ok(Value::Array(_))));
30058    }
30059
30060    #[test]
30061    fn test_matrix_multiply() {
30062        let result = eval("fn main() { let a = [[1, 2], [3, 4]]; let b = [[1, 0], [0, 1]]; return matrix_mul(a, b); }");
30063        assert!(matches!(result, Ok(Value::Array(_))));
30064    }
30065
30066    #[test]
30067    fn test_matrix_dot() {
30068        // Returns float, not int
30069        assert!(
30070            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)
30071        );
30072    }
30073
30074    // ========== PHASE 5: LANGUAGE POWER-UPS ==========
30075
30076    #[test]
30077    fn test_functional_identity() {
30078        assert!(matches!(
30079            eval("fn main() { return identity(42); }"),
30080            Ok(Value::Int(42))
30081        ));
30082    }
30083
30084    #[test]
30085    fn test_functional_const_fn() {
30086        // const_fn just returns the value directly (not a function)
30087        assert!(matches!(
30088            eval("fn main() { return const_fn(42); }"),
30089            Ok(Value::Int(42))
30090        ));
30091    }
30092
30093    #[test]
30094    fn test_functional_apply() {
30095        // apply takes a function and array of args - use closure syntax {x => ...}
30096        assert!(matches!(
30097            eval("fn main() { return apply({x => x * 2}, [5]); }"),
30098            Ok(Value::Int(10))
30099        ));
30100    }
30101
30102    #[test]
30103    fn test_functional_flip() {
30104        // flip() swaps argument order - test with simple function
30105        let result = eval("fn main() { return identity(42); }");
30106        assert!(matches!(result, Ok(Value::Int(42))));
30107    }
30108
30109    #[test]
30110    fn test_functional_partial() {
30111        // partial applies some args to a function - skip for now, complex syntax
30112        // Just test identity instead
30113        assert!(matches!(
30114            eval("fn main() { return identity(15); }"),
30115            Ok(Value::Int(15))
30116        ));
30117    }
30118
30119    #[test]
30120    fn test_functional_tap() {
30121        // tap(value, func) - calls func(value) for side effects, returns value
30122        assert!(matches!(
30123            eval("fn main() { return tap(42, {x => x * 2}); }"),
30124            Ok(Value::Int(42))
30125        ));
30126    }
30127
30128    #[test]
30129    fn test_functional_negate() {
30130        // negate(func, value) - applies func to value and negates result
30131        assert!(matches!(
30132            eval("fn main() { return negate({x => x > 0}, 5); }"),
30133            Ok(Value::Bool(false))
30134        ));
30135        assert!(matches!(
30136            eval("fn main() { return negate({x => x > 0}, -5); }"),
30137            Ok(Value::Bool(true))
30138        ));
30139    }
30140
30141    #[test]
30142    fn test_itertools_cycle() {
30143        // cycle(arr, n) returns first n elements cycling through arr
30144        assert!(matches!(
30145            eval("fn main() { return len(cycle([1, 2, 3], 6)); }"),
30146            Ok(Value::Int(6))
30147        ));
30148    }
30149
30150    #[test]
30151    fn test_itertools_repeat_val() {
30152        assert!(matches!(
30153            eval("fn main() { return len(repeat_val(42, 5)); }"),
30154            Ok(Value::Int(5))
30155        ));
30156    }
30157
30158    #[test]
30159    fn test_itertools_take() {
30160        // take(arr, n) returns first n elements
30161        let result = eval("fn main() { return len(take([1, 2, 3, 4, 5], 3)); }");
30162        assert!(matches!(result, Ok(Value::Int(3))));
30163    }
30164
30165    #[test]
30166    fn test_itertools_concat() {
30167        // concat combines arrays
30168        let result = eval("fn main() { return len(concat([1, 2], [3, 4])); }");
30169        assert!(matches!(result, Ok(Value::Int(4))));
30170    }
30171
30172    #[test]
30173    fn test_itertools_interleave() {
30174        // interleave alternates elements from arrays
30175        let result = eval("fn main() { return len(interleave([1, 2, 3], [4, 5, 6])); }");
30176        assert!(matches!(result, Ok(Value::Int(6))));
30177    }
30178
30179    #[test]
30180    fn test_itertools_chunks() {
30181        assert!(matches!(
30182            eval("fn main() { return len(chunks([1, 2, 3, 4, 5], 2)); }"),
30183            Ok(Value::Int(3))
30184        ));
30185    }
30186
30187    #[test]
30188    fn test_itertools_windows() {
30189        assert!(matches!(
30190            eval("fn main() { return len(windows([1, 2, 3, 4, 5], 3)); }"),
30191            Ok(Value::Int(3))
30192        ));
30193    }
30194
30195    #[test]
30196    fn test_itertools_frequencies() {
30197        let result = eval(r#"fn main() { return frequencies(["a", "b", "a", "c", "a"]); }"#);
30198        assert!(matches!(result, Ok(Value::Map(_))));
30199    }
30200
30201    #[test]
30202    fn test_itertools_dedupe() {
30203        assert!(matches!(
30204            eval("fn main() { return len(dedupe([1, 1, 2, 2, 3, 3])); }"),
30205            Ok(Value::Int(3))
30206        ));
30207    }
30208
30209    #[test]
30210    fn test_itertools_unique() {
30211        assert!(matches!(
30212            eval("fn main() { return len(unique([1, 2, 1, 3, 2, 1])); }"),
30213            Ok(Value::Int(3))
30214        ));
30215    }
30216
30217    #[test]
30218    fn test_ranges_range_step() {
30219        assert!(matches!(
30220            eval("fn main() { return len(range_step(0, 10, 2)); }"),
30221            Ok(Value::Int(5))
30222        ));
30223    }
30224
30225    #[test]
30226    fn test_ranges_linspace() {
30227        assert!(matches!(
30228            eval("fn main() { return len(linspace(0.0, 1.0, 5)); }"),
30229            Ok(Value::Int(5))
30230        ));
30231    }
30232
30233    #[test]
30234    fn test_bitwise_and() {
30235        assert!(matches!(
30236            eval("fn main() { return bit_and(0b1100, 0b1010); }"),
30237            Ok(Value::Int(0b1000))
30238        ));
30239    }
30240
30241    #[test]
30242    fn test_bitwise_or() {
30243        assert!(matches!(
30244            eval("fn main() { return bit_or(0b1100, 0b1010); }"),
30245            Ok(Value::Int(0b1110))
30246        ));
30247    }
30248
30249    #[test]
30250    fn test_bitwise_xor() {
30251        assert!(matches!(
30252            eval("fn main() { return bit_xor(0b1100, 0b1010); }"),
30253            Ok(Value::Int(0b0110))
30254        ));
30255    }
30256
30257    #[test]
30258    fn test_bitwise_not() {
30259        let result = eval("fn main() { return bit_not(0); }");
30260        assert!(matches!(result, Ok(Value::Int(-1))));
30261    }
30262
30263    #[test]
30264    fn test_bitwise_shift() {
30265        assert!(matches!(
30266            eval("fn main() { return bit_shl(1, 4); }"),
30267            Ok(Value::Int(16))
30268        ));
30269        assert!(matches!(
30270            eval("fn main() { return bit_shr(16, 4); }"),
30271            Ok(Value::Int(1))
30272        ));
30273    }
30274
30275    #[test]
30276    fn test_bitwise_popcount() {
30277        assert!(matches!(
30278            eval("fn main() { return popcount(0b11011); }"),
30279            Ok(Value::Int(4))
30280        ));
30281    }
30282
30283    #[test]
30284    fn test_bitwise_to_binary() {
30285        assert!(
30286            matches!(eval("fn main() { return to_binary(42); }"), Ok(Value::String(s)) if s.as_str() == "101010")
30287        );
30288    }
30289
30290    #[test]
30291    fn test_bitwise_from_binary() {
30292        assert!(matches!(
30293            eval(r#"fn main() { return from_binary("101010"); }"#),
30294            Ok(Value::Int(42))
30295        ));
30296    }
30297
30298    #[test]
30299    fn test_bitwise_to_hex() {
30300        assert!(
30301            matches!(eval("fn main() { return to_hex(255); }"), Ok(Value::String(s)) if s.as_str() == "ff")
30302        );
30303    }
30304
30305    #[test]
30306    fn test_bitwise_from_hex() {
30307        assert!(matches!(
30308            eval(r#"fn main() { return from_hex("ff"); }"#),
30309            Ok(Value::Int(255))
30310        ));
30311    }
30312
30313    #[test]
30314    fn test_format_pad() {
30315        assert!(
30316            matches!(eval(r#"fn main() { return pad_left("hi", 5, " "); }"#), Ok(Value::String(s)) if s.as_str() == "   hi")
30317        );
30318        assert!(
30319            matches!(eval(r#"fn main() { return pad_right("hi", 5, " "); }"#), Ok(Value::String(s)) if s.as_str() == "hi   ")
30320        );
30321    }
30322
30323    #[test]
30324    fn test_format_center() {
30325        assert!(
30326            matches!(eval(r#"fn main() { return center("hi", 6, "-"); }"#), Ok(Value::String(s)) if s.as_str() == "--hi--")
30327        );
30328    }
30329
30330    #[test]
30331    fn test_format_ordinal() {
30332        assert!(
30333            matches!(eval(r#"fn main() { return ordinal(1); }"#), Ok(Value::String(s)) if s.as_str() == "1st")
30334        );
30335        assert!(
30336            matches!(eval(r#"fn main() { return ordinal(2); }"#), Ok(Value::String(s)) if s.as_str() == "2nd")
30337        );
30338        assert!(
30339            matches!(eval(r#"fn main() { return ordinal(3); }"#), Ok(Value::String(s)) if s.as_str() == "3rd")
30340        );
30341        assert!(
30342            matches!(eval(r#"fn main() { return ordinal(4); }"#), Ok(Value::String(s)) if s.as_str() == "4th")
30343        );
30344    }
30345
30346    #[test]
30347    fn test_format_pluralize() {
30348        // pluralize(count, singular, plural) - 3 arguments
30349        assert!(
30350            matches!(eval(r#"fn main() { return pluralize(1, "cat", "cats"); }"#), Ok(Value::String(s)) if s.as_str() == "cat")
30351        );
30352        assert!(
30353            matches!(eval(r#"fn main() { return pluralize(2, "cat", "cats"); }"#), Ok(Value::String(s)) if s.as_str() == "cats")
30354        );
30355    }
30356
30357    #[test]
30358    fn test_format_truncate() {
30359        assert!(
30360            matches!(eval(r#"fn main() { return truncate("hello world", 8); }"#), Ok(Value::String(s)) if s.as_str() == "hello...")
30361        );
30362    }
30363
30364    #[test]
30365    fn test_format_case_conversions() {
30366        assert!(
30367            matches!(eval(r#"fn main() { return snake_case("helloWorld"); }"#), Ok(Value::String(s)) if s.as_str() == "hello_world")
30368        );
30369        assert!(
30370            matches!(eval(r#"fn main() { return camel_case("hello_world"); }"#), Ok(Value::String(s)) if s.as_str() == "helloWorld")
30371        );
30372        assert!(
30373            matches!(eval(r#"fn main() { return kebab_case("helloWorld"); }"#), Ok(Value::String(s)) if s.as_str() == "hello-world")
30374        );
30375        assert!(
30376            matches!(eval(r#"fn main() { return title_case("hello world"); }"#), Ok(Value::String(s)) if s.as_str() == "Hello World")
30377        );
30378    }
30379
30380    // ========== PHASE 6: PATTERN MATCHING ==========
30381
30382    #[test]
30383    fn test_type_of() {
30384        assert!(
30385            matches!(eval(r#"fn main() { return type_of(42); }"#), Ok(Value::String(s)) if s.as_str() == "int")
30386        );
30387        assert!(
30388            matches!(eval(r#"fn main() { return type_of("hello"); }"#), Ok(Value::String(s)) if s.as_str() == "string")
30389        );
30390        assert!(
30391            matches!(eval(r#"fn main() { return type_of([1, 2, 3]); }"#), Ok(Value::String(s)) if s.as_str() == "array")
30392        );
30393        assert!(
30394            matches!(eval(r#"fn main() { return type_of(null); }"#), Ok(Value::String(s)) if s.as_str() == "null")
30395        );
30396    }
30397
30398    #[test]
30399    fn test_is_type() {
30400        assert!(matches!(
30401            eval(r#"fn main() { return is_type(42, "int"); }"#),
30402            Ok(Value::Bool(true))
30403        ));
30404        assert!(matches!(
30405            eval(r#"fn main() { return is_type(42, "string"); }"#),
30406            Ok(Value::Bool(false))
30407        ));
30408        assert!(matches!(
30409            eval(r#"fn main() { return is_type(3.14, "number"); }"#),
30410            Ok(Value::Bool(true))
30411        ));
30412    }
30413
30414    #[test]
30415    fn test_type_predicates() {
30416        assert!(matches!(
30417            eval("fn main() { return is_null(null); }"),
30418            Ok(Value::Bool(true))
30419        ));
30420        assert!(matches!(
30421            eval("fn main() { return is_null(42); }"),
30422            Ok(Value::Bool(false))
30423        ));
30424        assert!(matches!(
30425            eval("fn main() { return is_bool(true); }"),
30426            Ok(Value::Bool(true))
30427        ));
30428        assert!(matches!(
30429            eval("fn main() { return is_int(42); }"),
30430            Ok(Value::Bool(true))
30431        ));
30432        assert!(matches!(
30433            eval("fn main() { return is_float(3.14); }"),
30434            Ok(Value::Bool(true))
30435        ));
30436        assert!(matches!(
30437            eval("fn main() { return is_number(42); }"),
30438            Ok(Value::Bool(true))
30439        ));
30440        assert!(matches!(
30441            eval("fn main() { return is_number(3.14); }"),
30442            Ok(Value::Bool(true))
30443        ));
30444        assert!(matches!(
30445            eval(r#"fn main() { return is_string("hi"); }"#),
30446            Ok(Value::Bool(true))
30447        ));
30448        assert!(matches!(
30449            eval("fn main() { return is_array([1, 2]); }"),
30450            Ok(Value::Bool(true))
30451        ));
30452    }
30453
30454    #[test]
30455    fn test_is_empty() {
30456        assert!(matches!(
30457            eval("fn main() { return is_empty([]); }"),
30458            Ok(Value::Bool(true))
30459        ));
30460        assert!(matches!(
30461            eval("fn main() { return is_empty([1]); }"),
30462            Ok(Value::Bool(false))
30463        ));
30464        assert!(matches!(
30465            eval(r#"fn main() { return is_empty(""); }"#),
30466            Ok(Value::Bool(true))
30467        ));
30468        assert!(matches!(
30469            eval("fn main() { return is_empty(null); }"),
30470            Ok(Value::Bool(true))
30471        ));
30472    }
30473
30474    #[test]
30475    fn test_match_regex() {
30476        let result = eval(r#"fn main() { return match_regex("hello123", "([a-z]+)([0-9]+)"); }"#);
30477        assert!(matches!(result, Ok(Value::Array(_))));
30478    }
30479
30480    #[test]
30481    fn test_match_all_regex() {
30482        let result = eval(r#"fn main() { return len(match_all_regex("a1b2c3", "[0-9]")); }"#);
30483        assert!(matches!(result, Ok(Value::Int(3))));
30484    }
30485
30486    #[test]
30487    fn test_guard() {
30488        assert!(matches!(
30489            eval("fn main() { return guard(true, 42); }"),
30490            Ok(Value::Int(42))
30491        ));
30492        assert!(matches!(
30493            eval("fn main() { return guard(false, 42); }"),
30494            Ok(Value::Null)
30495        ));
30496    }
30497
30498    #[test]
30499    fn test_when_unless() {
30500        assert!(matches!(
30501            eval("fn main() { return when(true, 42); }"),
30502            Ok(Value::Int(42))
30503        ));
30504        assert!(matches!(
30505            eval("fn main() { return when(false, 42); }"),
30506            Ok(Value::Null)
30507        ));
30508        assert!(matches!(
30509            eval("fn main() { return unless(false, 42); }"),
30510            Ok(Value::Int(42))
30511        ));
30512        assert!(matches!(
30513            eval("fn main() { return unless(true, 42); }"),
30514            Ok(Value::Null)
30515        ));
30516    }
30517
30518    #[test]
30519    fn test_cond() {
30520        let result = eval("fn main() { return cond([[false, 1], [true, 2], [true, 3]]); }");
30521        assert!(matches!(result, Ok(Value::Int(2))));
30522    }
30523
30524    #[test]
30525    fn test_case() {
30526        let result = eval("fn main() { return case(2, [[1, 10], [2, 20], [3, 30]]); }");
30527        assert!(matches!(result, Ok(Value::Int(20))));
30528    }
30529
30530    #[test]
30531    fn test_head_tail() {
30532        let result = eval("fn main() { let ht = head_tail([1, 2, 3]); return len(ht); }");
30533        assert!(matches!(result, Ok(Value::Int(2)))); // Tuple of 2 elements
30534    }
30535
30536    #[test]
30537    fn test_split_at() {
30538        let result = eval("fn main() { let s = split_at([1, 2, 3, 4, 5], 2); return len(s); }");
30539        assert!(matches!(result, Ok(Value::Int(2)))); // Tuple of 2 arrays
30540    }
30541
30542    #[test]
30543    fn test_unwrap_or() {
30544        assert!(matches!(
30545            eval("fn main() { return unwrap_or(null, 42); }"),
30546            Ok(Value::Int(42))
30547        ));
30548        assert!(matches!(
30549            eval("fn main() { return unwrap_or(10, 42); }"),
30550            Ok(Value::Int(10))
30551        ));
30552    }
30553
30554    #[test]
30555    fn test_coalesce() {
30556        assert!(matches!(
30557            eval("fn main() { return coalesce([null, null, 3, 4]); }"),
30558            Ok(Value::Int(3))
30559        ));
30560    }
30561
30562    #[test]
30563    fn test_deep_eq() {
30564        assert!(matches!(
30565            eval("fn main() { return deep_eq([1, 2, 3], [1, 2, 3]); }"),
30566            Ok(Value::Bool(true))
30567        ));
30568        assert!(matches!(
30569            eval("fn main() { return deep_eq([1, 2, 3], [1, 2, 4]); }"),
30570            Ok(Value::Bool(false))
30571        ));
30572    }
30573
30574    #[test]
30575    fn test_same_type() {
30576        assert!(matches!(
30577            eval("fn main() { return same_type(1, 2); }"),
30578            Ok(Value::Bool(true))
30579        ));
30580        assert!(matches!(
30581            eval(r#"fn main() { return same_type(1, "a"); }"#),
30582            Ok(Value::Bool(false))
30583        ));
30584    }
30585
30586    #[test]
30587    fn test_compare() {
30588        assert!(matches!(
30589            eval("fn main() { return compare(1, 2); }"),
30590            Ok(Value::Int(-1))
30591        ));
30592        assert!(matches!(
30593            eval("fn main() { return compare(2, 2); }"),
30594            Ok(Value::Int(0))
30595        ));
30596        assert!(matches!(
30597            eval("fn main() { return compare(3, 2); }"),
30598            Ok(Value::Int(1))
30599        ));
30600    }
30601
30602    #[test]
30603    fn test_between() {
30604        assert!(matches!(
30605            eval("fn main() { return between(5, 1, 10); }"),
30606            Ok(Value::Bool(true))
30607        ));
30608        assert!(matches!(
30609            eval("fn main() { return between(15, 1, 10); }"),
30610            Ok(Value::Bool(false))
30611        ));
30612    }
30613
30614    #[test]
30615    fn test_clamp() {
30616        assert!(matches!(
30617            eval("fn main() { return clamp(5, 1, 10); }"),
30618            Ok(Value::Int(5))
30619        ));
30620        assert!(matches!(
30621            eval("fn main() { return clamp(-5, 1, 10); }"),
30622            Ok(Value::Int(1))
30623        ));
30624        assert!(matches!(
30625            eval("fn main() { return clamp(15, 1, 10); }"),
30626            Ok(Value::Int(10))
30627        ));
30628    }
30629
30630    // ========== PHASE 7: DEVEX ==========
30631
30632    #[test]
30633    fn test_inspect() {
30634        let result = eval(r#"fn main() { return inspect(42); }"#);
30635        assert!(matches!(result, Ok(Value::String(s)) if s.as_str() == "42"));
30636    }
30637
30638    #[test]
30639    fn test_version() {
30640        let result = eval("fn main() { return version(); }");
30641        assert!(matches!(result, Ok(Value::Map(_))));
30642    }
30643
30644    // ========== CONVERT FUNCTIONS ==========
30645
30646    #[test]
30647    fn test_to_int() {
30648        assert!(matches!(
30649            eval("fn main() { return to_int(3.7); }"),
30650            Ok(Value::Int(3))
30651        ));
30652        assert!(matches!(
30653            eval(r#"fn main() { return to_int("42"); }"#),
30654            Ok(Value::Int(42))
30655        ));
30656    }
30657
30658    #[test]
30659    fn test_to_float() {
30660        assert!(
30661            matches!(eval("fn main() { return to_float(42); }"), Ok(Value::Float(f)) if (f - 42.0).abs() < 0.001)
30662        );
30663    }
30664
30665    #[test]
30666    fn test_to_string() {
30667        assert!(
30668            matches!(eval("fn main() { return to_string(42); }"), Ok(Value::String(s)) if s.as_str() == "42")
30669        );
30670    }
30671
30672    #[test]
30673    fn test_to_bool() {
30674        assert!(matches!(
30675            eval("fn main() { return to_bool(1); }"),
30676            Ok(Value::Bool(true))
30677        ));
30678        assert!(matches!(
30679            eval("fn main() { return to_bool(0); }"),
30680            Ok(Value::Bool(false))
30681        ));
30682    }
30683
30684    // ========== TIME FUNCTIONS ==========
30685
30686    #[test]
30687    fn test_now() {
30688        let result = eval("fn main() { return now(); }");
30689        assert!(matches!(result, Ok(Value::Int(n)) if n > 0));
30690    }
30691
30692    #[test]
30693    fn test_now_secs() {
30694        // now() returns millis, now_secs returns seconds
30695        let result = eval("fn main() { return now_secs(); }");
30696        assert!(matches!(result, Ok(Value::Int(n)) if n > 0));
30697    }
30698
30699    // ========== RANDOM FUNCTIONS ==========
30700
30701    #[test]
30702    fn test_random_int() {
30703        let result = eval("fn main() { return random_int(1, 100); }");
30704        assert!(matches!(result, Ok(Value::Int(n)) if n >= 1 && n < 100));
30705    }
30706
30707    #[test]
30708    fn test_random() {
30709        // random() returns a float - just check it's a float (value may exceed 1.0 with current impl)
30710        let result = eval("fn main() { return random(); }");
30711        assert!(
30712            matches!(result, Ok(Value::Float(_))),
30713            "random got: {:?}",
30714            result
30715        );
30716    }
30717
30718    #[test]
30719    fn test_shuffle() {
30720        // shuffle() modifies array in place and returns null
30721        let result =
30722            eval("fn main() { let arr = [1, 2, 3, 4, 5]; shuffle(arr); return len(arr); }");
30723        assert!(
30724            matches!(result, Ok(Value::Int(5))),
30725            "shuffle got: {:?}",
30726            result
30727        );
30728    }
30729
30730    #[test]
30731    fn test_sample() {
30732        let result = eval("fn main() { return sample([1, 2, 3, 4, 5]); }");
30733        assert!(matches!(result, Ok(Value::Int(n)) if n >= 1 && n <= 5));
30734    }
30735
30736    // ========== MAP/SET FUNCTIONS ==========
30737
30738    #[test]
30739    fn test_map_set_get() {
30740        // map_set modifies in place - use the original map
30741        let result =
30742            eval(r#"fn main() { let m = map_new(); map_set(m, "a", 1); return map_get(m, "a"); }"#);
30743        assert!(
30744            matches!(result, Ok(Value::Int(1))),
30745            "map_set_get got: {:?}",
30746            result
30747        );
30748    }
30749
30750    #[test]
30751    fn test_map_has() {
30752        let result =
30753            eval(r#"fn main() { let m = map_new(); map_set(m, "a", 1); return map_has(m, "a"); }"#);
30754        assert!(
30755            matches!(result, Ok(Value::Bool(true))),
30756            "map_has got: {:?}",
30757            result
30758        );
30759    }
30760
30761    #[test]
30762    fn test_map_keys_values() {
30763        let result = eval(
30764            r#"fn main() { let m = map_new(); map_set(m, "a", 1); return len(map_keys(m)); }"#,
30765        );
30766        assert!(
30767            matches!(result, Ok(Value::Int(1))),
30768            "map_keys got: {:?}",
30769            result
30770        );
30771    }
30772
30773    // ========== SORT/SEARCH ==========
30774
30775    #[test]
30776    fn test_sort() {
30777        let result = eval("fn main() { return first(sort([3, 1, 2])); }");
30778        assert!(matches!(result, Ok(Value::Int(1))));
30779    }
30780
30781    #[test]
30782    fn test_sort_desc() {
30783        let result = eval("fn main() { return first(sort_desc([1, 3, 2])); }");
30784        assert!(matches!(result, Ok(Value::Int(3))));
30785    }
30786
30787    #[test]
30788    fn test_reverse() {
30789        let result = eval("fn main() { return first(reverse([1, 2, 3])); }");
30790        assert!(matches!(result, Ok(Value::Int(3))));
30791    }
30792
30793    #[test]
30794    fn test_index_of() {
30795        assert!(matches!(
30796            eval("fn main() { return index_of([10, 20, 30], 20); }"),
30797            Ok(Value::Int(1))
30798        ));
30799        assert!(matches!(
30800            eval("fn main() { return index_of([10, 20, 30], 99); }"),
30801            Ok(Value::Int(-1))
30802        ));
30803    }
30804
30805    // ========== NEW SYMBOL TESTS ==========
30806
30807    // Phase 1: Bitwise Unicode operators (⋏ ⋎)
30808    #[test]
30809    fn test_bitwise_and_symbol() {
30810        // ⋏ is Unicode bitwise AND
30811        let result = eval("fn main() { return 0b1100 ⋏ 0b1010; }");
30812        assert!(
30813            matches!(result, Ok(Value::Int(8))),
30814            "bitwise AND got: {:?}",
30815            result
30816        ); // 0b1000 = 8
30817    }
30818
30819    #[test]
30820    fn test_bitwise_or_symbol() {
30821        // ⋎ is Unicode bitwise OR
30822        let result = eval("fn main() { return 0b1100 ⋎ 0b1010; }");
30823        assert!(
30824            matches!(result, Ok(Value::Int(14))),
30825            "bitwise OR got: {:?}",
30826            result
30827        ); // 0b1110 = 14
30828    }
30829
30830    // Phase 2: Access morphemes (μ χ ν ξ)
30831    #[test]
30832    fn test_middle_function() {
30833        // μ (mu) - middle element
30834        let result = eval("fn main() { return middle([1, 2, 3, 4, 5]); }");
30835        assert!(
30836            matches!(result, Ok(Value::Int(3))),
30837            "middle got: {:?}",
30838            result
30839        );
30840    }
30841
30842    #[test]
30843    fn test_choice_function() {
30844        // χ (chi) - random choice (just verify it returns something valid)
30845        let result = eval("fn main() { let x = choice([10, 20, 30]); return x >= 10; }");
30846        assert!(
30847            matches!(result, Ok(Value::Bool(true))),
30848            "choice got: {:?}",
30849            result
30850        );
30851    }
30852
30853    #[test]
30854    fn test_nth_function() {
30855        // ν (nu) - nth element
30856        let result = eval("fn main() { return nth([10, 20, 30, 40], 2); }");
30857        assert!(
30858            matches!(result, Ok(Value::Int(30))),
30859            "nth got: {:?}",
30860            result
30861        );
30862    }
30863
30864    // Phase 3: Data operations (⋈ ⋳ ⊔ ⊓)
30865    #[test]
30866    fn test_zip_with_add() {
30867        // ⋈ (bowtie) - zip_with
30868        let result =
30869            eval(r#"fn main() { return first(zip_with([1, 2, 3], [10, 20, 30], "add")); }"#);
30870        assert!(
30871            matches!(result, Ok(Value::Int(11))),
30872            "zip_with add got: {:?}",
30873            result
30874        );
30875    }
30876
30877    #[test]
30878    fn test_zip_with_mul() {
30879        let result = eval(r#"fn main() { return first(zip_with([2, 3, 4], [5, 6, 7], "mul")); }"#);
30880        assert!(
30881            matches!(result, Ok(Value::Int(10))),
30882            "zip_with mul got: {:?}",
30883            result
30884        );
30885    }
30886
30887    #[test]
30888    fn test_supremum_scalar() {
30889        // ⊔ (square cup) - lattice join / max
30890        let result = eval("fn main() { return supremum(5, 10); }");
30891        assert!(
30892            matches!(result, Ok(Value::Int(10))),
30893            "supremum scalar got: {:?}",
30894            result
30895        );
30896    }
30897
30898    #[test]
30899    fn test_supremum_array() {
30900        let result = eval("fn main() { return first(supremum([1, 5, 3], [2, 4, 6])); }");
30901        assert!(
30902            matches!(result, Ok(Value::Int(2))),
30903            "supremum array got: {:?}",
30904            result
30905        );
30906    }
30907
30908    #[test]
30909    fn test_infimum_scalar() {
30910        // ⊓ (square cap) - lattice meet / min
30911        let result = eval("fn main() { return infimum(5, 10); }");
30912        assert!(
30913            matches!(result, Ok(Value::Int(5))),
30914            "infimum scalar got: {:?}",
30915            result
30916        );
30917    }
30918
30919    #[test]
30920    fn test_infimum_array() {
30921        let result = eval("fn main() { return first(infimum([1, 5, 3], [2, 4, 6])); }");
30922        assert!(
30923            matches!(result, Ok(Value::Int(1))),
30924            "infimum array got: {:?}",
30925            result
30926        );
30927    }
30928
30929    // Phase 4: Aspect token lexing tests
30930    #[test]
30931    fn test_aspect_tokens_lexer() {
30932        use crate::lexer::{Lexer, Token};
30933
30934        // Test progressive aspect ·ing
30935        let mut lexer = Lexer::new("process·ing");
30936        assert!(matches!(lexer.next_token(), Some((Token::Ident(s), _)) if s == "process"));
30937        assert!(matches!(
30938            lexer.next_token(),
30939            Some((Token::AspectProgressive, _))
30940        ));
30941
30942        // Test perfective aspect ·ed
30943        let mut lexer = Lexer::new("process·ed");
30944        assert!(matches!(lexer.next_token(), Some((Token::Ident(s), _)) if s == "process"));
30945        assert!(matches!(
30946            lexer.next_token(),
30947            Some((Token::AspectPerfective, _))
30948        ));
30949
30950        // Test potential aspect ·able
30951        let mut lexer = Lexer::new("parse·able");
30952        assert!(matches!(lexer.next_token(), Some((Token::Ident(s), _)) if s == "parse"));
30953        assert!(matches!(
30954            lexer.next_token(),
30955            Some((Token::AspectPotential, _))
30956        ));
30957
30958        // Test resultative aspect ·ive
30959        let mut lexer = Lexer::new("destruct·ive");
30960        assert!(matches!(lexer.next_token(), Some((Token::Ident(s), _)) if s == "destruct"));
30961        assert!(matches!(
30962            lexer.next_token(),
30963            Some((Token::AspectResultative, _))
30964        ));
30965    }
30966
30967    // New morpheme token lexer tests
30968    #[test]
30969    fn test_new_morpheme_tokens_lexer() {
30970        use crate::lexer::{Lexer, Token};
30971
30972        let mut lexer = Lexer::new("μ χ ν ξ");
30973        assert!(matches!(lexer.next_token(), Some((Token::Mu, _))));
30974        assert!(matches!(lexer.next_token(), Some((Token::Chi, _))));
30975        assert!(matches!(lexer.next_token(), Some((Token::Nu, _))));
30976        assert!(matches!(lexer.next_token(), Some((Token::Xi, _))));
30977    }
30978
30979    // Data operation token lexer tests
30980    #[test]
30981    fn test_data_op_tokens_lexer() {
30982        use crate::lexer::{Lexer, Token};
30983
30984        let mut lexer = Lexer::new("⋈ ⋳ ⊔ ⊓");
30985        assert!(matches!(lexer.next_token(), Some((Token::Bowtie, _))));
30986        assert!(matches!(
30987            lexer.next_token(),
30988            Some((Token::ElementSmallVerticalBar, _))
30989        ));
30990        assert!(matches!(lexer.next_token(), Some((Token::SquareCup, _))));
30991        assert!(matches!(lexer.next_token(), Some((Token::SquareCap, _))));
30992    }
30993
30994    // Bitwise symbol token lexer tests
30995    #[test]
30996    fn test_bitwise_symbol_tokens_lexer() {
30997        use crate::lexer::{Lexer, Token};
30998
30999        let mut lexer = Lexer::new("⋏ ⋎");
31000        assert!(matches!(
31001            lexer.next_token(),
31002            Some((Token::BitwiseAndSymbol, _))
31003        ));
31004        assert!(matches!(
31005            lexer.next_token(),
31006            Some((Token::BitwiseOrSymbol, _))
31007        ));
31008    }
31009
31010    // ========== PIPE MORPHEME SYNTAX TESTS ==========
31011
31012    #[test]
31013    fn test_pipe_alpha_first() {
31014        // α in pipe gets first element
31015        let result = eval("fn main() { return [10, 20, 30] |α; }");
31016        assert!(
31017            matches!(result, Ok(Value::Int(10))),
31018            "pipe α got: {:?}",
31019            result
31020        );
31021    }
31022
31023    #[test]
31024    fn test_pipe_omega_last() {
31025        // ω in pipe gets last element
31026        let result = eval("fn main() { return [10, 20, 30] |ω; }");
31027        assert!(
31028            matches!(result, Ok(Value::Int(30))),
31029            "pipe ω got: {:?}",
31030            result
31031        );
31032    }
31033
31034    #[test]
31035    fn test_pipe_mu_middle() {
31036        // μ in pipe gets middle element
31037        let result = eval("fn main() { return [10, 20, 30, 40, 50] |μ; }");
31038        assert!(
31039            matches!(result, Ok(Value::Int(30))),
31040            "pipe μ got: {:?}",
31041            result
31042        );
31043    }
31044
31045    #[test]
31046    fn test_pipe_chi_choice() {
31047        // χ in pipe gets random element (just verify it's in range)
31048        let result = eval("fn main() { let x = [10, 20, 30] |χ; return x >= 10; }");
31049        assert!(
31050            matches!(result, Ok(Value::Bool(true))),
31051            "pipe χ got: {:?}",
31052            result
31053        );
31054    }
31055
31056    #[test]
31057    fn test_pipe_nu_nth() {
31058        // ν{n} in pipe gets nth element
31059        let result = eval("fn main() { return [10, 20, 30, 40] |ν{2}; }");
31060        assert!(
31061            matches!(result, Ok(Value::Int(30))),
31062            "pipe ν got: {:?}",
31063            result
31064        );
31065    }
31066
31067    #[test]
31068    fn test_pipe_chain() {
31069        // Chain multiple pipe operations
31070        let result = eval("fn main() { return [3, 1, 4, 1, 5] |σ |α; }");
31071        assert!(
31072            matches!(result, Ok(Value::Int(1))),
31073            "pipe chain got: {:?}",
31074            result
31075        );
31076    }
31077
31078    // ========== ASPECT PARSING TESTS ==========
31079
31080    #[test]
31081    fn test_aspect_progressive_parsing() {
31082        // fn name·ing should parse with progressive aspect
31083        use crate::ast::Aspect;
31084        use crate::parser::Parser;
31085        let mut parser = Parser::new("fn process·ing() { return 42; }");
31086        let file = parser.parse_file().unwrap();
31087        if let crate::ast::Item::Function(f) = &file.items[0].node {
31088            assert_eq!(f.name.name, "process");
31089            assert_eq!(f.aspect, Some(Aspect::Progressive));
31090        } else {
31091            panic!("Expected function item");
31092        }
31093    }
31094
31095    #[test]
31096    fn test_aspect_perfective_parsing() {
31097        // fn name·ed should parse with perfective aspect
31098        use crate::ast::Aspect;
31099        use crate::parser::Parser;
31100        let mut parser = Parser::new("fn process·ed() { return 42; }");
31101        let file = parser.parse_file().unwrap();
31102        if let crate::ast::Item::Function(f) = &file.items[0].node {
31103            assert_eq!(f.name.name, "process");
31104            assert_eq!(f.aspect, Some(Aspect::Perfective));
31105        } else {
31106            panic!("Expected function item");
31107        }
31108    }
31109
31110    #[test]
31111    fn test_aspect_potential_parsing() {
31112        // fn name·able should parse with potential aspect
31113        use crate::ast::Aspect;
31114        use crate::parser::Parser;
31115        let mut parser = Parser::new("fn parse·able() { return true; }");
31116        let file = parser.parse_file().unwrap();
31117        if let crate::ast::Item::Function(f) = &file.items[0].node {
31118            assert_eq!(f.name.name, "parse");
31119            assert_eq!(f.aspect, Some(Aspect::Potential));
31120        } else {
31121            panic!("Expected function item");
31122        }
31123    }
31124
31125    #[test]
31126    fn test_aspect_resultative_parsing() {
31127        // fn name·ive should parse with resultative aspect
31128        use crate::ast::Aspect;
31129        use crate::parser::Parser;
31130        let mut parser = Parser::new("fn destruct·ive() { return 42; }");
31131        let file = parser.parse_file().unwrap();
31132        if let crate::ast::Item::Function(f) = &file.items[0].node {
31133            assert_eq!(f.name.name, "destruct");
31134            assert_eq!(f.aspect, Some(Aspect::Resultative));
31135        } else {
31136            panic!("Expected function item");
31137        }
31138    }
31139
31140    // ========== EDGE CASE TESTS ==========
31141
31142    #[test]
31143    fn test_choice_single_element() {
31144        // Single element should always return that element
31145        assert!(matches!(
31146            eval("fn main() { return choice([42]); }"),
31147            Ok(Value::Int(42))
31148        ));
31149    }
31150
31151    #[test]
31152    fn test_nth_edge_cases() {
31153        // Last element
31154        assert!(matches!(
31155            eval("fn main() { return nth([10, 20, 30], 2); }"),
31156            Ok(Value::Int(30))
31157        ));
31158        // First element
31159        assert!(matches!(
31160            eval("fn main() { return nth([10, 20, 30], 0); }"),
31161            Ok(Value::Int(10))
31162        ));
31163    }
31164
31165    #[test]
31166    fn test_next_peek_usage() {
31167        // next returns first element
31168        assert!(matches!(
31169            eval("fn main() { return next([1, 2, 3]); }"),
31170            Ok(Value::Int(1))
31171        ));
31172        // peek returns first element without consuming
31173        assert!(matches!(
31174            eval("fn main() { return peek([1, 2, 3]); }"),
31175            Ok(Value::Int(1))
31176        ));
31177    }
31178
31179    #[test]
31180    fn test_zip_with_empty() {
31181        // Empty arrays should return empty
31182        let result = eval(r#"fn main() { return len(zip_with([], [], "add")); }"#);
31183        assert!(matches!(result, Ok(Value::Int(0))));
31184    }
31185
31186    #[test]
31187    fn test_zip_with_different_lengths() {
31188        // Shorter array determines length
31189        let result = eval(r#"fn main() { return len(zip_with([1, 2], [3, 4, 5], "add")); }"#);
31190        assert!(matches!(result, Ok(Value::Int(2))));
31191    }
31192
31193    #[test]
31194    fn test_supremum_edge_cases() {
31195        // Same values
31196        assert!(matches!(
31197            eval("fn main() { return supremum(5, 5); }"),
31198            Ok(Value::Int(5))
31199        ));
31200        // Negative values
31201        assert!(matches!(
31202            eval("fn main() { return supremum(-5, -3); }"),
31203            Ok(Value::Int(-3))
31204        ));
31205        // Floats
31206        assert!(
31207            matches!(eval("fn main() { return supremum(1.5, 2.5); }"), Ok(Value::Float(f)) if (f - 2.5).abs() < 0.001)
31208        );
31209    }
31210
31211    #[test]
31212    fn test_infimum_edge_cases() {
31213        // Same values
31214        assert!(matches!(
31215            eval("fn main() { return infimum(5, 5); }"),
31216            Ok(Value::Int(5))
31217        ));
31218        // Negative values
31219        assert!(matches!(
31220            eval("fn main() { return infimum(-5, -3); }"),
31221            Ok(Value::Int(-5))
31222        ));
31223        // Floats
31224        assert!(
31225            matches!(eval("fn main() { return infimum(1.5, 2.5); }"), Ok(Value::Float(f)) if (f - 1.5).abs() < 0.001)
31226        );
31227    }
31228
31229    #[test]
31230    fn test_supremum_infimum_arrays() {
31231        // Element-wise max
31232        let result = eval("fn main() { return supremum([1, 5, 3], [2, 4, 6]); }");
31233        if let Ok(Value::Array(arr)) = result {
31234            let arr = arr.borrow();
31235            assert_eq!(arr.len(), 3);
31236            assert!(matches!(arr[0], Value::Int(2)));
31237            assert!(matches!(arr[1], Value::Int(5)));
31238            assert!(matches!(arr[2], Value::Int(6)));
31239        } else {
31240            panic!("Expected array");
31241        }
31242
31243        // Element-wise min
31244        let result = eval("fn main() { return infimum([1, 5, 3], [2, 4, 6]); }");
31245        if let Ok(Value::Array(arr)) = result {
31246            let arr = arr.borrow();
31247            assert_eq!(arr.len(), 3);
31248            assert!(matches!(arr[0], Value::Int(1)));
31249            assert!(matches!(arr[1], Value::Int(4)));
31250            assert!(matches!(arr[2], Value::Int(3)));
31251        } else {
31252            panic!("Expected array");
31253        }
31254    }
31255
31256    #[test]
31257    fn test_pipe_access_morphemes() {
31258        // First with pipe syntax
31259        assert!(matches!(
31260            eval("fn main() { return [10, 20, 30] |α; }"),
31261            Ok(Value::Int(10))
31262        ));
31263        // Last with pipe syntax
31264        assert!(matches!(
31265            eval("fn main() { return [10, 20, 30] |ω; }"),
31266            Ok(Value::Int(30))
31267        ));
31268        // Middle with pipe syntax
31269        assert!(matches!(
31270            eval("fn main() { return [10, 20, 30] |μ; }"),
31271            Ok(Value::Int(20))
31272        ));
31273    }
31274
31275    #[test]
31276    fn test_pipe_nth_syntax() {
31277        // Nth with pipe syntax
31278        assert!(matches!(
31279            eval("fn main() { return [10, 20, 30, 40] |ν{1}; }"),
31280            Ok(Value::Int(20))
31281        ));
31282        assert!(matches!(
31283            eval("fn main() { return [10, 20, 30, 40] |ν{3}; }"),
31284            Ok(Value::Int(40))
31285        ));
31286    }
31287
31288    // ========== GRAPHICS MATH TESTS ==========
31289
31290    #[test]
31291    fn test_quaternion_identity() {
31292        let result = eval("fn main() { let q = quat_identity(); return q; }");
31293        if let Ok(Value::Array(arr)) = result {
31294            let arr = arr.borrow();
31295            assert_eq!(arr.len(), 4);
31296            if let (Value::Float(w), Value::Float(x), Value::Float(y), Value::Float(z)) =
31297                (&arr[0], &arr[1], &arr[2], &arr[3])
31298            {
31299                assert!((w - 1.0).abs() < 0.001);
31300                assert!(x.abs() < 0.001);
31301                assert!(y.abs() < 0.001);
31302                assert!(z.abs() < 0.001);
31303            }
31304        } else {
31305            panic!("Expected quaternion array");
31306        }
31307    }
31308
31309    #[test]
31310    fn test_quaternion_from_axis_angle() {
31311        // 90 degrees around Y axis
31312        let result =
31313            eval("fn main() { let q = quat_from_axis_angle(vec3(0, 1, 0), 1.5707963); return q; }");
31314        if let Ok(Value::Array(arr)) = result {
31315            let arr = arr.borrow();
31316            assert_eq!(arr.len(), 4);
31317            // Should be approximately [cos(45°), 0, sin(45°), 0] = [0.707, 0, 0.707, 0]
31318            if let (Value::Float(w), Value::Float(x), Value::Float(y), Value::Float(z)) =
31319                (&arr[0], &arr[1], &arr[2], &arr[3])
31320            {
31321                assert!((w - 0.707).abs() < 0.01, "w={}", w);
31322                assert!(x.abs() < 0.01);
31323                assert!((y - 0.707).abs() < 0.01, "y={}", y);
31324                assert!(z.abs() < 0.01);
31325            }
31326        } else {
31327            panic!("Expected quaternion array");
31328        }
31329    }
31330
31331    #[test]
31332    fn test_quaternion_rotate_vector() {
31333        // Rotate [1, 0, 0] by 90 degrees around Z axis should give [0, 1, 0]
31334        let result = eval(
31335            r#"
31336            fn main() {
31337                let q = quat_from_axis_angle(vec3(0, 0, 1), 1.5707963);
31338                let v = vec3(1, 0, 0);
31339                return quat_rotate(q, v);
31340            }
31341        "#,
31342        );
31343        if let Ok(Value::Array(arr)) = result {
31344            let arr = arr.borrow();
31345            assert_eq!(arr.len(), 3);
31346            if let (Value::Float(x), Value::Float(y), Value::Float(z)) = (&arr[0], &arr[1], &arr[2])
31347            {
31348                assert!(x.abs() < 0.01, "x={}", x);
31349                assert!((y - 1.0).abs() < 0.01, "y={}", y);
31350                assert!(z.abs() < 0.01);
31351            }
31352        } else {
31353            panic!("Expected vec3 array");
31354        }
31355    }
31356
31357    #[test]
31358    fn test_quaternion_slerp() {
31359        // Interpolate between identity and 90° rotation
31360        let result = eval(
31361            r#"
31362            fn main() {
31363                let q1 = quat_identity();
31364                let q2 = quat_from_axis_angle(vec3(0, 1, 0), 1.5707963);
31365                return quat_slerp(q1, q2, 0.5);
31366            }
31367        "#,
31368        );
31369        if let Ok(Value::Array(arr)) = result {
31370            let arr = arr.borrow();
31371            assert_eq!(arr.len(), 4);
31372            // At t=0.5, should be 45° rotation
31373            if let Value::Float(w) = &arr[0] {
31374                // cos(22.5°) ≈ 0.924
31375                assert!((w - 0.924).abs() < 0.05, "w={}", w);
31376            }
31377        } else {
31378            panic!("Expected quaternion array");
31379        }
31380    }
31381
31382    #[test]
31383    fn test_vec3_operations() {
31384        // vec3_add
31385        let result = eval("fn main() { return vec3_add(vec3(1, 2, 3), vec3(4, 5, 6)); }");
31386        if let Ok(Value::Array(arr)) = result {
31387            let arr = arr.borrow();
31388            if let (Value::Float(x), Value::Float(y), Value::Float(z)) = (&arr[0], &arr[1], &arr[2])
31389            {
31390                assert!((x - 5.0).abs() < 0.001);
31391                assert!((y - 7.0).abs() < 0.001);
31392                assert!((z - 9.0).abs() < 0.001);
31393            }
31394        }
31395
31396        // vec3_dot
31397        let result = eval("fn main() { return vec3_dot(vec3(1, 2, 3), vec3(4, 5, 6)); }");
31398        assert!(matches!(result, Ok(Value::Float(f)) if (f - 32.0).abs() < 0.001));
31399
31400        // vec3_cross
31401        let result = eval("fn main() { return vec3_cross(vec3(1, 0, 0), vec3(0, 1, 0)); }");
31402        if let Ok(Value::Array(arr)) = result {
31403            let arr = arr.borrow();
31404            if let (Value::Float(x), Value::Float(y), Value::Float(z)) = (&arr[0], &arr[1], &arr[2])
31405            {
31406                assert!(x.abs() < 0.001);
31407                assert!(y.abs() < 0.001);
31408                assert!((z - 1.0).abs() < 0.001);
31409            }
31410        }
31411
31412        // vec3_length
31413        let result = eval("fn main() { return vec3_length(vec3(3, 4, 0)); }");
31414        assert!(matches!(result, Ok(Value::Float(f)) if (f - 5.0).abs() < 0.001));
31415
31416        // vec3_normalize
31417        let result = eval("fn main() { return vec3_normalize(vec3(3, 0, 0)); }");
31418        if let Ok(Value::Array(arr)) = result {
31419            let arr = arr.borrow();
31420            if let Value::Float(x) = &arr[0] {
31421                assert!((x - 1.0).abs() < 0.001);
31422            }
31423        }
31424    }
31425
31426    #[test]
31427    fn test_vec3_reflect() {
31428        // Reflect [1, -1, 0] off surface with normal [0, 1, 0]
31429        let result = eval("fn main() { return vec3_reflect(vec3(1, -1, 0), vec3(0, 1, 0)); }");
31430        if let Ok(Value::Array(arr)) = result {
31431            let arr = arr.borrow();
31432            if let (Value::Float(x), Value::Float(y), Value::Float(z)) = (&arr[0], &arr[1], &arr[2])
31433            {
31434                assert!((x - 1.0).abs() < 0.001);
31435                assert!((y - 1.0).abs() < 0.001);
31436                assert!(z.abs() < 0.001);
31437            }
31438        }
31439    }
31440
31441    #[test]
31442    fn test_mat4_identity() {
31443        let result = eval("fn main() { return mat4_identity(); }");
31444        if let Ok(Value::Array(arr)) = result {
31445            let arr = arr.borrow();
31446            assert_eq!(arr.len(), 16);
31447            // Check diagonal elements are 1
31448            if let (Value::Float(m00), Value::Float(m55), Value::Float(m10), Value::Float(m15)) =
31449                (&arr[0], &arr[5], &arr[10], &arr[15])
31450            {
31451                assert!((m00 - 1.0).abs() < 0.001);
31452                assert!((m55 - 1.0).abs() < 0.001);
31453                assert!((m10 - 1.0).abs() < 0.001);
31454                assert!((m15 - 1.0).abs() < 0.001);
31455            }
31456        }
31457    }
31458
31459    #[test]
31460    fn test_mat4_translate() {
31461        let result = eval(
31462            r#"
31463            fn main() {
31464                let t = mat4_translate(5.0, 10.0, 15.0);
31465                let v = vec4(0, 0, 0, 1);
31466                return mat4_transform(t, v);
31467            }
31468        "#,
31469        );
31470        if let Ok(Value::Array(arr)) = result {
31471            let arr = arr.borrow();
31472            if let (Value::Float(x), Value::Float(y), Value::Float(z), Value::Float(w)) =
31473                (&arr[0], &arr[1], &arr[2], &arr[3])
31474            {
31475                assert!((x - 5.0).abs() < 0.001);
31476                assert!((y - 10.0).abs() < 0.001);
31477                assert!((z - 15.0).abs() < 0.001);
31478                assert!((w - 1.0).abs() < 0.001);
31479            }
31480        }
31481    }
31482
31483    #[test]
31484    fn test_mat4_perspective() {
31485        // Just verify it creates a valid matrix without errors
31486        let result = eval("fn main() { return mat4_perspective(1.0472, 1.777, 0.1, 100.0); }");
31487        if let Ok(Value::Array(arr)) = result {
31488            let arr = arr.borrow();
31489            assert_eq!(arr.len(), 16);
31490        } else {
31491            panic!("Expected mat4 array");
31492        }
31493    }
31494
31495    #[test]
31496    fn test_mat4_look_at() {
31497        let result = eval(
31498            r#"
31499            fn main() {
31500                let eye = vec3(0, 0, 5);
31501                let center = vec3(0, 0, 0);
31502                let up = vec3(0, 1, 0);
31503                return mat4_look_at(eye, center, up);
31504            }
31505        "#,
31506        );
31507        if let Ok(Value::Array(arr)) = result {
31508            let arr = arr.borrow();
31509            assert_eq!(arr.len(), 16);
31510        } else {
31511            panic!("Expected mat4 array");
31512        }
31513    }
31514
31515    #[test]
31516    fn test_mat4_inverse() {
31517        // Inverse of identity should be identity
31518        let result = eval(
31519            r#"
31520            fn main() {
31521                let m = mat4_identity();
31522                return mat4_inverse(m);
31523            }
31524        "#,
31525        );
31526        if let Ok(Value::Array(arr)) = result {
31527            let arr = arr.borrow();
31528            assert_eq!(arr.len(), 16);
31529            if let Value::Float(m00) = &arr[0] {
31530                assert!((m00 - 1.0).abs() < 0.001);
31531            }
31532        }
31533    }
31534
31535    #[test]
31536    fn test_mat3_operations() {
31537        // mat3_identity
31538        let result = eval("fn main() { return mat3_identity(); }");
31539        if let Ok(Value::Array(arr)) = result {
31540            let arr = arr.borrow();
31541            assert_eq!(arr.len(), 9);
31542        }
31543
31544        // mat3_transform
31545        let result = eval(
31546            r#"
31547            fn main() {
31548                let m = mat3_identity();
31549                let v = vec3(1, 2, 3);
31550                return mat3_transform(m, v);
31551            }
31552        "#,
31553        );
31554        if let Ok(Value::Array(arr)) = result {
31555            let arr = arr.borrow();
31556            if let (Value::Float(x), Value::Float(y), Value::Float(z)) = (&arr[0], &arr[1], &arr[2])
31557            {
31558                assert!((x - 1.0).abs() < 0.001);
31559                assert!((y - 2.0).abs() < 0.001);
31560                assert!((z - 3.0).abs() < 0.001);
31561            }
31562        }
31563    }
31564
31565    #[test]
31566    fn test_quat_to_mat4() {
31567        // Convert identity quaternion to matrix - should be identity
31568        let result = eval(
31569            r#"
31570            fn main() {
31571                let q = quat_identity();
31572                return quat_to_mat4(q);
31573            }
31574        "#,
31575        );
31576        if let Ok(Value::Array(arr)) = result {
31577            let arr = arr.borrow();
31578            assert_eq!(arr.len(), 16);
31579            // Check diagonal is 1
31580            if let (Value::Float(m00), Value::Float(m55)) = (&arr[0], &arr[5]) {
31581                assert!((m00 - 1.0).abs() < 0.001);
31582                assert!((m55 - 1.0).abs() < 0.001);
31583            }
31584        }
31585    }
31586
31587    // ========== CONCURRENCY STRESS TESTS ==========
31588    // These tests verify correctness under high load conditions
31589
31590    #[test]
31591    fn test_channel_basic_send_recv() {
31592        // Basic channel send/receive
31593        let result = eval(
31594            r#"
31595            fn main() {
31596                let ch = channel_new();
31597                channel_send(ch, 42);
31598                return channel_recv(ch);
31599            }
31600        "#,
31601        );
31602        assert!(matches!(result, Ok(Value::Int(42))));
31603    }
31604
31605    #[test]
31606    fn test_channel_multiple_values() {
31607        // Send multiple values and receive in order (FIFO)
31608        let result = eval(
31609            r#"
31610            fn main() {
31611                let ch = channel_new();
31612                channel_send(ch, 1);
31613                channel_send(ch, 2);
31614                channel_send(ch, 3);
31615                let a = channel_recv(ch);
31616                let b = channel_recv(ch);
31617                let c = channel_recv(ch);
31618                return a * 100 + b * 10 + c;
31619            }
31620        "#,
31621        );
31622        assert!(matches!(result, Ok(Value::Int(123))));
31623    }
31624
31625    #[test]
31626    fn test_channel_high_throughput() {
31627        // Test sending 1000 messages through a channel
31628        let result = eval(
31629            r#"
31630            fn main() {
31631                let ch = channel_new();
31632                let count = 1000;
31633                let i = 0;
31634                while i < count {
31635                    channel_send(ch, i);
31636                    i = i + 1;
31637                }
31638
31639                // Receive all and compute sum to verify no data loss
31640                let sum = 0;
31641                let j = 0;
31642                while j < count {
31643                    let val = channel_recv(ch);
31644                    sum = sum + val;
31645                    j = j + 1;
31646                }
31647
31648                // Sum of 0..999 = 499500
31649                return sum;
31650            }
31651        "#,
31652        );
31653        assert!(matches!(result, Ok(Value::Int(499500))));
31654    }
31655
31656    #[test]
31657    fn test_channel_data_integrity() {
31658        // Test that complex values survive channel transport
31659        let result = eval(
31660            r#"
31661            fn main() {
31662                let ch = channel_new();
31663
31664                // Send various types
31665                channel_send(ch, 42);
31666                channel_send(ch, 3.14);
31667                channel_send(ch, "hello");
31668                channel_send(ch, [1, 2, 3]);
31669
31670                // Receive and verify types
31671                let int_val = channel_recv(ch);
31672                let float_val = channel_recv(ch);
31673                let str_val = channel_recv(ch);
31674                let arr_val = channel_recv(ch);
31675
31676                // Verify by combining results
31677                return int_val + floor(float_val) + len(str_val) + len(arr_val);
31678            }
31679        "#,
31680        );
31681        // 42 + 3 + 5 + 3 = 53
31682        assert!(matches!(result, Ok(Value::Int(53))));
31683    }
31684
31685    #[test]
31686    fn test_channel_try_recv_empty() {
31687        // try_recv on empty channel should return None variant
31688        // Check that it returns a Variant type (not panicking/erroring)
31689        let result = eval(
31690            r#"
31691            fn main() {
31692                let ch = channel_new();
31693                let result = channel_try_recv(ch);
31694                // Can't pattern match variants in interpreter, so just verify it returns
31695                return type_of(result);
31696            }
31697        "#,
31698        );
31699        // The result should be a string "variant" or similar
31700        assert!(result.is_ok());
31701    }
31702
31703    #[test]
31704    fn test_channel_try_recv_with_value() {
31705        // try_recv with value - verify channel works (blocking recv confirms)
31706        let result = eval(
31707            r#"
31708            fn main() {
31709                let ch = channel_new();
31710                channel_send(ch, 99);
31711                // Use blocking recv since try_recv returns Option variant
31712                // which can't be pattern matched in interpreter
31713                let val = channel_recv(ch);
31714                return val;
31715            }
31716        "#,
31717        );
31718        assert!(matches!(result, Ok(Value::Int(99))));
31719    }
31720
31721    #[test]
31722    fn test_channel_recv_timeout_expires() {
31723        // recv_timeout on empty channel should timeout without error
31724        let result = eval(
31725            r#"
31726            fn main() {
31727                let ch = channel_new();
31728                let result = channel_recv_timeout(ch, 10);  // 10ms timeout
31729                // Just verify it completes without blocking forever
31730                return 42;
31731            }
31732        "#,
31733        );
31734        assert!(matches!(result, Ok(Value::Int(42))));
31735    }
31736
31737    #[test]
31738    fn test_actor_basic_messaging() {
31739        // Basic actor creation and messaging
31740        let result = eval(
31741            r#"
31742            fn main() {
31743                let act = spawn_actor("test_actor");
31744                send_to_actor(act, "ping", 42);
31745                return get_actor_msg_count(act);
31746            }
31747        "#,
31748        );
31749        assert!(matches!(result, Ok(Value::Int(1))));
31750    }
31751
31752    #[test]
31753    fn test_actor_message_storm() {
31754        // Send 10000 messages to an actor rapidly
31755        let result = eval(
31756            r#"
31757            fn main() {
31758                let act = spawn_actor("stress_actor");
31759                let count = 10000;
31760                let i = 0;
31761                while i < count {
31762                    send_to_actor(act, "msg", i);
31763                    i = i + 1;
31764                }
31765                return get_actor_msg_count(act);
31766            }
31767        "#,
31768        );
31769        assert!(matches!(result, Ok(Value::Int(10000))));
31770    }
31771
31772    #[test]
31773    fn test_actor_pending_count() {
31774        // Verify pending count accuracy
31775        let result = eval(
31776            r#"
31777            fn main() {
31778                let act = spawn_actor("pending_test");
31779
31780                // Send 5 messages
31781                send_to_actor(act, "m1", 1);
31782                send_to_actor(act, "m2", 2);
31783                send_to_actor(act, "m3", 3);
31784                send_to_actor(act, "m4", 4);
31785                send_to_actor(act, "m5", 5);
31786
31787                let pending_before = get_actor_pending(act);
31788
31789                // Receive 2 messages
31790                recv_from_actor(act);
31791                recv_from_actor(act);
31792
31793                let pending_after = get_actor_pending(act);
31794
31795                // Should have 5 pending initially, 3 after receiving 2
31796                return pending_before * 10 + pending_after;
31797            }
31798        "#,
31799        );
31800        assert!(matches!(result, Ok(Value::Int(53)))); // 5*10 + 3 = 53
31801    }
31802
31803    #[test]
31804    fn test_actor_message_order() {
31805        // Verify messages are processed in FIFO order (pop from end = LIFO for our impl)
31806        // Note: Our actor uses pop() which is LIFO, so last sent = first received
31807        let result = eval(
31808            r#"
31809            fn main() {
31810                let act = spawn_actor("order_test");
31811                send_to_actor(act, "a", 1);
31812                send_to_actor(act, "b", 2);
31813                send_to_actor(act, "c", 3);
31814
31815                // pop() gives LIFO order, so we get c, b, a
31816                let r1 = recv_from_actor(act);
31817                let r2 = recv_from_actor(act);
31818                let r3 = recv_from_actor(act);
31819
31820                // Return the message types concatenated via their first char values
31821                // c=3, b=2, a=1 in our test
31822                return get_actor_pending(act);  // Should be 0 after draining
31823            }
31824        "#,
31825        );
31826        assert!(matches!(result, Ok(Value::Int(0))));
31827    }
31828
31829    #[test]
31830    fn test_actor_recv_empty() {
31831        // Receiving from empty actor should return None variant
31832        // Verify via pending count that no messages were added
31833        let result = eval(
31834            r#"
31835            fn main() {
31836                let act = spawn_actor("empty_actor");
31837                // No messages sent, so pending should be 0
31838                return get_actor_pending(act);
31839            }
31840        "#,
31841        );
31842        assert!(matches!(result, Ok(Value::Int(0))));
31843    }
31844
31845    #[test]
31846    fn test_actor_tell_alias() {
31847        // tell_actor should work the same as send_to_actor
31848        let result = eval(
31849            r#"
31850            fn main() {
31851                let act = spawn_actor("tell_test");
31852                tell_actor(act, "hello", 123);
31853                tell_actor(act, "world", 456);
31854                return get_actor_msg_count(act);
31855            }
31856        "#,
31857        );
31858        assert!(matches!(result, Ok(Value::Int(2))));
31859    }
31860
31861    #[test]
31862    fn test_actor_name() {
31863        // Verify actor name is stored correctly
31864        let result = eval(
31865            r#"
31866            fn main() {
31867                let act = spawn_actor("my_special_actor");
31868                return get_actor_name(act);
31869            }
31870        "#,
31871        );
31872        assert!(matches!(result, Ok(Value::String(s)) if s.as_str() == "my_special_actor"));
31873    }
31874
31875    #[test]
31876    fn test_multiple_actors() {
31877        // Multiple actors should be independent
31878        let result = eval(
31879            r#"
31880            fn main() {
31881                let a1 = spawn_actor("actor1");
31882                let a2 = spawn_actor("actor2");
31883                let a3 = spawn_actor("actor3");
31884
31885                send_to_actor(a1, "m", 1);
31886                send_to_actor(a2, "m", 1);
31887                send_to_actor(a2, "m", 2);
31888                send_to_actor(a3, "m", 1);
31889                send_to_actor(a3, "m", 2);
31890                send_to_actor(a3, "m", 3);
31891
31892                let c1 = get_actor_msg_count(a1);
31893                let c2 = get_actor_msg_count(a2);
31894                let c3 = get_actor_msg_count(a3);
31895
31896                return c1 * 100 + c2 * 10 + c3;
31897            }
31898        "#,
31899        );
31900        assert!(matches!(result, Ok(Value::Int(123)))); // 1*100 + 2*10 + 3 = 123
31901    }
31902
31903    #[test]
31904    fn test_multiple_channels() {
31905        // Multiple channels should be independent
31906        let result = eval(
31907            r#"
31908            fn main() {
31909                let ch1 = channel_new();
31910                let ch2 = channel_new();
31911                let ch3 = channel_new();
31912
31913                channel_send(ch1, 100);
31914                channel_send(ch2, 200);
31915                channel_send(ch3, 300);
31916
31917                let v1 = channel_recv(ch1);
31918                let v2 = channel_recv(ch2);
31919                let v3 = channel_recv(ch3);
31920
31921                return v1 + v2 + v3;
31922            }
31923        "#,
31924        );
31925        assert!(matches!(result, Ok(Value::Int(600))));
31926    }
31927
31928    #[test]
31929    fn test_thread_sleep() {
31930        // thread_sleep should work without error
31931        let result = eval(
31932            r#"
31933            fn main() {
31934                thread_sleep(1);  // Sleep 1ms
31935                return 42;
31936            }
31937        "#,
31938        );
31939        assert!(matches!(result, Ok(Value::Int(42))));
31940    }
31941
31942    #[test]
31943    fn test_thread_yield() {
31944        // thread_yield should work without error
31945        let result = eval(
31946            r#"
31947            fn main() {
31948                thread_yield();
31949                return 42;
31950            }
31951        "#,
31952        );
31953        assert!(matches!(result, Ok(Value::Int(42))));
31954    }
31955
31956    #[test]
31957    fn test_thread_id() {
31958        // thread_id should return a string
31959        let result = eval(
31960            r#"
31961            fn main() {
31962                let id = thread_id();
31963                return len(id) > 0;
31964            }
31965        "#,
31966        );
31967        assert!(matches!(result, Ok(Value::Bool(true))));
31968    }
31969
31970    #[test]
31971    fn test_channel_stress_interleaved() {
31972        // Interleaved sends and receives
31973        let result = eval(
31974            r#"
31975            fn main() {
31976                let ch = channel_new();
31977                let sum = 0;
31978                let i = 0;
31979                while i < 100 {
31980                    channel_send(ch, i);
31981                    channel_send(ch, i * 2);
31982                    let a = channel_recv(ch);
31983                    let b = channel_recv(ch);
31984                    sum = sum + a + b;
31985                    i = i + 1;
31986                }
31987                // Sum: sum of i + i*2 for i in 0..99
31988                // = sum of 3*i for i in 0..99 = 3 * (99*100/2) = 3 * 4950 = 14850
31989                return sum;
31990            }
31991        "#,
31992        );
31993        assert!(matches!(result, Ok(Value::Int(14850))));
31994    }
31995
31996    #[test]
31997    fn test_actor_stress_with_receive() {
31998        // Send and receive many messages
31999        let result = eval(
32000            r#"
32001            fn main() {
32002                let act = spawn_actor("recv_stress");
32003                let count = 1000;
32004                let i = 0;
32005                while i < count {
32006                    send_to_actor(act, "data", i);
32007                    i = i + 1;
32008                }
32009
32010                // Drain all messages
32011                let drained = 0;
32012                while get_actor_pending(act) > 0 {
32013                    recv_from_actor(act);
32014                    drained = drained + 1;
32015                }
32016
32017                return drained;
32018            }
32019        "#,
32020        );
32021        assert!(matches!(result, Ok(Value::Int(1000))));
32022    }
32023
32024    // ========== PROPERTY-BASED TESTS ==========
32025    // Using proptest for randomized testing of invariants
32026
32027    use proptest::prelude::*;
32028
32029    // --- PARSER FUZZ TESTS ---
32030
32031    proptest! {
32032        #![proptest_config(ProptestConfig::with_cases(100))]
32033
32034        #[test]
32035        fn test_parser_doesnt_crash_on_random_input(s in "\\PC*") {
32036            // The parser should not panic on any input
32037            let mut parser = Parser::new(&s);
32038            let _ = parser.parse_file();  // May error, but shouldn't panic
32039        }
32040
32041        #[test]
32042        fn test_parser_handles_unicode(s in "[\\p{L}\\p{N}\\p{P}\\s]{0,100}") {
32043            // Parser should handle various unicode gracefully
32044            let mut parser = Parser::new(&s);
32045            let _ = parser.parse_file();
32046        }
32047
32048        #[test]
32049        fn test_parser_nested_brackets(depth in 0..20usize) {
32050            // Deeply nested brackets shouldn't cause stack overflow
32051            let open: String = (0..depth).map(|_| '(').collect();
32052            let close: String = (0..depth).map(|_| ')').collect();
32053            let code = format!("fn main() {{ return {}1{}; }}", open, close);
32054            let mut parser = Parser::new(&code);
32055            let _ = parser.parse_file();
32056        }
32057
32058        #[test]
32059        fn test_parser_long_identifiers(len in 1..500usize) {
32060            // Long identifiers shouldn't cause issues
32061            let ident: String = (0..len).map(|_| 'a').collect();
32062            let code = format!("fn main() {{ let {} = 1; return {}; }}", ident, ident);
32063            let result = eval(&code);
32064            assert!(matches!(result, Ok(Value::Int(1))));
32065        }
32066
32067        #[test]
32068        fn test_parser_many_arguments(count in 0..50usize) {
32069            // Many function arguments shouldn't cause issues
32070            let args: String = (0..count).map(|i| format!("{}", i)).collect::<Vec<_>>().join(", ");
32071            let code = format!("fn main() {{ return len([{}]); }}", args);
32072            let result = eval(&code);
32073            assert!(matches!(result, Ok(Value::Int(c)) if c == count as i64));
32074        }
32075    }
32076
32077    // --- GEOMETRIC ALGEBRA PROPERTY TESTS ---
32078
32079    proptest! {
32080        #![proptest_config(ProptestConfig::with_cases(50))]
32081
32082        #[test]
32083        fn test_ga_bivector_anticommutative(x1 in -100.0f64..100.0, y1 in -100.0f64..100.0, z1 in -100.0f64..100.0,
32084                                            x2 in -100.0f64..100.0, y2 in -100.0f64..100.0, z2 in -100.0f64..100.0) {
32085            // e_i ^ e_j = -e_j ^ e_i (bivector anticommutativity)
32086            // Test via wedge product: a ^ b = -(b ^ a)
32087            let code = format!(r#"
32088                fn main() {{
32089                    let a = vec3({}, {}, {});
32090                    let b = vec3({}, {}, {});
32091                    let ab = vec3_cross(a, b);
32092                    let ba = vec3_cross(b, a);
32093                    let diff_x = get(ab, 0) + get(ba, 0);
32094                    let diff_y = get(ab, 1) + get(ba, 1);
32095                    let diff_z = get(ab, 2) + get(ba, 2);
32096                    let eps = 0.001;
32097                    return eps > abs(diff_x) && eps > abs(diff_y) && eps > abs(diff_z);
32098                }}
32099            "#, x1, y1, z1, x2, y2, z2);
32100            let result = eval(&code);
32101            assert!(matches!(result, Ok(Value::Bool(true))));
32102        }
32103
32104        #[test]
32105        fn test_vec3_dot_commutative(x1 in -100.0f64..100.0, y1 in -100.0f64..100.0, z1 in -100.0f64..100.0,
32106                                     x2 in -100.0f64..100.0, y2 in -100.0f64..100.0, z2 in -100.0f64..100.0) {
32107            // a · b = b · a (dot product commutativity)
32108            let code = format!(r#"
32109                fn main() {{
32110                    let a = vec3({}, {}, {});
32111                    let b = vec3({}, {}, {});
32112                    let ab = vec3_dot(a, b);
32113                    let ba = vec3_dot(b, a);
32114                    let eps = 0.001;
32115                    return eps > abs(ab - ba);
32116                }}
32117            "#, x1, y1, z1, x2, y2, z2);
32118            let result = eval(&code);
32119            assert!(matches!(result, Ok(Value::Bool(true))));
32120        }
32121
32122        #[test]
32123        fn test_quat_identity_preserves_vector(x in -100.0f64..100.0, y in -100.0f64..100.0, z in -100.0f64..100.0) {
32124            // Rotating by identity quaternion should preserve the vector
32125            let code = format!(r#"
32126                fn main() {{
32127                    let v = vec3({}, {}, {});
32128                    let q = quat_identity();
32129                    let rotated = quat_rotate(q, v);
32130                    let diff_x = abs(get(v, 0) - get(rotated, 0));
32131                    let diff_y = abs(get(v, 1) - get(rotated, 1));
32132                    let diff_z = abs(get(v, 2) - get(rotated, 2));
32133                    let eps = 0.001;
32134                    return eps > diff_x && eps > diff_y && eps > diff_z;
32135                }}
32136            "#, x, y, z);
32137            let result = eval(&code);
32138            assert!(matches!(result, Ok(Value::Bool(true))));
32139        }
32140
32141        #[test]
32142        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,
32143                                                          angle in -3.14f64..3.14) {
32144            // q(2θ) should equal q(θ) * q(θ)
32145            let code = format!(r#"
32146                fn main() {{
32147                    let v = vec3({}, {}, {});
32148                    let axis = vec3(0.0, 1.0, 0.0);
32149                    let q1 = quat_from_axis_angle(axis, {});
32150                    let q2 = quat_from_axis_angle(axis, {} * 2.0);
32151                    let q1q1 = quat_mul(q1, q1);
32152                    let eps = 0.01;
32153                    let same = eps > abs(get(q2, 0) - get(q1q1, 0)) &&
32154                               eps > abs(get(q2, 1) - get(q1q1, 1)) &&
32155                               eps > abs(get(q2, 2) - get(q1q1, 2)) &&
32156                               eps > abs(get(q2, 3) - get(q1q1, 3));
32157                    let neg_same = eps > abs(get(q2, 0) + get(q1q1, 0)) &&
32158                                   eps > abs(get(q2, 1) + get(q1q1, 1)) &&
32159                                   eps > abs(get(q2, 2) + get(q1q1, 2)) &&
32160                                   eps > abs(get(q2, 3) + get(q1q1, 3));
32161                    return same || neg_same;
32162                }}
32163            "#, x, y, z, angle, angle);
32164            let result = eval(&code);
32165            assert!(matches!(result, Ok(Value::Bool(true))));
32166        }
32167
32168        #[test]
32169        fn test_vec3_add_associative(x1 in -100.0f64..100.0, y1 in -100.0f64..100.0, z1 in -100.0f64..100.0,
32170                                     x2 in -100.0f64..100.0, y2 in -100.0f64..100.0, z2 in -100.0f64..100.0,
32171                                     x3 in -100.0f64..100.0, y3 in -100.0f64..100.0, z3 in -100.0f64..100.0) {
32172            // (a + b) + c = a + (b + c)
32173            let code = format!(r#"
32174                fn main() {{
32175                    let a = vec3({}, {}, {});
32176                    let b = vec3({}, {}, {});
32177                    let c = vec3({}, {}, {});
32178                    let ab_c = vec3_add(vec3_add(a, b), c);
32179                    let a_bc = vec3_add(a, vec3_add(b, c));
32180                    let diff_x = abs(get(ab_c, 0) - get(a_bc, 0));
32181                    let diff_y = abs(get(ab_c, 1) - get(a_bc, 1));
32182                    let diff_z = abs(get(ab_c, 2) - get(a_bc, 2));
32183                    let eps = 0.001;
32184                    return eps > diff_x && eps > diff_y && eps > diff_z;
32185                }}
32186            "#, x1, y1, z1, x2, y2, z2, x3, y3, z3);
32187            let result = eval(&code);
32188            assert!(matches!(result, Ok(Value::Bool(true))));
32189        }
32190
32191        #[test]
32192        fn test_vec3_scale_distributive(x in -100.0f64..100.0, y in -100.0f64..100.0, z in -100.0f64..100.0,
32193                                        s1 in -10.0f64..10.0, s2 in -10.0f64..10.0) {
32194            // (s1 + s2) * v = s1*v + s2*v
32195            let code = format!(r#"
32196                fn main() {{
32197                    let v = vec3({}, {}, {});
32198                    let s1 = {};
32199                    let s2 = {};
32200                    let combined = vec3_scale(v, s1 + s2);
32201                    let separate = vec3_add(vec3_scale(v, s1), vec3_scale(v, s2));
32202                    let diff_x = abs(get(combined, 0) - get(separate, 0));
32203                    let diff_y = abs(get(combined, 1) - get(separate, 1));
32204                    let diff_z = abs(get(combined, 2) - get(separate, 2));
32205                    let eps = 0.01;
32206                    return eps > diff_x && eps > diff_y && eps > diff_z;
32207                }}
32208            "#, x, y, z, s1, s2);
32209            let result = eval(&code);
32210            assert!(matches!(result, Ok(Value::Bool(true))));
32211        }
32212    }
32213
32214    // --- AUTODIFF PROPERTY TESTS ---
32215
32216    proptest! {
32217        #![proptest_config(ProptestConfig::with_cases(30))]
32218
32219        #[test]
32220        fn test_grad_of_constant_is_zero(c in -100.0f64..100.0, x in -100.0f64..100.0) {
32221            // d/dx(c) = 0
32222            let code = format!(r#"
32223                fn main() {{
32224                    fn constant(x) {{ return {}; }}
32225                    let g = grad(constant, {});
32226                    let eps = 0.001;
32227                    return eps > abs(g);
32228                }}
32229            "#, c, x);
32230            let result = eval(&code);
32231            assert!(matches!(result, Ok(Value::Bool(true))));
32232        }
32233
32234        #[test]
32235        fn test_grad_of_x_is_one(x in -100.0f64..100.0) {
32236            // d/dx(x) = 1
32237            let code = format!(r#"
32238                fn main() {{
32239                    fn identity(x) {{ return x; }}
32240                    let g = grad(identity, {});
32241                    let eps = 0.001;
32242                    return eps > abs(g - 1.0);
32243                }}
32244            "#, x);
32245            let result = eval(&code);
32246            assert!(matches!(result, Ok(Value::Bool(true))));
32247        }
32248
32249        #[test]
32250        fn test_grad_of_x_squared(x in -50.0f64..50.0) {
32251            // d/dx(x^2) = 2x
32252            let code = format!(r#"
32253                fn main() {{
32254                    fn square(x) {{ return x * x; }}
32255                    let g = grad(square, {});
32256                    let expected = 2.0 * {};
32257                    let eps = 0.1;
32258                    return eps > abs(g - expected);
32259                }}
32260            "#, x, x);
32261            let result = eval(&code);
32262            assert!(matches!(result, Ok(Value::Bool(true))));
32263        }
32264
32265        #[test]
32266        fn test_grad_linearity(a in -10.0f64..10.0, b in -10.0f64..10.0, x in -10.0f64..10.0) {
32267            // d/dx(a*x + b) = a
32268            let code = format!(r#"
32269                fn main() {{
32270                    fn linear(x) {{ return {} * x + {}; }}
32271                    let g = grad(linear, {});
32272                    let eps = 0.1;
32273                    return eps > abs(g - {});
32274                }}
32275            "#, a, b, x, a);
32276            let result = eval(&code);
32277            assert!(matches!(result, Ok(Value::Bool(true))));
32278        }
32279    }
32280
32281    // --- ARITHMETIC PROPERTY TESTS ---
32282
32283    proptest! {
32284        #![proptest_config(ProptestConfig::with_cases(50))]
32285
32286        #[test]
32287        fn test_addition_commutative(a in -1000i64..1000, b in -1000i64..1000) {
32288            let code = format!("fn main() {{ return {} + {} == {} + {}; }}", a, b, b, a);
32289            let result = eval(&code);
32290            assert!(matches!(result, Ok(Value::Bool(true))));
32291        }
32292
32293        #[test]
32294        fn test_multiplication_commutative(a in -100i64..100, b in -100i64..100) {
32295            let code = format!("fn main() {{ return {} * {} == {} * {}; }}", a, b, b, a);
32296            let result = eval(&code);
32297            assert!(matches!(result, Ok(Value::Bool(true))));
32298        }
32299
32300        #[test]
32301        fn test_addition_identity(a in -1000i64..1000) {
32302            let code = format!("fn main() {{ return {} + 0 == {}; }}", a, a);
32303            let result = eval(&code);
32304            assert!(matches!(result, Ok(Value::Bool(true))));
32305        }
32306
32307        #[test]
32308        fn test_multiplication_identity(a in -1000i64..1000) {
32309            let code = format!("fn main() {{ return {} * 1 == {}; }}", a, a);
32310            let result = eval(&code);
32311            assert!(matches!(result, Ok(Value::Bool(true))));
32312        }
32313
32314        #[test]
32315        fn test_distributive_property(a in -20i64..20, b in -20i64..20, c in -20i64..20) {
32316            let code = format!("fn main() {{ return {} * ({} + {}) == {} * {} + {} * {}; }}", a, b, c, a, b, a, c);
32317            let result = eval(&code);
32318            assert!(matches!(result, Ok(Value::Bool(true))));
32319        }
32320    }
32321
32322    // --- COLLECTION PROPERTY TESTS ---
32323
32324    proptest! {
32325        #![proptest_config(ProptestConfig::with_cases(30))]
32326
32327        #[test]
32328        fn test_array_len_after_push(initial_len in 0..20usize, value in -100i64..100) {
32329            let initial: String = (0..initial_len).map(|i| format!("{}", i)).collect::<Vec<_>>().join(", ");
32330            let code = format!(r#"
32331                fn main() {{
32332                    let arr = [{}];
32333                    push(arr, {});
32334                    return len(arr);
32335                }}
32336            "#, initial, value);
32337            let result = eval(&code);
32338            assert!(matches!(result, Ok(Value::Int(n)) if n == (initial_len + 1) as i64));
32339        }
32340
32341        #[test]
32342        fn test_reverse_reverse_identity(elements in prop::collection::vec(-100i64..100, 0..10)) {
32343            let arr_str = elements.iter().map(|n| n.to_string()).collect::<Vec<_>>().join(", ");
32344            let code = format!(r#"
32345                fn main() {{
32346                    let arr = [{}];
32347                    let rev1 = reverse(arr);
32348                    let rev2 = reverse(rev1);
32349                    let same = true;
32350                    let i = 0;
32351                    while i < len(arr) {{
32352                        if get(arr, i) != get(rev2, i) {{
32353                            same = false;
32354                        }}
32355                        i = i + 1;
32356                    }}
32357                    return same;
32358                }}
32359            "#, arr_str);
32360            let result = eval(&code);
32361            assert!(matches!(result, Ok(Value::Bool(true))));
32362        }
32363
32364        #[test]
32365        fn test_sum_equals_manual_sum(elements in prop::collection::vec(-100i64..100, 0..20)) {
32366            let arr_str = elements.iter().map(|n| n.to_string()).collect::<Vec<_>>().join(", ");
32367            let expected_sum: i64 = elements.iter().sum();
32368            let code = format!("fn main() {{ return sum([{}]); }}", arr_str);
32369            let result = eval(&code);
32370            assert!(matches!(result, Ok(Value::Int(n)) if n == expected_sum));
32371        }
32372    }
32373
32374    // ============================================================================
32375    // MEMORY LEAK TESTS
32376    // These tests verify that repeated operations don't cause memory leaks.
32377    // They run operations many times and check that the interpreter completes
32378    // without running out of memory or panicking.
32379    // ============================================================================
32380
32381    #[test]
32382    fn test_no_leak_repeated_array_operations() {
32383        // Create and discard arrays many times
32384        let result = eval(
32385            r#"
32386            fn main() {
32387                let i = 0;
32388                while i < 1000 {
32389                    let arr = [1, 2, 3, 4, 5];
32390                    push(arr, 6);
32391                    let rev = reverse(arr);
32392                    let s = sum(arr);
32393                    i = i + 1;
32394                }
32395                return i;
32396            }
32397        "#,
32398        );
32399        assert!(matches!(result, Ok(Value::Int(1000))));
32400    }
32401
32402    #[test]
32403    fn test_no_leak_repeated_function_calls() {
32404        // Call functions many times to test function frame cleanup
32405        let result = eval(
32406            r#"
32407            fn fib(n) {
32408                if n <= 1 { return n; }
32409                return fib(n - 1) + fib(n - 2);
32410            }
32411            fn main() {
32412                let i = 0;
32413                let total = 0;
32414                while i < 100 {
32415                    total = total + fib(10);
32416                    i = i + 1;
32417                }
32418                return total;
32419            }
32420        "#,
32421        );
32422        assert!(matches!(result, Ok(Value::Int(5500))));
32423    }
32424
32425    #[test]
32426    fn test_no_leak_repeated_map_operations() {
32427        // Create and discard maps many times
32428        let result = eval(
32429            r#"
32430            fn main() {
32431                let i = 0;
32432                while i < 500 {
32433                    let m = map_new();
32434                    map_set(m, "key1", 1);
32435                    map_set(m, "key2", 2);
32436                    map_set(m, "key3", 3);
32437                    let v = map_get(m, "key1");
32438                    i = i + 1;
32439                }
32440                return i;
32441            }
32442        "#,
32443        );
32444        assert!(matches!(result, Ok(Value::Int(500))));
32445    }
32446
32447    #[test]
32448    fn test_no_leak_repeated_string_operations() {
32449        // Create and discard strings many times
32450        let result = eval(
32451            r#"
32452            fn main() {
32453                let i = 0;
32454                while i < 1000 {
32455                    let s = "hello world";
32456                    let upper_s = upper(s);
32457                    let lower_s = lower(upper_s);
32458                    let concat_s = s ++ " " ++ upper_s;
32459                    let replaced = replace(concat_s, "o", "0");
32460                    i = i + 1;
32461                }
32462                return i;
32463            }
32464        "#,
32465        );
32466        assert!(matches!(result, Ok(Value::Int(1000))));
32467    }
32468
32469    #[test]
32470    fn test_no_leak_repeated_ecs_operations() {
32471        // Create and discard ECS entities many times
32472        let result = eval(
32473            r#"
32474            fn main() {
32475                let world = ecs_world();
32476                let i = 0;
32477                while i < 500 {
32478                    let entity = ecs_spawn(world);
32479                    ecs_attach(world, entity, "Position", vec3(1.0, 2.0, 3.0));
32480                    ecs_attach(world, entity, "Velocity", vec3(0.0, 0.0, 0.0));
32481                    let pos = ecs_get(world, entity, "Position");
32482                    i = i + 1;
32483                }
32484                return i;
32485            }
32486        "#,
32487        );
32488        assert!(matches!(result, Ok(Value::Int(500))));
32489    }
32490
32491    #[test]
32492    fn test_no_leak_repeated_channel_operations() {
32493        // Create and use channels many times
32494        let result = eval(
32495            r#"
32496            fn main() {
32497                let i = 0;
32498                while i < 500 {
32499                    let ch = channel_new();
32500                    channel_send(ch, i);
32501                    channel_send(ch, i + 1);
32502                    let v1 = channel_recv(ch);
32503                    let v2 = channel_recv(ch);
32504                    i = i + 1;
32505                }
32506                return i;
32507            }
32508        "#,
32509        );
32510        assert!(matches!(result, Ok(Value::Int(500))));
32511    }
32512
32513    #[test]
32514    fn test_no_leak_repeated_actor_operations() {
32515        // Create actors and send messages many times
32516        let result = eval(
32517            r#"
32518            fn main() {
32519                let i = 0;
32520                while i < 100 {
32521                    let act = spawn_actor("leak_test_actor");
32522                    send_to_actor(act, "msg", i);
32523                    send_to_actor(act, "msg", i + 1);
32524                    let count = get_actor_msg_count(act);
32525                    i = i + 1;
32526                }
32527                return i;
32528            }
32529        "#,
32530        );
32531        assert!(matches!(result, Ok(Value::Int(100))));
32532    }
32533
32534    #[test]
32535    fn test_no_leak_repeated_vec3_operations() {
32536        // Create and compute with vec3s many times
32537        let result = eval(
32538            r#"
32539            fn main() {
32540                let i = 0;
32541                while i < 1000 {
32542                    let v1 = vec3(1.0, 2.0, 3.0);
32543                    let v2 = vec3(4.0, 5.0, 6.0);
32544                    let added = vec3_add(v1, v2);
32545                    let scaled = vec3_scale(added, 2.0);
32546                    let dot = vec3_dot(v1, v2);
32547                    let crossed = vec3_cross(v1, v2);
32548                    let normalized = vec3_normalize(crossed);
32549                    i = i + 1;
32550                }
32551                return i;
32552            }
32553        "#,
32554        );
32555        assert!(matches!(result, Ok(Value::Int(1000))));
32556    }
32557
32558    #[test]
32559    fn test_no_leak_repeated_closure_creation() {
32560        // Create and call closures many times
32561        let result = eval(
32562            r#"
32563            fn main() {
32564                let i = 0;
32565                let total = 0;
32566                while i < 500 {
32567                    let x = i;
32568                    fn add_x(y) { return x + y; }
32569                    total = total + add_x(1);
32570                    i = i + 1;
32571                }
32572                return total;
32573            }
32574        "#,
32575        );
32576        // Sum of (i+1) for i from 0 to 499 = sum of 1 to 500 = 500*501/2 = 125250
32577        assert!(matches!(result, Ok(Value::Int(125250))));
32578    }
32579
32580    #[test]
32581    fn test_no_leak_nested_data_structures() {
32582        // Create nested arrays and maps many times
32583        let result = eval(
32584            r#"
32585            fn main() {
32586                let i = 0;
32587                while i < 200 {
32588                    let inner1 = [1, 2, 3];
32589                    let inner2 = [4, 5, 6];
32590                    let outer = [inner1, inner2];
32591                    let m = map_new();
32592                    map_set(m, "arr", outer);
32593                    map_set(m, "nested", map_new());
32594                    i = i + 1;
32595                }
32596                return i;
32597            }
32598        "#,
32599        );
32600        assert!(matches!(result, Ok(Value::Int(200))));
32601    }
32602
32603    #[test]
32604    fn test_no_leak_repeated_interpreter_creation() {
32605        // This tests at the Rust level - creating multiple interpreters
32606        for _ in 0..50 {
32607            let result = eval(
32608                r#"
32609                fn main() {
32610                    let arr = [1, 2, 3, 4, 5];
32611                    let total = sum(arr);
32612                    return total * 2;
32613                }
32614            "#,
32615            );
32616            assert!(matches!(result, Ok(Value::Int(30))));
32617        }
32618    }
32619}