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        };
393        Ok(Value::String(Rc::new(type_name.to_string())))
394    });
395
396    // assert - assertion with optional message
397    define(interp, "assert", None, |_, args| {
398        if args.is_empty() {
399            return Err(RuntimeError::new("assert() requires at least one argument"));
400        }
401        let condition = match &args[0] {
402            Value::Bool(b) => *b,
403            _ => return Err(RuntimeError::new("assert() condition must be bool")),
404        };
405        if !condition {
406            let msg = if args.len() > 1 {
407                format!("{}", args[1])
408            } else {
409                "assertion failed".to_string()
410            };
411            return Err(RuntimeError::new(format!("Assertion failed: {}", msg)));
412        }
413        Ok(Value::Null)
414    });
415
416    // panic - abort execution with message
417    define(interp, "panic", None, |_, args| {
418        let msg = if args.is_empty() {
419            "explicit panic".to_string()
420        } else {
421            args.iter()
422                .map(|v| format!("{}", v))
423                .collect::<Vec<_>>()
424                .join(" ")
425        };
426        Err(RuntimeError::new(format!("PANIC: {}", msg)))
427    });
428
429    // todo - mark unimplemented code
430    define(interp, "todo", None, |_, args| {
431        let msg = if args.is_empty() {
432            "not yet implemented".to_string()
433        } else {
434            format!("{}", args[0])
435        };
436        Err(RuntimeError::new(format!("TODO: {}", msg)))
437    });
438
439    // unreachable - mark code that should never execute
440    define(interp, "unreachable", None, |_, args| {
441        let msg = if args.is_empty() {
442            "entered unreachable code".to_string()
443        } else {
444            format!("{}", args[0])
445        };
446        Err(RuntimeError::new(format!("UNREACHABLE: {}", msg)))
447    });
448
449    // clone - deep clone a value
450    define(interp, "clone", Some(1), |_, args| Ok(deep_clone(&args[0])));
451
452    // identity - return value unchanged (useful in pipes)
453    define(interp, "id", Some(1), |_, args| Ok(args[0].clone()));
454
455    // default - return default value for a type
456    // Can be called with 0 args (when context provides type) or 1 arg (type name string)
457    define(interp, "default", None, |interp, args| {
458        let type_name = if args.is_empty() {
459            // When called with 0 args (e.g., from TypeName::default() fallback),
460            // try to use current_self_type or return a generic empty struct
461            match &interp.current_self_type {
462                Some(t) => t.clone(),
463                None => return Ok(Value::Struct {
464                    name: "Default".to_string(),
465                    fields: Rc::new(RefCell::new(std::collections::HashMap::new())),
466                }),
467            }
468        } else {
469            match &args[0] {
470                Value::String(s) => s.to_string(),
471                _ => return Err(RuntimeError::new("default() requires type name string")),
472            }
473        };
474        let type_name = type_name.as_str();
475        match type_name {
476            "bool" => Ok(Value::Bool(false)),
477            "i64" | "int" => Ok(Value::Int(0)),
478            "f64" | "float" => Ok(Value::Float(0.0)),
479            "str" | "string" => Ok(Value::String(Rc::new(String::new()))),
480            "array" => Ok(Value::Array(Rc::new(RefCell::new(Vec::new())))),
481            _ => {
482                // Check if type is registered in default_structs
483                if let Some(struct_def) = interp.default_structs.get(type_name).cloned() {
484                    use crate::ast::StructFields;
485                    let mut fields = std::collections::HashMap::new();
486                    if let StructFields::Named(field_defs) = &struct_def.fields {
487                        for field in field_defs {
488                            // Use field default expression if available, otherwise Null
489                            let default_val = if let Some(ref default_expr) = field.default {
490                                match interp.evaluate(default_expr) {
491                                    Ok(v) => v,
492                                    Err(_) => Value::Null,
493                                }
494                            } else {
495                                Value::Null
496                            };
497                            fields.insert(field.name.name.clone(), default_val);
498                        }
499                    }
500                    Ok(Value::Struct {
501                        name: type_name.to_string(),
502                        fields: Rc::new(RefCell::new(fields)),
503                    })
504                } else {
505                    // For unknown types (e.g., from external crates), create empty struct
506                    Ok(Value::Struct {
507                        name: type_name.to_string(),
508                        fields: Rc::new(RefCell::new(std::collections::HashMap::new())),
509                    })
510                }
511            }
512        }
513    });
514
515    // Result::Ok - create Ok variant
516    define(interp, "Result·Ok", Some(1), |_, args| {
517        Ok(Value::Variant {
518            enum_name: "Result".to_string(),
519            variant_name: "Ok".to_string(),
520            fields: Some(Rc::new(vec![args[0].clone()])),
521        })
522    });
523
524    // Ok shorthand (without Result:: prefix)
525    define(interp, "Ok", Some(1), |_, args| {
526        Ok(Value::Variant {
527            enum_name: "Result".to_string(),
528            variant_name: "Ok".to_string(),
529            fields: Some(Rc::new(vec![args[0].clone()])),
530        })
531    });
532
533    // Result::Err - create Err variant
534    define(interp, "Result·Err", Some(1), |_, args| {
535        Ok(Value::Variant {
536            enum_name: "Result".to_string(),
537            variant_name: "Err".to_string(),
538            fields: Some(Rc::new(vec![args[0].clone()])),
539        })
540    });
541
542    // Err shorthand (without Result:: prefix)
543    define(interp, "Err", Some(1), |_, args| {
544        Ok(Value::Variant {
545            enum_name: "Result".to_string(),
546            variant_name: "Err".to_string(),
547            fields: Some(Rc::new(vec![args[0].clone()])),
548        })
549    });
550
551    // Option::Some - create Some variant
552    define(interp, "Option·Some", Some(1), |_, args| {
553        Ok(Value::Variant {
554            enum_name: "Option".to_string(),
555            variant_name: "Some".to_string(),
556            fields: Some(Rc::new(vec![args[0].clone()])),
557        })
558    });
559
560    // Some shorthand (without Option:: prefix)
561    define(interp, "Some", Some(1), |_, args| {
562        Ok(Value::Variant {
563            enum_name: "Option".to_string(),
564            variant_name: "Some".to_string(),
565            fields: Some(Rc::new(vec![args[0].clone()])),
566        })
567    });
568
569    // Option::None - create None variant (direct value, not a function)
570    interp.globals.borrow_mut().define(
571        "Option·None".to_string(),
572        Value::Variant {
573            enum_name: "Option".to_string(),
574            variant_name: "None".to_string(),
575            fields: None,
576        },
577    );
578
579    // None shorthand (without Option:: prefix) - direct value
580    interp.globals.borrow_mut().define(
581        "None".to_string(),
582        Value::Variant {
583            enum_name: "Option".to_string(),
584            variant_name: "None".to_string(),
585            fields: None,
586        },
587    );
588
589    // Map::new - create empty map
590    define(interp, "Map·new", Some(0), |_, _| {
591        Ok(Value::Map(Rc::new(RefCell::new(HashMap::new()))))
592    });
593
594    // HashMap::new
595    define(interp, "HashMap·new", Some(0), |_, _| {
596        Ok(Value::Map(Rc::new(RefCell::new(HashMap::new()))))
597    });
598
599    // HashMap::with_capacity
600    define(interp, "HashMap·with_capacity", Some(1), |_, _args| {
601        // Capacity hint is ignored in our implementation
602        Ok(Value::Map(Rc::new(RefCell::new(HashMap::new()))))
603    });
604
605    // std::collections::HashMap::new
606    define(interp, "std·collections·HashMap·new", Some(0), |_, _| {
607        Ok(Value::Map(Rc::new(RefCell::new(HashMap::new()))))
608    });
609
610    // std::collections::HashMap::with_capacity
611    define(interp, "std·collections·HashMap·with_capacity", Some(1), |_, _args| {
612        Ok(Value::Map(Rc::new(RefCell::new(HashMap::new()))))
613    });
614
615    // HashSet::new
616    define(interp, "HashSet·new", Some(0), |_, _| {
617        Ok(Value::Set(Rc::new(RefCell::new(std::collections::HashSet::new()))))
618    });
619
620    // HashSet::with_capacity
621    define(interp, "HashSet·with_capacity", Some(1), |_, _args| {
622        Ok(Value::Set(Rc::new(RefCell::new(std::collections::HashSet::new()))))
623    });
624
625    // std::collections::HashSet::new
626    define(interp, "std·collections·HashSet·new", Some(0), |_, _| {
627        Ok(Value::Set(Rc::new(RefCell::new(std::collections::HashSet::new()))))
628    });
629
630    // Vec::new - create empty vector/array
631    define(interp, "Vec·new", Some(0), |_, _| {
632        Ok(Value::Array(Rc::new(RefCell::new(Vec::new()))))
633    });
634
635    // String::new - create empty string
636    define(interp, "String·new", Some(0), |_, _| {
637        Ok(Value::String(Rc::new(String::new())))
638    });
639
640    // String::from - create string from value
641    define(interp, "String·from", Some(1), |_, args| {
642        let s = match &args[0] {
643            Value::String(s) => (**s).clone(),
644            Value::Int(n) => n.to_string(),
645            Value::Float(f) => f.to_string(),
646            Value::Bool(b) => b.to_string(),
647            Value::Char(c) => c.to_string(),
648            _ => format!("{}", args[0]),
649        };
650        Ok(Value::String(Rc::new(s)))
651    });
652
653    // Box::new - just return the value (Box is transparent in interpreter)
654    define(interp, "Box·new", Some(1), |_, args| {
655        Ok(args[0].clone())
656    });
657
658    // String::from_raw_parts - FFI emulation: construct string from "pointer", len, capacity
659    define(interp, "String·from_raw_parts", Some(3), |_, args| {
660        // In our FFI emulation, the first arg is already the string content
661        match &args[0] {
662            Value::String(s) => Ok(Value::String(s.clone())),
663            Value::Null => Ok(Value::String(Rc::new(String::new()))),
664            _ => Ok(Value::String(Rc::new(format!("{}", args[0])))),
665        }
666    });
667
668    // slice::from_raw_parts - FFI emulation
669    define(interp, "slice·from_raw_parts", Some(2), |_, args| {
670        // First arg is the "pointer" (string), second is len
671        match &args[0] {
672            Value::String(s) => Ok(Value::String(s.clone())),
673            Value::Array(arr) => Ok(Value::Array(arr.clone())),
674            _ => Ok(args[0].clone()),
675        }
676    });
677}
678
679// Deep clone helper
680fn deep_clone(value: &Value) -> Value {
681    match value {
682        Value::Array(arr) => {
683            let cloned: Vec<Value> = arr.borrow().iter().map(deep_clone).collect();
684            Value::Array(Rc::new(RefCell::new(cloned)))
685        }
686        Value::Struct { name, fields } => {
687            let cloned: HashMap<String, Value> = fields
688                .borrow()
689                .iter()
690                .map(|(k, v)| (k.clone(), deep_clone(v)))
691                .collect();
692            Value::Struct {
693                name: name.clone(),
694                fields: Rc::new(RefCell::new(cloned)),
695            }
696        }
697        Value::Evidential { value, evidence } => Value::Evidential {
698            value: Box::new(deep_clone(value)),
699            evidence: *evidence,
700        },
701        other => other.clone(),
702    }
703}
704
705// ============================================================================
706// MATH FUNCTIONS
707// ============================================================================
708
709fn register_math(interp: &mut Interpreter) {
710    // Basic math
711    define(interp, "abs", Some(1), |_, args| match &args[0] {
712        Value::Int(n) => Ok(Value::Int(n.abs())),
713        Value::Float(n) => Ok(Value::Float(n.abs())),
714        _ => Err(RuntimeError::new("abs() requires number")),
715    });
716
717    define(interp, "neg", Some(1), |_, args| match &args[0] {
718        Value::Int(n) => Ok(Value::Int(-n)),
719        Value::Float(n) => Ok(Value::Float(-n)),
720        _ => Err(RuntimeError::new("neg() requires number")),
721    });
722
723    define(interp, "sqrt", Some(1), |_, args| match &args[0] {
724        Value::Int(n) => Ok(Value::Float((*n as f64).sqrt())),
725        Value::Float(n) => Ok(Value::Float(n.sqrt())),
726        _ => Err(RuntimeError::new("sqrt() requires number")),
727    });
728
729    define(interp, "cbrt", Some(1), |_, args| match &args[0] {
730        Value::Int(n) => Ok(Value::Float((*n as f64).cbrt())),
731        Value::Float(n) => Ok(Value::Float(n.cbrt())),
732        _ => Err(RuntimeError::new("cbrt() requires number")),
733    });
734
735    define(interp, "pow", Some(2), |_, args| {
736        match (&args[0], &args[1]) {
737            (Value::Int(base), Value::Int(exp)) => {
738                if *exp >= 0 {
739                    Ok(Value::Int(base.pow(*exp as u32)))
740                } else {
741                    Ok(Value::Float((*base as f64).powi(*exp as i32)))
742                }
743            }
744            (Value::Float(base), Value::Int(exp)) => Ok(Value::Float(base.powi(*exp as i32))),
745            (Value::Float(base), Value::Float(exp)) => Ok(Value::Float(base.powf(*exp))),
746            (Value::Int(base), Value::Float(exp)) => Ok(Value::Float((*base as f64).powf(*exp))),
747            _ => Err(RuntimeError::new("pow() requires numbers")),
748        }
749    });
750
751    define(interp, "exp", Some(1), |_, args| match &args[0] {
752        Value::Int(n) => Ok(Value::Float((*n as f64).exp())),
753        Value::Float(n) => Ok(Value::Float(n.exp())),
754        _ => Err(RuntimeError::new("exp() requires number")),
755    });
756
757    define(interp, "ln", Some(1), |_, args| match &args[0] {
758        Value::Int(n) => Ok(Value::Float((*n as f64).ln())),
759        Value::Float(n) => Ok(Value::Float(n.ln())),
760        _ => Err(RuntimeError::new("ln() requires number")),
761    });
762
763    define(interp, "log", Some(2), |_, args| {
764        let (value, base) = match (&args[0], &args[1]) {
765            (Value::Int(v), Value::Int(b)) => (*v as f64, *b as f64),
766            (Value::Float(v), Value::Int(b)) => (*v, *b as f64),
767            (Value::Int(v), Value::Float(b)) => (*v as f64, *b),
768            (Value::Float(v), Value::Float(b)) => (*v, *b),
769            _ => return Err(RuntimeError::new("log() requires numbers")),
770        };
771        Ok(Value::Float(value.log(base)))
772    });
773
774    define(interp, "log10", Some(1), |_, args| match &args[0] {
775        Value::Int(n) => Ok(Value::Float((*n as f64).log10())),
776        Value::Float(n) => Ok(Value::Float(n.log10())),
777        _ => Err(RuntimeError::new("log10() requires number")),
778    });
779
780    define(interp, "log2", Some(1), |_, args| match &args[0] {
781        Value::Int(n) => Ok(Value::Float((*n as f64).log2())),
782        Value::Float(n) => Ok(Value::Float(n.log2())),
783        _ => Err(RuntimeError::new("log2() requires number")),
784    });
785
786    // Trigonometry
787    define(interp, "sin", Some(1), |_, args| match &args[0] {
788        Value::Int(n) => Ok(Value::Float((*n as f64).sin())),
789        Value::Float(n) => Ok(Value::Float(n.sin())),
790        _ => Err(RuntimeError::new("sin() requires number")),
791    });
792
793    define(interp, "cos", Some(1), |_, args| match &args[0] {
794        Value::Int(n) => Ok(Value::Float((*n as f64).cos())),
795        Value::Float(n) => Ok(Value::Float(n.cos())),
796        _ => Err(RuntimeError::new("cos() requires number")),
797    });
798
799    define(interp, "tan", Some(1), |_, args| match &args[0] {
800        Value::Int(n) => Ok(Value::Float((*n as f64).tan())),
801        Value::Float(n) => Ok(Value::Float(n.tan())),
802        _ => Err(RuntimeError::new("tan() requires number")),
803    });
804
805    define(interp, "asin", Some(1), |_, args| match &args[0] {
806        Value::Int(n) => Ok(Value::Float((*n as f64).asin())),
807        Value::Float(n) => Ok(Value::Float(n.asin())),
808        _ => Err(RuntimeError::new("asin() requires number")),
809    });
810
811    define(interp, "acos", Some(1), |_, args| match &args[0] {
812        Value::Int(n) => Ok(Value::Float((*n as f64).acos())),
813        Value::Float(n) => Ok(Value::Float(n.acos())),
814        _ => Err(RuntimeError::new("acos() requires number")),
815    });
816
817    define(interp, "atan", Some(1), |_, args| match &args[0] {
818        Value::Int(n) => Ok(Value::Float((*n as f64).atan())),
819        Value::Float(n) => Ok(Value::Float(n.atan())),
820        _ => Err(RuntimeError::new("atan() requires number")),
821    });
822
823    define(interp, "atan2", Some(2), |_, args| {
824        let (y, x) = match (&args[0], &args[1]) {
825            (Value::Int(y), Value::Int(x)) => (*y as f64, *x as f64),
826            (Value::Float(y), Value::Int(x)) => (*y, *x as f64),
827            (Value::Int(y), Value::Float(x)) => (*y as f64, *x),
828            (Value::Float(y), Value::Float(x)) => (*y, *x),
829            _ => return Err(RuntimeError::new("atan2() requires numbers")),
830        };
831        Ok(Value::Float(y.atan2(x)))
832    });
833
834    // Hyperbolic
835    define(interp, "sinh", Some(1), |_, args| match &args[0] {
836        Value::Int(n) => Ok(Value::Float((*n as f64).sinh())),
837        Value::Float(n) => Ok(Value::Float(n.sinh())),
838        _ => Err(RuntimeError::new("sinh() requires number")),
839    });
840
841    define(interp, "cosh", Some(1), |_, args| match &args[0] {
842        Value::Int(n) => Ok(Value::Float((*n as f64).cosh())),
843        Value::Float(n) => Ok(Value::Float(n.cosh())),
844        _ => Err(RuntimeError::new("cosh() requires number")),
845    });
846
847    define(interp, "tanh", Some(1), |_, args| match &args[0] {
848        Value::Int(n) => Ok(Value::Float((*n as f64).tanh())),
849        Value::Float(n) => Ok(Value::Float(n.tanh())),
850        _ => Err(RuntimeError::new("tanh() requires number")),
851    });
852
853    // Rounding
854    define(interp, "floor", Some(1), |_, args| match &args[0] {
855        Value::Int(n) => Ok(Value::Int(*n)),
856        Value::Float(n) => Ok(Value::Int(n.floor() as i64)),
857        _ => Err(RuntimeError::new("floor() requires number")),
858    });
859
860    define(interp, "ceil", Some(1), |_, args| match &args[0] {
861        Value::Int(n) => Ok(Value::Int(*n)),
862        Value::Float(n) => Ok(Value::Int(n.ceil() as i64)),
863        _ => Err(RuntimeError::new("ceil() requires number")),
864    });
865
866    define(interp, "round", Some(1), |_, args| match &args[0] {
867        Value::Int(n) => Ok(Value::Int(*n)),
868        Value::Float(n) => Ok(Value::Int(n.round() as i64)),
869        _ => Err(RuntimeError::new("round() requires number")),
870    });
871
872    define(interp, "trunc", Some(1), |_, args| match &args[0] {
873        Value::Int(n) => Ok(Value::Int(*n)),
874        Value::Float(n) => Ok(Value::Int(n.trunc() as i64)),
875        _ => Err(RuntimeError::new("trunc() requires number")),
876    });
877
878    define(interp, "fract", Some(1), |_, args| match &args[0] {
879        Value::Int(_) => Ok(Value::Float(0.0)),
880        Value::Float(n) => Ok(Value::Float(n.fract())),
881        _ => Err(RuntimeError::new("fract() requires number")),
882    });
883
884    // Min/Max/Clamp
885    define(interp, "min", Some(2), |_, args| {
886        match (&args[0], &args[1]) {
887            (Value::Int(a), Value::Int(b)) => Ok(Value::Int(*a.min(b))),
888            (Value::Float(a), Value::Float(b)) => Ok(Value::Float(a.min(*b))),
889            (Value::Int(a), Value::Float(b)) => Ok(Value::Float((*a as f64).min(*b))),
890            (Value::Float(a), Value::Int(b)) => Ok(Value::Float(a.min(*b as f64))),
891            _ => Err(RuntimeError::new("min() requires numbers")),
892        }
893    });
894
895    define(interp, "max", Some(2), |_, args| {
896        match (&args[0], &args[1]) {
897            (Value::Int(a), Value::Int(b)) => Ok(Value::Int(*a.max(b))),
898            (Value::Float(a), Value::Float(b)) => Ok(Value::Float(a.max(*b))),
899            (Value::Int(a), Value::Float(b)) => Ok(Value::Float((*a as f64).max(*b))),
900            (Value::Float(a), Value::Int(b)) => Ok(Value::Float(a.max(*b as f64))),
901            _ => Err(RuntimeError::new("max() requires numbers")),
902        }
903    });
904
905    define(interp, "clamp", Some(3), |_, args| {
906        match (&args[0], &args[1], &args[2]) {
907            (Value::Int(val), Value::Int(min), Value::Int(max)) => {
908                Ok(Value::Int(*val.max(min).min(max)))
909            }
910            (Value::Float(val), Value::Float(min), Value::Float(max)) => {
911                Ok(Value::Float(val.max(*min).min(*max)))
912            }
913            _ => Err(RuntimeError::new("clamp() requires matching number types")),
914        }
915    });
916
917    // Sign
918    define(interp, "sign", Some(1), |_, args| match &args[0] {
919        Value::Int(n) => Ok(Value::Int(n.signum())),
920        Value::Float(n) => Ok(Value::Float(if *n > 0.0 {
921            1.0
922        } else if *n < 0.0 {
923            -1.0
924        } else {
925            0.0
926        })),
927        _ => Err(RuntimeError::new("sign() requires number")),
928    });
929
930    // Constants
931    define(interp, "PI", Some(0), |_, _| {
932        Ok(Value::Float(std::f64::consts::PI))
933    });
934    define(interp, "E", Some(0), |_, _| {
935        Ok(Value::Float(std::f64::consts::E))
936    });
937    define(interp, "TAU", Some(0), |_, _| {
938        Ok(Value::Float(std::f64::consts::TAU))
939    });
940    define(interp, "PHI", Some(0), |_, _| {
941        Ok(Value::Float(1.618033988749895))
942    }); // Golden ratio
943
944    // GCD/LCM
945    define(interp, "gcd", Some(2), |_, args| {
946        match (&args[0], &args[1]) {
947            (Value::Int(a), Value::Int(b)) => Ok(Value::Int(gcd(*a, *b))),
948            _ => Err(RuntimeError::new("gcd() requires integers")),
949        }
950    });
951
952    define(interp, "lcm", Some(2), |_, args| {
953        match (&args[0], &args[1]) {
954            (Value::Int(a), Value::Int(b)) => {
955                let g = gcd(*a, *b);
956                Ok(Value::Int((a * b).abs() / g))
957            }
958            _ => Err(RuntimeError::new("lcm() requires integers")),
959        }
960    });
961
962    // Factorial
963    define(interp, "factorial", Some(1), |_, args| match &args[0] {
964        Value::Int(n) if *n >= 0 => {
965            let mut result: i64 = 1;
966            for i in 2..=(*n as u64) {
967                result = result.saturating_mul(i as i64);
968            }
969            Ok(Value::Int(result))
970        }
971        Value::Int(_) => Err(RuntimeError::new(
972            "factorial() requires non-negative integer",
973        )),
974        _ => Err(RuntimeError::new("factorial() requires integer")),
975    });
976
977    // Is checks
978    define(interp, "is_nan", Some(1), |_, args| match &args[0] {
979        Value::Float(n) => Ok(Value::Bool(n.is_nan())),
980        Value::Int(_) => Ok(Value::Bool(false)),
981        _ => Err(RuntimeError::new("is_nan() requires number")),
982    });
983
984    define(interp, "is_infinite", Some(1), |_, args| match &args[0] {
985        Value::Float(n) => Ok(Value::Bool(n.is_infinite())),
986        Value::Int(_) => Ok(Value::Bool(false)),
987        Value::Infinity => Ok(Value::Bool(true)),
988        _ => Err(RuntimeError::new("is_infinite() requires number")),
989    });
990
991    define(interp, "is_finite", Some(1), |_, args| match &args[0] {
992        Value::Float(n) => Ok(Value::Bool(n.is_finite())),
993        Value::Int(_) => Ok(Value::Bool(true)),
994        Value::Infinity => Ok(Value::Bool(false)),
995        _ => Err(RuntimeError::new("is_finite() requires number")),
996    });
997
998    define(interp, "is_even", Some(1), |_, args| match &args[0] {
999        Value::Int(n) => Ok(Value::Bool(n % 2 == 0)),
1000        _ => Err(RuntimeError::new("is_even() requires integer")),
1001    });
1002
1003    define(interp, "is_odd", Some(1), |_, args| match &args[0] {
1004        Value::Int(n) => Ok(Value::Bool(n % 2 != 0)),
1005        _ => Err(RuntimeError::new("is_odd() requires integer")),
1006    });
1007
1008    define(interp, "is_prime", Some(1), |_, args| match &args[0] {
1009        Value::Int(n) => Ok(Value::Bool(is_prime(*n))),
1010        _ => Err(RuntimeError::new("is_prime() requires integer")),
1011    });
1012}
1013
1014fn gcd(mut a: i64, mut b: i64) -> i64 {
1015    a = a.abs();
1016    b = b.abs();
1017    while b != 0 {
1018        let t = b;
1019        b = a % b;
1020        a = t;
1021    }
1022    a
1023}
1024
1025fn is_prime(n: i64) -> bool {
1026    if n < 2 {
1027        return false;
1028    }
1029    if n == 2 {
1030        return true;
1031    }
1032    if n % 2 == 0 {
1033        return false;
1034    }
1035    let sqrt = (n as f64).sqrt() as i64;
1036    for i in (3..=sqrt).step_by(2) {
1037        if n % i == 0 {
1038            return false;
1039        }
1040    }
1041    true
1042}
1043
1044// ============================================================================
1045// COLLECTION FUNCTIONS
1046// ============================================================================
1047
1048fn register_collections(interp: &mut Interpreter) {
1049    // Basic operations
1050    define(interp, "len", Some(1), |_, args| match &args[0] {
1051        Value::Array(arr) => Ok(Value::Int(arr.borrow().len() as i64)),
1052        Value::String(s) => Ok(Value::Int(s.chars().count() as i64)),
1053        Value::Tuple(t) => Ok(Value::Int(t.len() as i64)),
1054        Value::Map(m) => Ok(Value::Int(m.borrow().len() as i64)),
1055        Value::Set(s) => Ok(Value::Int(s.borrow().len() as i64)),
1056        _ => Err(RuntimeError::new(
1057            "len() requires array, string, tuple, map, or set",
1058        )),
1059    });
1060
1061    define(interp, "is_empty", Some(1), |_, args| match &args[0] {
1062        Value::Array(arr) => Ok(Value::Bool(arr.borrow().is_empty())),
1063        Value::String(s) => Ok(Value::Bool(s.is_empty())),
1064        Value::Tuple(t) => Ok(Value::Bool(t.is_empty())),
1065        Value::Map(m) => Ok(Value::Bool(m.borrow().is_empty())),
1066        Value::Set(s) => Ok(Value::Bool(s.borrow().is_empty())),
1067        _ => Err(RuntimeError::new("is_empty() requires collection")),
1068    });
1069
1070    // Array operations
1071    define(interp, "push", Some(2), |_, args| match &args[0] {
1072        Value::Array(arr) => {
1073            arr.borrow_mut().push(args[1].clone());
1074            Ok(Value::Null)
1075        }
1076        _ => Err(RuntimeError::new("push() requires array")),
1077    });
1078
1079    define(interp, "pop", Some(1), |_, args| match &args[0] {
1080        Value::Array(arr) => arr
1081            .borrow_mut()
1082            .pop()
1083            .ok_or_else(|| RuntimeError::new("pop() on empty array")),
1084        _ => Err(RuntimeError::new("pop() requires array")),
1085    });
1086
1087    define(interp, "first", Some(1), |_, args| match &args[0] {
1088        Value::Array(arr) => arr
1089            .borrow()
1090            .first()
1091            .cloned()
1092            .ok_or_else(|| RuntimeError::new("first() on empty array")),
1093        Value::Tuple(t) => t
1094            .first()
1095            .cloned()
1096            .ok_or_else(|| RuntimeError::new("first() on empty tuple")),
1097        _ => Err(RuntimeError::new("first() requires array or tuple")),
1098    });
1099
1100    define(interp, "last", Some(1), |_, args| match &args[0] {
1101        Value::Array(arr) => arr
1102            .borrow()
1103            .last()
1104            .cloned()
1105            .ok_or_else(|| RuntimeError::new("last() on empty array")),
1106        Value::Tuple(t) => t
1107            .last()
1108            .cloned()
1109            .ok_or_else(|| RuntimeError::new("last() on empty tuple")),
1110        _ => Err(RuntimeError::new("last() requires array or tuple")),
1111    });
1112
1113    // μ (mu) - middle/median element
1114    define(interp, "middle", Some(1), |_, args| match &args[0] {
1115        Value::Array(arr) => {
1116            let arr = arr.borrow();
1117            if arr.is_empty() {
1118                return Err(RuntimeError::new("middle() on empty array"));
1119            }
1120            let mid = arr.len() / 2;
1121            Ok(arr[mid].clone())
1122        }
1123        Value::Tuple(t) => {
1124            if t.is_empty() {
1125                return Err(RuntimeError::new("middle() on empty tuple"));
1126            }
1127            let mid = t.len() / 2;
1128            Ok(t[mid].clone())
1129        }
1130        _ => Err(RuntimeError::new("middle() requires array or tuple")),
1131    });
1132
1133    // χ (chi) - random choice from collection
1134    define(interp, "choice", Some(1), |_, args| {
1135        use std::time::{SystemTime, UNIX_EPOCH};
1136        match &args[0] {
1137            Value::Array(arr) => {
1138                let arr = arr.borrow();
1139                if arr.is_empty() {
1140                    return Err(RuntimeError::new("choice() on empty array"));
1141                }
1142                let seed = SystemTime::now()
1143                    .duration_since(UNIX_EPOCH)
1144                    .unwrap_or(std::time::Duration::ZERO)
1145                    .as_nanos() as u64;
1146                let idx = ((seed.wrapping_mul(1103515245).wrapping_add(12345)) >> 16) as usize
1147                    % arr.len();
1148                Ok(arr[idx].clone())
1149            }
1150            Value::Tuple(t) => {
1151                if t.is_empty() {
1152                    return Err(RuntimeError::new("choice() on empty tuple"));
1153                }
1154                let seed = SystemTime::now()
1155                    .duration_since(UNIX_EPOCH)
1156                    .unwrap_or(std::time::Duration::ZERO)
1157                    .as_nanos() as u64;
1158                let idx =
1159                    ((seed.wrapping_mul(1103515245).wrapping_add(12345)) >> 16) as usize % t.len();
1160                Ok(t[idx].clone())
1161            }
1162            _ => Err(RuntimeError::new("choice() requires array or tuple")),
1163        }
1164    });
1165
1166    // ν (nu) - nth element (alias for get with better semantics)
1167    define(interp, "nth", Some(2), |_, args| {
1168        let n = match &args[1] {
1169            Value::Int(i) => *i,
1170            _ => return Err(RuntimeError::new("nth() index must be integer")),
1171        };
1172        match &args[0] {
1173            Value::Array(arr) => {
1174                let arr = arr.borrow();
1175                if n < 0 || n as usize >= arr.len() {
1176                    return Err(RuntimeError::new("nth() index out of bounds"));
1177                }
1178                Ok(arr[n as usize].clone())
1179            }
1180            Value::Tuple(t) => {
1181                if n < 0 || n as usize >= t.len() {
1182                    return Err(RuntimeError::new("nth() index out of bounds"));
1183                }
1184                Ok(t[n as usize].clone())
1185            }
1186            _ => Err(RuntimeError::new("nth() requires array or tuple")),
1187        }
1188    });
1189
1190    // ξ (xi) - next: pop and return first element (advances iterator)
1191    define(interp, "next", Some(1), |_, args| match &args[0] {
1192        Value::Array(arr) => {
1193            let mut arr = arr.borrow_mut();
1194            if arr.is_empty() {
1195                return Err(RuntimeError::new("next() on empty array"));
1196            }
1197            Ok(arr.remove(0))
1198        }
1199        _ => Err(RuntimeError::new("next() requires array")),
1200    });
1201
1202    // peek - look at first element without consuming (for iterators)
1203    define(interp, "peek", Some(1), |_, args| match &args[0] {
1204        Value::Array(arr) => arr
1205            .borrow()
1206            .first()
1207            .cloned()
1208            .ok_or_else(|| RuntimeError::new("peek() on empty array")),
1209        _ => Err(RuntimeError::new("peek() requires array")),
1210    });
1211
1212    define(interp, "get", Some(2), |_, args| {
1213        let index = match &args[1] {
1214            Value::Int(i) => *i,
1215            _ => return Err(RuntimeError::new("get() index must be integer")),
1216        };
1217        match &args[0] {
1218            Value::Array(arr) => {
1219                let arr = arr.borrow();
1220                let idx = if index < 0 {
1221                    arr.len() as i64 + index
1222                } else {
1223                    index
1224                } as usize;
1225                arr.get(idx)
1226                    .cloned()
1227                    .ok_or_else(|| RuntimeError::new("index out of bounds"))
1228            }
1229            Value::Tuple(t) => {
1230                let idx = if index < 0 {
1231                    t.len() as i64 + index
1232                } else {
1233                    index
1234                } as usize;
1235                t.get(idx)
1236                    .cloned()
1237                    .ok_or_else(|| RuntimeError::new("index out of bounds"))
1238            }
1239            _ => Err(RuntimeError::new("get() requires array or tuple")),
1240        }
1241    });
1242
1243    define(interp, "set", Some(3), |_, args| {
1244        let index = match &args[1] {
1245            Value::Int(i) => *i as usize,
1246            _ => return Err(RuntimeError::new("set() index must be integer")),
1247        };
1248        match &args[0] {
1249            Value::Array(arr) => {
1250                let mut arr = arr.borrow_mut();
1251                if index >= arr.len() {
1252                    return Err(RuntimeError::new("index out of bounds"));
1253                }
1254                arr[index] = args[2].clone();
1255                Ok(Value::Null)
1256            }
1257            _ => Err(RuntimeError::new("set() requires array")),
1258        }
1259    });
1260
1261    define(interp, "insert", Some(3), |_, args| {
1262        let index = match &args[1] {
1263            Value::Int(i) => *i as usize,
1264            _ => return Err(RuntimeError::new("insert() index must be integer")),
1265        };
1266        match &args[0] {
1267            Value::Array(arr) => {
1268                let mut arr = arr.borrow_mut();
1269                if index > arr.len() {
1270                    return Err(RuntimeError::new("index out of bounds"));
1271                }
1272                arr.insert(index, args[2].clone());
1273                Ok(Value::Null)
1274            }
1275            _ => Err(RuntimeError::new("insert() requires array")),
1276        }
1277    });
1278
1279    define(interp, "remove", Some(2), |_, args| {
1280        let index = match &args[1] {
1281            Value::Int(i) => *i as usize,
1282            _ => return Err(RuntimeError::new("remove() index must be integer")),
1283        };
1284        match &args[0] {
1285            Value::Array(arr) => {
1286                let mut arr = arr.borrow_mut();
1287                if index >= arr.len() {
1288                    return Err(RuntimeError::new("index out of bounds"));
1289                }
1290                Ok(arr.remove(index))
1291            }
1292            _ => Err(RuntimeError::new("remove() requires array")),
1293        }
1294    });
1295
1296    define(interp, "clear", Some(1), |_, args| match &args[0] {
1297        Value::Array(arr) => {
1298            arr.borrow_mut().clear();
1299            Ok(Value::Null)
1300        }
1301        _ => Err(RuntimeError::new("clear() requires array")),
1302    });
1303
1304    // Searching
1305    define(interp, "contains", Some(2), |_, args| match &args[0] {
1306        Value::Array(arr) => Ok(Value::Bool(
1307            arr.borrow().iter().any(|v| values_equal(v, &args[1])),
1308        )),
1309        Value::String(s) => match &args[1] {
1310            Value::String(sub) => Ok(Value::Bool(s.contains(sub.as_str()))),
1311            Value::Char(c) => Ok(Value::Bool(s.contains(*c))),
1312            _ => Err(RuntimeError::new(
1313                "string contains() requires string or char",
1314            )),
1315        },
1316        _ => Err(RuntimeError::new("contains() requires array or string")),
1317    });
1318
1319    define(interp, "index_of", Some(2), |_, args| match &args[0] {
1320        Value::Array(arr) => {
1321            let idx = arr.borrow().iter().position(|v| values_equal(v, &args[1]));
1322            match idx {
1323                Some(i) => Ok(Value::Int(i as i64)),
1324                None => Ok(Value::Int(-1)),
1325            }
1326        }
1327        Value::String(s) => match &args[1] {
1328            Value::String(sub) => match s.find(sub.as_str()) {
1329                Some(i) => Ok(Value::Int(i as i64)),
1330                None => Ok(Value::Int(-1)),
1331            },
1332            Value::Char(c) => match s.find(*c) {
1333                Some(i) => Ok(Value::Int(i as i64)),
1334                None => Ok(Value::Int(-1)),
1335            },
1336            _ => Err(RuntimeError::new(
1337                "string index_of() requires string or char",
1338            )),
1339        },
1340        _ => Err(RuntimeError::new("index_of() requires array or string")),
1341    });
1342
1343    // Transformations
1344    define(interp, "reverse", Some(1), |_, args| match &args[0] {
1345        Value::Array(arr) => {
1346            let mut reversed: Vec<Value> = arr.borrow().clone();
1347            reversed.reverse();
1348            Ok(Value::Array(Rc::new(RefCell::new(reversed))))
1349        }
1350        Value::String(s) => {
1351            let reversed: String = s.chars().rev().collect();
1352            Ok(Value::String(Rc::new(reversed)))
1353        }
1354        _ => Err(RuntimeError::new("reverse() requires array or string")),
1355    });
1356
1357    define(interp, "sort", Some(1), |_, args| match &args[0] {
1358        Value::Array(arr) => {
1359            let mut sorted: Vec<Value> = arr.borrow().clone();
1360            sorted.sort_by(compare_values);
1361            Ok(Value::Array(Rc::new(RefCell::new(sorted))))
1362        }
1363        _ => Err(RuntimeError::new("sort() requires array")),
1364    });
1365
1366    define(interp, "sort_desc", Some(1), |_, args| match &args[0] {
1367        Value::Array(arr) => {
1368            let mut sorted: Vec<Value> = arr.borrow().clone();
1369            sorted.sort_by(|a, b| compare_values(b, a));
1370            Ok(Value::Array(Rc::new(RefCell::new(sorted))))
1371        }
1372        _ => Err(RuntimeError::new("sort_desc() requires array")),
1373    });
1374
1375    define(interp, "unique", Some(1), |_, args| match &args[0] {
1376        Value::Array(arr) => {
1377            let arr = arr.borrow();
1378            let mut seen = Vec::new();
1379            let unique: Vec<Value> = arr
1380                .iter()
1381                .filter(|v| {
1382                    if seen.iter().any(|s| values_equal(s, v)) {
1383                        false
1384                    } else {
1385                        seen.push((*v).clone());
1386                        true
1387                    }
1388                })
1389                .cloned()
1390                .collect();
1391            Ok(Value::Array(Rc::new(RefCell::new(unique))))
1392        }
1393        _ => Err(RuntimeError::new("unique() requires array")),
1394    });
1395
1396    define(interp, "flatten", Some(1), |_, args| match &args[0] {
1397        Value::Array(arr) => {
1398            let mut flattened = Vec::new();
1399            for item in arr.borrow().iter() {
1400                match item {
1401                    Value::Array(inner) => flattened.extend(inner.borrow().clone()),
1402                    other => flattened.push(other.clone()),
1403                }
1404            }
1405            Ok(Value::Array(Rc::new(RefCell::new(flattened))))
1406        }
1407        _ => Err(RuntimeError::new("flatten() requires array")),
1408    });
1409
1410    // Combining
1411    define(interp, "concat", Some(2), |_, args| {
1412        match (&args[0], &args[1]) {
1413            (Value::Array(a), Value::Array(b)) => {
1414                let mut result = a.borrow().clone();
1415                result.extend(b.borrow().clone());
1416                Ok(Value::Array(Rc::new(RefCell::new(result))))
1417            }
1418            (Value::String(a), Value::String(b)) => {
1419                Ok(Value::String(Rc::new(format!("{}{}", a, b))))
1420            }
1421            _ => Err(RuntimeError::new(
1422                "concat() requires two arrays or two strings",
1423            )),
1424        }
1425    });
1426
1427    define(interp, "zip", Some(2), |_, args| {
1428        match (&args[0], &args[1]) {
1429            (Value::Array(a), Value::Array(b)) => {
1430                let a = a.borrow();
1431                let b = b.borrow();
1432                let zipped: Vec<Value> = a
1433                    .iter()
1434                    .zip(b.iter())
1435                    .map(|(x, y)| Value::Tuple(Rc::new(vec![x.clone(), y.clone()])))
1436                    .collect();
1437                Ok(Value::Array(Rc::new(RefCell::new(zipped))))
1438            }
1439            _ => Err(RuntimeError::new("zip() requires two arrays")),
1440        }
1441    });
1442
1443    define(interp, "enumerate", Some(1), |_, args| match &args[0] {
1444        Value::Array(arr) => {
1445            let enumerated: Vec<Value> = arr
1446                .borrow()
1447                .iter()
1448                .enumerate()
1449                .map(|(i, v)| Value::Tuple(Rc::new(vec![Value::Int(i as i64), v.clone()])))
1450                .collect();
1451            Ok(Value::Array(Rc::new(RefCell::new(enumerated))))
1452        }
1453        _ => Err(RuntimeError::new("enumerate() requires array")),
1454    });
1455
1456    // ⋈ (bowtie) - zip_with: combine two arrays with a function
1457    // Since closures are complex, provide a simple zip variant that takes a mode
1458    define(interp, "zip_with", Some(3), |_, args| {
1459        let mode = match &args[2] {
1460            Value::String(s) => s.as_str(),
1461            _ => return Err(RuntimeError::new("zip_with() mode must be string")),
1462        };
1463        match (&args[0], &args[1]) {
1464            (Value::Array(a), Value::Array(b)) => {
1465                let a = a.borrow();
1466                let b = b.borrow();
1467                let result: Result<Vec<Value>, RuntimeError> = a
1468                    .iter()
1469                    .zip(b.iter())
1470                    .map(|(x, y)| match (x, y, mode) {
1471                        (Value::Int(a), Value::Int(b), "add") => Ok(Value::Int(a + b)),
1472                        (Value::Int(a), Value::Int(b), "sub") => Ok(Value::Int(a - b)),
1473                        (Value::Int(a), Value::Int(b), "mul") => Ok(Value::Int(a * b)),
1474                        (Value::Float(a), Value::Float(b), "add") => Ok(Value::Float(a + b)),
1475                        (Value::Float(a), Value::Float(b), "sub") => Ok(Value::Float(a - b)),
1476                        (Value::Float(a), Value::Float(b), "mul") => Ok(Value::Float(a * b)),
1477                        (_, _, "pair") => Ok(Value::Tuple(Rc::new(vec![x.clone(), y.clone()]))),
1478                        _ => Err(RuntimeError::new("zip_with() incompatible types or mode")),
1479                    })
1480                    .collect();
1481                Ok(Value::Array(Rc::new(RefCell::new(result?))))
1482            }
1483            _ => Err(RuntimeError::new("zip_with() requires two arrays")),
1484        }
1485    });
1486
1487    // ⊔ (square cup) - lattice join / supremum (max of two values)
1488    define(interp, "supremum", Some(2), |_, args| {
1489        match (&args[0], &args[1]) {
1490            (Value::Int(a), Value::Int(b)) => Ok(Value::Int(*a.max(b))),
1491            (Value::Float(a), Value::Float(b)) => Ok(Value::Float(a.max(*b))),
1492            (Value::Array(a), Value::Array(b)) => {
1493                // Element-wise max
1494                let a = a.borrow();
1495                let b = b.borrow();
1496                let result: Result<Vec<Value>, RuntimeError> = a
1497                    .iter()
1498                    .zip(b.iter())
1499                    .map(|(x, y)| match (x, y) {
1500                        (Value::Int(a), Value::Int(b)) => Ok(Value::Int(*a.max(b))),
1501                        (Value::Float(a), Value::Float(b)) => Ok(Value::Float(a.max(*b))),
1502                        _ => Err(RuntimeError::new("supremum() requires numeric arrays")),
1503                    })
1504                    .collect();
1505                Ok(Value::Array(Rc::new(RefCell::new(result?))))
1506            }
1507            _ => Err(RuntimeError::new(
1508                "supremum() requires numeric values or arrays",
1509            )),
1510        }
1511    });
1512
1513    // ⊓ (square cap) - lattice meet / infimum (min of two values)
1514    define(interp, "infimum", Some(2), |_, args| {
1515        match (&args[0], &args[1]) {
1516            (Value::Int(a), Value::Int(b)) => Ok(Value::Int(*a.min(b))),
1517            (Value::Float(a), Value::Float(b)) => Ok(Value::Float(a.min(*b))),
1518            (Value::Array(a), Value::Array(b)) => {
1519                // Element-wise min
1520                let a = a.borrow();
1521                let b = b.borrow();
1522                let result: Result<Vec<Value>, RuntimeError> = a
1523                    .iter()
1524                    .zip(b.iter())
1525                    .map(|(x, y)| match (x, y) {
1526                        (Value::Int(a), Value::Int(b)) => Ok(Value::Int(*a.min(b))),
1527                        (Value::Float(a), Value::Float(b)) => Ok(Value::Float(a.min(*b))),
1528                        _ => Err(RuntimeError::new("infimum() requires numeric arrays")),
1529                    })
1530                    .collect();
1531                Ok(Value::Array(Rc::new(RefCell::new(result?))))
1532            }
1533            _ => Err(RuntimeError::new(
1534                "infimum() requires numeric values or arrays",
1535            )),
1536        }
1537    });
1538
1539    // Slicing
1540    define(interp, "slice", Some(3), |_, args| {
1541        let start = match &args[1] {
1542            Value::Int(i) => *i as usize,
1543            _ => return Err(RuntimeError::new("slice() start must be integer")),
1544        };
1545        let end = match &args[2] {
1546            Value::Int(i) => *i as usize,
1547            _ => return Err(RuntimeError::new("slice() end must be integer")),
1548        };
1549        match &args[0] {
1550            Value::Array(arr) => {
1551                let arr = arr.borrow();
1552                let end = end.min(arr.len());
1553                let sliced: Vec<Value> = arr[start..end].to_vec();
1554                Ok(Value::Array(Rc::new(RefCell::new(sliced))))
1555            }
1556            Value::String(s) => {
1557                let chars: Vec<char> = s.chars().collect();
1558                let end = end.min(chars.len());
1559                let sliced: String = chars[start..end].iter().collect();
1560                Ok(Value::String(Rc::new(sliced)))
1561            }
1562            _ => Err(RuntimeError::new("slice() requires array or string")),
1563        }
1564    });
1565
1566    define(interp, "take", Some(2), |_, args| {
1567        let n = match &args[1] {
1568            Value::Int(i) => *i as usize,
1569            _ => return Err(RuntimeError::new("take() n must be integer")),
1570        };
1571        match &args[0] {
1572            Value::Array(arr) => {
1573                let taken: Vec<Value> = arr.borrow().iter().take(n).cloned().collect();
1574                Ok(Value::Array(Rc::new(RefCell::new(taken))))
1575            }
1576            _ => Err(RuntimeError::new("take() requires array")),
1577        }
1578    });
1579
1580    define(interp, "skip", Some(2), |_, args| {
1581        let n = match &args[1] {
1582            Value::Int(i) => *i as usize,
1583            _ => return Err(RuntimeError::new("skip() n must be integer")),
1584        };
1585        match &args[0] {
1586            Value::Array(arr) => {
1587                let skipped: Vec<Value> = arr.borrow().iter().skip(n).cloned().collect();
1588                Ok(Value::Array(Rc::new(RefCell::new(skipped))))
1589            }
1590            _ => Err(RuntimeError::new("skip() requires array")),
1591        }
1592    });
1593
1594    define(interp, "chunk", Some(2), |_, args| {
1595        let size = match &args[1] {
1596            Value::Int(i) if *i > 0 => *i as usize,
1597            _ => return Err(RuntimeError::new("chunk() size must be positive integer")),
1598        };
1599        match &args[0] {
1600            Value::Array(arr) => {
1601                let chunks: Vec<Value> = arr
1602                    .borrow()
1603                    .chunks(size)
1604                    .map(|c| Value::Array(Rc::new(RefCell::new(c.to_vec()))))
1605                    .collect();
1606                Ok(Value::Array(Rc::new(RefCell::new(chunks))))
1607            }
1608            _ => Err(RuntimeError::new("chunk() requires array")),
1609        }
1610    });
1611
1612    // Range
1613    define(interp, "range", Some(2), |_, args| {
1614        let start = match &args[0] {
1615            Value::Int(n) => *n,
1616            _ => return Err(RuntimeError::new("range() requires integers")),
1617        };
1618        let end = match &args[1] {
1619            Value::Int(n) => *n,
1620            _ => return Err(RuntimeError::new("range() requires integers")),
1621        };
1622        let values: Vec<Value> = (start..end).map(Value::Int).collect();
1623        Ok(Value::Array(Rc::new(RefCell::new(values))))
1624    });
1625
1626    define(interp, "range_inclusive", Some(2), |_, args| {
1627        let start = match &args[0] {
1628            Value::Int(n) => *n,
1629            _ => return Err(RuntimeError::new("range_inclusive() requires integers")),
1630        };
1631        let end = match &args[1] {
1632            Value::Int(n) => *n,
1633            _ => return Err(RuntimeError::new("range_inclusive() requires integers")),
1634        };
1635        let values: Vec<Value> = (start..=end).map(Value::Int).collect();
1636        Ok(Value::Array(Rc::new(RefCell::new(values))))
1637    });
1638
1639    define(interp, "repeat", Some(2), |_, args| {
1640        let n = match &args[1] {
1641            Value::Int(i) if *i >= 0 => *i as usize,
1642            _ => {
1643                return Err(RuntimeError::new(
1644                    "repeat() count must be non-negative integer",
1645                ))
1646            }
1647        };
1648        let repeated: Vec<Value> = std::iter::repeat(args[0].clone()).take(n).collect();
1649        Ok(Value::Array(Rc::new(RefCell::new(repeated))))
1650    });
1651
1652    // ========================================
1653    // HashMap operations
1654    // ========================================
1655
1656    // map_new - create empty HashMap
1657    define(interp, "map_new", Some(0), |_, _| {
1658        Ok(Value::Map(Rc::new(RefCell::new(HashMap::new()))))
1659    });
1660
1661    // map_get - get value by key
1662    define(interp, "map_get", Some(2), |_, args| {
1663        let key = match &args[1] {
1664            Value::String(s) => s.to_string(),
1665            _ => return Err(RuntimeError::new("map_get() key must be string")),
1666        };
1667        match &args[0] {
1668            Value::Map(map) => Ok(map.borrow().get(&key).cloned().unwrap_or(Value::Null)),
1669            _ => Err(RuntimeError::new("map_get() requires map")),
1670        }
1671    });
1672
1673    // map_set - set key-value pair
1674    define(interp, "map_set", Some(3), |_, args| {
1675        let key = match &args[1] {
1676            Value::String(s) => s.to_string(),
1677            _ => return Err(RuntimeError::new("map_set() key must be string")),
1678        };
1679        match &args[0] {
1680            Value::Map(map) => {
1681                map.borrow_mut().insert(key, args[2].clone());
1682                Ok(Value::Null)
1683            }
1684            _ => Err(RuntimeError::new("map_set() requires map")),
1685        }
1686    });
1687
1688    // map_has - check if key exists
1689    define(interp, "map_has", Some(2), |_, args| {
1690        let key = match &args[1] {
1691            Value::String(s) => s.to_string(),
1692            _ => return Err(RuntimeError::new("map_has() key must be string")),
1693        };
1694        match &args[0] {
1695            Value::Map(map) => Ok(Value::Bool(map.borrow().contains_key(&key))),
1696            _ => Err(RuntimeError::new("map_has() requires map")),
1697        }
1698    });
1699
1700    // map_remove - remove key from map
1701    define(interp, "map_remove", Some(2), |_, args| {
1702        let key = match &args[1] {
1703            Value::String(s) => s.to_string(),
1704            _ => return Err(RuntimeError::new("map_remove() key must be string")),
1705        };
1706        match &args[0] {
1707            Value::Map(map) => Ok(map.borrow_mut().remove(&key).unwrap_or(Value::Null)),
1708            _ => Err(RuntimeError::new("map_remove() requires map")),
1709        }
1710    });
1711
1712    // map_keys - get all keys as array
1713    define(interp, "map_keys", Some(1), |_, args| match &args[0] {
1714        Value::Map(map) => {
1715            let keys: Vec<Value> = map
1716                .borrow()
1717                .keys()
1718                .map(|k| Value::String(Rc::new(k.clone())))
1719                .collect();
1720            Ok(Value::Array(Rc::new(RefCell::new(keys))))
1721        }
1722        _ => Err(RuntimeError::new("map_keys() requires map")),
1723    });
1724
1725    // map_values - get all values as array
1726    define(interp, "map_values", Some(1), |_, args| match &args[0] {
1727        Value::Map(map) => {
1728            let values: Vec<Value> = map.borrow().values().cloned().collect();
1729            Ok(Value::Array(Rc::new(RefCell::new(values))))
1730        }
1731        _ => Err(RuntimeError::new("map_values() requires map")),
1732    });
1733
1734    // map_len - get number of entries
1735    define(interp, "map_len", Some(1), |_, args| match &args[0] {
1736        Value::Map(map) => Ok(Value::Int(map.borrow().len() as i64)),
1737        _ => Err(RuntimeError::new("map_len() requires map")),
1738    });
1739
1740    // map_clear - remove all entries
1741    define(interp, "map_clear", Some(1), |_, args| match &args[0] {
1742        Value::Map(map) => {
1743            map.borrow_mut().clear();
1744            Ok(Value::Null)
1745        }
1746        _ => Err(RuntimeError::new("map_clear() requires map")),
1747    });
1748
1749    // ========================================
1750    // HashSet operations
1751    // ========================================
1752
1753    // set_new - create empty HashSet
1754    define(interp, "set_new", Some(0), |_, _| {
1755        Ok(Value::Set(Rc::new(RefCell::new(
1756            std::collections::HashSet::new(),
1757        ))))
1758    });
1759
1760    // set_add - add item to set
1761    define(interp, "set_add", Some(2), |_, args| {
1762        let item = match &args[1] {
1763            Value::String(s) => s.to_string(),
1764            _ => return Err(RuntimeError::new("set_add() item must be string")),
1765        };
1766        match &args[0] {
1767            Value::Set(set) => {
1768                set.borrow_mut().insert(item);
1769                Ok(Value::Null)
1770            }
1771            _ => Err(RuntimeError::new("set_add() requires set")),
1772        }
1773    });
1774
1775    // set_has - check if item exists
1776    define(interp, "set_has", Some(2), |_, args| {
1777        let item = match &args[1] {
1778            Value::String(s) => s.to_string(),
1779            _ => return Err(RuntimeError::new("set_has() item must be string")),
1780        };
1781        match &args[0] {
1782            Value::Set(set) => Ok(Value::Bool(set.borrow().contains(&item))),
1783            _ => Err(RuntimeError::new("set_has() requires set")),
1784        }
1785    });
1786
1787    // set_remove - remove item from set
1788    define(interp, "set_remove", Some(2), |_, args| {
1789        let item = match &args[1] {
1790            Value::String(s) => s.to_string(),
1791            _ => return Err(RuntimeError::new("set_remove() item must be string")),
1792        };
1793        match &args[0] {
1794            Value::Set(set) => Ok(Value::Bool(set.borrow_mut().remove(&item))),
1795            _ => Err(RuntimeError::new("set_remove() requires set")),
1796        }
1797    });
1798
1799    // set_to_array - convert set to array
1800    define(interp, "set_to_array", Some(1), |_, args| match &args[0] {
1801        Value::Set(set) => {
1802            let items: Vec<Value> = set
1803                .borrow()
1804                .iter()
1805                .map(|s| Value::String(Rc::new(s.clone())))
1806                .collect();
1807            Ok(Value::Array(Rc::new(RefCell::new(items))))
1808        }
1809        _ => Err(RuntimeError::new("set_to_array() requires set")),
1810    });
1811
1812    // set_len - get number of items
1813    define(interp, "set_len", Some(1), |_, args| match &args[0] {
1814        Value::Set(set) => Ok(Value::Int(set.borrow().len() as i64)),
1815        _ => Err(RuntimeError::new("set_len() requires set")),
1816    });
1817
1818    // set_clear - remove all items
1819    define(interp, "set_clear", Some(1), |_, args| match &args[0] {
1820        Value::Set(set) => {
1821            set.borrow_mut().clear();
1822            Ok(Value::Null)
1823        }
1824        _ => Err(RuntimeError::new("set_clear() requires set")),
1825    });
1826}
1827
1828fn values_equal(a: &Value, b: &Value) -> bool {
1829    match (a, b) {
1830        (Value::Null, Value::Null) => true,
1831        (Value::Bool(a), Value::Bool(b)) => a == b,
1832        (Value::Int(a), Value::Int(b)) => a == b,
1833        (Value::Float(a), Value::Float(b)) => (a - b).abs() < f64::EPSILON,
1834        (Value::String(a), Value::String(b)) => a == b,
1835        (Value::Char(a), Value::Char(b)) => a == b,
1836        (Value::Array(a), Value::Array(b)) => {
1837            let a = a.borrow();
1838            let b = b.borrow();
1839            a.len() == b.len() && a.iter().zip(b.iter()).all(|(x, y)| values_equal(x, y))
1840        }
1841        (Value::Tuple(a), Value::Tuple(b)) => {
1842            a.len() == b.len() && a.iter().zip(b.iter()).all(|(x, y)| values_equal(x, y))
1843        }
1844        _ => false,
1845    }
1846}
1847
1848fn compare_values(a: &Value, b: &Value) -> std::cmp::Ordering {
1849    match (a, b) {
1850        (Value::Int(a), Value::Int(b)) => a.cmp(b),
1851        (Value::Float(a), Value::Float(b)) => a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal),
1852        (Value::String(a), Value::String(b)) => a.cmp(b),
1853        (Value::Char(a), Value::Char(b)) => a.cmp(b),
1854        _ => std::cmp::Ordering::Equal,
1855    }
1856}
1857
1858// ============================================================================
1859// STRING FUNCTIONS
1860// ============================================================================
1861
1862fn register_string(interp: &mut Interpreter) {
1863    define(interp, "chars", Some(1), |_, args| match &args[0] {
1864        Value::String(s) => {
1865            let chars: Vec<Value> = s.chars().map(Value::Char).collect();
1866            Ok(Value::Array(Rc::new(RefCell::new(chars))))
1867        }
1868        _ => Err(RuntimeError::new("chars() requires string")),
1869    });
1870
1871    define(interp, "bytes", Some(1), |_, args| match &args[0] {
1872        Value::String(s) => {
1873            let bytes: Vec<Value> = s.bytes().map(|b| Value::Int(b as i64)).collect();
1874            Ok(Value::Array(Rc::new(RefCell::new(bytes))))
1875        }
1876        _ => Err(RuntimeError::new("bytes() requires string")),
1877    });
1878
1879    define(interp, "split", Some(2), |_, args| {
1880        match (&args[0], &args[1]) {
1881            (Value::String(s), Value::String(sep)) => {
1882                let parts: Vec<Value> = s
1883                    .split(sep.as_str())
1884                    .map(|p| Value::String(Rc::new(p.to_string())))
1885                    .collect();
1886                Ok(Value::Array(Rc::new(RefCell::new(parts))))
1887            }
1888            (Value::String(s), Value::Char(sep)) => {
1889                let parts: Vec<Value> = s
1890                    .split(*sep)
1891                    .map(|p| Value::String(Rc::new(p.to_string())))
1892                    .collect();
1893                Ok(Value::Array(Rc::new(RefCell::new(parts))))
1894            }
1895            _ => Err(RuntimeError::new("split() requires string and separator")),
1896        }
1897    });
1898
1899    define(interp, "join", Some(2), |_, args| {
1900        match (&args[0], &args[1]) {
1901            (Value::Array(arr), Value::String(sep)) => {
1902                let parts: Vec<String> = arr.borrow().iter().map(|v| format!("{}", v)).collect();
1903                Ok(Value::String(Rc::new(parts.join(sep.as_str()))))
1904            }
1905            _ => Err(RuntimeError::new(
1906                "join() requires array and separator string",
1907            )),
1908        }
1909    });
1910
1911    define(interp, "trim", Some(1), |_, args| match &args[0] {
1912        Value::String(s) => Ok(Value::String(Rc::new(s.trim().to_string()))),
1913        _ => Err(RuntimeError::new("trim() requires string")),
1914    });
1915
1916    define(interp, "trim_start", Some(1), |_, args| match &args[0] {
1917        Value::String(s) => Ok(Value::String(Rc::new(s.trim_start().to_string()))),
1918        _ => Err(RuntimeError::new("trim_start() requires string")),
1919    });
1920
1921    define(interp, "trim_end", Some(1), |_, args| match &args[0] {
1922        Value::String(s) => Ok(Value::String(Rc::new(s.trim_end().to_string()))),
1923        _ => Err(RuntimeError::new("trim_end() requires string")),
1924    });
1925
1926    define(interp, "upper", Some(1), |_, args| match &args[0] {
1927        Value::String(s) => Ok(Value::String(Rc::new(s.to_uppercase()))),
1928        Value::Char(c) => Ok(Value::Char(c.to_uppercase().next().unwrap_or(*c))),
1929        _ => Err(RuntimeError::new("upper() requires string or char")),
1930    });
1931
1932    define(interp, "lower", Some(1), |_, args| match &args[0] {
1933        Value::String(s) => Ok(Value::String(Rc::new(s.to_lowercase()))),
1934        Value::Char(c) => Ok(Value::Char(c.to_lowercase().next().unwrap_or(*c))),
1935        _ => Err(RuntimeError::new("lower() requires string or char")),
1936    });
1937
1938    define(interp, "capitalize", Some(1), |_, args| match &args[0] {
1939        Value::String(s) => {
1940            let mut chars = s.chars();
1941            let capitalized = match chars.next() {
1942                None => String::new(),
1943                Some(c) => c.to_uppercase().chain(chars).collect(),
1944            };
1945            Ok(Value::String(Rc::new(capitalized)))
1946        }
1947        _ => Err(RuntimeError::new("capitalize() requires string")),
1948    });
1949
1950    define(interp, "replace", Some(3), |_, args| {
1951        match (&args[0], &args[1], &args[2]) {
1952            (Value::String(s), Value::String(from), Value::String(to)) => Ok(Value::String(
1953                Rc::new(s.replace(from.as_str(), to.as_str())),
1954            )),
1955            _ => Err(RuntimeError::new("replace() requires three strings")),
1956        }
1957    });
1958
1959    define(interp, "starts_with", Some(2), |_, args| {
1960        match (&args[0], &args[1]) {
1961            (Value::String(s), Value::String(prefix)) => {
1962                Ok(Value::Bool(s.starts_with(prefix.as_str())))
1963            }
1964            _ => Err(RuntimeError::new("starts_with() requires two strings")),
1965        }
1966    });
1967
1968    define(interp, "ends_with", Some(2), |_, args| {
1969        match (&args[0], &args[1]) {
1970            (Value::String(s), Value::String(suffix)) => {
1971                Ok(Value::Bool(s.ends_with(suffix.as_str())))
1972            }
1973            _ => Err(RuntimeError::new("ends_with() requires two strings")),
1974        }
1975    });
1976
1977    define(interp, "repeat_str", Some(2), |_, args| {
1978        match (&args[0], &args[1]) {
1979            (Value::String(s), Value::Int(n)) if *n >= 0 => {
1980                Ok(Value::String(Rc::new(s.repeat(*n as usize))))
1981            }
1982            _ => Err(RuntimeError::new(
1983                "repeat_str() requires string and non-negative integer",
1984            )),
1985        }
1986    });
1987
1988    define(interp, "pad_left", Some(3), |_, args| {
1989        match (&args[0], &args[1], &args[2]) {
1990            (Value::String(s), Value::Int(width), Value::Char(c)) => {
1991                let width = *width as usize;
1992                if s.len() >= width {
1993                    Ok(Value::String(s.clone()))
1994                } else {
1995                    let padding: String = std::iter::repeat(*c).take(width - s.len()).collect();
1996                    Ok(Value::String(Rc::new(format!("{}{}", padding, s))))
1997                }
1998            }
1999            _ => Err(RuntimeError::new(
2000                "pad_left() requires string, width, and char",
2001            )),
2002        }
2003    });
2004
2005    define(interp, "pad_right", Some(3), |_, args| {
2006        match (&args[0], &args[1], &args[2]) {
2007            (Value::String(s), Value::Int(width), Value::Char(c)) => {
2008                let width = *width as usize;
2009                if s.len() >= width {
2010                    Ok(Value::String(s.clone()))
2011                } else {
2012                    let padding: String = std::iter::repeat(*c).take(width - s.len()).collect();
2013                    Ok(Value::String(Rc::new(format!("{}{}", s, padding))))
2014                }
2015            }
2016            _ => Err(RuntimeError::new(
2017                "pad_right() requires string, width, and char",
2018            )),
2019        }
2020    });
2021
2022    define(interp, "lines", Some(1), |_, args| match &args[0] {
2023        Value::String(s) => {
2024            let lines: Vec<Value> = s
2025                .lines()
2026                .map(|l| Value::String(Rc::new(l.to_string())))
2027                .collect();
2028            Ok(Value::Array(Rc::new(RefCell::new(lines))))
2029        }
2030        _ => Err(RuntimeError::new("lines() requires string")),
2031    });
2032
2033    define(interp, "words", Some(1), |_, args| match &args[0] {
2034        Value::String(s) => {
2035            let words: Vec<Value> = s
2036                .split_whitespace()
2037                .map(|w| Value::String(Rc::new(w.to_string())))
2038                .collect();
2039            Ok(Value::Array(Rc::new(RefCell::new(words))))
2040        }
2041        _ => Err(RuntimeError::new("words() requires string")),
2042    });
2043
2044    define(interp, "is_alpha", Some(1), |_, args| match &args[0] {
2045        Value::String(s) => Ok(Value::Bool(
2046            !s.is_empty() && s.chars().all(|c| c.is_alphabetic()),
2047        )),
2048        Value::Char(c) => Ok(Value::Bool(c.is_alphabetic())),
2049        _ => Err(RuntimeError::new("is_alpha() requires string or char")),
2050    });
2051
2052    define(interp, "is_digit", Some(1), |_, args| match &args[0] {
2053        Value::String(s) => Ok(Value::Bool(
2054            !s.is_empty() && s.chars().all(|c| c.is_ascii_digit()),
2055        )),
2056        Value::Char(c) => Ok(Value::Bool(c.is_ascii_digit())),
2057        _ => Err(RuntimeError::new("is_digit() requires string or char")),
2058    });
2059
2060    define(interp, "is_alnum", Some(1), |_, args| match &args[0] {
2061        Value::String(s) => Ok(Value::Bool(
2062            !s.is_empty() && s.chars().all(|c| c.is_alphanumeric()),
2063        )),
2064        Value::Char(c) => Ok(Value::Bool(c.is_alphanumeric())),
2065        _ => Err(RuntimeError::new("is_alnum() requires string or char")),
2066    });
2067
2068    define(interp, "is_space", Some(1), |_, args| match &args[0] {
2069        Value::String(s) => Ok(Value::Bool(
2070            !s.is_empty() && s.chars().all(|c| c.is_whitespace()),
2071        )),
2072        Value::Char(c) => Ok(Value::Bool(c.is_whitespace())),
2073        _ => Err(RuntimeError::new("is_space() requires string or char")),
2074    });
2075
2076    // =========================================================================
2077    // ADVANCED STRING FUNCTIONS
2078    // =========================================================================
2079
2080    // find - find first occurrence of substring, returns index or -1
2081    define(interp, "find", Some(2), |_, args| {
2082        match (&args[0], &args[1]) {
2083            (Value::String(s), Value::String(sub)) => {
2084                match s.find(sub.as_str()) {
2085                    Some(byte_idx) => {
2086                        // Convert byte index to character index
2087                        let char_idx = s[..byte_idx].chars().count() as i64;
2088                        Ok(Value::Int(char_idx))
2089                    }
2090                    None => Ok(Value::Int(-1)),
2091                }
2092            }
2093            (Value::String(s), Value::Char(c)) => match s.find(*c) {
2094                Some(byte_idx) => {
2095                    let char_idx = s[..byte_idx].chars().count() as i64;
2096                    Ok(Value::Int(char_idx))
2097                }
2098                None => Ok(Value::Int(-1)),
2099            },
2100            _ => Err(RuntimeError::new(
2101                "find() requires string and substring/char",
2102            )),
2103        }
2104    });
2105
2106    // index_of - find index of element in array or substring in string
2107    define(interp, "index_of", Some(2), |_, args| {
2108        match (&args[0], &args[1]) {
2109            (Value::String(s), Value::String(sub)) => match s.find(sub.as_str()) {
2110                Some(byte_idx) => {
2111                    let char_idx = s[..byte_idx].chars().count() as i64;
2112                    Ok(Value::Int(char_idx))
2113                }
2114                None => Ok(Value::Int(-1)),
2115            },
2116            (Value::String(s), Value::Char(c)) => match s.find(*c) {
2117                Some(byte_idx) => {
2118                    let char_idx = s[..byte_idx].chars().count() as i64;
2119                    Ok(Value::Int(char_idx))
2120                }
2121                None => Ok(Value::Int(-1)),
2122            },
2123            (Value::Array(arr), search) => {
2124                // Array index_of - use Value comparison
2125                for (i, v) in arr.borrow().iter().enumerate() {
2126                    if values_equal_simple(v, search) {
2127                        return Ok(Value::Int(i as i64));
2128                    }
2129                }
2130                Ok(Value::Int(-1))
2131            }
2132            _ => Err(RuntimeError::new(
2133                "index_of() requires array/string and element/substring",
2134            )),
2135        }
2136    });
2137
2138    // last_index_of - find last occurrence of substring
2139    define(interp, "last_index_of", Some(2), |_, args| {
2140        match (&args[0], &args[1]) {
2141            (Value::String(s), Value::String(sub)) => match s.rfind(sub.as_str()) {
2142                Some(byte_idx) => {
2143                    let char_idx = s[..byte_idx].chars().count() as i64;
2144                    Ok(Value::Int(char_idx))
2145                }
2146                None => Ok(Value::Int(-1)),
2147            },
2148            (Value::String(s), Value::Char(c)) => match s.rfind(*c) {
2149                Some(byte_idx) => {
2150                    let char_idx = s[..byte_idx].chars().count() as i64;
2151                    Ok(Value::Int(char_idx))
2152                }
2153                None => Ok(Value::Int(-1)),
2154            },
2155            _ => Err(RuntimeError::new(
2156                "last_index_of() requires string and substring/char",
2157            )),
2158        }
2159    });
2160
2161    // substring - extract substring by character indices
2162    define(interp, "substring", Some(3), |_, args| {
2163        let s = match &args[0] {
2164            Value::String(s) => (**s).clone(),
2165            _ => {
2166                return Err(RuntimeError::new(
2167                    "substring: first argument must be a string",
2168                ))
2169            }
2170        };
2171        let start = match &args[1] {
2172            Value::Int(n) if *n >= 0 => *n as usize,
2173            _ => {
2174                return Err(RuntimeError::new(
2175                    "substring: start must be a non-negative integer",
2176                ))
2177            }
2178        };
2179        let end = match &args[2] {
2180            Value::Int(n) if *n >= 0 => *n as usize,
2181            _ => {
2182                return Err(RuntimeError::new(
2183                    "substring: end must be a non-negative integer",
2184                ))
2185            }
2186        };
2187        let chars: Vec<char> = s.chars().collect();
2188        let len = chars.len();
2189        let actual_start = start.min(len);
2190        let actual_end = end.min(len);
2191        if actual_start >= actual_end {
2192            return Ok(Value::String(Rc::new(String::new())));
2193        }
2194        let result: String = chars[actual_start..actual_end].iter().collect();
2195        Ok(Value::String(Rc::new(result)))
2196    });
2197
2198    // count - count occurrences of substring
2199    define(interp, "count", Some(2), |_, args| {
2200        match (&args[0], &args[1]) {
2201            (Value::String(s), Value::String(sub)) => {
2202                if sub.is_empty() {
2203                    return Err(RuntimeError::new("count: cannot count empty string"));
2204                }
2205                let count = s.matches(sub.as_str()).count() as i64;
2206                Ok(Value::Int(count))
2207            }
2208            (Value::String(s), Value::Char(c)) => {
2209                let count = s.chars().filter(|&ch| ch == *c).count() as i64;
2210                Ok(Value::Int(count))
2211            }
2212            _ => Err(RuntimeError::new(
2213                "count() requires string and substring/char",
2214            )),
2215        }
2216    });
2217
2218    // char_at - get character at byte index (safer than indexing)
2219    // Uses byte-based indexing to match self-hosted lexer's pos tracking
2220    define(interp, "char_at", Some(2), |_, args| {
2221        let s = match &args[0] {
2222            Value::String(s) => (**s).clone(),
2223            _ => {
2224                return Err(RuntimeError::new(
2225                    "char_at: first argument must be a string",
2226                ))
2227            }
2228        };
2229        let idx = match &args[1] {
2230            Value::Int(n) => *n,
2231            _ => {
2232                return Err(RuntimeError::new(
2233                    "char_at: second argument must be an integer",
2234                ))
2235            }
2236        };
2237        // Use byte-based indexing
2238        let actual_idx = if idx < 0 {
2239            // Negative indexing counts from end of string (in bytes)
2240            (s.len() as i64 + idx) as usize
2241        } else {
2242            idx as usize
2243        };
2244        if actual_idx < s.len() {
2245            let remaining = &s[actual_idx..];
2246            match remaining.chars().next() {
2247                Some(c) => Ok(Value::Char(c)),
2248                None => Ok(Value::Null),
2249            }
2250        } else {
2251            Ok(Value::Null)
2252        }
2253    });
2254
2255    // char_code_at - get Unicode code point at index
2256    define(interp, "char_code_at", Some(2), |_, args| {
2257        let s = match &args[0] {
2258            Value::String(s) => (**s).clone(),
2259            _ => {
2260                return Err(RuntimeError::new(
2261                    "char_code_at: first argument must be a string",
2262                ))
2263            }
2264        };
2265        let idx = match &args[1] {
2266            Value::Int(n) => *n,
2267            _ => {
2268                return Err(RuntimeError::new(
2269                    "char_code_at: second argument must be an integer",
2270                ))
2271            }
2272        };
2273        let chars: Vec<char> = s.chars().collect();
2274        let actual_idx = if idx < 0 {
2275            (chars.len() as i64 + idx) as usize
2276        } else {
2277            idx as usize
2278        };
2279        match chars.get(actual_idx) {
2280            Some(c) => Ok(Value::Int(*c as i64)),
2281            None => Ok(Value::Null),
2282        }
2283    });
2284
2285    // from_char_code - create string from Unicode code point
2286    define(interp, "from_char_code", Some(1), |_, args| {
2287        let code = match &args[0] {
2288            Value::Int(n) => *n as u32,
2289            _ => {
2290                return Err(RuntimeError::new(
2291                    "from_char_code: argument must be an integer",
2292                ))
2293            }
2294        };
2295        match char::from_u32(code) {
2296            Some(c) => Ok(Value::String(Rc::new(c.to_string()))),
2297            None => Err(RuntimeError::new(
2298                "from_char_code: invalid Unicode code point",
2299            )),
2300        }
2301    });
2302
2303    // insert - insert string at index
2304    define(interp, "insert", Some(3), |_, args| {
2305        let s = match &args[0] {
2306            Value::String(s) => (**s).clone(),
2307            _ => return Err(RuntimeError::new("insert: first argument must be a string")),
2308        };
2309        let idx = match &args[1] {
2310            Value::Int(n) if *n >= 0 => *n as usize,
2311            _ => {
2312                return Err(RuntimeError::new(
2313                    "insert: index must be a non-negative integer",
2314                ))
2315            }
2316        };
2317        let insertion = match &args[2] {
2318            Value::String(s) => (**s).clone(),
2319            _ => return Err(RuntimeError::new("insert: third argument must be a string")),
2320        };
2321        let chars: Vec<char> = s.chars().collect();
2322        let actual_idx = idx.min(chars.len());
2323        let mut result: String = chars[..actual_idx].iter().collect();
2324        result.push_str(&insertion);
2325        result.extend(chars[actual_idx..].iter());
2326        Ok(Value::String(Rc::new(result)))
2327    });
2328
2329    // remove - remove range from string
2330    define(interp, "remove", Some(3), |_, args| {
2331        let s = match &args[0] {
2332            Value::String(s) => (**s).clone(),
2333            _ => return Err(RuntimeError::new("remove: first argument must be a string")),
2334        };
2335        let start = match &args[1] {
2336            Value::Int(n) if *n >= 0 => *n as usize,
2337            _ => {
2338                return Err(RuntimeError::new(
2339                    "remove: start must be a non-negative integer",
2340                ))
2341            }
2342        };
2343        let len = match &args[2] {
2344            Value::Int(n) if *n >= 0 => *n as usize,
2345            _ => {
2346                return Err(RuntimeError::new(
2347                    "remove: length must be a non-negative integer",
2348                ))
2349            }
2350        };
2351        let chars: Vec<char> = s.chars().collect();
2352        let str_len = chars.len();
2353        let actual_start = start.min(str_len);
2354        let actual_end = (start + len).min(str_len);
2355        let mut result: String = chars[..actual_start].iter().collect();
2356        result.extend(chars[actual_end..].iter());
2357        Ok(Value::String(Rc::new(result)))
2358    });
2359
2360    // compare - compare two strings, returns -1, 0, or 1
2361    define(interp, "compare", Some(2), |_, args| {
2362        match (&args[0], &args[1]) {
2363            (Value::String(a), Value::String(b)) => {
2364                let result = match a.cmp(b) {
2365                    std::cmp::Ordering::Less => -1,
2366                    std::cmp::Ordering::Equal => 0,
2367                    std::cmp::Ordering::Greater => 1,
2368                };
2369                Ok(Value::Int(result))
2370            }
2371            _ => Err(RuntimeError::new("compare() requires two strings")),
2372        }
2373    });
2374
2375    // compare_ignore_case - case-insensitive comparison
2376    define(interp, "compare_ignore_case", Some(2), |_, args| {
2377        match (&args[0], &args[1]) {
2378            (Value::String(a), Value::String(b)) => {
2379                let result = match a.to_lowercase().cmp(&b.to_lowercase()) {
2380                    std::cmp::Ordering::Less => -1,
2381                    std::cmp::Ordering::Equal => 0,
2382                    std::cmp::Ordering::Greater => 1,
2383                };
2384                Ok(Value::Int(result))
2385            }
2386            _ => Err(RuntimeError::new(
2387                "compare_ignore_case() requires two strings",
2388            )),
2389        }
2390    });
2391
2392    // char_count - get character count (not byte length)
2393    define(interp, "char_count", Some(1), |_, args| match &args[0] {
2394        Value::String(s) => Ok(Value::Int(s.chars().count() as i64)),
2395        _ => Err(RuntimeError::new("char_count() requires string")),
2396    });
2397
2398    // byte_count - get byte length (for UTF-8 awareness)
2399    define(interp, "byte_count", Some(1), |_, args| match &args[0] {
2400        Value::String(s) => Ok(Value::Int(s.len() as i64)),
2401        _ => Err(RuntimeError::new("byte_count() requires string")),
2402    });
2403
2404    // is_empty - check if string is empty
2405    define(interp, "is_empty", Some(1), |_, args| match &args[0] {
2406        Value::String(s) => Ok(Value::Bool(s.is_empty())),
2407        Value::Array(arr) => Ok(Value::Bool(arr.borrow().is_empty())),
2408        _ => Err(RuntimeError::new("is_empty() requires string or array")),
2409    });
2410
2411    // is_blank - check if string is empty or only whitespace
2412    define(interp, "is_blank", Some(1), |_, args| match &args[0] {
2413        Value::String(s) => Ok(Value::Bool(s.trim().is_empty())),
2414        _ => Err(RuntimeError::new("is_blank() requires string")),
2415    });
2416
2417    // =========================================================================
2418    // UNICODE NORMALIZATION FUNCTIONS
2419    // =========================================================================
2420
2421    // nfc - Unicode Normalization Form C (Canonical Decomposition, followed by Canonical Composition)
2422    define(interp, "nfc", Some(1), |_, args| match &args[0] {
2423        Value::String(s) => Ok(Value::String(Rc::new(s.nfc().collect()))),
2424        _ => Err(RuntimeError::new("nfc() requires string")),
2425    });
2426
2427    // nfd - Unicode Normalization Form D (Canonical Decomposition)
2428    define(interp, "nfd", Some(1), |_, args| match &args[0] {
2429        Value::String(s) => Ok(Value::String(Rc::new(s.nfd().collect()))),
2430        _ => Err(RuntimeError::new("nfd() requires string")),
2431    });
2432
2433    // nfkc - Unicode Normalization Form KC (Compatibility Decomposition, followed by Canonical Composition)
2434    define(interp, "nfkc", Some(1), |_, args| match &args[0] {
2435        Value::String(s) => Ok(Value::String(Rc::new(s.nfkc().collect()))),
2436        _ => Err(RuntimeError::new("nfkc() requires string")),
2437    });
2438
2439    // nfkd - Unicode Normalization Form KD (Compatibility Decomposition)
2440    define(interp, "nfkd", Some(1), |_, args| match &args[0] {
2441        Value::String(s) => Ok(Value::String(Rc::new(s.nfkd().collect()))),
2442        _ => Err(RuntimeError::new("nfkd() requires string")),
2443    });
2444
2445    // is_nfc - check if string is in NFC form
2446    define(interp, "is_nfc", Some(1), |_, args| match &args[0] {
2447        Value::String(s) => {
2448            let normalized: String = s.nfc().collect();
2449            Ok(Value::Bool(*s.as_ref() == normalized))
2450        }
2451        _ => Err(RuntimeError::new("is_nfc() requires string")),
2452    });
2453
2454    // is_nfd - check if string is in NFD form
2455    define(interp, "is_nfd", Some(1), |_, args| match &args[0] {
2456        Value::String(s) => {
2457            let normalized: String = s.nfd().collect();
2458            Ok(Value::Bool(*s.as_ref() == normalized))
2459        }
2460        _ => Err(RuntimeError::new("is_nfd() requires string")),
2461    });
2462
2463    // =========================================================================
2464    // GRAPHEME CLUSTER FUNCTIONS
2465    // =========================================================================
2466
2467    // graphemes - split string into grapheme clusters (user-perceived characters)
2468    define(interp, "graphemes", Some(1), |_, args| match &args[0] {
2469        Value::String(s) => {
2470            let graphemes: Vec<Value> = s
2471                .graphemes(true)
2472                .map(|g| Value::String(Rc::new(g.to_string())))
2473                .collect();
2474            Ok(Value::Array(Rc::new(RefCell::new(graphemes))))
2475        }
2476        _ => Err(RuntimeError::new("graphemes() requires string")),
2477    });
2478
2479    // grapheme_count - count grapheme clusters (correct for emoji, combining chars, etc.)
2480    define(interp, "grapheme_count", Some(1), |_, args| {
2481        match &args[0] {
2482            Value::String(s) => Ok(Value::Int(s.graphemes(true).count() as i64)),
2483            _ => Err(RuntimeError::new("grapheme_count() requires string")),
2484        }
2485    });
2486
2487    // grapheme_at - get grapheme cluster at index
2488    define(interp, "grapheme_at", Some(2), |_, args| {
2489        let s = match &args[0] {
2490            Value::String(s) => (**s).clone(),
2491            _ => {
2492                return Err(RuntimeError::new(
2493                    "grapheme_at: first argument must be a string",
2494                ))
2495            }
2496        };
2497        let idx = match &args[1] {
2498            Value::Int(n) => *n,
2499            _ => {
2500                return Err(RuntimeError::new(
2501                    "grapheme_at: second argument must be an integer",
2502                ))
2503            }
2504        };
2505        let graphemes: Vec<&str> = s.graphemes(true).collect();
2506        let actual_idx = if idx < 0 {
2507            (graphemes.len() as i64 + idx) as usize
2508        } else {
2509            idx as usize
2510        };
2511        match graphemes.get(actual_idx) {
2512            Some(g) => Ok(Value::String(Rc::new(g.to_string()))),
2513            None => Ok(Value::Null),
2514        }
2515    });
2516
2517    // grapheme_slice - slice string by grapheme indices (proper Unicode slicing)
2518    define(interp, "grapheme_slice", Some(3), |_, args| {
2519        let s = match &args[0] {
2520            Value::String(s) => (**s).clone(),
2521            _ => {
2522                return Err(RuntimeError::new(
2523                    "grapheme_slice: first argument must be a string",
2524                ))
2525            }
2526        };
2527        let start = match &args[1] {
2528            Value::Int(n) if *n >= 0 => *n as usize,
2529            _ => {
2530                return Err(RuntimeError::new(
2531                    "grapheme_slice: start must be a non-negative integer",
2532                ))
2533            }
2534        };
2535        let end = match &args[2] {
2536            Value::Int(n) if *n >= 0 => *n as usize,
2537            _ => {
2538                return Err(RuntimeError::new(
2539                    "grapheme_slice: end must be a non-negative integer",
2540                ))
2541            }
2542        };
2543        let graphemes: Vec<&str> = s.graphemes(true).collect();
2544        let len = graphemes.len();
2545        let actual_start = start.min(len);
2546        let actual_end = end.min(len);
2547        if actual_start >= actual_end {
2548            return Ok(Value::String(Rc::new(String::new())));
2549        }
2550        let result: String = graphemes[actual_start..actual_end].join("");
2551        Ok(Value::String(Rc::new(result)))
2552    });
2553
2554    // grapheme_reverse - reverse string by grapheme clusters (correct for emoji, etc.)
2555    define(interp, "grapheme_reverse", Some(1), |_, args| {
2556        match &args[0] {
2557            Value::String(s) => {
2558                let reversed: String = s.graphemes(true).rev().collect();
2559                Ok(Value::String(Rc::new(reversed)))
2560            }
2561            _ => Err(RuntimeError::new("grapheme_reverse() requires string")),
2562        }
2563    });
2564
2565    // word_indices - get word boundaries
2566    define(interp, "word_boundaries", Some(1), |_, args| {
2567        match &args[0] {
2568            Value::String(s) => {
2569                let words: Vec<Value> = s
2570                    .unicode_words()
2571                    .map(|w| Value::String(Rc::new(w.to_string())))
2572                    .collect();
2573                Ok(Value::Array(Rc::new(RefCell::new(words))))
2574            }
2575            _ => Err(RuntimeError::new("word_boundaries() requires string")),
2576        }
2577    });
2578
2579    // =========================================================================
2580    // STRING BUILDER
2581    // =========================================================================
2582
2583    // string_builder - create a new string builder (just returns empty string for now,
2584    // operations can be chained with concat)
2585    define(interp, "string_builder", Some(0), |_, _| {
2586        Ok(Value::String(Rc::new(String::new())))
2587    });
2588
2589    // concat_all - concatenate array of strings efficiently
2590    define(interp, "concat_all", Some(1), |_, args| match &args[0] {
2591        Value::Array(arr) => {
2592            let parts: Vec<String> = arr
2593                .borrow()
2594                .iter()
2595                .map(|v| match v {
2596                    Value::String(s) => (**s).clone(),
2597                    other => format!("{}", other),
2598                })
2599                .collect();
2600            Ok(Value::String(Rc::new(parts.join(""))))
2601        }
2602        _ => Err(RuntimeError::new("concat_all() requires array")),
2603    });
2604
2605    // repeat_join - repeat a string n times with a separator
2606    define(interp, "repeat_join", Some(3), |_, args| {
2607        let s = match &args[0] {
2608            Value::String(s) => (**s).clone(),
2609            _ => {
2610                return Err(RuntimeError::new(
2611                    "repeat_join: first argument must be a string",
2612                ))
2613            }
2614        };
2615        let n = match &args[1] {
2616            Value::Int(n) if *n >= 0 => *n as usize,
2617            _ => {
2618                return Err(RuntimeError::new(
2619                    "repeat_join: count must be a non-negative integer",
2620                ))
2621            }
2622        };
2623        let sep = match &args[2] {
2624            Value::String(s) => (**s).clone(),
2625            _ => return Err(RuntimeError::new("repeat_join: separator must be a string")),
2626        };
2627        if n == 0 {
2628            return Ok(Value::String(Rc::new(String::new())));
2629        }
2630        let parts: Vec<&str> = std::iter::repeat(s.as_str()).take(n).collect();
2631        Ok(Value::String(Rc::new(parts.join(&sep))))
2632    });
2633}
2634
2635// ============================================================================
2636// EVIDENCE FUNCTIONS
2637// ============================================================================
2638
2639fn register_evidence(interp: &mut Interpreter) {
2640    use crate::interpreter::RuntimeConfidence;
2641
2642    // Create evidential values
2643    define(interp, "known", Some(1), |_, args| {
2644        Ok(Value::Evidential {
2645            value: Box::new(args[0].clone()),
2646            evidence: Evidence::Known,
2647        })
2648    });
2649
2650    define(interp, "uncertain", Some(1), |_, args| {
2651        Ok(Value::Evidential {
2652            value: Box::new(args[0].clone()),
2653            evidence: Evidence::Uncertain,
2654        })
2655    });
2656
2657    define(interp, "reported", Some(1), |_, args| {
2658        Ok(Value::Evidential {
2659            value: Box::new(args[0].clone()),
2660            evidence: Evidence::Reported,
2661        })
2662    });
2663
2664    define(interp, "paradox", Some(1), |_, args| {
2665        Ok(Value::Evidential {
2666            value: Box::new(args[0].clone()),
2667            evidence: Evidence::Paradox,
2668        })
2669    });
2670
2671    // Query evidence
2672    define(interp, "evidence_of", Some(1), |_, args| {
2673        match &args[0] {
2674            Value::Evidential { evidence, .. } => {
2675                let level = match evidence {
2676                    Evidence::Known => "known",
2677                    Evidence::Uncertain => "uncertain",
2678                    Evidence::Reported => "reported",
2679                    Evidence::Paradox => "paradox",
2680                };
2681                Ok(Value::String(Rc::new(level.to_string())))
2682            }
2683            _ => Ok(Value::String(Rc::new("known".to_string()))), // Non-evidential values are known
2684        }
2685    });
2686
2687    define(interp, "is_known", Some(1), |_, args| {
2688        match &args[0] {
2689            Value::Evidential {
2690                evidence: Evidence::Known,
2691                ..
2692            } => Ok(Value::Bool(true)),
2693            Value::Evidential { .. } => Ok(Value::Bool(false)),
2694            _ => Ok(Value::Bool(true)), // Non-evidential values are known
2695        }
2696    });
2697
2698    define(interp, "is_uncertain", Some(1), |_, args| match &args[0] {
2699        Value::Evidential {
2700            evidence: Evidence::Uncertain,
2701            ..
2702        } => Ok(Value::Bool(true)),
2703        _ => Ok(Value::Bool(false)),
2704    });
2705
2706    define(interp, "is_reported", Some(1), |_, args| match &args[0] {
2707        Value::Evidential {
2708            evidence: Evidence::Reported,
2709            ..
2710        } => Ok(Value::Bool(true)),
2711        _ => Ok(Value::Bool(false)),
2712    });
2713
2714    define(interp, "is_paradox", Some(1), |_, args| match &args[0] {
2715        Value::Evidential {
2716            evidence: Evidence::Paradox,
2717            ..
2718        } => Ok(Value::Bool(true)),
2719        _ => Ok(Value::Bool(false)),
2720    });
2721
2722    // Extract inner value
2723    define(interp, "strip_evidence", Some(1), |_, args| {
2724        match &args[0] {
2725            Value::Evidential { value, .. } => Ok(*value.clone()),
2726            other => Ok(other.clone()),
2727        }
2728    });
2729
2730    // Trust operations
2731    define(interp, "trust", Some(1), |_, args| {
2732        // Upgrade reported/uncertain to known (with assertion)
2733        match &args[0] {
2734            Value::Evidential { value, .. } => Ok(Value::Evidential {
2735                value: value.clone(),
2736                evidence: Evidence::Known,
2737            }),
2738            other => Ok(other.clone()),
2739        }
2740    });
2741
2742    define(interp, "verify", Some(2), |_, args| {
2743        // Verify evidential value with predicate, upgrading if true
2744        let pred_result = match &args[1] {
2745            Value::Bool(b) => *b,
2746            _ => return Err(RuntimeError::new("verify() predicate must be bool")),
2747        };
2748
2749        if pred_result {
2750            match &args[0] {
2751                Value::Evidential { value, .. } => Ok(Value::Evidential {
2752                    value: value.clone(),
2753                    evidence: Evidence::Known,
2754                }),
2755                other => Ok(other.clone()),
2756            }
2757        } else {
2758            Ok(args[0].clone()) // Keep original evidence
2759        }
2760    });
2761
2762    // Combine evidence (join in lattice)
2763    define(interp, "combine_evidence", Some(2), |_, args| {
2764        let ev1 = match &args[0] {
2765            Value::Evidential { evidence, .. } => *evidence,
2766            _ => Evidence::Known,
2767        };
2768        let ev2 = match &args[1] {
2769            Value::Evidential { evidence, .. } => *evidence,
2770            _ => Evidence::Known,
2771        };
2772
2773        // Join: max of the two
2774        let combined = match (ev1, ev2) {
2775            (Evidence::Paradox, _) | (_, Evidence::Paradox) => Evidence::Paradox,
2776            (Evidence::Reported, _) | (_, Evidence::Reported) => Evidence::Reported,
2777            (Evidence::Uncertain, _) | (_, Evidence::Uncertain) => Evidence::Uncertain,
2778            _ => Evidence::Known,
2779        };
2780
2781        Ok(Value::String(Rc::new(
2782            match combined {
2783                Evidence::Known => "known",
2784                Evidence::Uncertain => "uncertain",
2785                Evidence::Reported => "reported",
2786                Evidence::Paradox => "paradox",
2787            }
2788            .to_string(),
2789        )))
2790    });
2791
2792    // === Affect-Evidence Integration ===
2793
2794    // Derive evidence from affect markers
2795    define(interp, "affect_to_evidence", Some(1), |_, args| {
2796        match &args[0] {
2797            Value::Affective { affect, .. } => {
2798                // Sarcasm implies uncertainty (meaning is inverted)
2799                if affect.sarcasm {
2800                    return Ok(Value::String(Rc::new("uncertain".to_string())));
2801                }
2802                // Confidence maps to evidence
2803                match affect.confidence {
2804                    Some(RuntimeConfidence::High) => {
2805                        Ok(Value::String(Rc::new("known".to_string())))
2806                    }
2807                    Some(RuntimeConfidence::Low) => {
2808                        Ok(Value::String(Rc::new("uncertain".to_string())))
2809                    }
2810                    _ => Ok(Value::String(Rc::new("known".to_string()))),
2811                }
2812            }
2813            _ => Ok(Value::String(Rc::new("known".to_string()))),
2814        }
2815    });
2816
2817    // Convert affective value to evidential based on affect markers
2818    define(
2819        interp,
2820        "affect_as_evidence",
2821        Some(1),
2822        |_, args| match &args[0] {
2823            Value::Affective { value, affect } => {
2824                let evidence = if affect.sarcasm {
2825                    Evidence::Uncertain
2826                } else {
2827                    match affect.confidence {
2828                        Some(RuntimeConfidence::High) => Evidence::Known,
2829                        Some(RuntimeConfidence::Low) => Evidence::Uncertain,
2830                        _ => Evidence::Known,
2831                    }
2832                };
2833                Ok(Value::Evidential {
2834                    value: value.clone(),
2835                    evidence,
2836                })
2837            }
2838            other => Ok(other.clone()),
2839        },
2840    );
2841
2842    // Check if affective value implies uncertainty
2843    define(
2844        interp,
2845        "is_affect_uncertain",
2846        Some(1),
2847        |_, args| match &args[0] {
2848            Value::Affective { affect, .. } => {
2849                let uncertain =
2850                    affect.sarcasm || matches!(affect.confidence, Some(RuntimeConfidence::Low));
2851                Ok(Value::Bool(uncertain))
2852            }
2853            _ => Ok(Value::Bool(false)),
2854        },
2855    );
2856
2857    // Combine affect and evidence (wrap evidential in affect or vice versa)
2858    define(interp, "with_affect_evidence", Some(2), |_, args| {
2859        // args[0] = affect source, args[1] = value to wrap
2860        match &args[0] {
2861            Value::Affective { affect, .. } => {
2862                let evidence = if affect.sarcasm {
2863                    Evidence::Uncertain
2864                } else {
2865                    match affect.confidence {
2866                        Some(RuntimeConfidence::High) => Evidence::Known,
2867                        Some(RuntimeConfidence::Low) => Evidence::Uncertain,
2868                        _ => Evidence::Known,
2869                    }
2870                };
2871                Ok(Value::Evidential {
2872                    value: Box::new(args[1].clone()),
2873                    evidence,
2874                })
2875            }
2876            Value::Evidential { evidence, .. } => {
2877                // Preserve evidence on the new value
2878                Ok(Value::Evidential {
2879                    value: Box::new(args[1].clone()),
2880                    evidence: *evidence,
2881                })
2882            }
2883            _ => Ok(args[1].clone()),
2884        }
2885    });
2886}
2887
2888// ============================================================================
2889// AFFECT FUNCTIONS (Sentiment, Emotion, Sarcasm markers)
2890// ============================================================================
2891
2892fn register_affect(interp: &mut Interpreter) {
2893    use crate::interpreter::{
2894        RuntimeAffect, RuntimeConfidence, RuntimeEmotion, RuntimeFormality, RuntimeIntensity,
2895        RuntimeSentiment,
2896    };
2897
2898    // === Create affective values ===
2899
2900    // Sentiment markers
2901    define(interp, "positive", Some(1), |_, args| {
2902        Ok(Value::Affective {
2903            value: Box::new(args[0].clone()),
2904            affect: RuntimeAffect {
2905                sentiment: Some(RuntimeSentiment::Positive),
2906                sarcasm: false,
2907                intensity: None,
2908                formality: None,
2909                emotion: None,
2910                confidence: None,
2911            },
2912        })
2913    });
2914
2915    define(interp, "negative", Some(1), |_, args| {
2916        Ok(Value::Affective {
2917            value: Box::new(args[0].clone()),
2918            affect: RuntimeAffect {
2919                sentiment: Some(RuntimeSentiment::Negative),
2920                sarcasm: false,
2921                intensity: None,
2922                formality: None,
2923                emotion: None,
2924                confidence: None,
2925            },
2926        })
2927    });
2928
2929    define(interp, "neutral", Some(1), |_, args| {
2930        Ok(Value::Affective {
2931            value: Box::new(args[0].clone()),
2932            affect: RuntimeAffect {
2933                sentiment: Some(RuntimeSentiment::Neutral),
2934                sarcasm: false,
2935                intensity: None,
2936                formality: None,
2937                emotion: None,
2938                confidence: None,
2939            },
2940        })
2941    });
2942
2943    // Sarcasm marker
2944    define(interp, "sarcastic", Some(1), |_, args| {
2945        Ok(Value::Affective {
2946            value: Box::new(args[0].clone()),
2947            affect: RuntimeAffect {
2948                sentiment: None,
2949                sarcasm: true,
2950                intensity: None,
2951                formality: None,
2952                emotion: None,
2953                confidence: None,
2954            },
2955        })
2956    });
2957
2958    // Intensity markers
2959    define(interp, "intensify", Some(1), |_, args| {
2960        Ok(Value::Affective {
2961            value: Box::new(args[0].clone()),
2962            affect: RuntimeAffect {
2963                sentiment: None,
2964                sarcasm: false,
2965                intensity: Some(RuntimeIntensity::Up),
2966                formality: None,
2967                emotion: None,
2968                confidence: None,
2969            },
2970        })
2971    });
2972
2973    define(interp, "dampen", Some(1), |_, args| {
2974        Ok(Value::Affective {
2975            value: Box::new(args[0].clone()),
2976            affect: RuntimeAffect {
2977                sentiment: None,
2978                sarcasm: false,
2979                intensity: Some(RuntimeIntensity::Down),
2980                formality: None,
2981                emotion: None,
2982                confidence: None,
2983            },
2984        })
2985    });
2986
2987    define(interp, "maximize", Some(1), |_, args| {
2988        Ok(Value::Affective {
2989            value: Box::new(args[0].clone()),
2990            affect: RuntimeAffect {
2991                sentiment: None,
2992                sarcasm: false,
2993                intensity: Some(RuntimeIntensity::Max),
2994                formality: None,
2995                emotion: None,
2996                confidence: None,
2997            },
2998        })
2999    });
3000
3001    // Formality markers
3002    define(interp, "formal", Some(1), |_, args| {
3003        Ok(Value::Affective {
3004            value: Box::new(args[0].clone()),
3005            affect: RuntimeAffect {
3006                sentiment: None,
3007                sarcasm: false,
3008                intensity: None,
3009                formality: Some(RuntimeFormality::Formal),
3010                emotion: None,
3011                confidence: None,
3012            },
3013        })
3014    });
3015
3016    define(interp, "informal", Some(1), |_, args| {
3017        Ok(Value::Affective {
3018            value: Box::new(args[0].clone()),
3019            affect: RuntimeAffect {
3020                sentiment: None,
3021                sarcasm: false,
3022                intensity: None,
3023                formality: Some(RuntimeFormality::Informal),
3024                emotion: None,
3025                confidence: None,
3026            },
3027        })
3028    });
3029
3030    // Emotion markers (Plutchik's wheel)
3031    define(interp, "joyful", Some(1), |_, args| {
3032        Ok(Value::Affective {
3033            value: Box::new(args[0].clone()),
3034            affect: RuntimeAffect {
3035                sentiment: None,
3036                sarcasm: false,
3037                intensity: None,
3038                formality: None,
3039                emotion: Some(RuntimeEmotion::Joy),
3040                confidence: None,
3041            },
3042        })
3043    });
3044
3045    define(interp, "sad", Some(1), |_, args| {
3046        Ok(Value::Affective {
3047            value: Box::new(args[0].clone()),
3048            affect: RuntimeAffect {
3049                sentiment: None,
3050                sarcasm: false,
3051                intensity: None,
3052                formality: None,
3053                emotion: Some(RuntimeEmotion::Sadness),
3054                confidence: None,
3055            },
3056        })
3057    });
3058
3059    define(interp, "angry", Some(1), |_, args| {
3060        Ok(Value::Affective {
3061            value: Box::new(args[0].clone()),
3062            affect: RuntimeAffect {
3063                sentiment: None,
3064                sarcasm: false,
3065                intensity: None,
3066                formality: None,
3067                emotion: Some(RuntimeEmotion::Anger),
3068                confidence: None,
3069            },
3070        })
3071    });
3072
3073    define(interp, "fearful", Some(1), |_, args| {
3074        Ok(Value::Affective {
3075            value: Box::new(args[0].clone()),
3076            affect: RuntimeAffect {
3077                sentiment: None,
3078                sarcasm: false,
3079                intensity: None,
3080                formality: None,
3081                emotion: Some(RuntimeEmotion::Fear),
3082                confidence: None,
3083            },
3084        })
3085    });
3086
3087    define(interp, "surprised", Some(1), |_, args| {
3088        Ok(Value::Affective {
3089            value: Box::new(args[0].clone()),
3090            affect: RuntimeAffect {
3091                sentiment: None,
3092                sarcasm: false,
3093                intensity: None,
3094                formality: None,
3095                emotion: Some(RuntimeEmotion::Surprise),
3096                confidence: None,
3097            },
3098        })
3099    });
3100
3101    define(interp, "loving", Some(1), |_, args| {
3102        Ok(Value::Affective {
3103            value: Box::new(args[0].clone()),
3104            affect: RuntimeAffect {
3105                sentiment: None,
3106                sarcasm: false,
3107                intensity: None,
3108                formality: None,
3109                emotion: Some(RuntimeEmotion::Love),
3110                confidence: None,
3111            },
3112        })
3113    });
3114
3115    // Confidence markers
3116    define(interp, "high_confidence", Some(1), |_, args| {
3117        Ok(Value::Affective {
3118            value: Box::new(args[0].clone()),
3119            affect: RuntimeAffect {
3120                sentiment: None,
3121                sarcasm: false,
3122                intensity: None,
3123                formality: None,
3124                emotion: None,
3125                confidence: Some(RuntimeConfidence::High),
3126            },
3127        })
3128    });
3129
3130    define(interp, "medium_confidence", Some(1), |_, args| {
3131        Ok(Value::Affective {
3132            value: Box::new(args[0].clone()),
3133            affect: RuntimeAffect {
3134                sentiment: None,
3135                sarcasm: false,
3136                intensity: None,
3137                formality: None,
3138                emotion: None,
3139                confidence: Some(RuntimeConfidence::Medium),
3140            },
3141        })
3142    });
3143
3144    define(interp, "low_confidence", Some(1), |_, args| {
3145        Ok(Value::Affective {
3146            value: Box::new(args[0].clone()),
3147            affect: RuntimeAffect {
3148                sentiment: None,
3149                sarcasm: false,
3150                intensity: None,
3151                formality: None,
3152                emotion: None,
3153                confidence: Some(RuntimeConfidence::Low),
3154            },
3155        })
3156    });
3157
3158    // === Query affect ===
3159
3160    define(interp, "affect_of", Some(1), |_, args| match &args[0] {
3161        Value::Affective { affect, .. } => {
3162            let mut parts = Vec::new();
3163            if let Some(s) = &affect.sentiment {
3164                parts.push(match s {
3165                    RuntimeSentiment::Positive => "positive",
3166                    RuntimeSentiment::Negative => "negative",
3167                    RuntimeSentiment::Neutral => "neutral",
3168                });
3169            }
3170            if affect.sarcasm {
3171                parts.push("sarcastic");
3172            }
3173            if let Some(i) = &affect.intensity {
3174                parts.push(match i {
3175                    RuntimeIntensity::Up => "intensified",
3176                    RuntimeIntensity::Down => "dampened",
3177                    RuntimeIntensity::Max => "maximized",
3178                });
3179            }
3180            if let Some(f) = &affect.formality {
3181                parts.push(match f {
3182                    RuntimeFormality::Formal => "formal",
3183                    RuntimeFormality::Informal => "informal",
3184                });
3185            }
3186            if let Some(e) = &affect.emotion {
3187                parts.push(match e {
3188                    RuntimeEmotion::Joy => "joyful",
3189                    RuntimeEmotion::Sadness => "sad",
3190                    RuntimeEmotion::Anger => "angry",
3191                    RuntimeEmotion::Fear => "fearful",
3192                    RuntimeEmotion::Surprise => "surprised",
3193                    RuntimeEmotion::Love => "loving",
3194                });
3195            }
3196            if let Some(c) = &affect.confidence {
3197                parts.push(match c {
3198                    RuntimeConfidence::High => "high_confidence",
3199                    RuntimeConfidence::Medium => "medium_confidence",
3200                    RuntimeConfidence::Low => "low_confidence",
3201                });
3202            }
3203            Ok(Value::String(Rc::new(parts.join(", "))))
3204        }
3205        _ => Ok(Value::String(Rc::new("none".to_string()))),
3206    });
3207
3208    define(interp, "is_sarcastic", Some(1), |_, args| match &args[0] {
3209        Value::Affective { affect, .. } => Ok(Value::Bool(affect.sarcasm)),
3210        _ => Ok(Value::Bool(false)),
3211    });
3212
3213    define(interp, "is_positive", Some(1), |_, args| match &args[0] {
3214        Value::Affective { affect, .. } => Ok(Value::Bool(matches!(
3215            affect.sentiment,
3216            Some(RuntimeSentiment::Positive)
3217        ))),
3218        _ => Ok(Value::Bool(false)),
3219    });
3220
3221    define(interp, "is_negative", Some(1), |_, args| match &args[0] {
3222        Value::Affective { affect, .. } => Ok(Value::Bool(matches!(
3223            affect.sentiment,
3224            Some(RuntimeSentiment::Negative)
3225        ))),
3226        _ => Ok(Value::Bool(false)),
3227    });
3228
3229    define(interp, "is_formal", Some(1), |_, args| match &args[0] {
3230        Value::Affective { affect, .. } => Ok(Value::Bool(matches!(
3231            affect.formality,
3232            Some(RuntimeFormality::Formal)
3233        ))),
3234        _ => Ok(Value::Bool(false)),
3235    });
3236
3237    define(interp, "is_informal", Some(1), |_, args| match &args[0] {
3238        Value::Affective { affect, .. } => Ok(Value::Bool(matches!(
3239            affect.formality,
3240            Some(RuntimeFormality::Informal)
3241        ))),
3242        _ => Ok(Value::Bool(false)),
3243    });
3244
3245    define(interp, "emotion_of", Some(1), |_, args| match &args[0] {
3246        Value::Affective { affect, .. } => {
3247            let emotion_str = match &affect.emotion {
3248                Some(RuntimeEmotion::Joy) => "joy",
3249                Some(RuntimeEmotion::Sadness) => "sadness",
3250                Some(RuntimeEmotion::Anger) => "anger",
3251                Some(RuntimeEmotion::Fear) => "fear",
3252                Some(RuntimeEmotion::Surprise) => "surprise",
3253                Some(RuntimeEmotion::Love) => "love",
3254                None => "none",
3255            };
3256            Ok(Value::String(Rc::new(emotion_str.to_string())))
3257        }
3258        _ => Ok(Value::String(Rc::new("none".to_string()))),
3259    });
3260
3261    define(interp, "confidence_of", Some(1), |_, args| match &args[0] {
3262        Value::Affective { affect, .. } => {
3263            let conf_str = match &affect.confidence {
3264                Some(RuntimeConfidence::High) => "high",
3265                Some(RuntimeConfidence::Medium) => "medium",
3266                Some(RuntimeConfidence::Low) => "low",
3267                None => "none",
3268            };
3269            Ok(Value::String(Rc::new(conf_str.to_string())))
3270        }
3271        _ => Ok(Value::String(Rc::new("none".to_string()))),
3272    });
3273
3274    // Extract inner value
3275    define(interp, "strip_affect", Some(1), |_, args| match &args[0] {
3276        Value::Affective { value, .. } => Ok(*value.clone()),
3277        other => Ok(other.clone()),
3278    });
3279
3280    // Create full affect with multiple markers
3281    define(interp, "with_affect", None, |_, args| {
3282        if args.is_empty() {
3283            return Err(RuntimeError::new(
3284                "with_affect requires at least one argument",
3285            ));
3286        }
3287
3288        let base_value = args[0].clone();
3289        let mut affect = RuntimeAffect {
3290            sentiment: None,
3291            sarcasm: false,
3292            intensity: None,
3293            formality: None,
3294            emotion: None,
3295            confidence: None,
3296        };
3297
3298        // Parse string markers from remaining args
3299        for arg in args.iter().skip(1) {
3300            if let Value::String(s) = arg {
3301                match s.as_str() {
3302                    "positive" | "⊕" => affect.sentiment = Some(RuntimeSentiment::Positive),
3303                    "negative" | "⊖" => affect.sentiment = Some(RuntimeSentiment::Negative),
3304                    "neutral" | "⊜" => affect.sentiment = Some(RuntimeSentiment::Neutral),
3305                    "sarcastic" | "⸮" => affect.sarcasm = true,
3306                    "intensify" | "↑" => affect.intensity = Some(RuntimeIntensity::Up),
3307                    "dampen" | "↓" => affect.intensity = Some(RuntimeIntensity::Down),
3308                    "maximize" | "⇈" => affect.intensity = Some(RuntimeIntensity::Max),
3309                    "formal" | "♔" => affect.formality = Some(RuntimeFormality::Formal),
3310                    "informal" | "♟" => affect.formality = Some(RuntimeFormality::Informal),
3311                    "joy" | "☺" => affect.emotion = Some(RuntimeEmotion::Joy),
3312                    "sadness" | "☹" => affect.emotion = Some(RuntimeEmotion::Sadness),
3313                    "anger" | "⚡" => affect.emotion = Some(RuntimeEmotion::Anger),
3314                    "fear" | "❄" => affect.emotion = Some(RuntimeEmotion::Fear),
3315                    "surprise" | "✦" => affect.emotion = Some(RuntimeEmotion::Surprise),
3316                    "love" | "♡" => affect.emotion = Some(RuntimeEmotion::Love),
3317                    "high" | "◉" => affect.confidence = Some(RuntimeConfidence::High),
3318                    "medium" | "◎" => affect.confidence = Some(RuntimeConfidence::Medium),
3319                    "low" | "○" => affect.confidence = Some(RuntimeConfidence::Low),
3320                    _ => {}
3321                }
3322            }
3323        }
3324
3325        Ok(Value::Affective {
3326            value: Box::new(base_value),
3327            affect,
3328        })
3329    });
3330}
3331
3332// ============================================================================
3333// ITERATOR-STYLE FUNCTIONS (for use in pipes)
3334// ============================================================================
3335
3336fn register_iter(interp: &mut Interpreter) {
3337    // sum - sum all elements
3338    define(interp, "sum", Some(1), |_, args| match &args[0] {
3339        Value::Array(arr) => {
3340            let mut sum_int: i64 = 0;
3341            let mut sum_float: f64 = 0.0;
3342            let mut is_float = false;
3343
3344            for val in arr.borrow().iter() {
3345                match val {
3346                    Value::Int(n) => {
3347                        if is_float {
3348                            sum_float += *n as f64;
3349                        } else {
3350                            sum_int += n;
3351                        }
3352                    }
3353                    Value::Float(n) => {
3354                        if !is_float {
3355                            sum_float = sum_int as f64;
3356                            is_float = true;
3357                        }
3358                        sum_float += n;
3359                    }
3360                    _ => return Err(RuntimeError::new("sum() requires array of numbers")),
3361                }
3362            }
3363
3364            if is_float {
3365                Ok(Value::Float(sum_float))
3366            } else {
3367                Ok(Value::Int(sum_int))
3368            }
3369        }
3370        _ => Err(RuntimeError::new("sum() requires array")),
3371    });
3372
3373    // product - multiply all elements
3374    define(interp, "product", Some(1), |_, args| match &args[0] {
3375        Value::Array(arr) => {
3376            let mut prod_int: i64 = 1;
3377            let mut prod_float: f64 = 1.0;
3378            let mut is_float = false;
3379
3380            for val in arr.borrow().iter() {
3381                match val {
3382                    Value::Int(n) => {
3383                        if is_float {
3384                            prod_float *= *n as f64;
3385                        } else {
3386                            prod_int *= n;
3387                        }
3388                    }
3389                    Value::Float(n) => {
3390                        if !is_float {
3391                            prod_float = prod_int as f64;
3392                            is_float = true;
3393                        }
3394                        prod_float *= n;
3395                    }
3396                    _ => return Err(RuntimeError::new("product() requires array of numbers")),
3397                }
3398            }
3399
3400            if is_float {
3401                Ok(Value::Float(prod_float))
3402            } else {
3403                Ok(Value::Int(prod_int))
3404            }
3405        }
3406        _ => Err(RuntimeError::new("product() requires array")),
3407    });
3408
3409    // mean - average of elements
3410    define(interp, "mean", Some(1), |_, args| match &args[0] {
3411        Value::Array(arr) => {
3412            let arr = arr.borrow();
3413            if arr.is_empty() {
3414                return Err(RuntimeError::new("mean() on empty array"));
3415            }
3416
3417            let mut sum: f64 = 0.0;
3418            for val in arr.iter() {
3419                match val {
3420                    Value::Int(n) => sum += *n as f64,
3421                    Value::Float(n) => sum += n,
3422                    _ => return Err(RuntimeError::new("mean() requires array of numbers")),
3423                }
3424            }
3425
3426            Ok(Value::Float(sum / arr.len() as f64))
3427        }
3428        _ => Err(RuntimeError::new("mean() requires array")),
3429    });
3430
3431    // median - middle value
3432    define(interp, "median", Some(1), |_, args| match &args[0] {
3433        Value::Array(arr) => {
3434            let arr = arr.borrow();
3435            if arr.is_empty() {
3436                return Err(RuntimeError::new("median() on empty array"));
3437            }
3438
3439            let mut nums: Vec<f64> = Vec::new();
3440            for val in arr.iter() {
3441                match val {
3442                    Value::Int(n) => nums.push(*n as f64),
3443                    Value::Float(n) => nums.push(*n),
3444                    _ => return Err(RuntimeError::new("median() requires array of numbers")),
3445                }
3446            }
3447
3448            nums.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
3449            let mid = nums.len() / 2;
3450
3451            if nums.len() % 2 == 0 {
3452                Ok(Value::Float((nums[mid - 1] + nums[mid]) / 2.0))
3453            } else {
3454                Ok(Value::Float(nums[mid]))
3455            }
3456        }
3457        _ => Err(RuntimeError::new("median() requires array")),
3458    });
3459
3460    // min_of - minimum of array
3461    define(interp, "min_of", Some(1), |_, args| match &args[0] {
3462        Value::Array(arr) => {
3463            let arr = arr.borrow();
3464            if arr.is_empty() {
3465                return Err(RuntimeError::new("min_of() on empty array"));
3466            }
3467
3468            let mut min = &arr[0];
3469            for val in arr.iter().skip(1) {
3470                if matches!(compare_values(val, min), std::cmp::Ordering::Less) {
3471                    min = val;
3472                }
3473            }
3474            Ok(min.clone())
3475        }
3476        _ => Err(RuntimeError::new("min_of() requires array")),
3477    });
3478
3479    // max_of - maximum of array
3480    define(interp, "max_of", Some(1), |_, args| match &args[0] {
3481        Value::Array(arr) => {
3482            let arr = arr.borrow();
3483            if arr.is_empty() {
3484                return Err(RuntimeError::new("max_of() on empty array"));
3485            }
3486
3487            let mut max = &arr[0];
3488            for val in arr.iter().skip(1) {
3489                if matches!(compare_values(val, max), std::cmp::Ordering::Greater) {
3490                    max = val;
3491                }
3492            }
3493            Ok(max.clone())
3494        }
3495        _ => Err(RuntimeError::new("max_of() requires array")),
3496    });
3497
3498    // count - count elements (optionally matching predicate)
3499    define(interp, "count", Some(1), |_, args| match &args[0] {
3500        Value::Array(arr) => Ok(Value::Int(arr.borrow().len() as i64)),
3501        Value::String(s) => Ok(Value::Int(s.chars().count() as i64)),
3502        _ => Err(RuntimeError::new("count() requires array or string")),
3503    });
3504
3505    // any - check if any element is truthy
3506    define(interp, "any", Some(1), |_, args| match &args[0] {
3507        Value::Array(arr) => {
3508            for val in arr.borrow().iter() {
3509                if is_truthy(val) {
3510                    return Ok(Value::Bool(true));
3511                }
3512            }
3513            Ok(Value::Bool(false))
3514        }
3515        _ => Err(RuntimeError::new("any() requires array")),
3516    });
3517
3518    // all - check if all elements are truthy
3519    define(interp, "all", Some(1), |_, args| match &args[0] {
3520        Value::Array(arr) => {
3521            for val in arr.borrow().iter() {
3522                if !is_truthy(val) {
3523                    return Ok(Value::Bool(false));
3524                }
3525            }
3526            Ok(Value::Bool(true))
3527        }
3528        _ => Err(RuntimeError::new("all() requires array")),
3529    });
3530
3531    // none - check if no elements are truthy
3532    define(interp, "none", Some(1), |_, args| match &args[0] {
3533        Value::Array(arr) => {
3534            for val in arr.borrow().iter() {
3535                if is_truthy(val) {
3536                    return Ok(Value::Bool(false));
3537                }
3538            }
3539            Ok(Value::Bool(true))
3540        }
3541        _ => Err(RuntimeError::new("none() requires array")),
3542    });
3543}
3544
3545fn is_truthy(val: &Value) -> bool {
3546    match val {
3547        Value::Null | Value::Empty => false,
3548        Value::Bool(b) => *b,
3549        Value::Int(n) => *n != 0,
3550        Value::Float(n) => *n != 0.0 && !n.is_nan(),
3551        Value::String(s) => !s.is_empty(),
3552        Value::Array(arr) => !arr.borrow().is_empty(),
3553        Value::Evidential { value, .. } => is_truthy(value),
3554        _ => true,
3555    }
3556}
3557
3558// ============================================================================
3559// I/O FUNCTIONS
3560// ============================================================================
3561
3562fn register_io(interp: &mut Interpreter) {
3563    // read_file - read entire file as string
3564    define(interp, "read_file", Some(1), |_, args| {
3565        match &args[0] {
3566            Value::String(path) => {
3567                match std::fs::read_to_string(path.as_str()) {
3568                    Ok(content) => Ok(Value::Evidential {
3569                        value: Box::new(Value::String(Rc::new(content))),
3570                        evidence: Evidence::Reported, // File contents are reported, not known
3571                    }),
3572                    Err(e) => Err(RuntimeError::new(format!("read_file failed: {}", e))),
3573                }
3574            }
3575            _ => Err(RuntimeError::new("read_file() requires path string")),
3576        }
3577    });
3578
3579    // write_file - write string to file
3580    define(interp, "write_file", Some(2), |_, args| {
3581        match (&args[0], &args[1]) {
3582            (Value::String(path), Value::String(content)) => {
3583                match std::fs::write(path.as_str(), content.as_str()) {
3584                    Ok(_) => Ok(Value::Bool(true)),
3585                    Err(e) => Err(RuntimeError::new(format!("write_file failed: {}", e))),
3586                }
3587            }
3588            _ => Err(RuntimeError::new(
3589                "write_file() requires path and content strings",
3590            )),
3591        }
3592    });
3593
3594    // append_file - append to file
3595    define(interp, "append_file", Some(2), |_, args| {
3596        match (&args[0], &args[1]) {
3597            (Value::String(path), Value::String(content)) => {
3598                use std::fs::OpenOptions;
3599                let result = OpenOptions::new()
3600                    .create(true)
3601                    .append(true)
3602                    .open(path.as_str())
3603                    .and_then(|mut f| f.write_all(content.as_bytes()));
3604                match result {
3605                    Ok(_) => Ok(Value::Bool(true)),
3606                    Err(e) => Err(RuntimeError::new(format!("append_file failed: {}", e))),
3607                }
3608            }
3609            _ => Err(RuntimeError::new(
3610                "append_file() requires path and content strings",
3611            )),
3612        }
3613    });
3614
3615    // file_exists - check if file exists
3616    define(interp, "file_exists", Some(1), |_, args| match &args[0] {
3617        Value::String(path) => Ok(Value::Bool(std::path::Path::new(path.as_str()).exists())),
3618        _ => Err(RuntimeError::new("file_exists() requires path string")),
3619    });
3620
3621    // read_lines - read file as array of lines
3622    define(interp, "read_lines", Some(1), |_, args| match &args[0] {
3623        Value::String(path) => match std::fs::read_to_string(path.as_str()) {
3624            Ok(content) => {
3625                let lines: Vec<Value> = content
3626                    .lines()
3627                    .map(|l| Value::String(Rc::new(l.to_string())))
3628                    .collect();
3629                Ok(Value::Evidential {
3630                    value: Box::new(Value::Array(Rc::new(RefCell::new(lines)))),
3631                    evidence: Evidence::Reported,
3632                })
3633            }
3634            Err(e) => Err(RuntimeError::new(format!("read_lines failed: {}", e))),
3635        },
3636        _ => Err(RuntimeError::new("read_lines() requires path string")),
3637    });
3638
3639    // env - get environment variable
3640    define(interp, "env", Some(1), |_, args| {
3641        match &args[0] {
3642            Value::String(name) => {
3643                match std::env::var(name.as_str()) {
3644                    Ok(value) => Ok(Value::Evidential {
3645                        value: Box::new(Value::String(Rc::new(value))),
3646                        evidence: Evidence::Reported, // Env vars are external
3647                    }),
3648                    Err(_) => Ok(Value::Null),
3649                }
3650            }
3651            _ => Err(RuntimeError::new("env() requires variable name string")),
3652        }
3653    });
3654
3655    // env::var - Rust-style env::var that returns Result<String, VarError>
3656    define(interp, "env·var", Some(1), |_, args| {
3657        match &args[0] {
3658            Value::String(name) => {
3659                match std::env::var(name.as_str()) {
3660                    Ok(value) => Ok(Value::Variant {
3661                        enum_name: "Result".to_string(),
3662                        variant_name: "Ok".to_string(),
3663                        fields: Some(Rc::new(vec![Value::String(Rc::new(value))])),
3664                    }),
3665                    Err(_) => Ok(Value::Variant {
3666                        enum_name: "Result".to_string(),
3667                        variant_name: "Err".to_string(),
3668                        fields: Some(Rc::new(vec![Value::String(Rc::new("environment variable not found".to_string()))])),
3669                    }),
3670                }
3671            }
3672            _ => Err(RuntimeError::new("env::var() requires variable name string")),
3673        }
3674    });
3675
3676    // env_or - get environment variable with default
3677    define(interp, "env_or", Some(2), |_, args| {
3678        match (&args[0], &args[1]) {
3679            (Value::String(name), default) => match std::env::var(name.as_str()) {
3680                Ok(value) => Ok(Value::Evidential {
3681                    value: Box::new(Value::String(Rc::new(value))),
3682                    evidence: Evidence::Reported,
3683                }),
3684                Err(_) => Ok(default.clone()),
3685            },
3686            _ => Err(RuntimeError::new("env_or() requires variable name string")),
3687        }
3688    });
3689
3690    // cwd - current working directory
3691    define(interp, "cwd", Some(0), |_, _| {
3692        match std::env::current_dir() {
3693            Ok(path) => Ok(Value::String(Rc::new(path.to_string_lossy().to_string()))),
3694            Err(e) => Err(RuntimeError::new(format!("cwd() failed: {}", e))),
3695        }
3696    });
3697
3698    // args - command line arguments (filtered to exclude interpreter args)
3699    define(interp, "args", Some(0), |interp, _| {
3700        let args: Vec<Value> = if interp.program_args.as_ref().map(|v| v.is_empty()).unwrap_or(true) {
3701            // Fallback: return all args if program_args not set
3702            std::env::args()
3703                .map(|a| Value::String(Rc::new(a)))
3704                .collect()
3705        } else {
3706            // Return filtered program args
3707            interp.program_args.as_ref().unwrap().iter()
3708                .map(|a| Value::String(Rc::new(a.clone())))
3709                .collect()
3710        };
3711        Ok(Value::Array(Rc::new(RefCell::new(args))))
3712    });
3713}
3714
3715// ============================================================================
3716// TIME FUNCTIONS
3717// ============================================================================
3718
3719fn register_time(interp: &mut Interpreter) {
3720    // now - current Unix timestamp in milliseconds
3721    define(interp, "now", Some(0), |_, _| {
3722        let duration = SystemTime::now()
3723            .duration_since(UNIX_EPOCH)
3724            .unwrap_or(Duration::ZERO);
3725        Ok(Value::Int(duration.as_millis() as i64))
3726    });
3727
3728    // now_secs - current Unix timestamp in seconds
3729    define(interp, "now_secs", Some(0), |_, _| {
3730        let duration = SystemTime::now()
3731            .duration_since(UNIX_EPOCH)
3732            .unwrap_or(Duration::ZERO);
3733        Ok(Value::Int(duration.as_secs() as i64))
3734    });
3735
3736    // now_micros - current Unix timestamp in microseconds
3737    define(interp, "now_micros", Some(0), |_, _| {
3738        let duration = SystemTime::now()
3739            .duration_since(UNIX_EPOCH)
3740            .unwrap_or(Duration::ZERO);
3741        Ok(Value::Int(duration.as_micros() as i64))
3742    });
3743
3744    // sleep - sleep for milliseconds
3745    define(interp, "sleep", Some(1), |_, args| match &args[0] {
3746        Value::Int(ms) if *ms >= 0 => {
3747            std::thread::sleep(Duration::from_millis(*ms as u64));
3748            Ok(Value::Null)
3749        }
3750        _ => Err(RuntimeError::new(
3751            "sleep() requires non-negative integer milliseconds",
3752        )),
3753    });
3754
3755    // measure - measure execution time of a thunk (returns ms)
3756    // Note: This would need closure support to work properly
3757    // For now, we provide a simple timer API
3758
3759    // UNIX_EPOCH - constant representing Unix epoch (0 seconds)
3760    define(interp, "UNIX_EPOCH", Some(0), |_, _| {
3761        // Return a struct representing the Unix epoch
3762        let mut fields = std::collections::HashMap::new();
3763        fields.insert("secs".to_string(), Value::Int(0));
3764        fields.insert("nanos".to_string(), Value::Int(0));
3765        Ok(Value::Struct {
3766            name: "SystemTime".to_string(),
3767            fields: Rc::new(RefCell::new(fields)),
3768        })
3769    });
3770
3771    // std::time::UNIX_EPOCH alias
3772    define(interp, "std·time·UNIX_EPOCH", Some(0), |_, _| {
3773        let mut fields = std::collections::HashMap::new();
3774        fields.insert("secs".to_string(), Value::Int(0));
3775        fields.insert("nanos".to_string(), Value::Int(0));
3776        Ok(Value::Struct {
3777            name: "SystemTime".to_string(),
3778            fields: Rc::new(RefCell::new(fields)),
3779        })
3780    });
3781
3782    // timer_start - start a timer (returns opaque handle)
3783    define(interp, "timer_start", Some(0), |_, _| {
3784        let now = Instant::now();
3785        // Store as microseconds since we can't store Instant directly
3786        Ok(Value::Int(now.elapsed().as_nanos() as i64)) // This is a bit hacky
3787    });
3788}
3789
3790// ============================================================================
3791// RANDOM FUNCTIONS
3792// ============================================================================
3793
3794fn register_random(interp: &mut Interpreter) {
3795    // random - random float 0.0 to 1.0
3796    define(interp, "random", Some(0), |_, _| {
3797        // Simple LCG random - not cryptographically secure
3798        use std::time::SystemTime;
3799        let seed = SystemTime::now()
3800            .duration_since(UNIX_EPOCH)
3801            .unwrap_or(Duration::ZERO)
3802            .as_nanos() as u64;
3803        let rand = ((seed.wrapping_mul(1103515245).wrapping_add(12345)) >> 16) as f64;
3804        Ok(Value::Float(rand / u32::MAX as f64))
3805    });
3806
3807    // random_int - random integer in range [min, max)
3808    define(interp, "random_int", Some(2), |_, args| {
3809        match (&args[0], &args[1]) {
3810            (Value::Int(min), Value::Int(max)) if max > min => {
3811                use std::time::SystemTime;
3812                let seed = SystemTime::now()
3813                    .duration_since(UNIX_EPOCH)
3814                    .unwrap_or(Duration::ZERO)
3815                    .as_nanos() as u64;
3816                let range = (max - min) as u64;
3817                let rand = ((seed.wrapping_mul(1103515245).wrapping_add(12345)) >> 16) % range;
3818                Ok(Value::Int(*min + rand as i64))
3819            }
3820            _ => Err(RuntimeError::new(
3821                "random_int() requires min < max integers",
3822            )),
3823        }
3824    });
3825
3826    // shuffle - shuffle array in place (Fisher-Yates)
3827    define(interp, "shuffle", Some(1), |_, args| match &args[0] {
3828        Value::Array(arr) => {
3829            let mut arr = arr.borrow_mut();
3830            use std::time::SystemTime;
3831            let mut seed = SystemTime::now()
3832                .duration_since(UNIX_EPOCH)
3833                .unwrap_or(Duration::ZERO)
3834                .as_nanos() as u64;
3835
3836            for i in (1..arr.len()).rev() {
3837                seed = seed.wrapping_mul(1103515245).wrapping_add(12345);
3838                let j = ((seed >> 16) as usize) % (i + 1);
3839                arr.swap(i, j);
3840            }
3841            Ok(Value::Null)
3842        }
3843        _ => Err(RuntimeError::new("shuffle() requires array")),
3844    });
3845
3846    // sample - random sample from array
3847    define(interp, "sample", Some(1), |_, args| match &args[0] {
3848        Value::Array(arr) => {
3849            let arr = arr.borrow();
3850            if arr.is_empty() {
3851                return Err(RuntimeError::new("sample() on empty array"));
3852            }
3853
3854            use std::time::SystemTime;
3855            let seed = SystemTime::now()
3856                .duration_since(UNIX_EPOCH)
3857                .unwrap_or(Duration::ZERO)
3858                .as_nanos() as u64;
3859            let idx =
3860                ((seed.wrapping_mul(1103515245).wrapping_add(12345)) >> 16) as usize % arr.len();
3861            Ok(arr[idx].clone())
3862        }
3863        _ => Err(RuntimeError::new("sample() requires array")),
3864    });
3865}
3866
3867// ============================================================================
3868// CONVERSION FUNCTIONS
3869// ============================================================================
3870
3871fn register_convert(interp: &mut Interpreter) {
3872    // to_string - convert to string
3873    define(interp, "to_string", Some(1), |_, args| {
3874        Ok(Value::String(Rc::new(format!("{}", args[0]))))
3875    });
3876
3877    // to_int - convert to integer
3878    define(interp, "to_int", Some(1), |_, args| match &args[0] {
3879        Value::Int(n) => Ok(Value::Int(*n)),
3880        Value::Float(n) => Ok(Value::Int(*n as i64)),
3881        Value::Bool(b) => Ok(Value::Int(if *b { 1 } else { 0 })),
3882        Value::Char(c) => Ok(Value::Int(*c as i64)),
3883        Value::String(s) => s
3884            .parse::<i64>()
3885            .map(Value::Int)
3886            .map_err(|_| RuntimeError::new(format!("cannot parse '{}' as integer", s))),
3887        _ => Err(RuntimeError::new("to_int() cannot convert this type")),
3888    });
3889
3890    // to_float - convert to float
3891    define(interp, "to_float", Some(1), |_, args| match &args[0] {
3892        Value::Int(n) => Ok(Value::Float(*n as f64)),
3893        Value::Float(n) => Ok(Value::Float(*n)),
3894        Value::Bool(b) => Ok(Value::Float(if *b { 1.0 } else { 0.0 })),
3895        Value::String(s) => s
3896            .parse::<f64>()
3897            .map(Value::Float)
3898            .map_err(|_| RuntimeError::new(format!("cannot parse '{}' as float", s))),
3899        _ => Err(RuntimeError::new("to_float() cannot convert this type")),
3900    });
3901
3902    // to_bool - convert to boolean
3903    define(interp, "to_bool", Some(1), |_, args| {
3904        Ok(Value::Bool(is_truthy(&args[0])))
3905    });
3906
3907    // to_char - convert to character
3908    define(interp, "to_char", Some(1), |_, args| match &args[0] {
3909        Value::Char(c) => Ok(Value::Char(*c)),
3910        Value::Int(n) => char::from_u32(*n as u32)
3911            .map(Value::Char)
3912            .ok_or_else(|| RuntimeError::new(format!("invalid char code: {}", n))),
3913        Value::String(s) => s
3914            .chars()
3915            .next()
3916            .map(Value::Char)
3917            .ok_or_else(|| RuntimeError::new("to_char() on empty string")),
3918        _ => Err(RuntimeError::new("to_char() cannot convert this type")),
3919    });
3920
3921    // to_array - convert to array
3922    define(interp, "to_array", Some(1), |_, args| match &args[0] {
3923        Value::Array(arr) => Ok(Value::Array(arr.clone())),
3924        Value::Tuple(t) => Ok(Value::Array(Rc::new(RefCell::new(t.as_ref().clone())))),
3925        Value::String(s) => {
3926            let chars: Vec<Value> = s.chars().map(Value::Char).collect();
3927            Ok(Value::Array(Rc::new(RefCell::new(chars))))
3928        }
3929        _ => Ok(Value::Array(Rc::new(RefCell::new(vec![args[0].clone()])))),
3930    });
3931
3932    // to_tuple - convert to tuple
3933    define(interp, "to_tuple", Some(1), |_, args| match &args[0] {
3934        Value::Tuple(t) => Ok(Value::Tuple(t.clone())),
3935        Value::Array(arr) => Ok(Value::Tuple(Rc::new(arr.borrow().clone()))),
3936        _ => Ok(Value::Tuple(Rc::new(vec![args[0].clone()]))),
3937    });
3938
3939    // char_code - get unicode code point
3940    define(interp, "char_code", Some(1), |_, args| match &args[0] {
3941        Value::Char(c) => Ok(Value::Int(*c as i64)),
3942        _ => Err(RuntimeError::new("char_code() requires char")),
3943    });
3944
3945    // from_char_code - create char from code point
3946    define(interp, "from_char_code", Some(1), |_, args| {
3947        match &args[0] {
3948            Value::Int(n) => char::from_u32(*n as u32)
3949                .map(Value::Char)
3950                .ok_or_else(|| RuntimeError::new(format!("invalid char code: {}", n))),
3951            _ => Err(RuntimeError::new("from_char_code() requires integer")),
3952        }
3953    });
3954
3955    // hex - convert to hex string
3956    define(interp, "hex", Some(1), |_, args| match &args[0] {
3957        Value::Int(n) => Ok(Value::String(Rc::new(format!("{:x}", n)))),
3958        _ => Err(RuntimeError::new("hex() requires integer")),
3959    });
3960
3961    // oct - convert to octal string
3962    define(interp, "oct", Some(1), |_, args| match &args[0] {
3963        Value::Int(n) => Ok(Value::String(Rc::new(format!("{:o}", n)))),
3964        _ => Err(RuntimeError::new("oct() requires integer")),
3965    });
3966
3967    // bin - convert to binary string
3968    define(interp, "bin", Some(1), |_, args| match &args[0] {
3969        Value::Int(n) => Ok(Value::String(Rc::new(format!("{:b}", n)))),
3970        _ => Err(RuntimeError::new("bin() requires integer")),
3971    });
3972
3973    // parse_int - parse string as integer with optional base
3974    define(interp, "parse_int", Some(2), |_, args| {
3975        match (&args[0], &args[1]) {
3976            (Value::String(s), Value::Int(base)) if *base >= 2 && *base <= 36 => {
3977                i64::from_str_radix(s.trim(), *base as u32)
3978                    .map(Value::Int)
3979                    .map_err(|_| {
3980                        RuntimeError::new(format!("cannot parse '{}' as base-{} integer", s, base))
3981                    })
3982            }
3983            _ => Err(RuntimeError::new(
3984                "parse_int() requires string and base 2-36",
3985            )),
3986        }
3987    });
3988}
3989
3990// ============================================================================
3991// CYCLE (MODULAR ARITHMETIC) FUNCTIONS
3992// For poly-cultural mathematics
3993// ============================================================================
3994
3995fn register_cycle(interp: &mut Interpreter) {
3996    // cycle - create a cycle value (modular)
3997    define(interp, "cycle", Some(2), |_, args| {
3998        match (&args[0], &args[1]) {
3999            (Value::Int(value), Value::Int(modulus)) if *modulus > 0 => {
4000                let normalized = value.rem_euclid(*modulus);
4001                Ok(Value::Tuple(Rc::new(vec![
4002                    Value::Int(normalized),
4003                    Value::Int(*modulus),
4004                ])))
4005            }
4006            _ => Err(RuntimeError::new(
4007                "cycle() requires value and positive modulus",
4008            )),
4009        }
4010    });
4011
4012    // mod_add - modular addition
4013    define(interp, "mod_add", Some(3), |_, args| {
4014        match (&args[0], &args[1], &args[2]) {
4015            (Value::Int(a), Value::Int(b), Value::Int(m)) if *m > 0 => {
4016                Ok(Value::Int((a + b).rem_euclid(*m)))
4017            }
4018            _ => Err(RuntimeError::new(
4019                "mod_add() requires two integers and positive modulus",
4020            )),
4021        }
4022    });
4023
4024    // mod_sub - modular subtraction
4025    define(interp, "mod_sub", Some(3), |_, args| {
4026        match (&args[0], &args[1], &args[2]) {
4027            (Value::Int(a), Value::Int(b), Value::Int(m)) if *m > 0 => {
4028                Ok(Value::Int((a - b).rem_euclid(*m)))
4029            }
4030            _ => Err(RuntimeError::new(
4031                "mod_sub() requires two integers and positive modulus",
4032            )),
4033        }
4034    });
4035
4036    // mod_mul - modular multiplication
4037    define(interp, "mod_mul", Some(3), |_, args| {
4038        match (&args[0], &args[1], &args[2]) {
4039            (Value::Int(a), Value::Int(b), Value::Int(m)) if *m > 0 => {
4040                Ok(Value::Int((a * b).rem_euclid(*m)))
4041            }
4042            _ => Err(RuntimeError::new(
4043                "mod_mul() requires two integers and positive modulus",
4044            )),
4045        }
4046    });
4047
4048    // mod_pow - modular exponentiation (fast)
4049    define(interp, "mod_pow", Some(3), |_, args| {
4050        match (&args[0], &args[1], &args[2]) {
4051            (Value::Int(base), Value::Int(exp), Value::Int(m)) if *m > 0 && *exp >= 0 => {
4052                Ok(Value::Int(mod_pow(*base, *exp as u64, *m)))
4053            }
4054            _ => Err(RuntimeError::new(
4055                "mod_pow() requires base, non-negative exp, and positive modulus",
4056            )),
4057        }
4058    });
4059
4060    // mod_inv - modular multiplicative inverse (if exists)
4061    define(interp, "mod_inv", Some(2), |_, args| {
4062        match (&args[0], &args[1]) {
4063            (Value::Int(a), Value::Int(m)) if *m > 0 => match mod_inverse(*a, *m) {
4064                Some(inv) => Ok(Value::Int(inv)),
4065                None => Err(RuntimeError::new(format!(
4066                    "no modular inverse of {} mod {}",
4067                    a, m
4068                ))),
4069            },
4070            _ => Err(RuntimeError::new(
4071                "mod_inv() requires integer and positive modulus",
4072            )),
4073        }
4074    });
4075
4076    // Musical cycles (for tuning systems)
4077    // octave - normalize to octave (pitch class)
4078    define(interp, "octave", Some(1), |_, args| {
4079        match &args[0] {
4080            Value::Int(note) => Ok(Value::Int(note.rem_euclid(12))),
4081            Value::Float(freq) => {
4082                // Normalize frequency to octave starting at A4=440Hz
4083                let semitones = 12.0 * (freq / 440.0).log2();
4084                Ok(Value::Float(semitones.rem_euclid(12.0)))
4085            }
4086            _ => Err(RuntimeError::new("octave() requires number")),
4087        }
4088    });
4089
4090    // interval - musical interval (semitones)
4091    define(interp, "interval", Some(2), |_, args| {
4092        match (&args[0], &args[1]) {
4093            (Value::Int(a), Value::Int(b)) => Ok(Value::Int((b - a).rem_euclid(12))),
4094            _ => Err(RuntimeError::new("interval() requires two integers")),
4095        }
4096    });
4097
4098    // cents - convert semitones to cents or vice versa
4099    define(interp, "cents", Some(1), |_, args| match &args[0] {
4100        Value::Int(semitones) => Ok(Value::Int(*semitones * 100)),
4101        Value::Float(semitones) => Ok(Value::Float(*semitones * 100.0)),
4102        _ => Err(RuntimeError::new("cents() requires number")),
4103    });
4104
4105    // freq - convert MIDI note number to frequency
4106    define(interp, "freq", Some(1), |_, args| match &args[0] {
4107        Value::Int(midi) => {
4108            let freq = 440.0 * 2.0_f64.powf((*midi as f64 - 69.0) / 12.0);
4109            Ok(Value::Float(freq))
4110        }
4111        _ => Err(RuntimeError::new("freq() requires integer MIDI note")),
4112    });
4113
4114    // midi - convert frequency to MIDI note number
4115    define(interp, "midi", Some(1), |_, args| match &args[0] {
4116        Value::Float(freq) if *freq > 0.0 => {
4117            let midi = 69.0 + 12.0 * (freq / 440.0).log2();
4118            Ok(Value::Int(midi.round() as i64))
4119        }
4120        Value::Int(freq) if *freq > 0 => {
4121            let midi = 69.0 + 12.0 * (*freq as f64 / 440.0).log2();
4122            Ok(Value::Int(midi.round() as i64))
4123        }
4124        _ => Err(RuntimeError::new("midi() requires positive frequency")),
4125    });
4126}
4127
4128// Fast modular exponentiation
4129fn mod_pow(mut base: i64, mut exp: u64, modulus: i64) -> i64 {
4130    if modulus == 1 {
4131        return 0;
4132    }
4133    let mut result: i64 = 1;
4134    base = base.rem_euclid(modulus);
4135    while exp > 0 {
4136        if exp % 2 == 1 {
4137            result = (result * base).rem_euclid(modulus);
4138        }
4139        exp /= 2;
4140        base = (base * base).rem_euclid(modulus);
4141    }
4142    result
4143}
4144
4145// ============================================================================
4146// SIMD VECTOR FUNCTIONS
4147// High-performance vector operations for game/graphics math
4148// ============================================================================
4149
4150fn register_simd(interp: &mut Interpreter) {
4151    // simd_new - create a SIMD 4-component vector
4152    define(interp, "simd_new", Some(4), |_, args| {
4153        let values: Result<Vec<f64>, _> = args
4154            .iter()
4155            .map(|v| match v {
4156                Value::Float(f) => Ok(*f),
4157                Value::Int(i) => Ok(*i as f64),
4158                _ => Err(RuntimeError::new("simd_new() requires numbers")),
4159            })
4160            .collect();
4161        let values = values?;
4162        Ok(Value::Array(Rc::new(RefCell::new(vec![
4163            Value::Float(values[0]),
4164            Value::Float(values[1]),
4165            Value::Float(values[2]),
4166            Value::Float(values[3]),
4167        ]))))
4168    });
4169
4170    // simd_splat - create vector with all same components
4171    define(interp, "simd_splat", Some(1), |_, args| {
4172        let v = match &args[0] {
4173            Value::Float(f) => *f,
4174            Value::Int(i) => *i as f64,
4175            _ => return Err(RuntimeError::new("simd_splat() requires number")),
4176        };
4177        Ok(Value::Array(Rc::new(RefCell::new(vec![
4178            Value::Float(v),
4179            Value::Float(v),
4180            Value::Float(v),
4181            Value::Float(v),
4182        ]))))
4183    });
4184
4185    // simd_add - component-wise addition
4186    define(interp, "simd_add", Some(2), |_, args| {
4187        simd_binary_op(&args[0], &args[1], |a, b| a + b, "simd_add")
4188    });
4189
4190    // simd_sub - component-wise subtraction
4191    define(interp, "simd_sub", Some(2), |_, args| {
4192        simd_binary_op(&args[0], &args[1], |a, b| a - b, "simd_sub")
4193    });
4194
4195    // simd_mul - component-wise multiplication
4196    define(interp, "simd_mul", Some(2), |_, args| {
4197        simd_binary_op(&args[0], &args[1], |a, b| a * b, "simd_mul")
4198    });
4199
4200    // simd_div - component-wise division
4201    define(interp, "simd_div", Some(2), |_, args| {
4202        simd_binary_op(&args[0], &args[1], |a, b| a / b, "simd_div")
4203    });
4204
4205    // simd_dot - dot product of two vectors
4206    define(interp, "simd_dot", Some(2), |_, args| {
4207        let a = extract_simd(&args[0], "simd_dot")?;
4208        let b = extract_simd(&args[1], "simd_dot")?;
4209        let dot = a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
4210        Ok(Value::Float(dot))
4211    });
4212
4213    // simd_cross - 3D cross product (w component set to 0)
4214    define(interp, "simd_cross", Some(2), |_, args| {
4215        let a = extract_simd(&args[0], "simd_cross")?;
4216        let b = extract_simd(&args[1], "simd_cross")?;
4217        Ok(Value::Array(Rc::new(RefCell::new(vec![
4218            Value::Float(a[1] * b[2] - a[2] * b[1]),
4219            Value::Float(a[2] * b[0] - a[0] * b[2]),
4220            Value::Float(a[0] * b[1] - a[1] * b[0]),
4221            Value::Float(0.0),
4222        ]))))
4223    });
4224
4225    // simd_length - vector length (magnitude)
4226    define(interp, "simd_length", Some(1), |_, args| {
4227        let v = extract_simd(&args[0], "simd_length")?;
4228        let len_sq = v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3];
4229        Ok(Value::Float(len_sq.sqrt()))
4230    });
4231
4232    // simd_normalize - normalize vector to unit length
4233    define(interp, "simd_normalize", Some(1), |_, args| {
4234        let v = extract_simd(&args[0], "simd_normalize")?;
4235        let len_sq = v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3];
4236        let len = len_sq.sqrt();
4237        if len < 1e-10 {
4238            return Ok(Value::Array(Rc::new(RefCell::new(vec![
4239                Value::Float(0.0),
4240                Value::Float(0.0),
4241                Value::Float(0.0),
4242                Value::Float(0.0),
4243            ]))));
4244        }
4245        let inv_len = 1.0 / len;
4246        Ok(Value::Array(Rc::new(RefCell::new(vec![
4247            Value::Float(v[0] * inv_len),
4248            Value::Float(v[1] * inv_len),
4249            Value::Float(v[2] * inv_len),
4250            Value::Float(v[3] * inv_len),
4251        ]))))
4252    });
4253
4254    // simd_min - component-wise minimum
4255    define(interp, "simd_min", Some(2), |_, args| {
4256        simd_binary_op(&args[0], &args[1], |a, b| a.min(b), "simd_min")
4257    });
4258
4259    // simd_max - component-wise maximum
4260    define(interp, "simd_max", Some(2), |_, args| {
4261        simd_binary_op(&args[0], &args[1], |a, b| a.max(b), "simd_max")
4262    });
4263
4264    // simd_hadd - horizontal add (sum all components)
4265    define(interp, "simd_hadd", Some(1), |_, args| {
4266        let v = extract_simd(&args[0], "simd_hadd")?;
4267        Ok(Value::Float(v[0] + v[1] + v[2] + v[3]))
4268    });
4269
4270    // simd_extract - extract single component (0-3)
4271    define(interp, "simd_extract", Some(2), |_, args| {
4272        let v = extract_simd(&args[0], "simd_extract")?;
4273        let idx = match &args[1] {
4274            Value::Int(i) => *i as usize,
4275            _ => return Err(RuntimeError::new("simd_extract() requires integer index")),
4276        };
4277        if idx > 3 {
4278            return Err(RuntimeError::new("simd_extract() index must be 0-3"));
4279        }
4280        Ok(Value::Float(v[idx]))
4281    });
4282
4283    // simd_free - no-op in interpreter (for JIT compatibility)
4284    define(interp, "simd_free", Some(1), |_, _| Ok(Value::Null));
4285
4286    // simd_lerp - linear interpolation between vectors
4287    define(interp, "simd_lerp", Some(3), |_, args| {
4288        let a = extract_simd(&args[0], "simd_lerp")?;
4289        let b = extract_simd(&args[1], "simd_lerp")?;
4290        let t = match &args[2] {
4291            Value::Float(f) => *f,
4292            Value::Int(i) => *i as f64,
4293            _ => return Err(RuntimeError::new("simd_lerp() requires float t")),
4294        };
4295        let one_t = 1.0 - t;
4296        Ok(Value::Array(Rc::new(RefCell::new(vec![
4297            Value::Float(a[0] * one_t + b[0] * t),
4298            Value::Float(a[1] * one_t + b[1] * t),
4299            Value::Float(a[2] * one_t + b[2] * t),
4300            Value::Float(a[3] * one_t + b[3] * t),
4301        ]))))
4302    });
4303}
4304
4305// Helper to extract SIMD values from array
4306fn extract_simd(val: &Value, fn_name: &str) -> Result<[f64; 4], RuntimeError> {
4307    match val {
4308        Value::Array(arr) => {
4309            let arr = arr.borrow();
4310            if arr.len() < 4 {
4311                return Err(RuntimeError::new(format!(
4312                    "{}() requires 4-element array",
4313                    fn_name
4314                )));
4315            }
4316            let mut result = [0.0; 4];
4317            for (i, v) in arr.iter().take(4).enumerate() {
4318                result[i] = match v {
4319                    Value::Float(f) => *f,
4320                    Value::Int(n) => *n as f64,
4321                    _ => {
4322                        return Err(RuntimeError::new(format!(
4323                            "{}() requires numeric array",
4324                            fn_name
4325                        )))
4326                    }
4327                };
4328            }
4329            Ok(result)
4330        }
4331        _ => Err(RuntimeError::new(format!(
4332            "{}() requires array argument",
4333            fn_name
4334        ))),
4335    }
4336}
4337
4338// Helper for binary SIMD operations
4339fn simd_binary_op<F>(a: &Value, b: &Value, op: F, fn_name: &str) -> Result<Value, RuntimeError>
4340where
4341    F: Fn(f64, f64) -> f64,
4342{
4343    let a = extract_simd(a, fn_name)?;
4344    let b = extract_simd(b, fn_name)?;
4345    Ok(Value::Array(Rc::new(RefCell::new(vec![
4346        Value::Float(op(a[0], b[0])),
4347        Value::Float(op(a[1], b[1])),
4348        Value::Float(op(a[2], b[2])),
4349        Value::Float(op(a[3], b[3])),
4350    ]))))
4351}
4352
4353// ============================================================================
4354// GRAPHICS MATH LIBRARY
4355// ============================================================================
4356// Comprehensive 3D graphics mathematics for physics and rendering:
4357// - Quaternions for rotation without gimbal lock
4358// - vec2/vec3/vec4 vector types with swizzling
4359// - mat3/mat4 matrices with projection/view/model operations
4360// - Affine transforms, Euler angles, and interpolation
4361// ============================================================================
4362
4363fn register_graphics_math(interp: &mut Interpreter) {
4364    // -------------------------------------------------------------------------
4365    // QUATERNIONS - Essential for 3D rotations
4366    // -------------------------------------------------------------------------
4367    // Quaternion format: [w, x, y, z] where w is scalar, (x,y,z) is vector part
4368    // This follows the convention: q = w + xi + yj + zk
4369
4370    // quat_new(w, x, y, z) - create a quaternion
4371    define(interp, "quat_new", Some(4), |_, args| {
4372        let w = extract_number(&args[0], "quat_new")?;
4373        let x = extract_number(&args[1], "quat_new")?;
4374        let y = extract_number(&args[2], "quat_new")?;
4375        let z = extract_number(&args[3], "quat_new")?;
4376        Ok(make_vec4(w, x, y, z))
4377    });
4378
4379    // quat_identity() - identity quaternion (no rotation)
4380    define(interp, "quat_identity", Some(0), |_, _| {
4381        Ok(make_vec4(1.0, 0.0, 0.0, 0.0))
4382    });
4383
4384    // quat_from_axis_angle(axis_vec3, angle_radians) - create from axis-angle
4385    define(interp, "quat_from_axis_angle", Some(2), |_, args| {
4386        let axis = extract_vec3(&args[0], "quat_from_axis_angle")?;
4387        let angle = extract_number(&args[1], "quat_from_axis_angle")?;
4388
4389        // Normalize axis
4390        let len = (axis[0] * axis[0] + axis[1] * axis[1] + axis[2] * axis[2]).sqrt();
4391        if len < 1e-10 {
4392            return Ok(make_vec4(1.0, 0.0, 0.0, 0.0)); // Identity for zero axis
4393        }
4394        let ax = axis[0] / len;
4395        let ay = axis[1] / len;
4396        let az = axis[2] / len;
4397
4398        let half_angle = angle / 2.0;
4399        let s = half_angle.sin();
4400        let c = half_angle.cos();
4401
4402        Ok(make_vec4(c, ax * s, ay * s, az * s))
4403    });
4404
4405    // quat_from_euler(pitch, yaw, roll) - create from Euler angles (radians)
4406    // Uses XYZ order (pitch around X, yaw around Y, roll around Z)
4407    define(interp, "quat_from_euler", Some(3), |_, args| {
4408        let pitch = extract_number(&args[0], "quat_from_euler")?; // X
4409        let yaw = extract_number(&args[1], "quat_from_euler")?; // Y
4410        let roll = extract_number(&args[2], "quat_from_euler")?; // Z
4411
4412        let (sp, cp) = (pitch / 2.0).sin_cos();
4413        let (sy, cy) = (yaw / 2.0).sin_cos();
4414        let (sr, cr) = (roll / 2.0).sin_cos();
4415
4416        // Combined quaternion (XYZ order)
4417        let w = cp * cy * cr + sp * sy * sr;
4418        let x = sp * cy * cr - cp * sy * sr;
4419        let y = cp * sy * cr + sp * cy * sr;
4420        let z = cp * cy * sr - sp * sy * cr;
4421
4422        Ok(make_vec4(w, x, y, z))
4423    });
4424
4425    // quat_mul(q1, q2) - quaternion multiplication (q1 * q2)
4426    define(interp, "quat_mul", Some(2), |_, args| {
4427        let q1 = extract_vec4(&args[0], "quat_mul")?;
4428        let q2 = extract_vec4(&args[1], "quat_mul")?;
4429
4430        // Hamilton product
4431        let w = q1[0] * q2[0] - q1[1] * q2[1] - q1[2] * q2[2] - q1[3] * q2[3];
4432        let x = q1[0] * q2[1] + q1[1] * q2[0] + q1[2] * q2[3] - q1[3] * q2[2];
4433        let y = q1[0] * q2[2] - q1[1] * q2[3] + q1[2] * q2[0] + q1[3] * q2[1];
4434        let z = q1[0] * q2[3] + q1[1] * q2[2] - q1[2] * q2[1] + q1[3] * q2[0];
4435
4436        Ok(make_vec4(w, x, y, z))
4437    });
4438
4439    // quat_conjugate(q) - quaternion conjugate (inverse for unit quaternions)
4440    define(interp, "quat_conjugate", Some(1), |_, args| {
4441        let q = extract_vec4(&args[0], "quat_conjugate")?;
4442        Ok(make_vec4(q[0], -q[1], -q[2], -q[3]))
4443    });
4444
4445    // quat_inverse(q) - quaternion inverse (handles non-unit quaternions)
4446    define(interp, "quat_inverse", Some(1), |_, args| {
4447        let q = extract_vec4(&args[0], "quat_inverse")?;
4448        let norm_sq = q[0] * q[0] + q[1] * q[1] + q[2] * q[2] + q[3] * q[3];
4449        if norm_sq < 1e-10 {
4450            return Err(RuntimeError::new(
4451                "quat_inverse: cannot invert zero quaternion",
4452            ));
4453        }
4454        Ok(make_vec4(
4455            q[0] / norm_sq,
4456            -q[1] / norm_sq,
4457            -q[2] / norm_sq,
4458            -q[3] / norm_sq,
4459        ))
4460    });
4461
4462    // quat_normalize(q) - normalize to unit quaternion
4463    define(interp, "quat_normalize", Some(1), |_, args| {
4464        let q = extract_vec4(&args[0], "quat_normalize")?;
4465        let len = (q[0] * q[0] + q[1] * q[1] + q[2] * q[2] + q[3] * q[3]).sqrt();
4466        if len < 1e-10 {
4467            return Ok(make_vec4(1.0, 0.0, 0.0, 0.0));
4468        }
4469        Ok(make_vec4(q[0] / len, q[1] / len, q[2] / len, q[3] / len))
4470    });
4471
4472    // quat_rotate(q, vec3) - rotate a 3D vector by quaternion
4473    define(interp, "quat_rotate", Some(2), |_, args| {
4474        let q = extract_vec4(&args[0], "quat_rotate")?;
4475        let v = extract_vec3(&args[1], "quat_rotate")?;
4476
4477        // q * v * q^-1 optimized formula
4478        let qw = q[0];
4479        let qx = q[1];
4480        let qy = q[2];
4481        let qz = q[3];
4482        let vx = v[0];
4483        let vy = v[1];
4484        let vz = v[2];
4485
4486        // t = 2 * cross(q.xyz, v)
4487        let tx = 2.0 * (qy * vz - qz * vy);
4488        let ty = 2.0 * (qz * vx - qx * vz);
4489        let tz = 2.0 * (qx * vy - qy * vx);
4490
4491        // result = v + q.w * t + cross(q.xyz, t)
4492        let rx = vx + qw * tx + (qy * tz - qz * ty);
4493        let ry = vy + qw * ty + (qz * tx - qx * tz);
4494        let rz = vz + qw * tz + (qx * ty - qy * tx);
4495
4496        Ok(make_vec3(rx, ry, rz))
4497    });
4498
4499    // quat_slerp(q1, q2, t) - spherical linear interpolation
4500    define(interp, "quat_slerp", Some(3), |_, args| {
4501        let q1 = extract_vec4(&args[0], "quat_slerp")?;
4502        let mut q2 = extract_vec4(&args[1], "quat_slerp")?;
4503        let t = extract_number(&args[2], "quat_slerp")?;
4504
4505        // Compute dot product
4506        let mut dot = q1[0] * q2[0] + q1[1] * q2[1] + q1[2] * q2[2] + q1[3] * q2[3];
4507
4508        // If dot < 0, negate q2 to take shorter path
4509        if dot < 0.0 {
4510            q2 = [-q2[0], -q2[1], -q2[2], -q2[3]];
4511            dot = -dot;
4512        }
4513
4514        // If quaternions are very close, use linear interpolation
4515        if dot > 0.9995 {
4516            let w = q1[0] + t * (q2[0] - q1[0]);
4517            let x = q1[1] + t * (q2[1] - q1[1]);
4518            let y = q1[2] + t * (q2[2] - q1[2]);
4519            let z = q1[3] + t * (q2[3] - q1[3]);
4520            let len = (w * w + x * x + y * y + z * z).sqrt();
4521            return Ok(make_vec4(w / len, x / len, y / len, z / len));
4522        }
4523
4524        // Spherical interpolation
4525        let theta_0 = dot.acos();
4526        let theta = theta_0 * t;
4527        let sin_theta = theta.sin();
4528        let sin_theta_0 = theta_0.sin();
4529
4530        let s0 = (theta_0 - theta).cos() - dot * sin_theta / sin_theta_0;
4531        let s1 = sin_theta / sin_theta_0;
4532
4533        Ok(make_vec4(
4534            s0 * q1[0] + s1 * q2[0],
4535            s0 * q1[1] + s1 * q2[1],
4536            s0 * q1[2] + s1 * q2[2],
4537            s0 * q1[3] + s1 * q2[3],
4538        ))
4539    });
4540
4541    // quat_to_euler(q) - convert quaternion to Euler angles [pitch, yaw, roll]
4542    define(interp, "quat_to_euler", Some(1), |_, args| {
4543        let q = extract_vec4(&args[0], "quat_to_euler")?;
4544        let (w, x, y, z) = (q[0], q[1], q[2], q[3]);
4545
4546        // Roll (X-axis rotation)
4547        let sinr_cosp = 2.0 * (w * x + y * z);
4548        let cosr_cosp = 1.0 - 2.0 * (x * x + y * y);
4549        let roll = sinr_cosp.atan2(cosr_cosp);
4550
4551        // Pitch (Y-axis rotation)
4552        let sinp = 2.0 * (w * y - z * x);
4553        let pitch = if sinp.abs() >= 1.0 {
4554            std::f64::consts::FRAC_PI_2.copysign(sinp)
4555        } else {
4556            sinp.asin()
4557        };
4558
4559        // Yaw (Z-axis rotation)
4560        let siny_cosp = 2.0 * (w * z + x * y);
4561        let cosy_cosp = 1.0 - 2.0 * (y * y + z * z);
4562        let yaw = siny_cosp.atan2(cosy_cosp);
4563
4564        Ok(make_vec3(pitch, yaw, roll))
4565    });
4566
4567    // quat_to_mat4(q) - convert quaternion to 4x4 rotation matrix
4568    define(interp, "quat_to_mat4", Some(1), |_, args| {
4569        let q = extract_vec4(&args[0], "quat_to_mat4")?;
4570        let (w, x, y, z) = (q[0], q[1], q[2], q[3]);
4571
4572        let xx = x * x;
4573        let yy = y * y;
4574        let zz = z * z;
4575        let xy = x * y;
4576        let xz = x * z;
4577        let yz = y * z;
4578        let wx = w * x;
4579        let wy = w * y;
4580        let wz = w * z;
4581
4582        // Column-major 4x4 rotation matrix
4583        Ok(make_mat4([
4584            1.0 - 2.0 * (yy + zz),
4585            2.0 * (xy + wz),
4586            2.0 * (xz - wy),
4587            0.0,
4588            2.0 * (xy - wz),
4589            1.0 - 2.0 * (xx + zz),
4590            2.0 * (yz + wx),
4591            0.0,
4592            2.0 * (xz + wy),
4593            2.0 * (yz - wx),
4594            1.0 - 2.0 * (xx + yy),
4595            0.0,
4596            0.0,
4597            0.0,
4598            0.0,
4599            1.0,
4600        ]))
4601    });
4602
4603    // -------------------------------------------------------------------------
4604    // VECTOR TYPES - vec2, vec3, vec4
4605    // -------------------------------------------------------------------------
4606
4607    // vec2(x, y)
4608    define(interp, "vec2", Some(2), |_, args| {
4609        let x = extract_number(&args[0], "vec2")?;
4610        let y = extract_number(&args[1], "vec2")?;
4611        Ok(make_vec2(x, y))
4612    });
4613
4614    // vec3(x, y, z)
4615    define(interp, "vec3", Some(3), |_, args| {
4616        let x = extract_number(&args[0], "vec3")?;
4617        let y = extract_number(&args[1], "vec3")?;
4618        let z = extract_number(&args[2], "vec3")?;
4619        Ok(make_vec3(x, y, z))
4620    });
4621
4622    // vec4(x, y, z, w)
4623    define(interp, "vec4", Some(4), |_, args| {
4624        let x = extract_number(&args[0], "vec4")?;
4625        let y = extract_number(&args[1], "vec4")?;
4626        let z = extract_number(&args[2], "vec4")?;
4627        let w = extract_number(&args[3], "vec4")?;
4628        Ok(make_vec4(x, y, z, w))
4629    });
4630
4631    // vec3_add(a, b)
4632    define(interp, "vec3_add", Some(2), |_, args| {
4633        let a = extract_vec3(&args[0], "vec3_add")?;
4634        let b = extract_vec3(&args[1], "vec3_add")?;
4635        Ok(make_vec3(a[0] + b[0], a[1] + b[1], a[2] + b[2]))
4636    });
4637
4638    // vec3_sub(a, b)
4639    define(interp, "vec3_sub", Some(2), |_, args| {
4640        let a = extract_vec3(&args[0], "vec3_sub")?;
4641        let b = extract_vec3(&args[1], "vec3_sub")?;
4642        Ok(make_vec3(a[0] - b[0], a[1] - b[1], a[2] - b[2]))
4643    });
4644
4645    // vec3_scale(v, scalar)
4646    define(interp, "vec3_scale", Some(2), |_, args| {
4647        let v = extract_vec3(&args[0], "vec3_scale")?;
4648        let s = extract_number(&args[1], "vec3_scale")?;
4649        Ok(make_vec3(v[0] * s, v[1] * s, v[2] * s))
4650    });
4651
4652    // vec3_dot(a, b)
4653    define(interp, "vec3_dot", Some(2), |_, args| {
4654        let a = extract_vec3(&args[0], "vec3_dot")?;
4655        let b = extract_vec3(&args[1], "vec3_dot")?;
4656        Ok(Value::Float(a[0] * b[0] + a[1] * b[1] + a[2] * b[2]))
4657    });
4658
4659    // vec3_cross(a, b)
4660    define(interp, "vec3_cross", Some(2), |_, args| {
4661        let a = extract_vec3(&args[0], "vec3_cross")?;
4662        let b = extract_vec3(&args[1], "vec3_cross")?;
4663        Ok(make_vec3(
4664            a[1] * b[2] - a[2] * b[1],
4665            a[2] * b[0] - a[0] * b[2],
4666            a[0] * b[1] - a[1] * b[0],
4667        ))
4668    });
4669
4670    // vec3_length(v)
4671    define(interp, "vec3_length", Some(1), |_, args| {
4672        let v = extract_vec3(&args[0], "vec3_length")?;
4673        Ok(Value::Float(
4674            (v[0] * v[0] + v[1] * v[1] + v[2] * v[2]).sqrt(),
4675        ))
4676    });
4677
4678    // vec3_normalize(v)
4679    define(interp, "vec3_normalize", Some(1), |_, args| {
4680        let v = extract_vec3(&args[0], "vec3_normalize")?;
4681        let len = (v[0] * v[0] + v[1] * v[1] + v[2] * v[2]).sqrt();
4682        if len < 1e-10 {
4683            return Ok(make_vec3(0.0, 0.0, 0.0));
4684        }
4685        Ok(make_vec3(v[0] / len, v[1] / len, v[2] / len))
4686    });
4687
4688    // vec3_lerp(a, b, t) - linear interpolation
4689    define(interp, "vec3_lerp", Some(3), |_, args| {
4690        let a = extract_vec3(&args[0], "vec3_lerp")?;
4691        let b = extract_vec3(&args[1], "vec3_lerp")?;
4692        let t = extract_number(&args[2], "vec3_lerp")?;
4693        Ok(make_vec3(
4694            a[0] + t * (b[0] - a[0]),
4695            a[1] + t * (b[1] - a[1]),
4696            a[2] + t * (b[2] - a[2]),
4697        ))
4698    });
4699
4700    // vec3_reflect(incident, normal) - reflection vector
4701    define(interp, "vec3_reflect", Some(2), |_, args| {
4702        let i = extract_vec3(&args[0], "vec3_reflect")?;
4703        let n = extract_vec3(&args[1], "vec3_reflect")?;
4704        let dot = i[0] * n[0] + i[1] * n[1] + i[2] * n[2];
4705        Ok(make_vec3(
4706            i[0] - 2.0 * dot * n[0],
4707            i[1] - 2.0 * dot * n[1],
4708            i[2] - 2.0 * dot * n[2],
4709        ))
4710    });
4711
4712    // vec3_refract(incident, normal, eta) - refraction vector
4713    define(interp, "vec3_refract", Some(3), |_, args| {
4714        let i = extract_vec3(&args[0], "vec3_refract")?;
4715        let n = extract_vec3(&args[1], "vec3_refract")?;
4716        let eta = extract_number(&args[2], "vec3_refract")?;
4717
4718        let dot = i[0] * n[0] + i[1] * n[1] + i[2] * n[2];
4719        let k = 1.0 - eta * eta * (1.0 - dot * dot);
4720
4721        if k < 0.0 {
4722            // Total internal reflection
4723            return Ok(make_vec3(0.0, 0.0, 0.0));
4724        }
4725
4726        let coeff = eta * dot + k.sqrt();
4727        Ok(make_vec3(
4728            eta * i[0] - coeff * n[0],
4729            eta * i[1] - coeff * n[1],
4730            eta * i[2] - coeff * n[2],
4731        ))
4732    });
4733
4734    // vec4_dot(a, b)
4735    define(interp, "vec4_dot", Some(2), |_, args| {
4736        let a = extract_vec4(&args[0], "vec4_dot")?;
4737        let b = extract_vec4(&args[1], "vec4_dot")?;
4738        Ok(Value::Float(
4739            a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3],
4740        ))
4741    });
4742
4743    // -------------------------------------------------------------------------
4744    // MAT4 - 4x4 MATRICES (Column-major for OpenGL compatibility)
4745    // -------------------------------------------------------------------------
4746
4747    // mat4_identity() - 4x4 identity matrix
4748    define(interp, "mat4_identity", Some(0), |_, _| {
4749        Ok(make_mat4([
4750            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,
4751        ]))
4752    });
4753
4754    // mat4_mul(a, b) - matrix multiplication
4755    define(interp, "mat4_mul", Some(2), |_, args| {
4756        let a = extract_mat4(&args[0], "mat4_mul")?;
4757        let b = extract_mat4(&args[1], "mat4_mul")?;
4758
4759        let mut result = [0.0f64; 16];
4760        for col in 0..4 {
4761            for row in 0..4 {
4762                let mut sum = 0.0;
4763                for k in 0..4 {
4764                    sum += a[k * 4 + row] * b[col * 4 + k];
4765                }
4766                result[col * 4 + row] = sum;
4767            }
4768        }
4769        Ok(make_mat4(result))
4770    });
4771
4772    // mat4_transform(mat4, vec4) - transform vector by matrix
4773    define(interp, "mat4_transform", Some(2), |_, args| {
4774        let m = extract_mat4(&args[0], "mat4_transform")?;
4775        let v = extract_vec4(&args[1], "mat4_transform")?;
4776
4777        Ok(make_vec4(
4778            m[0] * v[0] + m[4] * v[1] + m[8] * v[2] + m[12] * v[3],
4779            m[1] * v[0] + m[5] * v[1] + m[9] * v[2] + m[13] * v[3],
4780            m[2] * v[0] + m[6] * v[1] + m[10] * v[2] + m[14] * v[3],
4781            m[3] * v[0] + m[7] * v[1] + m[11] * v[2] + m[15] * v[3],
4782        ))
4783    });
4784
4785    // mat4_translate(tx, ty, tz) - translation matrix
4786    define(interp, "mat4_translate", Some(3), |_, args| {
4787        let tx = extract_number(&args[0], "mat4_translate")?;
4788        let ty = extract_number(&args[1], "mat4_translate")?;
4789        let tz = extract_number(&args[2], "mat4_translate")?;
4790        Ok(make_mat4([
4791            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,
4792        ]))
4793    });
4794
4795    // mat4_scale(sx, sy, sz) - scale matrix
4796    define(interp, "mat4_scale", Some(3), |_, args| {
4797        let sx = extract_number(&args[0], "mat4_scale")?;
4798        let sy = extract_number(&args[1], "mat4_scale")?;
4799        let sz = extract_number(&args[2], "mat4_scale")?;
4800        Ok(make_mat4([
4801            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,
4802        ]))
4803    });
4804
4805    // mat4_rotate_x(angle) - rotation around X axis
4806    define(interp, "mat4_rotate_x", Some(1), |_, args| {
4807        let angle = extract_number(&args[0], "mat4_rotate_x")?;
4808        let (s, c) = angle.sin_cos();
4809        Ok(make_mat4([
4810            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,
4811        ]))
4812    });
4813
4814    // mat4_rotate_y(angle) - rotation around Y axis
4815    define(interp, "mat4_rotate_y", Some(1), |_, args| {
4816        let angle = extract_number(&args[0], "mat4_rotate_y")?;
4817        let (s, c) = angle.sin_cos();
4818        Ok(make_mat4([
4819            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,
4820        ]))
4821    });
4822
4823    // mat4_rotate_z(angle) - rotation around Z axis
4824    define(interp, "mat4_rotate_z", Some(1), |_, args| {
4825        let angle = extract_number(&args[0], "mat4_rotate_z")?;
4826        let (s, c) = angle.sin_cos();
4827        Ok(make_mat4([
4828            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,
4829        ]))
4830    });
4831
4832    // mat4_perspective(fov_y, aspect, near, far) - perspective projection
4833    define(interp, "mat4_perspective", Some(4), |_, args| {
4834        let fov_y = extract_number(&args[0], "mat4_perspective")?;
4835        let aspect = extract_number(&args[1], "mat4_perspective")?;
4836        let near = extract_number(&args[2], "mat4_perspective")?;
4837        let far = extract_number(&args[3], "mat4_perspective")?;
4838
4839        let f = 1.0 / (fov_y / 2.0).tan();
4840        let nf = 1.0 / (near - far);
4841
4842        Ok(make_mat4([
4843            f / aspect,
4844            0.0,
4845            0.0,
4846            0.0,
4847            0.0,
4848            f,
4849            0.0,
4850            0.0,
4851            0.0,
4852            0.0,
4853            (far + near) * nf,
4854            -1.0,
4855            0.0,
4856            0.0,
4857            2.0 * far * near * nf,
4858            0.0,
4859        ]))
4860    });
4861
4862    // mat4_ortho(left, right, bottom, top, near, far) - orthographic projection
4863    define(interp, "mat4_ortho", Some(6), |_, args| {
4864        let left = extract_number(&args[0], "mat4_ortho")?;
4865        let right = extract_number(&args[1], "mat4_ortho")?;
4866        let bottom = extract_number(&args[2], "mat4_ortho")?;
4867        let top = extract_number(&args[3], "mat4_ortho")?;
4868        let near = extract_number(&args[4], "mat4_ortho")?;
4869        let far = extract_number(&args[5], "mat4_ortho")?;
4870
4871        let lr = 1.0 / (left - right);
4872        let bt = 1.0 / (bottom - top);
4873        let nf = 1.0 / (near - far);
4874
4875        Ok(make_mat4([
4876            -2.0 * lr,
4877            0.0,
4878            0.0,
4879            0.0,
4880            0.0,
4881            -2.0 * bt,
4882            0.0,
4883            0.0,
4884            0.0,
4885            0.0,
4886            2.0 * nf,
4887            0.0,
4888            (left + right) * lr,
4889            (top + bottom) * bt,
4890            (far + near) * nf,
4891            1.0,
4892        ]))
4893    });
4894
4895    // mat4_look_at(eye, center, up) - view matrix (camera)
4896    define(interp, "mat4_look_at", Some(3), |_, args| {
4897        let eye = extract_vec3(&args[0], "mat4_look_at")?;
4898        let center = extract_vec3(&args[1], "mat4_look_at")?;
4899        let up = extract_vec3(&args[2], "mat4_look_at")?;
4900
4901        // Forward vector (z)
4902        let fx = center[0] - eye[0];
4903        let fy = center[1] - eye[1];
4904        let fz = center[2] - eye[2];
4905        let flen = (fx * fx + fy * fy + fz * fz).sqrt();
4906        let (fx, fy, fz) = (fx / flen, fy / flen, fz / flen);
4907
4908        // Right vector (x) = forward × up
4909        let rx = fy * up[2] - fz * up[1];
4910        let ry = fz * up[0] - fx * up[2];
4911        let rz = fx * up[1] - fy * up[0];
4912        let rlen = (rx * rx + ry * ry + rz * rz).sqrt();
4913        let (rx, ry, rz) = (rx / rlen, ry / rlen, rz / rlen);
4914
4915        // True up vector (y) = right × forward
4916        let ux = ry * fz - rz * fy;
4917        let uy = rz * fx - rx * fz;
4918        let uz = rx * fy - ry * fx;
4919
4920        Ok(make_mat4([
4921            rx,
4922            ux,
4923            -fx,
4924            0.0,
4925            ry,
4926            uy,
4927            -fy,
4928            0.0,
4929            rz,
4930            uz,
4931            -fz,
4932            0.0,
4933            -(rx * eye[0] + ry * eye[1] + rz * eye[2]),
4934            -(ux * eye[0] + uy * eye[1] + uz * eye[2]),
4935            -(-fx * eye[0] - fy * eye[1] - fz * eye[2]),
4936            1.0,
4937        ]))
4938    });
4939
4940    // mat4_inverse(m) - matrix inverse (for transformation matrices)
4941    define(interp, "mat4_inverse", Some(1), |_, args| {
4942        let m = extract_mat4(&args[0], "mat4_inverse")?;
4943
4944        // Optimized 4x4 matrix inverse using cofactors
4945        let a00 = m[0];
4946        let a01 = m[1];
4947        let a02 = m[2];
4948        let a03 = m[3];
4949        let a10 = m[4];
4950        let a11 = m[5];
4951        let a12 = m[6];
4952        let a13 = m[7];
4953        let a20 = m[8];
4954        let a21 = m[9];
4955        let a22 = m[10];
4956        let a23 = m[11];
4957        let a30 = m[12];
4958        let a31 = m[13];
4959        let a32 = m[14];
4960        let a33 = m[15];
4961
4962        let b00 = a00 * a11 - a01 * a10;
4963        let b01 = a00 * a12 - a02 * a10;
4964        let b02 = a00 * a13 - a03 * a10;
4965        let b03 = a01 * a12 - a02 * a11;
4966        let b04 = a01 * a13 - a03 * a11;
4967        let b05 = a02 * a13 - a03 * a12;
4968        let b06 = a20 * a31 - a21 * a30;
4969        let b07 = a20 * a32 - a22 * a30;
4970        let b08 = a20 * a33 - a23 * a30;
4971        let b09 = a21 * a32 - a22 * a31;
4972        let b10 = a21 * a33 - a23 * a31;
4973        let b11 = a22 * a33 - a23 * a32;
4974
4975        let det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
4976
4977        if det.abs() < 1e-10 {
4978            return Err(RuntimeError::new("mat4_inverse: singular matrix"));
4979        }
4980
4981        let inv_det = 1.0 / det;
4982
4983        Ok(make_mat4([
4984            (a11 * b11 - a12 * b10 + a13 * b09) * inv_det,
4985            (a02 * b10 - a01 * b11 - a03 * b09) * inv_det,
4986            (a31 * b05 - a32 * b04 + a33 * b03) * inv_det,
4987            (a22 * b04 - a21 * b05 - a23 * b03) * inv_det,
4988            (a12 * b08 - a10 * b11 - a13 * b07) * inv_det,
4989            (a00 * b11 - a02 * b08 + a03 * b07) * inv_det,
4990            (a32 * b02 - a30 * b05 - a33 * b01) * inv_det,
4991            (a20 * b05 - a22 * b02 + a23 * b01) * inv_det,
4992            (a10 * b10 - a11 * b08 + a13 * b06) * inv_det,
4993            (a01 * b08 - a00 * b10 - a03 * b06) * inv_det,
4994            (a30 * b04 - a31 * b02 + a33 * b00) * inv_det,
4995            (a21 * b02 - a20 * b04 - a23 * b00) * inv_det,
4996            (a11 * b07 - a10 * b09 - a12 * b06) * inv_det,
4997            (a00 * b09 - a01 * b07 + a02 * b06) * inv_det,
4998            (a31 * b01 - a30 * b03 - a32 * b00) * inv_det,
4999            (a20 * b03 - a21 * b01 + a22 * b00) * inv_det,
5000        ]))
5001    });
5002
5003    // mat4_transpose(m) - transpose matrix
5004    define(interp, "mat4_transpose", Some(1), |_, args| {
5005        let m = extract_mat4(&args[0], "mat4_transpose")?;
5006        Ok(make_mat4([
5007            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],
5008            m[11], m[15],
5009        ]))
5010    });
5011
5012    // -------------------------------------------------------------------------
5013    // MAT3 - 3x3 MATRICES (for normals, 2D transforms)
5014    // -------------------------------------------------------------------------
5015
5016    // mat3_identity() - 3x3 identity matrix
5017    define(interp, "mat3_identity", Some(0), |_, _| {
5018        Ok(make_mat3([1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0]))
5019    });
5020
5021    // mat3_from_mat4(m) - extract upper-left 3x3 from 4x4 (for normal matrix)
5022    define(interp, "mat3_from_mat4", Some(1), |_, args| {
5023        let m = extract_mat4(&args[0], "mat3_from_mat4")?;
5024        Ok(make_mat3([
5025            m[0], m[1], m[2], m[4], m[5], m[6], m[8], m[9], m[10],
5026        ]))
5027    });
5028
5029    // mat3_mul(a, b) - 3x3 matrix multiplication
5030    define(interp, "mat3_mul", Some(2), |_, args| {
5031        let a = extract_mat3(&args[0], "mat3_mul")?;
5032        let b = extract_mat3(&args[1], "mat3_mul")?;
5033
5034        let mut result = [0.0f64; 9];
5035        for col in 0..3 {
5036            for row in 0..3 {
5037                let mut sum = 0.0;
5038                for k in 0..3 {
5039                    sum += a[k * 3 + row] * b[col * 3 + k];
5040                }
5041                result[col * 3 + row] = sum;
5042            }
5043        }
5044        Ok(make_mat3(result))
5045    });
5046
5047    // mat3_transform(mat3, vec3) - transform 3D vector by 3x3 matrix
5048    define(interp, "mat3_transform", Some(2), |_, args| {
5049        let m = extract_mat3(&args[0], "mat3_transform")?;
5050        let v = extract_vec3(&args[1], "mat3_transform")?;
5051
5052        Ok(make_vec3(
5053            m[0] * v[0] + m[3] * v[1] + m[6] * v[2],
5054            m[1] * v[0] + m[4] * v[1] + m[7] * v[2],
5055            m[2] * v[0] + m[5] * v[1] + m[8] * v[2],
5056        ))
5057    });
5058
5059    // mat3_inverse(m) - 3x3 matrix inverse
5060    define(interp, "mat3_inverse", Some(1), |_, args| {
5061        let m = extract_mat3(&args[0], "mat3_inverse")?;
5062
5063        let det = m[0] * (m[4] * m[8] - m[5] * m[7]) - m[3] * (m[1] * m[8] - m[2] * m[7])
5064            + m[6] * (m[1] * m[5] - m[2] * m[4]);
5065
5066        if det.abs() < 1e-10 {
5067            return Err(RuntimeError::new("mat3_inverse: singular matrix"));
5068        }
5069
5070        let inv_det = 1.0 / det;
5071
5072        Ok(make_mat3([
5073            (m[4] * m[8] - m[5] * m[7]) * inv_det,
5074            (m[2] * m[7] - m[1] * m[8]) * inv_det,
5075            (m[1] * m[5] - m[2] * m[4]) * inv_det,
5076            (m[5] * m[6] - m[3] * m[8]) * inv_det,
5077            (m[0] * m[8] - m[2] * m[6]) * inv_det,
5078            (m[2] * m[3] - m[0] * m[5]) * inv_det,
5079            (m[3] * m[7] - m[4] * m[6]) * inv_det,
5080            (m[1] * m[6] - m[0] * m[7]) * inv_det,
5081            (m[0] * m[4] - m[1] * m[3]) * inv_det,
5082        ]))
5083    });
5084
5085    // mat3_transpose(m)
5086    define(interp, "mat3_transpose", Some(1), |_, args| {
5087        let m = extract_mat3(&args[0], "mat3_transpose")?;
5088        Ok(make_mat3([
5089            m[0], m[3], m[6], m[1], m[4], m[7], m[2], m[5], m[8],
5090        ]))
5091    });
5092}
5093
5094// Helper functions for graphics math
5095fn extract_number(v: &Value, fn_name: &str) -> Result<f64, RuntimeError> {
5096    match v {
5097        Value::Float(f) => Ok(*f),
5098        Value::Int(i) => Ok(*i as f64),
5099        _ => Err(RuntimeError::new(format!(
5100            "{}() requires number argument",
5101            fn_name
5102        ))),
5103    }
5104}
5105
5106fn extract_vec2(v: &Value, fn_name: &str) -> Result<[f64; 2], RuntimeError> {
5107    match v {
5108        Value::Array(arr) => {
5109            let arr = arr.borrow();
5110            if arr.len() < 2 {
5111                return Err(RuntimeError::new(format!(
5112                    "{}() requires vec2 (2 elements)",
5113                    fn_name
5114                )));
5115            }
5116            Ok([
5117                extract_number(&arr[0], fn_name)?,
5118                extract_number(&arr[1], fn_name)?,
5119            ])
5120        }
5121        _ => Err(RuntimeError::new(format!(
5122            "{}() requires vec2 array",
5123            fn_name
5124        ))),
5125    }
5126}
5127
5128fn extract_vec3(v: &Value, fn_name: &str) -> Result<[f64; 3], RuntimeError> {
5129    match v {
5130        Value::Array(arr) => {
5131            let arr = arr.borrow();
5132            if arr.len() < 3 {
5133                return Err(RuntimeError::new(format!(
5134                    "{}() requires vec3 (3 elements)",
5135                    fn_name
5136                )));
5137            }
5138            Ok([
5139                extract_number(&arr[0], fn_name)?,
5140                extract_number(&arr[1], fn_name)?,
5141                extract_number(&arr[2], fn_name)?,
5142            ])
5143        }
5144        _ => Err(RuntimeError::new(format!(
5145            "{}() requires vec3 array",
5146            fn_name
5147        ))),
5148    }
5149}
5150
5151fn extract_vec4(v: &Value, fn_name: &str) -> Result<[f64; 4], RuntimeError> {
5152    match v {
5153        Value::Array(arr) => {
5154            let arr = arr.borrow();
5155            if arr.len() < 4 {
5156                return Err(RuntimeError::new(format!(
5157                    "{}() requires vec4 (4 elements)",
5158                    fn_name
5159                )));
5160            }
5161            Ok([
5162                extract_number(&arr[0], fn_name)?,
5163                extract_number(&arr[1], fn_name)?,
5164                extract_number(&arr[2], fn_name)?,
5165                extract_number(&arr[3], fn_name)?,
5166            ])
5167        }
5168        _ => Err(RuntimeError::new(format!(
5169            "{}() requires vec4 array",
5170            fn_name
5171        ))),
5172    }
5173}
5174
5175fn extract_mat3(v: &Value, fn_name: &str) -> Result<[f64; 9], RuntimeError> {
5176    match v {
5177        Value::Array(arr) => {
5178            let arr = arr.borrow();
5179            if arr.len() < 9 {
5180                return Err(RuntimeError::new(format!(
5181                    "{}() requires mat3 (9 elements)",
5182                    fn_name
5183                )));
5184            }
5185            let mut result = [0.0f64; 9];
5186            for i in 0..9 {
5187                result[i] = extract_number(&arr[i], fn_name)?;
5188            }
5189            Ok(result)
5190        }
5191        _ => Err(RuntimeError::new(format!(
5192            "{}() requires mat3 array",
5193            fn_name
5194        ))),
5195    }
5196}
5197
5198fn extract_mat4(v: &Value, fn_name: &str) -> Result<[f64; 16], RuntimeError> {
5199    match v {
5200        Value::Array(arr) => {
5201            let arr = arr.borrow();
5202            if arr.len() < 16 {
5203                return Err(RuntimeError::new(format!(
5204                    "{}() requires mat4 (16 elements)",
5205                    fn_name
5206                )));
5207            }
5208            let mut result = [0.0f64; 16];
5209            for i in 0..16 {
5210                result[i] = extract_number(&arr[i], fn_name)?;
5211            }
5212            Ok(result)
5213        }
5214        _ => Err(RuntimeError::new(format!(
5215            "{}() requires mat4 array",
5216            fn_name
5217        ))),
5218    }
5219}
5220
5221fn make_vec2(x: f64, y: f64) -> Value {
5222    Value::Array(Rc::new(RefCell::new(vec![
5223        Value::Float(x),
5224        Value::Float(y),
5225    ])))
5226}
5227
5228fn make_vec3(x: f64, y: f64, z: f64) -> Value {
5229    Value::Array(Rc::new(RefCell::new(vec![
5230        Value::Float(x),
5231        Value::Float(y),
5232        Value::Float(z),
5233    ])))
5234}
5235
5236// Helper for making vec3 from array
5237fn make_vec3_arr(v: [f64; 3]) -> Value {
5238    make_vec3(v[0], v[1], v[2])
5239}
5240
5241fn make_vec4(x: f64, y: f64, z: f64, w: f64) -> Value {
5242    Value::Array(Rc::new(RefCell::new(vec![
5243        Value::Float(x),
5244        Value::Float(y),
5245        Value::Float(z),
5246        Value::Float(w),
5247    ])))
5248}
5249
5250fn make_mat3(m: [f64; 9]) -> Value {
5251    Value::Array(Rc::new(RefCell::new(
5252        m.iter().map(|&v| Value::Float(v)).collect(),
5253    )))
5254}
5255
5256fn make_mat4(m: [f64; 16]) -> Value {
5257    Value::Array(Rc::new(RefCell::new(
5258        m.iter().map(|&v| Value::Float(v)).collect(),
5259    )))
5260}
5261
5262// ============================================================================
5263// CONCURRENCY FUNCTIONS
5264// ============================================================================
5265// WARNING: Interpreter Limitations
5266// ---------------------------------
5267// The interpreter uses Rc<RefCell<>> which is NOT thread-safe (not Send/Sync).
5268// This means:
5269// - Channels work but block the main thread
5270// - Actors run single-threaded with message queuing
5271// - Thread primitives simulate behavior but don't provide true parallelism
5272// - Atomics work correctly for single-threaded access patterns
5273//
5274// For true parallel execution, compile with the JIT backend (--jit flag).
5275// The JIT uses Arc/Mutex and compiles to native code with proper threading.
5276// ============================================================================
5277
5278fn register_concurrency(interp: &mut Interpreter) {
5279    // --- CHANNELS ---
5280
5281    // channel_new - create a new channel for message passing
5282    define(interp, "channel_new", Some(0), |_, _| {
5283        let (sender, receiver) = mpsc::channel();
5284        let inner = ChannelInner {
5285            sender: Mutex::new(sender),
5286            receiver: Mutex::new(receiver),
5287        };
5288        Ok(Value::Channel(Arc::new(inner)))
5289    });
5290
5291    // channel_send - send a value on a channel (blocking)
5292    define(interp, "channel_send", Some(2), |_, args| {
5293        let channel = match &args[0] {
5294            Value::Channel(ch) => ch.clone(),
5295            _ => {
5296                return Err(RuntimeError::new(
5297                    "channel_send() requires channel as first argument",
5298                ))
5299            }
5300        };
5301        let value = args[1].clone();
5302
5303        let sender = channel
5304            .sender
5305            .lock()
5306            .map_err(|_| RuntimeError::new("channel mutex poisoned"))?;
5307        sender
5308            .send(value)
5309            .map_err(|_| RuntimeError::new("channel_send() failed: receiver dropped"))?;
5310
5311        Ok(Value::Null)
5312    });
5313
5314    // channel_recv - receive a value from a channel (blocking)
5315    define(interp, "channel_recv", Some(1), |_, args| {
5316        let channel = match &args[0] {
5317            Value::Channel(ch) => ch.clone(),
5318            _ => {
5319                return Err(RuntimeError::new(
5320                    "channel_recv() requires channel argument",
5321                ))
5322            }
5323        };
5324
5325        let receiver = channel
5326            .receiver
5327            .lock()
5328            .map_err(|_| RuntimeError::new("channel mutex poisoned"))?;
5329        match receiver.recv() {
5330            Ok(value) => Ok(value),
5331            Err(_) => Err(RuntimeError::new("channel_recv() failed: sender dropped")),
5332        }
5333    });
5334
5335    // channel_try_recv - non-blocking receive, returns Option
5336    define(interp, "channel_try_recv", Some(1), |_, args| {
5337        let channel = match &args[0] {
5338            Value::Channel(ch) => ch.clone(),
5339            _ => {
5340                return Err(RuntimeError::new(
5341                    "channel_try_recv() requires channel argument",
5342                ))
5343            }
5344        };
5345
5346        let receiver = channel
5347            .receiver
5348            .lock()
5349            .map_err(|_| RuntimeError::new("channel mutex poisoned"))?;
5350        match receiver.try_recv() {
5351            Ok(value) => {
5352                // Return Some(value) as a variant
5353                Ok(Value::Variant {
5354                    enum_name: "Option".to_string(),
5355                    variant_name: "Some".to_string(),
5356                    fields: Some(Rc::new(vec![value])),
5357                })
5358            }
5359            Err(mpsc::TryRecvError::Empty) => {
5360                // Return None
5361                Ok(Value::Variant {
5362                    enum_name: "Option".to_string(),
5363                    variant_name: "None".to_string(),
5364                    fields: None,
5365                })
5366            }
5367            Err(mpsc::TryRecvError::Disconnected) => Err(RuntimeError::new(
5368                "channel_try_recv() failed: sender dropped",
5369            )),
5370        }
5371    });
5372
5373    // channel_recv_timeout - receive with timeout in milliseconds
5374    define(interp, "channel_recv_timeout", Some(2), |_, args| {
5375        let channel = match &args[0] {
5376            Value::Channel(ch) => ch.clone(),
5377            _ => {
5378                return Err(RuntimeError::new(
5379                    "channel_recv_timeout() requires a channel as first argument.\n\
5380                 Create a channel with channel_new():\n\
5381                   let ch = channel_new();\n\
5382                   channel_send(ch, value);\n\
5383                   let result = channel_recv_timeout(ch, 1000);  // 1 second timeout",
5384                ))
5385            }
5386        };
5387        let timeout_ms = match &args[1] {
5388            Value::Int(ms) => *ms as u64,
5389            _ => {
5390                return Err(RuntimeError::new(
5391                    "channel_recv_timeout() requires timeout in milliseconds (integer).\n\
5392                 Example: channel_recv_timeout(ch, 1000)  // Wait up to 1 second",
5393                ))
5394            }
5395        };
5396
5397        let receiver = channel
5398            .receiver
5399            .lock()
5400            .map_err(|_| RuntimeError::new("channel mutex poisoned"))?;
5401        match receiver.recv_timeout(std::time::Duration::from_millis(timeout_ms)) {
5402            Ok(value) => Ok(Value::Variant {
5403                enum_name: "Option".to_string(),
5404                variant_name: "Some".to_string(),
5405                fields: Some(Rc::new(vec![value])),
5406            }),
5407            Err(mpsc::RecvTimeoutError::Timeout) => Ok(Value::Variant {
5408                enum_name: "Option".to_string(),
5409                variant_name: "None".to_string(),
5410                fields: None,
5411            }),
5412            Err(mpsc::RecvTimeoutError::Disconnected) => Err(RuntimeError::new(
5413                "channel_recv_timeout() failed: sender dropped",
5414            )),
5415        }
5416    });
5417
5418    // --- THREADS ---
5419    // Note: The interpreter's Value type uses Rc which is not Send.
5420    // For true threading, use channels to communicate primitive types.
5421    // These functions provide basic thread primitives.
5422
5423    // thread_spawn_detached - spawn a detached thread (no join)
5424    // Useful for background work, results communicated via channels
5425    define(interp, "thread_spawn_detached", Some(0), |_, _| {
5426        // Spawn a simple detached thread that does nothing
5427        // Real work should be done via channels
5428        thread::spawn(|| {
5429            // Background thread
5430        });
5431        Ok(Value::Null)
5432    });
5433
5434    // std::thread::spawn - spawn a thread with a closure
5435    // In interpreter mode, execute synchronously (Rc is not thread-safe)
5436    // Returns a JoinHandle-like value
5437    define(interp, "std·thread·spawn", Some(1), |interp, args| {
5438        // The argument should be a closure/function
5439        match &args[0] {
5440            Value::Function(f) => {
5441                // Execute the closure synchronously for now
5442                // This makes the server work in single-threaded mode
5443                match interp.call_function(f, vec![]) {
5444                    Ok(_) => {}
5445                    Err(e) => eprintln!("[Sigil thread] Error: {}", e),
5446                }
5447                // Return a mock JoinHandle
5448                let mut map = HashMap::new();
5449                map.insert("__type__".to_string(), Value::String(Rc::new("JoinHandle".to_string())));
5450                map.insert("done".to_string(), Value::Bool(true));
5451                Ok(Value::Map(Rc::new(RefCell::new(map))))
5452            }
5453            Value::BuiltIn(b) => {
5454                match (b.func)(interp, vec![]) {
5455                    Ok(_) => {}
5456                    Err(e) => eprintln!("[Sigil thread] Error: {}", e),
5457                }
5458                let mut map = HashMap::new();
5459                map.insert("__type__".to_string(), Value::String(Rc::new("JoinHandle".to_string())));
5460                map.insert("done".to_string(), Value::Bool(true));
5461                Ok(Value::Map(Rc::new(RefCell::new(map))))
5462            }
5463            _ => Err(RuntimeError::new("std::thread::spawn requires a closure")),
5464        }
5465    });
5466
5467    // thread_join - placeholder for join semantics
5468    // In interpreter, actual work is done via channels
5469    define(interp, "thread_join", Some(1), |_, args| {
5470        match &args[0] {
5471            Value::ThreadHandle(h) => {
5472                let mut guard = h
5473                    .lock()
5474                    .map_err(|_| RuntimeError::new("thread handle mutex poisoned"))?;
5475                if let Some(handle) = guard.take() {
5476                    match handle.join() {
5477                        Ok(v) => Ok(v),
5478                        Err(_) => Err(RuntimeError::new("thread panicked")),
5479                    }
5480                } else {
5481                    Err(RuntimeError::new("thread already joined"))
5482                }
5483            }
5484            // For non-handles, just return the value
5485            _ => Ok(args[0].clone()),
5486        }
5487    });
5488
5489    // thread_sleep - sleep for specified milliseconds
5490    define(interp, "thread_sleep", Some(1), |_, args| {
5491        let ms = match &args[0] {
5492            Value::Int(ms) => *ms as u64,
5493            Value::Float(ms) => *ms as u64,
5494            _ => {
5495                return Err(RuntimeError::new(
5496                    "thread_sleep() requires integer milliseconds",
5497                ))
5498            }
5499        };
5500
5501        thread::sleep(std::time::Duration::from_millis(ms));
5502        Ok(Value::Null)
5503    });
5504
5505    // thread_yield - yield the current thread
5506    define(interp, "thread_yield", Some(0), |_, _| {
5507        thread::yield_now();
5508        Ok(Value::Null)
5509    });
5510
5511    // thread_id - get current thread id as string
5512    define(interp, "thread_id", Some(0), |_, _| {
5513        let id = thread::current().id();
5514        Ok(Value::String(Rc::new(format!("{:?}", id))))
5515    });
5516
5517    // --- SYNCHRONIZATION PRIMITIVES ---
5518    // parking_lot::Mutex::new - create a mutex wrapper
5519    // Returns a Map with __type__="Mutex" and inner value
5520    define(interp, "parking_lot·Mutex·new", Some(1), |_, args| {
5521        let mut map = HashMap::new();
5522        map.insert("__type__".to_string(), Value::String(Rc::new("Mutex".to_string())));
5523        map.insert("inner".to_string(), args[0].clone());
5524        Ok(Value::Map(Rc::new(RefCell::new(map))))
5525    });
5526
5527    // Also register as std::sync::Mutex::new
5528    define(interp, "std·sync·Mutex·new", Some(1), |_, args| {
5529        let mut map = HashMap::new();
5530        map.insert("__type__".to_string(), Value::String(Rc::new("Mutex".to_string())));
5531        map.insert("inner".to_string(), args[0].clone());
5532        Ok(Value::Map(Rc::new(RefCell::new(map))))
5533    });
5534
5535    // parking_lot::RwLock::new - create a read-write lock wrapper
5536    define(interp, "parking_lot·RwLock·new", Some(1), |_, args| {
5537        let mut map = HashMap::new();
5538        map.insert("__type__".to_string(), Value::String(Rc::new("RwLock".to_string())));
5539        map.insert("inner".to_string(), args[0].clone());
5540        Ok(Value::Map(Rc::new(RefCell::new(map))))
5541    });
5542
5543    // std::sync::RwLock::new
5544    define(interp, "std·sync·RwLock·new", Some(1), |_, args| {
5545        let mut map = HashMap::new();
5546        map.insert("__type__".to_string(), Value::String(Rc::new("RwLock".to_string())));
5547        map.insert("inner".to_string(), args[0].clone());
5548        Ok(Value::Map(Rc::new(RefCell::new(map))))
5549    });
5550
5551    // RwLock::new (short form)
5552    define(interp, "RwLock·new", Some(1), |_, args| {
5553        let mut map = HashMap::new();
5554        map.insert("__type__".to_string(), Value::String(Rc::new("RwLock".to_string())));
5555        map.insert("inner".to_string(), args[0].clone());
5556        Ok(Value::Map(Rc::new(RefCell::new(map))))
5557    });
5558
5559    // AtomicU64::new - create atomic counter
5560    define(interp, "AtomicU64·new", Some(1), |_, args| {
5561        let val = match &args[0] {
5562            Value::Int(i) => *i,
5563            _ => 0,
5564        };
5565        let mut map = HashMap::new();
5566        map.insert("__type__".to_string(), Value::String(Rc::new("AtomicU64".to_string())));
5567        map.insert("value".to_string(), Value::Int(val));
5568        Ok(Value::Map(Rc::new(RefCell::new(map))))
5569    });
5570
5571    // std::sync::atomic::AtomicU64::new
5572    define(interp, "std·sync·atomic·AtomicU64·new", Some(1), |_, args| {
5573        let val = match &args[0] {
5574            Value::Int(i) => *i,
5575            _ => 0,
5576        };
5577        let mut map = HashMap::new();
5578        map.insert("__type__".to_string(), Value::String(Rc::new("AtomicU64".to_string())));
5579        map.insert("value".to_string(), Value::Int(val));
5580        Ok(Value::Map(Rc::new(RefCell::new(map))))
5581    });
5582
5583    // AtomicBool::new
5584    define(interp, "AtomicBool·new", Some(1), |_, args| {
5585        let val = match &args[0] {
5586            Value::Bool(b) => *b,
5587            _ => false,
5588        };
5589        let mut map = HashMap::new();
5590        map.insert("__type__".to_string(), Value::String(Rc::new("AtomicBool".to_string())));
5591        map.insert("value".to_string(), Value::Bool(val));
5592        Ok(Value::Map(Rc::new(RefCell::new(map))))
5593    });
5594
5595    define(interp, "std·sync·atomic·AtomicBool·new", Some(1), |_, args| {
5596        let val = match &args[0] {
5597            Value::Bool(b) => *b,
5598            _ => false,
5599        };
5600        let mut map = HashMap::new();
5601        map.insert("__type__".to_string(), Value::String(Rc::new("AtomicBool".to_string())));
5602        map.insert("value".to_string(), Value::Bool(val));
5603        Ok(Value::Map(Rc::new(RefCell::new(map))))
5604    });
5605
5606    // Arc::new - create atomic reference counted wrapper
5607    define(interp, "Arc·new", Some(1), |_, args| {
5608        let mut map = HashMap::new();
5609        map.insert("__type__".to_string(), Value::String(Rc::new("Arc".to_string())));
5610        map.insert("inner".to_string(), args[0].clone());
5611        Ok(Value::Map(Rc::new(RefCell::new(map))))
5612    });
5613
5614    define(interp, "std·sync·Arc·new", Some(1), |_, args| {
5615        let mut map = HashMap::new();
5616        map.insert("__type__".to_string(), Value::String(Rc::new("Arc".to_string())));
5617        map.insert("inner".to_string(), args[0].clone());
5618        Ok(Value::Map(Rc::new(RefCell::new(map))))
5619    });
5620
5621    // --- NETWORKING ---
5622    // TCP/IP networking support for HTTP servers
5623
5624    // TcpListener::bind - bind to an address and create a listener
5625    define(interp, "TcpListener·bind", Some(1), |_, args| {
5626        let addr_str = match &args[0] {
5627            Value::String(s) => s.to_string(),
5628            Value::Ref(r) => {
5629                if let Value::String(s) = &*r.borrow() {
5630                    s.to_string()
5631                } else {
5632                    return Err(RuntimeError::new("TcpListener::bind requires string address"));
5633                }
5634            }
5635            // Handle SocketAddr map (from parse())
5636            Value::Map(m) => {
5637                let borrowed = m.borrow();
5638                if let Some(Value::String(addr)) = borrowed.get("addr") {
5639                    addr.to_string()
5640                } else if let Some(Value::String(_)) = borrowed.get("__type__") {
5641                    // SocketAddr type, try addr field
5642                    if let Some(Value::String(addr)) = borrowed.get("addr") {
5643                        addr.to_string()
5644                    } else {
5645                        return Err(RuntimeError::new("SocketAddr missing addr field"));
5646                    }
5647                } else {
5648                    return Err(RuntimeError::new("TcpListener::bind requires string or SocketAddr"));
5649                }
5650            }
5651            _ => return Err(RuntimeError::new("TcpListener::bind requires string address")),
5652        };
5653
5654        // Parse the address
5655        let addr: std::net::SocketAddr = match addr_str.parse() {
5656            Ok(a) => a,
5657            Err(e) => return Err(RuntimeError::new(format!("Invalid address: {}", e))),
5658        };
5659
5660        // Bind the listener
5661        let listener = match std::net::TcpListener::bind(addr) {
5662            Ok(l) => l,
5663            Err(e) => return Err(RuntimeError::new(format!("Failed to bind: {}", e))),
5664        };
5665
5666        let local_addr = listener.local_addr().map(|a| a.to_string()).unwrap_or_default();
5667
5668        // Store the listener in the global registry
5669        let listener_id = store_listener(listener);
5670
5671        let mut map = HashMap::new();
5672        map.insert("__type__".to_string(), Value::String(Rc::new("TcpListener".to_string())));
5673        map.insert("addr".to_string(), Value::String(Rc::new(addr_str)));
5674        map.insert("local_addr".to_string(), Value::String(Rc::new(local_addr)));
5675        map.insert("__listener_id__".to_string(), Value::Int(listener_id as i64));
5676
5677        eprintln!("[Sigil] TcpListener bound to {} (id={})", addr, listener_id);
5678
5679        Ok(Value::Variant {
5680            enum_name: "Result".to_string(),
5681            variant_name: "Ok".to_string(),
5682            fields: Some(Rc::new(vec![Value::Map(Rc::new(RefCell::new(map)))])),
5683        })
5684    });
5685
5686    define(interp, "std·net·TcpListener·bind", Some(1), |_, args| {
5687        let addr_str = match &args[0] {
5688            Value::String(s) => s.to_string(),
5689            Value::Ref(r) => {
5690                if let Value::String(s) = &*r.borrow() {
5691                    s.to_string()
5692                } else {
5693                    return Err(RuntimeError::new("TcpListener::bind requires string address"));
5694                }
5695            }
5696            // Handle SocketAddr map (from parse())
5697            Value::Map(m) => {
5698                let borrowed = m.borrow();
5699                if let Some(Value::String(addr)) = borrowed.get("addr") {
5700                    addr.to_string()
5701                } else {
5702                    return Err(RuntimeError::new("TcpListener::bind requires string or SocketAddr"));
5703                }
5704            }
5705            _ => return Err(RuntimeError::new("TcpListener::bind requires string address")),
5706        };
5707
5708        let addr: std::net::SocketAddr = match addr_str.parse() {
5709            Ok(a) => a,
5710            Err(e) => return Err(RuntimeError::new(format!("Invalid address: {}", e))),
5711        };
5712
5713        let _listener = match std::net::TcpListener::bind(addr) {
5714            Ok(l) => l,
5715            Err(e) => return Err(RuntimeError::new(format!("Failed to bind: {}", e))),
5716        };
5717
5718        let mut map = HashMap::new();
5719        map.insert("__type__".to_string(), Value::String(Rc::new("TcpListener".to_string())));
5720        map.insert("addr".to_string(), Value::String(Rc::new(addr_str)));
5721
5722        eprintln!("[Sigil] TcpListener bound to {}", addr);
5723
5724        Ok(Value::Variant {
5725            enum_name: "Result".to_string(),
5726            variant_name: "Ok".to_string(),
5727            fields: Some(Rc::new(vec![Value::Map(Rc::new(RefCell::new(map)))])),
5728        })
5729    });
5730
5731    // SocketAddr::parse - parse a socket address string
5732    define(interp, "SocketAddr·parse", Some(1), |_, args| {
5733        let addr_str = match &args[0] {
5734            Value::String(s) => s.to_string(),
5735            _ => return Err(RuntimeError::new("SocketAddr::parse requires string")),
5736        };
5737
5738        match addr_str.parse::<std::net::SocketAddr>() {
5739            Ok(_) => {
5740                let mut map = HashMap::new();
5741                map.insert("__type__".to_string(), Value::String(Rc::new("SocketAddr".to_string())));
5742                map.insert("addr".to_string(), Value::String(Rc::new(addr_str)));
5743                Ok(Value::Variant {
5744                    enum_name: "Result".to_string(),
5745                    variant_name: "Ok".to_string(),
5746                    fields: Some(Rc::new(vec![Value::Map(Rc::new(RefCell::new(map)))])),
5747                })
5748            }
5749            Err(e) => Ok(Value::Variant {
5750                enum_name: "Result".to_string(),
5751                variant_name: "Err".to_string(),
5752                fields: Some(Rc::new(vec![Value::String(Rc::new(e.to_string()))])),
5753            }),
5754        }
5755    });
5756
5757    // --- TcpStream Methods ---
5758    // Methods for reading/writing from TcpStream connections
5759
5760    // TcpStream::peer_addr - get the remote address
5761    define(interp, "TcpStream·peer_addr", Some(1), |_, args| {
5762        let stream_id = match &args[0] {
5763            Value::Map(m) => {
5764                let borrowed = m.borrow();
5765                if let Some(Value::Int(id)) = borrowed.get("__stream_id__") {
5766                    *id as u64
5767                } else {
5768                    return Err(RuntimeError::new("TcpStream missing __stream_id__"));
5769                }
5770            }
5771            _ => return Err(RuntimeError::new("peer_addr requires TcpStream")),
5772        };
5773
5774        if let Some(guard) = get_stream_registry().lock().ok() {
5775            if let Some(stream) = guard.get(&stream_id) {
5776                match stream.peer_addr() {
5777                    Ok(addr) => {
5778                        let mut map = HashMap::new();
5779                        map.insert("__type__".to_string(), Value::String(Rc::new("SocketAddr".to_string())));
5780                        map.insert("addr".to_string(), Value::String(Rc::new(addr.to_string())));
5781                        Ok(Value::Variant {
5782                            enum_name: "Result".to_string(),
5783                            variant_name: "Ok".to_string(),
5784                            fields: Some(Rc::new(vec![Value::Map(Rc::new(RefCell::new(map)))])),
5785                        })
5786                    }
5787                    Err(e) => Ok(Value::Variant {
5788                        enum_name: "Result".to_string(),
5789                        variant_name: "Err".to_string(),
5790                        fields: Some(Rc::new(vec![Value::String(Rc::new(e.to_string()))])),
5791                    }),
5792                }
5793            } else {
5794                Err(RuntimeError::new("TcpStream not found in registry"))
5795            }
5796        } else {
5797            Err(RuntimeError::new("Failed to lock stream registry"))
5798        }
5799    });
5800
5801    // TcpStream::read - read bytes from stream
5802    define(interp, "TcpStream·read", Some(2), |_, args| {
5803        use std::io::Read;
5804
5805        let stream_id = match &args[0] {
5806            Value::Map(m) => {
5807                let borrowed = m.borrow();
5808                if let Some(Value::Int(id)) = borrowed.get("__stream_id__") {
5809                    *id as u64
5810                } else {
5811                    return Err(RuntimeError::new("TcpStream missing __stream_id__"));
5812                }
5813            }
5814            _ => return Err(RuntimeError::new("read requires TcpStream")),
5815        };
5816
5817        let size = match &args[1] {
5818            Value::Int(n) => *n as usize,
5819            _ => return Err(RuntimeError::new("read requires size as integer")),
5820        };
5821
5822        if let Some(mut guard) = get_stream_registry().lock().ok() {
5823            if let Some(stream) = guard.get_mut(&stream_id) {
5824                let mut buf = vec![0u8; size];
5825                match stream.read(&mut buf) {
5826                    Ok(n) => {
5827                        buf.truncate(n);
5828                        let bytes: Vec<Value> = buf.iter().map(|b| Value::Int(*b as i64)).collect();
5829                        Ok(Value::Variant {
5830                            enum_name: "Result".to_string(),
5831                            variant_name: "Ok".to_string(),
5832                            fields: Some(Rc::new(vec![Value::Array(Rc::new(RefCell::new(bytes)))])),
5833                        })
5834                    }
5835                    Err(e) => Ok(Value::Variant {
5836                        enum_name: "Result".to_string(),
5837                        variant_name: "Err".to_string(),
5838                        fields: Some(Rc::new(vec![Value::String(Rc::new(e.to_string()))])),
5839                    }),
5840                }
5841            } else {
5842                Err(RuntimeError::new("TcpStream not found in registry"))
5843            }
5844        } else {
5845            Err(RuntimeError::new("Failed to lock stream registry"))
5846        }
5847    });
5848
5849    // TcpStream::read_exact - read exact number of bytes
5850    define(interp, "TcpStream·read_exact", Some(2), |_, args| {
5851        use std::io::Read;
5852
5853        let stream_id = match &args[0] {
5854            Value::Map(m) => {
5855                let borrowed = m.borrow();
5856                if let Some(Value::Int(id)) = borrowed.get("__stream_id__") {
5857                    *id as u64
5858                } else {
5859                    return Err(RuntimeError::new("TcpStream missing __stream_id__"));
5860                }
5861            }
5862            _ => return Err(RuntimeError::new("read_exact requires TcpStream")),
5863        };
5864
5865        let size = match &args[1] {
5866            Value::Int(n) => *n as usize,
5867            _ => return Err(RuntimeError::new("read_exact requires size as integer")),
5868        };
5869
5870        if let Some(mut guard) = get_stream_registry().lock().ok() {
5871            if let Some(stream) = guard.get_mut(&stream_id) {
5872                let mut buf = vec![0u8; size];
5873                match stream.read_exact(&mut buf) {
5874                    Ok(()) => {
5875                        let bytes: Vec<Value> = buf.iter().map(|b| Value::Int(*b as i64)).collect();
5876                        Ok(Value::Variant {
5877                            enum_name: "Result".to_string(),
5878                            variant_name: "Ok".to_string(),
5879                            fields: Some(Rc::new(vec![Value::Array(Rc::new(RefCell::new(bytes)))])),
5880                        })
5881                    }
5882                    Err(e) => Ok(Value::Variant {
5883                        enum_name: "Result".to_string(),
5884                        variant_name: "Err".to_string(),
5885                        fields: Some(Rc::new(vec![Value::String(Rc::new(e.to_string()))])),
5886                    }),
5887                }
5888            } else {
5889                Err(RuntimeError::new("TcpStream not found in registry"))
5890            }
5891        } else {
5892            Err(RuntimeError::new("Failed to lock stream registry"))
5893        }
5894    });
5895
5896    // TcpStream::write_all - write all bytes to stream
5897    define(interp, "TcpStream·write_all", Some(2), |_, args| {
5898        use std::io::Write;
5899
5900        let stream_id = match &args[0] {
5901            Value::Map(m) => {
5902                let borrowed = m.borrow();
5903                if let Some(Value::Int(id)) = borrowed.get("__stream_id__") {
5904                    *id as u64
5905                } else {
5906                    return Err(RuntimeError::new("TcpStream missing __stream_id__"));
5907                }
5908            }
5909            _ => return Err(RuntimeError::new("write_all requires TcpStream")),
5910        };
5911
5912        // Handle various data types
5913        let data: Vec<u8> = match &args[1] {
5914            Value::String(s) => s.as_bytes().to_vec(),
5915            Value::Array(arr) => {
5916                arr.borrow().iter().filter_map(|v| {
5917                    if let Value::Int(n) = v { Some(*n as u8) } else { None }
5918                }).collect()
5919            }
5920            Value::Ref(r) => {
5921                if let Value::String(s) = &*r.borrow() {
5922                    s.as_bytes().to_vec()
5923                } else {
5924                    return Err(RuntimeError::new("write_all requires string or byte array"));
5925                }
5926            }
5927            _ => return Err(RuntimeError::new("write_all requires string or byte array")),
5928        };
5929
5930        if let Some(mut guard) = get_stream_registry().lock().ok() {
5931            if let Some(stream) = guard.get_mut(&stream_id) {
5932                match stream.write_all(&data) {
5933                    Ok(()) => Ok(Value::Variant {
5934                        enum_name: "Result".to_string(),
5935                        variant_name: "Ok".to_string(),
5936                        fields: Some(Rc::new(vec![Value::Null])),
5937                    }),
5938                    Err(e) => Ok(Value::Variant {
5939                        enum_name: "Result".to_string(),
5940                        variant_name: "Err".to_string(),
5941                        fields: Some(Rc::new(vec![Value::String(Rc::new(e.to_string()))])),
5942                    }),
5943                }
5944            } else {
5945                Err(RuntimeError::new("TcpStream not found in registry"))
5946            }
5947        } else {
5948            Err(RuntimeError::new("Failed to lock stream registry"))
5949        }
5950    });
5951
5952    // TcpStream::flush - flush the stream
5953    define(interp, "TcpStream·flush", Some(1), |_, args| {
5954        use std::io::Write;
5955
5956        let stream_id = match &args[0] {
5957            Value::Map(m) => {
5958                let borrowed = m.borrow();
5959                if let Some(Value::Int(id)) = borrowed.get("__stream_id__") {
5960                    *id as u64
5961                } else {
5962                    return Err(RuntimeError::new("TcpStream missing __stream_id__"));
5963                }
5964            }
5965            _ => return Err(RuntimeError::new("flush requires TcpStream")),
5966        };
5967
5968        if let Some(mut guard) = get_stream_registry().lock().ok() {
5969            if let Some(stream) = guard.get_mut(&stream_id) {
5970                match stream.flush() {
5971                    Ok(()) => Ok(Value::Variant {
5972                        enum_name: "Result".to_string(),
5973                        variant_name: "Ok".to_string(),
5974                        fields: Some(Rc::new(vec![Value::Null])),
5975                    }),
5976                    Err(e) => Ok(Value::Variant {
5977                        enum_name: "Result".to_string(),
5978                        variant_name: "Err".to_string(),
5979                        fields: Some(Rc::new(vec![Value::String(Rc::new(e.to_string()))])),
5980                    }),
5981                }
5982            } else {
5983                Err(RuntimeError::new("TcpStream not found in registry"))
5984            }
5985        } else {
5986            Err(RuntimeError::new("Failed to lock stream registry"))
5987        }
5988    });
5989
5990    // --- BufReader for HTTP parsing ---
5991
5992    // BufReader::new - create a buffered reader from a TcpStream
5993    define(interp, "BufReader·new", Some(1), |_, args| {
5994        use std::io::BufReader as StdBufReader;
5995
5996        // Handle both Map and Ref(Map) for &mut TcpStream
5997        let stream_id = match &args[0] {
5998            Value::Map(m) => {
5999                let borrowed = m.borrow();
6000                if let Some(Value::Int(id)) = borrowed.get("__stream_id__") {
6001                    *id as u64
6002                } else {
6003                    return Err(RuntimeError::new("BufReader::new requires TcpStream"));
6004                }
6005            }
6006            Value::Ref(r) => {
6007                // Handle &mut TcpStream - unwrap the Ref to get the Map
6008                let inner = r.borrow();
6009                if let Value::Map(m) = &*inner {
6010                    let borrowed = m.borrow();
6011                    if let Some(Value::Int(id)) = borrowed.get("__stream_id__") {
6012                        *id as u64
6013                    } else {
6014                        return Err(RuntimeError::new("BufReader::new requires TcpStream (missing stream_id in Ref)"));
6015                    }
6016                } else {
6017                    return Err(RuntimeError::new("BufReader::new requires TcpStream (Ref does not contain Map)"));
6018                }
6019            }
6020            _ => return Err(RuntimeError::new("BufReader::new requires TcpStream")),
6021        };
6022
6023        // Clone the stream and create a BufReader that persists
6024        let reader_id = if let Some(mut guard) = get_stream_registry().lock().ok() {
6025            if let Some(stream) = guard.get_mut(&stream_id) {
6026                let stream_clone = match stream.try_clone() {
6027                    Ok(s) => s,
6028                    Err(e) => return Err(RuntimeError::new(format!("Failed to clone stream: {}", e))),
6029                };
6030                let reader = StdBufReader::new(stream_clone);
6031                store_bufreader(reader)
6032            } else {
6033                return Err(RuntimeError::new("Stream not found in registry"));
6034            }
6035        } else {
6036            return Err(RuntimeError::new("Failed to lock stream registry"));
6037        };
6038
6039        let mut map = HashMap::new();
6040        map.insert("__type__".to_string(), Value::String(Rc::new("BufReader".to_string())));
6041        map.insert("__stream_id__".to_string(), Value::Int(stream_id as i64));
6042        map.insert("__reader_id__".to_string(), Value::Int(reader_id as i64));
6043        Ok(Value::Map(Rc::new(RefCell::new(map))))
6044    });
6045
6046    // BufReader::read_line - read a line from the buffered reader
6047    define(interp, "BufReader·read_line", Some(1), |_, args| {
6048        use std::io::BufRead;
6049
6050        let reader_id = match &args[0] {
6051            Value::Map(m) => {
6052                let borrowed = m.borrow();
6053                if let Some(Value::Int(id)) = borrowed.get("__reader_id__") {
6054                    *id as u64
6055                } else {
6056                    return Err(RuntimeError::new("BufReader missing __reader_id__"));
6057                }
6058            }
6059            _ => return Err(RuntimeError::new("read_line requires BufReader")),
6060        };
6061
6062        if let Some(mut guard) = get_bufreader_registry().lock().ok() {
6063            if let Some(reader) = guard.get_mut(&reader_id) {
6064                let mut line = String::new();
6065
6066                match reader.read_line(&mut line) {
6067                    Ok(n) => {
6068                        if n == 0 {
6069                            // EOF
6070                            Ok(Value::Variant {
6071                                enum_name: "Result".to_string(),
6072                                variant_name: "Ok".to_string(),
6073                                fields: Some(Rc::new(vec![Value::Null])),
6074                            })
6075                        } else {
6076                            Ok(Value::Variant {
6077                                enum_name: "Result".to_string(),
6078                                variant_name: "Ok".to_string(),
6079                                fields: Some(Rc::new(vec![Value::String(Rc::new(line))])),
6080                            })
6081                        }
6082                    }
6083                    Err(e) => Ok(Value::Variant {
6084                        enum_name: "Result".to_string(),
6085                        variant_name: "Err".to_string(),
6086                        fields: Some(Rc::new(vec![Value::String(Rc::new(e.to_string()))])),
6087                    }),
6088                }
6089            } else {
6090                Err(RuntimeError::new("BufReader not found in registry"))
6091            }
6092        } else {
6093            Err(RuntimeError::new("Failed to lock bufreader registry"))
6094        }
6095    });
6096
6097    // --- HTTP MIDDLEWARE STUBS ---
6098    // Stubs for Styx HTTP middleware until proper module path support is added
6099
6100    // Logger middleware
6101    define(interp, "styx_http·middleware·Logger·new", Some(0), |_, _| {
6102        let mut map = HashMap::new();
6103        map.insert("__type__".to_string(), Value::String(Rc::new("Logger".to_string())));
6104        map.insert("format".to_string(), Value::String(Rc::new("Common".to_string())));
6105        Ok(Value::Map(Rc::new(RefCell::new(map))))
6106    });
6107
6108    define(interp, "Logger·new", Some(0), |_, _| {
6109        let mut map = HashMap::new();
6110        map.insert("__type__".to_string(), Value::String(Rc::new("Logger".to_string())));
6111        map.insert("format".to_string(), Value::String(Rc::new("Common".to_string())));
6112        Ok(Value::Map(Rc::new(RefCell::new(map))))
6113    });
6114
6115    // CORS middleware
6116    define(interp, "styx_http·middleware·Cors·new", Some(0), |_, _| {
6117        let mut map = HashMap::new();
6118        map.insert("__type__".to_string(), Value::String(Rc::new("Cors".to_string())));
6119        map.insert("origins".to_string(), Value::Array(Rc::new(RefCell::new(vec![]))));
6120        Ok(Value::Map(Rc::new(RefCell::new(map))))
6121    });
6122
6123    define(interp, "Cors·new", Some(0), |_, _| {
6124        let mut map = HashMap::new();
6125        map.insert("__type__".to_string(), Value::String(Rc::new("Cors".to_string())));
6126        map.insert("origins".to_string(), Value::Array(Rc::new(RefCell::new(vec![]))));
6127        Ok(Value::Map(Rc::new(RefCell::new(map))))
6128    });
6129
6130    // Security headers middleware
6131    define(interp, "styx_http·middleware·SecurityHeaders·new", Some(0), |_, _| {
6132        let mut map = HashMap::new();
6133        map.insert("__type__".to_string(), Value::String(Rc::new("SecurityHeaders".to_string())));
6134        Ok(Value::Map(Rc::new(RefCell::new(map))))
6135    });
6136
6137    define(interp, "SecurityHeaders·new", Some(0), |_, _| {
6138        let mut map = HashMap::new();
6139        map.insert("__type__".to_string(), Value::String(Rc::new("SecurityHeaders".to_string())));
6140        Ok(Value::Map(Rc::new(RefCell::new(map))))
6141    });
6142
6143    // RateLimiter middleware
6144    define(interp, "styx_http·middleware·RateLimiter·new", Some(0), |_, _| {
6145        let mut map = HashMap::new();
6146        map.insert("__type__".to_string(), Value::String(Rc::new("RateLimiter".to_string())));
6147        Ok(Value::Map(Rc::new(RefCell::new(map))))
6148    });
6149
6150    define(interp, "RateLimiter·new", Some(0), |_, _| {
6151        let mut map = HashMap::new();
6152        map.insert("__type__".to_string(), Value::String(Rc::new("RateLimiter".to_string())));
6153        Ok(Value::Map(Rc::new(RefCell::new(map))))
6154    });
6155
6156    // RateLimit middleware (accepts rate and burst params)
6157    define(interp, "styx_http·middleware·RateLimit·new", None, |_, args| {
6158        let mut map = HashMap::new();
6159        map.insert("__type__".to_string(), Value::String(Rc::new("RateLimit".to_string())));
6160        if args.len() >= 2 {
6161            map.insert("rate".to_string(), args[0].clone());
6162            map.insert("burst".to_string(), args[1].clone());
6163        }
6164        Ok(Value::Map(Rc::new(RefCell::new(map))))
6165    });
6166
6167    define(interp, "RateLimit·new", None, |_, args| {
6168        let mut map = HashMap::new();
6169        map.insert("__type__".to_string(), Value::String(Rc::new("RateLimit".to_string())));
6170        if args.len() >= 2 {
6171            map.insert("rate".to_string(), args[0].clone());
6172            map.insert("burst".to_string(), args[1].clone());
6173        }
6174        Ok(Value::Map(Rc::new(RefCell::new(map))))
6175    });
6176
6177    // Compression middleware
6178    define(interp, "styx_http·middleware·Compression·new", Some(0), |_, _| {
6179        let mut map = HashMap::new();
6180        map.insert("__type__".to_string(), Value::String(Rc::new("Compression".to_string())));
6181        Ok(Value::Map(Rc::new(RefCell::new(map))))
6182    });
6183
6184    define(interp, "Compression·new", Some(0), |_, _| {
6185        let mut map = HashMap::new();
6186        map.insert("__type__".to_string(), Value::String(Rc::new("Compression".to_string())));
6187        Ok(Value::Map(Rc::new(RefCell::new(map))))
6188    });
6189
6190    // AuthMiddleware - authentication middleware with optional/required modes
6191    define(interp, "AuthMiddleware·optional", Some(0), |_, _| {
6192        let mut map = HashMap::new();
6193        map.insert("__type__".to_string(), Value::String(Rc::new("AuthMiddleware".to_string())));
6194        map.insert("mode".to_string(), Value::String(Rc::new("optional".to_string())));
6195        Ok(Value::Map(Rc::new(RefCell::new(map))))
6196    });
6197
6198    define(interp, "AuthMiddleware·required", Some(0), |_, _| {
6199        let mut map = HashMap::new();
6200        map.insert("__type__".to_string(), Value::String(Rc::new("AuthMiddleware".to_string())));
6201        map.insert("mode".to_string(), Value::String(Rc::new("required".to_string())));
6202        Ok(Value::Map(Rc::new(RefCell::new(map))))
6203    });
6204
6205    define(interp, "AuthMiddleware·new", Some(0), |_, _| {
6206        let mut map = HashMap::new();
6207        map.insert("__type__".to_string(), Value::String(Rc::new("AuthMiddleware".to_string())));
6208        map.insert("mode".to_string(), Value::String(Rc::new("required".to_string())));
6209        Ok(Value::Map(Rc::new(RefCell::new(map))))
6210    });
6211
6212    // --- ACTORS ---
6213    // Single-threaded actor model for the interpreter.
6214    // Messages are queued and processed synchronously.
6215    // For true async actors with background threads, use the JIT backend.
6216
6217    // spawn_actor - create a new actor with given name
6218    define(interp, "spawn_actor", Some(1), |_, args| {
6219        let name = match &args[0] {
6220            Value::String(s) => s.to_string(),
6221            _ => return Err(RuntimeError::new("actor_spawn() requires string name")),
6222        };
6223
6224        let inner = ActorInner {
6225            name,
6226            message_queue: Mutex::new(Vec::new()),
6227            message_count: std::sync::atomic::AtomicUsize::new(0),
6228        };
6229
6230        Ok(Value::Actor(Arc::new(inner)))
6231    });
6232
6233    // send_to_actor - send a message to an actor
6234    // Messages are queued for later processing
6235    define(interp, "send_to_actor", Some(3), |_, args| {
6236        let actor = match &args[0] {
6237            Value::Actor(a) => a.clone(),
6238            _ => {
6239                return Err(RuntimeError::new(
6240                    "actor_send() requires actor as first argument",
6241                ))
6242            }
6243        };
6244        let msg_type = match &args[1] {
6245            Value::String(s) => s.to_string(),
6246            _ => {
6247                return Err(RuntimeError::new(
6248                    "actor_send() requires string message type",
6249                ))
6250            }
6251        };
6252        let msg_data = format!("{}", args[2]);
6253
6254        let mut queue = actor
6255            .message_queue
6256            .lock()
6257            .map_err(|_| RuntimeError::new("actor queue poisoned"))?;
6258        queue.push((msg_type, msg_data));
6259        actor
6260            .message_count
6261            .fetch_add(1, std::sync::atomic::Ordering::SeqCst);
6262
6263        Ok(Value::Null)
6264    });
6265
6266    // tell_actor - alias for send_to_actor (Erlang/Akka style)
6267    define(interp, "tell_actor", Some(3), |_, args| {
6268        let actor = match &args[0] {
6269            Value::Actor(a) => a.clone(),
6270            _ => {
6271                return Err(RuntimeError::new(
6272                    "actor_tell() requires actor as first argument",
6273                ))
6274            }
6275        };
6276        let msg_type = match &args[1] {
6277            Value::String(s) => s.to_string(),
6278            _ => {
6279                return Err(RuntimeError::new(
6280                    "actor_tell() requires string message type",
6281                ))
6282            }
6283        };
6284        let msg_data = format!("{}", args[2]);
6285
6286        let mut queue = actor
6287            .message_queue
6288            .lock()
6289            .map_err(|_| RuntimeError::new("actor queue poisoned"))?;
6290        queue.push((msg_type, msg_data));
6291        actor
6292            .message_count
6293            .fetch_add(1, std::sync::atomic::Ordering::SeqCst);
6294
6295        Ok(Value::Null)
6296    });
6297
6298    // recv_from_actor - receive (pop) a message from the actor's queue
6299    // Returns Option<(type, data)>
6300    define(interp, "recv_from_actor", Some(1), |_, args| {
6301        let actor = match &args[0] {
6302            Value::Actor(a) => a.clone(),
6303            _ => return Err(RuntimeError::new("actor_recv() requires actor argument")),
6304        };
6305
6306        let mut queue = actor
6307            .message_queue
6308            .lock()
6309            .map_err(|_| RuntimeError::new("actor queue poisoned"))?;
6310        match queue.pop() {
6311            Some((msg_type, msg_data)) => {
6312                // Return Some((type, data))
6313                Ok(Value::Variant {
6314                    enum_name: "Option".to_string(),
6315                    variant_name: "Some".to_string(),
6316                    fields: Some(Rc::new(vec![Value::Tuple(Rc::new(vec![
6317                        Value::String(Rc::new(msg_type)),
6318                        Value::String(Rc::new(msg_data)),
6319                    ]))])),
6320                })
6321            }
6322            None => Ok(Value::Variant {
6323                enum_name: "Option".to_string(),
6324                variant_name: "None".to_string(),
6325                fields: None,
6326            }),
6327        }
6328    });
6329
6330    // get_actor_msg_count - get total messages ever sent to actor
6331    define(interp, "get_actor_msg_count", Some(1), |_, args| {
6332        let a = match &args[0] {
6333            Value::Actor(a) => a.clone(),
6334            _ => {
6335                return Err(RuntimeError::new(
6336                    "get_actor_msg_count() requires actor argument",
6337                ))
6338            }
6339        };
6340
6341        let count = a.message_count.load(std::sync::atomic::Ordering::SeqCst);
6342        Ok(Value::Int(count as i64))
6343    });
6344
6345    // get_actor_name - get actor's name
6346    define(interp, "get_actor_name", Some(1), |_, args| {
6347        let a = match &args[0] {
6348            Value::Actor(a) => a.clone(),
6349            _ => {
6350                return Err(RuntimeError::new(
6351                    "get_actor_name() requires actor argument",
6352                ))
6353            }
6354        };
6355
6356        Ok(Value::String(Rc::new(a.name.clone())))
6357    });
6358
6359    // get_actor_pending - get number of pending messages
6360    define(interp, "get_actor_pending", Some(1), |_, args| {
6361        let a = match &args[0] {
6362            Value::Actor(a) => a.clone(),
6363            _ => {
6364                return Err(RuntimeError::new(
6365                    "get_actor_pending() requires actor argument",
6366                ))
6367            }
6368        };
6369
6370        let queue = a
6371            .message_queue
6372            .lock()
6373            .map_err(|_| RuntimeError::new("actor queue poisoned"))?;
6374        Ok(Value::Int(queue.len() as i64))
6375    });
6376
6377    // --- SYNCHRONIZATION PRIMITIVES ---
6378
6379    // mutex_new - create a new mutex wrapping a value
6380    define(interp, "mutex_new", Some(1), |_, args| {
6381        let value = args[0].clone();
6382        // Store as a Map with special key for mutex semantics
6383        let mut map = std::collections::HashMap::new();
6384        map.insert("__mutex_value".to_string(), value);
6385        map.insert("__mutex_locked".to_string(), Value::Bool(false));
6386        Ok(Value::Map(Rc::new(RefCell::new(map))))
6387    });
6388
6389    // mutex_lock - lock a mutex and get the value
6390    define(interp, "mutex_lock", Some(1), |_, args| {
6391        let mutex = match &args[0] {
6392            Value::Map(m) => m.clone(),
6393            _ => return Err(RuntimeError::new("mutex_lock() requires mutex")),
6394        };
6395
6396        let mut map = mutex.borrow_mut();
6397        // Simple spin-wait for interpreter (not true mutex, but demonstrates concept)
6398        map.insert("__mutex_locked".to_string(), Value::Bool(true));
6399
6400        match map.get("__mutex_value") {
6401            Some(v) => Ok(v.clone()),
6402            None => Err(RuntimeError::new("invalid mutex")),
6403        }
6404    });
6405
6406    // mutex_unlock - unlock a mutex, optionally setting new value
6407    define(interp, "mutex_unlock", Some(2), |_, args| {
6408        let mutex = match &args[0] {
6409            Value::Map(m) => m.clone(),
6410            _ => return Err(RuntimeError::new("mutex_unlock() requires mutex")),
6411        };
6412        let new_value = args[1].clone();
6413
6414        let mut map = mutex.borrow_mut();
6415        map.insert("__mutex_value".to_string(), new_value);
6416        map.insert("__mutex_locked".to_string(), Value::Bool(false));
6417
6418        Ok(Value::Null)
6419    });
6420
6421    // atomic_new - create an atomic integer
6422    define(interp, "atomic_new", Some(1), |_, args| {
6423        let value = match &args[0] {
6424            Value::Int(i) => *i,
6425            _ => return Err(RuntimeError::new("atomic_new() requires integer")),
6426        };
6427
6428        // Wrap in Map with atomic semantics
6429        let mut map = std::collections::HashMap::new();
6430        map.insert("__atomic_value".to_string(), Value::Int(value));
6431        Ok(Value::Map(Rc::new(RefCell::new(map))))
6432    });
6433
6434    // atomic_load - atomically load value
6435    define(interp, "atomic_load", Some(1), |_, args| {
6436        let atomic = match &args[0] {
6437            Value::Map(m) => m.clone(),
6438            _ => return Err(RuntimeError::new("atomic_load() requires atomic")),
6439        };
6440
6441        let map = atomic.borrow();
6442        match map.get("__atomic_value") {
6443            Some(v) => Ok(v.clone()),
6444            None => Err(RuntimeError::new("invalid atomic")),
6445        }
6446    });
6447
6448    // atomic_store - atomically store value
6449    define(interp, "atomic_store", Some(2), |_, args| {
6450        let atomic = match &args[0] {
6451            Value::Map(m) => m.clone(),
6452            _ => return Err(RuntimeError::new("atomic_store() requires atomic")),
6453        };
6454        let value = match &args[1] {
6455            Value::Int(i) => *i,
6456            _ => return Err(RuntimeError::new("atomic_store() requires integer value")),
6457        };
6458
6459        let mut map = atomic.borrow_mut();
6460        map.insert("__atomic_value".to_string(), Value::Int(value));
6461        Ok(Value::Null)
6462    });
6463
6464    // atomic_add - atomically add and return old value
6465    define(interp, "atomic_add", Some(2), |_, args| {
6466        let atomic = match &args[0] {
6467            Value::Map(m) => m.clone(),
6468            _ => return Err(RuntimeError::new("atomic_add() requires atomic")),
6469        };
6470        let delta = match &args[1] {
6471            Value::Int(i) => *i,
6472            _ => return Err(RuntimeError::new("atomic_add() requires integer delta")),
6473        };
6474
6475        let mut map = atomic.borrow_mut();
6476        let old = match map.get("__atomic_value") {
6477            Some(Value::Int(i)) => *i,
6478            _ => return Err(RuntimeError::new("invalid atomic")),
6479        };
6480        map.insert("__atomic_value".to_string(), Value::Int(old + delta));
6481        Ok(Value::Int(old))
6482    });
6483
6484    // atomic_cas - compare and swap, returns bool success
6485    define(interp, "atomic_cas", Some(3), |_, args| {
6486        let atomic = match &args[0] {
6487            Value::Map(m) => m.clone(),
6488            _ => return Err(RuntimeError::new("atomic_cas() requires atomic")),
6489        };
6490        let expected = match &args[1] {
6491            Value::Int(i) => *i,
6492            _ => return Err(RuntimeError::new("atomic_cas() requires integer expected")),
6493        };
6494        let new_value = match &args[2] {
6495            Value::Int(i) => *i,
6496            _ => return Err(RuntimeError::new("atomic_cas() requires integer new value")),
6497        };
6498
6499        let mut map = atomic.borrow_mut();
6500        let current = match map.get("__atomic_value") {
6501            Some(Value::Int(i)) => *i,
6502            _ => return Err(RuntimeError::new("invalid atomic")),
6503        };
6504
6505        if current == expected {
6506            map.insert("__atomic_value".to_string(), Value::Int(new_value));
6507            Ok(Value::Bool(true))
6508        } else {
6509            Ok(Value::Bool(false))
6510        }
6511    });
6512
6513    // --- PARALLEL ITERATION ---
6514
6515    // parallel_map - map function over array in parallel (simplified)
6516    define(interp, "parallel_map", Some(2), |_, args| {
6517        let arr = match &args[0] {
6518            Value::Array(a) => a.borrow().clone(),
6519            _ => return Err(RuntimeError::new("parallel_map() requires array")),
6520        };
6521        let _func = args[1].clone();
6522
6523        // For interpreter, just return original array
6524        // Real parallelism needs thread-safe interpreter
6525        Ok(Value::Array(Rc::new(RefCell::new(arr))))
6526    });
6527
6528    // parallel_for - parallel for loop (simplified)
6529    define(interp, "parallel_for", Some(3), |_, args| {
6530        let start = match &args[0] {
6531            Value::Int(i) => *i,
6532            _ => return Err(RuntimeError::new("parallel_for() requires integer start")),
6533        };
6534        let end = match &args[1] {
6535            Value::Int(i) => *i,
6536            _ => return Err(RuntimeError::new("parallel_for() requires integer end")),
6537        };
6538        let _func = args[2].clone();
6539
6540        // For interpreter, execute sequentially
6541        // Returns range as array
6542        let range: Vec<Value> = (start..end).map(|i| Value::Int(i)).collect();
6543        Ok(Value::Array(Rc::new(RefCell::new(range))))
6544    });
6545
6546    // ============================================================================
6547    // ASYNC/AWAIT FUNCTIONS
6548    // ============================================================================
6549    // WARNING: Interpreter Blocking Behavior
6550    // --------------------------------------
6551    // In the interpreter, async operations use cooperative scheduling but
6552    // execute on the main thread. This means:
6553    // - async_sleep() blocks the interpreter for the specified duration
6554    // - await() polls futures but may block waiting for completion
6555    // - No true concurrent I/O - operations execute sequentially
6556    // - Future combinators (race, all) work but don't provide parallelism
6557    //
6558    // The async model is designed for composability and clean code structure.
6559    // For non-blocking async with true concurrency, use the JIT backend.
6560    // ============================================================================
6561
6562    // async_sleep - create a future that completes after specified milliseconds
6563    define(interp, "async_sleep", Some(1), |interp, args| {
6564        let ms = match &args[0] {
6565            Value::Int(ms) => *ms as u64,
6566            Value::Float(ms) => *ms as u64,
6567            _ => {
6568                return Err(RuntimeError::new(
6569                    "async_sleep() requires integer milliseconds",
6570                ))
6571            }
6572        };
6573
6574        Ok(interp.make_future_timer(std::time::Duration::from_millis(ms)))
6575    });
6576
6577    // future_ready - create an immediately resolved future
6578    define(interp, "future_ready", Some(1), |interp, args| {
6579        Ok(interp.make_future_immediate(args[0].clone()))
6580    });
6581
6582    // future_pending - create a pending future (never resolves)
6583    define(interp, "future_pending", Some(0), |_, _| {
6584        Ok(Value::Future(Rc::new(RefCell::new(
6585            crate::interpreter::FutureInner {
6586                state: crate::interpreter::FutureState::Pending,
6587                computation: None,
6588                complete_at: None,
6589            },
6590        ))))
6591    });
6592
6593    // is_future - check if a value is a future
6594    define(interp, "is_future", Some(1), |_, args| {
6595        Ok(Value::Bool(matches!(&args[0], Value::Future(_))))
6596    });
6597
6598    // is_ready - check if a future is ready
6599    define(interp, "is_ready", Some(1), |_, args| {
6600        match &args[0] {
6601            Value::Future(fut) => {
6602                let f = fut.borrow();
6603                Ok(Value::Bool(matches!(
6604                    f.state,
6605                    crate::interpreter::FutureState::Ready(_)
6606                )))
6607            }
6608            _ => Ok(Value::Bool(true)), // Non-futures are always "ready"
6609        }
6610    });
6611
6612    // join_futures - join multiple futures into one that resolves to array
6613    define(interp, "join_futures", Some(1), |_, args| {
6614        let futures = match &args[0] {
6615            Value::Array(arr) => {
6616                let arr = arr.borrow();
6617                let mut futs = Vec::new();
6618                for v in arr.iter() {
6619                    match v {
6620                        Value::Future(f) => futs.push(f.clone()),
6621                        _ => {
6622                            return Err(RuntimeError::new(
6623                                "join_futures() requires array of futures",
6624                            ))
6625                        }
6626                    }
6627                }
6628                futs
6629            }
6630            _ => {
6631                return Err(RuntimeError::new(
6632                    "join_futures() requires array of futures",
6633                ))
6634            }
6635        };
6636
6637        Ok(Value::Future(Rc::new(RefCell::new(
6638            crate::interpreter::FutureInner {
6639                state: crate::interpreter::FutureState::Pending,
6640                computation: Some(crate::interpreter::FutureComputation::Join(futures)),
6641                complete_at: None,
6642            },
6643        ))))
6644    });
6645
6646    // race_futures - return first future to complete
6647    define(interp, "race_futures", Some(1), |_, args| {
6648        let futures = match &args[0] {
6649            Value::Array(arr) => {
6650                let arr = arr.borrow();
6651                let mut futs = Vec::new();
6652                for v in arr.iter() {
6653                    match v {
6654                        Value::Future(f) => futs.push(f.clone()),
6655                        _ => {
6656                            return Err(RuntimeError::new(
6657                                "race_futures() requires array of futures",
6658                            ))
6659                        }
6660                    }
6661                }
6662                futs
6663            }
6664            _ => {
6665                return Err(RuntimeError::new(
6666                    "race_futures() requires array of futures",
6667                ))
6668            }
6669        };
6670
6671        Ok(Value::Future(Rc::new(RefCell::new(
6672            crate::interpreter::FutureInner {
6673                state: crate::interpreter::FutureState::Pending,
6674                computation: Some(crate::interpreter::FutureComputation::Race(futures)),
6675                complete_at: None,
6676            },
6677        ))))
6678    });
6679
6680    // poll_future - try to resolve a future without blocking (returns Option)
6681    define(interp, "poll_future", Some(1), |_, args| {
6682        match &args[0] {
6683            Value::Future(fut) => {
6684                let f = fut.borrow();
6685                match &f.state {
6686                    crate::interpreter::FutureState::Ready(v) => Ok(Value::Variant {
6687                        enum_name: "Option".to_string(),
6688                        variant_name: "Some".to_string(),
6689                        fields: Some(Rc::new(vec![(**v).clone()])),
6690                    }),
6691                    _ => Ok(Value::Variant {
6692                        enum_name: "Option".to_string(),
6693                        variant_name: "None".to_string(),
6694                        fields: None,
6695                    }),
6696                }
6697            }
6698            // Non-futures return Some(value)
6699            other => Ok(Value::Variant {
6700                enum_name: "Option".to_string(),
6701                variant_name: "Some".to_string(),
6702                fields: Some(Rc::new(vec![other.clone()])),
6703            }),
6704        }
6705    });
6706}
6707
6708// ============================================================================
6709// JSON FUNCTIONS
6710// ============================================================================
6711
6712fn register_json(interp: &mut Interpreter) {
6713    // json_parse - parse JSON string into Sigil value
6714    define(interp, "json_parse", Some(1), |_, args| {
6715        let json_str = match &args[0] {
6716            Value::String(s) => s.as_str(),
6717            _ => return Err(RuntimeError::new("json_parse() requires string argument")),
6718        };
6719
6720        fn json_to_value(json: &serde_json::Value) -> Value {
6721            match json {
6722                serde_json::Value::Null => Value::Null,
6723                serde_json::Value::Bool(b) => Value::Bool(*b),
6724                serde_json::Value::Number(n) => {
6725                    if let Some(i) = n.as_i64() {
6726                        Value::Int(i)
6727                    } else if let Some(f) = n.as_f64() {
6728                        Value::Float(f)
6729                    } else {
6730                        Value::Null
6731                    }
6732                }
6733                serde_json::Value::String(s) => Value::String(Rc::new(s.clone())),
6734                serde_json::Value::Array(arr) => {
6735                    let values: Vec<Value> = arr.iter().map(json_to_value).collect();
6736                    Value::Array(Rc::new(RefCell::new(values)))
6737                }
6738                serde_json::Value::Object(obj) => {
6739                    let mut map = HashMap::new();
6740                    for (k, v) in obj {
6741                        map.insert(k.clone(), json_to_value(v));
6742                    }
6743                    Value::Map(Rc::new(RefCell::new(map)))
6744                }
6745            }
6746        }
6747
6748        match serde_json::from_str(json_str) {
6749            Ok(json) => Ok(json_to_value(&json)),
6750            Err(e) => Err(RuntimeError::new(format!("JSON parse error: {}", e))),
6751        }
6752    });
6753
6754    // json_stringify - convert Sigil value to JSON string
6755    define(interp, "json_stringify", Some(1), |_, args| {
6756        fn value_to_json(val: &Value) -> serde_json::Value {
6757            match val {
6758                Value::Null => serde_json::Value::Null,
6759                Value::Bool(b) => serde_json::Value::Bool(*b),
6760                Value::Int(n) => serde_json::Value::Number(serde_json::Number::from(*n)),
6761                Value::Float(f) => serde_json::Number::from_f64(*f)
6762                    .map(serde_json::Value::Number)
6763                    .unwrap_or(serde_json::Value::Null),
6764                Value::String(s) => serde_json::Value::String(s.to_string()),
6765                Value::Array(arr) => {
6766                    let arr = arr.borrow();
6767                    serde_json::Value::Array(arr.iter().map(value_to_json).collect())
6768                }
6769                Value::Tuple(t) => serde_json::Value::Array(t.iter().map(value_to_json).collect()),
6770                Value::Map(map) => {
6771                    let map = map.borrow();
6772                    let obj: serde_json::Map<String, serde_json::Value> = map
6773                        .iter()
6774                        .map(|(k, v)| (k.clone(), value_to_json(v)))
6775                        .collect();
6776                    serde_json::Value::Object(obj)
6777                }
6778                Value::Struct { fields, .. } => {
6779                    let fields = fields.borrow();
6780                    let obj: serde_json::Map<String, serde_json::Value> = fields
6781                        .iter()
6782                        .map(|(k, v)| (k.clone(), value_to_json(v)))
6783                        .collect();
6784                    serde_json::Value::Object(obj)
6785                }
6786                _ => serde_json::Value::String(format!("{}", val)),
6787            }
6788        }
6789
6790        let json = value_to_json(&args[0]);
6791        Ok(Value::String(Rc::new(json.to_string())))
6792    });
6793
6794    // json_pretty - convert to pretty-printed JSON
6795    define(interp, "json_pretty", Some(1), |_, args| {
6796        fn value_to_json(val: &Value) -> serde_json::Value {
6797            match val {
6798                Value::Null => serde_json::Value::Null,
6799                Value::Bool(b) => serde_json::Value::Bool(*b),
6800                Value::Int(n) => serde_json::Value::Number(serde_json::Number::from(*n)),
6801                Value::Float(f) => serde_json::Number::from_f64(*f)
6802                    .map(serde_json::Value::Number)
6803                    .unwrap_or(serde_json::Value::Null),
6804                Value::String(s) => serde_json::Value::String(s.to_string()),
6805                Value::Array(arr) => {
6806                    let arr = arr.borrow();
6807                    serde_json::Value::Array(arr.iter().map(value_to_json).collect())
6808                }
6809                Value::Map(map) => {
6810                    let map = map.borrow();
6811                    let obj: serde_json::Map<String, serde_json::Value> = map
6812                        .iter()
6813                        .map(|(k, v)| (k.clone(), value_to_json(v)))
6814                        .collect();
6815                    serde_json::Value::Object(obj)
6816                }
6817                _ => serde_json::Value::String(format!("{}", val)),
6818            }
6819        }
6820
6821        let json = value_to_json(&args[0]);
6822        match serde_json::to_string_pretty(&json) {
6823            Ok(s) => Ok(Value::String(Rc::new(s))),
6824            Err(e) => Err(RuntimeError::new(format!("JSON stringify error: {}", e))),
6825        }
6826    });
6827
6828    // json_get - get value at JSON path (dot notation)
6829    define(interp, "json_get", Some(2), |_, args| {
6830        let path = match &args[1] {
6831            Value::String(s) => s.to_string(),
6832            _ => return Err(RuntimeError::new("json_get() requires string path")),
6833        };
6834
6835        let mut current = args[0].clone();
6836        for key in path.split('.') {
6837            current = match &current {
6838                Value::Map(map) => {
6839                    let map = map.borrow();
6840                    map.get(key).cloned().unwrap_or(Value::Null)
6841                }
6842                Value::Array(arr) => {
6843                    if let Ok(idx) = key.parse::<usize>() {
6844                        let arr = arr.borrow();
6845                        arr.get(idx).cloned().unwrap_or(Value::Null)
6846                    } else {
6847                        Value::Null
6848                    }
6849                }
6850                _ => Value::Null,
6851            };
6852        }
6853        Ok(current)
6854    });
6855
6856    // json_set - set value at JSON path
6857    define(interp, "json_set", Some(3), |_, args| {
6858        let path = match &args[1] {
6859            Value::String(s) => s.to_string(),
6860            _ => return Err(RuntimeError::new("json_set() requires string path")),
6861        };
6862        let new_value = args[2].clone();
6863
6864        // For simplicity, only handle single-level paths
6865        match &args[0] {
6866            Value::Map(map) => {
6867                let mut map = map.borrow_mut();
6868                map.insert(path, new_value);
6869                Ok(Value::Map(Rc::new(RefCell::new(map.clone()))))
6870            }
6871            _ => Err(RuntimeError::new("json_set() requires map/object")),
6872        }
6873    });
6874}
6875
6876// ============================================================================
6877// FILE SYSTEM FUNCTIONS
6878// ============================================================================
6879
6880fn register_fs(interp: &mut Interpreter) {
6881    // fs_read - read entire file as string
6882    define(interp, "fs_read", Some(1), |_, args| {
6883        let path = match &args[0] {
6884            Value::String(s) => s.to_string(),
6885            _ => return Err(RuntimeError::new("fs_read() requires string path")),
6886        };
6887
6888        match std::fs::read_to_string(&path) {
6889            Ok(content) => Ok(Value::String(Rc::new(content))),
6890            Err(e) => Err(RuntimeError::new(format!("fs_read() error: {}", e))),
6891        }
6892    });
6893
6894    // fs_read_bytes - read file as byte array
6895    define(interp, "fs_read_bytes", Some(1), |_, args| {
6896        let path = match &args[0] {
6897            Value::String(s) => s.to_string(),
6898            _ => return Err(RuntimeError::new("fs_read_bytes() requires string path")),
6899        };
6900
6901        match std::fs::read(&path) {
6902            Ok(bytes) => {
6903                let values: Vec<Value> = bytes.iter().map(|b| Value::Int(*b as i64)).collect();
6904                Ok(Value::Array(Rc::new(RefCell::new(values))))
6905            }
6906            Err(e) => Err(RuntimeError::new(format!("fs_read_bytes() error: {}", e))),
6907        }
6908    });
6909
6910    // fs_write - write string to file
6911    define(interp, "fs_write", Some(2), |_, args| {
6912        let path = match &args[0] {
6913            Value::String(s) => s.to_string(),
6914            _ => return Err(RuntimeError::new("fs_write() requires string path")),
6915        };
6916        let content = format!("{}", args[1]);
6917
6918        match std::fs::write(&path, content) {
6919            Ok(()) => Ok(Value::Null),
6920            Err(e) => Err(RuntimeError::new(format!("fs_write() error: {}", e))),
6921        }
6922    });
6923
6924    // fs_append - append to file
6925    define(interp, "fs_append", Some(2), |_, args| {
6926        let path = match &args[0] {
6927            Value::String(s) => s.to_string(),
6928            _ => return Err(RuntimeError::new("fs_append() requires string path")),
6929        };
6930        let content = format!("{}", args[1]);
6931
6932        use std::fs::OpenOptions;
6933        match OpenOptions::new().append(true).create(true).open(&path) {
6934            Ok(mut file) => {
6935                use std::io::Write;
6936                match file.write_all(content.as_bytes()) {
6937                    Ok(()) => Ok(Value::Null),
6938                    Err(e) => Err(RuntimeError::new(format!("fs_append() write error: {}", e))),
6939                }
6940            }
6941            Err(e) => Err(RuntimeError::new(format!("fs_append() error: {}", e))),
6942        }
6943    });
6944
6945    // fs_exists - check if path exists
6946    define(interp, "fs_exists", Some(1), |_, args| {
6947        let path = match &args[0] {
6948            Value::String(s) => s.to_string(),
6949            _ => return Err(RuntimeError::new("fs_exists() requires string path")),
6950        };
6951        Ok(Value::Bool(std::path::Path::new(&path).exists()))
6952    });
6953
6954    // fs_is_file - check if path is a file
6955    define(interp, "fs_is_file", Some(1), |_, args| {
6956        let path = match &args[0] {
6957            Value::String(s) => s.to_string(),
6958            _ => return Err(RuntimeError::new("fs_is_file() requires string path")),
6959        };
6960        Ok(Value::Bool(std::path::Path::new(&path).is_file()))
6961    });
6962
6963    // fs_is_dir - check if path is a directory
6964    define(interp, "fs_is_dir", Some(1), |_, args| {
6965        let path = match &args[0] {
6966            Value::String(s) => s.to_string(),
6967            _ => return Err(RuntimeError::new("fs_is_dir() requires string path")),
6968        };
6969        Ok(Value::Bool(std::path::Path::new(&path).is_dir()))
6970    });
6971
6972    // fs_mkdir - create directory
6973    define(interp, "fs_mkdir", Some(1), |_, args| {
6974        let path = match &args[0] {
6975            Value::String(s) => s.to_string(),
6976            _ => return Err(RuntimeError::new("fs_mkdir() requires string path")),
6977        };
6978
6979        match std::fs::create_dir_all(&path) {
6980            Ok(()) => Ok(Value::Null),
6981            Err(e) => Err(RuntimeError::new(format!("fs_mkdir() error: {}", e))),
6982        }
6983    });
6984
6985    // fs_remove - remove file or directory
6986    define(interp, "fs_remove", Some(1), |_, args| {
6987        let path = match &args[0] {
6988            Value::String(s) => s.to_string(),
6989            _ => return Err(RuntimeError::new("fs_remove() requires string path")),
6990        };
6991
6992        let p = std::path::Path::new(&path);
6993        let result = if p.is_dir() {
6994            std::fs::remove_dir_all(&path)
6995        } else {
6996            std::fs::remove_file(&path)
6997        };
6998
6999        match result {
7000            Ok(()) => Ok(Value::Null),
7001            Err(e) => Err(RuntimeError::new(format!("fs_remove() error: {}", e))),
7002        }
7003    });
7004
7005    // fs_list - list directory contents
7006    define(interp, "fs_list", Some(1), |_, args| {
7007        let path = match &args[0] {
7008            Value::String(s) => s.to_string(),
7009            _ => return Err(RuntimeError::new("fs_list() requires string path")),
7010        };
7011
7012        match std::fs::read_dir(&path) {
7013            Ok(entries) => {
7014                let mut files = Vec::new();
7015                for entry in entries.flatten() {
7016                    if let Some(name) = entry.file_name().to_str() {
7017                        files.push(Value::String(Rc::new(name.to_string())));
7018                    }
7019                }
7020                Ok(Value::Array(Rc::new(RefCell::new(files))))
7021            }
7022            Err(e) => Err(RuntimeError::new(format!("fs_list() error: {}", e))),
7023        }
7024    });
7025
7026    // fs_copy - copy file
7027    define(interp, "fs_copy", Some(2), |_, args| {
7028        let src = match &args[0] {
7029            Value::String(s) => s.to_string(),
7030            _ => return Err(RuntimeError::new("fs_copy() requires string source path")),
7031        };
7032        let dst = match &args[1] {
7033            Value::String(s) => s.to_string(),
7034            _ => {
7035                return Err(RuntimeError::new(
7036                    "fs_copy() requires string destination path",
7037                ))
7038            }
7039        };
7040
7041        match std::fs::copy(&src, &dst) {
7042            Ok(bytes) => Ok(Value::Int(bytes as i64)),
7043            Err(e) => Err(RuntimeError::new(format!("fs_copy() error: {}", e))),
7044        }
7045    });
7046
7047    // fs_rename - rename/move file
7048    define(interp, "fs_rename", Some(2), |_, args| {
7049        let src = match &args[0] {
7050            Value::String(s) => s.to_string(),
7051            _ => return Err(RuntimeError::new("fs_rename() requires string source path")),
7052        };
7053        let dst = match &args[1] {
7054            Value::String(s) => s.to_string(),
7055            _ => {
7056                return Err(RuntimeError::new(
7057                    "fs_rename() requires string destination path",
7058                ))
7059            }
7060        };
7061
7062        match std::fs::rename(&src, &dst) {
7063            Ok(()) => Ok(Value::Null),
7064            Err(e) => Err(RuntimeError::new(format!("fs_rename() error: {}", e))),
7065        }
7066    });
7067
7068    // fs_size - get file size in bytes
7069    define(interp, "fs_size", Some(1), |_, args| {
7070        let path = match &args[0] {
7071            Value::String(s) => s.to_string(),
7072            _ => return Err(RuntimeError::new("fs_size() requires string path")),
7073        };
7074
7075        match std::fs::metadata(&path) {
7076            Ok(meta) => Ok(Value::Int(meta.len() as i64)),
7077            Err(e) => Err(RuntimeError::new(format!("fs_size() error: {}", e))),
7078        }
7079    });
7080
7081    // path_join - join path components
7082    define(interp, "path_join", None, |_, args| {
7083        let mut path = std::path::PathBuf::new();
7084        for arg in &args {
7085            match arg {
7086                Value::String(s) => path.push(s.as_str()),
7087                Value::Array(arr) => {
7088                    for v in arr.borrow().iter() {
7089                        if let Value::String(s) = v {
7090                            path.push(s.as_str());
7091                        }
7092                    }
7093                }
7094                _ => {}
7095            }
7096        }
7097        Ok(Value::String(Rc::new(path.to_string_lossy().to_string())))
7098    });
7099
7100    // path_parent - get parent directory
7101    define(interp, "path_parent", Some(1), |_, args| {
7102        let path = match &args[0] {
7103            Value::String(s) => s.to_string(),
7104            _ => return Err(RuntimeError::new("path_parent() requires string path")),
7105        };
7106
7107        let p = std::path::Path::new(&path);
7108        match p.parent() {
7109            Some(parent) => Ok(Value::String(Rc::new(parent.to_string_lossy().to_string()))),
7110            None => Ok(Value::Null),
7111        }
7112    });
7113
7114    // path_filename - get filename component
7115    define(interp, "path_filename", Some(1), |_, args| {
7116        let path = match &args[0] {
7117            Value::String(s) => s.to_string(),
7118            _ => return Err(RuntimeError::new("path_filename() requires string path")),
7119        };
7120
7121        let p = std::path::Path::new(&path);
7122        match p.file_name() {
7123            Some(name) => Ok(Value::String(Rc::new(name.to_string_lossy().to_string()))),
7124            None => Ok(Value::Null),
7125        }
7126    });
7127
7128    // path_extension - get file extension
7129    define(interp, "path_extension", Some(1), |_, args| {
7130        let path = match &args[0] {
7131            Value::String(s) => s.to_string(),
7132            _ => return Err(RuntimeError::new("path_extension() requires string path")),
7133        };
7134
7135        let p = std::path::Path::new(&path);
7136        match p.extension() {
7137            Some(ext) => Ok(Value::String(Rc::new(ext.to_string_lossy().to_string()))),
7138            None => Ok(Value::Null),
7139        }
7140    });
7141
7142    // ============================================================================
7143    // FFI-style functions for self-hosted compiler compatibility
7144    // These provide the low-level file I/O that the self-hosted compiler expects
7145    // ============================================================================
7146
7147    // Store last read file content for sigil_file_len()
7148    use std::cell::RefCell;
7149    use std::collections::HashMap;
7150    thread_local! {
7151        static LAST_FILE_CONTENT: RefCell<String> = RefCell::new(String::new());
7152        // Fake pointer map: stores strings that can be looked up by pointer ID
7153        static FAKE_PTR_MAP: RefCell<HashMap<i64, String>> = RefCell::new(HashMap::new());
7154    }
7155
7156    // sigil_read_file - read file content (FFI-compatible interface)
7157    // Takes path pointer and length, returns pointer to content
7158    // In interpreter, we fake the pointer API and just read the file
7159    define(interp, "sigil_read_file", Some(2), |_, args| {
7160        // Look up the path from either a string or a fake pointer ID
7161        let path = match &args[0] {
7162            Value::String(s) => s.to_string(),
7163            Value::Int(ptr_id) => {
7164                // Look up the string from the fake pointer map
7165                FAKE_PTR_MAP.with(|map| {
7166                    map.borrow().get(ptr_id).cloned()
7167                }).ok_or_else(|| RuntimeError::new(format!(
7168                    "sigil_read_file: invalid pointer {}", ptr_id
7169                )))?
7170            }
7171            _ => return Err(RuntimeError::new("sigil_read_file() requires string path")),
7172        };
7173
7174        match std::fs::read_to_string(&path) {
7175            Ok(content) => {
7176                // Store content for sigil_file_len
7177                LAST_FILE_CONTENT.with(|last| {
7178                    *last.borrow_mut() = content.clone();
7179                });
7180                // Return the content as a string (not a pointer in interpreted mode)
7181                Ok(Value::String(Rc::new(content)))
7182            }
7183            Err(_) => Ok(Value::Null), // Return null for error (like a null pointer)
7184        }
7185    });
7186
7187    // sigil_file_len - get length of last read file
7188    define(interp, "sigil_file_len", Some(0), |_, _| {
7189        LAST_FILE_CONTENT.with(|last| {
7190            Ok(Value::Int(last.borrow().len() as i64))
7191        })
7192    });
7193
7194    // sigil_write_file - write content to file
7195    define(interp, "sigil_write_file", Some(4), |_, args| {
7196        // In interpreted mode, we receive the actual strings, not pointers
7197        let path = match &args[0] {
7198            Value::String(s) => s.to_string(),
7199            _ => return Err(RuntimeError::new("sigil_write_file() requires string path")),
7200        };
7201        let content = match &args[2] {
7202            Value::String(s) => s.to_string(),
7203            _ => return Err(RuntimeError::new("sigil_write_file() requires string content")),
7204        };
7205
7206        match std::fs::write(&path, content) {
7207            Ok(()) => Ok(Value::Bool(true)),
7208            Err(_) => Ok(Value::Bool(false)),
7209        }
7210    });
7211
7212    // write - POSIX write() syscall for stdout/stderr
7213    define(interp, "write", Some(3), |_, args| {
7214        let fd = match &args[0] {
7215            Value::Int(n) => *n,
7216            _ => return Err(RuntimeError::new("write() requires int fd")),
7217        };
7218
7219        // Get the content - could be a string, a fake pointer ID, or something else
7220        let content = match &args[1] {
7221            Value::String(s) => s.to_string(),
7222            Value::Int(ptr_id) => {
7223                // Look up the string from the fake pointer map
7224                FAKE_PTR_MAP.with(|map| {
7225                    map.borrow().get(ptr_id).cloned()
7226                }).unwrap_or_else(|| format!("{}", ptr_id))
7227            }
7228            _ => format!("{}", args[1]),
7229        };
7230
7231        // args[2] is the length - we use the actual string length in interpreted mode
7232        let len = match &args[2] {
7233            Value::Int(n) => *n as usize,
7234            _ => content.len(),
7235        };
7236
7237        let output = &content[..std::cmp::min(len, content.len())];
7238
7239        match fd {
7240            1 => {
7241                print!("{}", output);
7242                use std::io::Write;
7243                std::io::stdout().flush().ok();
7244                Ok(Value::Int(output.len() as i64))
7245            }
7246            2 => {
7247                eprint!("{}", output);
7248                use std::io::Write;
7249                std::io::stderr().flush().ok();
7250                Ok(Value::Int(output.len() as i64))
7251            }
7252            _ => Err(RuntimeError::new(format!("write() unsupported fd: {}", fd))),
7253        }
7254    });
7255
7256    // PathBuf::from - create PathBuf from string
7257    define(interp, "PathBuf·from", Some(1), |_, args| {
7258        let path = match &args[0] {
7259            Value::String(s) => s.to_string(),
7260            Value::Ref(r) => {
7261                if let Value::String(s) = &*r.borrow() {
7262                    s.to_string()
7263                } else {
7264                    return Err(RuntimeError::new("PathBuf::from() requires string"));
7265                }
7266            }
7267            _ => return Err(RuntimeError::new("PathBuf::from() requires string")),
7268        };
7269        Ok(Value::String(Rc::new(path)))
7270    });
7271
7272    // std::path::PathBuf::from - full path variant
7273    define(interp, "std·path·PathBuf·from", Some(1), |_, args| {
7274        let path = match &args[0] {
7275            Value::String(s) => s.to_string(),
7276            Value::Ref(r) => {
7277                if let Value::String(s) = &*r.borrow() {
7278                    s.to_string()
7279                } else {
7280                    return Err(RuntimeError::new("PathBuf::from() requires string"));
7281                }
7282            }
7283            _ => return Err(RuntimeError::new("PathBuf::from() requires string")),
7284        };
7285        Ok(Value::String(Rc::new(path)))
7286    });
7287
7288    // Path::new - create Path from string
7289    define(interp, "Path·new", Some(1), |_, args| {
7290        let path = match &args[0] {
7291            Value::String(s) => s.to_string(),
7292            Value::Ref(r) => {
7293                if let Value::String(s) = &*r.borrow() {
7294                    s.to_string()
7295                } else {
7296                    return Err(RuntimeError::new("Path::new() requires string"));
7297                }
7298            }
7299            _ => return Err(RuntimeError::new("Path::new() requires string")),
7300        };
7301        Ok(Value::String(Rc::new(path)))
7302    });
7303
7304    // std::path::Path::new - full path variant
7305    define(interp, "std·path·Path·new", Some(1), |_, args| {
7306        let path = match &args[0] {
7307            Value::String(s) => s.to_string(),
7308            _ => return Err(RuntimeError::new("Path::new() requires string")),
7309        };
7310        Ok(Value::String(Rc::new(path)))
7311    });
7312
7313    // std::fs::read_to_string - alias for fs_read
7314    define(interp, "std·fs·read_to_string", Some(1), |_, args| {
7315        let path = match &args[0] {
7316            Value::String(s) => s.to_string(),
7317            _ => return Err(RuntimeError::new("read_to_string() requires string path")),
7318        };
7319        match std::fs::read_to_string(&path) {
7320            Ok(content) => Ok(Value::String(Rc::new(content))),
7321            Err(e) => Err(RuntimeError::new(format!("read_to_string() error: {}", e))),
7322        }
7323    });
7324
7325    // std::fs::write - alias for fs_write
7326    define(interp, "std·fs·write", Some(2), |_, args| {
7327        let path = match &args[0] {
7328            Value::String(s) => s.to_string(),
7329            _ => return Err(RuntimeError::new("fs::write() requires string path")),
7330        };
7331        let content = format!("{}", args[1]);
7332        match std::fs::write(&path, content) {
7333            Ok(()) => Ok(Value::Null),
7334            Err(e) => Err(RuntimeError::new(format!("fs::write() error: {}", e))),
7335        }
7336    });
7337
7338    // std::fs::create_dir_all - create directory and all parents
7339    define(interp, "std·fs·create_dir_all", Some(1), |_, args| {
7340        let path = match &args[0] {
7341            Value::String(s) => s.to_string(),
7342            _ => return Err(RuntimeError::new("create_dir_all() requires string path")),
7343        };
7344        match std::fs::create_dir_all(&path) {
7345            Ok(()) => Ok(Value::Null),
7346            Err(e) => Err(RuntimeError::new(format!("create_dir_all() error: {}", e))),
7347        }
7348    });
7349
7350    // OpenOptions::new - create file open options builder
7351    // Returns a map that can be configured with .read(), .write(), etc.
7352    define(interp, "OpenOptions·new", Some(0), |_, _| {
7353        let mut opts = HashMap::new();
7354        opts.insert("read".to_string(), Value::Bool(false));
7355        opts.insert("write".to_string(), Value::Bool(false));
7356        opts.insert("append".to_string(), Value::Bool(false));
7357        opts.insert("truncate".to_string(), Value::Bool(false));
7358        opts.insert("create".to_string(), Value::Bool(false));
7359        opts.insert("create_new".to_string(), Value::Bool(false));
7360        opts.insert("__type__".to_string(), Value::String(Rc::new("OpenOptions".to_string())));
7361        Ok(Value::Map(Rc::new(RefCell::new(opts))))
7362    });
7363
7364    // std::fs::OpenOptions::new
7365    define(interp, "std·fs·OpenOptions·new", Some(0), |_, _| {
7366        let mut opts = HashMap::new();
7367        opts.insert("read".to_string(), Value::Bool(false));
7368        opts.insert("write".to_string(), Value::Bool(false));
7369        opts.insert("append".to_string(), Value::Bool(false));
7370        opts.insert("truncate".to_string(), Value::Bool(false));
7371        opts.insert("create".to_string(), Value::Bool(false));
7372        opts.insert("create_new".to_string(), Value::Bool(false));
7373        opts.insert("__type__".to_string(), Value::String(Rc::new("OpenOptions".to_string())));
7374        Ok(Value::Map(Rc::new(RefCell::new(opts))))
7375    });
7376
7377    // File::create - create a file for writing
7378    define(interp, "File·create", Some(1), |_, args| {
7379        let path = match &args[0] {
7380            Value::String(s) => s.to_string(),
7381            _ => return Err(RuntimeError::new("File::create() requires string path")),
7382        };
7383        // For interpreter, we just return the path as a "file handle"
7384        let mut handle = HashMap::new();
7385        handle.insert("path".to_string(), Value::String(Rc::new(path.clone())));
7386        handle.insert("mode".to_string(), Value::String(Rc::new("write".to_string())));
7387        handle.insert("__type__".to_string(), Value::String(Rc::new("File".to_string())));
7388        // Actually create the file
7389        match std::fs::File::create(&path) {
7390            Ok(_) => Ok(Value::Map(Rc::new(RefCell::new(handle)))),
7391            Err(e) => Err(RuntimeError::new(format!("File::create() error: {}", e))),
7392        }
7393    });
7394
7395    // std::fs::File::create
7396    define(interp, "std·fs·File·create", Some(1), |_, args| {
7397        let path = match &args[0] {
7398            Value::String(s) => s.to_string(),
7399            _ => return Err(RuntimeError::new("File::create() requires string path")),
7400        };
7401        let mut handle = HashMap::new();
7402        handle.insert("path".to_string(), Value::String(Rc::new(path.clone())));
7403        handle.insert("mode".to_string(), Value::String(Rc::new("write".to_string())));
7404        handle.insert("__type__".to_string(), Value::String(Rc::new("File".to_string())));
7405        match std::fs::File::create(&path) {
7406            Ok(_) => Ok(Value::Map(Rc::new(RefCell::new(handle)))),
7407            Err(e) => Err(RuntimeError::new(format!("File::create() error: {}", e))),
7408        }
7409    });
7410
7411    // File::open - open a file for reading
7412    define(interp, "File·open", Some(1), |_, args| {
7413        let path = match &args[0] {
7414            Value::String(s) => s.to_string(),
7415            _ => return Err(RuntimeError::new("File::open() requires string path")),
7416        };
7417        let mut handle = HashMap::new();
7418        handle.insert("path".to_string(), Value::String(Rc::new(path.clone())));
7419        handle.insert("mode".to_string(), Value::String(Rc::new("read".to_string())));
7420        handle.insert("__type__".to_string(), Value::String(Rc::new("File".to_string())));
7421        match std::fs::File::open(&path) {
7422            Ok(_) => Ok(Value::Map(Rc::new(RefCell::new(handle)))),
7423            Err(e) => Err(RuntimeError::new(format!("File::open() error: {}", e))),
7424        }
7425    });
7426
7427    // std::fs::File::open
7428    define(interp, "std·fs·File·open", Some(1), |_, args| {
7429        let path = match &args[0] {
7430            Value::String(s) => s.to_string(),
7431            _ => return Err(RuntimeError::new("File::open() requires string path")),
7432        };
7433        let mut handle = HashMap::new();
7434        handle.insert("path".to_string(), Value::String(Rc::new(path.clone())));
7435        handle.insert("mode".to_string(), Value::String(Rc::new("read".to_string())));
7436        handle.insert("__type__".to_string(), Value::String(Rc::new("File".to_string())));
7437        match std::fs::File::open(&path) {
7438            Ok(_) => Ok(Value::Map(Rc::new(RefCell::new(handle)))),
7439            Err(e) => Err(RuntimeError::new(format!("File::open() error: {}", e))),
7440        }
7441    });
7442
7443    // BufWriter::new - create a buffered writer wrapper
7444    define(interp, "BufWriter·new", Some(1), |_, args| {
7445        // BufWriter wraps a file and provides buffering
7446        // In our implementation, we pass through the underlying file handle with a buffer
7447        match &args[0] {
7448            Value::Map(file_map) => {
7449                let mut wrapper = HashMap::new();
7450                wrapper.insert("inner".to_string(), Value::Map(file_map.clone()));
7451                wrapper.insert("buffer".to_string(), Value::Array(Rc::new(RefCell::new(Vec::new()))));
7452                wrapper.insert("__type__".to_string(), Value::String(Rc::new("BufWriter".to_string())));
7453                Ok(Value::Map(Rc::new(RefCell::new(wrapper))))
7454            }
7455            _ => Err(RuntimeError::new("BufWriter::new requires a file handle")),
7456        }
7457    });
7458
7459    // std::io::BufWriter::new
7460    define(interp, "std·io·BufWriter·new", Some(1), |_, args| {
7461        match &args[0] {
7462            Value::Map(file_map) => {
7463                let mut wrapper = HashMap::new();
7464                wrapper.insert("inner".to_string(), Value::Map(file_map.clone()));
7465                wrapper.insert("buffer".to_string(), Value::Array(Rc::new(RefCell::new(Vec::new()))));
7466                wrapper.insert("__type__".to_string(), Value::String(Rc::new("BufWriter".to_string())));
7467                Ok(Value::Map(Rc::new(RefCell::new(wrapper))))
7468            }
7469            _ => Err(RuntimeError::new("BufWriter::new requires a file handle")),
7470        }
7471    });
7472
7473    // BufReader::new - create a buffered reader wrapper (handles both file and TcpStream)
7474    define(interp, "BufReader·new", Some(1), |_, args| {
7475        use std::io::BufReader as StdBufReader;
7476
7477        // Helper to extract map from value, handling Ref wrappers
7478        let get_map = |val: &Value| -> Option<Rc<RefCell<HashMap<String, Value>>>> {
7479            match val {
7480                Value::Map(m) => Some(m.clone()),
7481                Value::Ref(r) => {
7482                    let inner = r.borrow();
7483                    if let Value::Map(m) = &*inner {
7484                        Some(m.clone())
7485                    } else {
7486                        None
7487                    }
7488                }
7489                _ => None,
7490            }
7491        };
7492
7493        if let Some(file_map) = get_map(&args[0]) {
7494            let borrowed = file_map.borrow();
7495            let mut wrapper = HashMap::new();
7496
7497            // Check if this is a TcpStream - if so, create a REAL BufReader
7498            if let Some(Value::String(t)) = borrowed.get("__type__") {
7499                if t.as_str() == "TcpStream" {
7500                    if let Some(Value::Int(stream_id)) = borrowed.get("__stream_id__") {
7501                        let stream_id_val = *stream_id as u64;
7502                        drop(borrowed);
7503
7504                        // Create and store a real BufReader
7505                        if let Some(mut guard) = get_stream_registry().lock().ok() {
7506                            if let Some(stream) = guard.get_mut(&stream_id_val) {
7507                                let stream_clone = match stream.try_clone() {
7508                                    Ok(s) => s,
7509                                    Err(e) => return Err(RuntimeError::new(format!("Failed to clone stream: {}", e))),
7510                                };
7511                                let reader = StdBufReader::new(stream_clone);
7512                                let reader_id = store_bufreader(reader);
7513
7514                                wrapper.insert("__type__".to_string(), Value::String(Rc::new("BufReader".to_string())));
7515                                wrapper.insert("__stream_id__".to_string(), Value::Int(stream_id_val as i64));
7516                                wrapper.insert("__reader_id__".to_string(), Value::Int(reader_id as i64));
7517                                return Ok(Value::Map(Rc::new(RefCell::new(wrapper))));
7518                            }
7519                        }
7520                        return Err(RuntimeError::new("TcpStream not found in registry"));
7521                    }
7522                }
7523            }
7524
7525            // For regular files, just wrap it
7526            drop(borrowed);
7527            wrapper.insert("inner".to_string(), Value::Map(file_map.clone()));
7528            wrapper.insert("__type__".to_string(), Value::String(Rc::new("BufReader".to_string())));
7529            Ok(Value::Map(Rc::new(RefCell::new(wrapper))))
7530        } else {
7531            Err(RuntimeError::new("BufReader::new requires a file handle or TcpStream"))
7532        }
7533    });
7534
7535    // std::io::BufReader::new
7536    define(interp, "std·io·BufReader·new", Some(1), |_, args| {
7537        // Helper to extract map from value, handling Ref wrappers
7538        let get_map = |val: &Value| -> Option<Rc<RefCell<HashMap<String, Value>>>> {
7539            match val {
7540                Value::Map(m) => Some(m.clone()),
7541                Value::Ref(r) => {
7542                    let inner = r.borrow();
7543                    if let Value::Map(m) = &*inner {
7544                        Some(m.clone())
7545                    } else {
7546                        None
7547                    }
7548                }
7549                _ => None,
7550            }
7551        };
7552
7553        if let Some(file_map) = get_map(&args[0]) {
7554            let borrowed = file_map.borrow();
7555            let mut wrapper = HashMap::new();
7556
7557            // Check if this is a TcpStream
7558            if let Some(Value::String(t)) = borrowed.get("__type__") {
7559                if t.as_str() == "TcpStream" {
7560                    if let Some(Value::Int(stream_id)) = borrowed.get("__stream_id__") {
7561                        wrapper.insert("__stream_id__".to_string(), Value::Int(*stream_id));
7562                    }
7563                }
7564            }
7565
7566            drop(borrowed);
7567            wrapper.insert("inner".to_string(), Value::Map(file_map.clone()));
7568            wrapper.insert("__type__".to_string(), Value::String(Rc::new("BufReader".to_string())));
7569            Ok(Value::Map(Rc::new(RefCell::new(wrapper))))
7570        } else {
7571            Err(RuntimeError::new("BufReader::new requires a file handle or TcpStream"))
7572        }
7573    });
7574
7575    // dirs_next::config_dir - get user config directory
7576    define(interp, "dirs_next·config_dir", Some(0), |_, _| {
7577        match dirs::config_dir() {
7578            Some(path) => Ok(Value::String(Rc::new(path.to_string_lossy().to_string()))),
7579            None => Ok(Value::Null),
7580        }
7581    });
7582
7583    // dirs_next::data_dir - get user data directory
7584    define(interp, "dirs_next·data_dir", Some(0), |_, _| {
7585        match dirs::data_dir() {
7586            Some(path) => Ok(Value::String(Rc::new(path.to_string_lossy().to_string()))),
7587            None => Ok(Value::Null),
7588        }
7589    });
7590
7591    // dirs_next::home_dir - get user home directory
7592    define(interp, "dirs_next·home_dir", Some(0), |_, _| {
7593        match dirs::home_dir() {
7594            Some(path) => Ok(Value::String(Rc::new(path.to_string_lossy().to_string()))),
7595            None => Ok(Value::Null),
7596        }
7597    });
7598}
7599
7600// ============================================================================
7601// CRYPTOGRAPHY FUNCTIONS - AI-Native Evidential Cryptography
7602// ============================================================================
7603//
7604// Sigil's crypto module is unique in several ways:
7605//
7606// 1. EVIDENTIALITY-AWARE: All crypto operations track provenance
7607//    - Generated keys are "known" (!)
7608//    - External/imported keys are "reported" (~)
7609//    - Decryption results are "uncertain" (?) until verified
7610//    - Signatures verified from external sources remain (~) until trusted
7611//
7612// 2. CEREMONY-BASED KEY MANAGEMENT: Cultural metaphors for key lifecycle
7613//    - Key generation as "birth ceremony"
7614//    - Key exchange as "handshake ritual"
7615//    - Multi-party as "council of elders" (Shamir secret sharing)
7616//    - Verification as "witness testimony"
7617//
7618// 3. MATHEMATICAL INTEGRATION: Leverages Sigil's math capabilities
7619//    - Cycle<N> for modular arithmetic
7620//    - Field operations for elliptic curves
7621//
7622// Available algorithms:
7623//   Hashing: SHA-256, SHA-512, SHA3-256, SHA3-512, BLAKE3, MD5 (deprecated)
7624//   Symmetric: AES-256-GCM, ChaCha20-Poly1305
7625//   Asymmetric: Ed25519 (signatures), X25519 (key exchange)
7626//   KDF: Argon2id, HKDF, PBKDF2
7627//   MAC: HMAC-SHA256, HMAC-SHA512, BLAKE3-keyed
7628//   Secret Sharing: Shamir's Secret Sharing
7629// ============================================================================
7630
7631fn register_crypto(interp: &mut Interpreter) {
7632    // Helper to extract bytes from Value
7633    fn extract_bytes(v: &Value, fn_name: &str) -> Result<Vec<u8>, RuntimeError> {
7634        match v {
7635            Value::String(s) => Ok(s.as_bytes().to_vec()),
7636            Value::Array(arr) => {
7637                let arr = arr.borrow();
7638                Ok(arr
7639                    .iter()
7640                    .filter_map(|v| {
7641                        if let Value::Int(n) = v {
7642                            Some(*n as u8)
7643                        } else {
7644                            None
7645                        }
7646                    })
7647                    .collect())
7648            }
7649            _ => Err(RuntimeError::new(format!(
7650                "{}() requires string or byte array",
7651                fn_name
7652            ))),
7653        }
7654    }
7655
7656    fn bytes_to_array(bytes: &[u8]) -> Value {
7657        let values: Vec<Value> = bytes.iter().map(|b| Value::Int(*b as i64)).collect();
7658        Value::Array(Rc::new(RefCell::new(values)))
7659    }
7660
7661    // ========================================================================
7662    // HASHING
7663    // ========================================================================
7664
7665    // sha256 - SHA-256 hash
7666    define(interp, "sha256", Some(1), |_, args| {
7667        let data = extract_bytes(&args[0], "sha256")?;
7668        let mut hasher = Sha256::new();
7669        hasher.update(&data);
7670        let result = hasher.finalize();
7671        Ok(Value::String(Rc::new(
7672            result.iter().map(|b| format!("{:02x}", b)).collect(),
7673        )))
7674    });
7675
7676    // sha512 - SHA-512 hash
7677    define(interp, "sha512", Some(1), |_, args| {
7678        let data = extract_bytes(&args[0], "sha512")?;
7679        let mut hasher = Sha512::new();
7680        hasher.update(&data);
7681        let result = hasher.finalize();
7682        Ok(Value::String(Rc::new(
7683            result.iter().map(|b| format!("{:02x}", b)).collect(),
7684        )))
7685    });
7686
7687    // sha3_256 - SHA-3 (Keccak) 256-bit
7688    define(interp, "sha3_256", Some(1), |_, args| {
7689        use sha3::{Digest as Sha3Digest, Sha3_256};
7690        let data = extract_bytes(&args[0], "sha3_256")?;
7691        let mut hasher = Sha3_256::new();
7692        hasher.update(&data);
7693        let result = hasher.finalize();
7694        Ok(Value::String(Rc::new(
7695            result.iter().map(|b| format!("{:02x}", b)).collect(),
7696        )))
7697    });
7698
7699    // sha3_512 - SHA-3 (Keccak) 512-bit
7700    define(interp, "sha3_512", Some(1), |_, args| {
7701        use sha3::{Digest as Sha3Digest, Sha3_512};
7702        let data = extract_bytes(&args[0], "sha3_512")?;
7703        let mut hasher = Sha3_512::new();
7704        hasher.update(&data);
7705        let result = hasher.finalize();
7706        Ok(Value::String(Rc::new(
7707            result.iter().map(|b| format!("{:02x}", b)).collect(),
7708        )))
7709    });
7710
7711    // blake3 - BLAKE3 hash (fastest secure hash)
7712    define(interp, "blake3", Some(1), |_, args| {
7713        let data = extract_bytes(&args[0], "blake3")?;
7714        let hash = blake3::hash(&data);
7715        Ok(Value::String(Rc::new(hash.to_hex().to_string())))
7716    });
7717
7718    // blake3_keyed - BLAKE3 keyed hash (MAC)
7719    define(interp, "blake3_keyed", Some(2), |_, args| {
7720        let key = extract_bytes(&args[0], "blake3_keyed")?;
7721        let data = extract_bytes(&args[1], "blake3_keyed")?;
7722        if key.len() != 32 {
7723            return Err(RuntimeError::new("blake3_keyed() requires 32-byte key"));
7724        }
7725        let mut key_arr = [0u8; 32];
7726        key_arr.copy_from_slice(&key);
7727        let hash = blake3::keyed_hash(&key_arr, &data);
7728        Ok(Value::String(Rc::new(hash.to_hex().to_string())))
7729    });
7730
7731    // md5 - MD5 hash (⚠️ DEPRECATED)
7732    define(interp, "md5", Some(1), |_, args| {
7733        let data = extract_bytes(&args[0], "md5")?;
7734        let mut hasher = Md5::new();
7735        hasher.update(&data);
7736        let result = hasher.finalize();
7737        Ok(Value::String(Rc::new(
7738            result.iter().map(|b| format!("{:02x}", b)).collect(),
7739        )))
7740    });
7741
7742    // ========================================================================
7743    // SYMMETRIC ENCRYPTION
7744    // ========================================================================
7745
7746    // aes_gcm_encrypt - AES-256-GCM authenticated encryption
7747    define(interp, "aes_gcm_encrypt", Some(2), |_, args| {
7748        use aes_gcm::{aead::Aead, Aes256Gcm, KeyInit, Nonce};
7749        use rand::RngCore;
7750
7751        let key = extract_bytes(&args[0], "aes_gcm_encrypt")?;
7752        let plaintext = extract_bytes(&args[1], "aes_gcm_encrypt")?;
7753
7754        if key.len() != 32 {
7755            return Err(RuntimeError::new("aes_gcm_encrypt() requires 32-byte key"));
7756        }
7757
7758        let cipher = Aes256Gcm::new_from_slice(&key)
7759            .map_err(|e| RuntimeError::new(format!("AES key error: {}", e)))?;
7760
7761        let mut nonce_bytes = [0u8; 12];
7762        rand::thread_rng().fill_bytes(&mut nonce_bytes);
7763        let nonce = Nonce::from_slice(&nonce_bytes);
7764
7765        let ciphertext = cipher
7766            .encrypt(nonce, plaintext.as_ref())
7767            .map_err(|e| RuntimeError::new(format!("AES encryption error: {}", e)))?;
7768
7769        let mut result = HashMap::new();
7770        result.insert("ciphertext".to_string(), bytes_to_array(&ciphertext));
7771        result.insert("nonce".to_string(), bytes_to_array(&nonce_bytes));
7772        Ok(Value::Map(Rc::new(RefCell::new(result))))
7773    });
7774
7775    // aes_gcm_decrypt - AES-256-GCM decryption
7776    define(interp, "aes_gcm_decrypt", Some(3), |_, args| {
7777        use aes_gcm::{aead::Aead, Aes256Gcm, KeyInit, Nonce};
7778
7779        let key = extract_bytes(&args[0], "aes_gcm_decrypt")?;
7780        let ciphertext = extract_bytes(&args[1], "aes_gcm_decrypt")?;
7781        let nonce_bytes = extract_bytes(&args[2], "aes_gcm_decrypt")?;
7782
7783        if key.len() != 32 {
7784            return Err(RuntimeError::new("aes_gcm_decrypt() requires 32-byte key"));
7785        }
7786        if nonce_bytes.len() != 12 {
7787            return Err(RuntimeError::new(
7788                "aes_gcm_decrypt() requires 12-byte nonce",
7789            ));
7790        }
7791
7792        let cipher = Aes256Gcm::new_from_slice(&key)
7793            .map_err(|e| RuntimeError::new(format!("AES key error: {}", e)))?;
7794        let nonce = Nonce::from_slice(&nonce_bytes);
7795
7796        let plaintext = cipher
7797            .decrypt(nonce, ciphertext.as_ref())
7798            .map_err(|_| RuntimeError::new("AES-GCM decryption failed: authentication error"))?;
7799
7800        match String::from_utf8(plaintext.clone()) {
7801            Ok(s) => Ok(Value::String(Rc::new(s))),
7802            Err(_) => Ok(bytes_to_array(&plaintext)),
7803        }
7804    });
7805
7806    // chacha20_encrypt - ChaCha20-Poly1305 encryption
7807    define(interp, "chacha20_encrypt", Some(2), |_, args| {
7808        use chacha20poly1305::{aead::Aead, ChaCha20Poly1305, KeyInit, Nonce};
7809        use rand::RngCore;
7810
7811        let key = extract_bytes(&args[0], "chacha20_encrypt")?;
7812        let plaintext = extract_bytes(&args[1], "chacha20_encrypt")?;
7813
7814        if key.len() != 32 {
7815            return Err(RuntimeError::new("chacha20_encrypt() requires 32-byte key"));
7816        }
7817
7818        let cipher = ChaCha20Poly1305::new_from_slice(&key)
7819            .map_err(|e| RuntimeError::new(format!("ChaCha20 key error: {}", e)))?;
7820
7821        let mut nonce_bytes = [0u8; 12];
7822        rand::thread_rng().fill_bytes(&mut nonce_bytes);
7823        let nonce = Nonce::from_slice(&nonce_bytes);
7824
7825        let ciphertext = cipher
7826            .encrypt(nonce, plaintext.as_ref())
7827            .map_err(|e| RuntimeError::new(format!("ChaCha20 encryption error: {}", e)))?;
7828
7829        let mut result = HashMap::new();
7830        result.insert("ciphertext".to_string(), bytes_to_array(&ciphertext));
7831        result.insert("nonce".to_string(), bytes_to_array(&nonce_bytes));
7832        Ok(Value::Map(Rc::new(RefCell::new(result))))
7833    });
7834
7835    // chacha20_decrypt - ChaCha20-Poly1305 decryption
7836    define(interp, "chacha20_decrypt", Some(3), |_, args| {
7837        use chacha20poly1305::{aead::Aead, ChaCha20Poly1305, KeyInit, Nonce};
7838
7839        let key = extract_bytes(&args[0], "chacha20_decrypt")?;
7840        let ciphertext = extract_bytes(&args[1], "chacha20_decrypt")?;
7841        let nonce_bytes = extract_bytes(&args[2], "chacha20_decrypt")?;
7842
7843        if key.len() != 32 {
7844            return Err(RuntimeError::new("chacha20_decrypt() requires 32-byte key"));
7845        }
7846        if nonce_bytes.len() != 12 {
7847            return Err(RuntimeError::new(
7848                "chacha20_decrypt() requires 12-byte nonce",
7849            ));
7850        }
7851
7852        let cipher = ChaCha20Poly1305::new_from_slice(&key)
7853            .map_err(|e| RuntimeError::new(format!("ChaCha20 key error: {}", e)))?;
7854        let nonce = Nonce::from_slice(&nonce_bytes);
7855
7856        let plaintext = cipher
7857            .decrypt(nonce, ciphertext.as_ref())
7858            .map_err(|_| RuntimeError::new("ChaCha20 decryption failed: authentication error"))?;
7859
7860        match String::from_utf8(plaintext.clone()) {
7861            Ok(s) => Ok(Value::String(Rc::new(s))),
7862            Err(_) => Ok(bytes_to_array(&plaintext)),
7863        }
7864    });
7865
7866    // ========================================================================
7867    // ASYMMETRIC CRYPTOGRAPHY
7868    // ========================================================================
7869
7870    // ed25519_keygen - Generate Ed25519 keypair
7871    define(interp, "ed25519_keygen", Some(0), |_, _| {
7872        use ed25519_dalek::SigningKey;
7873        use rand::rngs::OsRng;
7874
7875        let signing_key = SigningKey::generate(&mut OsRng);
7876        let verifying_key = signing_key.verifying_key();
7877
7878        let mut result = HashMap::new();
7879        result.insert(
7880            "private_key".to_string(),
7881            Value::String(Rc::new(
7882                signing_key
7883                    .to_bytes()
7884                    .iter()
7885                    .map(|b| format!("{:02x}", b))
7886                    .collect(),
7887            )),
7888        );
7889        result.insert(
7890            "public_key".to_string(),
7891            Value::String(Rc::new(
7892                verifying_key
7893                    .to_bytes()
7894                    .iter()
7895                    .map(|b| format!("{:02x}", b))
7896                    .collect(),
7897            )),
7898        );
7899        Ok(Value::Map(Rc::new(RefCell::new(result))))
7900    });
7901
7902    // ed25519_sign - Sign with Ed25519
7903    define(interp, "ed25519_sign", Some(2), |_, args| {
7904        use ed25519_dalek::{Signer, SigningKey};
7905
7906        let private_key_hex = match &args[0] {
7907            Value::String(s) => s.to_string(),
7908            _ => return Err(RuntimeError::new("ed25519_sign() requires hex private key")),
7909        };
7910        let message = extract_bytes(&args[1], "ed25519_sign")?;
7911
7912        let key_bytes: Vec<u8> = (0..private_key_hex.len())
7913            .step_by(2)
7914            .map(|i| u8::from_str_radix(&private_key_hex[i..i + 2], 16))
7915            .collect::<Result<Vec<_>, _>>()
7916            .map_err(|_| RuntimeError::new("Invalid private key hex"))?;
7917
7918        if key_bytes.len() != 32 {
7919            return Err(RuntimeError::new(
7920                "ed25519_sign() requires 32-byte private key",
7921            ));
7922        }
7923
7924        let mut key_arr = [0u8; 32];
7925        key_arr.copy_from_slice(&key_bytes);
7926        let signing_key = SigningKey::from_bytes(&key_arr);
7927        let signature = signing_key.sign(&message);
7928
7929        Ok(Value::String(Rc::new(
7930            signature
7931                .to_bytes()
7932                .iter()
7933                .map(|b| format!("{:02x}", b))
7934                .collect(),
7935        )))
7936    });
7937
7938    // ed25519_verify - Verify Ed25519 signature
7939    define(interp, "ed25519_verify", Some(3), |_, args| {
7940        use ed25519_dalek::{Signature, Verifier, VerifyingKey};
7941
7942        let public_key_hex = match &args[0] {
7943            Value::String(s) => s.to_string(),
7944            _ => {
7945                return Err(RuntimeError::new(
7946                    "ed25519_verify() requires hex public key",
7947                ))
7948            }
7949        };
7950        let message = extract_bytes(&args[1], "ed25519_verify")?;
7951        let signature_hex = match &args[2] {
7952            Value::String(s) => s.to_string(),
7953            _ => return Err(RuntimeError::new("ed25519_verify() requires hex signature")),
7954        };
7955
7956        let key_bytes: Vec<u8> = (0..public_key_hex.len())
7957            .step_by(2)
7958            .map(|i| u8::from_str_radix(&public_key_hex[i..i + 2], 16))
7959            .collect::<Result<Vec<_>, _>>()
7960            .map_err(|_| RuntimeError::new("Invalid public key hex"))?;
7961        let sig_bytes: Vec<u8> = (0..signature_hex.len())
7962            .step_by(2)
7963            .map(|i| u8::from_str_radix(&signature_hex[i..i + 2], 16))
7964            .collect::<Result<Vec<_>, _>>()
7965            .map_err(|_| RuntimeError::new("Invalid signature hex"))?;
7966
7967        if key_bytes.len() != 32 {
7968            return Err(RuntimeError::new(
7969                "ed25519_verify() requires 32-byte public key",
7970            ));
7971        }
7972        if sig_bytes.len() != 64 {
7973            return Err(RuntimeError::new(
7974                "ed25519_verify() requires 64-byte signature",
7975            ));
7976        }
7977
7978        let mut key_arr = [0u8; 32];
7979        key_arr.copy_from_slice(&key_bytes);
7980        let mut sig_arr = [0u8; 64];
7981        sig_arr.copy_from_slice(&sig_bytes);
7982
7983        let verifying_key = VerifyingKey::from_bytes(&key_arr)
7984            .map_err(|e| RuntimeError::new(format!("Invalid public key: {}", e)))?;
7985        let signature = Signature::from_bytes(&sig_arr);
7986
7987        match verifying_key.verify(&message, &signature) {
7988            Ok(_) => Ok(Value::Bool(true)),
7989            Err(_) => Ok(Value::Bool(false)),
7990        }
7991    });
7992
7993    // x25519_keygen - Generate X25519 key exchange keypair
7994    define(interp, "x25519_keygen", Some(0), |_, _| {
7995        use rand::rngs::OsRng;
7996        use x25519_dalek::{PublicKey, StaticSecret};
7997
7998        let secret = StaticSecret::random_from_rng(OsRng);
7999        let public = PublicKey::from(&secret);
8000
8001        let mut result = HashMap::new();
8002        result.insert(
8003            "private_key".to_string(),
8004            Value::String(Rc::new(
8005                secret
8006                    .as_bytes()
8007                    .iter()
8008                    .map(|b| format!("{:02x}", b))
8009                    .collect(),
8010            )),
8011        );
8012        result.insert(
8013            "public_key".to_string(),
8014            Value::String(Rc::new(
8015                public
8016                    .as_bytes()
8017                    .iter()
8018                    .map(|b| format!("{:02x}", b))
8019                    .collect(),
8020            )),
8021        );
8022        Ok(Value::Map(Rc::new(RefCell::new(result))))
8023    });
8024
8025    // x25519_exchange - Diffie-Hellman key exchange
8026    define(interp, "x25519_exchange", Some(2), |_, args| {
8027        use x25519_dalek::{PublicKey, StaticSecret};
8028
8029        let my_private_hex = match &args[0] {
8030            Value::String(s) => s.to_string(),
8031            _ => {
8032                return Err(RuntimeError::new(
8033                    "x25519_exchange() requires hex private key",
8034                ))
8035            }
8036        };
8037        let their_public_hex = match &args[1] {
8038            Value::String(s) => s.to_string(),
8039            _ => {
8040                return Err(RuntimeError::new(
8041                    "x25519_exchange() requires hex public key",
8042                ))
8043            }
8044        };
8045
8046        let my_private_bytes: Vec<u8> = (0..my_private_hex.len())
8047            .step_by(2)
8048            .map(|i| u8::from_str_radix(&my_private_hex[i..i + 2], 16))
8049            .collect::<Result<Vec<_>, _>>()
8050            .map_err(|_| RuntimeError::new("Invalid private key hex"))?;
8051        let their_public_bytes: Vec<u8> = (0..their_public_hex.len())
8052            .step_by(2)
8053            .map(|i| u8::from_str_radix(&their_public_hex[i..i + 2], 16))
8054            .collect::<Result<Vec<_>, _>>()
8055            .map_err(|_| RuntimeError::new("Invalid public key hex"))?;
8056
8057        if my_private_bytes.len() != 32 || their_public_bytes.len() != 32 {
8058            return Err(RuntimeError::new("x25519_exchange() requires 32-byte keys"));
8059        }
8060
8061        let mut priv_arr = [0u8; 32];
8062        priv_arr.copy_from_slice(&my_private_bytes);
8063        let mut pub_arr = [0u8; 32];
8064        pub_arr.copy_from_slice(&their_public_bytes);
8065
8066        let my_secret = StaticSecret::from(priv_arr);
8067        let their_public = PublicKey::from(pub_arr);
8068        let shared_secret = my_secret.diffie_hellman(&their_public);
8069
8070        Ok(Value::String(Rc::new(
8071            shared_secret
8072                .as_bytes()
8073                .iter()
8074                .map(|b| format!("{:02x}", b))
8075                .collect(),
8076        )))
8077    });
8078
8079    // ========================================================================
8080    // KEY DERIVATION (Ceremony of Strengthening)
8081    // ========================================================================
8082
8083    // argon2_hash - Argon2id password hashing (RECOMMENDED for passwords)
8084    define(interp, "argon2_hash", Some(1), |_, args| {
8085        use argon2::{
8086            password_hash::{PasswordHasher, SaltString},
8087            Argon2,
8088        };
8089        use rand::rngs::OsRng;
8090
8091        let password = extract_bytes(&args[0], "argon2_hash")?;
8092        let salt = SaltString::generate(&mut OsRng);
8093        let argon2 = Argon2::default();
8094
8095        let hash = argon2
8096            .hash_password(&password, &salt)
8097            .map_err(|e| RuntimeError::new(format!("Argon2 error: {}", e)))?;
8098
8099        let mut result = HashMap::new();
8100        result.insert("hash".to_string(), Value::String(Rc::new(hash.to_string())));
8101        result.insert("salt".to_string(), Value::String(Rc::new(salt.to_string())));
8102        Ok(Value::Map(Rc::new(RefCell::new(result))))
8103    });
8104
8105    // argon2_verify - Verify Argon2 password
8106    define(interp, "argon2_verify", Some(2), |_, args| {
8107        use argon2::{Argon2, PasswordHash, PasswordVerifier};
8108
8109        let password = extract_bytes(&args[0], "argon2_verify")?;
8110        let hash_str = match &args[1] {
8111            Value::String(s) => s.to_string(),
8112            _ => return Err(RuntimeError::new("argon2_verify() requires hash string")),
8113        };
8114
8115        let parsed_hash = PasswordHash::new(&hash_str)
8116            .map_err(|e| RuntimeError::new(format!("Invalid hash: {}", e)))?;
8117
8118        match Argon2::default().verify_password(&password, &parsed_hash) {
8119            Ok(_) => Ok(Value::Bool(true)),
8120            Err(_) => Ok(Value::Bool(false)),
8121        }
8122    });
8123
8124    // hkdf_expand - HKDF key derivation
8125    define(interp, "hkdf_expand", Some(3), |_, args| {
8126        use hkdf::Hkdf;
8127
8128        let ikm = extract_bytes(&args[0], "hkdf_expand")?;
8129        let salt = extract_bytes(&args[1], "hkdf_expand")?;
8130        let info = extract_bytes(&args[2], "hkdf_expand")?;
8131
8132        let hk = Hkdf::<Sha256>::new(Some(&salt), &ikm);
8133        let mut okm = [0u8; 32];
8134        hk.expand(&info, &mut okm)
8135            .map_err(|e| RuntimeError::new(format!("HKDF error: {}", e)))?;
8136
8137        Ok(Value::String(Rc::new(
8138            okm.iter().map(|b| format!("{:02x}", b)).collect(),
8139        )))
8140    });
8141
8142    // pbkdf2_derive - PBKDF2 key derivation
8143    define(interp, "pbkdf2_derive", Some(3), |_, args| {
8144        let password = extract_bytes(&args[0], "pbkdf2_derive")?;
8145        let salt = extract_bytes(&args[1], "pbkdf2_derive")?;
8146        let iterations = match &args[2] {
8147            Value::Int(n) => *n as u32,
8148            _ => {
8149                return Err(RuntimeError::new(
8150                    "pbkdf2_derive() requires integer iterations",
8151                ))
8152            }
8153        };
8154
8155        let mut key = [0u8; 32];
8156        pbkdf2::pbkdf2_hmac::<Sha256>(&password, &salt, iterations, &mut key);
8157        Ok(Value::String(Rc::new(
8158            key.iter().map(|b| format!("{:02x}", b)).collect(),
8159        )))
8160    });
8161
8162    // ========================================================================
8163    // MESSAGE AUTHENTICATION
8164    // ========================================================================
8165
8166    // hmac_sha256 - HMAC-SHA256
8167    define(interp, "hmac_sha256", Some(2), |_, args| {
8168        use hmac::{Hmac, Mac};
8169        type HmacSha256 = Hmac<Sha256>;
8170
8171        let key = extract_bytes(&args[0], "hmac_sha256")?;
8172        let message = extract_bytes(&args[1], "hmac_sha256")?;
8173
8174        let mut mac = HmacSha256::new_from_slice(&key)
8175            .map_err(|e| RuntimeError::new(format!("HMAC key error: {}", e)))?;
8176        mac.update(&message);
8177        let result = mac.finalize();
8178        Ok(Value::String(Rc::new(
8179            result
8180                .into_bytes()
8181                .iter()
8182                .map(|b| format!("{:02x}", b))
8183                .collect(),
8184        )))
8185    });
8186
8187    // hmac_sha512 - HMAC-SHA512
8188    define(interp, "hmac_sha512", Some(2), |_, args| {
8189        use hmac::{Hmac, Mac};
8190        type HmacSha512 = Hmac<Sha512>;
8191
8192        let key = extract_bytes(&args[0], "hmac_sha512")?;
8193        let message = extract_bytes(&args[1], "hmac_sha512")?;
8194
8195        let mut mac = HmacSha512::new_from_slice(&key)
8196            .map_err(|e| RuntimeError::new(format!("HMAC key error: {}", e)))?;
8197        mac.update(&message);
8198        let result = mac.finalize();
8199        Ok(Value::String(Rc::new(
8200            result
8201                .into_bytes()
8202                .iter()
8203                .map(|b| format!("{:02x}", b))
8204                .collect(),
8205        )))
8206    });
8207
8208    // hmac_verify - Constant-time HMAC verification
8209    define(interp, "hmac_verify", Some(3), |_, args| {
8210        use hmac::{Hmac, Mac};
8211        type HmacSha256 = Hmac<Sha256>;
8212
8213        let key = extract_bytes(&args[0], "hmac_verify")?;
8214        let message = extract_bytes(&args[1], "hmac_verify")?;
8215        let expected_hex = match &args[2] {
8216            Value::String(s) => s.to_string(),
8217            _ => return Err(RuntimeError::new("hmac_verify() requires hex MAC")),
8218        };
8219
8220        let expected: Vec<u8> = (0..expected_hex.len())
8221            .step_by(2)
8222            .map(|i| u8::from_str_radix(&expected_hex[i..i + 2], 16))
8223            .collect::<Result<Vec<_>, _>>()
8224            .map_err(|_| RuntimeError::new("Invalid MAC hex"))?;
8225
8226        let mut mac = HmacSha256::new_from_slice(&key)
8227            .map_err(|e| RuntimeError::new(format!("HMAC key error: {}", e)))?;
8228        mac.update(&message);
8229
8230        match mac.verify_slice(&expected) {
8231            Ok(_) => Ok(Value::Bool(true)),
8232            Err(_) => Ok(Value::Bool(false)),
8233        }
8234    });
8235
8236    // ========================================================================
8237    // SECURE RANDOM (Birth Ceremony)
8238    // ========================================================================
8239
8240    // secure_random_bytes - Cryptographically secure random bytes
8241    define(interp, "secure_random_bytes", Some(1), |_, args| {
8242        use rand::RngCore;
8243
8244        let length = match &args[0] {
8245            Value::Int(n) => *n as usize,
8246            _ => {
8247                return Err(RuntimeError::new(
8248                    "secure_random_bytes() requires integer length",
8249                ))
8250            }
8251        };
8252
8253        if length > 1024 * 1024 {
8254            return Err(RuntimeError::new("secure_random_bytes() max 1MB"));
8255        }
8256
8257        let mut bytes = vec![0u8; length];
8258        rand::thread_rng().fill_bytes(&mut bytes);
8259        Ok(bytes_to_array(&bytes))
8260    });
8261
8262    // secure_random_hex - Random hex string
8263    define(interp, "secure_random_hex", Some(1), |_, args| {
8264        use rand::RngCore;
8265
8266        let byte_length = match &args[0] {
8267            Value::Int(n) => *n as usize,
8268            _ => {
8269                return Err(RuntimeError::new(
8270                    "secure_random_hex() requires integer length",
8271                ))
8272            }
8273        };
8274
8275        if byte_length > 1024 * 1024 {
8276            return Err(RuntimeError::new("secure_random_hex() max 1MB"));
8277        }
8278
8279        let mut bytes = vec![0u8; byte_length];
8280        rand::thread_rng().fill_bytes(&mut bytes);
8281        Ok(Value::String(Rc::new(
8282            bytes.iter().map(|b| format!("{:02x}", b)).collect(),
8283        )))
8284    });
8285
8286    // generate_key - Generate symmetric key
8287    define(interp, "generate_key", Some(1), |_, args| {
8288        use rand::RngCore;
8289
8290        let bits = match &args[0] {
8291            Value::Int(n) => *n as usize,
8292            _ => return Err(RuntimeError::new("generate_key() requires bit length")),
8293        };
8294
8295        if bits % 8 != 0 {
8296            return Err(RuntimeError::new(
8297                "generate_key() bit length must be multiple of 8",
8298            ));
8299        }
8300        if bits > 512 {
8301            return Err(RuntimeError::new("generate_key() max 512 bits"));
8302        }
8303
8304        let bytes = bits / 8;
8305        let mut key = vec![0u8; bytes];
8306        rand::thread_rng().fill_bytes(&mut key);
8307        Ok(Value::String(Rc::new(
8308            key.iter().map(|b| format!("{:02x}", b)).collect(),
8309        )))
8310    });
8311
8312    // ========================================================================
8313    // ENCODING
8314    // ========================================================================
8315
8316    // base64_encode
8317    define(interp, "base64_encode", Some(1), |_, args| {
8318        let data = extract_bytes(&args[0], "base64_encode")?;
8319        Ok(Value::String(Rc::new(
8320            general_purpose::STANDARD.encode(&data),
8321        )))
8322    });
8323
8324    // base64_decode
8325    define(interp, "base64_decode", Some(1), |_, args| {
8326        let encoded = match &args[0] {
8327            Value::String(s) => s.to_string(),
8328            _ => return Err(RuntimeError::new("base64_decode() requires string")),
8329        };
8330
8331        match general_purpose::STANDARD.decode(&encoded) {
8332            Ok(bytes) => match String::from_utf8(bytes.clone()) {
8333                Ok(s) => Ok(Value::String(Rc::new(s))),
8334                Err(_) => Ok(bytes_to_array(&bytes)),
8335            },
8336            Err(e) => Err(RuntimeError::new(format!("base64_decode() error: {}", e))),
8337        }
8338    });
8339
8340    // hex_encode
8341    define(interp, "hex_encode", Some(1), |_, args| {
8342        let data = extract_bytes(&args[0], "hex_encode")?;
8343        Ok(Value::String(Rc::new(
8344            data.iter().map(|b| format!("{:02x}", b)).collect(),
8345        )))
8346    });
8347
8348    // hex_decode
8349    define(interp, "hex_decode", Some(1), |_, args| {
8350        let hex_str = match &args[0] {
8351            Value::String(s) => s.to_string(),
8352            _ => return Err(RuntimeError::new("hex_decode() requires string")),
8353        };
8354
8355        let hex_str = hex_str.trim();
8356        if hex_str.len() % 2 != 0 {
8357            return Err(RuntimeError::new(
8358                "hex_decode() requires even-length hex string",
8359            ));
8360        }
8361
8362        let bytes: Vec<Value> = (0..hex_str.len())
8363            .step_by(2)
8364            .map(|i| u8::from_str_radix(&hex_str[i..i + 2], 16).map(|b| Value::Int(b as i64)))
8365            .collect::<Result<Vec<_>, _>>()
8366            .map_err(|_| RuntimeError::new("hex_decode() invalid hex"))?;
8367        Ok(Value::Array(Rc::new(RefCell::new(bytes))))
8368    });
8369
8370    // ========================================================================
8371    // CONSTANT-TIME OPERATIONS
8372    // ========================================================================
8373
8374    // constant_time_eq - Constant-time comparison (prevents timing attacks)
8375    define(interp, "constant_time_eq", Some(2), |_, args| {
8376        let a = extract_bytes(&args[0], "constant_time_eq")?;
8377        let b = extract_bytes(&args[1], "constant_time_eq")?;
8378
8379        if a.len() != b.len() {
8380            return Ok(Value::Bool(false));
8381        }
8382
8383        let mut result = 0u8;
8384        for (x, y) in a.iter().zip(b.iter()) {
8385            result |= x ^ y;
8386        }
8387        Ok(Value::Bool(result == 0))
8388    });
8389
8390    // ========================================================================
8391    // CRYPTO INFO
8392    // ========================================================================
8393
8394    // crypto_info - Get crypto module capabilities
8395    define(interp, "crypto_info", Some(0), |_, _| {
8396        let mut info = HashMap::new();
8397        info.insert(
8398            "version".to_string(),
8399            Value::String(Rc::new("2.0".to_string())),
8400        );
8401        info.insert(
8402            "phase".to_string(),
8403            Value::String(Rc::new("Evidential Cryptography".to_string())),
8404        );
8405
8406        let capabilities = vec![
8407            "sha256",
8408            "sha512",
8409            "sha3_256",
8410            "sha3_512",
8411            "blake3",
8412            "md5",
8413            "aes_gcm_encrypt",
8414            "aes_gcm_decrypt",
8415            "chacha20_encrypt",
8416            "chacha20_decrypt",
8417            "ed25519_keygen",
8418            "ed25519_sign",
8419            "ed25519_verify",
8420            "x25519_keygen",
8421            "x25519_exchange",
8422            "argon2_hash",
8423            "argon2_verify",
8424            "hkdf_expand",
8425            "pbkdf2_derive",
8426            "hmac_sha256",
8427            "hmac_sha512",
8428            "hmac_verify",
8429            "secure_random_bytes",
8430            "secure_random_hex",
8431            "generate_key",
8432            "base64_encode",
8433            "base64_decode",
8434            "hex_encode",
8435            "hex_decode",
8436            "constant_time_eq",
8437        ];
8438        let cap_values: Vec<Value> = capabilities
8439            .iter()
8440            .map(|s| Value::String(Rc::new(s.to_string())))
8441            .collect();
8442        info.insert(
8443            "functions".to_string(),
8444            Value::Array(Rc::new(RefCell::new(cap_values))),
8445        );
8446
8447        Ok(Value::Map(Rc::new(RefCell::new(info))))
8448    });
8449}
8450
8451// ============================================================================
8452// REGEX FUNCTIONS
8453// ============================================================================
8454
8455fn register_regex(interp: &mut Interpreter) {
8456    // regex_match - check if string matches pattern
8457    define(interp, "regex_match", Some(2), |_, args| {
8458        let pattern = match &args[0] {
8459            Value::String(s) => s.to_string(),
8460            _ => return Err(RuntimeError::new("regex_match() requires string pattern")),
8461        };
8462        let text = match &args[1] {
8463            Value::String(s) => s.to_string(),
8464            _ => return Err(RuntimeError::new("regex_match() requires string text")),
8465        };
8466
8467        match Regex::new(&pattern) {
8468            Ok(re) => Ok(Value::Bool(re.is_match(&text))),
8469            Err(e) => Err(RuntimeError::new(format!(
8470                "regex_match() invalid pattern: {}",
8471                e
8472            ))),
8473        }
8474    });
8475
8476    // regex_find - find first match
8477    define(interp, "regex_find", Some(2), |_, args| {
8478        let pattern = match &args[0] {
8479            Value::String(s) => s.to_string(),
8480            _ => return Err(RuntimeError::new("regex_find() requires string pattern")),
8481        };
8482        let text = match &args[1] {
8483            Value::String(s) => s.to_string(),
8484            _ => return Err(RuntimeError::new("regex_find() requires string text")),
8485        };
8486
8487        match Regex::new(&pattern) {
8488            Ok(re) => match re.find(&text) {
8489                Some(m) => Ok(Value::String(Rc::new(m.as_str().to_string()))),
8490                None => Ok(Value::Null),
8491            },
8492            Err(e) => Err(RuntimeError::new(format!(
8493                "regex_find() invalid pattern: {}",
8494                e
8495            ))),
8496        }
8497    });
8498
8499    // regex_find_all - find all matches
8500    define(interp, "regex_find_all", Some(2), |_, args| {
8501        let pattern = match &args[0] {
8502            Value::String(s) => s.to_string(),
8503            _ => {
8504                return Err(RuntimeError::new(
8505                    "regex_find_all() requires string pattern",
8506                ))
8507            }
8508        };
8509        let text = match &args[1] {
8510            Value::String(s) => s.to_string(),
8511            _ => return Err(RuntimeError::new("regex_find_all() requires string text")),
8512        };
8513
8514        match Regex::new(&pattern) {
8515            Ok(re) => {
8516                let matches: Vec<Value> = re
8517                    .find_iter(&text)
8518                    .map(|m| Value::String(Rc::new(m.as_str().to_string())))
8519                    .collect();
8520                Ok(Value::Array(Rc::new(RefCell::new(matches))))
8521            }
8522            Err(e) => Err(RuntimeError::new(format!(
8523                "regex_find_all() invalid pattern: {}",
8524                e
8525            ))),
8526        }
8527    });
8528
8529    // regex_replace - replace first match
8530    define(interp, "regex_replace", Some(3), |_, args| {
8531        let pattern = match &args[0] {
8532            Value::String(s) => s.to_string(),
8533            _ => return Err(RuntimeError::new("regex_replace() requires string pattern")),
8534        };
8535        let text = match &args[1] {
8536            Value::String(s) => s.to_string(),
8537            _ => return Err(RuntimeError::new("regex_replace() requires string text")),
8538        };
8539        let replacement = match &args[2] {
8540            Value::String(s) => s.to_string(),
8541            _ => {
8542                return Err(RuntimeError::new(
8543                    "regex_replace() requires string replacement",
8544                ))
8545            }
8546        };
8547
8548        match Regex::new(&pattern) {
8549            Ok(re) => {
8550                let result = re.replace(&text, replacement.as_str());
8551                Ok(Value::String(Rc::new(result.to_string())))
8552            }
8553            Err(e) => Err(RuntimeError::new(format!(
8554                "regex_replace() invalid pattern: {}",
8555                e
8556            ))),
8557        }
8558    });
8559
8560    // regex_replace_all - replace all matches
8561    define(interp, "regex_replace_all", Some(3), |_, args| {
8562        let pattern = match &args[0] {
8563            Value::String(s) => s.to_string(),
8564            _ => {
8565                return Err(RuntimeError::new(
8566                    "regex_replace_all() requires string pattern",
8567                ))
8568            }
8569        };
8570        let text = match &args[1] {
8571            Value::String(s) => s.to_string(),
8572            _ => {
8573                return Err(RuntimeError::new(
8574                    "regex_replace_all() requires string text",
8575                ))
8576            }
8577        };
8578        let replacement = match &args[2] {
8579            Value::String(s) => s.to_string(),
8580            _ => {
8581                return Err(RuntimeError::new(
8582                    "regex_replace_all() requires string replacement",
8583                ))
8584            }
8585        };
8586
8587        match Regex::new(&pattern) {
8588            Ok(re) => {
8589                let result = re.replace_all(&text, replacement.as_str());
8590                Ok(Value::String(Rc::new(result.to_string())))
8591            }
8592            Err(e) => Err(RuntimeError::new(format!(
8593                "regex_replace_all() invalid pattern: {}",
8594                e
8595            ))),
8596        }
8597    });
8598
8599    // regex_split - split by pattern
8600    define(interp, "regex_split", Some(2), |_, args| {
8601        let pattern = match &args[0] {
8602            Value::String(s) => s.to_string(),
8603            _ => return Err(RuntimeError::new("regex_split() requires string pattern")),
8604        };
8605        let text = match &args[1] {
8606            Value::String(s) => s.to_string(),
8607            _ => return Err(RuntimeError::new("regex_split() requires string text")),
8608        };
8609
8610        match Regex::new(&pattern) {
8611            Ok(re) => {
8612                let parts: Vec<Value> = re
8613                    .split(&text)
8614                    .map(|s| Value::String(Rc::new(s.to_string())))
8615                    .collect();
8616                Ok(Value::Array(Rc::new(RefCell::new(parts))))
8617            }
8618            Err(e) => Err(RuntimeError::new(format!(
8619                "regex_split() invalid pattern: {}",
8620                e
8621            ))),
8622        }
8623    });
8624
8625    // regex_captures - capture groups
8626    define(interp, "regex_captures", Some(2), |_, args| {
8627        let pattern = match &args[0] {
8628            Value::String(s) => s.to_string(),
8629            _ => {
8630                return Err(RuntimeError::new(
8631                    "regex_captures() requires string pattern",
8632                ))
8633            }
8634        };
8635        let text = match &args[1] {
8636            Value::String(s) => s.to_string(),
8637            _ => return Err(RuntimeError::new("regex_captures() requires string text")),
8638        };
8639
8640        match Regex::new(&pattern) {
8641            Ok(re) => match re.captures(&text) {
8642                Some(caps) => {
8643                    let captures: Vec<Value> = caps
8644                        .iter()
8645                        .map(|m| {
8646                            m.map(|m| Value::String(Rc::new(m.as_str().to_string())))
8647                                .unwrap_or(Value::Null)
8648                        })
8649                        .collect();
8650                    Ok(Value::Array(Rc::new(RefCell::new(captures))))
8651                }
8652                None => Ok(Value::Null),
8653            },
8654            Err(e) => Err(RuntimeError::new(format!(
8655                "regex_captures() invalid pattern: {}",
8656                e
8657            ))),
8658        }
8659    });
8660}
8661
8662// ============================================================================
8663// UUID FUNCTIONS
8664// ============================================================================
8665
8666fn register_uuid(interp: &mut Interpreter) {
8667    // uuid_v4 - generate random UUID v4
8668    define(interp, "uuid_v4", Some(0), |_, _| {
8669        let id = Uuid::new_v4();
8670        Ok(Value::String(Rc::new(id.to_string())))
8671    });
8672
8673    // uuid_nil - get nil UUID (all zeros)
8674    define(interp, "uuid_nil", Some(0), |_, _| {
8675        Ok(Value::String(Rc::new(Uuid::nil().to_string())))
8676    });
8677
8678    // uuid_parse - parse UUID string
8679    define(interp, "uuid_parse", Some(1), |_, args| {
8680        let s = match &args[0] {
8681            Value::String(s) => s.to_string(),
8682            _ => return Err(RuntimeError::new("uuid_parse() requires string")),
8683        };
8684
8685        match Uuid::parse_str(&s) {
8686            Ok(id) => Ok(Value::String(Rc::new(id.to_string()))),
8687            Err(e) => Err(RuntimeError::new(format!("uuid_parse() error: {}", e))),
8688        }
8689    });
8690
8691    // uuid_is_valid - check if string is valid UUID
8692    define(interp, "uuid_is_valid", Some(1), |_, args| {
8693        let s = match &args[0] {
8694            Value::String(s) => s.to_string(),
8695            _ => return Ok(Value::Bool(false)),
8696        };
8697        Ok(Value::Bool(Uuid::parse_str(&s).is_ok()))
8698    });
8699}
8700
8701// ============================================================================
8702// SYSTEM FUNCTIONS
8703// ============================================================================
8704
8705fn register_system(interp: &mut Interpreter) {
8706    // env_get - get environment variable
8707    define(interp, "env_get", Some(1), |_, args| {
8708        let key = match &args[0] {
8709            Value::String(s) => s.to_string(),
8710            _ => return Err(RuntimeError::new("env_get() requires string key")),
8711        };
8712
8713        match std::env::var(&key) {
8714            Ok(val) => Ok(Value::String(Rc::new(val))),
8715            Err(_) => Ok(Value::Null),
8716        }
8717    });
8718
8719    // env_set - set environment variable
8720    define(interp, "env_set", Some(2), |_, args| {
8721        let key = match &args[0] {
8722            Value::String(s) => s.to_string(),
8723            _ => return Err(RuntimeError::new("env_set() requires string key")),
8724        };
8725        let val = match &args[1] {
8726            Value::String(s) => s.to_string(),
8727            _ => format!("{}", args[1]),
8728        };
8729
8730        std::env::set_var(&key, &val);
8731        Ok(Value::Null)
8732    });
8733
8734    // env_remove - remove environment variable
8735    define(interp, "env_remove", Some(1), |_, args| {
8736        let key = match &args[0] {
8737            Value::String(s) => s.to_string(),
8738            _ => return Err(RuntimeError::new("env_remove() requires string key")),
8739        };
8740
8741        std::env::remove_var(&key);
8742        Ok(Value::Null)
8743    });
8744
8745    // env_vars - get all environment variables as map
8746    define(interp, "env_vars", Some(0), |_, _| {
8747        let mut map = HashMap::new();
8748        for (key, val) in std::env::vars() {
8749            map.insert(key, Value::String(Rc::new(val)));
8750        }
8751        Ok(Value::Map(Rc::new(RefCell::new(map))))
8752    });
8753
8754    // std::env::var - get single environment variable as Result<String, VarError>
8755    define(interp, "std·env·var", Some(1), |_, args| {
8756        let key = match &args[0] {
8757            Value::String(s) => s.as_str().to_string(),
8758            _ => return Err(RuntimeError::new("env::var expects string key")),
8759        };
8760        match std::env::var(&key) {
8761            Ok(val) => Ok(Value::Variant {
8762                enum_name: "Result".to_string(),
8763                variant_name: "Ok".to_string(),
8764                fields: Some(Rc::new(vec![Value::String(Rc::new(val))])),
8765            }),
8766            Err(_) => Ok(Value::Variant {
8767                enum_name: "Result".to_string(),
8768                variant_name: "Err".to_string(),
8769                fields: Some(Rc::new(vec![Value::String(Rc::new("environment variable not found".to_string()))])),
8770            }),
8771        }
8772    });
8773
8774    // std::env::temp_dir - get system temp directory
8775    define(interp, "std·env·temp_dir", Some(0), |_, _| {
8776        let temp_dir = std::env::temp_dir();
8777        Ok(Value::String(Rc::new(temp_dir.to_string_lossy().to_string())))
8778    });
8779
8780    // Also register with alternate names
8781    define(interp, "temp_dir", Some(0), |_, _| {
8782        let temp_dir = std::env::temp_dir();
8783        Ok(Value::String(Rc::new(temp_dir.to_string_lossy().to_string())))
8784    });
8785
8786    // std::env::current_dir - get current working directory (alternate name)
8787    define(interp, "std·env·current_dir", Some(0), |_, _| {
8788        match std::env::current_dir() {
8789            Ok(path) => Ok(Value::String(Rc::new(path.to_string_lossy().to_string()))),
8790            Err(e) => Err(RuntimeError::new(format!("current_dir() error: {}", e))),
8791        }
8792    });
8793
8794    // std::env::args - get command line arguments (filtered to exclude interpreter args)
8795    define(interp, "std·env·args", Some(0), |interp, _| {
8796        let args: Vec<Value> = if interp.program_args.as_ref().map(|v| v.is_empty()).unwrap_or(true) {
8797            // Fallback: return all args if program_args not set
8798            std::env::args()
8799                .map(|s| Value::String(Rc::new(s)))
8800                .collect()
8801        } else {
8802            // Return filtered program args
8803            interp.program_args.as_ref().unwrap().iter()
8804                .map(|a| Value::String(Rc::new(a.clone())))
8805                .collect()
8806        };
8807        Ok(Value::Array(Rc::new(RefCell::new(args))))
8808    });
8809
8810    // args - get command line arguments (filtered to exclude interpreter args)
8811    define(interp, "args", Some(0), |interp, _| {
8812        let args: Vec<Value> = if interp.program_args.as_ref().map(|v| v.is_empty()).unwrap_or(true) {
8813            // Fallback: return all args if program_args not set
8814            std::env::args()
8815                .map(|s| Value::String(Rc::new(s)))
8816                .collect()
8817        } else {
8818            // Return filtered program args
8819            interp.program_args.as_ref().unwrap().iter()
8820                .map(|a| Value::String(Rc::new(a.clone())))
8821                .collect()
8822        };
8823        Ok(Value::Array(Rc::new(RefCell::new(args))))
8824    });
8825
8826    // cwd - get current working directory
8827    define(interp, "cwd", Some(0), |_, _| {
8828        match std::env::current_dir() {
8829            Ok(path) => Ok(Value::String(Rc::new(path.to_string_lossy().to_string()))),
8830            Err(e) => Err(RuntimeError::new(format!("cwd() error: {}", e))),
8831        }
8832    });
8833
8834    // chdir - change current directory
8835    define(interp, "chdir", Some(1), |_, args| {
8836        let path = match &args[0] {
8837            Value::String(s) => s.to_string(),
8838            _ => return Err(RuntimeError::new("chdir() requires string path")),
8839        };
8840
8841        match std::env::set_current_dir(&path) {
8842            Ok(()) => Ok(Value::Null),
8843            Err(e) => Err(RuntimeError::new(format!("chdir() error: {}", e))),
8844        }
8845    });
8846
8847    // hostname - get system hostname
8848    define(interp, "hostname", Some(0), |_, _| {
8849        // Try to read from /etc/hostname or use fallback
8850        match std::fs::read_to_string("/etc/hostname") {
8851            Ok(name) => Ok(Value::String(Rc::new(name.trim().to_string()))),
8852            Err(_) => Ok(Value::String(Rc::new("unknown".to_string()))),
8853        }
8854    });
8855
8856    // pid - get current process ID
8857    define(interp, "pid", Some(0), |_, _| {
8858        Ok(Value::Int(std::process::id() as i64))
8859    });
8860
8861    // exit - exit the program with code
8862    define(interp, "exit", Some(1), |_, args| {
8863        let code = match &args[0] {
8864            Value::Int(n) => *n as i32,
8865            _ => 0,
8866        };
8867        std::process::exit(code);
8868    });
8869
8870    // std::process::exit - exit the program with code (qualified name)
8871    define(interp, "std·process·exit", Some(1), |_, args| {
8872        let code = match &args[0] {
8873            Value::Int(n) => *n as i32,
8874            _ => 0,
8875        };
8876        std::process::exit(code);
8877    });
8878
8879    // shell - execute shell command and return output
8880    define(interp, "shell", Some(1), |_, args| {
8881        let cmd = match &args[0] {
8882            Value::String(s) => s.to_string(),
8883            _ => return Err(RuntimeError::new("shell() requires string command")),
8884        };
8885
8886        match std::process::Command::new("sh")
8887            .arg("-c")
8888            .arg(&cmd)
8889            .output()
8890        {
8891            Ok(output) => {
8892                let stdout = String::from_utf8_lossy(&output.stdout).to_string();
8893                let stderr = String::from_utf8_lossy(&output.stderr).to_string();
8894                let code = output.status.code().unwrap_or(-1);
8895
8896                let mut result = HashMap::new();
8897                result.insert("stdout".to_string(), Value::String(Rc::new(stdout)));
8898                result.insert("stderr".to_string(), Value::String(Rc::new(stderr)));
8899                result.insert("code".to_string(), Value::Int(code as i64));
8900                result.insert("success".to_string(), Value::Bool(output.status.success()));
8901
8902                Ok(Value::Map(Rc::new(RefCell::new(result))))
8903            }
8904            Err(e) => Err(RuntimeError::new(format!("shell() error: {}", e))),
8905        }
8906    });
8907
8908    // platform - get OS name
8909    define(interp, "platform", Some(0), |_, _| {
8910        Ok(Value::String(Rc::new(std::env::consts::OS.to_string())))
8911    });
8912
8913    // arch - get CPU architecture
8914    define(interp, "arch", Some(0), |_, _| {
8915        Ok(Value::String(Rc::new(std::env::consts::ARCH.to_string())))
8916    });
8917
8918    // num_cpus::get - get number of available CPUs
8919    define(interp, "num_cpus·get", Some(0), |_, _| {
8920        Ok(Value::Int(num_cpus::get() as i64))
8921    });
8922
8923    // num_cpus::get_physical - get number of physical CPU cores
8924    define(interp, "num_cpus·get_physical", Some(0), |_, _| {
8925        Ok(Value::Int(num_cpus::get_physical() as i64))
8926    });
8927}
8928
8929// ============================================================================
8930// STATISTICS FUNCTIONS
8931// ============================================================================
8932
8933fn register_stats(interp: &mut Interpreter) {
8934    // Helper to extract numbers from array
8935    fn extract_numbers(val: &Value) -> Result<Vec<f64>, RuntimeError> {
8936        match val {
8937            Value::Array(arr) => {
8938                let arr = arr.borrow();
8939                let mut nums = Vec::new();
8940                for v in arr.iter() {
8941                    match v {
8942                        Value::Int(n) => nums.push(*n as f64),
8943                        Value::Float(f) => nums.push(*f),
8944                        _ => {
8945                            return Err(RuntimeError::new("stats functions require numeric array"))
8946                        }
8947                    }
8948                }
8949                Ok(nums)
8950            }
8951            _ => Err(RuntimeError::new("stats functions require array")),
8952        }
8953    }
8954
8955    // mean - arithmetic mean
8956    define(interp, "mean", Some(1), |_, args| {
8957        let nums = extract_numbers(&args[0])?;
8958        if nums.is_empty() {
8959            return Ok(Value::Float(0.0));
8960        }
8961        let sum: f64 = nums.iter().sum();
8962        Ok(Value::Float(sum / nums.len() as f64))
8963    });
8964
8965    // median - middle value
8966    define(interp, "median", Some(1), |_, args| {
8967        let mut nums = extract_numbers(&args[0])?;
8968        if nums.is_empty() {
8969            return Ok(Value::Float(0.0));
8970        }
8971        nums.sort_by(|a, b| a.partial_cmp(b).unwrap());
8972        let len = nums.len();
8973        if len % 2 == 0 {
8974            Ok(Value::Float((nums[len / 2 - 1] + nums[len / 2]) / 2.0))
8975        } else {
8976            Ok(Value::Float(nums[len / 2]))
8977        }
8978    });
8979
8980    // mode - most frequent value
8981    define(interp, "mode", Some(1), |_, args| {
8982        let nums = extract_numbers(&args[0])?;
8983        if nums.is_empty() {
8984            return Ok(Value::Null);
8985        }
8986
8987        let mut counts: HashMap<String, usize> = HashMap::new();
8988        for n in &nums {
8989            let key = format!("{:.10}", n);
8990            *counts.entry(key).or_insert(0) += 1;
8991        }
8992
8993        let max_count = counts.values().max().unwrap_or(&0);
8994        for n in &nums {
8995            let key = format!("{:.10}", n);
8996            if counts.get(&key) == Some(max_count) {
8997                return Ok(Value::Float(*n));
8998            }
8999        }
9000        Ok(Value::Null)
9001    });
9002
9003    // variance - population variance
9004    define(interp, "variance", Some(1), |_, args| {
9005        let nums = extract_numbers(&args[0])?;
9006        if nums.is_empty() {
9007            return Ok(Value::Float(0.0));
9008        }
9009        let mean: f64 = nums.iter().sum::<f64>() / nums.len() as f64;
9010        let variance: f64 =
9011            nums.iter().map(|x| (x - mean).powi(2)).sum::<f64>() / nums.len() as f64;
9012        Ok(Value::Float(variance))
9013    });
9014
9015    // stddev - standard deviation
9016    define(interp, "stddev", Some(1), |_, args| {
9017        let nums = extract_numbers(&args[0])?;
9018        if nums.is_empty() {
9019            return Ok(Value::Float(0.0));
9020        }
9021        let mean: f64 = nums.iter().sum::<f64>() / nums.len() as f64;
9022        let variance: f64 =
9023            nums.iter().map(|x| (x - mean).powi(2)).sum::<f64>() / nums.len() as f64;
9024        Ok(Value::Float(variance.sqrt()))
9025    });
9026
9027    // percentile - compute nth percentile
9028    define(interp, "percentile", Some(2), |_, args| {
9029        let mut nums = extract_numbers(&args[0])?;
9030        let p = match &args[1] {
9031            Value::Int(n) => *n as f64,
9032            Value::Float(f) => *f,
9033            _ => {
9034                return Err(RuntimeError::new(
9035                    "percentile() requires numeric percentile",
9036                ))
9037            }
9038        };
9039
9040        if nums.is_empty() {
9041            return Ok(Value::Float(0.0));
9042        }
9043
9044        nums.sort_by(|a, b| a.partial_cmp(b).unwrap());
9045        let idx = (p / 100.0 * (nums.len() - 1) as f64).round() as usize;
9046        Ok(Value::Float(nums[idx.min(nums.len() - 1)]))
9047    });
9048
9049    // correlation - Pearson correlation coefficient
9050    define(interp, "correlation", Some(2), |_, args| {
9051        let x = extract_numbers(&args[0])?;
9052        let y = extract_numbers(&args[1])?;
9053
9054        if x.len() != y.len() || x.is_empty() {
9055            return Err(RuntimeError::new(
9056                "correlation() requires equal-length non-empty arrays",
9057            ));
9058        }
9059
9060        let n = x.len() as f64;
9061        let mean_x: f64 = x.iter().sum::<f64>() / n;
9062        let mean_y: f64 = y.iter().sum::<f64>() / n;
9063
9064        let mut cov = 0.0;
9065        let mut var_x = 0.0;
9066        let mut var_y = 0.0;
9067
9068        for i in 0..x.len() {
9069            let dx = x[i] - mean_x;
9070            let dy = y[i] - mean_y;
9071            cov += dx * dy;
9072            var_x += dx * dx;
9073            var_y += dy * dy;
9074        }
9075
9076        if var_x == 0.0 || var_y == 0.0 {
9077            return Ok(Value::Float(0.0));
9078        }
9079
9080        Ok(Value::Float(cov / (var_x.sqrt() * var_y.sqrt())))
9081    });
9082
9083    // range - difference between max and min
9084    define(interp, "range", Some(1), |_, args| {
9085        let nums = extract_numbers(&args[0])?;
9086        if nums.is_empty() {
9087            return Ok(Value::Float(0.0));
9088        }
9089        let min = nums.iter().cloned().fold(f64::INFINITY, f64::min);
9090        let max = nums.iter().cloned().fold(f64::NEG_INFINITY, f64::max);
9091        Ok(Value::Float(max - min))
9092    });
9093
9094    // zscore - compute z-scores for array
9095    define(interp, "zscore", Some(1), |_, args| {
9096        let nums = extract_numbers(&args[0])?;
9097        if nums.is_empty() {
9098            return Ok(Value::Array(Rc::new(RefCell::new(vec![]))));
9099        }
9100
9101        let mean: f64 = nums.iter().sum::<f64>() / nums.len() as f64;
9102        let variance: f64 =
9103            nums.iter().map(|x| (x - mean).powi(2)).sum::<f64>() / nums.len() as f64;
9104        let stddev = variance.sqrt();
9105
9106        if stddev == 0.0 {
9107            let zeros: Vec<Value> = nums.iter().map(|_| Value::Float(0.0)).collect();
9108            return Ok(Value::Array(Rc::new(RefCell::new(zeros))));
9109        }
9110
9111        let zscores: Vec<Value> = nums
9112            .iter()
9113            .map(|x| Value::Float((x - mean) / stddev))
9114            .collect();
9115        Ok(Value::Array(Rc::new(RefCell::new(zscores))))
9116    });
9117}
9118
9119// ============================================================================
9120// MATRIX FUNCTIONS
9121// ============================================================================
9122
9123fn register_matrix(interp: &mut Interpreter) {
9124    // Helper to extract 2D matrix from nested arrays
9125    fn extract_matrix(val: &Value) -> Result<Vec<Vec<f64>>, RuntimeError> {
9126        match val {
9127            Value::Array(arr) => {
9128                let arr = arr.borrow();
9129                let mut matrix = Vec::new();
9130                for row in arr.iter() {
9131                    match row {
9132                        Value::Array(row_arr) => {
9133                            let row_arr = row_arr.borrow();
9134                            let mut row_vec = Vec::new();
9135                            for v in row_arr.iter() {
9136                                match v {
9137                                    Value::Int(n) => row_vec.push(*n as f64),
9138                                    Value::Float(f) => row_vec.push(*f),
9139                                    _ => {
9140                                        return Err(RuntimeError::new(
9141                                            "matrix requires numeric values",
9142                                        ))
9143                                    }
9144                                }
9145                            }
9146                            matrix.push(row_vec);
9147                        }
9148                        _ => return Err(RuntimeError::new("matrix requires 2D array")),
9149                    }
9150                }
9151                Ok(matrix)
9152            }
9153            _ => Err(RuntimeError::new("matrix requires array")),
9154        }
9155    }
9156
9157    fn matrix_to_value(m: Vec<Vec<f64>>) -> Value {
9158        let rows: Vec<Value> = m
9159            .into_iter()
9160            .map(|row| {
9161                let cols: Vec<Value> = row.into_iter().map(Value::Float).collect();
9162                Value::Array(Rc::new(RefCell::new(cols)))
9163            })
9164            .collect();
9165        Value::Array(Rc::new(RefCell::new(rows)))
9166    }
9167
9168    // matrix_new - create matrix filled with value
9169    define(interp, "matrix_new", Some(3), |_, args| {
9170        let rows = match &args[0] {
9171            Value::Int(n) => *n as usize,
9172            _ => return Err(RuntimeError::new("matrix_new() requires integer rows")),
9173        };
9174        let cols = match &args[1] {
9175            Value::Int(n) => *n as usize,
9176            _ => return Err(RuntimeError::new("matrix_new() requires integer cols")),
9177        };
9178        let fill = match &args[2] {
9179            Value::Int(n) => *n as f64,
9180            Value::Float(f) => *f,
9181            _ => 0.0,
9182        };
9183
9184        let matrix = vec![vec![fill; cols]; rows];
9185        Ok(matrix_to_value(matrix))
9186    });
9187
9188    // matrix_identity - create identity matrix
9189    define(interp, "matrix_identity", Some(1), |_, args| {
9190        let size = match &args[0] {
9191            Value::Int(n) => *n as usize,
9192            _ => return Err(RuntimeError::new("matrix_identity() requires integer size")),
9193        };
9194
9195        let mut matrix = vec![vec![0.0; size]; size];
9196        for i in 0..size {
9197            matrix[i][i] = 1.0;
9198        }
9199        Ok(matrix_to_value(matrix))
9200    });
9201
9202    // matrix_add - add two matrices
9203    define(interp, "matrix_add", Some(2), |_, args| {
9204        let a = extract_matrix(&args[0])?;
9205        let b = extract_matrix(&args[1])?;
9206
9207        if a.len() != b.len() || a.is_empty() || a[0].len() != b[0].len() {
9208            return Err(RuntimeError::new(
9209                "matrix_add() requires same-size matrices",
9210            ));
9211        }
9212
9213        let result: Vec<Vec<f64>> = a
9214            .iter()
9215            .zip(b.iter())
9216            .map(|(row_a, row_b)| row_a.iter().zip(row_b.iter()).map(|(x, y)| x + y).collect())
9217            .collect();
9218
9219        Ok(matrix_to_value(result))
9220    });
9221
9222    // matrix_sub - subtract two matrices
9223    define(interp, "matrix_sub", Some(2), |_, args| {
9224        let a = extract_matrix(&args[0])?;
9225        let b = extract_matrix(&args[1])?;
9226
9227        if a.len() != b.len() || a.is_empty() || a[0].len() != b[0].len() {
9228            return Err(RuntimeError::new(
9229                "matrix_sub() requires same-size matrices",
9230            ));
9231        }
9232
9233        let result: Vec<Vec<f64>> = a
9234            .iter()
9235            .zip(b.iter())
9236            .map(|(row_a, row_b)| row_a.iter().zip(row_b.iter()).map(|(x, y)| x - y).collect())
9237            .collect();
9238
9239        Ok(matrix_to_value(result))
9240    });
9241
9242    // matrix_mul - multiply two matrices
9243    define(interp, "matrix_mul", Some(2), |_, args| {
9244        let a = extract_matrix(&args[0])?;
9245        let b = extract_matrix(&args[1])?;
9246
9247        if a.is_empty() || b.is_empty() || a[0].len() != b.len() {
9248            return Err(RuntimeError::new(
9249                "matrix_mul() requires compatible matrices (a.cols == b.rows)",
9250            ));
9251        }
9252
9253        let rows = a.len();
9254        let cols = b[0].len();
9255        let inner = b.len();
9256
9257        let mut result = vec![vec![0.0; cols]; rows];
9258        for i in 0..rows {
9259            for j in 0..cols {
9260                for k in 0..inner {
9261                    result[i][j] += a[i][k] * b[k][j];
9262                }
9263            }
9264        }
9265
9266        Ok(matrix_to_value(result))
9267    });
9268
9269    // matrix_scale - multiply matrix by scalar
9270    define(interp, "matrix_scale", Some(2), |_, args| {
9271        let m = extract_matrix(&args[0])?;
9272        let scale = match &args[1] {
9273            Value::Int(n) => *n as f64,
9274            Value::Float(f) => *f,
9275            _ => return Err(RuntimeError::new("matrix_scale() requires numeric scalar")),
9276        };
9277
9278        let result: Vec<Vec<f64>> = m
9279            .iter()
9280            .map(|row| row.iter().map(|x| x * scale).collect())
9281            .collect();
9282
9283        Ok(matrix_to_value(result))
9284    });
9285
9286    // matrix_transpose - transpose matrix
9287    define(interp, "matrix_transpose", Some(1), |_, args| {
9288        let m = extract_matrix(&args[0])?;
9289        if m.is_empty() {
9290            return Ok(Value::Array(Rc::new(RefCell::new(vec![]))));
9291        }
9292
9293        let rows = m.len();
9294        let cols = m[0].len();
9295        let mut result = vec![vec![0.0; rows]; cols];
9296
9297        for i in 0..rows {
9298            for j in 0..cols {
9299                result[j][i] = m[i][j];
9300            }
9301        }
9302
9303        Ok(matrix_to_value(result))
9304    });
9305
9306    // matrix_det - determinant (for 2x2 and 3x3)
9307    define(interp, "matrix_det", Some(1), |_, args| {
9308        let m = extract_matrix(&args[0])?;
9309
9310        if m.is_empty() || m.len() != m[0].len() {
9311            return Err(RuntimeError::new("matrix_det() requires square matrix"));
9312        }
9313
9314        let n = m.len();
9315        match n {
9316            1 => Ok(Value::Float(m[0][0])),
9317            2 => Ok(Value::Float(m[0][0] * m[1][1] - m[0][1] * m[1][0])),
9318            3 => {
9319                let det = m[0][0] * (m[1][1] * m[2][2] - m[1][2] * m[2][1])
9320                    - m[0][1] * (m[1][0] * m[2][2] - m[1][2] * m[2][0])
9321                    + m[0][2] * (m[1][0] * m[2][1] - m[1][1] * m[2][0]);
9322                Ok(Value::Float(det))
9323            }
9324            _ => Err(RuntimeError::new(
9325                "matrix_det() only supports up to 3x3 matrices",
9326            )),
9327        }
9328    });
9329
9330    // matrix_trace - trace (sum of diagonal)
9331    define(interp, "matrix_trace", Some(1), |_, args| {
9332        let m = extract_matrix(&args[0])?;
9333
9334        let size = m.len().min(if m.is_empty() { 0 } else { m[0].len() });
9335        let trace: f64 = (0..size).map(|i| m[i][i]).sum();
9336
9337        Ok(Value::Float(trace))
9338    });
9339
9340    // matrix_dot - dot product of vectors (1D arrays)
9341    define(interp, "matrix_dot", Some(2), |_, args| {
9342        fn extract_vector(val: &Value) -> Result<Vec<f64>, RuntimeError> {
9343            match val {
9344                Value::Array(arr) => {
9345                    let arr = arr.borrow();
9346                    let mut vec = Vec::new();
9347                    for v in arr.iter() {
9348                        match v {
9349                            Value::Int(n) => vec.push(*n as f64),
9350                            Value::Float(f) => vec.push(*f),
9351                            _ => {
9352                                return Err(RuntimeError::new(
9353                                    "dot product requires numeric vectors",
9354                                ))
9355                            }
9356                        }
9357                    }
9358                    Ok(vec)
9359                }
9360                _ => Err(RuntimeError::new("dot product requires arrays")),
9361            }
9362        }
9363
9364        let a = extract_vector(&args[0])?;
9365        let b = extract_vector(&args[1])?;
9366
9367        if a.len() != b.len() {
9368            return Err(RuntimeError::new(
9369                "matrix_dot() requires same-length vectors",
9370            ));
9371        }
9372
9373        let dot: f64 = a.iter().zip(b.iter()).map(|(x, y)| x * y).sum();
9374        Ok(Value::Float(dot))
9375    });
9376}
9377
9378// Extended Euclidean algorithm for modular inverse
9379fn mod_inverse(a: i64, m: i64) -> Option<i64> {
9380    let (mut old_r, mut r) = (a, m);
9381    let (mut old_s, mut s) = (1i64, 0i64);
9382
9383    while r != 0 {
9384        let q = old_r / r;
9385        (old_r, r) = (r, old_r - q * r);
9386        (old_s, s) = (s, old_s - q * s);
9387    }
9388
9389    if old_r != 1 {
9390        None // No inverse exists
9391    } else {
9392        Some(old_s.rem_euclid(m))
9393    }
9394}
9395
9396// ============================================================================
9397// Phase 5: Language Power-Ups
9398// ============================================================================
9399
9400/// Functional programming utilities
9401fn register_functional(interp: &mut Interpreter) {
9402    // identity - returns its argument unchanged
9403    define(interp, "identity", Some(1), |_, args| Ok(args[0].clone()));
9404
9405    // const_fn - returns a function that always returns the given value
9406    define(interp, "const_fn", Some(1), |_, args| Ok(args[0].clone()));
9407
9408    // apply - apply a function to an array of arguments
9409    define(interp, "apply", Some(2), |interp, args| {
9410        let func = match &args[0] {
9411            Value::Function(f) => f.clone(),
9412            _ => {
9413                return Err(RuntimeError::new(
9414                    "apply: first argument must be a function",
9415                ))
9416            }
9417        };
9418        let fn_args = match &args[1] {
9419            Value::Array(arr) => arr.borrow().clone(),
9420            _ => return Err(RuntimeError::new("apply: second argument must be an array")),
9421        };
9422        interp.call_function(&func, fn_args)
9423    });
9424
9425    // flip - swap the first two arguments of a binary function
9426    define(interp, "flip", Some(3), |interp, args| {
9427        let func = match &args[0] {
9428            Value::Function(f) => f.clone(),
9429            _ => return Err(RuntimeError::new("flip: first argument must be a function")),
9430        };
9431        let flipped_args = vec![args[2].clone(), args[1].clone()];
9432        interp.call_function(&func, flipped_args)
9433    });
9434
9435    // tap - execute a function for side effects, return original value
9436    define(interp, "tap", Some(2), |interp, args| {
9437        let val = args[0].clone();
9438        let func = match &args[1] {
9439            Value::Function(f) => f.clone(),
9440            _ => return Err(RuntimeError::new("tap: second argument must be a function")),
9441        };
9442        let _ = interp.call_function(&func, vec![val.clone()]);
9443        Ok(val)
9444    });
9445
9446    // thunk - create a delayed computation (wrap in array for later forcing)
9447    define(interp, "thunk", Some(1), |_, args| {
9448        Ok(Value::Array(Rc::new(RefCell::new(vec![args[0].clone()]))))
9449    });
9450
9451    // force - force evaluation of a thunk
9452    define(interp, "force", Some(1), |interp, args| match &args[0] {
9453        Value::Array(arr) => {
9454            let arr = arr.borrow();
9455            if arr.len() == 1 {
9456                if let Value::Function(f) = &arr[0] {
9457                    return interp.call_function(f, vec![]);
9458                }
9459            }
9460            Ok(arr.get(0).cloned().unwrap_or(Value::Null))
9461        }
9462        v => Ok(v.clone()),
9463    });
9464
9465    // negate - negate a predicate function result
9466    define(interp, "negate", Some(2), |interp, args| {
9467        let func = match &args[0] {
9468            Value::Function(f) => f.clone(),
9469            _ => {
9470                return Err(RuntimeError::new(
9471                    "negate: first argument must be a function",
9472                ))
9473            }
9474        };
9475        let result = interp.call_function(&func, vec![args[1].clone()])?;
9476        Ok(Value::Bool(!is_truthy(&result)))
9477    });
9478
9479    // complement - same as negate
9480    define(interp, "complement", Some(2), |interp, args| {
9481        let func = match &args[0] {
9482            Value::Function(f) => f.clone(),
9483            _ => {
9484                return Err(RuntimeError::new(
9485                    "complement: first argument must be a function",
9486                ))
9487            }
9488        };
9489        let result = interp.call_function(&func, vec![args[1].clone()])?;
9490        Ok(Value::Bool(!is_truthy(&result)))
9491    });
9492
9493    // partial - partially apply a function with some arguments
9494    define(interp, "partial", None, |interp, args| {
9495        if args.len() < 2 {
9496            return Err(RuntimeError::new(
9497                "partial: requires at least function and one argument",
9498            ));
9499        }
9500        let func = match &args[0] {
9501            Value::Function(f) => f.clone(),
9502            _ => {
9503                return Err(RuntimeError::new(
9504                    "partial: first argument must be a function",
9505                ))
9506            }
9507        };
9508        let partial_args: Vec<Value> = args[1..].to_vec();
9509        interp.call_function(&func, partial_args)
9510    });
9511
9512    // juxt - apply multiple functions to same args, return array of results
9513    define(interp, "juxt", None, |interp, args| {
9514        if args.len() < 2 {
9515            return Err(RuntimeError::new("juxt: requires functions and a value"));
9516        }
9517        let val = args.last().unwrap().clone();
9518        let results: Result<Vec<Value>, _> = args[..args.len() - 1]
9519            .iter()
9520            .map(|f| match f {
9521                Value::Function(func) => interp.call_function(func, vec![val.clone()]),
9522                _ => Err(RuntimeError::new(
9523                    "juxt: all but last argument must be functions",
9524                )),
9525            })
9526            .collect();
9527        Ok(Value::Array(Rc::new(RefCell::new(results?))))
9528    });
9529}
9530
9531/// Benchmarking and profiling utilities
9532fn register_benchmark(interp: &mut Interpreter) {
9533    // bench - run a function N times and return average time in ms
9534    define(interp, "bench", Some(2), |interp, args| {
9535        let func = match &args[0] {
9536            Value::Function(f) => f.clone(),
9537            _ => {
9538                return Err(RuntimeError::new(
9539                    "bench: first argument must be a function",
9540                ))
9541            }
9542        };
9543        let iterations = match &args[1] {
9544            Value::Int(n) => *n as usize,
9545            _ => {
9546                return Err(RuntimeError::new(
9547                    "bench: second argument must be an integer",
9548                ))
9549            }
9550        };
9551
9552        let start = std::time::Instant::now();
9553        for _ in 0..iterations {
9554            let _ = interp.call_function(&func, vec![])?;
9555        }
9556        let elapsed = start.elapsed();
9557        let avg_ms = elapsed.as_secs_f64() * 1000.0 / iterations as f64;
9558        Ok(Value::Float(avg_ms))
9559    });
9560
9561    // time_it - run a function once and return (result, time_ms) tuple
9562    define(interp, "time_it", Some(1), |interp, args| {
9563        let func = match &args[0] {
9564            Value::Function(f) => f.clone(),
9565            _ => return Err(RuntimeError::new("time_it: argument must be a function")),
9566        };
9567
9568        let start = std::time::Instant::now();
9569        let result = interp.call_function(&func, vec![])?;
9570        let elapsed_ms = start.elapsed().as_secs_f64() * 1000.0;
9571
9572        Ok(Value::Tuple(Rc::new(vec![
9573            result,
9574            Value::Float(elapsed_ms),
9575        ])))
9576    });
9577
9578    // stopwatch_start - return current time in ms
9579    define(interp, "stopwatch_start", Some(0), |_, _| {
9580        let elapsed = std::time::SystemTime::now()
9581            .duration_since(std::time::UNIX_EPOCH)
9582            .unwrap_or_default();
9583        Ok(Value::Float(elapsed.as_secs_f64() * 1000.0))
9584    });
9585
9586    // stopwatch_elapsed - get elapsed time since a stopwatch start
9587    define(interp, "stopwatch_elapsed", Some(1), |_, args| {
9588        let start_ms = match &args[0] {
9589            Value::Float(f) => *f,
9590            Value::Int(n) => *n as f64,
9591            _ => {
9592                return Err(RuntimeError::new(
9593                    "stopwatch_elapsed: argument must be a number",
9594                ))
9595            }
9596        };
9597        let now = std::time::SystemTime::now()
9598            .duration_since(std::time::UNIX_EPOCH)
9599            .unwrap_or_default();
9600        let now_ms = now.as_secs_f64() * 1000.0;
9601        Ok(Value::Float(now_ms - start_ms))
9602    });
9603
9604    // compare_bench - compare two functions, return speedup ratio
9605    define(interp, "compare_bench", Some(3), |interp, args| {
9606        let func1 = match &args[0] {
9607            Value::Function(f) => f.clone(),
9608            _ => {
9609                return Err(RuntimeError::new(
9610                    "compare_bench: first argument must be a function",
9611                ))
9612            }
9613        };
9614        let func2 = match &args[1] {
9615            Value::Function(f) => f.clone(),
9616            _ => {
9617                return Err(RuntimeError::new(
9618                    "compare_bench: second argument must be a function",
9619                ))
9620            }
9621        };
9622        let iterations = match &args[2] {
9623            Value::Int(n) => *n as usize,
9624            _ => {
9625                return Err(RuntimeError::new(
9626                    "compare_bench: third argument must be an integer",
9627                ))
9628            }
9629        };
9630
9631        let start1 = std::time::Instant::now();
9632        for _ in 0..iterations {
9633            let _ = interp.call_function(&func1, vec![])?;
9634        }
9635        let time1 = start1.elapsed().as_secs_f64();
9636
9637        let start2 = std::time::Instant::now();
9638        for _ in 0..iterations {
9639            let _ = interp.call_function(&func2, vec![])?;
9640        }
9641        let time2 = start2.elapsed().as_secs_f64();
9642
9643        let mut results = std::collections::HashMap::new();
9644        results.insert("time1_ms".to_string(), Value::Float(time1 * 1000.0));
9645        results.insert("time2_ms".to_string(), Value::Float(time2 * 1000.0));
9646        results.insert("speedup".to_string(), Value::Float(time1 / time2));
9647        results.insert("iterations".to_string(), Value::Int(iterations as i64));
9648
9649        Ok(Value::Struct {
9650            name: "BenchResult".to_string(),
9651            fields: Rc::new(RefCell::new(results)),
9652        })
9653    });
9654
9655    // memory_usage - placeholder
9656    define(interp, "memory_usage", Some(0), |_, _| Ok(Value::Int(0)));
9657}
9658
9659/// Extended iterator utilities (itertools-inspired)
9660fn register_itertools(interp: &mut Interpreter) {
9661    // cycle - create infinite cycle of array elements (returns first N)
9662    define(interp, "cycle", Some(2), |_, args| {
9663        let arr = match &args[0] {
9664            Value::Array(a) => a.borrow().clone(),
9665            _ => return Err(RuntimeError::new("cycle: first argument must be an array")),
9666        };
9667        let n = match &args[1] {
9668            Value::Int(n) => *n as usize,
9669            _ => {
9670                return Err(RuntimeError::new(
9671                    "cycle: second argument must be an integer",
9672                ))
9673            }
9674        };
9675
9676        if arr.is_empty() {
9677            return Ok(Value::Array(Rc::new(RefCell::new(vec![]))));
9678        }
9679
9680        let result: Vec<Value> = (0..n).map(|i| arr[i % arr.len()].clone()).collect();
9681        Ok(Value::Array(Rc::new(RefCell::new(result))))
9682    });
9683
9684    // repeat_val - repeat a value N times
9685    define(interp, "repeat_val", Some(2), |_, args| {
9686        let val = args[0].clone();
9687        let n = match &args[1] {
9688            Value::Int(n) => *n as usize,
9689            _ => {
9690                return Err(RuntimeError::new(
9691                    "repeat_val: second argument must be an integer",
9692                ))
9693            }
9694        };
9695
9696        let result: Vec<Value> = std::iter::repeat(val).take(n).collect();
9697        Ok(Value::Array(Rc::new(RefCell::new(result))))
9698    });
9699
9700    // take_while - take elements while predicate is true
9701    define(interp, "take_while", Some(2), |interp, args| {
9702        let arr = match &args[0] {
9703            Value::Array(a) => a.borrow().clone(),
9704            _ => {
9705                return Err(RuntimeError::new(
9706                    "take_while: first argument must be an array",
9707                ))
9708            }
9709        };
9710        let pred = match &args[1] {
9711            Value::Function(f) => f.clone(),
9712            _ => {
9713                return Err(RuntimeError::new(
9714                    "take_while: second argument must be a function",
9715                ))
9716            }
9717        };
9718
9719        let mut result = Vec::new();
9720        for item in arr {
9721            let keep = interp.call_function(&pred, vec![item.clone()])?;
9722            if is_truthy(&keep) {
9723                result.push(item);
9724            } else {
9725                break;
9726            }
9727        }
9728        Ok(Value::Array(Rc::new(RefCell::new(result))))
9729    });
9730
9731    // drop_while - drop elements while predicate is true
9732    define(interp, "drop_while", Some(2), |interp, args| {
9733        let arr = match &args[0] {
9734            Value::Array(a) => a.borrow().clone(),
9735            _ => {
9736                return Err(RuntimeError::new(
9737                    "drop_while: first argument must be an array",
9738                ))
9739            }
9740        };
9741        let pred = match &args[1] {
9742            Value::Function(f) => f.clone(),
9743            _ => {
9744                return Err(RuntimeError::new(
9745                    "drop_while: second argument must be a function",
9746                ))
9747            }
9748        };
9749
9750        let mut dropping = true;
9751        let mut result = Vec::new();
9752        for item in arr {
9753            if dropping {
9754                let drop = interp.call_function(&pred, vec![item.clone()])?;
9755                if !is_truthy(&drop) {
9756                    dropping = false;
9757                    result.push(item);
9758                }
9759            } else {
9760                result.push(item);
9761            }
9762        }
9763        Ok(Value::Array(Rc::new(RefCell::new(result))))
9764    });
9765
9766    // group_by - group consecutive elements by key function
9767    define(interp, "group_by", Some(2), |interp, args| {
9768        let arr = match &args[0] {
9769            Value::Array(a) => a.borrow().clone(),
9770            _ => {
9771                return Err(RuntimeError::new(
9772                    "group_by: first argument must be an array",
9773                ))
9774            }
9775        };
9776        let key_fn = match &args[1] {
9777            Value::Function(f) => f.clone(),
9778            _ => {
9779                return Err(RuntimeError::new(
9780                    "group_by: second argument must be a function",
9781                ))
9782            }
9783        };
9784
9785        let mut groups: Vec<Value> = Vec::new();
9786        let mut current_group: Vec<Value> = Vec::new();
9787        let mut current_key: Option<Value> = None;
9788
9789        for item in arr {
9790            let key = interp.call_function(&key_fn, vec![item.clone()])?;
9791            match &current_key {
9792                Some(k) if value_eq(k, &key) => {
9793                    current_group.push(item);
9794                }
9795                _ => {
9796                    if !current_group.is_empty() {
9797                        groups.push(Value::Array(Rc::new(RefCell::new(current_group))));
9798                    }
9799                    current_group = vec![item];
9800                    current_key = Some(key);
9801                }
9802            }
9803        }
9804        if !current_group.is_empty() {
9805            groups.push(Value::Array(Rc::new(RefCell::new(current_group))));
9806        }
9807
9808        Ok(Value::Array(Rc::new(RefCell::new(groups))))
9809    });
9810
9811    // partition - split array by predicate into (true_items, false_items)
9812    define(interp, "partition", Some(2), |interp, args| {
9813        let arr = match &args[0] {
9814            Value::Array(a) => a.borrow().clone(),
9815            _ => {
9816                return Err(RuntimeError::new(
9817                    "partition: first argument must be an array",
9818                ))
9819            }
9820        };
9821        let pred = match &args[1] {
9822            Value::Function(f) => f.clone(),
9823            _ => {
9824                return Err(RuntimeError::new(
9825                    "partition: second argument must be a function",
9826                ))
9827            }
9828        };
9829
9830        let mut true_items = Vec::new();
9831        let mut false_items = Vec::new();
9832
9833        for item in arr {
9834            let result = interp.call_function(&pred, vec![item.clone()])?;
9835            if is_truthy(&result) {
9836                true_items.push(item);
9837            } else {
9838                false_items.push(item);
9839            }
9840        }
9841
9842        Ok(Value::Tuple(Rc::new(vec![
9843            Value::Array(Rc::new(RefCell::new(true_items))),
9844            Value::Array(Rc::new(RefCell::new(false_items))),
9845        ])))
9846    });
9847
9848    // interleave - interleave two arrays
9849    define(interp, "interleave", Some(2), |_, args| {
9850        let arr1 = match &args[0] {
9851            Value::Array(a) => a.borrow().clone(),
9852            _ => {
9853                return Err(RuntimeError::new(
9854                    "interleave: first argument must be an array",
9855                ))
9856            }
9857        };
9858        let arr2 = match &args[1] {
9859            Value::Array(a) => a.borrow().clone(),
9860            _ => {
9861                return Err(RuntimeError::new(
9862                    "interleave: second argument must be an array",
9863                ))
9864            }
9865        };
9866
9867        let mut result = Vec::new();
9868        let mut i1 = arr1.into_iter();
9869        let mut i2 = arr2.into_iter();
9870
9871        loop {
9872            match (i1.next(), i2.next()) {
9873                (Some(a), Some(b)) => {
9874                    result.push(a);
9875                    result.push(b);
9876                }
9877                (Some(a), None) => {
9878                    result.push(a);
9879                    result.extend(i1);
9880                    break;
9881                }
9882                (None, Some(b)) => {
9883                    result.push(b);
9884                    result.extend(i2);
9885                    break;
9886                }
9887                (None, None) => break,
9888            }
9889        }
9890
9891        Ok(Value::Array(Rc::new(RefCell::new(result))))
9892    });
9893
9894    // chunks - split array into chunks of size N
9895    define(interp, "chunks", Some(2), |_, args| {
9896        let arr = match &args[0] {
9897            Value::Array(a) => a.borrow().clone(),
9898            _ => return Err(RuntimeError::new("chunks: first argument must be an array")),
9899        };
9900        let size = match &args[1] {
9901            Value::Int(n) if *n > 0 => *n as usize,
9902            _ => {
9903                return Err(RuntimeError::new(
9904                    "chunks: second argument must be a positive integer",
9905                ))
9906            }
9907        };
9908
9909        let chunks: Vec<Value> = arr
9910            .chunks(size)
9911            .map(|chunk| Value::Array(Rc::new(RefCell::new(chunk.to_vec()))))
9912            .collect();
9913
9914        Ok(Value::Array(Rc::new(RefCell::new(chunks))))
9915    });
9916
9917    // windows - sliding windows of size N
9918    define(interp, "windows", Some(2), |_, args| {
9919        let arr = match &args[0] {
9920            Value::Array(a) => a.borrow().clone(),
9921            _ => {
9922                return Err(RuntimeError::new(
9923                    "windows: first argument must be an array",
9924                ))
9925            }
9926        };
9927        let size = match &args[1] {
9928            Value::Int(n) if *n > 0 => *n as usize,
9929            _ => {
9930                return Err(RuntimeError::new(
9931                    "windows: second argument must be a positive integer",
9932                ))
9933            }
9934        };
9935
9936        if arr.len() < size {
9937            return Ok(Value::Array(Rc::new(RefCell::new(vec![]))));
9938        }
9939
9940        let windows: Vec<Value> = arr
9941            .windows(size)
9942            .map(|window| Value::Array(Rc::new(RefCell::new(window.to_vec()))))
9943            .collect();
9944
9945        Ok(Value::Array(Rc::new(RefCell::new(windows))))
9946    });
9947
9948    // scan - like fold but returns all intermediate values
9949    define(interp, "scan", Some(3), |interp, args| {
9950        let arr = match &args[0] {
9951            Value::Array(a) => a.borrow().clone(),
9952            _ => return Err(RuntimeError::new("scan: first argument must be an array")),
9953        };
9954        let init = args[1].clone();
9955        let func = match &args[2] {
9956            Value::Function(f) => f.clone(),
9957            _ => return Err(RuntimeError::new("scan: third argument must be a function")),
9958        };
9959
9960        let mut results = vec![init.clone()];
9961        let mut acc = init;
9962
9963        for item in arr {
9964            acc = interp.call_function(&func, vec![acc, item])?;
9965            results.push(acc.clone());
9966        }
9967
9968        Ok(Value::Array(Rc::new(RefCell::new(results))))
9969    });
9970
9971    // frequencies - count occurrences of each element
9972    define(interp, "frequencies", Some(1), |_, args| {
9973        let arr = match &args[0] {
9974            Value::Array(a) => a.borrow().clone(),
9975            _ => return Err(RuntimeError::new("frequencies: argument must be an array")),
9976        };
9977
9978        let mut counts: std::collections::HashMap<String, i64> = std::collections::HashMap::new();
9979        for item in &arr {
9980            let key = format!("{}", item);
9981            *counts.entry(key).or_insert(0) += 1;
9982        }
9983
9984        let result: std::collections::HashMap<String, Value> = counts
9985            .into_iter()
9986            .map(|(k, v)| (k, Value::Int(v)))
9987            .collect();
9988
9989        Ok(Value::Map(Rc::new(RefCell::new(result))))
9990    });
9991
9992    // dedupe - remove consecutive duplicates
9993    define(interp, "dedupe", Some(1), |_, args| {
9994        let arr = match &args[0] {
9995            Value::Array(a) => a.borrow().clone(),
9996            _ => return Err(RuntimeError::new("dedupe: argument must be an array")),
9997        };
9998
9999        let mut result = Vec::new();
10000        let mut prev: Option<Value> = None;
10001
10002        for item in arr {
10003            match &prev {
10004                Some(p) if value_eq(p, &item) => continue,
10005                _ => {
10006                    result.push(item.clone());
10007                    prev = Some(item);
10008                }
10009            }
10010        }
10011
10012        Ok(Value::Array(Rc::new(RefCell::new(result))))
10013    });
10014
10015    // unique - remove all duplicates (not just consecutive)
10016    define(interp, "unique", Some(1), |_, args| {
10017        let arr = match &args[0] {
10018            Value::Array(a) => a.borrow().clone(),
10019            _ => return Err(RuntimeError::new("unique: argument must be an array")),
10020        };
10021
10022        let mut seen = std::collections::HashSet::new();
10023        let mut result = Vec::new();
10024
10025        for item in arr {
10026            let key = format!("{}", item);
10027            if seen.insert(key) {
10028                result.push(item);
10029            }
10030        }
10031
10032        Ok(Value::Array(Rc::new(RefCell::new(result))))
10033    });
10034}
10035
10036/// Advanced range utilities
10037fn register_ranges(interp: &mut Interpreter) {
10038    // range_step - range with custom step
10039    define(interp, "range_step", Some(3), |_, args| {
10040        let start = match &args[0] {
10041            Value::Int(n) => *n,
10042            Value::Float(f) => *f as i64,
10043            _ => return Err(RuntimeError::new("range_step: start must be a number")),
10044        };
10045        let end = match &args[1] {
10046            Value::Int(n) => *n,
10047            Value::Float(f) => *f as i64,
10048            _ => return Err(RuntimeError::new("range_step: end must be a number")),
10049        };
10050        let step = match &args[2] {
10051            Value::Int(n) if *n != 0 => *n,
10052            Value::Float(f) if *f != 0.0 => *f as i64,
10053            _ => {
10054                return Err(RuntimeError::new(
10055                    "range_step: step must be a non-zero number",
10056                ))
10057            }
10058        };
10059
10060        let mut result = Vec::new();
10061        if step > 0 {
10062            let mut i = start;
10063            while i < end {
10064                result.push(Value::Int(i));
10065                i += step;
10066            }
10067        } else {
10068            let mut i = start;
10069            while i > end {
10070                result.push(Value::Int(i));
10071                i += step;
10072            }
10073        }
10074
10075        Ok(Value::Array(Rc::new(RefCell::new(result))))
10076    });
10077
10078    // linspace - N evenly spaced values from start to end (inclusive)
10079    define(interp, "linspace", Some(3), |_, args| {
10080        let start = match &args[0] {
10081            Value::Int(n) => *n as f64,
10082            Value::Float(f) => *f,
10083            _ => return Err(RuntimeError::new("linspace: start must be a number")),
10084        };
10085        let end = match &args[1] {
10086            Value::Int(n) => *n as f64,
10087            Value::Float(f) => *f,
10088            _ => return Err(RuntimeError::new("linspace: end must be a number")),
10089        };
10090        let n = match &args[2] {
10091            Value::Int(n) if *n > 0 => *n as usize,
10092            _ => {
10093                return Err(RuntimeError::new(
10094                    "linspace: count must be a positive integer",
10095                ))
10096            }
10097        };
10098
10099        if n == 1 {
10100            return Ok(Value::Array(Rc::new(RefCell::new(vec![Value::Float(
10101                start,
10102            )]))));
10103        }
10104
10105        let step = (end - start) / (n - 1) as f64;
10106        let result: Vec<Value> = (0..n)
10107            .map(|i| Value::Float(start + step * i as f64))
10108            .collect();
10109
10110        Ok(Value::Array(Rc::new(RefCell::new(result))))
10111    });
10112
10113    // logspace - N logarithmically spaced values
10114    define(interp, "logspace", Some(3), |_, args| {
10115        let start_exp = match &args[0] {
10116            Value::Int(n) => *n as f64,
10117            Value::Float(f) => *f,
10118            _ => {
10119                return Err(RuntimeError::new(
10120                    "logspace: start exponent must be a number",
10121                ))
10122            }
10123        };
10124        let end_exp = match &args[1] {
10125            Value::Int(n) => *n as f64,
10126            Value::Float(f) => *f,
10127            _ => return Err(RuntimeError::new("logspace: end exponent must be a number")),
10128        };
10129        let n = match &args[2] {
10130            Value::Int(n) if *n > 0 => *n as usize,
10131            _ => {
10132                return Err(RuntimeError::new(
10133                    "logspace: count must be a positive integer",
10134                ))
10135            }
10136        };
10137
10138        if n == 1 {
10139            return Ok(Value::Array(Rc::new(RefCell::new(vec![Value::Float(
10140                10f64.powf(start_exp),
10141            )]))));
10142        }
10143
10144        let step = (end_exp - start_exp) / (n - 1) as f64;
10145        let result: Vec<Value> = (0..n)
10146            .map(|i| Value::Float(10f64.powf(start_exp + step * i as f64)))
10147            .collect();
10148
10149        Ok(Value::Array(Rc::new(RefCell::new(result))))
10150    });
10151
10152    // arange - like numpy arange (start, stop, step with float support)
10153    define(interp, "arange", Some(3), |_, args| {
10154        let start = match &args[0] {
10155            Value::Int(n) => *n as f64,
10156            Value::Float(f) => *f,
10157            _ => return Err(RuntimeError::new("arange: start must be a number")),
10158        };
10159        let stop = match &args[1] {
10160            Value::Int(n) => *n as f64,
10161            Value::Float(f) => *f,
10162            _ => return Err(RuntimeError::new("arange: stop must be a number")),
10163        };
10164        let step = match &args[2] {
10165            Value::Int(n) if *n != 0 => *n as f64,
10166            Value::Float(f) if *f != 0.0 => *f,
10167            _ => return Err(RuntimeError::new("arange: step must be a non-zero number")),
10168        };
10169
10170        let mut result = Vec::new();
10171        if step > 0.0 {
10172            let mut x = start;
10173            while x < stop {
10174                result.push(Value::Float(x));
10175                x += step;
10176            }
10177        } else {
10178            let mut x = start;
10179            while x > stop {
10180                result.push(Value::Float(x));
10181                x += step;
10182            }
10183        }
10184
10185        Ok(Value::Array(Rc::new(RefCell::new(result))))
10186    });
10187
10188    // geomspace - geometrically spaced values (like logspace but using actual values)
10189    define(interp, "geomspace", Some(3), |_, args| {
10190        let start = match &args[0] {
10191            Value::Int(n) if *n > 0 => *n as f64,
10192            Value::Float(f) if *f > 0.0 => *f,
10193            _ => {
10194                return Err(RuntimeError::new(
10195                    "geomspace: start must be a positive number",
10196                ))
10197            }
10198        };
10199        let end = match &args[1] {
10200            Value::Int(n) if *n > 0 => *n as f64,
10201            Value::Float(f) if *f > 0.0 => *f,
10202            _ => {
10203                return Err(RuntimeError::new(
10204                    "geomspace: end must be a positive number",
10205                ))
10206            }
10207        };
10208        let n = match &args[2] {
10209            Value::Int(n) if *n > 0 => *n as usize,
10210            _ => {
10211                return Err(RuntimeError::new(
10212                    "geomspace: count must be a positive integer",
10213                ))
10214            }
10215        };
10216
10217        if n == 1 {
10218            return Ok(Value::Array(Rc::new(RefCell::new(vec![Value::Float(
10219                start,
10220            )]))));
10221        }
10222
10223        let ratio = (end / start).powf(1.0 / (n - 1) as f64);
10224        let result: Vec<Value> = (0..n)
10225            .map(|i| Value::Float(start * ratio.powi(i as i32)))
10226            .collect();
10227
10228        Ok(Value::Array(Rc::new(RefCell::new(result))))
10229    });
10230}
10231
10232/// Bitwise operations
10233fn register_bitwise(interp: &mut Interpreter) {
10234    define(interp, "bit_and", Some(2), |_, args| {
10235        let a = match &args[0] {
10236            Value::Int(n) => *n,
10237            _ => return Err(RuntimeError::new("bit_and: arguments must be integers")),
10238        };
10239        let b = match &args[1] {
10240            Value::Int(n) => *n,
10241            _ => return Err(RuntimeError::new("bit_and: arguments must be integers")),
10242        };
10243        Ok(Value::Int(a & b))
10244    });
10245
10246    define(interp, "bit_or", Some(2), |_, args| {
10247        let a = match &args[0] {
10248            Value::Int(n) => *n,
10249            _ => return Err(RuntimeError::new("bit_or: arguments must be integers")),
10250        };
10251        let b = match &args[1] {
10252            Value::Int(n) => *n,
10253            _ => return Err(RuntimeError::new("bit_or: arguments must be integers")),
10254        };
10255        Ok(Value::Int(a | b))
10256    });
10257
10258    define(interp, "bit_xor", Some(2), |_, args| {
10259        let a = match &args[0] {
10260            Value::Int(n) => *n,
10261            _ => return Err(RuntimeError::new("bit_xor: arguments must be integers")),
10262        };
10263        let b = match &args[1] {
10264            Value::Int(n) => *n,
10265            _ => return Err(RuntimeError::new("bit_xor: arguments must be integers")),
10266        };
10267        Ok(Value::Int(a ^ b))
10268    });
10269
10270    define(interp, "bit_not", Some(1), |_, args| {
10271        let a = match &args[0] {
10272            Value::Int(n) => *n,
10273            _ => return Err(RuntimeError::new("bit_not: argument must be an integer")),
10274        };
10275        Ok(Value::Int(!a))
10276    });
10277
10278    define(interp, "bit_shl", Some(2), |_, args| {
10279        let a = match &args[0] {
10280            Value::Int(n) => *n,
10281            _ => {
10282                return Err(RuntimeError::new(
10283                    "bit_shl: first argument must be an integer",
10284                ))
10285            }
10286        };
10287        let b = match &args[1] {
10288            Value::Int(n) if *n >= 0 && *n < 64 => *n as u32,
10289            _ => return Err(RuntimeError::new("bit_shl: shift amount must be 0-63")),
10290        };
10291        Ok(Value::Int(a << b))
10292    });
10293
10294    define(interp, "bit_shr", Some(2), |_, args| {
10295        let a = match &args[0] {
10296            Value::Int(n) => *n,
10297            _ => {
10298                return Err(RuntimeError::new(
10299                    "bit_shr: first argument must be an integer",
10300                ))
10301            }
10302        };
10303        let b = match &args[1] {
10304            Value::Int(n) if *n >= 0 && *n < 64 => *n as u32,
10305            _ => return Err(RuntimeError::new("bit_shr: shift amount must be 0-63")),
10306        };
10307        Ok(Value::Int(a >> b))
10308    });
10309
10310    define(interp, "popcount", Some(1), |_, args| {
10311        let a = match &args[0] {
10312            Value::Int(n) => *n,
10313            _ => return Err(RuntimeError::new("popcount: argument must be an integer")),
10314        };
10315        Ok(Value::Int(a.count_ones() as i64))
10316    });
10317
10318    define(interp, "leading_zeros", Some(1), |_, args| {
10319        let a = match &args[0] {
10320            Value::Int(n) => *n,
10321            _ => {
10322                return Err(RuntimeError::new(
10323                    "leading_zeros: argument must be an integer",
10324                ))
10325            }
10326        };
10327        Ok(Value::Int(a.leading_zeros() as i64))
10328    });
10329
10330    define(interp, "trailing_zeros", Some(1), |_, args| {
10331        let a = match &args[0] {
10332            Value::Int(n) => *n,
10333            _ => {
10334                return Err(RuntimeError::new(
10335                    "trailing_zeros: argument must be an integer",
10336                ))
10337            }
10338        };
10339        Ok(Value::Int(a.trailing_zeros() as i64))
10340    });
10341
10342    define(interp, "bit_test", Some(2), |_, args| {
10343        let a = match &args[0] {
10344            Value::Int(n) => *n,
10345            _ => {
10346                return Err(RuntimeError::new(
10347                    "bit_test: first argument must be an integer",
10348                ))
10349            }
10350        };
10351        let pos = match &args[1] {
10352            Value::Int(n) if *n >= 0 && *n < 64 => *n as u32,
10353            _ => return Err(RuntimeError::new("bit_test: position must be 0-63")),
10354        };
10355        Ok(Value::Bool((a >> pos) & 1 == 1))
10356    });
10357
10358    define(interp, "bit_set", Some(2), |_, args| {
10359        let a = match &args[0] {
10360            Value::Int(n) => *n,
10361            _ => {
10362                return Err(RuntimeError::new(
10363                    "bit_set: first argument must be an integer",
10364                ))
10365            }
10366        };
10367        let pos = match &args[1] {
10368            Value::Int(n) if *n >= 0 && *n < 64 => *n as u32,
10369            _ => return Err(RuntimeError::new("bit_set: position must be 0-63")),
10370        };
10371        Ok(Value::Int(a | (1 << pos)))
10372    });
10373
10374    define(interp, "bit_clear", Some(2), |_, args| {
10375        let a = match &args[0] {
10376            Value::Int(n) => *n,
10377            _ => {
10378                return Err(RuntimeError::new(
10379                    "bit_clear: first argument must be an integer",
10380                ))
10381            }
10382        };
10383        let pos = match &args[1] {
10384            Value::Int(n) if *n >= 0 && *n < 64 => *n as u32,
10385            _ => return Err(RuntimeError::new("bit_clear: position must be 0-63")),
10386        };
10387        Ok(Value::Int(a & !(1 << pos)))
10388    });
10389
10390    define(interp, "bit_toggle", Some(2), |_, args| {
10391        let a = match &args[0] {
10392            Value::Int(n) => *n,
10393            _ => {
10394                return Err(RuntimeError::new(
10395                    "bit_toggle: first argument must be an integer",
10396                ))
10397            }
10398        };
10399        let pos = match &args[1] {
10400            Value::Int(n) if *n >= 0 && *n < 64 => *n as u32,
10401            _ => return Err(RuntimeError::new("bit_toggle: position must be 0-63")),
10402        };
10403        Ok(Value::Int(a ^ (1 << pos)))
10404    });
10405
10406    define(interp, "to_binary", Some(1), |_, args| {
10407        let a = match &args[0] {
10408            Value::Int(n) => *n,
10409            _ => return Err(RuntimeError::new("to_binary: argument must be an integer")),
10410        };
10411        Ok(Value::String(Rc::new(format!("{:b}", a))))
10412    });
10413
10414    define(interp, "from_binary", Some(1), |_, args| {
10415        let s = match &args[0] {
10416            Value::String(s) => (**s).clone(),
10417            _ => return Err(RuntimeError::new("from_binary: argument must be a string")),
10418        };
10419        match i64::from_str_radix(&s, 2) {
10420            Ok(n) => Ok(Value::Int(n)),
10421            Err(_) => Err(RuntimeError::new("from_binary: invalid binary string")),
10422        }
10423    });
10424
10425    define(interp, "to_hex", Some(1), |_, args| {
10426        let a = match &args[0] {
10427            Value::Int(n) => *n,
10428            _ => return Err(RuntimeError::new("to_hex: argument must be an integer")),
10429        };
10430        Ok(Value::String(Rc::new(format!("{:x}", a))))
10431    });
10432
10433    define(interp, "from_hex", Some(1), |_, args| {
10434        let s = match &args[0] {
10435            Value::String(s) => s.trim_start_matches("0x").to_string(),
10436            _ => return Err(RuntimeError::new("from_hex: argument must be a string")),
10437        };
10438        match i64::from_str_radix(&s, 16) {
10439            Ok(n) => Ok(Value::Int(n)),
10440            Err(_) => Err(RuntimeError::new("from_hex: invalid hex string")),
10441        }
10442    });
10443
10444    define(interp, "to_octal", Some(1), |_, args| {
10445        let a = match &args[0] {
10446            Value::Int(n) => *n,
10447            _ => return Err(RuntimeError::new("to_octal: argument must be an integer")),
10448        };
10449        Ok(Value::String(Rc::new(format!("{:o}", a))))
10450    });
10451
10452    define(interp, "from_octal", Some(1), |_, args| {
10453        let s = match &args[0] {
10454            Value::String(s) => s.trim_start_matches("0o").to_string(),
10455            _ => return Err(RuntimeError::new("from_octal: argument must be a string")),
10456        };
10457        match i64::from_str_radix(&s, 8) {
10458            Ok(n) => Ok(Value::Int(n)),
10459            Err(_) => Err(RuntimeError::new("from_octal: invalid octal string")),
10460        }
10461    });
10462}
10463
10464/// String formatting utilities
10465fn register_format(interp: &mut Interpreter) {
10466    // format - basic string formatting with {} placeholders
10467    define(interp, "format", None, |_, args| {
10468        if args.is_empty() {
10469            return Err(RuntimeError::new(
10470                "format: requires at least a format string",
10471            ));
10472        }
10473        let template = match &args[0] {
10474            Value::String(s) => (**s).clone(),
10475            _ => return Err(RuntimeError::new("format: first argument must be a string")),
10476        };
10477        let mut result = template;
10478        for arg in &args[1..] {
10479            if let Some(pos) = result.find("{}") {
10480                result = format!("{}{}{}", &result[..pos], arg, &result[pos + 2..]);
10481            }
10482        }
10483        Ok(Value::String(Rc::new(result)))
10484    });
10485
10486    // pad_left - left-pad string to length with char (uses character count, not bytes)
10487    define(interp, "pad_left", Some(3), |_, args| {
10488        let s = match &args[0] {
10489            Value::String(s) => (**s).clone(),
10490            _ => {
10491                return Err(RuntimeError::new(
10492                    "pad_left: first argument must be a string",
10493                ))
10494            }
10495        };
10496        let width = match &args[1] {
10497            Value::Int(n) if *n >= 0 => *n as usize,
10498            _ => {
10499                return Err(RuntimeError::new(
10500                    "pad_left: width must be a non-negative integer",
10501                ))
10502            }
10503        };
10504        let pad_char = match &args[2] {
10505            Value::String(s) if !s.is_empty() => s.chars().next().unwrap(),
10506            Value::Char(c) => *c,
10507            _ => {
10508                return Err(RuntimeError::new(
10509                    "pad_left: pad character must be a non-empty string or char",
10510                ))
10511            }
10512        };
10513        let char_count = s.chars().count();
10514        if char_count >= width {
10515            return Ok(Value::String(Rc::new(s)));
10516        }
10517        let padding: String = std::iter::repeat(pad_char)
10518            .take(width - char_count)
10519            .collect();
10520        Ok(Value::String(Rc::new(format!("{}{}", padding, s))))
10521    });
10522
10523    // pad_right - right-pad string to length with char (uses character count, not bytes)
10524    define(interp, "pad_right", Some(3), |_, args| {
10525        let s = match &args[0] {
10526            Value::String(s) => (**s).clone(),
10527            _ => {
10528                return Err(RuntimeError::new(
10529                    "pad_right: first argument must be a string",
10530                ))
10531            }
10532        };
10533        let width = match &args[1] {
10534            Value::Int(n) if *n >= 0 => *n as usize,
10535            _ => {
10536                return Err(RuntimeError::new(
10537                    "pad_right: width must be a non-negative integer",
10538                ))
10539            }
10540        };
10541        let pad_char = match &args[2] {
10542            Value::String(s) if !s.is_empty() => s.chars().next().unwrap(),
10543            Value::Char(c) => *c,
10544            _ => {
10545                return Err(RuntimeError::new(
10546                    "pad_right: pad character must be a non-empty string or char",
10547                ))
10548            }
10549        };
10550        let char_count = s.chars().count();
10551        if char_count >= width {
10552            return Ok(Value::String(Rc::new(s)));
10553        }
10554        let padding: String = std::iter::repeat(pad_char)
10555            .take(width - char_count)
10556            .collect();
10557        Ok(Value::String(Rc::new(format!("{}{}", s, padding))))
10558    });
10559
10560    // center - center string with padding (uses character count, not bytes)
10561    define(interp, "center", Some(3), |_, args| {
10562        let s = match &args[0] {
10563            Value::String(s) => (**s).clone(),
10564            _ => return Err(RuntimeError::new("center: first argument must be a string")),
10565        };
10566        let width = match &args[1] {
10567            Value::Int(n) if *n >= 0 => *n as usize,
10568            _ => {
10569                return Err(RuntimeError::new(
10570                    "center: width must be a non-negative integer",
10571                ))
10572            }
10573        };
10574        let pad_char = match &args[2] {
10575            Value::String(s) if !s.is_empty() => s.chars().next().unwrap(),
10576            Value::Char(c) => *c,
10577            _ => {
10578                return Err(RuntimeError::new(
10579                    "center: pad character must be a non-empty string or char",
10580                ))
10581            }
10582        };
10583        let char_count = s.chars().count();
10584        if char_count >= width {
10585            return Ok(Value::String(Rc::new(s)));
10586        }
10587        let total_padding = width - char_count;
10588        let left_padding = total_padding / 2;
10589        let right_padding = total_padding - left_padding;
10590        let left: String = std::iter::repeat(pad_char).take(left_padding).collect();
10591        let right: String = std::iter::repeat(pad_char).take(right_padding).collect();
10592        Ok(Value::String(Rc::new(format!("{}{}{}", left, s, right))))
10593    });
10594
10595    // number_format - format number with thousand separators
10596    define(interp, "number_format", Some(1), |_, args| {
10597        let n = match &args[0] {
10598            Value::Int(n) => *n,
10599            Value::Float(f) => *f as i64,
10600            _ => {
10601                return Err(RuntimeError::new(
10602                    "number_format: argument must be a number",
10603                ))
10604            }
10605        };
10606        let s = n.abs().to_string();
10607        let mut result = String::new();
10608        for (i, c) in s.chars().rev().enumerate() {
10609            if i > 0 && i % 3 == 0 {
10610                result.push(',');
10611            }
10612            result.push(c);
10613        }
10614        let formatted: String = result.chars().rev().collect();
10615        if n < 0 {
10616            Ok(Value::String(Rc::new(format!("-{}", formatted))))
10617        } else {
10618            Ok(Value::String(Rc::new(formatted)))
10619        }
10620    });
10621
10622    // ordinal - convert number to ordinal string (1st, 2nd, 3rd, etc)
10623    define(interp, "ordinal", Some(1), |_, args| {
10624        let n = match &args[0] {
10625            Value::Int(n) => *n,
10626            _ => return Err(RuntimeError::new("ordinal: argument must be an integer")),
10627        };
10628        let suffix = match (n % 10, n % 100) {
10629            (1, 11) => "th",
10630            (2, 12) => "th",
10631            (3, 13) => "th",
10632            (1, _) => "st",
10633            (2, _) => "nd",
10634            (3, _) => "rd",
10635            _ => "th",
10636        };
10637        Ok(Value::String(Rc::new(format!("{}{}", n, suffix))))
10638    });
10639
10640    // pluralize - simple pluralization
10641    define(interp, "pluralize", Some(3), |_, args| {
10642        let count = match &args[0] {
10643            Value::Int(n) => *n,
10644            _ => {
10645                return Err(RuntimeError::new(
10646                    "pluralize: first argument must be an integer",
10647                ))
10648            }
10649        };
10650        let singular = match &args[1] {
10651            Value::String(s) => s.clone(),
10652            _ => {
10653                return Err(RuntimeError::new(
10654                    "pluralize: second argument must be a string",
10655                ))
10656            }
10657        };
10658        let plural = match &args[2] {
10659            Value::String(s) => s.clone(),
10660            _ => {
10661                return Err(RuntimeError::new(
10662                    "pluralize: third argument must be a string",
10663                ))
10664            }
10665        };
10666        if count == 1 || count == -1 {
10667            Ok(Value::String(singular))
10668        } else {
10669            Ok(Value::String(plural))
10670        }
10671    });
10672
10673    // truncate - truncate string with ellipsis (uses character count, not bytes)
10674    define(interp, "truncate", Some(2), |_, args| {
10675        let s = match &args[0] {
10676            Value::String(s) => (**s).clone(),
10677            _ => {
10678                return Err(RuntimeError::new(
10679                    "truncate: first argument must be a string",
10680                ))
10681            }
10682        };
10683        let max_len = match &args[1] {
10684            Value::Int(n) if *n >= 0 => *n as usize,
10685            _ => {
10686                return Err(RuntimeError::new(
10687                    "truncate: max length must be a non-negative integer",
10688                ))
10689            }
10690        };
10691        let char_count = s.chars().count();
10692        if char_count <= max_len {
10693            return Ok(Value::String(Rc::new(s)));
10694        }
10695        if max_len <= 3 {
10696            return Ok(Value::String(Rc::new(s.chars().take(max_len).collect())));
10697        }
10698        let truncated: String = s.chars().take(max_len - 3).collect();
10699        Ok(Value::String(Rc::new(format!("{}...", truncated))))
10700    });
10701
10702    // word_wrap - wrap text at specified width
10703    define(interp, "word_wrap", Some(2), |_, args| {
10704        let s = match &args[0] {
10705            Value::String(s) => (**s).clone(),
10706            _ => {
10707                return Err(RuntimeError::new(
10708                    "word_wrap: first argument must be a string",
10709                ))
10710            }
10711        };
10712        let width = match &args[1] {
10713            Value::Int(n) if *n > 0 => *n as usize,
10714            _ => {
10715                return Err(RuntimeError::new(
10716                    "word_wrap: width must be a positive integer",
10717                ))
10718            }
10719        };
10720        let mut result = String::new();
10721        let mut line_len = 0;
10722        for word in s.split_whitespace() {
10723            if line_len > 0 && line_len + 1 + word.len() > width {
10724                result.push('\n');
10725                line_len = 0;
10726            } else if line_len > 0 {
10727                result.push(' ');
10728                line_len += 1;
10729            }
10730            result.push_str(word);
10731            line_len += word.len();
10732        }
10733        Ok(Value::String(Rc::new(result)))
10734    });
10735
10736    // snake_case - convert string to snake_case
10737    define(interp, "snake_case", Some(1), |_, args| {
10738        let s = match &args[0] {
10739            Value::String(s) => (**s).clone(),
10740            _ => return Err(RuntimeError::new("snake_case: argument must be a string")),
10741        };
10742        let mut result = String::new();
10743        for (i, c) in s.chars().enumerate() {
10744            if c.is_uppercase() {
10745                if i > 0 {
10746                    result.push('_');
10747                }
10748                result.push(c.to_lowercase().next().unwrap());
10749            } else if c == ' ' || c == '-' {
10750                result.push('_');
10751            } else {
10752                result.push(c);
10753            }
10754        }
10755        Ok(Value::String(Rc::new(result)))
10756    });
10757
10758    // camel_case - convert string to camelCase
10759    define(interp, "camel_case", Some(1), |_, args| {
10760        let s = match &args[0] {
10761            Value::String(s) => (**s).clone(),
10762            _ => return Err(RuntimeError::new("camel_case: argument must be a string")),
10763        };
10764        let mut result = String::new();
10765        let mut capitalize_next = false;
10766        for (i, c) in s.chars().enumerate() {
10767            if c == '_' || c == '-' || c == ' ' {
10768                capitalize_next = true;
10769            } else if capitalize_next {
10770                result.push(c.to_uppercase().next().unwrap());
10771                capitalize_next = false;
10772            } else if i == 0 {
10773                result.push(c.to_lowercase().next().unwrap());
10774            } else {
10775                result.push(c);
10776            }
10777        }
10778        Ok(Value::String(Rc::new(result)))
10779    });
10780
10781    // kebab_case - convert string to kebab-case
10782    define(interp, "kebab_case", Some(1), |_, args| {
10783        let s = match &args[0] {
10784            Value::String(s) => (**s).clone(),
10785            _ => return Err(RuntimeError::new("kebab_case: argument must be a string")),
10786        };
10787        let mut result = String::new();
10788        for (i, c) in s.chars().enumerate() {
10789            if c.is_uppercase() {
10790                if i > 0 {
10791                    result.push('-');
10792                }
10793                result.push(c.to_lowercase().next().unwrap());
10794            } else if c == '_' || c == ' ' {
10795                result.push('-');
10796            } else {
10797                result.push(c);
10798            }
10799        }
10800        Ok(Value::String(Rc::new(result)))
10801    });
10802
10803    // title_case - convert string to Title Case
10804    define(interp, "title_case", Some(1), |_, args| {
10805        let s = match &args[0] {
10806            Value::String(s) => (**s).clone(),
10807            _ => return Err(RuntimeError::new("title_case: argument must be a string")),
10808        };
10809        let result: String = s
10810            .split_whitespace()
10811            .map(|word| {
10812                let mut chars = word.chars();
10813                match chars.next() {
10814                    None => String::new(),
10815                    Some(first) => {
10816                        first.to_uppercase().collect::<String>() + &chars.as_str().to_lowercase()
10817                    }
10818                }
10819            })
10820            .collect::<Vec<_>>()
10821            .join(" ");
10822        Ok(Value::String(Rc::new(result)))
10823    });
10824}
10825
10826// ============================================================================
10827// PATTERN MATCHING FUNCTIONS (Phase 6)
10828// ============================================================================
10829// Advanced pattern matching utilities for expressive data manipulation.
10830// These complement Sigil's match expressions with functional alternatives.
10831// ============================================================================
10832
10833fn register_pattern(interp: &mut Interpreter) {
10834    // --- TYPE MATCHING ---
10835
10836    // type_of - get the type name as a string
10837    define(interp, "type_of", Some(1), |_, args| {
10838        let type_name = match &args[0] {
10839            Value::Null => "null",
10840            Value::Bool(_) => "bool",
10841            Value::Int(_) => "int",
10842            Value::Float(_) => "float",
10843            Value::String(_) => "string",
10844            Value::Char(_) => "char",
10845            Value::Array(_) => "array",
10846            Value::Tuple(_) => "tuple",
10847            Value::Map(_) => "map",
10848            Value::Set(_) => "set",
10849            Value::Struct { name, .. } => {
10850                return Ok(Value::String(Rc::new(format!("struct:{}", name))))
10851            }
10852            Value::Variant {
10853                enum_name,
10854                variant_name,
10855                ..
10856            } => {
10857                return Ok(Value::String(Rc::new(format!(
10858                    "{}::{}",
10859                    enum_name, variant_name
10860                ))))
10861            }
10862            Value::Function(_) => "function",
10863            Value::BuiltIn(_) => "builtin",
10864            Value::Ref(_) => "ref",
10865            Value::Infinity => "infinity",
10866            Value::Empty => "empty",
10867            Value::Evidential { .. } => "evidential",
10868            Value::Affective { .. } => "affective",
10869            Value::Channel(_) => "channel",
10870            Value::ThreadHandle(_) => "thread",
10871            Value::Actor(_) => "actor",
10872            Value::Future(_) => "future",
10873            Value::VariantConstructor { .. } => "variant_constructor",
10874            Value::DefaultConstructor { .. } => "default_constructor",
10875            Value::Range { .. } => "range",
10876        };
10877        Ok(Value::String(Rc::new(type_name.to_string())))
10878    });
10879
10880    // is_type - check if value matches type name
10881    define(interp, "is_type", Some(2), |_, args| {
10882        let type_name = match &args[1] {
10883            Value::String(s) => s.to_lowercase(),
10884            _ => {
10885                return Err(RuntimeError::new(
10886                    "is_type: second argument must be type name string",
10887                ))
10888            }
10889        };
10890        let matches = match (&args[0], type_name.as_str()) {
10891            (Value::Null, "null") => true,
10892            (Value::Bool(_), "bool") => true,
10893            (Value::Int(_), "int") | (Value::Int(_), "integer") => true,
10894            (Value::Float(_), "float") | (Value::Float(_), "number") => true,
10895            (Value::Int(_), "number") => true,
10896            (Value::String(_), "string") => true,
10897            (Value::Array(_), "array") | (Value::Array(_), "list") => true,
10898            (Value::Tuple(_), "tuple") => true,
10899            (Value::Map(_), "map") | (Value::Map(_), "dict") | (Value::Map(_), "object") => true,
10900            (Value::Set(_), "set") => true,
10901            (Value::Function(_), "function") | (Value::Function(_), "fn") => true,
10902            (Value::BuiltIn(_), "function") | (Value::BuiltIn(_), "builtin") => true,
10903            (Value::Struct { name, .. }, t) => t == "struct" || t == &name.to_lowercase(),
10904            (Value::Variant { enum_name, .. }, t) => {
10905                t == "variant" || t == "enum" || t == &enum_name.to_lowercase()
10906            }
10907            (Value::Channel(_), "channel") => true,
10908            (Value::ThreadHandle(_), "thread") => true,
10909            (Value::Actor(_), "actor") => true,
10910            (Value::Future(_), "future") => true,
10911            _ => false,
10912        };
10913        Ok(Value::Bool(matches))
10914    });
10915
10916    // is_null, is_bool, is_int, is_float, is_string, is_array, is_map - type predicates
10917    define(interp, "is_null", Some(1), |_, args| {
10918        Ok(Value::Bool(matches!(&args[0], Value::Null)))
10919    });
10920    define(interp, "is_bool", Some(1), |_, args| {
10921        Ok(Value::Bool(matches!(&args[0], Value::Bool(_))))
10922    });
10923    define(interp, "is_int", Some(1), |_, args| {
10924        Ok(Value::Bool(matches!(&args[0], Value::Int(_))))
10925    });
10926    define(interp, "is_float", Some(1), |_, args| {
10927        Ok(Value::Bool(matches!(&args[0], Value::Float(_))))
10928    });
10929    define(interp, "is_number", Some(1), |_, args| {
10930        Ok(Value::Bool(matches!(
10931            &args[0],
10932            Value::Int(_) | Value::Float(_)
10933        )))
10934    });
10935    define(interp, "is_string", Some(1), |_, args| {
10936        Ok(Value::Bool(matches!(&args[0], Value::String(_))))
10937    });
10938    define(interp, "is_array", Some(1), |_, args| {
10939        Ok(Value::Bool(matches!(&args[0], Value::Array(_))))
10940    });
10941    define(interp, "is_tuple", Some(1), |_, args| {
10942        Ok(Value::Bool(matches!(&args[0], Value::Tuple(_))))
10943    });
10944    define(interp, "is_map", Some(1), |_, args| {
10945        Ok(Value::Bool(matches!(&args[0], Value::Map(_))))
10946    });
10947    define(interp, "is_set", Some(1), |_, args| {
10948        Ok(Value::Bool(matches!(&args[0], Value::Set(_))))
10949    });
10950    define(interp, "is_function", Some(1), |_, args| {
10951        Ok(Value::Bool(matches!(
10952            &args[0],
10953            Value::Function(_) | Value::BuiltIn(_)
10954        )))
10955    });
10956    define(interp, "is_struct", Some(1), |_, args| {
10957        Ok(Value::Bool(matches!(&args[0], Value::Struct { .. })))
10958    });
10959    define(interp, "is_variant", Some(1), |_, args| {
10960        Ok(Value::Bool(matches!(&args[0], Value::Variant { .. })))
10961    });
10962    define(interp, "is_future", Some(1), |_, args| {
10963        Ok(Value::Bool(matches!(&args[0], Value::Future(_))))
10964    });
10965    define(interp, "is_channel", Some(1), |_, args| {
10966        Ok(Value::Bool(matches!(&args[0], Value::Channel(_))))
10967    });
10968
10969    // is_empty - check if collection is empty
10970    define(interp, "is_empty", Some(1), |_, args| {
10971        let empty = match &args[0] {
10972            Value::Null => true,
10973            Value::String(s) => s.is_empty(),
10974            Value::Array(a) => a.borrow().is_empty(),
10975            Value::Tuple(t) => t.is_empty(),
10976            Value::Map(m) => m.borrow().is_empty(),
10977            Value::Set(s) => s.borrow().is_empty(),
10978            _ => false,
10979        };
10980        Ok(Value::Bool(empty))
10981    });
10982
10983    // --- REGEX PATTERN MATCHING ---
10984
10985    // match_regex - match string against regex, return captures or null
10986    define(interp, "match_regex", Some(2), |_, args| {
10987        let text = match &args[0] {
10988            Value::String(s) => (**s).clone(),
10989            _ => {
10990                return Err(RuntimeError::new(
10991                    "match_regex: first argument must be a string",
10992                ))
10993            }
10994        };
10995        let pattern = match &args[1] {
10996            Value::String(s) => (**s).clone(),
10997            _ => {
10998                return Err(RuntimeError::new(
10999                    "match_regex: second argument must be a regex pattern string",
11000                ))
11001            }
11002        };
11003
11004        let re = match Regex::new(&pattern) {
11005            Ok(r) => r,
11006            Err(e) => {
11007                return Err(RuntimeError::new(format!(
11008                    "match_regex: invalid regex: {}",
11009                    e
11010                )))
11011            }
11012        };
11013
11014        match re.captures(&text) {
11015            Some(caps) => {
11016                let mut captures: Vec<Value> = Vec::new();
11017                for i in 0..caps.len() {
11018                    if let Some(m) = caps.get(i) {
11019                        captures.push(Value::String(Rc::new(m.as_str().to_string())));
11020                    } else {
11021                        captures.push(Value::Null);
11022                    }
11023                }
11024                Ok(Value::Array(Rc::new(RefCell::new(captures))))
11025            }
11026            None => Ok(Value::Null),
11027        }
11028    });
11029
11030    // match_all_regex - find all matches of regex in string
11031    define(interp, "match_all_regex", Some(2), |_, args| {
11032        let text = match &args[0] {
11033            Value::String(s) => (**s).clone(),
11034            _ => {
11035                return Err(RuntimeError::new(
11036                    "match_all_regex: first argument must be a string",
11037                ))
11038            }
11039        };
11040        let pattern = match &args[1] {
11041            Value::String(s) => (**s).clone(),
11042            _ => {
11043                return Err(RuntimeError::new(
11044                    "match_all_regex: second argument must be a regex pattern string",
11045                ))
11046            }
11047        };
11048
11049        let re = match Regex::new(&pattern) {
11050            Ok(r) => r,
11051            Err(e) => {
11052                return Err(RuntimeError::new(format!(
11053                    "match_all_regex: invalid regex: {}",
11054                    e
11055                )))
11056            }
11057        };
11058
11059        let matches: Vec<Value> = re
11060            .find_iter(&text)
11061            .map(|m| Value::String(Rc::new(m.as_str().to_string())))
11062            .collect();
11063        Ok(Value::Array(Rc::new(RefCell::new(matches))))
11064    });
11065
11066    // capture_named - extract named captures from regex match
11067    define(interp, "capture_named", Some(2), |_, args| {
11068        let text = match &args[0] {
11069            Value::String(s) => (**s).clone(),
11070            _ => {
11071                return Err(RuntimeError::new(
11072                    "capture_named: first argument must be a string",
11073                ))
11074            }
11075        };
11076        let pattern = match &args[1] {
11077            Value::String(s) => (**s).clone(),
11078            _ => {
11079                return Err(RuntimeError::new(
11080                    "capture_named: second argument must be a regex pattern string",
11081                ))
11082            }
11083        };
11084
11085        let re = match Regex::new(&pattern) {
11086            Ok(r) => r,
11087            Err(e) => {
11088                return Err(RuntimeError::new(format!(
11089                    "capture_named: invalid regex: {}",
11090                    e
11091                )))
11092            }
11093        };
11094
11095        match re.captures(&text) {
11096            Some(caps) => {
11097                let mut result: HashMap<String, Value> = HashMap::new();
11098                for name in re.capture_names().flatten() {
11099                    if let Some(m) = caps.name(name) {
11100                        result.insert(
11101                            name.to_string(),
11102                            Value::String(Rc::new(m.as_str().to_string())),
11103                        );
11104                    }
11105                }
11106                Ok(Value::Map(Rc::new(RefCell::new(result))))
11107            }
11108            None => Ok(Value::Null),
11109        }
11110    });
11111
11112    // --- STRUCTURAL PATTERN MATCHING ---
11113
11114    // match_struct - check if value is a struct with given name
11115    define(interp, "match_struct", Some(2), |_, args| {
11116        let expected_name = match &args[1] {
11117            Value::String(s) => (**s).clone(),
11118            _ => {
11119                return Err(RuntimeError::new(
11120                    "match_struct: second argument must be struct name string",
11121                ))
11122            }
11123        };
11124        match &args[0] {
11125            Value::Struct { name, .. } => Ok(Value::Bool(name == &expected_name)),
11126            _ => Ok(Value::Bool(false)),
11127        }
11128    });
11129
11130    // match_variant - check if value is a variant with given enum and variant name
11131    define(interp, "match_variant", Some(3), |_, args| {
11132        let expected_enum = match &args[1] {
11133            Value::String(s) => (**s).clone(),
11134            _ => {
11135                return Err(RuntimeError::new(
11136                    "match_variant: second argument must be enum name string",
11137                ))
11138            }
11139        };
11140        let expected_variant = match &args[2] {
11141            Value::String(s) => (**s).clone(),
11142            _ => {
11143                return Err(RuntimeError::new(
11144                    "match_variant: third argument must be variant name string",
11145                ))
11146            }
11147        };
11148        match &args[0] {
11149            Value::Variant {
11150                enum_name,
11151                variant_name,
11152                ..
11153            } => Ok(Value::Bool(
11154                enum_name == &expected_enum && variant_name == &expected_variant,
11155            )),
11156            _ => Ok(Value::Bool(false)),
11157        }
11158    });
11159
11160    // get_field - get field from struct by name (returns null if not found)
11161    define(interp, "get_field", Some(2), |_, args| {
11162        let field_name = match &args[1] {
11163            Value::String(s) => (**s).clone(),
11164            _ => {
11165                return Err(RuntimeError::new(
11166                    "get_field: second argument must be field name string",
11167                ))
11168            }
11169        };
11170        match &args[0] {
11171            Value::Struct { fields, .. } => Ok(fields
11172                .borrow()
11173                .get(&field_name)
11174                .cloned()
11175                .unwrap_or(Value::Null)),
11176            Value::Map(m) => Ok(m.borrow().get(&field_name).cloned().unwrap_or(Value::Null)),
11177            _ => Ok(Value::Null),
11178        }
11179    });
11180
11181    // has_field - check if struct/map has a field
11182    define(interp, "has_field", Some(2), |_, args| {
11183        let field_name = match &args[1] {
11184            Value::String(s) => (**s).clone(),
11185            _ => {
11186                return Err(RuntimeError::new(
11187                    "has_field: second argument must be field name string",
11188                ))
11189            }
11190        };
11191        match &args[0] {
11192            Value::Struct { fields, .. } => {
11193                Ok(Value::Bool(fields.borrow().contains_key(&field_name)))
11194            }
11195            Value::Map(m) => Ok(Value::Bool(m.borrow().contains_key(&field_name))),
11196            _ => Ok(Value::Bool(false)),
11197        }
11198    });
11199
11200    // get_fields - get all field names from struct/map
11201    define(interp, "get_fields", Some(1), |_, args| {
11202        let fields: Vec<Value> = match &args[0] {
11203            Value::Struct { fields, .. } => fields
11204                .borrow()
11205                .keys()
11206                .map(|k| Value::String(Rc::new(k.clone())))
11207                .collect(),
11208            Value::Map(m) => m
11209                .borrow()
11210                .keys()
11211                .map(|k| Value::String(Rc::new(k.clone())))
11212                .collect(),
11213            _ => {
11214                return Err(RuntimeError::new(
11215                    "get_fields: argument must be struct or map",
11216                ))
11217            }
11218        };
11219        Ok(Value::Array(Rc::new(RefCell::new(fields))))
11220    });
11221
11222    // struct_name - get the name of a struct
11223    define(interp, "struct_name", Some(1), |_, args| match &args[0] {
11224        Value::Struct { name, .. } => Ok(Value::String(Rc::new(name.clone()))),
11225        _ => Ok(Value::Null),
11226    });
11227
11228    // variant_name - get the variant name of an enum value
11229    define(interp, "variant_name", Some(1), |_, args| match &args[0] {
11230        Value::Variant { variant_name, .. } => Ok(Value::String(Rc::new(variant_name.clone()))),
11231        _ => Ok(Value::Null),
11232    });
11233
11234    // variant_data - get the data payload of a variant
11235    define(interp, "variant_data", Some(1), |_, args| match &args[0] {
11236        Value::Variant { fields, .. } => match fields {
11237            Some(f) => Ok(Value::Array(Rc::new(RefCell::new((**f).clone())))),
11238            None => Ok(Value::Null),
11239        },
11240        _ => Ok(Value::Null),
11241    });
11242
11243    // --- GUARDS AND CONDITIONALS ---
11244
11245    // guard - conditionally return value or null (for pattern guard chains)
11246    define(interp, "guard", Some(2), |_, args| {
11247        if is_truthy(&args[0]) {
11248            Ok(args[1].clone())
11249        } else {
11250            Ok(Value::Null)
11251        }
11252    });
11253
11254    // when - like guard but evaluates a function if condition is true
11255    define(interp, "when", Some(2), |interp, args| {
11256        if is_truthy(&args[0]) {
11257            match &args[1] {
11258                Value::Function(f) => interp.call_function(f, vec![]),
11259                other => Ok(other.clone()),
11260            }
11261        } else {
11262            Ok(Value::Null)
11263        }
11264    });
11265
11266    // unless - opposite of when
11267    define(interp, "unless", Some(2), |interp, args| {
11268        if !is_truthy(&args[0]) {
11269            match &args[1] {
11270                Value::Function(f) => interp.call_function(f, vec![]),
11271                other => Ok(other.clone()),
11272            }
11273        } else {
11274            Ok(Value::Null)
11275        }
11276    });
11277
11278    // cond - evaluate conditions in order, return first matching result
11279    // cond([[cond1, val1], [cond2, val2], ...])
11280    define(interp, "cond", Some(1), |interp, args| {
11281        let clauses = match &args[0] {
11282            Value::Array(a) => a.borrow().clone(),
11283            _ => {
11284                return Err(RuntimeError::new(
11285                    "cond: argument must be array of [condition, value] pairs",
11286                ))
11287            }
11288        };
11289
11290        for clause in clauses {
11291            let pair = match &clause {
11292                Value::Array(a) => a.borrow().clone(),
11293                Value::Tuple(t) => (**t).clone(),
11294                _ => {
11295                    return Err(RuntimeError::new(
11296                        "cond: each clause must be [condition, value] pair",
11297                    ))
11298                }
11299            };
11300            if pair.len() != 2 {
11301                return Err(RuntimeError::new(
11302                    "cond: each clause must have exactly 2 elements",
11303                ));
11304            }
11305
11306            if is_truthy(&pair[0]) {
11307                return match &pair[1] {
11308                    Value::Function(f) => interp.call_function(f, vec![]),
11309                    other => Ok(other.clone()),
11310                };
11311            }
11312        }
11313        Ok(Value::Null)
11314    });
11315
11316    // case - match value against patterns, return matching result
11317    // case(val, [[pattern1, result1], [pattern2, result2], ...])
11318    define(interp, "case", Some(2), |interp, args| {
11319        let value = &args[0];
11320        let clauses = match &args[1] {
11321            Value::Array(a) => a.borrow().clone(),
11322            _ => {
11323                return Err(RuntimeError::new(
11324                    "case: second argument must be array of [pattern, result] pairs",
11325                ))
11326            }
11327        };
11328
11329        for clause in clauses {
11330            let pair = match &clause {
11331                Value::Array(a) => a.borrow().clone(),
11332                Value::Tuple(t) => (**t).clone(),
11333                _ => {
11334                    return Err(RuntimeError::new(
11335                        "case: each clause must be [pattern, result] pair",
11336                    ))
11337                }
11338            };
11339            if pair.len() != 2 {
11340                return Err(RuntimeError::new(
11341                    "case: each clause must have exactly 2 elements",
11342                ));
11343            }
11344
11345            if value_eq(value, &pair[0]) {
11346                return match &pair[1] {
11347                    Value::Function(f) => interp.call_function(f, vec![value.clone()]),
11348                    other => Ok(other.clone()),
11349                };
11350            }
11351        }
11352        Ok(Value::Null)
11353    });
11354
11355    // --- DESTRUCTURING ---
11356
11357    // destructure_array - extract elements at specified indices
11358    define(interp, "destructure_array", Some(2), |_, args| {
11359        let arr = match &args[0] {
11360            Value::Array(a) => a.borrow().clone(),
11361            Value::Tuple(t) => (**t).clone(),
11362            _ => {
11363                return Err(RuntimeError::new(
11364                    "destructure_array: first argument must be array or tuple",
11365                ))
11366            }
11367        };
11368        let indices = match &args[1] {
11369            Value::Array(a) => a.borrow().clone(),
11370            _ => {
11371                return Err(RuntimeError::new(
11372                    "destructure_array: second argument must be array of indices",
11373                ))
11374            }
11375        };
11376
11377        let mut result = Vec::new();
11378        for idx in indices {
11379            match idx {
11380                Value::Int(i) => {
11381                    let i = if i < 0 { arr.len() as i64 + i } else { i } as usize;
11382                    result.push(arr.get(i).cloned().unwrap_or(Value::Null));
11383                }
11384                _ => result.push(Value::Null),
11385            }
11386        }
11387        Ok(Value::Array(Rc::new(RefCell::new(result))))
11388    });
11389
11390    // destructure_map - extract values for specified keys
11391    define(interp, "destructure_map", Some(2), |_, args| {
11392        let map = match &args[0] {
11393            Value::Map(m) => m.borrow().clone(),
11394            Value::Struct { fields, .. } => fields.borrow().clone(),
11395            _ => {
11396                return Err(RuntimeError::new(
11397                    "destructure_map: first argument must be map or struct",
11398                ))
11399            }
11400        };
11401        let keys = match &args[1] {
11402            Value::Array(a) => a.borrow().clone(),
11403            _ => {
11404                return Err(RuntimeError::new(
11405                    "destructure_map: second argument must be array of keys",
11406                ))
11407            }
11408        };
11409
11410        let mut result = Vec::new();
11411        for key in keys {
11412            match key {
11413                Value::String(k) => {
11414                    result.push(map.get(&*k).cloned().unwrap_or(Value::Null));
11415                }
11416                _ => result.push(Value::Null),
11417            }
11418        }
11419        Ok(Value::Array(Rc::new(RefCell::new(result))))
11420    });
11421
11422    // head_tail - split array into [head, tail]
11423    define(interp, "head_tail", Some(1), |_, args| {
11424        let arr = match &args[0] {
11425            Value::Array(a) => a.borrow().clone(),
11426            _ => return Err(RuntimeError::new("head_tail: argument must be array")),
11427        };
11428
11429        if arr.is_empty() {
11430            Ok(Value::Tuple(Rc::new(vec![
11431                Value::Null,
11432                Value::Array(Rc::new(RefCell::new(vec![]))),
11433            ])))
11434        } else {
11435            let head = arr[0].clone();
11436            let tail = arr[1..].to_vec();
11437            Ok(Value::Tuple(Rc::new(vec![
11438                head,
11439                Value::Array(Rc::new(RefCell::new(tail))),
11440            ])))
11441        }
11442    });
11443
11444    // init_last - split array into [init, last]
11445    define(interp, "init_last", Some(1), |_, args| {
11446        let arr = match &args[0] {
11447            Value::Array(a) => a.borrow().clone(),
11448            _ => return Err(RuntimeError::new("init_last: argument must be array")),
11449        };
11450
11451        if arr.is_empty() {
11452            Ok(Value::Tuple(Rc::new(vec![
11453                Value::Array(Rc::new(RefCell::new(vec![]))),
11454                Value::Null,
11455            ])))
11456        } else {
11457            let last = arr[arr.len() - 1].clone();
11458            let init = arr[..arr.len() - 1].to_vec();
11459            Ok(Value::Tuple(Rc::new(vec![
11460                Value::Array(Rc::new(RefCell::new(init))),
11461                last,
11462            ])))
11463        }
11464    });
11465
11466    // split_at - split array at index into [left, right]
11467    define(interp, "split_at", Some(2), |_, args| {
11468        let arr = match &args[0] {
11469            Value::Array(a) => a.borrow().clone(),
11470            _ => return Err(RuntimeError::new("split_at: first argument must be array")),
11471        };
11472        let idx = match &args[1] {
11473            Value::Int(i) => *i as usize,
11474            _ => {
11475                return Err(RuntimeError::new(
11476                    "split_at: second argument must be integer",
11477                ))
11478            }
11479        };
11480
11481        let idx = idx.min(arr.len());
11482        let left = arr[..idx].to_vec();
11483        let right = arr[idx..].to_vec();
11484        Ok(Value::Tuple(Rc::new(vec![
11485            Value::Array(Rc::new(RefCell::new(left))),
11486            Value::Array(Rc::new(RefCell::new(right))),
11487        ])))
11488    });
11489
11490    // --- OPTIONAL/NULLABLE HELPERS ---
11491
11492    // unwrap_or - return value if not null, else default
11493    define(interp, "unwrap_or", Some(2), |_, args| {
11494        if matches!(&args[0], Value::Null) {
11495            Ok(args[1].clone())
11496        } else {
11497            Ok(args[0].clone())
11498        }
11499    });
11500
11501    // unwrap_or_else - return value if not null, else call function
11502    define(interp, "unwrap_or_else", Some(2), |interp, args| {
11503        if matches!(&args[0], Value::Null) {
11504            match &args[1] {
11505                Value::Function(f) => interp.call_function(f, vec![]),
11506                other => Ok(other.clone()),
11507            }
11508        } else {
11509            Ok(args[0].clone())
11510        }
11511    });
11512
11513    // map_or - if value is not null, apply function, else return default
11514    define(interp, "map_or", Some(3), |interp, args| {
11515        if matches!(&args[0], Value::Null) {
11516            Ok(args[1].clone())
11517        } else {
11518            match &args[2] {
11519                Value::Function(f) => interp.call_function(f, vec![args[0].clone()]),
11520                _ => Err(RuntimeError::new(
11521                    "map_or: third argument must be a function",
11522                )),
11523            }
11524        }
11525    });
11526
11527    // coalesce - return first non-null value from array
11528    define(interp, "coalesce", Some(1), |_, args| {
11529        let values = match &args[0] {
11530            Value::Array(a) => a.borrow().clone(),
11531            _ => return Err(RuntimeError::new("coalesce: argument must be array")),
11532        };
11533
11534        for v in values {
11535            if !matches!(v, Value::Null) {
11536                return Ok(v);
11537            }
11538        }
11539        Ok(Value::Null)
11540    });
11541
11542    // --- EQUALITY AND COMPARISON ---
11543
11544    // deep_eq - deep structural equality check
11545    define(interp, "deep_eq", Some(2), |_, args| {
11546        Ok(Value::Bool(deep_value_eq(&args[0], &args[1])))
11547    });
11548
11549    // same_type - check if two values have the same type
11550    define(interp, "same_type", Some(2), |_, args| {
11551        let same = match (&args[0], &args[1]) {
11552            (Value::Null, Value::Null) => true,
11553            (Value::Bool(_), Value::Bool(_)) => true,
11554            (Value::Int(_), Value::Int(_)) => true,
11555            (Value::Float(_), Value::Float(_)) => true,
11556            (Value::String(_), Value::String(_)) => true,
11557            (Value::Array(_), Value::Array(_)) => true,
11558            (Value::Tuple(_), Value::Tuple(_)) => true,
11559            (Value::Map(_), Value::Map(_)) => true,
11560            (Value::Set(_), Value::Set(_)) => true,
11561            (Value::Function(_), Value::Function(_)) => true,
11562            (Value::BuiltIn(_), Value::BuiltIn(_)) => true,
11563            (Value::Struct { name: n1, .. }, Value::Struct { name: n2, .. }) => n1 == n2,
11564            (Value::Variant { enum_name: e1, .. }, Value::Variant { enum_name: e2, .. }) => {
11565                e1 == e2
11566            }
11567            _ => false,
11568        };
11569        Ok(Value::Bool(same))
11570    });
11571
11572    // compare - three-way comparison: -1, 0, or 1
11573    define(interp, "compare", Some(2), |_, args| {
11574        let cmp = match (&args[0], &args[1]) {
11575            (Value::Int(a), Value::Int(b)) => a.cmp(b),
11576            (Value::Float(a), Value::Float(b)) => {
11577                a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal)
11578            }
11579            (Value::Int(a), Value::Float(b)) => (*a as f64)
11580                .partial_cmp(b)
11581                .unwrap_or(std::cmp::Ordering::Equal),
11582            (Value::Float(a), Value::Int(b)) => a
11583                .partial_cmp(&(*b as f64))
11584                .unwrap_or(std::cmp::Ordering::Equal),
11585            (Value::String(a), Value::String(b)) => a.cmp(b),
11586            _ => {
11587                return Err(RuntimeError::new(
11588                    "compare: can only compare numbers or strings",
11589                ))
11590            }
11591        };
11592        Ok(Value::Int(match cmp {
11593            std::cmp::Ordering::Less => -1,
11594            std::cmp::Ordering::Equal => 0,
11595            std::cmp::Ordering::Greater => 1,
11596        }))
11597    });
11598
11599    // between - check if value is between min and max (inclusive)
11600    define(interp, "between", Some(3), |_, args| {
11601        let in_range = match (&args[0], &args[1], &args[2]) {
11602            (Value::Int(v), Value::Int(min), Value::Int(max)) => v >= min && v <= max,
11603            (Value::Float(v), Value::Float(min), Value::Float(max)) => v >= min && v <= max,
11604            (Value::Int(v), Value::Int(min), Value::Float(max)) => {
11605                (*v as f64) >= (*min as f64) && (*v as f64) <= *max
11606            }
11607            (Value::Int(v), Value::Float(min), Value::Int(max)) => {
11608                (*v as f64) >= *min && (*v as f64) <= (*max as f64)
11609            }
11610            (Value::Float(v), Value::Int(min), Value::Int(max)) => {
11611                *v >= (*min as f64) && *v <= (*max as f64)
11612            }
11613            (Value::String(v), Value::String(min), Value::String(max)) => v >= min && v <= max,
11614            _ => {
11615                return Err(RuntimeError::new(
11616                    "between: arguments must be comparable (numbers or strings)",
11617                ))
11618            }
11619        };
11620        Ok(Value::Bool(in_range))
11621    });
11622
11623    // clamp - constrain value to range
11624    define(interp, "clamp", Some(3), |_, args| {
11625        match (&args[0], &args[1], &args[2]) {
11626            (Value::Int(v), Value::Int(min), Value::Int(max)) => {
11627                Ok(Value::Int((*v).max(*min).min(*max)))
11628            }
11629            (Value::Float(v), Value::Float(min), Value::Float(max)) => {
11630                Ok(Value::Float(v.max(*min).min(*max)))
11631            }
11632            (Value::Int(v), Value::Int(min), Value::Float(max)) => {
11633                Ok(Value::Float((*v as f64).max(*min as f64).min(*max)))
11634            }
11635            _ => Err(RuntimeError::new("clamp: arguments must be numbers")),
11636        }
11637    });
11638}
11639
11640// Deep value equality for nested structures
11641fn deep_value_eq(a: &Value, b: &Value) -> bool {
11642    match (a, b) {
11643        (Value::Null, Value::Null) => true,
11644        (Value::Bool(a), Value::Bool(b)) => a == b,
11645        (Value::Int(a), Value::Int(b)) => a == b,
11646        (Value::Float(a), Value::Float(b)) => (a - b).abs() < f64::EPSILON,
11647        (Value::Int(a), Value::Float(b)) | (Value::Float(b), Value::Int(a)) => {
11648            (*a as f64 - b).abs() < f64::EPSILON
11649        }
11650        (Value::String(a), Value::String(b)) => a == b,
11651        (Value::Array(a), Value::Array(b)) => {
11652            let a = a.borrow();
11653            let b = b.borrow();
11654            a.len() == b.len() && a.iter().zip(b.iter()).all(|(x, y)| deep_value_eq(x, y))
11655        }
11656        (Value::Tuple(a), Value::Tuple(b)) => {
11657            a.len() == b.len() && a.iter().zip(b.iter()).all(|(x, y)| deep_value_eq(x, y))
11658        }
11659        (Value::Map(a), Value::Map(b)) => {
11660            let a = a.borrow();
11661            let b = b.borrow();
11662            a.len() == b.len()
11663                && a.iter()
11664                    .all(|(k, v)| b.get(k).map_or(false, |bv| deep_value_eq(v, bv)))
11665        }
11666        (Value::Set(a), Value::Set(b)) => {
11667            let a = a.borrow();
11668            let b = b.borrow();
11669            a.len() == b.len() && a.iter().all(|k| b.contains(k))
11670        }
11671        (
11672            Value::Struct {
11673                name: n1,
11674                fields: f1,
11675            },
11676            Value::Struct {
11677                name: n2,
11678                fields: f2,
11679            },
11680        ) => {
11681            let f1 = f1.borrow();
11682            let f2 = f2.borrow();
11683            n1 == n2
11684                && f1.len() == f2.len()
11685                && f1
11686                    .iter()
11687                    .all(|(k, v)| f2.get(k).map_or(false, |v2| deep_value_eq(v, v2)))
11688        }
11689        (
11690            Value::Variant {
11691                enum_name: e1,
11692                variant_name: v1,
11693                fields: d1,
11694            },
11695            Value::Variant {
11696                enum_name: e2,
11697                variant_name: v2,
11698                fields: d2,
11699            },
11700        ) => {
11701            if e1 != e2 || v1 != v2 {
11702                return false;
11703            }
11704            match (d1, d2) {
11705                (Some(f1), Some(f2)) => {
11706                    f1.len() == f2.len()
11707                        && f1.iter().zip(f2.iter()).all(|(x, y)| deep_value_eq(x, y))
11708                }
11709                (None, None) => true,
11710                _ => false,
11711            }
11712        }
11713        _ => false,
11714    }
11715}
11716
11717// Helper for value equality comparison
11718fn value_eq(a: &Value, b: &Value) -> bool {
11719    match (a, b) {
11720        (Value::Null, Value::Null) => true,
11721        (Value::Bool(a), Value::Bool(b)) => a == b,
11722        (Value::Int(a), Value::Int(b)) => a == b,
11723        (Value::Float(a), Value::Float(b)) => (a - b).abs() < f64::EPSILON,
11724        (Value::String(a), Value::String(b)) => a == b,
11725        (Value::Int(a), Value::Float(b)) | (Value::Float(b), Value::Int(a)) => {
11726            (*a as f64 - b).abs() < f64::EPSILON
11727        }
11728        _ => false,
11729    }
11730}
11731
11732// ============================================================================
11733// DEVEX FUNCTIONS (Phase 7)
11734// ============================================================================
11735// Developer experience enhancements: debugging, assertions, profiling,
11736// documentation, and introspection utilities.
11737// ============================================================================
11738
11739fn register_devex(interp: &mut Interpreter) {
11740    // --- DEBUGGING AND INTROSPECTION ---
11741
11742    // debug - print value with type info for debugging
11743    define(interp, "debug", Some(1), |_, args| {
11744        let type_name = match &args[0] {
11745            Value::Null => "null".to_string(),
11746            Value::Bool(_) => "bool".to_string(),
11747            Value::Int(_) => "int".to_string(),
11748            Value::Float(_) => "float".to_string(),
11749            Value::String(_) => "string".to_string(),
11750            Value::Char(_) => "char".to_string(),
11751            Value::Array(a) => format!("array[{}]", a.borrow().len()),
11752            Value::Tuple(t) => format!("tuple[{}]", t.len()),
11753            Value::Map(m) => format!("map[{}]", m.borrow().len()),
11754            Value::Set(s) => format!("set[{}]", s.borrow().len()),
11755            Value::Struct { name, fields } => format!("struct {}[{}]", name, fields.borrow().len()),
11756            Value::Variant {
11757                enum_name,
11758                variant_name,
11759                ..
11760            } => format!("{}::{}", enum_name, variant_name),
11761            Value::Function(_) => "function".to_string(),
11762            Value::BuiltIn(_) => "builtin".to_string(),
11763            Value::Ref(_) => "ref".to_string(),
11764            Value::Infinity => "infinity".to_string(),
11765            Value::Empty => "empty".to_string(),
11766            Value::Evidential { evidence, .. } => format!("evidential[{:?}]", evidence),
11767            Value::Affective { affect, .. } => format!("affective[sarcasm={}]", affect.sarcasm),
11768            Value::Channel(_) => "channel".to_string(),
11769            Value::ThreadHandle(_) => "thread".to_string(),
11770            Value::Actor(_) => "actor".to_string(),
11771            Value::Future(_) => "future".to_string(),
11772            Value::VariantConstructor { enum_name, variant_name } => {
11773                format!("<constructor {}::{}>", enum_name, variant_name)
11774            }
11775            Value::DefaultConstructor { type_name } => {
11776                format!("<default {}>", type_name)
11777            }
11778            Value::Range { start, end, inclusive } => {
11779                match (start, end) {
11780                    (Some(s), Some(e)) => if *inclusive {
11781                        format!("range({}..={})", s, e)
11782                    } else {
11783                        format!("range({}..{})", s, e)
11784                    },
11785                    (Some(s), None) => format!("range({}..)", s),
11786                    (None, Some(e)) => if *inclusive {
11787                        format!("range(..={})", e)
11788                    } else {
11789                        format!("range(..{})", e)
11790                    },
11791                    (None, None) => "range(..)".to_string(),
11792                }
11793            }
11794        };
11795        let value_repr = format_value_debug(&args[0]);
11796        println!("[DEBUG] {}: {}", type_name, value_repr);
11797        Ok(args[0].clone())
11798    });
11799
11800    // inspect - return detailed string representation of value
11801    define(interp, "inspect", Some(1), |_, args| {
11802        Ok(Value::String(Rc::new(format_value_debug(&args[0]))))
11803    });
11804
11805    // dbg - print and return value (tap for debugging)
11806    define(interp, "dbg", Some(1), |_, args| {
11807        println!("{}", format_value_debug(&args[0]));
11808        Ok(args[0].clone())
11809    });
11810
11811    // trace - print message and value, return value
11812    define(interp, "trace", Some(2), |_, args| {
11813        let label = match &args[0] {
11814            Value::String(s) => (**s).clone(),
11815            _ => format_value_debug(&args[0]),
11816        };
11817        println!("[TRACE] {}: {}", label, format_value_debug(&args[1]));
11818        Ok(args[1].clone())
11819    });
11820
11821    // pp - pretty print with indentation
11822    define(interp, "pp", Some(1), |_, args| {
11823        println!("{}", pretty_print_value(&args[0], 0));
11824        Ok(Value::Null)
11825    });
11826
11827    // --- RICH ASSERTIONS ---
11828
11829    // assert_eq - assert two values are equal
11830    define(interp, "assert_eq", Some(2), |_, args| {
11831        if deep_value_eq(&args[0], &args[1]) {
11832            Ok(Value::Bool(true))
11833        } else {
11834            Err(RuntimeError::new(format!(
11835                "Assertion failed: expected {} to equal {}",
11836                format_value_debug(&args[0]),
11837                format_value_debug(&args[1])
11838            )))
11839        }
11840    });
11841
11842    // assert_ne - assert two values are not equal
11843    define(interp, "assert_ne", Some(2), |_, args| {
11844        if !deep_value_eq(&args[0], &args[1]) {
11845            Ok(Value::Bool(true))
11846        } else {
11847            Err(RuntimeError::new(format!(
11848                "Assertion failed: expected {} to not equal {}",
11849                format_value_debug(&args[0]),
11850                format_value_debug(&args[1])
11851            )))
11852        }
11853    });
11854
11855    // assert_lt - assert first value is less than second
11856    define(interp, "assert_lt", Some(2), |_, args| {
11857        let cmp = devex_compare(&args[0], &args[1])?;
11858        if cmp < 0 {
11859            Ok(Value::Bool(true))
11860        } else {
11861            Err(RuntimeError::new(format!(
11862                "Assertion failed: expected {} < {}",
11863                format_value_debug(&args[0]),
11864                format_value_debug(&args[1])
11865            )))
11866        }
11867    });
11868
11869    // assert_le - assert first value is less than or equal to second
11870    define(interp, "assert_le", Some(2), |_, args| {
11871        let cmp = devex_compare(&args[0], &args[1])?;
11872        if cmp <= 0 {
11873            Ok(Value::Bool(true))
11874        } else {
11875            Err(RuntimeError::new(format!(
11876                "Assertion failed: expected {} <= {}",
11877                format_value_debug(&args[0]),
11878                format_value_debug(&args[1])
11879            )))
11880        }
11881    });
11882
11883    // assert_gt - assert first value is greater than second
11884    define(interp, "assert_gt", Some(2), |_, args| {
11885        let cmp = devex_compare(&args[0], &args[1])?;
11886        if cmp > 0 {
11887            Ok(Value::Bool(true))
11888        } else {
11889            Err(RuntimeError::new(format!(
11890                "Assertion failed: expected {} > {}",
11891                format_value_debug(&args[0]),
11892                format_value_debug(&args[1])
11893            )))
11894        }
11895    });
11896
11897    // assert_ge - assert first value is greater than or equal to second
11898    define(interp, "assert_ge", Some(2), |_, args| {
11899        let cmp = devex_compare(&args[0], &args[1])?;
11900        if cmp >= 0 {
11901            Ok(Value::Bool(true))
11902        } else {
11903            Err(RuntimeError::new(format!(
11904                "Assertion failed: expected {} >= {}",
11905                format_value_debug(&args[0]),
11906                format_value_debug(&args[1])
11907            )))
11908        }
11909    });
11910
11911    // assert_true - assert value is truthy
11912    define(interp, "assert_true", Some(1), |_, args| {
11913        if is_truthy(&args[0]) {
11914            Ok(Value::Bool(true))
11915        } else {
11916            Err(RuntimeError::new(format!(
11917                "Assertion failed: expected {} to be truthy",
11918                format_value_debug(&args[0])
11919            )))
11920        }
11921    });
11922
11923    // assert_false - assert value is falsy
11924    define(interp, "assert_false", Some(1), |_, args| {
11925        if !is_truthy(&args[0]) {
11926            Ok(Value::Bool(true))
11927        } else {
11928            Err(RuntimeError::new(format!(
11929                "Assertion failed: expected {} to be falsy",
11930                format_value_debug(&args[0])
11931            )))
11932        }
11933    });
11934
11935    // assert_null - assert value is null
11936    define(interp, "assert_null", Some(1), |_, args| {
11937        if matches!(&args[0], Value::Null) {
11938            Ok(Value::Bool(true))
11939        } else {
11940            Err(RuntimeError::new(format!(
11941                "Assertion failed: expected null, got {}",
11942                format_value_debug(&args[0])
11943            )))
11944        }
11945    });
11946
11947    // assert_not_null - assert value is not null
11948    define(interp, "assert_not_null", Some(1), |_, args| {
11949        if !matches!(&args[0], Value::Null) {
11950            Ok(Value::Bool(true))
11951        } else {
11952            Err(RuntimeError::new(
11953                "Assertion failed: expected non-null value, got null",
11954            ))
11955        }
11956    });
11957
11958    // assert_type - assert value has expected type
11959    define(interp, "assert_type", Some(2), |_, args| {
11960        let expected = match &args[1] {
11961            Value::String(s) => s.to_lowercase(),
11962            _ => {
11963                return Err(RuntimeError::new(
11964                    "assert_type: second argument must be type name string",
11965                ))
11966            }
11967        };
11968        let actual = get_type_name(&args[0]).to_lowercase();
11969        if actual == expected || matches_type_alias(&args[0], &expected) {
11970            Ok(Value::Bool(true))
11971        } else {
11972            Err(RuntimeError::new(format!(
11973                "Assertion failed: expected type '{}', got '{}'",
11974                expected, actual
11975            )))
11976        }
11977    });
11978
11979    // assert_contains - assert collection contains value
11980    define(interp, "assert_contains", Some(2), |_, args| {
11981        let contains = match &args[0] {
11982            Value::Array(a) => a.borrow().iter().any(|v| deep_value_eq(v, &args[1])),
11983            Value::String(s) => {
11984                if let Value::String(sub) = &args[1] {
11985                    s.contains(&**sub)
11986                } else {
11987                    false
11988                }
11989            }
11990            Value::Map(m) => {
11991                if let Value::String(k) = &args[1] {
11992                    m.borrow().contains_key(&**k)
11993                } else {
11994                    false
11995                }
11996            }
11997            Value::Set(s) => {
11998                if let Value::String(k) = &args[1] {
11999                    s.borrow().contains(&**k)
12000                } else {
12001                    false
12002                }
12003            }
12004            _ => false,
12005        };
12006        if contains {
12007            Ok(Value::Bool(true))
12008        } else {
12009            Err(RuntimeError::new(format!(
12010                "Assertion failed: {} does not contain {}",
12011                format_value_debug(&args[0]),
12012                format_value_debug(&args[1])
12013            )))
12014        }
12015    });
12016
12017    // assert_len - assert collection has expected length
12018    define(interp, "assert_len", Some(2), |_, args| {
12019        let expected = match &args[1] {
12020            Value::Int(n) => *n as usize,
12021            _ => {
12022                return Err(RuntimeError::new(
12023                    "assert_len: second argument must be integer",
12024                ))
12025            }
12026        };
12027        let actual = match &args[0] {
12028            Value::String(s) => s.len(),
12029            Value::Array(a) => a.borrow().len(),
12030            Value::Tuple(t) => t.len(),
12031            Value::Map(m) => m.borrow().len(),
12032            Value::Set(s) => s.borrow().len(),
12033            _ => {
12034                return Err(RuntimeError::new(
12035                    "assert_len: first argument must be a collection",
12036                ))
12037            }
12038        };
12039        if actual == expected {
12040            Ok(Value::Bool(true))
12041        } else {
12042            Err(RuntimeError::new(format!(
12043                "Assertion failed: expected length {}, got {}",
12044                expected, actual
12045            )))
12046        }
12047    });
12048
12049    // assert_match - assert string matches regex
12050    define(interp, "assert_match", Some(2), |_, args| {
12051        let text = match &args[0] {
12052            Value::String(s) => (**s).clone(),
12053            _ => {
12054                return Err(RuntimeError::new(
12055                    "assert_match: first argument must be string",
12056                ))
12057            }
12058        };
12059        let pattern = match &args[1] {
12060            Value::String(s) => (**s).clone(),
12061            _ => {
12062                return Err(RuntimeError::new(
12063                    "assert_match: second argument must be regex pattern",
12064                ))
12065            }
12066        };
12067        let re =
12068            Regex::new(&pattern).map_err(|e| RuntimeError::new(format!("Invalid regex: {}", e)))?;
12069        if re.is_match(&text) {
12070            Ok(Value::Bool(true))
12071        } else {
12072            Err(RuntimeError::new(format!(
12073                "Assertion failed: '{}' does not match pattern '{}'",
12074                text, pattern
12075            )))
12076        }
12077    });
12078
12079    // --- TESTING UTILITIES ---
12080
12081    // test - run a test function and report result
12082    define(interp, "test", Some(2), |interp, args| {
12083        let name = match &args[0] {
12084            Value::String(s) => (**s).clone(),
12085            _ => {
12086                return Err(RuntimeError::new(
12087                    "test: first argument must be test name string",
12088                ))
12089            }
12090        };
12091        let func = match &args[1] {
12092            Value::Function(f) => f.clone(),
12093            _ => {
12094                return Err(RuntimeError::new(
12095                    "test: second argument must be test function",
12096                ))
12097            }
12098        };
12099
12100        let start = Instant::now();
12101        let result = interp.call_function(&func, vec![]);
12102        let elapsed = start.elapsed();
12103
12104        match result {
12105            Ok(_) => {
12106                println!("✓ {} ({:.2}ms)", name, elapsed.as_secs_f64() * 1000.0);
12107                Ok(Value::Bool(true))
12108            }
12109            Err(e) => {
12110                println!(
12111                    "✗ {} ({:.2}ms): {}",
12112                    name,
12113                    elapsed.as_secs_f64() * 1000.0,
12114                    e
12115                );
12116                Ok(Value::Bool(false))
12117            }
12118        }
12119    });
12120
12121    // skip - mark a test as skipped
12122    define(interp, "skip", Some(1), |_, args| {
12123        let reason = match &args[0] {
12124            Value::String(s) => (**s).clone(),
12125            _ => "skipped".to_string(),
12126        };
12127        println!("⊘ {}", reason);
12128        Ok(Value::Null)
12129    });
12130
12131    // --- PROFILING ---
12132
12133    // profile - profile a function call and return [result, timing_info]
12134    define(interp, "profile", Some(1), |interp, args| {
12135        let func = match &args[0] {
12136            Value::Function(f) => f.clone(),
12137            _ => return Err(RuntimeError::new("profile: argument must be function")),
12138        };
12139
12140        let start = Instant::now();
12141        let result = interp.call_function(&func, vec![])?;
12142        let elapsed = start.elapsed();
12143
12144        let mut timing = HashMap::new();
12145        timing.insert(
12146            "ms".to_string(),
12147            Value::Float(elapsed.as_secs_f64() * 1000.0),
12148        );
12149        timing.insert("us".to_string(), Value::Float(elapsed.as_micros() as f64));
12150        timing.insert("ns".to_string(), Value::Int(elapsed.as_nanos() as i64));
12151
12152        Ok(Value::Tuple(Rc::new(vec![
12153            result,
12154            Value::Map(Rc::new(RefCell::new(timing))),
12155        ])))
12156    });
12157
12158    // measure - measure execution time of function N times
12159    define(interp, "measure", Some(2), |interp, args| {
12160        let func = match &args[0] {
12161            Value::Function(f) => f.clone(),
12162            _ => {
12163                return Err(RuntimeError::new(
12164                    "measure: first argument must be function",
12165                ))
12166            }
12167        };
12168        let iterations = match &args[1] {
12169            Value::Int(n) => *n as usize,
12170            _ => {
12171                return Err(RuntimeError::new(
12172                    "measure: second argument must be iteration count",
12173                ))
12174            }
12175        };
12176
12177        let mut times: Vec<f64> = Vec::new();
12178        let mut last_result = Value::Null;
12179
12180        for _ in 0..iterations {
12181            let start = Instant::now();
12182            last_result = interp.call_function(&func, vec![])?;
12183            times.push(start.elapsed().as_secs_f64() * 1000.0);
12184        }
12185
12186        let sum: f64 = times.iter().sum();
12187        let avg = sum / iterations as f64;
12188        let min = times.iter().cloned().fold(f64::INFINITY, f64::min);
12189        let max = times.iter().cloned().fold(f64::NEG_INFINITY, f64::max);
12190
12191        let variance: f64 =
12192            times.iter().map(|t| (t - avg).powi(2)).sum::<f64>() / iterations as f64;
12193        let stddev = variance.sqrt();
12194
12195        let mut stats = HashMap::new();
12196        stats.insert("iterations".to_string(), Value::Int(iterations as i64));
12197        stats.insert("total_ms".to_string(), Value::Float(sum));
12198        stats.insert("avg_ms".to_string(), Value::Float(avg));
12199        stats.insert("min_ms".to_string(), Value::Float(min));
12200        stats.insert("max_ms".to_string(), Value::Float(max));
12201        stats.insert("stddev_ms".to_string(), Value::Float(stddev));
12202
12203        Ok(Value::Tuple(Rc::new(vec![
12204            last_result,
12205            Value::Map(Rc::new(RefCell::new(stats))),
12206        ])))
12207    });
12208
12209    // --- DOCUMENTATION ---
12210
12211    // help - get help text for a builtin function
12212    define(interp, "help", Some(1), |_, args| {
12213        let name = match &args[0] {
12214            Value::String(s) => (**s).clone(),
12215            Value::BuiltIn(f) => f.name.clone(),
12216            _ => {
12217                return Err(RuntimeError::new(
12218                    "help: argument must be function name or builtin",
12219                ))
12220            }
12221        };
12222
12223        // Return documentation for known functions
12224        let doc = get_function_doc(&name);
12225        Ok(Value::String(Rc::new(doc)))
12226    });
12227
12228    // list_builtins - list common builtin functions (categories)
12229    define(interp, "list_builtins", Some(0), |_, _| {
12230        let categories = vec![
12231            "Core: print, println, assert, panic, len, type_of",
12232            "Math: abs, floor, ceil, round, sqrt, pow, log, sin, cos, tan",
12233            "Collections: map, filter, reduce, zip, flatten, first, last, sort, reverse",
12234            "Strings: upper, lower, trim, split, join, contains, replace, format",
12235            "IO: read_file, write_file, file_exists, read_line",
12236            "Time: now, sleep, timestamp, format_time",
12237            "JSON: json_parse, json_stringify",
12238            "Crypto: sha256, sha512, md5, base64_encode, base64_decode",
12239            "Regex: regex_match, regex_replace, regex_split",
12240            "Pattern: type_of, is_type, match_regex, match_struct, guard, when",
12241            "DevEx: debug, inspect, trace, assert_eq, assert_ne, test, profile",
12242        ];
12243        let values: Vec<Value> = categories
12244            .iter()
12245            .map(|s| Value::String(Rc::new(s.to_string())))
12246            .collect();
12247        Ok(Value::Array(Rc::new(RefCell::new(values))))
12248    });
12249
12250    // --- UTILITY ---
12251
12252    // todo - placeholder that throws with message
12253    define(interp, "todo", Some(0), |_, _| {
12254        Err(RuntimeError::new("not yet implemented"))
12255    });
12256
12257    // unreachable - mark code as unreachable
12258    define(interp, "unreachable", Some(0), |_, _| {
12259        Err(RuntimeError::new("reached unreachable code"))
12260    });
12261
12262    // unimplemented - mark feature as unimplemented
12263    define(interp, "unimplemented", Some(1), |_, args| {
12264        let msg = match &args[0] {
12265            Value::String(s) => (**s).clone(),
12266            _ => "unimplemented".to_string(),
12267        };
12268        Err(RuntimeError::new(format!("unimplemented: {}", msg)))
12269    });
12270
12271    // deprecated - warn about deprecated usage and return value
12272    define(interp, "deprecated", Some(2), |_, args| {
12273        let msg = match &args[0] {
12274            Value::String(s) => (**s).clone(),
12275            _ => "deprecated".to_string(),
12276        };
12277        eprintln!("[DEPRECATED] {}", msg);
12278        Ok(args[1].clone())
12279    });
12280
12281    // version - return Sigil version info
12282    define(interp, "version", Some(0), |_, _| {
12283        let mut info = HashMap::new();
12284        info.insert(
12285            "sigil".to_string(),
12286            Value::String(Rc::new("0.1.0".to_string())),
12287        );
12288        info.insert(
12289            "stdlib".to_string(),
12290            Value::String(Rc::new("7.0".to_string())),
12291        );
12292        info.insert(
12293            "phase".to_string(),
12294            Value::String(Rc::new("Phase 7 - DevEx".to_string())),
12295        );
12296        Ok(Value::Map(Rc::new(RefCell::new(info))))
12297    });
12298}
12299
12300// Helper to format value for debug output
12301fn format_value_debug(value: &Value) -> String {
12302    match value {
12303        Value::Null => "null".to_string(),
12304        Value::Bool(b) => b.to_string(),
12305        Value::Int(n) => n.to_string(),
12306        Value::Float(f) => format!("{:.6}", f),
12307        Value::String(s) => format!("\"{}\"", s),
12308        Value::Char(c) => format!("'{}'", c),
12309        Value::Array(a) => {
12310            let items: Vec<String> = a.borrow().iter().take(10).map(format_value_debug).collect();
12311            if a.borrow().len() > 10 {
12312                format!(
12313                    "[{}, ... ({} more)]",
12314                    items.join(", "),
12315                    a.borrow().len() - 10
12316                )
12317            } else {
12318                format!("[{}]", items.join(", "))
12319            }
12320        }
12321        Value::Tuple(t) => {
12322            let items: Vec<String> = t.iter().map(format_value_debug).collect();
12323            format!("({})", items.join(", "))
12324        }
12325        Value::Map(m) => {
12326            let items: Vec<String> = m
12327                .borrow()
12328                .iter()
12329                .take(5)
12330                .map(|(k, v)| format!("{}: {}", k, format_value_debug(v)))
12331                .collect();
12332            if m.borrow().len() > 5 {
12333                format!(
12334                    "{{{}, ... ({} more)}}",
12335                    items.join(", "),
12336                    m.borrow().len() - 5
12337                )
12338            } else {
12339                format!("{{{}}}", items.join(", "))
12340            }
12341        }
12342        Value::Set(s) => {
12343            let items: Vec<String> = s.borrow().iter().take(5).cloned().collect();
12344            if s.borrow().len() > 5 {
12345                format!(
12346                    "#{{{}, ... ({} more)}}",
12347                    items.join(", "),
12348                    s.borrow().len() - 5
12349                )
12350            } else {
12351                format!("#{{{}}}", items.join(", "))
12352            }
12353        }
12354        Value::Struct { name, fields } => {
12355            let items: Vec<String> = fields
12356                .borrow()
12357                .iter()
12358                .map(|(k, v)| format!("{}: {}", k, format_value_debug(v)))
12359                .collect();
12360            format!("{} {{{}}}", name, items.join(", "))
12361        }
12362        Value::Variant {
12363            enum_name,
12364            variant_name,
12365            fields,
12366        } => match fields {
12367            Some(f) => {
12368                let items: Vec<String> = f.iter().map(format_value_debug).collect();
12369                format!("{}::{}({})", enum_name, variant_name, items.join(", "))
12370            }
12371            None => format!("{}::{}", enum_name, variant_name),
12372        },
12373        Value::Function(_) => "<function>".to_string(),
12374        Value::BuiltIn(f) => format!("<builtin:{}>", f.name),
12375        Value::Ref(r) => format!("&{}", format_value_debug(&r.borrow())),
12376        Value::Infinity => "∞".to_string(),
12377        Value::Empty => "∅".to_string(),
12378        Value::Evidential { value, evidence } => {
12379            format!("{:?}({})", evidence, format_value_debug(value))
12380        }
12381        Value::Affective { value, affect } => {
12382            let mut markers = Vec::new();
12383            if let Some(s) = &affect.sentiment {
12384                markers.push(format!("{:?}", s));
12385            }
12386            if affect.sarcasm {
12387                markers.push("sarcasm".to_string());
12388            }
12389            if let Some(i) = &affect.intensity {
12390                markers.push(format!("{:?}", i));
12391            }
12392            if let Some(f) = &affect.formality {
12393                markers.push(format!("{:?}", f));
12394            }
12395            if let Some(e) = &affect.emotion {
12396                markers.push(format!("{:?}", e));
12397            }
12398            if let Some(c) = &affect.confidence {
12399                markers.push(format!("{:?}", c));
12400            }
12401            format!("{}[{}]", format_value_debug(value), markers.join(","))
12402        }
12403        Value::Channel(_) => "<channel>".to_string(),
12404        Value::ThreadHandle(_) => "<thread>".to_string(),
12405        Value::Actor(_) => "<actor>".to_string(),
12406        Value::Future(_) => "<future>".to_string(),
12407        Value::VariantConstructor { enum_name, variant_name } => {
12408            format!("<constructor {}::{}>", enum_name, variant_name)
12409        }
12410        Value::DefaultConstructor { type_name } => {
12411            format!("<default {}>", type_name)
12412        }
12413        Value::Range { start, end, inclusive } => {
12414            match (start, end) {
12415                (Some(s), Some(e)) => if *inclusive {
12416                    format!("{}..={}", s, e)
12417                } else {
12418                    format!("{}..{}", s, e)
12419                },
12420                (Some(s), None) => format!("{}..", s),
12421                (None, Some(e)) => if *inclusive {
12422                    format!("..={}", e)
12423                } else {
12424                    format!("..{}", e)
12425                },
12426                (None, None) => "..".to_string(),
12427            }
12428        }
12429    }
12430}
12431
12432// Helper for pretty printing with indentation
12433fn pretty_print_value(value: &Value, indent: usize) -> String {
12434    let prefix = "  ".repeat(indent);
12435    match value {
12436        Value::Array(a) => {
12437            if a.borrow().is_empty() {
12438                "[]".to_string()
12439            } else {
12440                let items: Vec<String> = a
12441                    .borrow()
12442                    .iter()
12443                    .map(|v| {
12444                        format!(
12445                            "{}{}",
12446                            "  ".repeat(indent + 1),
12447                            pretty_print_value(v, indent + 1)
12448                        )
12449                    })
12450                    .collect();
12451                format!("[\n{}\n{}]", items.join(",\n"), prefix)
12452            }
12453        }
12454        Value::Map(m) => {
12455            if m.borrow().is_empty() {
12456                "{}".to_string()
12457            } else {
12458                let items: Vec<String> = m
12459                    .borrow()
12460                    .iter()
12461                    .map(|(k, v)| {
12462                        format!(
12463                            "{}\"{}\": {}",
12464                            "  ".repeat(indent + 1),
12465                            k,
12466                            pretty_print_value(v, indent + 1)
12467                        )
12468                    })
12469                    .collect();
12470                format!("{{\n{}\n{}}}", items.join(",\n"), prefix)
12471            }
12472        }
12473        Value::Struct { name, fields } => {
12474            if fields.borrow().is_empty() {
12475                format!("{} {{}}", name)
12476            } else {
12477                let items: Vec<String> = fields
12478                    .borrow()
12479                    .iter()
12480                    .map(|(k, v)| {
12481                        format!(
12482                            "{}{}: {}",
12483                            "  ".repeat(indent + 1),
12484                            k,
12485                            pretty_print_value(v, indent + 1)
12486                        )
12487                    })
12488                    .collect();
12489                format!("{} {{\n{}\n{}}}", name, items.join(",\n"), prefix)
12490            }
12491        }
12492        _ => format_value_debug(value),
12493    }
12494}
12495
12496// Helper to compare values for ordering (DevEx assertions)
12497fn devex_compare(a: &Value, b: &Value) -> Result<i64, RuntimeError> {
12498    match (a, b) {
12499        (Value::Int(a), Value::Int(b)) => Ok(if a < b {
12500            -1
12501        } else if a > b {
12502            1
12503        } else {
12504            0
12505        }),
12506        (Value::Float(a), Value::Float(b)) => Ok(if a < b {
12507            -1
12508        } else if a > b {
12509            1
12510        } else {
12511            0
12512        }),
12513        (Value::Int(a), Value::Float(b)) => {
12514            let a = *a as f64;
12515            Ok(if a < *b {
12516                -1
12517            } else if a > *b {
12518                1
12519            } else {
12520                0
12521            })
12522        }
12523        (Value::Float(a), Value::Int(b)) => {
12524            let b = *b as f64;
12525            Ok(if *a < b {
12526                -1
12527            } else if *a > b {
12528                1
12529            } else {
12530                0
12531            })
12532        }
12533        (Value::String(a), Value::String(b)) => Ok(if a < b {
12534            -1
12535        } else if a > b {
12536            1
12537        } else {
12538            0
12539        }),
12540        _ => Err(RuntimeError::new("cannot compare these types")),
12541    }
12542}
12543
12544// Helper to get type name
12545fn get_type_name(value: &Value) -> String {
12546    match value {
12547        Value::Null => "null".to_string(),
12548        Value::Bool(_) => "bool".to_string(),
12549        Value::Int(_) => "int".to_string(),
12550        Value::Float(_) => "float".to_string(),
12551        Value::String(_) => "string".to_string(),
12552        Value::Char(_) => "char".to_string(),
12553        Value::Array(_) => "array".to_string(),
12554        Value::Tuple(_) => "tuple".to_string(),
12555        Value::Map(_) => "map".to_string(),
12556        Value::Set(_) => "set".to_string(),
12557        Value::Struct { name, .. } => name.clone(),
12558        Value::Variant { enum_name, .. } => enum_name.clone(),
12559        Value::Function(_) => "function".to_string(),
12560        Value::BuiltIn(_) => "builtin".to_string(),
12561        Value::Ref(_) => "ref".to_string(),
12562        Value::Infinity => "infinity".to_string(),
12563        Value::Empty => "empty".to_string(),
12564        Value::Evidential { .. } => "evidential".to_string(),
12565        Value::Affective { .. } => "affective".to_string(),
12566        Value::Channel(_) => "channel".to_string(),
12567        Value::ThreadHandle(_) => "thread".to_string(),
12568        Value::Actor(_) => "actor".to_string(),
12569        Value::Future(_) => "future".to_string(),
12570        Value::VariantConstructor { enum_name, .. } => format!("{}_constructor", enum_name),
12571        Value::DefaultConstructor { type_name } => format!("{}_default", type_name),
12572        Value::Range { .. } => "range".to_string(),
12573    }
12574}
12575
12576// Helper to check type aliases
12577fn matches_type_alias(value: &Value, type_name: &str) -> bool {
12578    match (value, type_name) {
12579        (Value::Int(_), "number") | (Value::Float(_), "number") => true,
12580        (Value::Int(_), "integer") => true,
12581        (Value::Array(_), "list") => true,
12582        (Value::Map(_), "dict") | (Value::Map(_), "object") => true,
12583        (Value::Function(_), "fn") | (Value::BuiltIn(_), "fn") => true,
12584        (Value::BuiltIn(_), "function") => true,
12585        _ => false,
12586    }
12587}
12588
12589// Helper to get function documentation
12590fn get_function_doc(name: &str) -> String {
12591    match name {
12592        "print" => "print(value) - Print value to stdout".to_string(),
12593        "println" => "println(value) - Print value with newline".to_string(),
12594        "len" => "len(collection) - Get length of string, array, map, or set".to_string(),
12595        "type_of" => "type_of(value) - Get type name as string".to_string(),
12596        "assert" => "assert(condition) - Assert condition is truthy, panic if false".to_string(),
12597        "assert_eq" => "assert_eq(a, b) - Assert two values are deeply equal".to_string(),
12598        "debug" => "debug(value) - Print value with type info and return it".to_string(),
12599        "map" => "map(array, fn) - Apply function to each element".to_string(),
12600        "filter" => "filter(array, fn) - Keep elements where predicate is true".to_string(),
12601        "reduce" => "reduce(array, init, fn) - Fold array with function".to_string(),
12602        "range" => "range(start, end) - Create array of integers from start to end".to_string(),
12603        "sum" => "sum(array) - Sum all numeric elements".to_string(),
12604        "product" => "product(array) - Multiply all numeric elements".to_string(),
12605        "sort" => "sort(array) - Sort array in ascending order".to_string(),
12606        "reverse" => "reverse(array) - Reverse array order".to_string(),
12607        "join" => "join(array, sep) - Join array elements with separator".to_string(),
12608        "split" => "split(string, sep) - Split string by separator".to_string(),
12609        "trim" => "trim(string) - Remove leading/trailing whitespace".to_string(),
12610        "upper" => "upper(string) - Convert to uppercase".to_string(),
12611        "lower" => "lower(string) - Convert to lowercase".to_string(),
12612        _ => format!("No documentation available for '{}'", name),
12613    }
12614}
12615
12616// ============================================================================
12617// PHASE 8: PERFORMANCE OPTIMIZATIONS
12618// ============================================================================
12619// SoA transforms, tensor ops, autodiff, spatial hashing, constraint solving
12620
12621// ============================================================================
12622// SOA (STRUCT OF ARRAYS) TRANSFORMS
12623// ============================================================================
12624// Convert between AoS (Array of Structs) and SoA (Struct of Arrays) layouts
12625// Critical for SIMD and cache-friendly physics/graphics computations
12626
12627fn register_soa(interp: &mut Interpreter) {
12628    // aos_to_soa(array, keys) - Convert Array of Structs to Struct of Arrays
12629    // Example: aos_to_soa([{x:1,y:2}, {x:3,y:4}], ["x","y"]) -> {x:[1,3], y:[2,4]}
12630    define(interp, "aos_to_soa", Some(2), |_, args| {
12631        let arr = match &args[0] {
12632            Value::Array(arr) => arr.borrow().clone(),
12633            _ => {
12634                return Err(RuntimeError::new(
12635                    "aos_to_soa: first argument must be array",
12636                ))
12637            }
12638        };
12639        let keys = match &args[1] {
12640            Value::Array(keys) => keys.borrow().clone(),
12641            _ => {
12642                return Err(RuntimeError::new(
12643                    "aos_to_soa: second argument must be array of keys",
12644                ))
12645            }
12646        };
12647
12648        if arr.is_empty() {
12649            // Return empty SoA
12650            let mut result = HashMap::new();
12651            for key in &keys {
12652                if let Value::String(k) = key {
12653                    result.insert((**k).clone(), Value::Array(Rc::new(RefCell::new(vec![]))));
12654                }
12655            }
12656            return Ok(Value::Map(Rc::new(RefCell::new(result))));
12657        }
12658
12659        // Extract key names
12660        let key_names: Vec<String> = keys
12661            .iter()
12662            .filter_map(|k| {
12663                if let Value::String(s) = k {
12664                    Some((**s).clone())
12665                } else {
12666                    None
12667                }
12668            })
12669            .collect();
12670
12671        // Build arrays for each key
12672        let mut soa: HashMap<String, Vec<Value>> = HashMap::new();
12673        for key in &key_names {
12674            soa.insert(key.clone(), Vec::with_capacity(arr.len()));
12675        }
12676
12677        // Extract values from each struct
12678        for item in &arr {
12679            match item {
12680                Value::Map(map) => {
12681                    let map = map.borrow();
12682                    for key in &key_names {
12683                        let val = map.get(key).cloned().unwrap_or(Value::Null);
12684                        soa.get_mut(key).unwrap().push(val);
12685                    }
12686                }
12687                Value::Struct { fields, .. } => {
12688                    let fields = fields.borrow();
12689                    for key in &key_names {
12690                        let val = fields.get(key).cloned().unwrap_or(Value::Null);
12691                        soa.get_mut(key).unwrap().push(val);
12692                    }
12693                }
12694                _ => {
12695                    return Err(RuntimeError::new(
12696                        "aos_to_soa: array must contain structs or maps",
12697                    ))
12698                }
12699            }
12700        }
12701
12702        // Convert to Value::Map
12703        let result: HashMap<String, Value> = soa
12704            .into_iter()
12705            .map(|(k, v)| (k, Value::Array(Rc::new(RefCell::new(v)))))
12706            .collect();
12707
12708        Ok(Value::Map(Rc::new(RefCell::new(result))))
12709    });
12710
12711    // soa_to_aos(soa) - Convert Struct of Arrays back to Array of Structs
12712    // Example: soa_to_aos({x:[1,3], y:[2,4]}) -> [{x:1,y:2}, {x:3,y:4}]
12713    define(interp, "soa_to_aos", Some(1), |_, args| {
12714        let soa = match &args[0] {
12715            Value::Map(map) => map.borrow().clone(),
12716            _ => return Err(RuntimeError::new("soa_to_aos: argument must be map")),
12717        };
12718
12719        if soa.is_empty() {
12720            return Ok(Value::Array(Rc::new(RefCell::new(vec![]))));
12721        }
12722
12723        // Get the length from first array
12724        let len = soa
12725            .values()
12726            .next()
12727            .and_then(|v| {
12728                if let Value::Array(arr) = v {
12729                    Some(arr.borrow().len())
12730                } else {
12731                    None
12732                }
12733            })
12734            .unwrap_or(0);
12735
12736        // Build array of structs
12737        let mut aos: Vec<Value> = Vec::with_capacity(len);
12738        for i in 0..len {
12739            let mut fields = HashMap::new();
12740            for (key, value) in &soa {
12741                if let Value::Array(arr) = value {
12742                    let arr = arr.borrow();
12743                    if i < arr.len() {
12744                        fields.insert(key.clone(), arr[i].clone());
12745                    }
12746                }
12747            }
12748            aos.push(Value::Map(Rc::new(RefCell::new(fields))));
12749        }
12750
12751        Ok(Value::Array(Rc::new(RefCell::new(aos))))
12752    });
12753
12754    // soa_map(soa, key, fn) - Apply function to a single array in SoA
12755    // Allows SIMD-friendly operations on one field at a time
12756    define(interp, "soa_map", Some(3), |interp, args| {
12757        let mut soa = match &args[0] {
12758            Value::Map(map) => map.borrow().clone(),
12759            _ => return Err(RuntimeError::new("soa_map: first argument must be SoA map")),
12760        };
12761        let key = match &args[1] {
12762            Value::String(s) => (**s).clone(),
12763            _ => {
12764                return Err(RuntimeError::new(
12765                    "soa_map: second argument must be key string",
12766                ))
12767            }
12768        };
12769        let func = match &args[2] {
12770            Value::Function(f) => f.clone(),
12771            _ => {
12772                return Err(RuntimeError::new(
12773                    "soa_map: third argument must be a function",
12774                ))
12775            }
12776        };
12777
12778        // Get the array for this key
12779        let arr = soa
12780            .get(&key)
12781            .ok_or_else(|| RuntimeError::new(format!("soa_map: key '{}' not found", key)))?;
12782
12783        let arr_vals = match arr {
12784            Value::Array(a) => a.borrow().clone(),
12785            _ => return Err(RuntimeError::new("soa_map: key must map to array")),
12786        };
12787
12788        // Apply function to each element
12789        let results: Vec<Value> = arr_vals
12790            .iter()
12791            .map(|val| interp.call_function(&func, vec![val.clone()]))
12792            .collect::<Result<_, _>>()?;
12793
12794        // Update SoA
12795        soa.insert(key, Value::Array(Rc::new(RefCell::new(results))));
12796
12797        Ok(Value::Map(Rc::new(RefCell::new(soa))))
12798    });
12799
12800    // soa_zip(soa, keys, fn) - Apply function to multiple fields in parallel
12801    // Example: soa_zip(soa, ["x", "y"], fn(x, y) { sqrt(x*x + y*y) }) -> array of magnitudes
12802    define(interp, "soa_zip", Some(3), |interp, args| {
12803        let soa = match &args[0] {
12804            Value::Map(map) => map.borrow().clone(),
12805            _ => return Err(RuntimeError::new("soa_zip: first argument must be SoA map")),
12806        };
12807        let keys = match &args[1] {
12808            Value::Array(keys) => keys.borrow().clone(),
12809            _ => {
12810                return Err(RuntimeError::new(
12811                    "soa_zip: second argument must be array of keys",
12812                ))
12813            }
12814        };
12815        let func = match &args[2] {
12816            Value::Function(f) => f.clone(),
12817            _ => {
12818                return Err(RuntimeError::new(
12819                    "soa_zip: third argument must be a function",
12820                ))
12821            }
12822        };
12823
12824        // Extract arrays for each key
12825        let arrays: Vec<Vec<Value>> = keys
12826            .iter()
12827            .filter_map(|k| {
12828                if let Value::String(s) = k {
12829                    if let Some(Value::Array(arr)) = soa.get(&**s) {
12830                        return Some(arr.borrow().clone());
12831                    }
12832                }
12833                None
12834            })
12835            .collect();
12836
12837        if arrays.is_empty() {
12838            return Ok(Value::Array(Rc::new(RefCell::new(vec![]))));
12839        }
12840
12841        let len = arrays[0].len();
12842
12843        // Apply function with zipped values
12844        let results: Vec<Value> = (0..len)
12845            .map(|i| {
12846                let fn_args: Vec<Value> = arrays
12847                    .iter()
12848                    .filter_map(|arr| arr.get(i).cloned())
12849                    .collect();
12850                interp.call_function(&func, fn_args)
12851            })
12852            .collect::<Result<_, _>>()?;
12853
12854        Ok(Value::Array(Rc::new(RefCell::new(results))))
12855    });
12856
12857    // interleave(arrays...) - Interleave multiple arrays (for position/normal/uv vertices)
12858    // Example: interleave([x1,x2], [y1,y2], [z1,z2]) -> [x1,y1,z1,x2,y2,z2]
12859    define(interp, "interleave", None, |_, args| {
12860        if args.is_empty() {
12861            return Ok(Value::Array(Rc::new(RefCell::new(vec![]))));
12862        }
12863
12864        let arrays: Vec<Vec<Value>> = args
12865            .iter()
12866            .filter_map(|arg| {
12867                if let Value::Array(arr) = arg {
12868                    Some(arr.borrow().clone())
12869                } else {
12870                    None
12871                }
12872            })
12873            .collect();
12874
12875        if arrays.is_empty() {
12876            return Ok(Value::Array(Rc::new(RefCell::new(vec![]))));
12877        }
12878
12879        let len = arrays[0].len();
12880        let stride = arrays.len();
12881        let mut result = Vec::with_capacity(len * stride);
12882
12883        for i in 0..len {
12884            for arr in &arrays {
12885                if let Some(val) = arr.get(i) {
12886                    result.push(val.clone());
12887                }
12888            }
12889        }
12890
12891        Ok(Value::Array(Rc::new(RefCell::new(result))))
12892    });
12893
12894    // deinterleave(array, stride) - Deinterleave an array (inverse of interleave)
12895    // Example: deinterleave([x1,y1,z1,x2,y2,z2], 3) -> [[x1,x2], [y1,y2], [z1,z2]]
12896    define(interp, "deinterleave", Some(2), |_, args| {
12897        let arr = match &args[0] {
12898            Value::Array(arr) => arr.borrow().clone(),
12899            _ => {
12900                return Err(RuntimeError::new(
12901                    "deinterleave: first argument must be array",
12902                ))
12903            }
12904        };
12905        let stride = match &args[1] {
12906            Value::Int(n) => *n as usize,
12907            _ => {
12908                return Err(RuntimeError::new(
12909                    "deinterleave: second argument must be integer stride",
12910                ))
12911            }
12912        };
12913
12914        if stride == 0 {
12915            return Err(RuntimeError::new("deinterleave: stride must be > 0"));
12916        }
12917
12918        let mut result: Vec<Vec<Value>> = (0..stride).map(|_| Vec::new()).collect();
12919
12920        for (i, val) in arr.iter().enumerate() {
12921            result[i % stride].push(val.clone());
12922        }
12923
12924        Ok(Value::Array(Rc::new(RefCell::new(
12925            result
12926                .into_iter()
12927                .map(|v| Value::Array(Rc::new(RefCell::new(v))))
12928                .collect(),
12929        ))))
12930    });
12931}
12932
12933// ============================================================================
12934// TENSOR OPERATIONS
12935// ============================================================================
12936// Outer products, contractions, tensor transpose for advanced linear algebra
12937
12938fn register_tensor(interp: &mut Interpreter) {
12939    // outer_product(a, b) - Tensor outer product: a ⊗ b
12940    // vec × vec -> matrix, mat × vec -> rank-3 tensor
12941    define(interp, "outer_product", Some(2), |_, args| {
12942        let a = match &args[0] {
12943            Value::Array(arr) => arr.borrow().clone(),
12944            _ => return Err(RuntimeError::new("outer_product: arguments must be arrays")),
12945        };
12946        let b = match &args[1] {
12947            Value::Array(arr) => arr.borrow().clone(),
12948            _ => return Err(RuntimeError::new("outer_product: arguments must be arrays")),
12949        };
12950
12951        // vec ⊗ vec -> matrix
12952        let mut result: Vec<Value> = Vec::with_capacity(a.len() * b.len());
12953        for ai in &a {
12954            for bi in &b {
12955                let product = match (ai, bi) {
12956                    (Value::Float(x), Value::Float(y)) => Value::Float(x * y),
12957                    (Value::Int(x), Value::Int(y)) => Value::Int(x * y),
12958                    (Value::Float(x), Value::Int(y)) => Value::Float(x * (*y as f64)),
12959                    (Value::Int(x), Value::Float(y)) => Value::Float((*x as f64) * y),
12960                    _ => return Err(RuntimeError::new("outer_product: elements must be numeric")),
12961                };
12962                result.push(product);
12963            }
12964        }
12965
12966        Ok(Value::Array(Rc::new(RefCell::new(result))))
12967    });
12968
12969    // tensor_contract(a, b, axis_a, axis_b) - Contract tensors along specified axes
12970    // Generalized matrix multiplication and index contraction
12971    define(interp, "tensor_contract", Some(4), |_, args| {
12972        let a = match &args[0] {
12973            Value::Array(arr) => arr.borrow().clone(),
12974            _ => {
12975                return Err(RuntimeError::new(
12976                    "tensor_contract: first argument must be array",
12977                ))
12978            }
12979        };
12980        let b = match &args[1] {
12981            Value::Array(arr) => arr.borrow().clone(),
12982            _ => {
12983                return Err(RuntimeError::new(
12984                    "tensor_contract: second argument must be array",
12985                ))
12986            }
12987        };
12988        let _axis_a = match &args[2] {
12989            Value::Int(n) => *n as usize,
12990            _ => return Err(RuntimeError::new("tensor_contract: axis must be integer")),
12991        };
12992        let _axis_b = match &args[3] {
12993            Value::Int(n) => *n as usize,
12994            _ => return Err(RuntimeError::new("tensor_contract: axis must be integer")),
12995        };
12996
12997        // Simple dot product for 1D tensors (vectors)
12998        if a.len() != b.len() {
12999            return Err(RuntimeError::new(
13000                "tensor_contract: vectors must have same length for contraction",
13001            ));
13002        }
13003
13004        let mut sum = 0.0f64;
13005        for (ai, bi) in a.iter().zip(b.iter()) {
13006            let product = match (ai, bi) {
13007                (Value::Float(x), Value::Float(y)) => x * y,
13008                (Value::Int(x), Value::Int(y)) => (*x as f64) * (*y as f64),
13009                (Value::Float(x), Value::Int(y)) => x * (*y as f64),
13010                (Value::Int(x), Value::Float(y)) => (*x as f64) * y,
13011                _ => {
13012                    return Err(RuntimeError::new(
13013                        "tensor_contract: elements must be numeric",
13014                    ))
13015                }
13016            };
13017            sum += product;
13018        }
13019
13020        Ok(Value::Float(sum))
13021    });
13022
13023    // kronecker_product(a, b) - Kronecker tensor product
13024    // Used in quantum computing and multi-linear algebra
13025    define(interp, "kronecker_product", Some(2), |_, args| {
13026        let a = match &args[0] {
13027            Value::Array(arr) => arr.borrow().clone(),
13028            _ => {
13029                return Err(RuntimeError::new(
13030                    "kronecker_product: arguments must be arrays",
13031                ))
13032            }
13033        };
13034        let b = match &args[1] {
13035            Value::Array(arr) => arr.borrow().clone(),
13036            _ => {
13037                return Err(RuntimeError::new(
13038                    "kronecker_product: arguments must be arrays",
13039                ))
13040            }
13041        };
13042
13043        // For 1D vectors: same as outer product
13044        let mut result: Vec<Value> = Vec::with_capacity(a.len() * b.len());
13045        for ai in &a {
13046            for bi in &b {
13047                let product = match (ai, bi) {
13048                    (Value::Float(x), Value::Float(y)) => Value::Float(x * y),
13049                    (Value::Int(x), Value::Int(y)) => Value::Int(x * y),
13050                    (Value::Float(x), Value::Int(y)) => Value::Float(x * (*y as f64)),
13051                    (Value::Int(x), Value::Float(y)) => Value::Float((*x as f64) * y),
13052                    _ => {
13053                        return Err(RuntimeError::new(
13054                            "kronecker_product: elements must be numeric",
13055                        ))
13056                    }
13057                };
13058                result.push(product);
13059            }
13060        }
13061
13062        Ok(Value::Array(Rc::new(RefCell::new(result))))
13063    });
13064
13065    // hadamard_product(a, b) - Element-wise product (Hadamard/Schur product)
13066    define(interp, "hadamard_product", Some(2), |_, args| {
13067        let a = match &args[0] {
13068            Value::Array(arr) => arr.borrow().clone(),
13069            _ => {
13070                return Err(RuntimeError::new(
13071                    "hadamard_product: arguments must be arrays",
13072                ))
13073            }
13074        };
13075        let b = match &args[1] {
13076            Value::Array(arr) => arr.borrow().clone(),
13077            _ => {
13078                return Err(RuntimeError::new(
13079                    "hadamard_product: arguments must be arrays",
13080                ))
13081            }
13082        };
13083
13084        if a.len() != b.len() {
13085            return Err(RuntimeError::new(
13086                "hadamard_product: arrays must have same length",
13087            ));
13088        }
13089
13090        let result: Vec<Value> = a
13091            .iter()
13092            .zip(b.iter())
13093            .map(|(ai, bi)| match (ai, bi) {
13094                (Value::Float(x), Value::Float(y)) => Ok(Value::Float(x * y)),
13095                (Value::Int(x), Value::Int(y)) => Ok(Value::Int(x * y)),
13096                (Value::Float(x), Value::Int(y)) => Ok(Value::Float(x * (*y as f64))),
13097                (Value::Int(x), Value::Float(y)) => Ok(Value::Float((*x as f64) * y)),
13098                _ => Err(RuntimeError::new(
13099                    "hadamard_product: elements must be numeric",
13100                )),
13101            })
13102            .collect::<Result<_, _>>()?;
13103
13104        Ok(Value::Array(Rc::new(RefCell::new(result))))
13105    });
13106
13107    // trace(matrix, size) - Trace of square matrix (sum of diagonal)
13108    define(interp, "trace", Some(2), |_, args| {
13109        let arr = match &args[0] {
13110            Value::Array(arr) => arr.borrow().clone(),
13111            _ => return Err(RuntimeError::new("trace: first argument must be array")),
13112        };
13113        let size = match &args[1] {
13114            Value::Int(n) => *n as usize,
13115            _ => {
13116                return Err(RuntimeError::new(
13117                    "trace: second argument must be matrix size",
13118                ))
13119            }
13120        };
13121
13122        let mut sum = 0.0f64;
13123        for i in 0..size {
13124            let idx = i * size + i;
13125            if idx < arr.len() {
13126                sum += match &arr[idx] {
13127                    Value::Float(f) => *f,
13128                    Value::Int(n) => *n as f64,
13129                    _ => return Err(RuntimeError::new("trace: elements must be numeric")),
13130                };
13131            }
13132        }
13133
13134        Ok(Value::Float(sum))
13135    });
13136}
13137
13138// ============================================================================
13139// AUTOMATIC DIFFERENTIATION
13140// ============================================================================
13141//
13142// This module provides numerical differentiation using finite differences.
13143// While not as accurate as symbolic or dual-number autodiff, it's simple
13144// and works for any function without special annotations.
13145//
13146// ## Available Functions
13147//
13148// | Function | Description | Complexity |
13149// |----------|-------------|------------|
13150// | `grad(f, x, [h])` | Gradient of f at x | O(n) function calls |
13151// | `jacobian(f, x, [h])` | Jacobian matrix | O(m*n) function calls |
13152// | `hessian(f, x, [h])` | Hessian matrix | O(n²) function calls |
13153// | `directional_derivative(f, x, v, [h])` | Derivative along v | O(1) |
13154// | `laplacian(f, x, [h])` | Sum of second partials | O(n) |
13155//
13156// ## Algorithm Details
13157//
13158// All functions use central differences: (f(x+h) - f(x-h)) / 2h
13159// Default step size h = 1e-7 (optimized for f64 precision)
13160//
13161// ## Usage Examples
13162//
13163// ```sigil
13164// // Scalar function gradient
13165// fn f(x) { return x * x; }
13166// let df = grad(f, 3.0);  // Returns 6.0 (derivative of x² at x=3)
13167//
13168// // Multi-variable gradient
13169// fn g(x) { return get(x, 0)*get(x, 0) + get(x, 1)*get(x, 1); }
13170// let dg = grad(g, [1.0, 2.0]);  // Returns [2.0, 4.0]
13171//
13172// // Hessian of f at point x
13173// let H = hessian(f, [x, y]);  // Returns 2D array of second derivatives
13174// ```
13175//
13176// ## Performance Notes
13177//
13178// - grad: 2n function evaluations for n-dimensional input
13179// - jacobian: 2mn evaluations for m-output, n-input function
13180// - hessian: 4n² evaluations (computed from gradient)
13181// - For performance-critical code, consider symbolic differentiation
13182
13183fn register_autodiff(interp: &mut Interpreter) {
13184    // grad(f, x, h) - Numerical gradient of f at x using finite differences
13185    // h is optional step size (default 1e-7)
13186    define(interp, "grad", None, |interp, args| {
13187        if args.len() < 2 {
13188            return Err(RuntimeError::new(
13189                "grad() requires function and point arguments.\n\
13190                 Usage: grad(f, x) or grad(f, x, step_size)\n\
13191                 Example:\n\
13192                   fn f(x) { return x * x; }\n\
13193                   let derivative = grad(f, 3.0);  // Returns 6.0",
13194            ));
13195        }
13196
13197        let func = match &args[0] {
13198            Value::Function(f) => f.clone(),
13199            _ => {
13200                return Err(RuntimeError::new(
13201                    "grad() first argument must be a function.\n\
13202                 Got non-function value. Define a function first:\n\
13203                   fn my_func(x) { return x * x; }\n\
13204                   grad(my_func, 2.0)",
13205                ))
13206            }
13207        };
13208        let x = match &args[1] {
13209            Value::Float(f) => *f,
13210            Value::Int(n) => *n as f64,
13211            Value::Array(arr) => {
13212                // Multi-variable gradient
13213                let arr = arr.borrow().clone();
13214                let h = if args.len() > 2 {
13215                    match &args[2] {
13216                        Value::Float(f) => *f,
13217                        Value::Int(n) => *n as f64,
13218                        _ => 1e-7,
13219                    }
13220                } else {
13221                    1e-7
13222                };
13223
13224                let mut gradient = Vec::with_capacity(arr.len());
13225                for (i, xi) in arr.iter().enumerate() {
13226                    let xi_val = match xi {
13227                        Value::Float(f) => *f,
13228                        Value::Int(n) => *n as f64,
13229                        _ => continue,
13230                    };
13231
13232                    // f(x + h*ei) - f(x - h*ei) / 2h
13233                    let mut x_plus = arr.clone();
13234                    let mut x_minus = arr.clone();
13235                    x_plus[i] = Value::Float(xi_val + h);
13236                    x_minus[i] = Value::Float(xi_val - h);
13237
13238                    let f_plus = interp
13239                        .call_function(&func, vec![Value::Array(Rc::new(RefCell::new(x_plus)))])?;
13240                    let f_minus = interp
13241                        .call_function(&func, vec![Value::Array(Rc::new(RefCell::new(x_minus)))])?;
13242
13243                    let grad_i = match (f_plus, f_minus) {
13244                        (Value::Float(fp), Value::Float(fm)) => (fp - fm) / (2.0 * h),
13245                        (Value::Int(fp), Value::Int(fm)) => (fp - fm) as f64 / (2.0 * h),
13246                        _ => return Err(RuntimeError::new("grad: function must return numeric")),
13247                    };
13248
13249                    gradient.push(Value::Float(grad_i));
13250                }
13251
13252                return Ok(Value::Array(Rc::new(RefCell::new(gradient))));
13253            }
13254            _ => return Err(RuntimeError::new("grad: x must be numeric or array")),
13255        };
13256
13257        let h = if args.len() > 2 {
13258            match &args[2] {
13259                Value::Float(f) => *f,
13260                Value::Int(n) => *n as f64,
13261                _ => 1e-7,
13262            }
13263        } else {
13264            1e-7
13265        };
13266
13267        // Single variable derivative using central difference
13268        let f_plus = interp.call_function(&func, vec![Value::Float(x + h)])?;
13269        let f_minus = interp.call_function(&func, vec![Value::Float(x - h)])?;
13270
13271        let derivative = match (f_plus, f_minus) {
13272            (Value::Float(fp), Value::Float(fm)) => (fp - fm) / (2.0 * h),
13273            (Value::Int(fp), Value::Int(fm)) => (fp - fm) as f64 / (2.0 * h),
13274            _ => return Err(RuntimeError::new("grad: function must return numeric")),
13275        };
13276
13277        Ok(Value::Float(derivative))
13278    });
13279
13280    // jacobian(f, x) - Compute Jacobian matrix for vector function
13281    define(interp, "jacobian", Some(2), |interp, args| {
13282        let func = match &args[0] {
13283            Value::Function(f) => f.clone(),
13284            _ => {
13285                return Err(RuntimeError::new(
13286                    "jacobian: first argument must be a function",
13287                ))
13288            }
13289        };
13290        let x = match &args[1] {
13291            Value::Array(arr) => arr.borrow().clone(),
13292            _ => return Err(RuntimeError::new("jacobian: second argument must be array")),
13293        };
13294
13295        let h = 1e-7;
13296        let n = x.len();
13297
13298        // Evaluate f at x to get output dimension
13299        let f_x =
13300            interp.call_function(&func, vec![Value::Array(Rc::new(RefCell::new(x.clone())))])?;
13301        let m = match &f_x {
13302            Value::Array(arr) => arr.borrow().len(),
13303            _ => 1,
13304        };
13305
13306        // Build Jacobian matrix (m x n)
13307        let mut jacobian: Vec<Value> = Vec::with_capacity(m * n);
13308
13309        for j in 0..n {
13310            let xj = match &x[j] {
13311                Value::Float(f) => *f,
13312                Value::Int(i) => *i as f64,
13313                _ => continue,
13314            };
13315
13316            let mut x_plus = x.clone();
13317            let mut x_minus = x.clone();
13318            x_plus[j] = Value::Float(xj + h);
13319            x_minus[j] = Value::Float(xj - h);
13320
13321            let f_plus =
13322                interp.call_function(&func, vec![Value::Array(Rc::new(RefCell::new(x_plus)))])?;
13323            let f_minus =
13324                interp.call_function(&func, vec![Value::Array(Rc::new(RefCell::new(x_minus)))])?;
13325
13326            // Extract derivatives for each output component
13327            match (&f_plus, &f_minus) {
13328                (Value::Array(fp), Value::Array(fm)) => {
13329                    let fp = fp.borrow();
13330                    let fm = fm.borrow();
13331                    for i in 0..m {
13332                        let dfi_dxj = match (&fp[i], &fm[i]) {
13333                            (Value::Float(a), Value::Float(b)) => (*a - *b) / (2.0 * h),
13334                            (Value::Int(a), Value::Int(b)) => (*a - *b) as f64 / (2.0 * h),
13335                            _ => 0.0,
13336                        };
13337                        jacobian.push(Value::Float(dfi_dxj));
13338                    }
13339                }
13340                (Value::Float(fp), Value::Float(fm)) => {
13341                    jacobian.push(Value::Float((fp - fm) / (2.0 * h)));
13342                }
13343                _ => {
13344                    return Err(RuntimeError::new(
13345                        "jacobian: function must return array or numeric",
13346                    ))
13347                }
13348            }
13349        }
13350
13351        Ok(Value::Array(Rc::new(RefCell::new(jacobian))))
13352    });
13353
13354    // hessian(f, x) - Compute Hessian matrix (second derivatives)
13355    define(interp, "hessian", Some(2), |interp, args| {
13356        let func = match &args[0] {
13357            Value::Function(f) => f.clone(),
13358            _ => {
13359                return Err(RuntimeError::new(
13360                    "hessian: first argument must be a function",
13361                ))
13362            }
13363        };
13364        let x = match &args[1] {
13365            Value::Array(arr) => arr.borrow().clone(),
13366            _ => return Err(RuntimeError::new("hessian: second argument must be array")),
13367        };
13368
13369        let h = 1e-5; // Larger h for second derivatives
13370        let n = x.len();
13371
13372        let mut hessian: Vec<Value> = Vec::with_capacity(n * n);
13373
13374        for i in 0..n {
13375            for j in 0..n {
13376                let xi = match &x[i] {
13377                    Value::Float(f) => *f,
13378                    Value::Int(k) => *k as f64,
13379                    _ => continue,
13380                };
13381                let xj = match &x[j] {
13382                    Value::Float(f) => *f,
13383                    Value::Int(k) => *k as f64,
13384                    _ => continue,
13385                };
13386
13387                // Second partial derivative using finite differences
13388                let mut x_pp = x.clone();
13389                let mut x_pm = x.clone();
13390                let mut x_mp = x.clone();
13391                let mut x_mm = x.clone();
13392
13393                x_pp[i] = Value::Float(xi + h);
13394                x_pp[j] = Value::Float(if i == j { xi + 2.0 * h } else { xj + h });
13395                x_pm[i] = Value::Float(xi + h);
13396                x_pm[j] = Value::Float(if i == j { xi } else { xj - h });
13397                x_mp[i] = Value::Float(xi - h);
13398                x_mp[j] = Value::Float(if i == j { xi } else { xj + h });
13399                x_mm[i] = Value::Float(xi - h);
13400                x_mm[j] = Value::Float(if i == j { xi - 2.0 * h } else { xj - h });
13401
13402                let f_pp =
13403                    interp.call_function(&func, vec![Value::Array(Rc::new(RefCell::new(x_pp)))])?;
13404                let f_pm =
13405                    interp.call_function(&func, vec![Value::Array(Rc::new(RefCell::new(x_pm)))])?;
13406                let f_mp =
13407                    interp.call_function(&func, vec![Value::Array(Rc::new(RefCell::new(x_mp)))])?;
13408                let f_mm =
13409                    interp.call_function(&func, vec![Value::Array(Rc::new(RefCell::new(x_mm)))])?;
13410
13411                let d2f = match (f_pp, f_pm, f_mp, f_mm) {
13412                    (
13413                        Value::Float(fpp),
13414                        Value::Float(fpm),
13415                        Value::Float(fmp),
13416                        Value::Float(fmm),
13417                    ) => (fpp - fpm - fmp + fmm) / (4.0 * h * h),
13418                    _ => 0.0,
13419                };
13420
13421                hessian.push(Value::Float(d2f));
13422            }
13423        }
13424
13425        Ok(Value::Array(Rc::new(RefCell::new(hessian))))
13426    });
13427
13428    // divergence(f, x) - Compute divergence of vector field (∇·F)
13429    define(interp, "divergence", Some(2), |interp, args| {
13430        let func = match &args[0] {
13431            Value::Function(f) => f.clone(),
13432            _ => {
13433                return Err(RuntimeError::new(
13434                    "divergence: first argument must be a function",
13435                ))
13436            }
13437        };
13438        let x = match &args[1] {
13439            Value::Array(arr) => arr.borrow().clone(),
13440            _ => {
13441                return Err(RuntimeError::new(
13442                    "divergence: second argument must be array",
13443                ))
13444            }
13445        };
13446
13447        let h = 1e-7;
13448        let mut div = 0.0f64;
13449
13450        for (i, xi) in x.iter().enumerate() {
13451            let xi_val = match xi {
13452                Value::Float(f) => *f,
13453                Value::Int(n) => *n as f64,
13454                _ => continue,
13455            };
13456
13457            let mut x_plus = x.clone();
13458            let mut x_minus = x.clone();
13459            x_plus[i] = Value::Float(xi_val + h);
13460            x_minus[i] = Value::Float(xi_val - h);
13461
13462            let f_plus =
13463                interp.call_function(&func, vec![Value::Array(Rc::new(RefCell::new(x_plus)))])?;
13464            let f_minus =
13465                interp.call_function(&func, vec![Value::Array(Rc::new(RefCell::new(x_minus)))])?;
13466
13467            // Extract i-th component
13468            let df_i = match (&f_plus, &f_minus) {
13469                (Value::Array(fp), Value::Array(fm)) => {
13470                    let fp = fp.borrow();
13471                    let fm = fm.borrow();
13472                    if i < fp.len() && i < fm.len() {
13473                        match (&fp[i], &fm[i]) {
13474                            (Value::Float(a), Value::Float(b)) => (*a - *b) / (2.0 * h),
13475                            (Value::Int(a), Value::Int(b)) => (*a - *b) as f64 / (2.0 * h),
13476                            _ => 0.0,
13477                        }
13478                    } else {
13479                        0.0
13480                    }
13481                }
13482                _ => 0.0,
13483            };
13484
13485            div += df_i;
13486        }
13487
13488        Ok(Value::Float(div))
13489    });
13490}
13491
13492// ============================================================================
13493// SPATIAL HASHING / ACCELERATION STRUCTURES
13494// ============================================================================
13495// BVH, octrees, spatial hashing for efficient collision detection and queries
13496
13497fn register_spatial(interp: &mut Interpreter) {
13498    // spatial_hash_new(cell_size) - Create new spatial hash grid
13499    define(interp, "spatial_hash_new", Some(1), |_, args| {
13500        let cell_size = match &args[0] {
13501            Value::Float(f) => *f,
13502            Value::Int(n) => *n as f64,
13503            _ => {
13504                return Err(RuntimeError::new(
13505                    "spatial_hash_new: cell_size must be numeric",
13506                ))
13507            }
13508        };
13509
13510        let mut config = HashMap::new();
13511        config.insert("cell_size".to_string(), Value::Float(cell_size));
13512        config.insert(
13513            "buckets".to_string(),
13514            Value::Map(Rc::new(RefCell::new(HashMap::new()))),
13515        );
13516
13517        Ok(Value::Map(Rc::new(RefCell::new(config))))
13518    });
13519
13520    // spatial_hash_insert(hash, id, position) - Insert object at position
13521    define(interp, "spatial_hash_insert", Some(3), |_, args| {
13522        let hash = match &args[0] {
13523            Value::Map(map) => map.clone(),
13524            _ => {
13525                return Err(RuntimeError::new(
13526                    "spatial_hash_insert: first argument must be spatial hash",
13527                ))
13528            }
13529        };
13530        let id = args[1].clone();
13531        let pos = match &args[2] {
13532            Value::Array(arr) => arr.borrow().clone(),
13533            _ => {
13534                return Err(RuntimeError::new(
13535                    "spatial_hash_insert: position must be array",
13536                ))
13537            }
13538        };
13539
13540        let cell_size = {
13541            let h = hash.borrow();
13542            match h.get("cell_size") {
13543                Some(Value::Float(f)) => *f,
13544                _ => 1.0,
13545            }
13546        };
13547
13548        // Compute cell key
13549        let key = pos
13550            .iter()
13551            .filter_map(|v| match v {
13552                Value::Float(f) => Some((*f / cell_size).floor() as i64),
13553                Value::Int(n) => Some(*n / (cell_size as i64)),
13554                _ => None,
13555            })
13556            .map(|n| n.to_string())
13557            .collect::<Vec<_>>()
13558            .join(",");
13559
13560        // Insert into bucket
13561        {
13562            let mut h = hash.borrow_mut();
13563            let buckets = h
13564                .entry("buckets".to_string())
13565                .or_insert_with(|| Value::Map(Rc::new(RefCell::new(HashMap::new()))));
13566
13567            if let Value::Map(buckets_map) = buckets {
13568                let mut bm = buckets_map.borrow_mut();
13569                let bucket = bm
13570                    .entry(key)
13571                    .or_insert_with(|| Value::Array(Rc::new(RefCell::new(vec![]))));
13572
13573                if let Value::Array(arr) = bucket {
13574                    arr.borrow_mut().push(id);
13575                }
13576            }
13577        }
13578
13579        Ok(Value::Map(hash))
13580    });
13581
13582    // spatial_hash_query(hash, position, radius) - Query objects near position
13583    define(interp, "spatial_hash_query", Some(3), |_, args| {
13584        let hash = match &args[0] {
13585            Value::Map(map) => map.borrow().clone(),
13586            _ => {
13587                return Err(RuntimeError::new(
13588                    "spatial_hash_query: first argument must be spatial hash",
13589                ))
13590            }
13591        };
13592        let pos = match &args[1] {
13593            Value::Array(arr) => arr.borrow().clone(),
13594            _ => {
13595                return Err(RuntimeError::new(
13596                    "spatial_hash_query: position must be array",
13597                ))
13598            }
13599        };
13600        let radius = match &args[2] {
13601            Value::Float(f) => *f,
13602            Value::Int(n) => *n as f64,
13603            _ => {
13604                return Err(RuntimeError::new(
13605                    "spatial_hash_query: radius must be numeric",
13606                ))
13607            }
13608        };
13609
13610        let cell_size = match hash.get("cell_size") {
13611            Some(Value::Float(f)) => *f,
13612            _ => 1.0,
13613        };
13614
13615        // Get center cell
13616        let center: Vec<i64> = pos
13617            .iter()
13618            .filter_map(|v| match v {
13619                Value::Float(f) => Some((*f / cell_size).floor() as i64),
13620                Value::Int(n) => Some(*n / (cell_size as i64)),
13621                _ => None,
13622            })
13623            .collect();
13624
13625        // Compute cell range to check
13626        let cells_to_check = (radius / cell_size).ceil() as i64;
13627
13628        let mut results: Vec<Value> = Vec::new();
13629
13630        if let Some(Value::Map(buckets)) = hash.get("buckets") {
13631            let buckets = buckets.borrow();
13632
13633            // Check neighboring cells
13634            if center.len() >= 2 {
13635                for dx in -cells_to_check..=cells_to_check {
13636                    for dy in -cells_to_check..=cells_to_check {
13637                        let key = format!("{},{}", center[0] + dx, center[1] + dy);
13638                        if let Some(Value::Array(bucket)) = buckets.get(&key) {
13639                            for item in bucket.borrow().iter() {
13640                                // Push without duplicate check since Value doesn't impl PartialEq
13641                                // For production use, would need to track IDs separately
13642                                results.push(item.clone());
13643                            }
13644                        }
13645                    }
13646                }
13647            }
13648        }
13649
13650        Ok(Value::Array(Rc::new(RefCell::new(results))))
13651    });
13652
13653    // aabb_new(min, max) - Create axis-aligned bounding box
13654    define(interp, "aabb_new", Some(2), |_, args| {
13655        let min = match &args[0] {
13656            Value::Array(arr) => arr.borrow().clone(),
13657            _ => return Err(RuntimeError::new("aabb_new: min must be array")),
13658        };
13659        let max = match &args[1] {
13660            Value::Array(arr) => arr.borrow().clone(),
13661            _ => return Err(RuntimeError::new("aabb_new: max must be array")),
13662        };
13663
13664        let mut aabb = HashMap::new();
13665        aabb.insert("min".to_string(), Value::Array(Rc::new(RefCell::new(min))));
13666        aabb.insert("max".to_string(), Value::Array(Rc::new(RefCell::new(max))));
13667
13668        Ok(Value::Map(Rc::new(RefCell::new(aabb))))
13669    });
13670
13671    // aabb_intersects(a, b) - Test if two AABBs intersect
13672    define(interp, "aabb_intersects", Some(2), |_, args| {
13673        let a = match &args[0] {
13674            Value::Map(map) => map.borrow().clone(),
13675            _ => {
13676                return Err(RuntimeError::new(
13677                    "aabb_intersects: arguments must be AABBs",
13678                ))
13679            }
13680        };
13681        let b = match &args[1] {
13682            Value::Map(map) => map.borrow().clone(),
13683            _ => {
13684                return Err(RuntimeError::new(
13685                    "aabb_intersects: arguments must be AABBs",
13686                ))
13687            }
13688        };
13689
13690        let a_min = extract_vec_from_map(&a, "min")?;
13691        let a_max = extract_vec_from_map(&a, "max")?;
13692        let b_min = extract_vec_from_map(&b, "min")?;
13693        let b_max = extract_vec_from_map(&b, "max")?;
13694
13695        // Check overlap in each dimension
13696        for i in 0..a_min
13697            .len()
13698            .min(a_max.len())
13699            .min(b_min.len())
13700            .min(b_max.len())
13701        {
13702            if a_max[i] < b_min[i] || b_max[i] < a_min[i] {
13703                return Ok(Value::Bool(false));
13704            }
13705        }
13706
13707        Ok(Value::Bool(true))
13708    });
13709
13710    // aabb_contains(aabb, point) - Test if AABB contains point
13711    define(interp, "aabb_contains", Some(2), |_, args| {
13712        let aabb = match &args[0] {
13713            Value::Map(map) => map.borrow().clone(),
13714            _ => {
13715                return Err(RuntimeError::new(
13716                    "aabb_contains: first argument must be AABB",
13717                ))
13718            }
13719        };
13720        let point = match &args[1] {
13721            Value::Array(arr) => arr.borrow().clone(),
13722            _ => {
13723                return Err(RuntimeError::new(
13724                    "aabb_contains: second argument must be point array",
13725                ))
13726            }
13727        };
13728
13729        let min = extract_vec_from_map(&aabb, "min")?;
13730        let max = extract_vec_from_map(&aabb, "max")?;
13731
13732        for (i, p) in point.iter().enumerate() {
13733            let p_val = match p {
13734                Value::Float(f) => *f,
13735                Value::Int(n) => *n as f64,
13736                _ => continue,
13737            };
13738
13739            if i < min.len() && p_val < min[i] {
13740                return Ok(Value::Bool(false));
13741            }
13742            if i < max.len() && p_val > max[i] {
13743                return Ok(Value::Bool(false));
13744            }
13745        }
13746
13747        Ok(Value::Bool(true))
13748    });
13749}
13750
13751// Helper for extracting vector from AABB map
13752fn extract_vec_from_map(map: &HashMap<String, Value>, key: &str) -> Result<Vec<f64>, RuntimeError> {
13753    match map.get(key) {
13754        Some(Value::Array(arr)) => arr
13755            .borrow()
13756            .iter()
13757            .map(|v| match v {
13758                Value::Float(f) => Ok(*f),
13759                Value::Int(n) => Ok(*n as f64),
13760                _ => Err(RuntimeError::new("Expected numeric value")),
13761            })
13762            .collect(),
13763        _ => Err(RuntimeError::new(format!(
13764            "Missing or invalid '{}' in AABB",
13765            key
13766        ))),
13767    }
13768}
13769
13770// ============================================================================
13771// PHYSICS / CONSTRAINT SOLVER
13772// ============================================================================
13773// Verlet integration, constraint solving, spring systems
13774
13775fn register_physics(interp: &mut Interpreter) {
13776    // verlet_integrate(pos, prev_pos, accel, dt) - Verlet integration step
13777    // Returns new position: pos + (pos - prev_pos) + accel * dt^2
13778    define(interp, "verlet_integrate", Some(4), |_, args| {
13779        let pos = extract_vec3(&args[0], "verlet_integrate")?;
13780        let prev = extract_vec3(&args[1], "verlet_integrate")?;
13781        let accel = extract_vec3(&args[2], "verlet_integrate")?;
13782        let dt = match &args[3] {
13783            Value::Float(f) => *f,
13784            Value::Int(n) => *n as f64,
13785            _ => return Err(RuntimeError::new("verlet_integrate: dt must be numeric")),
13786        };
13787
13788        let dt2 = dt * dt;
13789        let new_pos = [
13790            pos[0] + (pos[0] - prev[0]) + accel[0] * dt2,
13791            pos[1] + (pos[1] - prev[1]) + accel[1] * dt2,
13792            pos[2] + (pos[2] - prev[2]) + accel[2] * dt2,
13793        ];
13794
13795        Ok(make_vec3_arr(new_pos))
13796    });
13797
13798    // spring_force(p1, p2, rest_length, stiffness) - Compute spring force
13799    define(interp, "spring_force", Some(4), |_, args| {
13800        let p1 = extract_vec3(&args[0], "spring_force")?;
13801        let p2 = extract_vec3(&args[1], "spring_force")?;
13802        let rest_length = match &args[2] {
13803            Value::Float(f) => *f,
13804            Value::Int(n) => *n as f64,
13805            _ => {
13806                return Err(RuntimeError::new(
13807                    "spring_force: rest_length must be numeric",
13808                ))
13809            }
13810        };
13811        let stiffness = match &args[3] {
13812            Value::Float(f) => *f,
13813            Value::Int(n) => *n as f64,
13814            _ => return Err(RuntimeError::new("spring_force: stiffness must be numeric")),
13815        };
13816
13817        let delta = [p2[0] - p1[0], p2[1] - p1[1], p2[2] - p1[2]];
13818        let length = (delta[0] * delta[0] + delta[1] * delta[1] + delta[2] * delta[2]).sqrt();
13819
13820        if length < 1e-10 {
13821            return Ok(make_vec3_arr([0.0, 0.0, 0.0]));
13822        }
13823
13824        let displacement = length - rest_length;
13825        let force_mag = stiffness * displacement;
13826        let normalized = [delta[0] / length, delta[1] / length, delta[2] / length];
13827
13828        Ok(make_vec3_arr([
13829            normalized[0] * force_mag,
13830            normalized[1] * force_mag,
13831            normalized[2] * force_mag,
13832        ]))
13833    });
13834
13835    // distance_constraint(p1, p2, target_distance) - Apply distance constraint
13836    // Returns tuple of (new_p1, new_p2) that satisfy the constraint
13837    define(interp, "distance_constraint", Some(3), |_, args| {
13838        let p1 = extract_vec3(&args[0], "distance_constraint")?;
13839        let p2 = extract_vec3(&args[1], "distance_constraint")?;
13840        let target = match &args[2] {
13841            Value::Float(f) => *f,
13842            Value::Int(n) => *n as f64,
13843            _ => {
13844                return Err(RuntimeError::new(
13845                    "distance_constraint: target must be numeric",
13846                ))
13847            }
13848        };
13849
13850        let delta = [p2[0] - p1[0], p2[1] - p1[1], p2[2] - p1[2]];
13851        let length = (delta[0] * delta[0] + delta[1] * delta[1] + delta[2] * delta[2]).sqrt();
13852
13853        if length < 1e-10 {
13854            return Ok(Value::Tuple(Rc::new(vec![
13855                make_vec3_arr(p1),
13856                make_vec3_arr(p2),
13857            ])));
13858        }
13859
13860        let correction = (length - target) / length * 0.5;
13861        let corr_vec = [
13862            delta[0] * correction,
13863            delta[1] * correction,
13864            delta[2] * correction,
13865        ];
13866
13867        let new_p1 = [
13868            p1[0] + corr_vec[0],
13869            p1[1] + corr_vec[1],
13870            p1[2] + corr_vec[2],
13871        ];
13872        let new_p2 = [
13873            p2[0] - corr_vec[0],
13874            p2[1] - corr_vec[1],
13875            p2[2] - corr_vec[2],
13876        ];
13877
13878        Ok(Value::Tuple(Rc::new(vec![
13879            make_vec3_arr(new_p1),
13880            make_vec3_arr(new_p2),
13881        ])))
13882    });
13883
13884    // solve_constraints(points, constraints, iterations) - Iterative constraint solver
13885    // constraints: array of {type, indices, params}
13886    define(interp, "solve_constraints", Some(3), |_, args| {
13887        let mut points = match &args[0] {
13888            Value::Array(arr) => arr.borrow().clone(),
13889            _ => {
13890                return Err(RuntimeError::new(
13891                    "solve_constraints: first argument must be array of points",
13892                ))
13893            }
13894        };
13895        let constraints = match &args[1] {
13896            Value::Array(arr) => arr.borrow().clone(),
13897            _ => {
13898                return Err(RuntimeError::new(
13899                    "solve_constraints: second argument must be array of constraints",
13900                ))
13901            }
13902        };
13903        let iterations = match &args[2] {
13904            Value::Int(n) => *n as usize,
13905            _ => {
13906                return Err(RuntimeError::new(
13907                    "solve_constraints: iterations must be integer",
13908                ))
13909            }
13910        };
13911
13912        for _ in 0..iterations {
13913            for constraint in &constraints {
13914                match constraint {
13915                    Value::Map(c) => {
13916                        let c = c.borrow();
13917                        let constraint_type = c
13918                            .get("type")
13919                            .and_then(|v| {
13920                                if let Value::String(s) = v {
13921                                    Some((**s).clone())
13922                                } else {
13923                                    None
13924                                }
13925                            })
13926                            .unwrap_or_default();
13927
13928                        match constraint_type.as_str() {
13929                            "distance" => {
13930                                let indices = match c.get("indices") {
13931                                    Some(Value::Array(arr)) => arr.borrow().clone(),
13932                                    _ => continue,
13933                                };
13934                                let target = match c.get("distance") {
13935                                    Some(Value::Float(f)) => *f,
13936                                    Some(Value::Int(n)) => *n as f64,
13937                                    _ => continue,
13938                                };
13939
13940                                if indices.len() >= 2 {
13941                                    let i1 = match &indices[0] {
13942                                        Value::Int(n) => *n as usize,
13943                                        _ => continue,
13944                                    };
13945                                    let i2 = match &indices[1] {
13946                                        Value::Int(n) => *n as usize,
13947                                        _ => continue,
13948                                    };
13949
13950                                    if i1 < points.len() && i2 < points.len() {
13951                                        // Apply distance constraint inline
13952                                        let p1 = extract_vec3(&points[i1], "solve")?;
13953                                        let p2 = extract_vec3(&points[i2], "solve")?;
13954
13955                                        let delta = [p2[0] - p1[0], p2[1] - p1[1], p2[2] - p1[2]];
13956                                        let length = (delta[0] * delta[0]
13957                                            + delta[1] * delta[1]
13958                                            + delta[2] * delta[2])
13959                                            .sqrt();
13960
13961                                        if length > 1e-10 {
13962                                            let correction = (length - target) / length * 0.5;
13963                                            let corr_vec = [
13964                                                delta[0] * correction,
13965                                                delta[1] * correction,
13966                                                delta[2] * correction,
13967                                            ];
13968
13969                                            points[i1] = make_vec3_arr([
13970                                                p1[0] + corr_vec[0],
13971                                                p1[1] + corr_vec[1],
13972                                                p1[2] + corr_vec[2],
13973                                            ]);
13974                                            points[i2] = make_vec3_arr([
13975                                                p2[0] - corr_vec[0],
13976                                                p2[1] - corr_vec[1],
13977                                                p2[2] - corr_vec[2],
13978                                            ]);
13979                                        }
13980                                    }
13981                                }
13982                            }
13983                            _ => {}
13984                        }
13985                    }
13986                    _ => continue,
13987                }
13988            }
13989        }
13990
13991        Ok(Value::Array(Rc::new(RefCell::new(points))))
13992    });
13993
13994    // ray_sphere_intersect(ray_origin, ray_dir, sphere_center, radius) - Ray-sphere intersection
13995    // Returns distance to intersection or -1 if no hit
13996    define(interp, "ray_sphere_intersect", Some(4), |_, args| {
13997        let origin = extract_vec3(&args[0], "ray_sphere_intersect")?;
13998        let dir = extract_vec3(&args[1], "ray_sphere_intersect")?;
13999        let center = extract_vec3(&args[2], "ray_sphere_intersect")?;
14000        let radius = match &args[3] {
14001            Value::Float(f) => *f,
14002            Value::Int(n) => *n as f64,
14003            _ => {
14004                return Err(RuntimeError::new(
14005                    "ray_sphere_intersect: radius must be numeric",
14006                ))
14007            }
14008        };
14009
14010        let oc = [
14011            origin[0] - center[0],
14012            origin[1] - center[1],
14013            origin[2] - center[2],
14014        ];
14015
14016        let a = dir[0] * dir[0] + dir[1] * dir[1] + dir[2] * dir[2];
14017        let b = 2.0 * (oc[0] * dir[0] + oc[1] * dir[1] + oc[2] * dir[2]);
14018        let c = oc[0] * oc[0] + oc[1] * oc[1] + oc[2] * oc[2] - radius * radius;
14019
14020        let discriminant = b * b - 4.0 * a * c;
14021
14022        if discriminant < 0.0 {
14023            Ok(Value::Float(-1.0))
14024        } else {
14025            let t = (-b - discriminant.sqrt()) / (2.0 * a);
14026            if t > 0.0 {
14027                Ok(Value::Float(t))
14028            } else {
14029                let t2 = (-b + discriminant.sqrt()) / (2.0 * a);
14030                if t2 > 0.0 {
14031                    Ok(Value::Float(t2))
14032                } else {
14033                    Ok(Value::Float(-1.0))
14034                }
14035            }
14036        }
14037    });
14038
14039    // ray_plane_intersect(ray_origin, ray_dir, plane_point, plane_normal) - Ray-plane intersection
14040    define(interp, "ray_plane_intersect", Some(4), |_, args| {
14041        let origin = extract_vec3(&args[0], "ray_plane_intersect")?;
14042        let dir = extract_vec3(&args[1], "ray_plane_intersect")?;
14043        let plane_pt = extract_vec3(&args[2], "ray_plane_intersect")?;
14044        let normal = extract_vec3(&args[3], "ray_plane_intersect")?;
14045
14046        let denom = dir[0] * normal[0] + dir[1] * normal[1] + dir[2] * normal[2];
14047
14048        if denom.abs() < 1e-10 {
14049            return Ok(Value::Float(-1.0)); // Parallel to plane
14050        }
14051
14052        let diff = [
14053            plane_pt[0] - origin[0],
14054            plane_pt[1] - origin[1],
14055            plane_pt[2] - origin[2],
14056        ];
14057        let t = (diff[0] * normal[0] + diff[1] * normal[1] + diff[2] * normal[2]) / denom;
14058
14059        if t > 0.0 {
14060            Ok(Value::Float(t))
14061        } else {
14062            Ok(Value::Float(-1.0))
14063        }
14064    });
14065}
14066
14067// ============================================================================
14068// GEOMETRIC ALGEBRA (GA3D - Cl(3,0,0))
14069// ============================================================================
14070//
14071// Complete Clifford Algebra implementation in 3D. Geometric Algebra unifies:
14072// - Complex numbers (as rotations in 2D)
14073// - Quaternions (as rotors in 3D)
14074// - Vectors, bivectors, and trivectors
14075// - Reflections, rotations, and projections
14076//
14077// ## Multivector Structure
14078//
14079// | Grade | Basis | Name | Geometric Meaning |
14080// |-------|-------|------|-------------------|
14081// | 0 | 1 | Scalar | Magnitude |
14082// | 1 | e₁, e₂, e₃ | Vectors | Directed lengths |
14083// | 2 | e₁₂, e₂₃, e₃₁ | Bivectors | Oriented planes |
14084// | 3 | e₁₂₃ | Trivector | Oriented volume |
14085//
14086// ## Key Operations
14087//
14088// | Function | Description | Mathematical Form |
14089// |----------|-------------|-------------------|
14090// | `mv_new(s, e1..e123)` | Create multivector | s + e₁v₁ + ... + e₁₂₃t |
14091// | `mv_geometric_product(a, b)` | Geometric product | ab (non-commutative) |
14092// | `mv_inner_product(a, b)` | Inner product | a·b |
14093// | `mv_outer_product(a, b)` | Outer product | a∧b (wedge) |
14094// | `rotor_from_axis_angle(axis, θ)` | Create rotor | cos(θ/2) + sin(θ/2)·B |
14095// | `rotor_apply(R, v)` | Apply rotor | RvR† (sandwich) |
14096//
14097// ## Rotor Properties
14098//
14099// Rotors are normalized even-grade multivectors (scalar + bivector).
14100// They rotate vectors via the "sandwich product": v' = RvR†
14101// This is more efficient than matrix multiplication and composes naturally.
14102//
14103// ## Usage Examples
14104//
14105// ```sigil
14106// // Create a 90° rotation around Z-axis
14107// let axis = vec3(0, 0, 1);
14108// let R = rotor_from_axis_angle(axis, PI / 2.0);
14109//
14110// // Rotate a vector
14111// let v = vec3(1, 0, 0);
14112// let v_rotated = rotor_apply(R, v);  // Returns [0, 1, 0]
14113//
14114// // Compose rotations
14115// let R2 = rotor_from_axis_angle(vec3(0, 1, 0), PI / 4.0);
14116// let R_combined = rotor_compose(R, R2);  // First R, then R2
14117// ```
14118//
14119// ## Grade Extraction
14120//
14121// | Function | Returns |
14122// |----------|---------|
14123// | `mv_grade(mv, 0)` | Scalar part |
14124// | `mv_grade(mv, 1)` | Vector part |
14125// | `mv_grade(mv, 2)` | Bivector part |
14126// | `mv_grade(mv, 3)` | Trivector part |
14127
14128fn register_geometric_algebra(interp: &mut Interpreter) {
14129    // Helper to create a multivector from 8 components
14130    fn make_multivector(components: [f64; 8]) -> Value {
14131        let mut mv = HashMap::new();
14132        mv.insert("s".to_string(), Value::Float(components[0])); // scalar
14133        mv.insert("e1".to_string(), Value::Float(components[1])); // e₁
14134        mv.insert("e2".to_string(), Value::Float(components[2])); // e₂
14135        mv.insert("e3".to_string(), Value::Float(components[3])); // e₃
14136        mv.insert("e12".to_string(), Value::Float(components[4])); // e₁₂
14137        mv.insert("e23".to_string(), Value::Float(components[5])); // e₂₃
14138        mv.insert("e31".to_string(), Value::Float(components[6])); // e₃₁
14139        mv.insert("e123".to_string(), Value::Float(components[7])); // e₁₂₃ (pseudoscalar)
14140        mv.insert(
14141            "_type".to_string(),
14142            Value::String(Rc::new("multivector".to_string())),
14143        );
14144        Value::Map(Rc::new(RefCell::new(mv)))
14145    }
14146
14147    fn extract_multivector(v: &Value, fn_name: &str) -> Result<[f64; 8], RuntimeError> {
14148        match v {
14149            Value::Map(map) => {
14150                let map = map.borrow();
14151                let get_component = |key: &str| -> f64 {
14152                    match map.get(key) {
14153                        Some(Value::Float(f)) => *f,
14154                        Some(Value::Int(n)) => *n as f64,
14155                        _ => 0.0,
14156                    }
14157                };
14158                Ok([
14159                    get_component("s"),
14160                    get_component("e1"),
14161                    get_component("e2"),
14162                    get_component("e3"),
14163                    get_component("e12"),
14164                    get_component("e23"),
14165                    get_component("e31"),
14166                    get_component("e123"),
14167                ])
14168            }
14169            _ => Err(RuntimeError::new(format!(
14170                "{}: expected multivector",
14171                fn_name
14172            ))),
14173        }
14174    }
14175
14176    // mv_new(s, e1, e2, e3, e12, e23, e31, e123) - Create multivector from components
14177    define(interp, "mv_new", Some(8), |_, args| {
14178        let mut components = [0.0f64; 8];
14179        for (i, arg) in args.iter().enumerate().take(8) {
14180            components[i] = match arg {
14181                Value::Float(f) => *f,
14182                Value::Int(n) => *n as f64,
14183                _ => 0.0,
14184            };
14185        }
14186        Ok(make_multivector(components))
14187    });
14188
14189    // mv_scalar(s) - Create scalar multivector
14190    define(interp, "mv_scalar", Some(1), |_, args| {
14191        let s = match &args[0] {
14192            Value::Float(f) => *f,
14193            Value::Int(n) => *n as f64,
14194            _ => return Err(RuntimeError::new("mv_scalar: expected number")),
14195        };
14196        Ok(make_multivector([s, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]))
14197    });
14198
14199    // mv_vector(x, y, z) - Create vector (grade-1 multivector)
14200    define(interp, "mv_vector", Some(3), |_, args| {
14201        let x = match &args[0] {
14202            Value::Float(f) => *f,
14203            Value::Int(n) => *n as f64,
14204            _ => 0.0,
14205        };
14206        let y = match &args[1] {
14207            Value::Float(f) => *f,
14208            Value::Int(n) => *n as f64,
14209            _ => 0.0,
14210        };
14211        let z = match &args[2] {
14212            Value::Float(f) => *f,
14213            Value::Int(n) => *n as f64,
14214            _ => 0.0,
14215        };
14216        Ok(make_multivector([0.0, x, y, z, 0.0, 0.0, 0.0, 0.0]))
14217    });
14218
14219    // mv_bivector(xy, yz, zx) - Create bivector (grade-2, represents oriented planes)
14220    define(interp, "mv_bivector", Some(3), |_, args| {
14221        let xy = match &args[0] {
14222            Value::Float(f) => *f,
14223            Value::Int(n) => *n as f64,
14224            _ => 0.0,
14225        };
14226        let yz = match &args[1] {
14227            Value::Float(f) => *f,
14228            Value::Int(n) => *n as f64,
14229            _ => 0.0,
14230        };
14231        let zx = match &args[2] {
14232            Value::Float(f) => *f,
14233            Value::Int(n) => *n as f64,
14234            _ => 0.0,
14235        };
14236        Ok(make_multivector([0.0, 0.0, 0.0, 0.0, xy, yz, zx, 0.0]))
14237    });
14238
14239    // mv_trivector(xyz) - Create trivector/pseudoscalar (grade-3, represents oriented volume)
14240    define(interp, "mv_trivector", Some(1), |_, args| {
14241        let xyz = match &args[0] {
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, 0.0, 0.0, 0.0, xyz]))
14247    });
14248
14249    // mv_add(a, b) - Add two multivectors
14250    define(interp, "mv_add", Some(2), |_, args| {
14251        let a = extract_multivector(&args[0], "mv_add")?;
14252        let b = extract_multivector(&args[1], "mv_add")?;
14253        Ok(make_multivector([
14254            a[0] + b[0],
14255            a[1] + b[1],
14256            a[2] + b[2],
14257            a[3] + b[3],
14258            a[4] + b[4],
14259            a[5] + b[5],
14260            a[6] + b[6],
14261            a[7] + b[7],
14262        ]))
14263    });
14264
14265    // mv_sub(a, b) - Subtract two multivectors
14266    define(interp, "mv_sub", Some(2), |_, args| {
14267        let a = extract_multivector(&args[0], "mv_sub")?;
14268        let b = extract_multivector(&args[1], "mv_sub")?;
14269        Ok(make_multivector([
14270            a[0] - b[0],
14271            a[1] - b[1],
14272            a[2] - b[2],
14273            a[3] - b[3],
14274            a[4] - b[4],
14275            a[5] - b[5],
14276            a[6] - b[6],
14277            a[7] - b[7],
14278        ]))
14279    });
14280
14281    // mv_scale(mv, scalar) - Scale a multivector
14282    define(interp, "mv_scale", Some(2), |_, args| {
14283        let a = extract_multivector(&args[0], "mv_scale")?;
14284        let s = match &args[1] {
14285            Value::Float(f) => *f,
14286            Value::Int(n) => *n as f64,
14287            _ => {
14288                return Err(RuntimeError::new(
14289                    "mv_scale: second argument must be number",
14290                ))
14291            }
14292        };
14293        Ok(make_multivector([
14294            a[0] * s,
14295            a[1] * s,
14296            a[2] * s,
14297            a[3] * s,
14298            a[4] * s,
14299            a[5] * s,
14300            a[6] * s,
14301            a[7] * s,
14302        ]))
14303    });
14304
14305    // mv_geometric(a, b) - Geometric product (THE fundamental operation)
14306    // This is what makes GA powerful: ab = a·b + a∧b
14307    define(interp, "mv_geometric", Some(2), |_, args| {
14308        let a = extract_multivector(&args[0], "mv_geometric")?;
14309        let b = extract_multivector(&args[1], "mv_geometric")?;
14310
14311        // Full geometric product in Cl(3,0,0)
14312        // Using: e₁² = e₂² = e₃² = 1, eᵢeⱼ = -eⱼeᵢ for i≠j
14313        let mut r = [0.0f64; 8];
14314
14315        // Scalar part
14316        r[0] = a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]
14317            - a[4] * b[4]
14318            - a[5] * b[5]
14319            - a[6] * b[6]
14320            - a[7] * b[7];
14321
14322        // e₁ part
14323        r[1] = a[0] * b[1] + a[1] * b[0] - a[2] * b[4] + a[3] * b[6] + a[4] * b[2]
14324            - a[5] * b[7]
14325            - a[6] * b[3]
14326            - a[7] * b[5];
14327
14328        // e₂ part
14329        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]
14330            - a[6] * b[7]
14331            - a[7] * b[6];
14332
14333        // e₃ part
14334        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]
14335            + a[6] * b[1]
14336            - a[7] * b[4];
14337
14338        // e₁₂ part
14339        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]
14340            - a[6] * b[5]
14341            + a[7] * b[3];
14342
14343        // e₂₃ part
14344        r[5] = a[0] * b[5] + a[1] * b[7] + a[2] * b[3] - a[3] * b[2] - a[4] * b[6]
14345            + a[5] * b[0]
14346            + a[6] * b[4]
14347            + a[7] * b[1];
14348
14349        // e₃₁ part
14350        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]
14351            + a[6] * b[0]
14352            + a[7] * b[2];
14353
14354        // e₁₂₃ part
14355        r[7] = a[0] * b[7]
14356            + a[1] * b[5]
14357            + a[2] * b[6]
14358            + a[3] * b[4]
14359            + a[4] * b[3]
14360            + a[5] * b[1]
14361            + a[6] * b[2]
14362            + a[7] * b[0];
14363
14364        Ok(make_multivector(r))
14365    });
14366
14367    // mv_wedge(a, b) - Outer/wedge product (∧) - antisymmetric part
14368    // Creates higher-grade elements: vector ∧ vector = bivector
14369    define(interp, "mv_wedge", Some(2), |_, args| {
14370        let a = extract_multivector(&args[0], "mv_wedge")?;
14371        let b = extract_multivector(&args[1], "mv_wedge")?;
14372
14373        let mut r = [0.0f64; 8];
14374
14375        // Scalar ∧ anything = scalar * anything (grade 0)
14376        r[0] = a[0] * b[0];
14377
14378        // Vector parts (grade 1): s∧v + v∧s
14379        r[1] = a[0] * b[1] + a[1] * b[0];
14380        r[2] = a[0] * b[2] + a[2] * b[0];
14381        r[3] = a[0] * b[3] + a[3] * b[0];
14382
14383        // Bivector parts (grade 2): s∧B + v∧v + B∧s
14384        r[4] = a[0] * b[4] + a[1] * b[2] - a[2] * b[1] + a[4] * b[0];
14385        r[5] = a[0] * b[5] + a[2] * b[3] - a[3] * b[2] + a[5] * b[0];
14386        r[6] = a[0] * b[6] + a[3] * b[1] - a[1] * b[3] + a[6] * b[0];
14387
14388        // Trivector part (grade 3): s∧T + v∧B + B∧v + T∧s
14389        r[7] = a[0] * b[7] + a[7] * b[0] + a[1] * b[5] + a[2] * b[6] + a[3] * b[4]
14390            - a[4] * b[3]
14391            - a[5] * b[1]
14392            - a[6] * b[2];
14393
14394        Ok(make_multivector(r))
14395    });
14396
14397    // mv_inner(a, b) - Inner/dot product (⟂) - symmetric contraction
14398    // Lowers grade: vector · vector = scalar, bivector · vector = vector
14399    define(interp, "mv_inner", Some(2), |_, args| {
14400        let a = extract_multivector(&args[0], "mv_inner")?;
14401        let b = extract_multivector(&args[1], "mv_inner")?;
14402
14403        let mut r = [0.0f64; 8];
14404
14405        // Left contraction formula
14406        // Scalar (vectors dotted)
14407        r[0] = a[1] * b[1] + a[2] * b[2] + a[3] * b[3]
14408            - a[4] * b[4]
14409            - a[5] * b[5]
14410            - a[6] * b[6]
14411            - a[7] * b[7];
14412
14413        // Vector parts (bivector · vector)
14414        r[1] = a[4] * b[2] - a[6] * b[3] - a[5] * b[7];
14415        r[2] = -a[4] * b[1] + a[5] * b[3] - a[6] * b[7];
14416        r[3] = a[6] * b[1] - a[5] * b[2] - a[4] * b[7];
14417
14418        // Bivector parts (trivector · vector)
14419        r[4] = a[7] * b[3];
14420        r[5] = a[7] * b[1];
14421        r[6] = a[7] * b[2];
14422
14423        Ok(make_multivector(r))
14424    });
14425
14426    // mv_reverse(a) - Reverse (†) - reverses order of basis vectors
14427    // (e₁e₂)† = e₂e₁ = -e₁e₂
14428    define(interp, "mv_reverse", Some(1), |_, args| {
14429        let a = extract_multivector(&args[0], "mv_reverse")?;
14430        // Grade 0,1 unchanged; Grade 2,3 negated
14431        Ok(make_multivector([
14432            a[0], a[1], a[2], a[3], -a[4], -a[5], -a[6], -a[7],
14433        ]))
14434    });
14435
14436    // mv_dual(a) - Dual (Hodge star) - multiply by pseudoscalar
14437    // Maps grade k to grade (n-k) in n dimensions
14438    define(interp, "mv_dual", Some(1), |_, args| {
14439        let a = extract_multivector(&args[0], "mv_dual")?;
14440        // In 3D: dual(1) = e123, dual(e1) = e23, etc.
14441        // Multiplying by e123: since e123² = -1 in Cl(3,0,0)
14442        Ok(make_multivector([
14443            -a[7], // s ← -e123
14444            -a[5], // e1 ← -e23
14445            -a[6], // e2 ← -e31
14446            -a[4], // e3 ← -e12
14447            a[3],  // e12 ← e3
14448            a[1],  // e23 ← e1
14449            a[2],  // e31 ← e2
14450            a[0],  // e123 ← s
14451        ]))
14452    });
14453
14454    // mv_magnitude(a) - Magnitude/norm of multivector
14455    define(interp, "mv_magnitude", Some(1), |_, args| {
14456        let a = extract_multivector(&args[0], "mv_magnitude")?;
14457        let mag_sq = a[0] * a[0]
14458            + a[1] * a[1]
14459            + a[2] * a[2]
14460            + a[3] * a[3]
14461            + a[4] * a[4]
14462            + a[5] * a[5]
14463            + a[6] * a[6]
14464            + a[7] * a[7];
14465        Ok(Value::Float(mag_sq.sqrt()))
14466    });
14467
14468    // mv_normalize(a) - Normalize multivector
14469    define(interp, "mv_normalize", Some(1), |_, args| {
14470        let a = extract_multivector(&args[0], "mv_normalize")?;
14471        let mag = (a[0] * a[0]
14472            + a[1] * a[1]
14473            + a[2] * a[2]
14474            + a[3] * a[3]
14475            + a[4] * a[4]
14476            + a[5] * a[5]
14477            + a[6] * a[6]
14478            + a[7] * a[7])
14479            .sqrt();
14480        if mag < 1e-10 {
14481            return Ok(make_multivector([0.0; 8]));
14482        }
14483        Ok(make_multivector([
14484            a[0] / mag,
14485            a[1] / mag,
14486            a[2] / mag,
14487            a[3] / mag,
14488            a[4] / mag,
14489            a[5] / mag,
14490            a[6] / mag,
14491            a[7] / mag,
14492        ]))
14493    });
14494
14495    // rotor_from_axis_angle(axis, angle) - Create rotor from axis-angle
14496    // Rotor R = cos(θ/2) + sin(θ/2) * B where B is the normalized bivector plane
14497    define(interp, "rotor_from_axis_angle", Some(2), |_, args| {
14498        let axis = extract_vec3(&args[0], "rotor_from_axis_angle")?;
14499        let angle = match &args[1] {
14500            Value::Float(f) => *f,
14501            Value::Int(n) => *n as f64,
14502            _ => {
14503                return Err(RuntimeError::new(
14504                    "rotor_from_axis_angle: angle must be number",
14505                ))
14506            }
14507        };
14508
14509        // Normalize axis
14510        let len = (axis[0] * axis[0] + axis[1] * axis[1] + axis[2] * axis[2]).sqrt();
14511        if len < 1e-10 {
14512            // Return identity rotor
14513            return Ok(make_multivector([1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]));
14514        }
14515        let (nx, ny, nz) = (axis[0] / len, axis[1] / len, axis[2] / len);
14516
14517        let half_angle = angle / 2.0;
14518        let (s, c) = half_angle.sin_cos();
14519
14520        // Rotor: cos(θ/2) - sin(θ/2) * (n₁e₂₃ + n₂e₃₁ + n₃e₁₂)
14521        // Note: axis maps to bivector via dual
14522        Ok(make_multivector([
14523            c, // scalar
14524            0.0,
14525            0.0,
14526            0.0,     // no vector part
14527            -s * nz, // e12 (axis z → bivector xy)
14528            -s * nx, // e23 (axis x → bivector yz)
14529            -s * ny, // e31 (axis y → bivector zx)
14530            0.0,     // no trivector
14531        ]))
14532    });
14533
14534    // rotor_apply(rotor, vector) - Apply rotor to vector: RvR†
14535    // This is the sandwich product - THE way to rotate in GA
14536    define(interp, "rotor_apply", Some(2), |_, args| {
14537        let r = extract_multivector(&args[0], "rotor_apply")?;
14538        let v = extract_vec3(&args[1], "rotor_apply")?;
14539
14540        // Create vector multivector
14541        let v_mv = [0.0, v[0], v[1], v[2], 0.0, 0.0, 0.0, 0.0];
14542
14543        // Compute R† (reverse of rotor)
14544        let r_rev = [r[0], r[1], r[2], r[3], -r[4], -r[5], -r[6], -r[7]];
14545
14546        // First: R * v
14547        let mut rv = [0.0f64; 8];
14548        rv[0] = r[0] * v_mv[0] + r[1] * v_mv[1] + r[2] * v_mv[2] + r[3] * v_mv[3]
14549            - r[4] * v_mv[4]
14550            - r[5] * v_mv[5]
14551            - r[6] * v_mv[6]
14552            - r[7] * v_mv[7];
14553        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]
14554            - r[5] * v_mv[7]
14555            - r[6] * v_mv[3]
14556            - r[7] * v_mv[5];
14557        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]
14558            + r[5] * v_mv[3]
14559            - r[6] * v_mv[7]
14560            - r[7] * v_mv[6];
14561        rv[3] = r[0] * v_mv[3] - r[1] * v_mv[6] + r[2] * v_mv[5] + r[3] * v_mv[0]
14562            - r[4] * v_mv[7]
14563            - r[5] * v_mv[2]
14564            + r[6] * v_mv[1]
14565            - r[7] * v_mv[4];
14566        rv[4] = r[0] * v_mv[4] + r[1] * v_mv[2] - r[2] * v_mv[1]
14567            + r[3] * v_mv[7]
14568            + r[4] * v_mv[0]
14569            + r[5] * v_mv[6]
14570            - r[6] * v_mv[5]
14571            + r[7] * v_mv[3];
14572        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]
14573            + r[5] * v_mv[0]
14574            + r[6] * v_mv[4]
14575            + r[7] * v_mv[1];
14576        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]
14577            - r[5] * v_mv[4]
14578            + r[6] * v_mv[0]
14579            + r[7] * v_mv[2];
14580        rv[7] = r[0] * v_mv[7]
14581            + r[1] * v_mv[5]
14582            + r[2] * v_mv[6]
14583            + r[3] * v_mv[4]
14584            + r[4] * v_mv[3]
14585            + r[5] * v_mv[1]
14586            + r[6] * v_mv[2]
14587            + r[7] * v_mv[0];
14588
14589        // Then: (R * v) * R†
14590        let mut result = [0.0f64; 8];
14591        result[1] = rv[0] * r_rev[1] + rv[1] * r_rev[0] - rv[2] * r_rev[4]
14592            + rv[3] * r_rev[6]
14593            + rv[4] * r_rev[2]
14594            - rv[5] * r_rev[7]
14595            - rv[6] * r_rev[3]
14596            - rv[7] * r_rev[5];
14597        result[2] = rv[0] * r_rev[2] + rv[1] * r_rev[4] + rv[2] * r_rev[0]
14598            - rv[3] * r_rev[5]
14599            - rv[4] * r_rev[1]
14600            + rv[5] * r_rev[3]
14601            - rv[6] * r_rev[7]
14602            - rv[7] * r_rev[6];
14603        result[3] = rv[0] * r_rev[3] - rv[1] * r_rev[6] + rv[2] * r_rev[5] + rv[3] * r_rev[0]
14604            - rv[4] * r_rev[7]
14605            - rv[5] * r_rev[2]
14606            + rv[6] * r_rev[1]
14607            - rv[7] * r_rev[4];
14608
14609        // Return as vec3
14610        Ok(make_vec3(result[1], result[2], result[3]))
14611    });
14612
14613    // rotor_compose(r1, r2) - Compose rotors: R1 * R2
14614    define(interp, "rotor_compose", Some(2), |_, args| {
14615        let a = extract_multivector(&args[0], "rotor_compose")?;
14616        let b = extract_multivector(&args[1], "rotor_compose")?;
14617
14618        // Same as geometric product
14619        let mut r = [0.0f64; 8];
14620        r[0] = a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]
14621            - a[4] * b[4]
14622            - a[5] * b[5]
14623            - a[6] * b[6]
14624            - a[7] * b[7];
14625        r[1] = a[0] * b[1] + a[1] * b[0] - a[2] * b[4] + a[3] * b[6] + a[4] * b[2]
14626            - a[5] * b[7]
14627            - a[6] * b[3]
14628            - a[7] * b[5];
14629        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]
14630            - a[6] * b[7]
14631            - a[7] * b[6];
14632        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]
14633            + a[6] * b[1]
14634            - a[7] * b[4];
14635        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]
14636            - a[6] * b[5]
14637            + a[7] * b[3];
14638        r[5] = a[0] * b[5] + a[1] * b[7] + a[2] * b[3] - a[3] * b[2] - a[4] * b[6]
14639            + a[5] * b[0]
14640            + a[6] * b[4]
14641            + a[7] * b[1];
14642        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]
14643            + a[6] * b[0]
14644            + a[7] * b[2];
14645        r[7] = a[0] * b[7]
14646            + a[1] * b[5]
14647            + a[2] * b[6]
14648            + a[3] * b[4]
14649            + a[4] * b[3]
14650            + a[5] * b[1]
14651            + a[6] * b[2]
14652            + a[7] * b[0];
14653
14654        Ok(make_multivector(r))
14655    });
14656
14657    // mv_reflect(v, n) - Reflect vector v in plane with normal n
14658    // Reflection: -n * v * n (sandwich with negative)
14659    define(interp, "mv_reflect", Some(2), |_, args| {
14660        let v = extract_vec3(&args[0], "mv_reflect")?;
14661        let n = extract_vec3(&args[1], "mv_reflect")?;
14662
14663        // Normalize n
14664        let len = (n[0] * n[0] + n[1] * n[1] + n[2] * n[2]).sqrt();
14665        if len < 1e-10 {
14666            return Ok(make_vec3(v[0], v[1], v[2]));
14667        }
14668        let (nx, ny, nz) = (n[0] / len, n[1] / len, n[2] / len);
14669
14670        // v - 2(v·n)n
14671        let dot = v[0] * nx + v[1] * ny + v[2] * nz;
14672        Ok(make_vec3(
14673            v[0] - 2.0 * dot * nx,
14674            v[1] - 2.0 * dot * ny,
14675            v[2] - 2.0 * dot * nz,
14676        ))
14677    });
14678
14679    // mv_project(v, n) - Project vector v onto plane with normal n
14680    define(interp, "mv_project", Some(2), |_, args| {
14681        let v = extract_vec3(&args[0], "mv_project")?;
14682        let n = extract_vec3(&args[1], "mv_project")?;
14683
14684        let len = (n[0] * n[0] + n[1] * n[1] + n[2] * n[2]).sqrt();
14685        if len < 1e-10 {
14686            return Ok(make_vec3(v[0], v[1], v[2]));
14687        }
14688        let (nx, ny, nz) = (n[0] / len, n[1] / len, n[2] / len);
14689
14690        // v - (v·n)n
14691        let dot = v[0] * nx + v[1] * ny + v[2] * nz;
14692        Ok(make_vec3(v[0] - dot * nx, v[1] - dot * ny, v[2] - dot * nz))
14693    });
14694
14695    // mv_grade(mv, k) - Extract grade-k part of multivector
14696    define(interp, "mv_grade", Some(2), |_, args| {
14697        let a = extract_multivector(&args[0], "mv_grade")?;
14698        let k = match &args[1] {
14699            Value::Int(n) => *n,
14700            _ => return Err(RuntimeError::new("mv_grade: grade must be integer")),
14701        };
14702
14703        match k {
14704            0 => Ok(make_multivector([a[0], 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0])),
14705            1 => Ok(make_multivector([
14706                0.0, a[1], a[2], a[3], 0.0, 0.0, 0.0, 0.0,
14707            ])),
14708            2 => Ok(make_multivector([
14709                0.0, 0.0, 0.0, 0.0, a[4], a[5], a[6], 0.0,
14710            ])),
14711            3 => Ok(make_multivector([0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, a[7]])),
14712            _ => Ok(make_multivector([0.0; 8])),
14713        }
14714    });
14715}
14716
14717// ============================================================================
14718// DIMENSIONAL ANALYSIS (Unit-aware arithmetic)
14719// ============================================================================
14720// Automatic unit tracking and conversion - catch physics errors at runtime
14721// Base SI units: m (length), kg (mass), s (time), A (current), K (temperature), mol, cd
14722
14723fn register_dimensional(interp: &mut Interpreter) {
14724    // Helper to create a quantity with units
14725    // Units stored as exponents: [m, kg, s, A, K, mol, cd]
14726    fn make_quantity(value: f64, units: [i32; 7]) -> Value {
14727        let mut q = HashMap::new();
14728        q.insert("value".to_string(), Value::Float(value));
14729        q.insert("m".to_string(), Value::Int(units[0] as i64)); // meters
14730        q.insert("kg".to_string(), Value::Int(units[1] as i64)); // kilograms
14731        q.insert("s".to_string(), Value::Int(units[2] as i64)); // seconds
14732        q.insert("A".to_string(), Value::Int(units[3] as i64)); // amperes
14733        q.insert("K".to_string(), Value::Int(units[4] as i64)); // kelvin
14734        q.insert("mol".to_string(), Value::Int(units[5] as i64)); // moles
14735        q.insert("cd".to_string(), Value::Int(units[6] as i64)); // candela
14736        q.insert(
14737            "_type".to_string(),
14738            Value::String(Rc::new("quantity".to_string())),
14739        );
14740        Value::Map(Rc::new(RefCell::new(q)))
14741    }
14742
14743    fn extract_quantity(v: &Value, fn_name: &str) -> Result<(f64, [i32; 7]), RuntimeError> {
14744        match v {
14745            Value::Map(map) => {
14746                let map = map.borrow();
14747                let value = match map.get("value") {
14748                    Some(Value::Float(f)) => *f,
14749                    Some(Value::Int(n)) => *n as f64,
14750                    _ => return Err(RuntimeError::new(format!("{}: missing value", fn_name))),
14751                };
14752                let get_exp = |key: &str| -> i32 {
14753                    match map.get(key) {
14754                        Some(Value::Int(n)) => *n as i32,
14755                        _ => 0,
14756                    }
14757                };
14758                Ok((
14759                    value,
14760                    [
14761                        get_exp("m"),
14762                        get_exp("kg"),
14763                        get_exp("s"),
14764                        get_exp("A"),
14765                        get_exp("K"),
14766                        get_exp("mol"),
14767                        get_exp("cd"),
14768                    ],
14769                ))
14770            }
14771            Value::Float(f) => Ok((*f, [0; 7])),
14772            Value::Int(n) => Ok((*n as f64, [0; 7])),
14773            _ => Err(RuntimeError::new(format!(
14774                "{}: expected quantity or number",
14775                fn_name
14776            ))),
14777        }
14778    }
14779
14780    fn units_to_string(units: [i32; 7]) -> String {
14781        let names = ["m", "kg", "s", "A", "K", "mol", "cd"];
14782        let mut parts = Vec::new();
14783        for (i, &exp) in units.iter().enumerate() {
14784            if exp == 1 {
14785                parts.push(names[i].to_string());
14786            } else if exp != 0 {
14787                parts.push(format!("{}^{}", names[i], exp));
14788            }
14789        }
14790        if parts.is_empty() {
14791            "dimensionless".to_string()
14792        } else {
14793            parts.join("·")
14794        }
14795    }
14796
14797    // qty(value, unit_string) - Create quantity with units
14798    // e.g., qty(9.8, "m/s^2") for acceleration
14799    define(interp, "qty", Some(2), |_, args| {
14800        let value = match &args[0] {
14801            Value::Float(f) => *f,
14802            Value::Int(n) => *n as f64,
14803            _ => return Err(RuntimeError::new("qty: first argument must be number")),
14804        };
14805        let unit_str = match &args[1] {
14806            Value::String(s) => s.to_string(),
14807            _ => {
14808                return Err(RuntimeError::new(
14809                    "qty: second argument must be unit string",
14810                ))
14811            }
14812        };
14813
14814        // Parse unit string
14815        let mut units = [0i32; 7];
14816        // Simplified: if '/' present, treat everything as denominator
14817        // For proper parsing, would need to track position relative to '/'
14818        let in_denominator = unit_str.contains('/');
14819
14820        // Simple parser for common units
14821        for part in unit_str.split(|c: char| c == '*' || c == '·' || c == ' ') {
14822            let part = part.trim();
14823            if part.is_empty() {
14824                continue;
14825            }
14826
14827            let (base, exp) = if let Some(idx) = part.find('^') {
14828                let (b, e) = part.split_at(idx);
14829                (b, e[1..].parse::<i32>().unwrap_or(1))
14830            } else if part.contains('/') {
14831                // Handle division inline
14832                continue;
14833            } else {
14834                (part, 1)
14835            };
14836
14837            let sign = if in_denominator { -1 } else { 1 };
14838            match base {
14839                "m" | "meter" | "meters" => units[0] += exp * sign,
14840                "kg" | "kilogram" | "kilograms" => units[1] += exp * sign,
14841                "s" | "sec" | "second" | "seconds" => units[2] += exp * sign,
14842                "A" | "amp" | "ampere" | "amperes" => units[3] += exp * sign,
14843                "K" | "kelvin" => units[4] += exp * sign,
14844                "mol" | "mole" | "moles" => units[5] += exp * sign,
14845                "cd" | "candela" => units[6] += exp * sign,
14846                // Derived units
14847                "N" | "newton" | "newtons" => {
14848                    units[1] += sign;
14849                    units[0] += sign;
14850                    units[2] -= 2 * sign;
14851                }
14852                "J" | "joule" | "joules" => {
14853                    units[1] += sign;
14854                    units[0] += 2 * sign;
14855                    units[2] -= 2 * sign;
14856                }
14857                "W" | "watt" | "watts" => {
14858                    units[1] += sign;
14859                    units[0] += 2 * sign;
14860                    units[2] -= 3 * sign;
14861                }
14862                "Pa" | "pascal" | "pascals" => {
14863                    units[1] += sign;
14864                    units[0] -= sign;
14865                    units[2] -= 2 * sign;
14866                }
14867                "Hz" | "hertz" => {
14868                    units[2] -= sign;
14869                }
14870                "C" | "coulomb" | "coulombs" => {
14871                    units[3] += sign;
14872                    units[2] += sign;
14873                }
14874                "V" | "volt" | "volts" => {
14875                    units[1] += sign;
14876                    units[0] += 2 * sign;
14877                    units[2] -= 3 * sign;
14878                    units[3] -= sign;
14879                }
14880                "Ω" | "ohm" | "ohms" => {
14881                    units[1] += sign;
14882                    units[0] += 2 * sign;
14883                    units[2] -= 3 * sign;
14884                    units[3] -= 2 * sign;
14885                }
14886                _ => {}
14887            }
14888        }
14889
14890        Ok(make_quantity(value, units))
14891    });
14892
14893    // qty_add(a, b) - Add quantities (must have same units)
14894    define(interp, "qty_add", Some(2), |_, args| {
14895        let (val_a, units_a) = extract_quantity(&args[0], "qty_add")?;
14896        let (val_b, units_b) = extract_quantity(&args[1], "qty_add")?;
14897
14898        if units_a != units_b {
14899            return Err(RuntimeError::new(format!(
14900                "qty_add: unit mismatch: {} vs {}",
14901                units_to_string(units_a),
14902                units_to_string(units_b)
14903            )));
14904        }
14905
14906        Ok(make_quantity(val_a + val_b, units_a))
14907    });
14908
14909    // qty_sub(a, b) - Subtract quantities (must have same units)
14910    define(interp, "qty_sub", Some(2), |_, args| {
14911        let (val_a, units_a) = extract_quantity(&args[0], "qty_sub")?;
14912        let (val_b, units_b) = extract_quantity(&args[1], "qty_sub")?;
14913
14914        if units_a != units_b {
14915            return Err(RuntimeError::new(format!(
14916                "qty_sub: unit mismatch: {} vs {}",
14917                units_to_string(units_a),
14918                units_to_string(units_b)
14919            )));
14920        }
14921
14922        Ok(make_quantity(val_a - val_b, units_a))
14923    });
14924
14925    // qty_mul(a, b) - Multiply quantities (units add)
14926    define(interp, "qty_mul", Some(2), |_, args| {
14927        let (val_a, units_a) = extract_quantity(&args[0], "qty_mul")?;
14928        let (val_b, units_b) = extract_quantity(&args[1], "qty_mul")?;
14929
14930        let mut result_units = [0i32; 7];
14931        for i in 0..7 {
14932            result_units[i] = units_a[i] + units_b[i];
14933        }
14934
14935        Ok(make_quantity(val_a * val_b, result_units))
14936    });
14937
14938    // qty_div(a, b) - Divide quantities (units subtract)
14939    define(interp, "qty_div", Some(2), |_, args| {
14940        let (val_a, units_a) = extract_quantity(&args[0], "qty_div")?;
14941        let (val_b, units_b) = extract_quantity(&args[1], "qty_div")?;
14942
14943        if val_b.abs() < 1e-15 {
14944            return Err(RuntimeError::new("qty_div: division by zero"));
14945        }
14946
14947        let mut result_units = [0i32; 7];
14948        for i in 0..7 {
14949            result_units[i] = units_a[i] - units_b[i];
14950        }
14951
14952        Ok(make_quantity(val_a / val_b, result_units))
14953    });
14954
14955    // qty_pow(q, n) - Raise quantity to power (units multiply)
14956    define(interp, "qty_pow", Some(2), |_, args| {
14957        let (val, units) = extract_quantity(&args[0], "qty_pow")?;
14958        let n = match &args[1] {
14959            Value::Int(n) => *n as i32,
14960            Value::Float(f) => *f as i32,
14961            _ => return Err(RuntimeError::new("qty_pow: exponent must be number")),
14962        };
14963
14964        let mut result_units = [0i32; 7];
14965        for i in 0..7 {
14966            result_units[i] = units[i] * n;
14967        }
14968
14969        Ok(make_quantity(val.powi(n), result_units))
14970    });
14971
14972    // qty_sqrt(q) - Square root of quantity (units halve)
14973    define(interp, "qty_sqrt", Some(1), |_, args| {
14974        let (val, units) = extract_quantity(&args[0], "qty_sqrt")?;
14975
14976        // Check that all exponents are even
14977        for (i, &exp) in units.iter().enumerate() {
14978            if exp % 2 != 0 {
14979                let names = ["m", "kg", "s", "A", "K", "mol", "cd"];
14980                return Err(RuntimeError::new(format!(
14981                    "qty_sqrt: cannot take sqrt of {} (odd exponent on {})",
14982                    units_to_string(units),
14983                    names[i]
14984                )));
14985            }
14986        }
14987
14988        let mut result_units = [0i32; 7];
14989        for i in 0..7 {
14990            result_units[i] = units[i] / 2;
14991        }
14992
14993        Ok(make_quantity(val.sqrt(), result_units))
14994    });
14995
14996    // qty_value(q) - Get numeric value of quantity
14997    define(interp, "qty_value", Some(1), |_, args| {
14998        let (val, _) = extract_quantity(&args[0], "qty_value")?;
14999        Ok(Value::Float(val))
15000    });
15001
15002    // qty_units(q) - Get units as string
15003    define(interp, "qty_units", Some(1), |_, args| {
15004        let (_, units) = extract_quantity(&args[0], "qty_units")?;
15005        Ok(Value::String(Rc::new(units_to_string(units))))
15006    });
15007
15008    // qty_convert(q, target_units) - Convert to different units
15009    // Currently just validates compatible dimensions
15010    define(interp, "qty_convert", Some(2), |_, args| {
15011        let (val, units) = extract_quantity(&args[0], "qty_convert")?;
15012        let _target = match &args[1] {
15013            Value::String(s) => s.to_string(),
15014            _ => return Err(RuntimeError::new("qty_convert: target must be unit string")),
15015        };
15016
15017        // For now, just return with same value if dimensions match
15018        // A full implementation would handle unit prefixes (kilo, milli, etc.)
15019        Ok(make_quantity(val, units))
15020    });
15021
15022    // qty_check(q, expected_units) - Check if quantity has expected dimensions
15023    define(interp, "qty_check", Some(2), |_, args| {
15024        let (_, units) = extract_quantity(&args[0], "qty_check")?;
15025        let expected = match &args[1] {
15026            Value::String(s) => s.to_string(),
15027            _ => return Err(RuntimeError::new("qty_check: expected string")),
15028        };
15029
15030        // Quick dimension check by comparing unit string patterns
15031        let actual_str = units_to_string(units);
15032        Ok(Value::Bool(
15033            actual_str.contains(&expected) || expected.contains(&actual_str),
15034        ))
15035    });
15036
15037    // Common physical constants with units
15038    // c - speed of light
15039    define(interp, "c_light", Some(0), |_, _| {
15040        Ok(make_quantity(299792458.0, [1, 0, -1, 0, 0, 0, 0])) // m/s
15041    });
15042
15043    // G - gravitational constant
15044    define(interp, "G_gravity", Some(0), |_, _| {
15045        Ok(make_quantity(6.67430e-11, [3, -1, -2, 0, 0, 0, 0])) // m³/(kg·s²)
15046    });
15047
15048    // h - Planck constant
15049    define(interp, "h_planck", Some(0), |_, _| {
15050        Ok(make_quantity(6.62607015e-34, [2, 1, -1, 0, 0, 0, 0])) // J·s = m²·kg/s
15051    });
15052
15053    // e - elementary charge
15054    define(interp, "e_charge", Some(0), |_, _| {
15055        Ok(make_quantity(1.602176634e-19, [0, 0, 1, 1, 0, 0, 0])) // C = A·s
15056    });
15057
15058    // k_B - Boltzmann constant
15059    define(interp, "k_boltzmann", Some(0), |_, _| {
15060        Ok(make_quantity(1.380649e-23, [2, 1, -2, 0, -1, 0, 0])) // J/K = m²·kg/(s²·K)
15061    });
15062}
15063
15064// ============================================================================
15065// ENTITY COMPONENT SYSTEM (ECS)
15066// ============================================================================
15067//
15068// A lightweight Entity Component System for game development and simulations.
15069// ECS separates data (components) from behavior (systems) for maximum flexibility.
15070//
15071// ## Core Concepts
15072//
15073// | Concept | Description |
15074// |---------|-------------|
15075// | World | Container for all entities and components |
15076// | Entity | Unique ID representing a game object |
15077// | Component | Data attached to an entity (position, velocity, health) |
15078// | Query | Retrieve entities with specific components |
15079//
15080// ## Available Functions
15081//
15082// ### World Management
15083// | Function | Description |
15084// |----------|-------------|
15085// | `ecs_world()` | Create a new ECS world |
15086// | `ecs_count(world)` | Count total entities |
15087//
15088// ### Entity Management
15089// | Function | Description |
15090// |----------|-------------|
15091// | `ecs_spawn(world)` | Create entity, returns ID |
15092// | `ecs_despawn(world, id)` | Remove entity and components |
15093// | `ecs_exists(world, id)` | Check if entity exists |
15094//
15095// ### Component Management
15096// | Function | Description |
15097// |----------|-------------|
15098// | `ecs_attach(world, id, name, data)` | Add component to entity |
15099// | `ecs_detach(world, id, name)` | Remove component |
15100// | `ecs_get(world, id, name)` | Get component data |
15101// | `ecs_has(world, id, name)` | Check if entity has component |
15102//
15103// ### Querying
15104// | Function | Description |
15105// |----------|-------------|
15106// | `ecs_query(world, ...names)` | Find entities with all listed components |
15107// | `ecs_query_any(world, ...names)` | Find entities with any listed component |
15108//
15109// ## Usage Example
15110//
15111// ```sigil
15112// // Create world and entities
15113// let world = ecs_world();
15114// let player = ecs_spawn(world);
15115// let enemy = ecs_spawn(world);
15116//
15117// // Attach components
15118// ecs_attach(world, player, "Position", vec3(0, 0, 0));
15119// ecs_attach(world, player, "Velocity", vec3(1, 0, 0));
15120// ecs_attach(world, player, "Health", 100);
15121//
15122// ecs_attach(world, enemy, "Position", vec3(10, 0, 0));
15123// ecs_attach(world, enemy, "Health", 50);
15124//
15125// // Query all entities with Position and Health
15126// let living = ecs_query(world, "Position", "Health");
15127// // Returns [player_id, enemy_id]
15128//
15129// // Update loop
15130// for id in ecs_query(world, "Position", "Velocity") {
15131//     let pos = ecs_get(world, id, "Position");
15132//     let vel = ecs_get(world, id, "Velocity");
15133//     ecs_attach(world, id, "Position", vec3_add(pos, vel));
15134// }
15135// ```
15136//
15137// ## Performance Notes
15138//
15139// - Queries are O(entities) - for large worlds, consider caching results
15140// - Component access is O(1) via hash lookup
15141// - Entity spawning is O(1)
15142
15143fn register_ecs(interp: &mut Interpreter) {
15144    // ecs_world() - Create new ECS world
15145    define(interp, "ecs_world", Some(0), |_, _| {
15146        let mut world = HashMap::new();
15147        world.insert(
15148            "_type".to_string(),
15149            Value::String(Rc::new("ecs_world".to_string())),
15150        );
15151        world.insert("next_id".to_string(), Value::Int(0));
15152        world.insert(
15153            "entities".to_string(),
15154            Value::Map(Rc::new(RefCell::new(HashMap::new()))),
15155        );
15156        world.insert(
15157            "components".to_string(),
15158            Value::Map(Rc::new(RefCell::new(HashMap::new()))),
15159        );
15160        Ok(Value::Map(Rc::new(RefCell::new(world))))
15161    });
15162
15163    // ecs_spawn(world) - Spawn new entity, returns entity ID
15164    define(interp, "ecs_spawn", Some(1), |_, args| {
15165        let world = match &args[0] {
15166            Value::Map(m) => m.clone(),
15167            _ => return Err(RuntimeError::new("ecs_spawn: expected world")),
15168        };
15169
15170        let mut world_ref = world.borrow_mut();
15171        let id = match world_ref.get("next_id") {
15172            Some(Value::Int(n)) => *n,
15173            _ => 0,
15174        };
15175
15176        // Increment next_id
15177        world_ref.insert("next_id".to_string(), Value::Int(id + 1));
15178
15179        // Add to entities set
15180        if let Some(Value::Map(entities)) = world_ref.get("entities") {
15181            entities
15182                .borrow_mut()
15183                .insert(id.to_string(), Value::Bool(true));
15184        }
15185
15186        Ok(Value::Int(id))
15187    });
15188
15189    // ecs_despawn(world, entity_id) - Remove entity and all its components
15190    define(interp, "ecs_despawn", Some(2), |_, args| {
15191        let world = match &args[0] {
15192            Value::Map(m) => m.clone(),
15193            _ => return Err(RuntimeError::new("ecs_despawn: expected world")),
15194        };
15195        let id = match &args[1] {
15196            Value::Int(n) => *n,
15197            _ => return Err(RuntimeError::new("ecs_despawn: expected entity id")),
15198        };
15199
15200        let world_ref = world.borrow();
15201
15202        // Remove from entities
15203        if let Some(Value::Map(entities)) = world_ref.get("entities") {
15204            entities.borrow_mut().remove(&id.to_string());
15205        }
15206
15207        // Remove all components for this entity
15208        if let Some(Value::Map(components)) = world_ref.get("components") {
15209            let comps = components.borrow();
15210            for (_, comp_storage) in comps.iter() {
15211                if let Value::Map(storage) = comp_storage {
15212                    storage.borrow_mut().remove(&id.to_string());
15213                }
15214            }
15215        }
15216
15217        Ok(Value::Bool(true))
15218    });
15219
15220    // ecs_attach(world, entity_id, component_name, data) - Add component to entity
15221    define(interp, "ecs_attach", Some(4), |_, args| {
15222        let world = match &args[0] {
15223            Value::Map(m) => m.clone(),
15224            _ => {
15225                return Err(RuntimeError::new(
15226                    "ecs_attach() expects a world as first argument.\n\
15227                 Usage: ecs_attach(world, entity_id, component_name, data)\n\
15228                 Example:\n\
15229                   let world = ecs_world();\n\
15230                   let e = ecs_spawn(world);\n\
15231                   ecs_attach(world, e, \"Position\", vec3(0, 0, 0));",
15232                ))
15233            }
15234        };
15235        let id = match &args[1] {
15236            Value::Int(n) => *n,
15237            _ => {
15238                return Err(RuntimeError::new(
15239                    "ecs_attach() expects an entity ID (integer) as second argument.\n\
15240                 Entity IDs are returned by ecs_spawn().\n\
15241                 Example:\n\
15242                   let entity = ecs_spawn(world);  // Returns 0, 1, 2...\n\
15243                   ecs_attach(world, entity, \"Health\", 100);",
15244                ))
15245            }
15246        };
15247        let comp_name = match &args[2] {
15248            Value::String(s) => s.to_string(),
15249            _ => {
15250                return Err(RuntimeError::new(
15251                    "ecs_attach() expects a string component name as third argument.\n\
15252                 Common component names: \"Position\", \"Velocity\", \"Health\", \"Sprite\"\n\
15253                 Example: ecs_attach(world, entity, \"Position\", vec3(0, 0, 0));",
15254                ))
15255            }
15256        };
15257        let data = args[3].clone();
15258
15259        let world_ref = world.borrow();
15260
15261        // Get or create component storage
15262        if let Some(Value::Map(components)) = world_ref.get("components") {
15263            let mut comps = components.borrow_mut();
15264
15265            let storage = comps
15266                .entry(comp_name.clone())
15267                .or_insert_with(|| Value::Map(Rc::new(RefCell::new(HashMap::new()))));
15268
15269            if let Value::Map(storage_map) = storage {
15270                storage_map.borrow_mut().insert(id.to_string(), data);
15271            }
15272        }
15273
15274        Ok(Value::Bool(true))
15275    });
15276
15277    // ecs_get(world, entity_id, component_name) - Get component data
15278    define(interp, "ecs_get", Some(3), |_, args| {
15279        let world = match &args[0] {
15280            Value::Map(m) => m.clone(),
15281            _ => return Err(RuntimeError::new("ecs_get: expected world")),
15282        };
15283        let id = match &args[1] {
15284            Value::Int(n) => *n,
15285            _ => return Err(RuntimeError::new("ecs_get: expected entity id")),
15286        };
15287        let comp_name = match &args[2] {
15288            Value::String(s) => s.to_string(),
15289            _ => return Err(RuntimeError::new("ecs_get: expected component name")),
15290        };
15291
15292        let world_ref = world.borrow();
15293
15294        if let Some(Value::Map(components)) = world_ref.get("components") {
15295            let comps = components.borrow();
15296            if let Some(Value::Map(storage)) = comps.get(&comp_name) {
15297                if let Some(data) = storage.borrow().get(&id.to_string()) {
15298                    return Ok(data.clone());
15299                }
15300            }
15301        }
15302
15303        Ok(Value::Null)
15304    });
15305
15306    // ecs_has(world, entity_id, component_name) - Check if entity has component
15307    define(interp, "ecs_has", Some(3), |_, args| {
15308        let world = match &args[0] {
15309            Value::Map(m) => m.clone(),
15310            _ => return Err(RuntimeError::new("ecs_has: expected world")),
15311        };
15312        let id = match &args[1] {
15313            Value::Int(n) => *n,
15314            _ => return Err(RuntimeError::new("ecs_has: expected entity id")),
15315        };
15316        let comp_name = match &args[2] {
15317            Value::String(s) => s.to_string(),
15318            _ => return Err(RuntimeError::new("ecs_has: expected component name")),
15319        };
15320
15321        let world_ref = world.borrow();
15322
15323        if let Some(Value::Map(components)) = world_ref.get("components") {
15324            let comps = components.borrow();
15325            if let Some(Value::Map(storage)) = comps.get(&comp_name) {
15326                return Ok(Value::Bool(storage.borrow().contains_key(&id.to_string())));
15327            }
15328        }
15329
15330        Ok(Value::Bool(false))
15331    });
15332
15333    // ecs_remove(world, entity_id, component_name) - Remove component from entity
15334    define(interp, "ecs_remove", Some(3), |_, args| {
15335        let world = match &args[0] {
15336            Value::Map(m) => m.clone(),
15337            _ => return Err(RuntimeError::new("ecs_remove: expected world")),
15338        };
15339        let id = match &args[1] {
15340            Value::Int(n) => *n,
15341            _ => return Err(RuntimeError::new("ecs_remove: expected entity id")),
15342        };
15343        let comp_name = match &args[2] {
15344            Value::String(s) => s.to_string(),
15345            _ => return Err(RuntimeError::new("ecs_remove: expected component name")),
15346        };
15347
15348        let world_ref = world.borrow();
15349
15350        if let Some(Value::Map(components)) = world_ref.get("components") {
15351            let comps = components.borrow();
15352            if let Some(Value::Map(storage)) = comps.get(&comp_name) {
15353                storage.borrow_mut().remove(&id.to_string());
15354                return Ok(Value::Bool(true));
15355            }
15356        }
15357
15358        Ok(Value::Bool(false))
15359    });
15360
15361    // ecs_query(world, component_names...) - Get all entities with all specified components
15362    // Returns array of entity IDs
15363    define(interp, "ecs_query", None, |_, args| {
15364        if args.is_empty() {
15365            return Err(RuntimeError::new(
15366                "ecs_query: expected at least world argument",
15367            ));
15368        }
15369
15370        let world = match &args[0] {
15371            Value::Map(m) => m.clone(),
15372            _ => return Err(RuntimeError::new("ecs_query: expected world")),
15373        };
15374
15375        let comp_names: Vec<String> = args[1..]
15376            .iter()
15377            .filter_map(|a| match a {
15378                Value::String(s) => Some(s.to_string()),
15379                _ => None,
15380            })
15381            .collect();
15382
15383        if comp_names.is_empty() {
15384            // Return all entities
15385            let world_ref = world.borrow();
15386            if let Some(Value::Map(entities)) = world_ref.get("entities") {
15387                let result: Vec<Value> = entities
15388                    .borrow()
15389                    .keys()
15390                    .filter_map(|k| k.parse::<i64>().ok().map(Value::Int))
15391                    .collect();
15392                return Ok(Value::Array(Rc::new(RefCell::new(result))));
15393            }
15394            return Ok(Value::Array(Rc::new(RefCell::new(vec![]))));
15395        }
15396
15397        let world_ref = world.borrow();
15398        let mut result_ids: Option<Vec<String>> = None;
15399
15400        if let Some(Value::Map(components)) = world_ref.get("components") {
15401            let comps = components.borrow();
15402
15403            for comp_name in &comp_names {
15404                if let Some(Value::Map(storage)) = comps.get(comp_name) {
15405                    let keys: Vec<String> = storage.borrow().keys().cloned().collect();
15406
15407                    result_ids = Some(match result_ids {
15408                        None => keys,
15409                        Some(existing) => {
15410                            existing.into_iter().filter(|k| keys.contains(k)).collect()
15411                        }
15412                    });
15413                } else {
15414                    // Component type doesn't exist, no entities match
15415                    return Ok(Value::Array(Rc::new(RefCell::new(vec![]))));
15416                }
15417            }
15418        }
15419
15420        let result: Vec<Value> = result_ids
15421            .unwrap_or_default()
15422            .iter()
15423            .filter_map(|k| k.parse::<i64>().ok().map(Value::Int))
15424            .collect();
15425
15426        Ok(Value::Array(Rc::new(RefCell::new(result))))
15427    });
15428
15429    // ecs_query_with(world, component_names, callback) - Iterate over matching entities
15430    // Callback receives (entity_id, components_map)
15431    define(interp, "ecs_query_with", Some(3), |interp, args| {
15432        let world = match &args[0] {
15433            Value::Map(m) => m.clone(),
15434            _ => return Err(RuntimeError::new("ecs_query_with: expected world")),
15435        };
15436        let comp_names: Vec<String> = match &args[1] {
15437            Value::Array(arr) => arr
15438                .borrow()
15439                .iter()
15440                .filter_map(|v| match v {
15441                    Value::String(s) => Some(s.to_string()),
15442                    _ => None,
15443                })
15444                .collect(),
15445            _ => {
15446                return Err(RuntimeError::new(
15447                    "ecs_query_with: expected array of component names",
15448                ))
15449            }
15450        };
15451        let callback = match &args[2] {
15452            Value::Function(f) => f.clone(),
15453            _ => {
15454                return Err(RuntimeError::new(
15455                    "ecs_query_with: expected callback function",
15456                ))
15457            }
15458        };
15459
15460        // Pre-collect all data to avoid borrow issues during callbacks
15461        let mut callback_data: Vec<(i64, HashMap<String, Value>)> = Vec::new();
15462
15463        {
15464            let world_ref = world.borrow();
15465            let mut result_ids: Option<Vec<String>> = None;
15466
15467            if let Some(Value::Map(components)) = world_ref.get("components") {
15468                let comps = components.borrow();
15469
15470                for comp_name in &comp_names {
15471                    if let Some(Value::Map(storage)) = comps.get(comp_name) {
15472                        let keys: Vec<String> = storage.borrow().keys().cloned().collect();
15473                        result_ids = Some(match result_ids {
15474                            None => keys,
15475                            Some(existing) => {
15476                                existing.into_iter().filter(|k| keys.contains(k)).collect()
15477                            }
15478                        });
15479                    } else {
15480                        result_ids = Some(vec![]);
15481                        break;
15482                    }
15483                }
15484
15485                // Collect data for each matching entity
15486                for id_str in result_ids.unwrap_or_default() {
15487                    if let Ok(id) = id_str.parse::<i64>() {
15488                        let mut entity_comps = HashMap::new();
15489                        for comp_name in &comp_names {
15490                            if let Some(Value::Map(storage)) = comps.get(comp_name) {
15491                                if let Some(data) = storage.borrow().get(&id_str) {
15492                                    entity_comps.insert(comp_name.clone(), data.clone());
15493                                }
15494                            }
15495                        }
15496                        callback_data.push((id, entity_comps));
15497                    }
15498                }
15499            }
15500        } // Release borrows here
15501
15502        // Now call callbacks without holding borrows
15503        for (id, entity_comps) in callback_data {
15504            let callback_args = vec![
15505                Value::Int(id),
15506                Value::Map(Rc::new(RefCell::new(entity_comps))),
15507            ];
15508            interp.call_function(&callback, callback_args)?;
15509        }
15510
15511        Ok(Value::Null)
15512    });
15513
15514    // ecs_count(world) - Count total entities
15515    define(interp, "ecs_count", Some(1), |_, args| {
15516        let world = match &args[0] {
15517            Value::Map(m) => m.clone(),
15518            _ => return Err(RuntimeError::new("ecs_count: expected world")),
15519        };
15520
15521        let world_ref = world.borrow();
15522        if let Some(Value::Map(entities)) = world_ref.get("entities") {
15523            return Ok(Value::Int(entities.borrow().len() as i64));
15524        }
15525
15526        Ok(Value::Int(0))
15527    });
15528
15529    // ecs_alive(world, entity_id) - Check if entity is alive
15530    define(interp, "ecs_alive", Some(2), |_, args| {
15531        let world = match &args[0] {
15532            Value::Map(m) => m.clone(),
15533            _ => return Err(RuntimeError::new("ecs_alive: expected world")),
15534        };
15535        let id = match &args[1] {
15536            Value::Int(n) => *n,
15537            _ => return Err(RuntimeError::new("ecs_alive: expected entity id")),
15538        };
15539
15540        let world_ref = world.borrow();
15541        if let Some(Value::Map(entities)) = world_ref.get("entities") {
15542            return Ok(Value::Bool(entities.borrow().contains_key(&id.to_string())));
15543        }
15544
15545        Ok(Value::Bool(false))
15546    });
15547}
15548
15549// ============================================================================
15550// POLYCULTURAL TEXT PROCESSING
15551// ============================================================================
15552//
15553// Sigil's philosophy: Mathematics is poly-cultural, and so is TEXT.
15554// Different writing systems have different needs:
15555//
15556// | Writing System | Special Needs |
15557// |----------------|---------------|
15558// | Latin          | Diacritics, ligatures, case folding |
15559// | Arabic/Hebrew  | RTL, contextual shaping, vowel marks |
15560// | CJK            | No word boundaries, display width, ruby text |
15561// | Devanagari     | Complex clusters, conjuncts |
15562// | Thai           | No spaces between words |
15563// | Hangul         | Jamo composition/decomposition |
15564//
15565// This module provides world-class text handling for ALL scripts.
15566//
15567
15568fn register_polycultural_text(interp: &mut Interpreter) {
15569    // =========================================================================
15570    // SCRIPT DETECTION
15571    // =========================================================================
15572    //
15573    // Detect what writing system(s) a text uses.
15574    // Essential for choosing appropriate processing strategies.
15575    //
15576
15577    // script - get the dominant script of a string
15578    define(interp, "script", Some(1), |_, args| {
15579        match &args[0] {
15580            Value::String(s) => {
15581                // Count scripts
15582                let mut script_counts: HashMap<String, usize> = HashMap::new();
15583                for c in s.chars() {
15584                    if !c.is_whitespace() && !c.is_ascii_punctuation() {
15585                        let script = c.script();
15586                        let name = format!("{:?}", script);
15587                        *script_counts.entry(name).or_insert(0) += 1;
15588                    }
15589                }
15590                // Find dominant script
15591                let dominant = script_counts
15592                    .into_iter()
15593                    .max_by_key(|(_, count)| *count)
15594                    .map(|(name, _)| name)
15595                    .unwrap_or_else(|| "Unknown".to_string());
15596                Ok(Value::String(Rc::new(dominant)))
15597            }
15598            _ => Err(RuntimeError::new("script() requires string")),
15599        }
15600    });
15601
15602    // scripts - get all scripts present in text
15603    define(interp, "scripts", Some(1), |_, args| match &args[0] {
15604        Value::String(s) => {
15605            let mut scripts: Vec<String> = s
15606                .chars()
15607                .filter(|c| !c.is_whitespace() && !c.is_ascii_punctuation())
15608                .map(|c| format!("{:?}", c.script()))
15609                .collect();
15610            scripts.sort();
15611            scripts.dedup();
15612            let values: Vec<Value> = scripts
15613                .into_iter()
15614                .map(|s| Value::String(Rc::new(s)))
15615                .collect();
15616            Ok(Value::Array(Rc::new(RefCell::new(values))))
15617        }
15618        _ => Err(RuntimeError::new("scripts() requires string")),
15619    });
15620
15621    // is_script - check if text is primarily in a specific script
15622    define(interp, "is_script", Some(2), |_, args| {
15623        match (&args[0], &args[1]) {
15624            (Value::String(s), Value::String(script_name)) => {
15625                let target = script_name.to_lowercase();
15626                let mut matching = 0usize;
15627                let mut total = 0usize;
15628                for c in s.chars() {
15629                    if !c.is_whitespace() && !c.is_ascii_punctuation() {
15630                        total += 1;
15631                        let script_str = format!("{:?}", c.script()).to_lowercase();
15632                        if script_str == target {
15633                            matching += 1;
15634                        }
15635                    }
15636                }
15637                let ratio = if total > 0 {
15638                    matching as f64 / total as f64
15639                } else {
15640                    0.0
15641                };
15642                Ok(Value::Bool(ratio > 0.5))
15643            }
15644            _ => Err(RuntimeError::new(
15645                "is_script() requires string and script name",
15646            )),
15647        }
15648    });
15649
15650    // Script-specific detection functions
15651    define(interp, "is_latin", Some(1), |_, args| match &args[0] {
15652        Value::String(s) => {
15653            let is_latin = s
15654                .chars()
15655                .filter(|c| !c.is_whitespace())
15656                .all(|c| matches!(c.script(), Script::Latin | Script::Common));
15657            Ok(Value::Bool(is_latin && !s.is_empty()))
15658        }
15659        _ => Err(RuntimeError::new("is_latin() requires string")),
15660    });
15661
15662    define(interp, "is_cjk", Some(1), |_, args| match &args[0] {
15663        Value::String(s) => {
15664            let has_cjk = s.chars().any(|c| {
15665                matches!(
15666                    c.script(),
15667                    Script::Han
15668                        | Script::Hiragana
15669                        | Script::Katakana
15670                        | Script::Hangul
15671                        | Script::Bopomofo
15672                )
15673            });
15674            Ok(Value::Bool(has_cjk))
15675        }
15676        _ => Err(RuntimeError::new("is_cjk() requires string")),
15677    });
15678
15679    define(interp, "is_arabic", Some(1), |_, args| match &args[0] {
15680        Value::String(s) => {
15681            let has_arabic = s.chars().any(|c| matches!(c.script(), Script::Arabic));
15682            Ok(Value::Bool(has_arabic))
15683        }
15684        _ => Err(RuntimeError::new("is_arabic() requires string")),
15685    });
15686
15687    define(interp, "is_hebrew", Some(1), |_, args| match &args[0] {
15688        Value::String(s) => {
15689            let has_hebrew = s.chars().any(|c| matches!(c.script(), Script::Hebrew));
15690            Ok(Value::Bool(has_hebrew))
15691        }
15692        _ => Err(RuntimeError::new("is_hebrew() requires string")),
15693    });
15694
15695    define(interp, "is_cyrillic", Some(1), |_, args| match &args[0] {
15696        Value::String(s) => {
15697            let has_cyrillic = s.chars().any(|c| matches!(c.script(), Script::Cyrillic));
15698            Ok(Value::Bool(has_cyrillic))
15699        }
15700        _ => Err(RuntimeError::new("is_cyrillic() requires string")),
15701    });
15702
15703    define(interp, "is_greek", Some(1), |_, args| match &args[0] {
15704        Value::String(s) => {
15705            let has_greek = s.chars().any(|c| matches!(c.script(), Script::Greek));
15706            Ok(Value::Bool(has_greek))
15707        }
15708        _ => Err(RuntimeError::new("is_greek() requires string")),
15709    });
15710
15711    define(interp, "is_devanagari", Some(1), |_, args| match &args[0] {
15712        Value::String(s) => {
15713            let has_devanagari = s.chars().any(|c| matches!(c.script(), Script::Devanagari));
15714            Ok(Value::Bool(has_devanagari))
15715        }
15716        _ => Err(RuntimeError::new("is_devanagari() requires string")),
15717    });
15718
15719    define(interp, "is_thai", Some(1), |_, args| match &args[0] {
15720        Value::String(s) => {
15721            let has_thai = s.chars().any(|c| matches!(c.script(), Script::Thai));
15722            Ok(Value::Bool(has_thai))
15723        }
15724        _ => Err(RuntimeError::new("is_thai() requires string")),
15725    });
15726
15727    define(interp, "is_hangul", Some(1), |_, args| match &args[0] {
15728        Value::String(s) => {
15729            let has_hangul = s.chars().any(|c| matches!(c.script(), Script::Hangul));
15730            Ok(Value::Bool(has_hangul))
15731        }
15732        _ => Err(RuntimeError::new("is_hangul() requires string")),
15733    });
15734
15735    define(interp, "is_hiragana", Some(1), |_, args| match &args[0] {
15736        Value::String(s) => {
15737            let has_hiragana = s.chars().any(|c| matches!(c.script(), Script::Hiragana));
15738            Ok(Value::Bool(has_hiragana))
15739        }
15740        _ => Err(RuntimeError::new("is_hiragana() requires string")),
15741    });
15742
15743    define(interp, "is_katakana", Some(1), |_, args| match &args[0] {
15744        Value::String(s) => {
15745            let has_katakana = s.chars().any(|c| matches!(c.script(), Script::Katakana));
15746            Ok(Value::Bool(has_katakana))
15747        }
15748        _ => Err(RuntimeError::new("is_katakana() requires string")),
15749    });
15750
15751    // char_script - get script of a single character
15752    define(interp, "char_script", Some(1), |_, args| match &args[0] {
15753        Value::Char(c) => {
15754            let script = format!("{:?}", c.script());
15755            Ok(Value::String(Rc::new(script)))
15756        }
15757        Value::String(s) if s.chars().count() == 1 => {
15758            let c = s.chars().next().unwrap();
15759            let script = format!("{:?}", c.script());
15760            Ok(Value::String(Rc::new(script)))
15761        }
15762        _ => Err(RuntimeError::new("char_script() requires single character")),
15763    });
15764
15765    // =========================================================================
15766    // BIDIRECTIONAL TEXT (RTL/LTR)
15767    // =========================================================================
15768    //
15769    // Arabic, Hebrew, and other scripts are written right-to-left.
15770    // Mixed text (e.g., Arabic with English) needs bidirectional handling.
15771    //
15772
15773    // text_direction - get overall text direction
15774    define(interp, "text_direction", Some(1), |_, args| {
15775        match &args[0] {
15776            Value::String(s) => {
15777                let bidi_info = BidiInfo::new(s, None);
15778                // Check if any paragraph is RTL
15779                let has_rtl = bidi_info.paragraphs.iter().any(|p| p.level.is_rtl());
15780                let direction = if has_rtl { "rtl" } else { "ltr" };
15781                Ok(Value::String(Rc::new(direction.to_string())))
15782            }
15783            _ => Err(RuntimeError::new("text_direction() requires string")),
15784        }
15785    });
15786
15787    // is_rtl - check if text is right-to-left
15788    define(interp, "is_rtl", Some(1), |_, args| match &args[0] {
15789        Value::String(s) => {
15790            let bidi_info = BidiInfo::new(s, None);
15791            let has_rtl = bidi_info.paragraphs.iter().any(|p| p.level.is_rtl());
15792            Ok(Value::Bool(has_rtl))
15793        }
15794        _ => Err(RuntimeError::new("is_rtl() requires string")),
15795    });
15796
15797    // is_ltr - check if text is left-to-right
15798    define(interp, "is_ltr", Some(1), |_, args| match &args[0] {
15799        Value::String(s) => {
15800            let bidi_info = BidiInfo::new(s, None);
15801            let is_ltr = bidi_info.paragraphs.iter().all(|p| !p.level.is_rtl());
15802            Ok(Value::Bool(is_ltr))
15803        }
15804        _ => Err(RuntimeError::new("is_ltr() requires string")),
15805    });
15806
15807    // is_bidi - check if text contains mixed directions
15808    define(interp, "is_bidi", Some(1), |_, args| {
15809        match &args[0] {
15810            Value::String(s) => {
15811                // Check for both RTL and LTR characters
15812                let has_rtl = s.chars().any(|c| {
15813                    matches!(
15814                        c.script(),
15815                        Script::Arabic | Script::Hebrew | Script::Syriac | Script::Thaana
15816                    )
15817                });
15818                let has_ltr = s.chars().any(|c| {
15819                    matches!(c.script(), Script::Latin | Script::Greek | Script::Cyrillic)
15820                });
15821                Ok(Value::Bool(has_rtl && has_ltr))
15822            }
15823            _ => Err(RuntimeError::new("is_bidi() requires string")),
15824        }
15825    });
15826
15827    // bidi_reorder - reorder text for visual display
15828    define(interp, "bidi_reorder", Some(1), |_, args| match &args[0] {
15829        Value::String(s) => {
15830            let bidi_info = BidiInfo::new(s, None);
15831            let mut result = String::new();
15832            for para in &bidi_info.paragraphs {
15833                let line = para.range.clone();
15834                let reordered = bidi_info.reorder_line(para, line);
15835                result.push_str(&reordered);
15836            }
15837            Ok(Value::String(Rc::new(result)))
15838        }
15839        _ => Err(RuntimeError::new("bidi_reorder() requires string")),
15840    });
15841
15842    // =========================================================================
15843    // DISPLAY WIDTH (CJK-aware)
15844    // =========================================================================
15845    //
15846    // CJK characters are "full-width" (2 columns), while Latin is "half-width".
15847    // Critical for proper terminal output and text alignment.
15848    //
15849
15850    // display_width - get visual width in terminal columns
15851    define(interp, "display_width", Some(1), |_, args| match &args[0] {
15852        Value::String(s) => {
15853            let width = UnicodeWidthStr::width(s.as_str());
15854            Ok(Value::Int(width as i64))
15855        }
15856        _ => Err(RuntimeError::new("display_width() requires string")),
15857    });
15858
15859    // is_fullwidth - check if string contains full-width characters
15860    define(interp, "is_fullwidth", Some(1), |_, args| {
15861        match &args[0] {
15862            Value::String(s) => {
15863                let char_count = s.chars().count();
15864                let display_width = UnicodeWidthStr::width(s.as_str());
15865                // If display width > char count, we have full-width chars
15866                Ok(Value::Bool(display_width > char_count))
15867            }
15868            _ => Err(RuntimeError::new("is_fullwidth() requires string")),
15869        }
15870    });
15871
15872    // pad_display - pad string to display width (CJK-aware)
15873    define(interp, "pad_display", Some(3), |_, args| {
15874        match (&args[0], &args[1], &args[2]) {
15875            (Value::String(s), Value::Int(target_width), Value::String(align)) => {
15876                let current_width = UnicodeWidthStr::width(s.as_str());
15877                let target = *target_width as usize;
15878                if current_width >= target {
15879                    return Ok(Value::String(s.clone()));
15880                }
15881                let padding = target - current_width;
15882                let result = match align.as_str() {
15883                    "left" => format!("{}{}", s, " ".repeat(padding)),
15884                    "right" => format!("{}{}", " ".repeat(padding), s),
15885                    "center" => {
15886                        let left = padding / 2;
15887                        let right = padding - left;
15888                        format!("{}{}{}", " ".repeat(left), s, " ".repeat(right))
15889                    }
15890                    _ => {
15891                        return Err(RuntimeError::new(
15892                            "pad_display: align must be 'left', 'right', or 'center'",
15893                        ))
15894                    }
15895                };
15896                Ok(Value::String(Rc::new(result)))
15897            }
15898            _ => Err(RuntimeError::new(
15899                "pad_display() requires string, width, and alignment",
15900            )),
15901        }
15902    });
15903
15904    // =========================================================================
15905    // TRANSLITERATION
15906    // =========================================================================
15907    //
15908    // Convert text from any script to ASCII representation.
15909    // Essential for: search, URLs, usernames, file names.
15910    //
15911
15912    // transliterate - convert any Unicode text to ASCII
15913    define(interp, "transliterate", Some(1), |_, args| match &args[0] {
15914        Value::String(s) => {
15915            let ascii = deunicode(s);
15916            Ok(Value::String(Rc::new(ascii)))
15917        }
15918        _ => Err(RuntimeError::new("transliterate() requires string")),
15919    });
15920
15921    // to_ascii - alias for transliterate
15922    define(interp, "to_ascii", Some(1), |_, args| match &args[0] {
15923        Value::String(s) => {
15924            let ascii = deunicode(s);
15925            Ok(Value::String(Rc::new(ascii)))
15926        }
15927        _ => Err(RuntimeError::new("to_ascii() requires string")),
15928    });
15929
15930    // slugify - create URL-safe slug from any text
15931    define(interp, "slugify", Some(1), |_, args| {
15932        match &args[0] {
15933            Value::String(s) => {
15934                let ascii = deunicode(s);
15935                let slug: String = ascii
15936                    .to_lowercase()
15937                    .chars()
15938                    .map(|c| if c.is_alphanumeric() { c } else { '-' })
15939                    .collect();
15940                // Collapse multiple dashes and trim
15941                let mut result = String::new();
15942                let mut last_was_dash = true; // Start true to trim leading dashes
15943                for c in slug.chars() {
15944                    if c == '-' {
15945                        if !last_was_dash {
15946                            result.push(c);
15947                            last_was_dash = true;
15948                        }
15949                    } else {
15950                        result.push(c);
15951                        last_was_dash = false;
15952                    }
15953                }
15954                // Trim trailing dash
15955                if result.ends_with('-') {
15956                    result.pop();
15957                }
15958                Ok(Value::String(Rc::new(result)))
15959            }
15960            _ => Err(RuntimeError::new("slugify() requires string")),
15961        }
15962    });
15963
15964    // =========================================================================
15965    // DIACRITICS AND ACCENTS
15966    // =========================================================================
15967    //
15968    // Many scripts use combining marks: é = e + ́ (combining acute)
15969    // Need to handle decomposition, stripping, and normalization.
15970    //
15971
15972    // strip_diacritics - remove accents and combining marks
15973    define(interp, "strip_diacritics", Some(1), |_, args| {
15974        match &args[0] {
15975            Value::String(s) => {
15976                // NFD decomposition separates base chars from combining marks
15977                let decomposed: String = s.nfd().collect();
15978                // Filter out combining marks (category Mn, Mc, Me)
15979                let stripped: String = decomposed
15980                    .chars()
15981                    .filter(|c| {
15982                        // Keep if not a combining mark
15983                        // Combining marks are in Unicode categories Mn, Mc, Me
15984                        // which are roughly in ranges U+0300-U+036F (common) and others
15985                        let code = *c as u32;
15986                        // Quick check for common combining diacritical marks
15987                        !(0x0300..=0x036F).contains(&code)
15988                            && !(0x1AB0..=0x1AFF).contains(&code)
15989                            && !(0x1DC0..=0x1DFF).contains(&code)
15990                            && !(0x20D0..=0x20FF).contains(&code)
15991                            && !(0xFE20..=0xFE2F).contains(&code)
15992                    })
15993                    .collect();
15994                Ok(Value::String(Rc::new(stripped)))
15995            }
15996            _ => Err(RuntimeError::new("strip_diacritics() requires string")),
15997        }
15998    });
15999
16000    // has_diacritics - check if string contains diacritical marks
16001    define(interp, "has_diacritics", Some(1), |_, args| {
16002        match &args[0] {
16003            Value::String(s) => {
16004                let decomposed: String = s.nfd().collect();
16005                let has_marks = decomposed.chars().any(|c| {
16006                    let code = c as u32;
16007                    (0x0300..=0x036F).contains(&code)
16008                        || (0x1AB0..=0x1AFF).contains(&code)
16009                        || (0x1DC0..=0x1DFF).contains(&code)
16010                        || (0x20D0..=0x20FF).contains(&code)
16011                        || (0xFE20..=0xFE2F).contains(&code)
16012                });
16013                Ok(Value::Bool(has_marks))
16014            }
16015            _ => Err(RuntimeError::new("has_diacritics() requires string")),
16016        }
16017    });
16018
16019    // normalize_accents - convert composed to decomposed or vice versa
16020    define(interp, "normalize_accents", Some(2), |_, args| {
16021        match (&args[0], &args[1]) {
16022            (Value::String(s), Value::String(form)) => {
16023                let result = match form.as_str() {
16024                    "composed" | "nfc" => s.nfc().collect(),
16025                    "decomposed" | "nfd" => s.nfd().collect(),
16026                    _ => {
16027                        return Err(RuntimeError::new(
16028                            "normalize_accents: form must be 'composed' or 'decomposed'",
16029                        ))
16030                    }
16031                };
16032                Ok(Value::String(Rc::new(result)))
16033            }
16034            _ => Err(RuntimeError::new(
16035                "normalize_accents() requires string and form",
16036            )),
16037        }
16038    });
16039
16040    // =========================================================================
16041    // LOCALE-AWARE CASE MAPPING
16042    // =========================================================================
16043    //
16044    // Case mapping varies by locale:
16045    // - Turkish: i ↔ İ, ı ↔ I (dotted/dotless distinction)
16046    // - German: ß → SS (uppercase), but SS → ss or ß (lowercase)
16047    // - Greek: final sigma rules
16048    //
16049
16050    // upper_locale - locale-aware uppercase
16051    define(interp, "upper_locale", Some(2), |_, args| {
16052        match (&args[0], &args[1]) {
16053            (Value::String(s), Value::String(locale_str)) => {
16054                let case_mapper = CaseMapper::new();
16055                let langid: LanguageIdentifier =
16056                    locale_str.parse().unwrap_or_else(|_| "en".parse().unwrap());
16057                let result = case_mapper.uppercase_to_string(s, &langid);
16058                Ok(Value::String(Rc::new(result)))
16059            }
16060            _ => Err(RuntimeError::new(
16061                "upper_locale() requires string and locale",
16062            )),
16063        }
16064    });
16065
16066    // lower_locale - locale-aware lowercase
16067    define(interp, "lower_locale", Some(2), |_, args| {
16068        match (&args[0], &args[1]) {
16069            (Value::String(s), Value::String(locale_str)) => {
16070                let case_mapper = CaseMapper::new();
16071                let langid: LanguageIdentifier =
16072                    locale_str.parse().unwrap_or_else(|_| "en".parse().unwrap());
16073                let result = case_mapper.lowercase_to_string(s, &langid);
16074                Ok(Value::String(Rc::new(result)))
16075            }
16076            _ => Err(RuntimeError::new(
16077                "lower_locale() requires string and locale",
16078            )),
16079        }
16080    });
16081
16082    // titlecase_locale - locale-aware titlecase
16083    define(interp, "titlecase_locale", Some(2), |_, args| {
16084        match (&args[0], &args[1]) {
16085            (Value::String(s), Value::String(locale_str)) => {
16086                let case_mapper = CaseMapper::new();
16087                let langid: LanguageIdentifier =
16088                    locale_str.parse().unwrap_or_else(|_| "en".parse().unwrap());
16089                let options = TitlecaseOptions::default();
16090                let result = case_mapper
16091                    .titlecase_segment_with_only_case_data_to_string(s, &langid, options);
16092                Ok(Value::String(Rc::new(result)))
16093            }
16094            _ => Err(RuntimeError::new(
16095                "titlecase_locale() requires string and locale",
16096            )),
16097        }
16098    });
16099
16100    // case_fold - Unicode case folding for comparison
16101    define(interp, "case_fold", Some(1), |_, args| match &args[0] {
16102        Value::String(s) => {
16103            let case_mapper = CaseMapper::new();
16104            let result = case_mapper.fold_string(s);
16105            Ok(Value::String(Rc::new(result)))
16106        }
16107        _ => Err(RuntimeError::new("case_fold() requires string")),
16108    });
16109
16110    // case_insensitive_eq - compare strings ignoring case (using case folding)
16111    define(interp, "case_insensitive_eq", Some(2), |_, args| {
16112        match (&args[0], &args[1]) {
16113            (Value::String(a), Value::String(b)) => {
16114                let case_mapper = CaseMapper::new();
16115                let folded_a = case_mapper.fold_string(a);
16116                let folded_b = case_mapper.fold_string(b);
16117                Ok(Value::Bool(folded_a == folded_b))
16118            }
16119            _ => Err(RuntimeError::new(
16120                "case_insensitive_eq() requires two strings",
16121            )),
16122        }
16123    });
16124
16125    // =========================================================================
16126    // LOCALE-AWARE COLLATION (SORTING)
16127    // =========================================================================
16128    //
16129    // Sorting order varies dramatically by locale:
16130    // - German: ä sorts with a
16131    // - Swedish: ä sorts after z
16132    // - Spanish: ñ is a separate letter after n
16133    //
16134
16135    // compare_locale - locale-aware string comparison
16136    define(interp, "compare_locale", Some(3), |_, args| {
16137        match (&args[0], &args[1], &args[2]) {
16138            (Value::String(a), Value::String(b), Value::String(locale_str)) => {
16139                let locale: Locale = locale_str.parse().unwrap_or_else(|_| "en".parse().unwrap());
16140                let options = CollatorOptions::new();
16141                let collator = Collator::try_new(&locale.into(), options)
16142                    .unwrap_or_else(|_| Collator::try_new(&Default::default(), options).unwrap());
16143                let result = match collator.compare(a, b) {
16144                    std::cmp::Ordering::Less => -1,
16145                    std::cmp::Ordering::Equal => 0,
16146                    std::cmp::Ordering::Greater => 1,
16147                };
16148                Ok(Value::Int(result))
16149            }
16150            _ => Err(RuntimeError::new(
16151                "compare_locale() requires two strings and locale",
16152            )),
16153        }
16154    });
16155
16156    // sort_locale - sort array of strings by locale
16157    define(interp, "sort_locale", Some(2), |_, args| {
16158        match (&args[0], &args[1]) {
16159            (Value::Array(arr), Value::String(locale_str)) => {
16160                let locale: Locale = locale_str.parse().unwrap_or_else(|_| "en".parse().unwrap());
16161                let options = CollatorOptions::new();
16162                let collator = Collator::try_new(&locale.into(), options)
16163                    .unwrap_or_else(|_| Collator::try_new(&Default::default(), options).unwrap());
16164
16165                let mut items: Vec<(String, Value)> = arr
16166                    .borrow()
16167                    .iter()
16168                    .map(|v| {
16169                        let s = match v {
16170                            Value::String(s) => (**s).clone(),
16171                            _ => format!("{}", v),
16172                        };
16173                        (s, v.clone())
16174                    })
16175                    .collect();
16176
16177                items.sort_by(|(a, _), (b, _)| collator.compare(a, b));
16178
16179                let sorted: Vec<Value> = items.into_iter().map(|(_, v)| v).collect();
16180                Ok(Value::Array(Rc::new(RefCell::new(sorted))))
16181            }
16182            _ => Err(RuntimeError::new("sort_locale() requires array and locale")),
16183        }
16184    });
16185
16186    // =========================================================================
16187    // ADVANCED SEGMENTATION
16188    // =========================================================================
16189    //
16190    // Different languages have different boundary rules:
16191    // - Thai/Lao/Khmer: No spaces between words
16192    // - CJK: Characters can be words themselves
16193    // - German: Compound words are single words
16194    //
16195
16196    // sentences - split text into sentences (locale-aware)
16197    define(interp, "sentences", Some(1), |_, args| match &args[0] {
16198        Value::String(s) => {
16199            let segmenter = SentenceSegmenter::new();
16200            let breakpoints: Vec<usize> = segmenter.segment_str(s).collect();
16201            let mut sentences = Vec::new();
16202            let mut start = 0;
16203            for end in breakpoints {
16204                let sentence = s[start..end].trim();
16205                if !sentence.is_empty() {
16206                    sentences.push(Value::String(Rc::new(sentence.to_string())));
16207                }
16208                start = end;
16209            }
16210            Ok(Value::Array(Rc::new(RefCell::new(sentences))))
16211        }
16212        _ => Err(RuntimeError::new("sentences() requires string")),
16213    });
16214
16215    // sentence_count - count sentences
16216    define(interp, "sentence_count", Some(1), |_, args| {
16217        match &args[0] {
16218            Value::String(s) => {
16219                let segmenter = SentenceSegmenter::new();
16220                let breakpoints: Vec<usize> = segmenter.segment_str(s).collect();
16221                // Sentences are between breakpoints
16222                let count = breakpoints.len().saturating_sub(1);
16223                Ok(Value::Int(count as i64))
16224            }
16225            _ => Err(RuntimeError::new("sentence_count() requires string")),
16226        }
16227    });
16228
16229    // words_icu - ICU-based word segmentation (better for CJK, Thai)
16230    define(interp, "words_icu", Some(1), |_, args| {
16231        match &args[0] {
16232            Value::String(s) => {
16233                let segmenter = WordSegmenter::new_auto();
16234                let breakpoints: Vec<usize> = segmenter.segment_str(s).collect();
16235                let mut words = Vec::new();
16236                let mut start = 0;
16237                for end in breakpoints {
16238                    let word = &s[start..end];
16239                    // Filter out whitespace-only segments
16240                    if !word.trim().is_empty() {
16241                        words.push(Value::String(Rc::new(word.to_string())));
16242                    }
16243                    start = end;
16244                }
16245                Ok(Value::Array(Rc::new(RefCell::new(words))))
16246            }
16247            _ => Err(RuntimeError::new("words_icu() requires string")),
16248        }
16249    });
16250
16251    // word_count_icu - ICU-based word count (handles Thai, CJK correctly)
16252    define(interp, "word_count_icu", Some(1), |_, args| {
16253        match &args[0] {
16254            Value::String(s) => {
16255                let segmenter = WordSegmenter::new_auto();
16256                let breakpoints: Vec<usize> = segmenter.segment_str(s).collect();
16257                let mut count = 0;
16258                let mut start = 0;
16259                for end in breakpoints {
16260                    let word = &s[start..end];
16261                    if !word.trim().is_empty() && word.chars().any(|c| c.is_alphanumeric()) {
16262                        count += 1;
16263                    }
16264                    start = end;
16265                }
16266                Ok(Value::Int(count))
16267            }
16268            _ => Err(RuntimeError::new("word_count_icu() requires string")),
16269        }
16270    });
16271
16272    // =========================================================================
16273    // SCRIPT-SPECIFIC UTILITIES
16274    // =========================================================================
16275
16276    // is_emoji - check if string contains emoji
16277    define(interp, "is_emoji", Some(1), |_, args| {
16278        match &args[0] {
16279            Value::String(s) => {
16280                let has_emoji = s.chars().any(|c| {
16281                    let code = c as u32;
16282                    // Common emoji ranges
16283                    (0x1F600..=0x1F64F).contains(&code) ||  // Emoticons
16284                    (0x1F300..=0x1F5FF).contains(&code) ||  // Misc Symbols and Pictographs
16285                    (0x1F680..=0x1F6FF).contains(&code) ||  // Transport and Map
16286                    (0x1F1E0..=0x1F1FF).contains(&code) ||  // Flags
16287                    (0x2600..=0x26FF).contains(&code) ||    // Misc symbols
16288                    (0x2700..=0x27BF).contains(&code) ||    // Dingbats
16289                    (0xFE00..=0xFE0F).contains(&code) ||    // Variation Selectors
16290                    (0x1F900..=0x1F9FF).contains(&code) ||  // Supplemental Symbols and Pictographs
16291                    (0x1FA00..=0x1FA6F).contains(&code) ||  // Chess Symbols
16292                    (0x1FA70..=0x1FAFF).contains(&code) ||  // Symbols and Pictographs Extended-A
16293                    (0x231A..=0x231B).contains(&code) ||    // Watch, Hourglass
16294                    (0x23E9..=0x23F3).contains(&code) ||    // Various symbols
16295                    (0x23F8..=0x23FA).contains(&code) // Various symbols
16296                });
16297                Ok(Value::Bool(has_emoji))
16298            }
16299            _ => Err(RuntimeError::new("is_emoji() requires string")),
16300        }
16301    });
16302
16303    // extract_emoji - extract all emoji from text
16304    define(interp, "extract_emoji", Some(1), |_, args| match &args[0] {
16305        Value::String(s) => {
16306            let emoji: Vec<Value> = s
16307                .graphemes(true)
16308                .filter(|g| {
16309                    g.chars().any(|c| {
16310                        let code = c as u32;
16311                        (0x1F600..=0x1F64F).contains(&code)
16312                            || (0x1F300..=0x1F5FF).contains(&code)
16313                            || (0x1F680..=0x1F6FF).contains(&code)
16314                            || (0x1F1E0..=0x1F1FF).contains(&code)
16315                            || (0x2600..=0x26FF).contains(&code)
16316                            || (0x2700..=0x27BF).contains(&code)
16317                            || (0x1F900..=0x1F9FF).contains(&code)
16318                            || (0x1FA00..=0x1FA6F).contains(&code)
16319                            || (0x1FA70..=0x1FAFF).contains(&code)
16320                    })
16321                })
16322                .map(|g| Value::String(Rc::new(g.to_string())))
16323                .collect();
16324            Ok(Value::Array(Rc::new(RefCell::new(emoji))))
16325        }
16326        _ => Err(RuntimeError::new("extract_emoji() requires string")),
16327    });
16328
16329    // strip_emoji - remove emoji from text
16330    define(interp, "strip_emoji", Some(1), |_, args| match &args[0] {
16331        Value::String(s) => {
16332            let stripped: String = s
16333                .graphemes(true)
16334                .filter(|g| {
16335                    !g.chars().any(|c| {
16336                        let code = c as u32;
16337                        (0x1F600..=0x1F64F).contains(&code)
16338                            || (0x1F300..=0x1F5FF).contains(&code)
16339                            || (0x1F680..=0x1F6FF).contains(&code)
16340                            || (0x1F1E0..=0x1F1FF).contains(&code)
16341                            || (0x2600..=0x26FF).contains(&code)
16342                            || (0x2700..=0x27BF).contains(&code)
16343                            || (0x1F900..=0x1F9FF).contains(&code)
16344                            || (0x1FA00..=0x1FA6F).contains(&code)
16345                            || (0x1FA70..=0x1FAFF).contains(&code)
16346                    })
16347                })
16348                .collect();
16349            Ok(Value::String(Rc::new(stripped)))
16350        }
16351        _ => Err(RuntimeError::new("strip_emoji() requires string")),
16352    });
16353
16354    // =========================================================================
16355    // MIXED SCRIPT TEXT UTILITIES
16356    // =========================================================================
16357
16358    // script_runs - split text into runs of the same script
16359    define(interp, "script_runs", Some(1), |_, args| {
16360        match &args[0] {
16361            Value::String(s) => {
16362                let mut runs: Vec<Value> = Vec::new();
16363                let mut current_run = String::new();
16364                let mut current_script: Option<Script> = None;
16365
16366                for c in s.chars() {
16367                    let script = c.script();
16368                    // Common and Inherited scripts don't start new runs
16369                    if script != Script::Common && script != Script::Inherited {
16370                        if let Some(curr) = current_script {
16371                            if script != curr {
16372                                // New script - save current run
16373                                if !current_run.is_empty() {
16374                                    runs.push(Value::String(Rc::new(current_run.clone())));
16375                                    current_run.clear();
16376                                }
16377                                current_script = Some(script);
16378                            }
16379                        } else {
16380                            current_script = Some(script);
16381                        }
16382                    }
16383                    current_run.push(c);
16384                }
16385
16386                // Don't forget the last run
16387                if !current_run.is_empty() {
16388                    runs.push(Value::String(Rc::new(current_run)));
16389                }
16390
16391                Ok(Value::Array(Rc::new(RefCell::new(runs))))
16392            }
16393            _ => Err(RuntimeError::new("script_runs() requires string")),
16394        }
16395    });
16396
16397    // script_ratio - get ratio of scripts in text
16398    define(interp, "script_ratio", Some(1), |_, args| {
16399        match &args[0] {
16400            Value::String(s) => {
16401                let mut script_counts: HashMap<String, usize> = HashMap::new();
16402                let mut total = 0usize;
16403
16404                for c in s.chars() {
16405                    if !c.is_whitespace() && c != ' ' {
16406                        let script = format!("{:?}", c.script());
16407                        *script_counts.entry(script).or_insert(0) += 1;
16408                        total += 1;
16409                    }
16410                }
16411
16412                // Convert to map of ratios
16413                let mut result = HashMap::new();
16414                for (script, count) in script_counts {
16415                    let ratio = if total > 0 {
16416                        count as f64 / total as f64
16417                    } else {
16418                        0.0
16419                    };
16420                    result.insert(script, Value::Float(ratio));
16421                }
16422
16423                let map = Rc::new(RefCell::new(result));
16424                Ok(Value::Map(map))
16425            }
16426            _ => Err(RuntimeError::new("script_ratio() requires string")),
16427        }
16428    });
16429
16430    // =========================================================================
16431    // INTERNATIONALIZATION HELPERS
16432    // =========================================================================
16433
16434    // locale_name - get display name for a locale
16435    define(interp, "locale_name", Some(1), |_, args| {
16436        match &args[0] {
16437            Value::String(locale_str) => {
16438                // Return the locale code itself as a simple implementation
16439                // A full implementation would use ICU's display names
16440                Ok(Value::String(locale_str.clone()))
16441            }
16442            _ => Err(RuntimeError::new("locale_name() requires string")),
16443        }
16444    });
16445
16446    // supported_locales - list of supported locales for collation
16447    define(interp, "supported_locales", Some(0), |_, _| {
16448        // Common locales supported by ICU
16449        let locales = vec![
16450            "ar", "bg", "ca", "cs", "da", "de", "el", "en", "es", "et", "fi", "fr", "he", "hi",
16451            "hr", "hu", "id", "it", "ja", "ko", "lt", "lv", "ms", "nb", "nl", "pl", "pt", "ro",
16452            "ru", "sk", "sl", "sr", "sv", "th", "tr", "uk", "vi", "zh",
16453        ];
16454        let values: Vec<Value> = locales
16455            .into_iter()
16456            .map(|s| Value::String(Rc::new(s.to_string())))
16457            .collect();
16458        Ok(Value::Array(Rc::new(RefCell::new(values))))
16459    });
16460}
16461
16462// =============================================================================
16463// TEXT INTELLIGENCE MODULE - AI-Native Text Analysis
16464// =============================================================================
16465
16466fn register_text_intelligence(interp: &mut Interpreter) {
16467    // =========================================================================
16468    // STRING SIMILARITY METRICS
16469    // =========================================================================
16470
16471    // levenshtein - edit distance between strings
16472    define(interp, "levenshtein", Some(2), |_, args| {
16473        match (&args[0], &args[1]) {
16474            (Value::String(a), Value::String(b)) => {
16475                let distance = strsim::levenshtein(a, b);
16476                Ok(Value::Int(distance as i64))
16477            }
16478            _ => Err(RuntimeError::new("levenshtein() requires two strings")),
16479        }
16480    });
16481
16482    // levenshtein_normalized - normalized edit distance (0.0 to 1.0)
16483    define(
16484        interp,
16485        "levenshtein_normalized",
16486        Some(2),
16487        |_, args| match (&args[0], &args[1]) {
16488            (Value::String(a), Value::String(b)) => {
16489                let distance = strsim::normalized_levenshtein(a, b);
16490                Ok(Value::Float(distance))
16491            }
16492            _ => Err(RuntimeError::new(
16493                "levenshtein_normalized() requires two strings",
16494            )),
16495        },
16496    );
16497
16498    // jaro - Jaro similarity (0.0 to 1.0)
16499    define(interp, "jaro", Some(2), |_, args| {
16500        match (&args[0], &args[1]) {
16501            (Value::String(a), Value::String(b)) => {
16502                let sim = strsim::jaro(a, b);
16503                Ok(Value::Float(sim))
16504            }
16505            _ => Err(RuntimeError::new("jaro() requires two strings")),
16506        }
16507    });
16508
16509    // jaro_winkler - Jaro-Winkler similarity (0.0 to 1.0, favors common prefixes)
16510    define(interp, "jaro_winkler", Some(2), |_, args| {
16511        match (&args[0], &args[1]) {
16512            (Value::String(a), Value::String(b)) => {
16513                let sim = strsim::jaro_winkler(a, b);
16514                Ok(Value::Float(sim))
16515            }
16516            _ => Err(RuntimeError::new("jaro_winkler() requires two strings")),
16517        }
16518    });
16519
16520    // sorensen_dice - Sørensen-Dice coefficient (0.0 to 1.0)
16521    define(interp, "sorensen_dice", Some(2), |_, args| {
16522        match (&args[0], &args[1]) {
16523            (Value::String(a), Value::String(b)) => {
16524                let sim = strsim::sorensen_dice(a, b);
16525                Ok(Value::Float(sim))
16526            }
16527            _ => Err(RuntimeError::new("sorensen_dice() requires two strings")),
16528        }
16529    });
16530
16531    // damerau_levenshtein - edit distance with transpositions
16532    define(interp, "damerau_levenshtein", Some(2), |_, args| {
16533        match (&args[0], &args[1]) {
16534            (Value::String(a), Value::String(b)) => {
16535                let distance = strsim::damerau_levenshtein(a, b);
16536                Ok(Value::Int(distance as i64))
16537            }
16538            _ => Err(RuntimeError::new(
16539                "damerau_levenshtein() requires two strings",
16540            )),
16541        }
16542    });
16543
16544    // osa_distance - Optimal String Alignment distance
16545    define(interp, "osa_distance", Some(2), |_, args| {
16546        match (&args[0], &args[1]) {
16547            (Value::String(a), Value::String(b)) => {
16548                let distance = strsim::osa_distance(a, b);
16549                Ok(Value::Int(distance as i64))
16550            }
16551            _ => Err(RuntimeError::new("osa_distance() requires two strings")),
16552        }
16553    });
16554
16555    // fuzzy_match - check if strings are similar above threshold
16556    define(interp, "fuzzy_match", Some(3), |_, args| {
16557        match (&args[0], &args[1], &args[2]) {
16558            (Value::String(a), Value::String(b), Value::Float(threshold)) => {
16559                let sim = strsim::jaro_winkler(a, b);
16560                Ok(Value::Bool(sim >= *threshold))
16561            }
16562            (Value::String(a), Value::String(b), Value::Int(threshold)) => {
16563                let sim = strsim::jaro_winkler(a, b);
16564                Ok(Value::Bool(sim >= *threshold as f64))
16565            }
16566            _ => Err(RuntimeError::new(
16567                "fuzzy_match() requires two strings and threshold",
16568            )),
16569        }
16570    });
16571
16572    // fuzzy_search - find best matches in array
16573    define(interp, "fuzzy_search", Some(3), |_, args| {
16574        match (&args[0], &args[1], &args[2]) {
16575            (Value::String(query), Value::Array(items), Value::Int(limit)) => {
16576                let items_ref = items.borrow();
16577                let mut scores: Vec<(f64, &str)> = items_ref
16578                    .iter()
16579                    .filter_map(|v| {
16580                        if let Value::String(s) = v {
16581                            Some((strsim::jaro_winkler(query, s), s.as_str()))
16582                        } else {
16583                            None
16584                        }
16585                    })
16586                    .collect();
16587                scores.sort_by(|a, b| b.0.partial_cmp(&a.0).unwrap_or(std::cmp::Ordering::Equal));
16588                let results: Vec<Value> = scores
16589                    .into_iter()
16590                    .take(*limit as usize)
16591                    .map(|(_, s)| Value::String(Rc::new(s.to_string())))
16592                    .collect();
16593                Ok(Value::Array(Rc::new(RefCell::new(results))))
16594            }
16595            _ => Err(RuntimeError::new(
16596                "fuzzy_search() requires query string, array, and limit",
16597            )),
16598        }
16599    });
16600
16601    // =========================================================================
16602    // PHONETIC ENCODING
16603    // =========================================================================
16604
16605    // soundex - American Soundex encoding
16606    define(interp, "soundex", Some(1), |_, args| match &args[0] {
16607        Value::String(s) => {
16608            let code = compute_soundex(s);
16609            Ok(Value::String(Rc::new(code)))
16610        }
16611        _ => Err(RuntimeError::new("soundex() requires string")),
16612    });
16613
16614    // soundex_match - check if two strings have same Soundex code
16615    define(interp, "soundex_match", Some(2), |_, args| {
16616        match (&args[0], &args[1]) {
16617            (Value::String(a), Value::String(b)) => {
16618                let code_a = compute_soundex(a);
16619                let code_b = compute_soundex(b);
16620                Ok(Value::Bool(code_a == code_b))
16621            }
16622            _ => Err(RuntimeError::new("soundex_match() requires two strings")),
16623        }
16624    });
16625
16626    // metaphone - Metaphone encoding (better for English)
16627    define(interp, "metaphone", Some(1), |_, args| match &args[0] {
16628        Value::String(s) => {
16629            let code = compute_metaphone(s);
16630            Ok(Value::String(Rc::new(code)))
16631        }
16632        _ => Err(RuntimeError::new("metaphone() requires string")),
16633    });
16634
16635    // metaphone_match - check if two strings have same Metaphone code
16636    define(interp, "metaphone_match", Some(2), |_, args| {
16637        match (&args[0], &args[1]) {
16638            (Value::String(a), Value::String(b)) => {
16639                let code_a = compute_metaphone(a);
16640                let code_b = compute_metaphone(b);
16641                Ok(Value::Bool(code_a == code_b))
16642            }
16643            _ => Err(RuntimeError::new("metaphone_match() requires two strings")),
16644        }
16645    });
16646
16647    // cologne_phonetic - Cologne phonetic encoding (for German)
16648    define(interp, "cologne_phonetic", Some(1), |_, args| {
16649        match &args[0] {
16650            Value::String(s) => {
16651                let code = compute_cologne(s);
16652                Ok(Value::String(Rc::new(code)))
16653            }
16654            _ => Err(RuntimeError::new("cologne_phonetic() requires string")),
16655        }
16656    });
16657
16658    // =========================================================================
16659    // LANGUAGE DETECTION
16660    // =========================================================================
16661
16662    // detect_language - detect the language of text
16663    define(interp, "detect_language", Some(1), |_, args| {
16664        match &args[0] {
16665            Value::String(s) => {
16666                if let Some(info) = detect(s) {
16667                    let lang_code = match info.lang() {
16668                        Lang::Eng => "en",
16669                        Lang::Spa => "es",
16670                        Lang::Fra => "fr",
16671                        Lang::Deu => "de",
16672                        Lang::Ita => "it",
16673                        Lang::Por => "pt",
16674                        Lang::Rus => "ru",
16675                        Lang::Ara => "ar",
16676                        Lang::Hin => "hi",
16677                        Lang::Cmn => "zh",
16678                        Lang::Jpn => "ja",
16679                        Lang::Kor => "ko",
16680                        Lang::Nld => "nl",
16681                        Lang::Swe => "sv",
16682                        Lang::Tur => "tr",
16683                        Lang::Pol => "pl",
16684                        Lang::Ukr => "uk",
16685                        Lang::Ces => "cs",
16686                        Lang::Dan => "da",
16687                        Lang::Fin => "fi",
16688                        Lang::Ell => "el",
16689                        Lang::Heb => "he",
16690                        Lang::Hun => "hu",
16691                        Lang::Ind => "id",
16692                        Lang::Nob => "no",
16693                        Lang::Ron => "ro",
16694                        Lang::Slk => "sk",
16695                        Lang::Tha => "th",
16696                        Lang::Vie => "vi",
16697                        _ => "unknown",
16698                    };
16699                    Ok(Value::String(Rc::new(lang_code.to_string())))
16700                } else {
16701                    Ok(Value::String(Rc::new("unknown".to_string())))
16702                }
16703            }
16704            _ => Err(RuntimeError::new("detect_language() requires string")),
16705        }
16706    });
16707
16708    // detect_language_confidence - detect language with confidence score
16709    define(
16710        interp,
16711        "detect_language_confidence",
16712        Some(1),
16713        |_, args| match &args[0] {
16714            Value::String(s) => {
16715                if let Some(info) = detect(s) {
16716                    let lang_code = match info.lang() {
16717                        Lang::Eng => "en",
16718                        Lang::Spa => "es",
16719                        Lang::Fra => "fr",
16720                        Lang::Deu => "de",
16721                        Lang::Ita => "it",
16722                        Lang::Por => "pt",
16723                        Lang::Rus => "ru",
16724                        Lang::Ara => "ar",
16725                        Lang::Cmn => "zh",
16726                        Lang::Jpn => "ja",
16727                        _ => "unknown",
16728                    };
16729                    let confidence = info.confidence();
16730                    let mut map = HashMap::new();
16731                    map.insert(
16732                        "lang".to_string(),
16733                        Value::String(Rc::new(lang_code.to_string())),
16734                    );
16735                    map.insert("confidence".to_string(), Value::Float(confidence as f64));
16736                    Ok(Value::Map(Rc::new(RefCell::new(map))))
16737                } else {
16738                    let mut map = HashMap::new();
16739                    map.insert(
16740                        "lang".to_string(),
16741                        Value::String(Rc::new("unknown".to_string())),
16742                    );
16743                    map.insert("confidence".to_string(), Value::Float(0.0));
16744                    Ok(Value::Map(Rc::new(RefCell::new(map))))
16745                }
16746            }
16747            _ => Err(RuntimeError::new(
16748                "detect_language_confidence() requires string",
16749            )),
16750        },
16751    );
16752
16753    // detect_script - detect the script of text using whatlang
16754    define(
16755        interp,
16756        "detect_script_whatlang",
16757        Some(1),
16758        |_, args| match &args[0] {
16759            Value::String(s) => {
16760                if let Some(info) = detect(s) {
16761                    let script_name = match info.script() {
16762                        WhatLangScript::Latin => "Latin",
16763                        WhatLangScript::Cyrillic => "Cyrillic",
16764                        WhatLangScript::Arabic => "Arabic",
16765                        WhatLangScript::Devanagari => "Devanagari",
16766                        WhatLangScript::Ethiopic => "Ethiopic",
16767                        WhatLangScript::Georgian => "Georgian",
16768                        WhatLangScript::Greek => "Greek",
16769                        WhatLangScript::Gujarati => "Gujarati",
16770                        WhatLangScript::Gurmukhi => "Gurmukhi",
16771                        WhatLangScript::Hangul => "Hangul",
16772                        WhatLangScript::Hebrew => "Hebrew",
16773                        WhatLangScript::Hiragana => "Hiragana",
16774                        WhatLangScript::Kannada => "Kannada",
16775                        WhatLangScript::Katakana => "Katakana",
16776                        WhatLangScript::Khmer => "Khmer",
16777                        WhatLangScript::Malayalam => "Malayalam",
16778                        WhatLangScript::Mandarin => "Mandarin",
16779                        WhatLangScript::Myanmar => "Myanmar",
16780                        WhatLangScript::Oriya => "Oriya",
16781                        WhatLangScript::Sinhala => "Sinhala",
16782                        WhatLangScript::Tamil => "Tamil",
16783                        WhatLangScript::Telugu => "Telugu",
16784                        WhatLangScript::Thai => "Thai",
16785                        WhatLangScript::Bengali => "Bengali",
16786                        WhatLangScript::Armenian => "Armenian",
16787                    };
16788                    Ok(Value::String(Rc::new(script_name.to_string())))
16789                } else {
16790                    Ok(Value::String(Rc::new("Unknown".to_string())))
16791                }
16792            }
16793            _ => Err(RuntimeError::new(
16794                "detect_script_whatlang() requires string",
16795            )),
16796        },
16797    );
16798
16799    // is_language - check if text is in a specific language
16800    define(interp, "is_language", Some(2), |_, args| {
16801        match (&args[0], &args[1]) {
16802            (Value::String(s), Value::String(lang)) => {
16803                if let Some(info) = detect(s) {
16804                    let detected = match info.lang() {
16805                        Lang::Eng => "en",
16806                        Lang::Spa => "es",
16807                        Lang::Fra => "fr",
16808                        Lang::Deu => "de",
16809                        Lang::Ita => "it",
16810                        Lang::Por => "pt",
16811                        Lang::Rus => "ru",
16812                        _ => "unknown",
16813                    };
16814                    Ok(Value::Bool(detected == lang.as_str()))
16815                } else {
16816                    Ok(Value::Bool(false))
16817                }
16818            }
16819            _ => Err(RuntimeError::new(
16820                "is_language() requires string and language code",
16821            )),
16822        }
16823    });
16824
16825    // =========================================================================
16826    // LLM TOKEN COUNTING
16827    // =========================================================================
16828
16829    // token_count - count tokens using cl100k_base (GPT-4, Claude compatible)
16830    define(interp, "token_count", Some(1), |_, args| match &args[0] {
16831        Value::String(s) => {
16832            if let Ok(bpe) = cl100k_base() {
16833                let tokens = bpe.encode_with_special_tokens(s);
16834                Ok(Value::Int(tokens.len() as i64))
16835            } else {
16836                Err(RuntimeError::new("Failed to initialize tokenizer"))
16837            }
16838        }
16839        _ => Err(RuntimeError::new("token_count() requires string")),
16840    });
16841
16842    // token_count_model - count tokens for specific model
16843    define(interp, "token_count_model", Some(2), |_, args| {
16844        match (&args[0], &args[1]) {
16845            (Value::String(s), Value::String(model)) => {
16846                let bpe_result = match model.as_str() {
16847                    "gpt4" | "gpt-4" | "claude" | "cl100k" => cl100k_base(),
16848                    "gpt3" | "gpt-3" | "p50k" => p50k_base(),
16849                    "codex" | "r50k" => r50k_base(),
16850                    _ => cl100k_base(), // Default to GPT-4/Claude
16851                };
16852                if let Ok(bpe) = bpe_result {
16853                    let tokens = bpe.encode_with_special_tokens(s);
16854                    Ok(Value::Int(tokens.len() as i64))
16855                } else {
16856                    Err(RuntimeError::new("Failed to initialize tokenizer"))
16857                }
16858            }
16859            _ => Err(RuntimeError::new(
16860                "token_count_model() requires string and model name",
16861            )),
16862        }
16863    });
16864
16865    // tokenize_ids - get token IDs as array
16866    define(interp, "tokenize_ids", Some(1), |_, args| match &args[0] {
16867        Value::String(s) => {
16868            if let Ok(bpe) = cl100k_base() {
16869                let tokens = bpe.encode_with_special_tokens(s);
16870                let values: Vec<Value> = tokens.into_iter().map(|t| Value::Int(t as i64)).collect();
16871                Ok(Value::Array(Rc::new(RefCell::new(values))))
16872            } else {
16873                Err(RuntimeError::new("Failed to initialize tokenizer"))
16874            }
16875        }
16876        _ => Err(RuntimeError::new("tokenize_ids() requires string")),
16877    });
16878
16879    // truncate_tokens - truncate string to max tokens
16880    define(interp, "truncate_tokens", Some(2), |_, args| {
16881        match (&args[0], &args[1]) {
16882            (Value::String(s), Value::Int(max_tokens)) => {
16883                if let Ok(bpe) = cl100k_base() {
16884                    let tokens = bpe.encode_with_special_tokens(s);
16885                    if tokens.len() <= *max_tokens as usize {
16886                        Ok(Value::String(s.clone()))
16887                    } else {
16888                        let truncated: Vec<usize> =
16889                            tokens.into_iter().take(*max_tokens as usize).collect();
16890                        if let Ok(decoded) = bpe.decode(truncated) {
16891                            Ok(Value::String(Rc::new(decoded)))
16892                        } else {
16893                            Err(RuntimeError::new("Failed to decode tokens"))
16894                        }
16895                    }
16896                } else {
16897                    Err(RuntimeError::new("Failed to initialize tokenizer"))
16898                }
16899            }
16900            _ => Err(RuntimeError::new(
16901                "truncate_tokens() requires string and max tokens",
16902            )),
16903        }
16904    });
16905
16906    // estimate_cost - estimate API cost based on token count
16907    define(interp, "estimate_cost", Some(3), |_, args| {
16908        match (&args[0], &args[1], &args[2]) {
16909            (Value::String(s), Value::Float(input_cost), Value::Float(output_cost)) => {
16910                if let Ok(bpe) = cl100k_base() {
16911                    let tokens = bpe.encode_with_special_tokens(s);
16912                    let count = tokens.len() as f64;
16913                    // Cost per 1K tokens
16914                    let input_total = (count / 1000.0) * input_cost;
16915                    let output_total = (count / 1000.0) * output_cost;
16916                    let mut map = HashMap::new();
16917                    map.insert("tokens".to_string(), Value::Int(tokens.len() as i64));
16918                    map.insert("input_cost".to_string(), Value::Float(input_total));
16919                    map.insert("output_cost".to_string(), Value::Float(output_total));
16920                    Ok(Value::Map(Rc::new(RefCell::new(map))))
16921                } else {
16922                    Err(RuntimeError::new("Failed to initialize tokenizer"))
16923                }
16924            }
16925            _ => Err(RuntimeError::new(
16926                "estimate_cost() requires string, input cost, output cost",
16927            )),
16928        }
16929    });
16930
16931    // =========================================================================
16932    // STEMMING
16933    // =========================================================================
16934
16935    // stem - stem a word using Porter algorithm
16936    define(interp, "stem", Some(1), |_, args| match &args[0] {
16937        Value::String(s) => {
16938            let stemmer = Stemmer::create(StemAlgorithm::English);
16939            let stemmed = stemmer.stem(s);
16940            Ok(Value::String(Rc::new(stemmed.to_string())))
16941        }
16942        _ => Err(RuntimeError::new("stem() requires string")),
16943    });
16944
16945    // stem_language - stem a word for specific language
16946    define(interp, "stem_language", Some(2), |_, args| {
16947        match (&args[0], &args[1]) {
16948            (Value::String(s), Value::String(lang)) => {
16949                let algorithm = match lang.as_str() {
16950                    "en" | "english" => StemAlgorithm::English,
16951                    "fr" | "french" => StemAlgorithm::French,
16952                    "de" | "german" => StemAlgorithm::German,
16953                    "es" | "spanish" => StemAlgorithm::Spanish,
16954                    "it" | "italian" => StemAlgorithm::Italian,
16955                    "pt" | "portuguese" => StemAlgorithm::Portuguese,
16956                    "nl" | "dutch" => StemAlgorithm::Dutch,
16957                    "sv" | "swedish" => StemAlgorithm::Swedish,
16958                    "no" | "norwegian" => StemAlgorithm::Norwegian,
16959                    "da" | "danish" => StemAlgorithm::Danish,
16960                    "fi" | "finnish" => StemAlgorithm::Finnish,
16961                    "ru" | "russian" => StemAlgorithm::Russian,
16962                    "ro" | "romanian" => StemAlgorithm::Romanian,
16963                    "hu" | "hungarian" => StemAlgorithm::Hungarian,
16964                    "tr" | "turkish" => StemAlgorithm::Turkish,
16965                    "ar" | "arabic" => StemAlgorithm::Arabic,
16966                    _ => StemAlgorithm::English,
16967                };
16968                let stemmer = Stemmer::create(algorithm);
16969                let stemmed = stemmer.stem(s);
16970                Ok(Value::String(Rc::new(stemmed.to_string())))
16971            }
16972            _ => Err(RuntimeError::new(
16973                "stem_language() requires string and language code",
16974            )),
16975        }
16976    });
16977
16978    // stem_all - stem all words in array
16979    define(interp, "stem_all", Some(1), |_, args| match &args[0] {
16980        Value::Array(arr) => {
16981            let stemmer = Stemmer::create(StemAlgorithm::English);
16982            let arr_ref = arr.borrow();
16983            let results: Vec<Value> = arr_ref
16984                .iter()
16985                .filter_map(|v| {
16986                    if let Value::String(s) = v {
16987                        Some(Value::String(Rc::new(stemmer.stem(s).to_string())))
16988                    } else {
16989                        None
16990                    }
16991                })
16992                .collect();
16993            Ok(Value::Array(Rc::new(RefCell::new(results))))
16994        }
16995        _ => Err(RuntimeError::new("stem_all() requires array of strings")),
16996    });
16997
16998    // =========================================================================
16999    // STOPWORDS
17000    // =========================================================================
17001
17002    // is_stopword - check if word is a stopword
17003    define(interp, "is_stopword", Some(1), |_, args| match &args[0] {
17004        Value::String(s) => {
17005            let word = s.to_lowercase();
17006            let stopwords = get_stopwords("en");
17007            Ok(Value::Bool(stopwords.contains(&word.as_str())))
17008        }
17009        _ => Err(RuntimeError::new("is_stopword() requires string")),
17010    });
17011
17012    // is_stopword_language - check if word is stopword in language
17013    define(interp, "is_stopword_language", Some(2), |_, args| {
17014        match (&args[0], &args[1]) {
17015            (Value::String(s), Value::String(lang)) => {
17016                let word = s.to_lowercase();
17017                let stopwords = get_stopwords(lang);
17018                Ok(Value::Bool(stopwords.contains(&word.as_str())))
17019            }
17020            _ => Err(RuntimeError::new(
17021                "is_stopword_language() requires string and language",
17022            )),
17023        }
17024    });
17025
17026    // remove_stopwords - remove stopwords from array
17027    define(interp, "remove_stopwords", Some(1), |_, args| {
17028        match &args[0] {
17029            Value::Array(arr) => {
17030                let stopwords = get_stopwords("en");
17031                let arr_ref = arr.borrow();
17032                let results: Vec<Value> = arr_ref
17033                    .iter()
17034                    .filter(|v| {
17035                        if let Value::String(s) = v {
17036                            !stopwords.contains(&s.to_lowercase().as_str())
17037                        } else {
17038                            true
17039                        }
17040                    })
17041                    .cloned()
17042                    .collect();
17043                Ok(Value::Array(Rc::new(RefCell::new(results))))
17044            }
17045            _ => Err(RuntimeError::new(
17046                "remove_stopwords() requires array of strings",
17047            )),
17048        }
17049    });
17050
17051    // remove_stopwords_text - remove stopwords from text string
17052    define(
17053        interp,
17054        "remove_stopwords_text",
17055        Some(1),
17056        |_, args| match &args[0] {
17057            Value::String(s) => {
17058                let stopwords = get_stopwords("en");
17059                let words: Vec<&str> = s
17060                    .split_whitespace()
17061                    .filter(|w| !stopwords.contains(&w.to_lowercase().as_str()))
17062                    .collect();
17063                Ok(Value::String(Rc::new(words.join(" "))))
17064            }
17065            _ => Err(RuntimeError::new("remove_stopwords_text() requires string")),
17066        },
17067    );
17068
17069    // get_stopwords_list - get list of stopwords for language
17070    define(
17071        interp,
17072        "get_stopwords_list",
17073        Some(1),
17074        |_, args| match &args[0] {
17075            Value::String(lang) => {
17076                let stopwords = get_stopwords(lang);
17077                let values: Vec<Value> = stopwords
17078                    .iter()
17079                    .map(|s| Value::String(Rc::new(s.to_string())))
17080                    .collect();
17081                Ok(Value::Array(Rc::new(RefCell::new(values))))
17082            }
17083            _ => Err(RuntimeError::new(
17084                "get_stopwords_list() requires language code",
17085            )),
17086        },
17087    );
17088
17089    // =========================================================================
17090    // N-GRAMS AND SHINGLES
17091    // =========================================================================
17092
17093    // ngrams - extract word n-grams
17094    define(interp, "ngrams", Some(2), |_, args| {
17095        match (&args[0], &args[1]) {
17096            (Value::String(s), Value::Int(n)) => {
17097                let words: Vec<&str> = s.split_whitespace().collect();
17098                let n = *n as usize;
17099                if n == 0 || n > words.len() {
17100                    return Ok(Value::Array(Rc::new(RefCell::new(vec![]))));
17101                }
17102                let ngrams: Vec<Value> = words
17103                    .windows(n)
17104                    .map(|w| Value::String(Rc::new(w.join(" "))))
17105                    .collect();
17106                Ok(Value::Array(Rc::new(RefCell::new(ngrams))))
17107            }
17108            _ => Err(RuntimeError::new("ngrams() requires string and n")),
17109        }
17110    });
17111
17112    // char_ngrams - extract character n-grams
17113    define(interp, "char_ngrams", Some(2), |_, args| {
17114        match (&args[0], &args[1]) {
17115            (Value::String(s), Value::Int(n)) => {
17116                let chars: Vec<char> = s.chars().collect();
17117                let n = *n as usize;
17118                if n == 0 || n > chars.len() {
17119                    return Ok(Value::Array(Rc::new(RefCell::new(vec![]))));
17120                }
17121                let ngrams: Vec<Value> = chars
17122                    .windows(n)
17123                    .map(|w| Value::String(Rc::new(w.iter().collect())))
17124                    .collect();
17125                Ok(Value::Array(Rc::new(RefCell::new(ngrams))))
17126            }
17127            _ => Err(RuntimeError::new("char_ngrams() requires string and n")),
17128        }
17129    });
17130
17131    // shingles - extract word shingles (same as ngrams, but as set)
17132    define(interp, "shingles", Some(2), |_, args| {
17133        match (&args[0], &args[1]) {
17134            (Value::String(s), Value::Int(n)) => {
17135                let words: Vec<&str> = s.split_whitespace().collect();
17136                let n = *n as usize;
17137                if n == 0 || n > words.len() {
17138                    return Ok(Value::Array(Rc::new(RefCell::new(vec![]))));
17139                }
17140                let mut seen = std::collections::HashSet::new();
17141                let shingles: Vec<Value> = words
17142                    .windows(n)
17143                    .filter_map(|w| {
17144                        let s = w.join(" ");
17145                        if seen.insert(s.clone()) {
17146                            Some(Value::String(Rc::new(s)))
17147                        } else {
17148                            None
17149                        }
17150                    })
17151                    .collect();
17152                Ok(Value::Array(Rc::new(RefCell::new(shingles))))
17153            }
17154            _ => Err(RuntimeError::new("shingles() requires string and n")),
17155        }
17156    });
17157
17158    // jaccard_similarity - Jaccard similarity between two sets of shingles
17159    define(interp, "jaccard_similarity", Some(2), |_, args| {
17160        match (&args[0], &args[1]) {
17161            (Value::Array(a), Value::Array(b)) => {
17162                let a_ref = a.borrow();
17163                let b_ref = b.borrow();
17164                let set_a: std::collections::HashSet<String> = a_ref
17165                    .iter()
17166                    .filter_map(|v| {
17167                        if let Value::String(s) = v {
17168                            Some(s.to_string())
17169                        } else {
17170                            None
17171                        }
17172                    })
17173                    .collect();
17174                let set_b: std::collections::HashSet<String> = b_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 intersection = set_a.intersection(&set_b).count();
17185                let union = set_a.union(&set_b).count();
17186                if union == 0 {
17187                    Ok(Value::Float(0.0))
17188                } else {
17189                    Ok(Value::Float(intersection as f64 / union as f64))
17190                }
17191            }
17192            _ => Err(RuntimeError::new(
17193                "jaccard_similarity() requires two arrays",
17194            )),
17195        }
17196    });
17197
17198    // minhash_signature - compute MinHash signature for LSH
17199    define(interp, "minhash_signature", Some(2), |_, args| {
17200        match (&args[0], &args[1]) {
17201            (Value::Array(arr), Value::Int(num_hashes)) => {
17202                let arr_ref = arr.borrow();
17203                let items: std::collections::HashSet<String> = arr_ref
17204                    .iter()
17205                    .filter_map(|v| {
17206                        if let Value::String(s) = v {
17207                            Some(s.to_string())
17208                        } else {
17209                            None
17210                        }
17211                    })
17212                    .collect();
17213
17214                // Simple MinHash using polynomial rolling hash
17215                let mut signature: Vec<Value> = Vec::with_capacity(*num_hashes as usize);
17216                for i in 0..*num_hashes {
17217                    let mut min_hash: u64 = u64::MAX;
17218                    for item in &items {
17219                        let hash = compute_hash(item, i as u64);
17220                        if hash < min_hash {
17221                            min_hash = hash;
17222                        }
17223                    }
17224                    signature.push(Value::Int(min_hash as i64));
17225                }
17226                Ok(Value::Array(Rc::new(RefCell::new(signature))))
17227            }
17228            _ => Err(RuntimeError::new(
17229                "minhash_signature() requires array and num_hashes",
17230            )),
17231        }
17232    });
17233
17234    // =========================================================================
17235    // TEXT PREPROCESSING
17236    // =========================================================================
17237
17238    // preprocess_text - full text preprocessing pipeline
17239    define(interp, "preprocess_text", Some(1), |_, args| {
17240        match &args[0] {
17241            Value::String(s) => {
17242                // Lowercase
17243                let lower = s.to_lowercase();
17244                // Remove punctuation (keep letters, numbers, spaces)
17245                let clean: String = lower
17246                    .chars()
17247                    .filter(|c| c.is_alphanumeric() || c.is_whitespace())
17248                    .collect();
17249                // Normalize whitespace
17250                let normalized: String = clean.split_whitespace().collect::<Vec<_>>().join(" ");
17251                Ok(Value::String(Rc::new(normalized)))
17252            }
17253            _ => Err(RuntimeError::new("preprocess_text() requires string")),
17254        }
17255    });
17256
17257    // tokenize_words - split text into word tokens
17258    define(interp, "tokenize_words", Some(1), |_, args| {
17259        match &args[0] {
17260            Value::String(s) => {
17261                let words: Vec<Value> = s
17262                    .split_whitespace()
17263                    .map(|w| Value::String(Rc::new(w.to_string())))
17264                    .collect();
17265                Ok(Value::Array(Rc::new(RefCell::new(words))))
17266            }
17267            _ => Err(RuntimeError::new("tokenize_words() requires string")),
17268        }
17269    });
17270
17271    // extract_keywords - extract likely keywords (content words)
17272    define(interp, "extract_keywords", Some(1), |_, args| {
17273        match &args[0] {
17274            Value::String(s) => {
17275                let stopwords = get_stopwords("en");
17276                let words: Vec<Value> = s
17277                    .split_whitespace()
17278                    .filter(|w| {
17279                        let lower = w.to_lowercase();
17280                        !stopwords.contains(&lower.as_str()) && lower.len() > 2
17281                    })
17282                    .map(|w| Value::String(Rc::new(w.to_lowercase())))
17283                    .collect();
17284                Ok(Value::Array(Rc::new(RefCell::new(words))))
17285            }
17286            _ => Err(RuntimeError::new("extract_keywords() requires string")),
17287        }
17288    });
17289
17290    // word_frequency - count word frequencies
17291    define(interp, "word_frequency", Some(1), |_, args| {
17292        match &args[0] {
17293            Value::String(s) => {
17294                let mut freq: HashMap<String, i64> = HashMap::new();
17295                for word in s.split_whitespace() {
17296                    let lower = word.to_lowercase();
17297                    *freq.entry(lower).or_insert(0) += 1;
17298                }
17299                let map: HashMap<String, Value> =
17300                    freq.into_iter().map(|(k, v)| (k, Value::Int(v))).collect();
17301                Ok(Value::Map(Rc::new(RefCell::new(map))))
17302            }
17303            _ => Err(RuntimeError::new("word_frequency() requires string")),
17304        }
17305    });
17306
17307    // =========================================================================
17308    // AFFECTIVE MARKERS (Emotional Intelligence)
17309    // =========================================================================
17310
17311    // sentiment_words - basic sentiment word detection
17312    define(interp, "sentiment_words", Some(1), |_, args| {
17313        match &args[0] {
17314            Value::String(s) => {
17315                let positive = vec![
17316                    "good",
17317                    "great",
17318                    "excellent",
17319                    "amazing",
17320                    "wonderful",
17321                    "fantastic",
17322                    "love",
17323                    "happy",
17324                    "joy",
17325                    "beautiful",
17326                    "awesome",
17327                    "perfect",
17328                    "best",
17329                    "brilliant",
17330                    "delightful",
17331                    "pleasant",
17332                    "positive",
17333                ];
17334                let negative = vec![
17335                    "bad",
17336                    "terrible",
17337                    "awful",
17338                    "horrible",
17339                    "hate",
17340                    "sad",
17341                    "angry",
17342                    "worst",
17343                    "poor",
17344                    "negative",
17345                    "disappointing",
17346                    "ugly",
17347                    "disgusting",
17348                    "painful",
17349                    "miserable",
17350                    "annoying",
17351                ];
17352
17353                let lower = s.to_lowercase();
17354                let words: Vec<&str> = lower.split_whitespace().collect();
17355                let pos_count: i64 = words.iter().filter(|w| positive.contains(w)).count() as i64;
17356                let neg_count: i64 = words.iter().filter(|w| negative.contains(w)).count() as i64;
17357
17358                let mut map = HashMap::new();
17359                map.insert("positive".to_string(), Value::Int(pos_count));
17360                map.insert("negative".to_string(), Value::Int(neg_count));
17361                map.insert("total".to_string(), Value::Int(words.len() as i64));
17362
17363                let score = if pos_count + neg_count > 0 {
17364                    (pos_count - neg_count) as f64 / (pos_count + neg_count) as f64
17365                } else {
17366                    0.0
17367                };
17368                map.insert("score".to_string(), Value::Float(score));
17369
17370                Ok(Value::Map(Rc::new(RefCell::new(map))))
17371            }
17372            _ => Err(RuntimeError::new("sentiment_words() requires string")),
17373        }
17374    });
17375
17376    // has_question - detect if text contains a question
17377    define(interp, "has_question", Some(1), |_, args| match &args[0] {
17378        Value::String(s) => {
17379            let has_q_mark = s.contains('?');
17380            let lower = s.to_lowercase();
17381            let question_words = [
17382                "what", "where", "when", "why", "how", "who", "which", "whose", "whom",
17383            ];
17384            let starts_with_q = question_words.iter().any(|w| lower.starts_with(w));
17385            Ok(Value::Bool(has_q_mark || starts_with_q))
17386        }
17387        _ => Err(RuntimeError::new("has_question() requires string")),
17388    });
17389
17390    // has_exclamation - detect if text has strong emotion markers
17391    define(interp, "has_exclamation", Some(1), |_, args| {
17392        match &args[0] {
17393            Value::String(s) => Ok(Value::Bool(s.contains('!'))),
17394            _ => Err(RuntimeError::new("has_exclamation() requires string")),
17395        }
17396    });
17397
17398    // text_formality - estimate text formality (0=informal, 1=formal)
17399    define(interp, "text_formality", Some(1), |_, args| {
17400        match &args[0] {
17401            Value::String(s) => {
17402                let lower = s.to_lowercase();
17403                let informal_markers = vec![
17404                    "gonna", "wanna", "gotta", "kinda", "sorta", "dunno", "yeah", "yep", "nope",
17405                    "ok", "lol", "omg", "btw", "u", "ur", "r", "y", "2", "4",
17406                ];
17407                let formal_markers = vec![
17408                    "therefore",
17409                    "furthermore",
17410                    "moreover",
17411                    "consequently",
17412                    "nevertheless",
17413                    "however",
17414                    "whereas",
17415                    "hereby",
17416                    "respectfully",
17417                    "sincerely",
17418                    "accordingly",
17419                ];
17420
17421                let words: Vec<&str> = lower.split_whitespace().collect();
17422                let informal_count = words
17423                    .iter()
17424                    .filter(|w| informal_markers.contains(w))
17425                    .count();
17426                let formal_count = words.iter().filter(|w| formal_markers.contains(w)).count();
17427
17428                let score = if informal_count + formal_count > 0 {
17429                    formal_count as f64 / (informal_count + formal_count) as f64
17430                } else {
17431                    0.5 // Neutral if no markers
17432                };
17433
17434                Ok(Value::Float(score))
17435            }
17436            _ => Err(RuntimeError::new("text_formality() requires string")),
17437        }
17438    });
17439
17440    // =========================================================================
17441    // VADER-STYLE SENTIMENT ANALYSIS
17442    // =========================================================================
17443
17444    // sentiment_vader - VADER-inspired sentiment analysis with intensity
17445    define(interp, "sentiment_vader", Some(1), |_, args| {
17446        match &args[0] {
17447            Value::String(s) => {
17448                let result = compute_vader_sentiment(s);
17449                let mut map = HashMap::new();
17450                map.insert("positive".to_string(), Value::Float(result.0));
17451                map.insert("negative".to_string(), Value::Float(result.1));
17452                map.insert("neutral".to_string(), Value::Float(result.2));
17453                map.insert("compound".to_string(), Value::Float(result.3));
17454                Ok(Value::Map(Rc::new(RefCell::new(map))))
17455            }
17456            _ => Err(RuntimeError::new("sentiment_vader() requires string")),
17457        }
17458    });
17459
17460    // emotion_detect - detect specific emotions
17461    define(interp, "emotion_detect", Some(1), |_, args| {
17462        match &args[0] {
17463            Value::String(s) => {
17464                let emotions = compute_emotions(s);
17465                let map: HashMap<String, Value> = emotions
17466                    .into_iter()
17467                    .map(|(k, v)| (k, Value::Float(v)))
17468                    .collect();
17469                Ok(Value::Map(Rc::new(RefCell::new(map))))
17470            }
17471            _ => Err(RuntimeError::new("emotion_detect() requires string")),
17472        }
17473    });
17474
17475    // intensity_words - detect intensity modifiers
17476    define(interp, "intensity_score", Some(1), |_, args| {
17477        match &args[0] {
17478            Value::String(s) => {
17479                let score = compute_intensity(s);
17480                Ok(Value::Float(score))
17481            }
17482            _ => Err(RuntimeError::new("intensity_score() requires string")),
17483        }
17484    });
17485
17486    // =========================================================================
17487    // SARCASM AND IRONY DETECTION
17488    // =========================================================================
17489
17490    // detect_sarcasm - detect potential sarcasm/irony markers
17491    define(interp, "detect_sarcasm", Some(1), |_, args| {
17492        match &args[0] {
17493            Value::String(s) => {
17494                let result = compute_sarcasm_score(s);
17495                let mut map = HashMap::new();
17496                map.insert("score".to_string(), Value::Float(result.0));
17497                map.insert("confidence".to_string(), Value::Float(result.1));
17498                let markers: Vec<Value> = result
17499                    .2
17500                    .into_iter()
17501                    .map(|m| Value::String(Rc::new(m)))
17502                    .collect();
17503                map.insert(
17504                    "markers".to_string(),
17505                    Value::Array(Rc::new(RefCell::new(markers))),
17506                );
17507                Ok(Value::Map(Rc::new(RefCell::new(map))))
17508            }
17509            _ => Err(RuntimeError::new("detect_sarcasm() requires string")),
17510        }
17511    });
17512
17513    // is_sarcastic - simple boolean sarcasm check
17514    define(interp, "is_sarcastic", Some(1), |_, args| match &args[0] {
17515        Value::String(s) => {
17516            let result = compute_sarcasm_score(s);
17517            Ok(Value::Bool(result.0 > 0.5))
17518        }
17519        _ => Err(RuntimeError::new("is_sarcastic() requires string")),
17520    });
17521
17522    // detect_irony - detect verbal irony patterns
17523    define(interp, "detect_irony", Some(1), |_, args| match &args[0] {
17524        Value::String(s) => {
17525            let score = compute_irony_score(s);
17526            Ok(Value::Float(score))
17527        }
17528        _ => Err(RuntimeError::new("detect_irony() requires string")),
17529    });
17530
17531    // =========================================================================
17532    // NAMED ENTITY RECOGNITION (Pattern-based)
17533    // =========================================================================
17534
17535    // extract_emails - extract email addresses
17536    define(interp, "extract_emails", Some(1), |_, args| {
17537        match &args[0] {
17538            Value::String(s) => {
17539                let re = Regex::new(r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}").unwrap();
17540                let emails: Vec<Value> = re
17541                    .find_iter(s)
17542                    .map(|m| Value::String(Rc::new(m.as_str().to_string())))
17543                    .collect();
17544                Ok(Value::Array(Rc::new(RefCell::new(emails))))
17545            }
17546            _ => Err(RuntimeError::new("extract_emails() requires string")),
17547        }
17548    });
17549
17550    // extract_urls - extract URLs
17551    define(interp, "extract_urls", Some(1), |_, args| match &args[0] {
17552        Value::String(s) => {
17553            let re = Regex::new(r"https?://[^\s<>\[\]{}|\\^]+").unwrap();
17554            let urls: Vec<Value> = re
17555                .find_iter(s)
17556                .map(|m| Value::String(Rc::new(m.as_str().to_string())))
17557                .collect();
17558            Ok(Value::Array(Rc::new(RefCell::new(urls))))
17559        }
17560        _ => Err(RuntimeError::new("extract_urls() requires string")),
17561    });
17562
17563    // extract_phone_numbers - extract phone numbers
17564    define(
17565        interp,
17566        "extract_phone_numbers",
17567        Some(1),
17568        |_, args| match &args[0] {
17569            Value::String(s) => {
17570                let re =
17571                    Regex::new(r"(?:\+?1[-.\s]?)?\(?[0-9]{3}\)?[-.\s]?[0-9]{3}[-.\s]?[0-9]{4}")
17572                        .unwrap();
17573                let phones: Vec<Value> = re
17574                    .find_iter(s)
17575                    .map(|m| Value::String(Rc::new(m.as_str().to_string())))
17576                    .collect();
17577                Ok(Value::Array(Rc::new(RefCell::new(phones))))
17578            }
17579            _ => Err(RuntimeError::new("extract_phone_numbers() requires string")),
17580        },
17581    );
17582
17583    // extract_dates - extract date patterns
17584    define(interp, "extract_dates", Some(1), |_, args| {
17585        match &args[0] {
17586            Value::String(s) => {
17587                // Various date formats
17588                let patterns = vec![
17589                    r"\d{4}-\d{2}-\d{2}", // 2024-01-15
17590                    r"\d{2}/\d{2}/\d{4}", // 01/15/2024
17591                    r"\d{2}-\d{2}-\d{4}", // 01-15-2024
17592                    r"(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[a-z]*\s+\d{1,2},?\s+\d{4}",
17593                    r"\d{1,2}\s+(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[a-z]*\s+\d{4}",
17594                ];
17595                let mut dates = Vec::new();
17596                for pattern in patterns {
17597                    if let Ok(re) = Regex::new(pattern) {
17598                        for m in re.find_iter(s) {
17599                            dates.push(Value::String(Rc::new(m.as_str().to_string())));
17600                        }
17601                    }
17602                }
17603                Ok(Value::Array(Rc::new(RefCell::new(dates))))
17604            }
17605            _ => Err(RuntimeError::new("extract_dates() requires string")),
17606        }
17607    });
17608
17609    // extract_money - extract monetary values
17610    define(interp, "extract_money", Some(1), |_, args| match &args[0] {
17611        Value::String(s) => {
17612            let re = Regex::new(r"[$€£¥]\s*\d+(?:,\d{3})*(?:\.\d{2})?|\d+(?:,\d{3})*(?:\.\d{2})?\s*(?:dollars?|euros?|pounds?|USD|EUR|GBP)").unwrap();
17613            let money: Vec<Value> = re
17614                .find_iter(s)
17615                .map(|m| Value::String(Rc::new(m.as_str().to_string())))
17616                .collect();
17617            Ok(Value::Array(Rc::new(RefCell::new(money))))
17618        }
17619        _ => Err(RuntimeError::new("extract_money() requires string")),
17620    });
17621
17622    // extract_hashtags - extract hashtags
17623    define(interp, "extract_hashtags", Some(1), |_, args| {
17624        match &args[0] {
17625            Value::String(s) => {
17626                let re = Regex::new(r"#\w+").unwrap();
17627                let tags: Vec<Value> = re
17628                    .find_iter(s)
17629                    .map(|m| Value::String(Rc::new(m.as_str().to_string())))
17630                    .collect();
17631                Ok(Value::Array(Rc::new(RefCell::new(tags))))
17632            }
17633            _ => Err(RuntimeError::new("extract_hashtags() requires string")),
17634        }
17635    });
17636
17637    // extract_mentions - extract @mentions
17638    define(interp, "extract_mentions", Some(1), |_, args| {
17639        match &args[0] {
17640            Value::String(s) => {
17641                let re = Regex::new(r"@\w+").unwrap();
17642                let mentions: Vec<Value> = re
17643                    .find_iter(s)
17644                    .map(|m| Value::String(Rc::new(m.as_str().to_string())))
17645                    .collect();
17646                Ok(Value::Array(Rc::new(RefCell::new(mentions))))
17647            }
17648            _ => Err(RuntimeError::new("extract_mentions() requires string")),
17649        }
17650    });
17651
17652    // extract_numbers - extract all numbers
17653    define(interp, "extract_numbers", Some(1), |_, args| {
17654        match &args[0] {
17655            Value::String(s) => {
17656                let re = Regex::new(r"-?\d+(?:,\d{3})*(?:\.\d+)?").unwrap();
17657                let numbers: Vec<Value> = re
17658                    .find_iter(s)
17659                    .filter_map(|m| {
17660                        let num_str = m.as_str().replace(",", "");
17661                        if let Ok(n) = num_str.parse::<f64>() {
17662                            Some(Value::Float(n))
17663                        } else {
17664                            None
17665                        }
17666                    })
17667                    .collect();
17668                Ok(Value::Array(Rc::new(RefCell::new(numbers))))
17669            }
17670            _ => Err(RuntimeError::new("extract_numbers() requires string")),
17671        }
17672    });
17673
17674    // extract_entities - extract likely named entities (capitalized words)
17675    define(interp, "extract_entities", Some(1), |_, args| {
17676        match &args[0] {
17677            Value::String(s) => {
17678                // Simple heuristic: capitalized words not at sentence start
17679                let re = Regex::new(r"(?:[.!?]\s+)?([A-Z][a-z]+(?:\s+[A-Z][a-z]+)*)").unwrap();
17680                let mut entities = std::collections::HashSet::new();
17681                for cap in re.captures_iter(s) {
17682                    if let Some(m) = cap.get(1) {
17683                        let entity = m.as_str().to_string();
17684                        // Filter out common sentence starters
17685                        let starters = [
17686                            "The", "A", "An", "This", "That", "It", "I", "We", "They", "He", "She",
17687                        ];
17688                        if !starters.contains(&entity.as_str()) {
17689                            entities.insert(entity);
17690                        }
17691                    }
17692                }
17693                let results: Vec<Value> = entities
17694                    .into_iter()
17695                    .map(|e| Value::String(Rc::new(e)))
17696                    .collect();
17697                Ok(Value::Array(Rc::new(RefCell::new(results))))
17698            }
17699            _ => Err(RuntimeError::new("extract_entities() requires string")),
17700        }
17701    });
17702
17703    // =========================================================================
17704    // TEXT EMBEDDINGS (Hash-based, no ML required)
17705    // =========================================================================
17706
17707    // text_hash_vector - create a simple hash-based embedding
17708    define(interp, "text_hash_vector", Some(2), |_, args| {
17709        match (&args[0], &args[1]) {
17710            (Value::String(s), Value::Int(dims)) => {
17711                let dims = *dims as usize;
17712                let mut vector = vec![0.0f64; dims];
17713
17714                // Hash each word and add to vector
17715                for word in s.to_lowercase().split_whitespace() {
17716                    let hash = compute_hash(word, 0);
17717                    let idx = (hash as usize) % dims;
17718                    vector[idx] += 1.0;
17719                }
17720
17721                // Normalize
17722                let magnitude: f64 = vector.iter().map(|x| x * x).sum::<f64>().sqrt();
17723                if magnitude > 0.0 {
17724                    for v in vector.iter_mut() {
17725                        *v /= magnitude;
17726                    }
17727                }
17728
17729                let values: Vec<Value> = vector.into_iter().map(Value::Float).collect();
17730                Ok(Value::Array(Rc::new(RefCell::new(values))))
17731            }
17732            _ => Err(RuntimeError::new(
17733                "text_hash_vector() requires string and dimensions",
17734            )),
17735        }
17736    });
17737
17738    // text_fingerprint - create a compact fingerprint of text
17739    define(interp, "text_fingerprint", Some(1), |_, args| {
17740        match &args[0] {
17741            Value::String(s) => {
17742                // Create 64-bit fingerprint using multiple hashes
17743                let lower = s.to_lowercase();
17744                let words: Vec<&str> = lower.split_whitespace().collect();
17745
17746                let mut fp: u64 = 0;
17747                for (i, word) in words.iter().enumerate() {
17748                    let h = compute_hash(word, i as u64);
17749                    fp ^= h.rotate_left((i % 64) as u32);
17750                }
17751
17752                Ok(Value::String(Rc::new(format!("{:016x}", fp))))
17753            }
17754            _ => Err(RuntimeError::new("text_fingerprint() requires string")),
17755        }
17756    });
17757
17758    // cosine_similarity - compute cosine similarity between two vectors
17759    define(interp, "cosine_similarity", Some(2), |_, args| {
17760        match (&args[0], &args[1]) {
17761            (Value::Array(a), Value::Array(b)) => {
17762                let a_ref = a.borrow();
17763                let b_ref = b.borrow();
17764
17765                if a_ref.len() != b_ref.len() {
17766                    return Err(RuntimeError::new("Vectors must have same length"));
17767                }
17768
17769                let mut dot = 0.0;
17770                let mut mag_a = 0.0;
17771                let mut mag_b = 0.0;
17772
17773                for (va, vb) in a_ref.iter().zip(b_ref.iter()) {
17774                    let fa = match va {
17775                        Value::Float(f) => *f,
17776                        Value::Int(i) => *i as f64,
17777                        _ => continue,
17778                    };
17779                    let fb = match vb {
17780                        Value::Float(f) => *f,
17781                        Value::Int(i) => *i as f64,
17782                        _ => continue,
17783                    };
17784                    dot += fa * fb;
17785                    mag_a += fa * fa;
17786                    mag_b += fb * fb;
17787                }
17788
17789                let denom = (mag_a.sqrt()) * (mag_b.sqrt());
17790                if denom == 0.0 {
17791                    Ok(Value::Float(0.0))
17792                } else {
17793                    Ok(Value::Float(dot / denom))
17794                }
17795            }
17796            _ => Err(RuntimeError::new("cosine_similarity() requires two arrays")),
17797        }
17798    });
17799
17800    // text_similarity_embedding - compare texts using hash embeddings
17801    define(interp, "text_similarity_embedding", Some(2), |_, args| {
17802        match (&args[0], &args[1]) {
17803            (Value::String(a), Value::String(b)) => {
17804                let dims = 128;
17805
17806                // Create vectors for both texts
17807                let vec_a = create_hash_vector(a, dims);
17808                let vec_b = create_hash_vector(b, dims);
17809
17810                // Compute cosine similarity
17811                let mut dot = 0.0;
17812                let mut mag_a = 0.0;
17813                let mut mag_b = 0.0;
17814
17815                for i in 0..dims {
17816                    dot += vec_a[i] * vec_b[i];
17817                    mag_a += vec_a[i] * vec_a[i];
17818                    mag_b += vec_b[i] * vec_b[i];
17819                }
17820
17821                let denom = (mag_a.sqrt()) * (mag_b.sqrt());
17822                if denom == 0.0 {
17823                    Ok(Value::Float(0.0))
17824                } else {
17825                    Ok(Value::Float(dot / denom))
17826                }
17827            }
17828            _ => Err(RuntimeError::new(
17829                "text_similarity_embedding() requires two strings",
17830            )),
17831        }
17832    });
17833
17834    // =========================================================================
17835    // READABILITY METRICS
17836    // =========================================================================
17837
17838    // flesch_reading_ease - Flesch Reading Ease score
17839    define(
17840        interp,
17841        "flesch_reading_ease",
17842        Some(1),
17843        |_, args| match &args[0] {
17844            Value::String(s) => {
17845                let (words, sentences, syllables) = count_text_stats(s);
17846                if words == 0 || sentences == 0 {
17847                    return Ok(Value::Float(0.0));
17848                }
17849                let score = 206.835
17850                    - 1.015 * (words as f64 / sentences as f64)
17851                    - 84.6 * (syllables as f64 / words as f64);
17852                Ok(Value::Float(score.max(0.0).min(100.0)))
17853            }
17854            _ => Err(RuntimeError::new("flesch_reading_ease() requires string")),
17855        },
17856    );
17857
17858    // flesch_kincaid_grade - Flesch-Kincaid Grade Level
17859    define(
17860        interp,
17861        "flesch_kincaid_grade",
17862        Some(1),
17863        |_, args| match &args[0] {
17864            Value::String(s) => {
17865                let (words, sentences, syllables) = count_text_stats(s);
17866                if words == 0 || sentences == 0 {
17867                    return Ok(Value::Float(0.0));
17868                }
17869                let grade = 0.39 * (words as f64 / sentences as f64)
17870                    + 11.8 * (syllables as f64 / words as f64)
17871                    - 15.59;
17872                Ok(Value::Float(grade.max(0.0)))
17873            }
17874            _ => Err(RuntimeError::new("flesch_kincaid_grade() requires string")),
17875        },
17876    );
17877
17878    // automated_readability_index - ARI score
17879    define(
17880        interp,
17881        "automated_readability_index",
17882        Some(1),
17883        |_, args| match &args[0] {
17884            Value::String(s) => {
17885                let chars: usize = s.chars().filter(|c| c.is_alphanumeric()).count();
17886                let words: usize = s.split_whitespace().count();
17887                let sentences: usize = s
17888                    .matches(|c| c == '.' || c == '!' || c == '?')
17889                    .count()
17890                    .max(1);
17891
17892                if words == 0 {
17893                    return Ok(Value::Float(0.0));
17894                }
17895
17896                let ari = 4.71 * (chars as f64 / words as f64)
17897                    + 0.5 * (words as f64 / sentences as f64)
17898                    - 21.43;
17899                Ok(Value::Float(ari.max(0.0)))
17900            }
17901            _ => Err(RuntimeError::new(
17902                "automated_readability_index() requires string",
17903            )),
17904        },
17905    );
17906
17907    // reading_time - estimated reading time in minutes
17908    define(interp, "reading_time", Some(1), |_, args| {
17909        match &args[0] {
17910            Value::String(s) => {
17911                let words = s.split_whitespace().count();
17912                let minutes = words as f64 / 200.0; // Average reading speed
17913                Ok(Value::Float(minutes))
17914            }
17915            _ => Err(RuntimeError::new("reading_time() requires string")),
17916        }
17917    });
17918
17919    // speaking_time - estimated speaking time in minutes
17920    define(interp, "speaking_time", Some(1), |_, args| {
17921        match &args[0] {
17922            Value::String(s) => {
17923                let words = s.split_whitespace().count();
17924                let minutes = words as f64 / 150.0; // Average speaking speed
17925                Ok(Value::Float(minutes))
17926            }
17927            _ => Err(RuntimeError::new("speaking_time() requires string")),
17928        }
17929    });
17930}
17931
17932// =============================================================================
17933// HELPER FUNCTIONS FOR TEXT INTELLIGENCE
17934// =============================================================================
17935
17936/// VADER-style sentiment computation
17937fn compute_vader_sentiment(s: &str) -> (f64, f64, f64, f64) {
17938    // Sentiment lexicon with intensity
17939    let positive_words: Vec<(&str, f64)> = vec![
17940        ("love", 3.0),
17941        ("loved", 3.0),
17942        ("loving", 3.0),
17943        ("excellent", 3.0),
17944        ("amazing", 3.0),
17945        ("fantastic", 3.0),
17946        ("wonderful", 3.0),
17947        ("great", 2.5),
17948        ("awesome", 2.5),
17949        ("brilliant", 2.5),
17950        ("superb", 2.5),
17951        ("good", 2.0),
17952        ("nice", 2.0),
17953        ("pleasant", 2.0),
17954        ("happy", 2.0),
17955        ("like", 1.5),
17956        ("enjoy", 1.5),
17957        ("fine", 1.5),
17958        ("okay", 1.0),
17959        ("best", 3.0),
17960        ("perfect", 3.0),
17961        ("beautiful", 2.5),
17962        ("delightful", 2.5),
17963        ("excited", 2.5),
17964        ("thrilled", 3.0),
17965        ("glad", 2.0),
17966        ("pleased", 2.0),
17967    ];
17968
17969    let negative_words: Vec<(&str, f64)> = vec![
17970        ("hate", 3.0),
17971        ("hated", 3.0),
17972        ("hating", 3.0),
17973        ("terrible", 3.0),
17974        ("horrible", 3.0),
17975        ("awful", 3.0),
17976        ("disgusting", 3.0),
17977        ("bad", 2.5),
17978        ("poor", 2.5),
17979        ("worst", 3.0),
17980        ("pathetic", 2.5),
17981        ("sad", 2.0),
17982        ("angry", 2.5),
17983        ("upset", 2.0),
17984        ("disappointed", 2.0),
17985        ("dislike", 1.5),
17986        ("annoying", 2.0),
17987        ("boring", 1.5),
17988        ("mediocre", 1.0),
17989        ("ugly", 2.5),
17990        ("stupid", 2.5),
17991        ("dumb", 2.0),
17992        ("useless", 2.5),
17993        ("painful", 2.5),
17994        ("miserable", 3.0),
17995        ("depressing", 2.5),
17996        ("frustrating", 2.0),
17997    ];
17998
17999    // Intensity modifiers
18000    let boosters = vec![
18001        "very",
18002        "really",
18003        "extremely",
18004        "absolutely",
18005        "incredibly",
18006        "totally",
18007        "so",
18008    ];
18009    let dampeners = vec![
18010        "somewhat", "slightly", "a bit", "kind of", "sort of", "barely",
18011    ];
18012
18013    let lower = s.to_lowercase();
18014    let words: Vec<&str> = lower.split_whitespace().collect();
18015
18016    let mut pos_score = 0.0;
18017    let mut neg_score = 0.0;
18018    let mut word_count = 0;
18019
18020    for (i, word) in words.iter().enumerate() {
18021        let mut modifier = 1.0;
18022
18023        // Check for boosters/dampeners before this word
18024        if i > 0 {
18025            if boosters.contains(&words[i - 1]) {
18026                modifier = 1.5;
18027            } else if dampeners.iter().any(|d| words[i - 1].contains(d)) {
18028                modifier = 0.5;
18029            }
18030        }
18031
18032        // Check for negation
18033        let negated = i > 0
18034            && [
18035                "not",
18036                "no",
18037                "never",
18038                "neither",
18039                "don't",
18040                "doesn't",
18041                "didn't",
18042                "won't",
18043                "wouldn't",
18044                "couldn't",
18045                "shouldn't",
18046            ]
18047            .contains(&words[i - 1]);
18048
18049        if let Some((_, score)) = positive_words.iter().find(|(w, _)| w == word) {
18050            if negated {
18051                neg_score += score * modifier;
18052            } else {
18053                pos_score += score * modifier;
18054            }
18055            word_count += 1;
18056        } else if let Some((_, score)) = negative_words.iter().find(|(w, _)| w == word) {
18057            if negated {
18058                pos_score += score * modifier * 0.5; // Negated negative is mildly positive
18059            } else {
18060                neg_score += score * modifier;
18061            }
18062            word_count += 1;
18063        }
18064    }
18065
18066    // Normalize scores
18067    let total = pos_score + neg_score;
18068    let (pos_norm, neg_norm) = if total > 0.0 {
18069        (pos_score / total, neg_score / total)
18070    } else {
18071        (0.0, 0.0)
18072    };
18073
18074    let neutral = 1.0 - pos_norm - neg_norm;
18075
18076    // Compound score: normalized to [-1, 1]
18077    let compound = if word_count > 0 {
18078        ((pos_score - neg_score) / (word_count as f64 * 3.0))
18079            .max(-1.0)
18080            .min(1.0)
18081    } else {
18082        0.0
18083    };
18084
18085    (pos_norm, neg_norm, neutral.max(0.0), compound)
18086}
18087
18088/// Detect specific emotions
18089fn compute_emotions(s: &str) -> HashMap<String, f64> {
18090    let emotion_words: Vec<(&str, &str)> = vec![
18091        // Joy
18092        ("happy", "joy"),
18093        ("joyful", "joy"),
18094        ("delighted", "joy"),
18095        ("cheerful", "joy"),
18096        ("excited", "joy"),
18097        ("thrilled", "joy"),
18098        ("ecstatic", "joy"),
18099        ("elated", "joy"),
18100        // Sadness
18101        ("sad", "sadness"),
18102        ("unhappy", "sadness"),
18103        ("depressed", "sadness"),
18104        ("miserable", "sadness"),
18105        ("gloomy", "sadness"),
18106        ("heartbroken", "sadness"),
18107        ("sorrowful", "sadness"),
18108        ("melancholy", "sadness"),
18109        // Anger
18110        ("angry", "anger"),
18111        ("furious", "anger"),
18112        ("enraged", "anger"),
18113        ("irritated", "anger"),
18114        ("annoyed", "anger"),
18115        ("outraged", "anger"),
18116        ("livid", "anger"),
18117        ("mad", "anger"),
18118        // Fear
18119        ("afraid", "fear"),
18120        ("scared", "fear"),
18121        ("terrified", "fear"),
18122        ("frightened", "fear"),
18123        ("anxious", "fear"),
18124        ("worried", "fear"),
18125        ("nervous", "fear"),
18126        ("panicked", "fear"),
18127        // Surprise
18128        ("surprised", "surprise"),
18129        ("amazed", "surprise"),
18130        ("astonished", "surprise"),
18131        ("shocked", "surprise"),
18132        ("stunned", "surprise"),
18133        ("startled", "surprise"),
18134        ("bewildered", "surprise"),
18135        // Disgust
18136        ("disgusted", "disgust"),
18137        ("revolted", "disgust"),
18138        ("repulsed", "disgust"),
18139        ("sickened", "disgust"),
18140        ("nauseated", "disgust"),
18141        ("appalled", "disgust"),
18142        // Trust
18143        ("trust", "trust"),
18144        ("confident", "trust"),
18145        ("secure", "trust"),
18146        ("reliable", "trust"),
18147        ("faithful", "trust"),
18148        ("loyal", "trust"),
18149        // Anticipation
18150        ("eager", "anticipation"),
18151        ("hopeful", "anticipation"),
18152        ("expectant", "anticipation"),
18153        ("looking forward", "anticipation"),
18154        ("excited", "anticipation"),
18155    ];
18156
18157    let lower = s.to_lowercase();
18158    let mut counts: HashMap<String, f64> = HashMap::new();
18159
18160    for (word, emotion) in emotion_words {
18161        if lower.contains(word) {
18162            *counts.entry(emotion.to_string()).or_insert(0.0) += 1.0;
18163        }
18164    }
18165
18166    // Normalize
18167    let total: f64 = counts.values().sum();
18168    if total > 0.0 {
18169        for v in counts.values_mut() {
18170            *v /= total;
18171        }
18172    }
18173
18174    counts
18175}
18176
18177/// Compute text intensity
18178fn compute_intensity(s: &str) -> f64 {
18179    let intensifiers = vec![
18180        ("very", 1.5),
18181        ("really", 1.5),
18182        ("extremely", 2.0),
18183        ("incredibly", 2.0),
18184        ("absolutely", 2.0),
18185        ("totally", 1.5),
18186        ("completely", 1.5),
18187        ("utterly", 2.0),
18188        ("so", 1.3),
18189        ("such", 1.3),
18190        ("quite", 1.2),
18191        ("rather", 1.1),
18192    ];
18193
18194    let exclamation_boost = 0.5;
18195    let caps_boost = 0.3;
18196
18197    let lower = s.to_lowercase();
18198    let mut score = 1.0;
18199
18200    for (word, boost) in intensifiers {
18201        if lower.contains(word) {
18202            score *= boost;
18203        }
18204    }
18205
18206    // Check for exclamation marks
18207    let exclamations = s.matches('!').count();
18208    score += exclamations as f64 * exclamation_boost;
18209
18210    // Check for ALL CAPS words
18211    let caps_words = s
18212        .split_whitespace()
18213        .filter(|w| w.len() > 2 && w.chars().all(|c| c.is_uppercase()))
18214        .count();
18215    score += caps_words as f64 * caps_boost;
18216
18217    score.min(5.0)
18218}
18219
18220/// Detect sarcasm markers
18221fn compute_sarcasm_score(s: &str) -> (f64, f64, Vec<String>) {
18222    let mut markers = Vec::new();
18223    let mut score: f64 = 0.0;
18224
18225    let lower = s.to_lowercase();
18226
18227    // Explicit sarcasm markers
18228    let explicit = vec![
18229        "/s",
18230        "not!",
18231        "yeah right",
18232        "sure thing",
18233        "oh really",
18234        "oh great",
18235        "wow, just wow",
18236        "thanks a lot",
18237        "how wonderful",
18238        "isn't that special",
18239        "clearly",
18240        "obviously",
18241        "shocking",
18242        "no way",
18243        "what a surprise",
18244    ];
18245
18246    for marker in &explicit {
18247        if lower.contains(marker) {
18248            markers.push(format!("explicit: {}", marker));
18249            score += 0.4;
18250        }
18251    }
18252
18253    // Hyperbolic expressions
18254    let hyperbolic = vec![
18255        "best thing ever",
18256        "worst thing ever",
18257        "literally dying",
18258        "absolutely perfect",
18259        "world's greatest",
18260        "totally awesome",
18261        "so much fun",
18262        "couldn't be happier",
18263    ];
18264
18265    for h in &hyperbolic {
18266        if lower.contains(h) {
18267            markers.push(format!("hyperbole: {}", h));
18268            score += 0.3;
18269        }
18270    }
18271
18272    // Positive-negative contradiction patterns
18273    let has_positive = ["great", "wonderful", "amazing", "love", "best", "awesome"]
18274        .iter()
18275        .any(|w| lower.contains(w));
18276    let has_negative_context = ["but", "however", "although", "except", "unfortunately"]
18277        .iter()
18278        .any(|w| lower.contains(w));
18279
18280    if has_positive && has_negative_context {
18281        markers.push("positive-negative contrast".to_string());
18282        score += 0.25;
18283    }
18284
18285    // Quotation marks around positive words (air quotes)
18286    let quote_pattern = Regex::new(r#"["'](\w+)["']"#).unwrap();
18287    for cap in quote_pattern.captures_iter(s) {
18288        if let Some(m) = cap.get(1) {
18289            let word = m.as_str().to_lowercase();
18290            if [
18291                "great",
18292                "wonderful",
18293                "helpful",
18294                "useful",
18295                "smart",
18296                "genius",
18297                "brilliant",
18298            ]
18299            .contains(&word.as_str())
18300            {
18301                markers.push(format!("air quotes: \"{}\"", word));
18302                score += 0.35;
18303            }
18304        }
18305    }
18306
18307    // Excessive punctuation
18308    if s.contains("...") || s.contains("!!!") || s.contains("???") {
18309        markers.push("excessive punctuation".to_string());
18310        score += 0.15;
18311    }
18312
18313    // Calculate confidence based on number of markers
18314    let confidence = if markers.is_empty() {
18315        0.0
18316    } else {
18317        (markers.len() as f64 * 0.25).min(1.0)
18318    };
18319
18320    (score.min(1.0), confidence, markers)
18321}
18322
18323/// Detect irony patterns
18324fn compute_irony_score(s: &str) -> f64 {
18325    let mut score: f64 = 0.0;
18326    let lower = s.to_lowercase();
18327
18328    // Situational irony markers
18329    let irony_phrases = vec![
18330        "of course",
18331        "as expected",
18332        "naturally",
18333        "predictably",
18334        "who would have thought",
18335        "surprise surprise",
18336        "go figure",
18337        "typical",
18338        "as usual",
18339        "yet again",
18340        "once again",
18341    ];
18342
18343    for phrase in irony_phrases {
18344        if lower.contains(phrase) {
18345            score += 0.2;
18346        }
18347    }
18348
18349    // Contrast indicators
18350    if lower.contains("but") || lower.contains("yet") || lower.contains("however") {
18351        score += 0.1;
18352    }
18353
18354    // Rhetorical questions
18355    if s.contains('?')
18356        && (lower.starts_with("isn't")
18357            || lower.starts_with("aren't")
18358            || lower.starts_with("doesn't")
18359            || lower.starts_with("don't")
18360            || lower.contains("right?")
18361            || lower.contains("isn't it"))
18362    {
18363        score += 0.25;
18364    }
18365
18366    score.min(1.0)
18367}
18368
18369/// Create hash-based vector for text
18370fn create_hash_vector(s: &str, dims: usize) -> Vec<f64> {
18371    let mut vector = vec![0.0f64; dims];
18372
18373    for word in s.to_lowercase().split_whitespace() {
18374        let hash = compute_hash(word, 0);
18375        let idx = (hash as usize) % dims;
18376        vector[idx] += 1.0;
18377    }
18378
18379    // Normalize
18380    let magnitude: f64 = vector.iter().map(|x| x * x).sum::<f64>().sqrt();
18381    if magnitude > 0.0 {
18382        for v in vector.iter_mut() {
18383            *v /= magnitude;
18384        }
18385    }
18386
18387    vector
18388}
18389
18390/// Count text statistics for readability
18391fn count_text_stats(s: &str) -> (usize, usize, usize) {
18392    let words: Vec<&str> = s.split_whitespace().collect();
18393    let word_count = words.len();
18394    let sentence_count = s
18395        .matches(|c| c == '.' || c == '!' || c == '?')
18396        .count()
18397        .max(1);
18398
18399    let mut syllable_count = 0;
18400    for word in &words {
18401        syllable_count += count_syllables(word);
18402    }
18403
18404    (word_count, sentence_count, syllable_count)
18405}
18406
18407/// Count syllables in a word (English approximation)
18408fn count_syllables(word: &str) -> usize {
18409    let word = word.to_lowercase();
18410    let vowels = ['a', 'e', 'i', 'o', 'u', 'y'];
18411    let mut count = 0;
18412    let mut prev_was_vowel = false;
18413
18414    for c in word.chars() {
18415        let is_vowel = vowels.contains(&c);
18416        if is_vowel && !prev_was_vowel {
18417            count += 1;
18418        }
18419        prev_was_vowel = is_vowel;
18420    }
18421
18422    // Adjust for silent e
18423    if word.ends_with('e') && count > 1 {
18424        count -= 1;
18425    }
18426
18427    count.max(1)
18428}
18429
18430/// Compute American Soundex encoding
18431fn compute_soundex(s: &str) -> String {
18432    if s.is_empty() {
18433        return "0000".to_string();
18434    }
18435
18436    let s = s.to_uppercase();
18437    let chars: Vec<char> = s.chars().filter(|c| c.is_ascii_alphabetic()).collect();
18438
18439    if chars.is_empty() {
18440        return "0000".to_string();
18441    }
18442
18443    let first = chars[0];
18444    let mut code = String::new();
18445    code.push(first);
18446
18447    let get_code = |c: char| -> char {
18448        match c {
18449            'B' | 'F' | 'P' | 'V' => '1',
18450            'C' | 'G' | 'J' | 'K' | 'Q' | 'S' | 'X' | 'Z' => '2',
18451            'D' | 'T' => '3',
18452            'L' => '4',
18453            'M' | 'N' => '5',
18454            'R' => '6',
18455            _ => '0',
18456        }
18457    };
18458
18459    let mut prev_code = get_code(first);
18460
18461    for &c in chars.iter().skip(1) {
18462        let curr_code = get_code(c);
18463        if curr_code != '0' && curr_code != prev_code {
18464            code.push(curr_code);
18465            if code.len() == 4 {
18466                break;
18467            }
18468        }
18469        prev_code = curr_code;
18470    }
18471
18472    while code.len() < 4 {
18473        code.push('0');
18474    }
18475
18476    code
18477}
18478
18479/// Compute Metaphone encoding
18480fn compute_metaphone(s: &str) -> String {
18481    let s = s.to_uppercase();
18482    let chars: Vec<char> = s.chars().filter(|c| c.is_ascii_alphabetic()).collect();
18483
18484    if chars.is_empty() {
18485        return String::new();
18486    }
18487
18488    let mut result = String::new();
18489    let mut i = 0;
18490
18491    // Skip initial KN, GN, PN, AE, WR
18492    if chars.len() >= 2 {
18493        let prefix: String = chars[0..2].iter().collect();
18494        if ["KN", "GN", "PN", "AE", "WR"].contains(&prefix.as_str()) {
18495            i = 1;
18496        }
18497    }
18498
18499    while i < chars.len() && result.len() < 6 {
18500        let c = chars[i];
18501        let prev = if i > 0 { Some(chars[i - 1]) } else { None };
18502        let next = chars.get(i + 1).copied();
18503
18504        let code = match c {
18505            'A' | 'E' | 'I' | 'O' | 'U' => {
18506                if i == 0 {
18507                    Some(c)
18508                } else {
18509                    None
18510                }
18511            }
18512            'B' => {
18513                if prev != Some('M') || i == chars.len() - 1 {
18514                    Some('B')
18515                } else {
18516                    None
18517                }
18518            }
18519            'C' => {
18520                if next == Some('H') {
18521                    Some('X')
18522                } else if matches!(next, Some('I') | Some('E') | Some('Y')) {
18523                    Some('S')
18524                } else {
18525                    Some('K')
18526                }
18527            }
18528            'D' => {
18529                if next == Some('G')
18530                    && matches!(chars.get(i + 2), Some('E') | Some('I') | Some('Y'))
18531                {
18532                    Some('J')
18533                } else {
18534                    Some('T')
18535                }
18536            }
18537            'F' => Some('F'),
18538            'G' => {
18539                if next == Some('H')
18540                    && !matches!(
18541                        chars.get(i + 2),
18542                        Some('A') | Some('E') | Some('I') | Some('O') | Some('U')
18543                    )
18544                {
18545                    None
18546                } else if matches!(next, Some('N') | Some('E') | Some('I') | Some('Y')) {
18547                    Some('J')
18548                } else {
18549                    Some('K')
18550                }
18551            }
18552            'H' => {
18553                if matches!(
18554                    prev,
18555                    Some('A') | Some('E') | Some('I') | Some('O') | Some('U')
18556                ) {
18557                    None
18558                } else if matches!(
18559                    next,
18560                    Some('A') | Some('E') | Some('I') | Some('O') | Some('U')
18561                ) {
18562                    Some('H')
18563                } else {
18564                    None
18565                }
18566            }
18567            'J' => Some('J'),
18568            'K' => {
18569                if prev != Some('C') {
18570                    Some('K')
18571                } else {
18572                    None
18573                }
18574            }
18575            'L' => Some('L'),
18576            'M' => Some('M'),
18577            'N' => Some('N'),
18578            'P' => {
18579                if next == Some('H') {
18580                    Some('F')
18581                } else {
18582                    Some('P')
18583                }
18584            }
18585            'Q' => Some('K'),
18586            'R' => Some('R'),
18587            'S' => {
18588                if next == Some('H') {
18589                    Some('X')
18590                } else {
18591                    Some('S')
18592                }
18593            }
18594            'T' => {
18595                if next == Some('H') {
18596                    Some('0') // TH sound
18597                } else if next == Some('I') && matches!(chars.get(i + 2), Some('O') | Some('A')) {
18598                    Some('X')
18599                } else {
18600                    Some('T')
18601                }
18602            }
18603            'V' => Some('F'),
18604            'W' | 'Y' => {
18605                if matches!(
18606                    next,
18607                    Some('A') | Some('E') | Some('I') | Some('O') | Some('U')
18608                ) {
18609                    Some(c)
18610                } else {
18611                    None
18612                }
18613            }
18614            'X' => {
18615                result.push('K');
18616                Some('S')
18617            }
18618            'Z' => Some('S'),
18619            _ => None,
18620        };
18621
18622        if let Some(ch) = code {
18623            result.push(ch);
18624        }
18625
18626        // Skip double letters
18627        if next == Some(c) {
18628            i += 1;
18629        }
18630        i += 1;
18631    }
18632
18633    result
18634}
18635
18636/// Compute Cologne phonetic encoding (for German)
18637fn compute_cologne(s: &str) -> String {
18638    let s = s.to_uppercase();
18639    let chars: Vec<char> = s.chars().filter(|c| c.is_ascii_alphabetic()).collect();
18640
18641    if chars.is_empty() {
18642        return String::new();
18643    }
18644
18645    let mut result = String::new();
18646
18647    for (i, &c) in chars.iter().enumerate() {
18648        let prev = if i > 0 { Some(chars[i - 1]) } else { None };
18649        let next = chars.get(i + 1).copied();
18650
18651        let code = match c {
18652            'A' | 'E' | 'I' | 'O' | 'U' | 'J' | 'Y' => '0',
18653            'H' => continue,
18654            'B' | 'P' => '1',
18655            'D' | 'T' => {
18656                if matches!(next, Some('C') | Some('S') | Some('Z')) {
18657                    '8'
18658                } else {
18659                    '2'
18660                }
18661            }
18662            'F' | 'V' | 'W' => '3',
18663            'G' | 'K' | 'Q' => '4',
18664            'C' => {
18665                if i == 0 {
18666                    if matches!(
18667                        next,
18668                        Some('A')
18669                            | Some('H')
18670                            | Some('K')
18671                            | Some('L')
18672                            | Some('O')
18673                            | Some('Q')
18674                            | Some('R')
18675                            | Some('U')
18676                            | Some('X')
18677                    ) {
18678                        '4'
18679                    } else {
18680                        '8'
18681                    }
18682                } else if matches!(prev, Some('S') | Some('Z')) {
18683                    '8'
18684                } else if matches!(
18685                    next,
18686                    Some('A')
18687                        | Some('H')
18688                        | Some('K')
18689                        | Some('O')
18690                        | Some('Q')
18691                        | Some('U')
18692                        | Some('X')
18693                ) {
18694                    '4'
18695                } else {
18696                    '8'
18697                }
18698            }
18699            'X' => {
18700                if matches!(prev, Some('C') | Some('K') | Some('Q')) {
18701                    '8'
18702                } else {
18703                    result.push('4');
18704                    '8'
18705                }
18706            }
18707            'L' => '5',
18708            'M' | 'N' => '6',
18709            'R' => '7',
18710            'S' | 'Z' => '8',
18711            _ => continue,
18712        };
18713
18714        result.push(code);
18715    }
18716
18717    // Remove consecutive duplicates
18718    let mut deduped = String::new();
18719    let mut prev = None;
18720    for c in result.chars() {
18721        if prev != Some(c) {
18722            deduped.push(c);
18723        }
18724        prev = Some(c);
18725    }
18726
18727    // Remove leading zeros (except if all zeros)
18728    let trimmed: String = deduped.trim_start_matches('0').to_string();
18729    if trimmed.is_empty() {
18730        "0".to_string()
18731    } else {
18732        trimmed
18733    }
18734}
18735
18736/// Get stopwords for a language
18737fn get_stopwords(lang: &str) -> Vec<&'static str> {
18738    match lang {
18739        "en" | "english" => vec![
18740            "a", "an", "the", "and", "or", "but", "in", "on", "at", "to", "for", "of", "with",
18741            "by", "from", "as", "is", "was", "are", "were", "been", "be", "have", "has", "had",
18742            "do", "does", "did", "will", "would", "could", "should", "may", "might", "must",
18743            "shall", "can", "need", "it", "its", "this", "that", "these", "those", "i", "you",
18744            "he", "she", "we", "they", "me", "him", "her", "us", "them", "my", "your", "his",
18745            "her", "our", "their", "what", "which", "who", "whom", "whose", "when", "where", "why",
18746            "how", "all", "each", "every", "both", "few", "more", "most", "other", "some", "such",
18747            "no", "nor", "not", "only", "own", "same", "so", "than", "too", "very", "just", "also",
18748            "now",
18749        ],
18750        "de" | "german" => vec![
18751            "der", "die", "das", "den", "dem", "des", "ein", "eine", "einer", "einem", "einen",
18752            "und", "oder", "aber", "in", "auf", "an", "zu", "für", "von", "mit", "bei", "als",
18753            "ist", "war", "sind", "waren", "sein", "haben", "hat", "hatte", "werden", "wird",
18754            "wurde", "kann", "können", "muss", "müssen", "soll", "sollen", "will", "wollen", "es",
18755            "sie", "er", "wir", "ihr", "ich", "du", "man", "sich", "nicht", "auch", "nur", "noch",
18756            "schon", "mehr", "sehr", "so",
18757        ],
18758        "fr" | "french" => vec![
18759            "le", "la", "les", "un", "une", "des", "et", "ou", "mais", "dans", "sur", "à", "de",
18760            "pour", "par", "avec", "ce", "cette", "ces", "est", "sont", "était", "être", "avoir",
18761            "a", "ont", "avait", "je", "tu", "il", "elle", "nous", "vous", "ils", "elles", "on",
18762            "ne", "pas", "plus", "moins", "très", "aussi", "que", "qui",
18763        ],
18764        "es" | "spanish" => vec![
18765            "el", "la", "los", "las", "un", "una", "unos", "unas", "y", "o", "pero", "en", "de",
18766            "a", "para", "por", "con", "es", "son", "era", "ser", "estar", "tiene", "tienen", "yo",
18767            "tú", "él", "ella", "nosotros", "ustedes", "ellos", "ellas", "no", "sí", "muy", "más",
18768            "menos", "también", "que", "quien", "cual", "como", "cuando",
18769        ],
18770        "it" | "italian" => vec![
18771            "il", "lo", "la", "i", "gli", "le", "un", "uno", "una", "e", "o", "ma", "in", "di",
18772            "a", "da", "per", "con", "su", "tra", "fra", "è", "sono", "era", "erano", "essere",
18773            "avere", "ha", "hanno", "io", "tu", "lui", "lei", "noi", "voi", "loro", "mi", "ti",
18774            "ci", "non", "più", "molto", "anche", "come", "che", "chi", "quale", "questo",
18775            "quello", "quando", "dove", "perché", "se", "però",
18776        ],
18777        "pt" | "portuguese" => vec![
18778            "o", "a", "os", "as", "um", "uma", "uns", "umas", "e", "ou", "mas", "em", "de", "para",
18779            "por", "com", "sem", "sob", "sobre", "é", "são", "era", "eram", "ser", "estar", "ter",
18780            "tem", "têm", "eu", "tu", "ele", "ela", "nós", "vós", "eles", "elas", "me", "te",
18781            "não", "mais", "muito", "também", "como", "que", "quem", "qual", "este", "esse",
18782            "aquele", "quando", "onde", "porque", "se", "já",
18783        ],
18784        "nl" | "dutch" => vec![
18785            "de", "het", "een", "en", "of", "maar", "in", "op", "aan", "van", "voor", "met", "bij",
18786            "naar", "om", "te", "tot", "uit", "over", "is", "zijn", "was", "waren", "worden",
18787            "wordt", "werd", "hebben", "ik", "je", "jij", "hij", "zij", "wij", "jullie", "ze",
18788            "mij", "jou", "niet", "geen", "meer", "ook", "als", "dat", "die", "wat", "wie", "dit",
18789            "deze", "wanneer", "waar", "waarom", "hoe", "dan", "nog",
18790        ],
18791        "ru" | "russian" => vec![
18792            "и",
18793            "в",
18794            "на",
18795            "с",
18796            "к",
18797            "по",
18798            "за",
18799            "из",
18800            "у",
18801            "о",
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        "ar" | "arabic" => vec![
18851            "في",
18852            "من",
18853            "إلى",
18854            "على",
18855            "عن",
18856            "مع",
18857            "هذا",
18858            "هذه",
18859            "ذلك",
18860            "تلك",
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        "zh" | "chinese" => vec![
18907            "的", "了", "是", "在", "有", "和", "与", "或", "但", "而", "我", "你", "他", "她",
18908            "它", "我们", "你们", "他们", "她们", "这", "那", "这个", "那个", "这些", "那些",
18909            "什么", "哪", "哪个", "不", "没", "没有", "很", "也", "都", "就", "才", "只", "还",
18910            "把", "被", "给", "从", "到", "为", "以", "因为", "所以", "如果", "会", "能", "可以",
18911            "要", "想", "应该", "必须", "可能", "一", "个",
18912        ],
18913        "ja" | "japanese" => vec![
18914            "の",
18915            "に",
18916            "は",
18917            "を",
18918            "た",
18919            "が",
18920            "で",
18921            "て",
18922            "と",
18923            "し",
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        "ko" | "korean" => vec![
18966            "이",
18967            "그",
18968            "저",
18969            "것",
18970            "수",
18971            "등",
18972            "들",
18973            "및",
18974            "에",
18975            "의",
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        "hi" | "hindi" => vec![
19019            "का",
19020            "के",
19021            "की",
19022            "में",
19023            "है",
19024            "हैं",
19025            "को",
19026            "से",
19027            "पर",
19028            "था",
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        "tr" | "turkish" => vec![
19074            "bir",
19075            "ve",
19076            "bu",
19077            "da",
19078            "de",
19079            "için",
19080            "ile",
19081            "mi",
19082            "ne",
19083            "o",
19084            "var",
19085            "ben",
19086            "sen",
19087            "biz",
19088            "siz",
19089            "onlar",
19090            "ki",
19091            "ama",
19092            "çok",
19093            "daha",
19094            "gibi",
19095            "kadar",
19096            "sonra",
19097            "şey",
19098            "kendi",
19099            "bütün",
19100            "her",
19101            "bazı",
19102            "olan",
19103            "olarak",
19104            "değil",
19105            "ya",
19106            "hem",
19107            "veya",
19108            "ancak",
19109            "ise",
19110            "göre",
19111            "rağmen",
19112            "dolayı",
19113            "üzere",
19114            "karşı",
19115            "arasında",
19116            "olan",
19117            "oldu",
19118            "olur",
19119            "olmak",
19120            "etmek",
19121            "yapmak",
19122            "demek",
19123        ],
19124        "pl" | "polish" => vec![
19125            "i",
19126            "w",
19127            "z",
19128            "na",
19129            "do",
19130            "o",
19131            "że",
19132            "to",
19133            "nie",
19134            "się",
19135            "jest",
19136            "tak",
19137            "jak",
19138            "ale",
19139            "po",
19140            "co",
19141            "czy",
19142            "lub",
19143            "oraz",
19144            "ja",
19145            "ty",
19146            "on",
19147            "ona",
19148            "my",
19149            "wy",
19150            "oni",
19151            "one",
19152            "pan",
19153            "pani",
19154            "ten",
19155            "ta",
19156            "te",
19157            "tego",
19158            "tej",
19159            "tym",
19160            "tych",
19161            "który",
19162            "która",
19163            "być",
19164            "mieć",
19165            "móc",
19166            "musieć",
19167            "chcieć",
19168            "wiedzieć",
19169            "mówić",
19170            "bardzo",
19171            "tylko",
19172            "już",
19173            "jeszcze",
19174            "też",
19175            "więc",
19176            "jednak",
19177        ],
19178        "sv" | "swedish" => vec![
19179            "och", "i", "att", "det", "som", "en", "på", "är", "av", "för", "med", "till", "den",
19180            "har", "de", "inte", "om", "ett", "men", "jag", "du", "han", "hon", "vi", "ni", "de",
19181            "dem", "sig", "sin", "var", "från", "eller", "när", "kan", "ska", "så", "än", "nu",
19182            "också", "bara", "mycket", "mer", "andra", "detta", "sedan", "hade", "varit", "skulle",
19183            "vara", "bli", "blev", "blir", "göra",
19184        ],
19185        _ => vec![
19186            "a", "an", "the", "and", "or", "but", "in", "on", "at", "to", "for",
19187        ],
19188    }
19189}
19190
19191/// Simple hash function for MinHash
19192fn compute_hash(s: &str, seed: u64) -> u64 {
19193    let mut hash: u64 = seed.wrapping_mul(0x517cc1b727220a95);
19194    for b in s.bytes() {
19195        hash = hash.wrapping_mul(31).wrapping_add(b as u64);
19196    }
19197    hash
19198}
19199
19200// ============================================================================
19201// EMOTIONAL HOLOGRAM: Multi-dimensional affective projection with cultural awareness
19202// ============================================================================
19203//
19204// The Emotional Hologram is a unique Sigil concept that projects affect onto a
19205// normalized coordinate space, enabling:
19206// - Emotional distance calculations
19207// - Cross-cultural emotion mappings
19208// - Emotional fingerprinting and cryptographic signing
19209// - Dissonance detection (e.g., positive + sarcastic)
19210//
19211// Dimensions:
19212//   Valence     (-1 to +1): Negative to Positive sentiment
19213//   Arousal     (0 to 1):   Low to High intensity
19214//   Dominance   (0 to 1):   Submissive to Dominant (formality)
19215//   Authenticity(-1 to +1): Sincere to Ironic
19216//   Certainty   (0 to 1):   Low to High confidence
19217//   Emotion     (0-6):      Discrete emotion index (or -1 for none)
19218
19219fn register_hologram(interp: &mut Interpreter) {
19220    use crate::interpreter::{
19221        RuntimeAffect, RuntimeConfidence, RuntimeEmotion, RuntimeFormality, RuntimeIntensity,
19222        RuntimeSentiment,
19223    };
19224
19225    // emotional_hologram - project affect onto normalized coordinate space
19226    // Returns a map: { valence, arousal, dominance, authenticity, certainty, emotion_index }
19227    define(interp, "emotional_hologram", Some(1), |_, args| {
19228        let affect = match &args[0] {
19229            Value::Affective { affect, .. } => affect.clone(),
19230            _ => RuntimeAffect {
19231                sentiment: None,
19232                sarcasm: false,
19233                intensity: None,
19234                formality: None,
19235                emotion: None,
19236                confidence: None,
19237            },
19238        };
19239
19240        let mut hologram = std::collections::HashMap::new();
19241
19242        // Valence: sentiment mapped to -1, 0, +1
19243        let valence = match affect.sentiment {
19244            Some(RuntimeSentiment::Positive) => 1.0,
19245            Some(RuntimeSentiment::Negative) => -1.0,
19246            Some(RuntimeSentiment::Neutral) | None => 0.0,
19247        };
19248        hologram.insert("valence".to_string(), Value::Float(valence));
19249
19250        // Arousal: intensity mapped to 0, 0.33, 0.66, 1.0
19251        let arousal = match affect.intensity {
19252            Some(RuntimeIntensity::Down) => 0.25,
19253            None => 0.5,
19254            Some(RuntimeIntensity::Up) => 0.75,
19255            Some(RuntimeIntensity::Max) => 1.0,
19256        };
19257        hologram.insert("arousal".to_string(), Value::Float(arousal));
19258
19259        // Dominance: formality mapped to 0 (informal/submissive) to 1 (formal/dominant)
19260        let dominance = match affect.formality {
19261            Some(RuntimeFormality::Informal) => 0.25,
19262            None => 0.5,
19263            Some(RuntimeFormality::Formal) => 0.85,
19264        };
19265        hologram.insert("dominance".to_string(), Value::Float(dominance));
19266
19267        // Authenticity: -1 (ironic/sarcastic) to +1 (sincere)
19268        let authenticity = if affect.sarcasm { -0.9 } else { 0.9 };
19269        hologram.insert("authenticity".to_string(), Value::Float(authenticity));
19270
19271        // Certainty: confidence mapped to 0, 0.5, 1.0
19272        let certainty = match affect.confidence {
19273            Some(RuntimeConfidence::Low) => 0.2,
19274            None | Some(RuntimeConfidence::Medium) => 0.5,
19275            Some(RuntimeConfidence::High) => 0.9,
19276        };
19277        hologram.insert("certainty".to_string(), Value::Float(certainty));
19278
19279        // Emotion index: 0=joy, 1=sadness, 2=anger, 3=fear, 4=surprise, 5=love, -1=none
19280        let emotion_index = match affect.emotion {
19281            Some(RuntimeEmotion::Joy) => 0,
19282            Some(RuntimeEmotion::Sadness) => 1,
19283            Some(RuntimeEmotion::Anger) => 2,
19284            Some(RuntimeEmotion::Fear) => 3,
19285            Some(RuntimeEmotion::Surprise) => 4,
19286            Some(RuntimeEmotion::Love) => 5,
19287            None => -1,
19288        };
19289        hologram.insert("emotion_index".to_string(), Value::Int(emotion_index));
19290
19291        // Emotion name
19292        let emotion_name = match affect.emotion {
19293            Some(RuntimeEmotion::Joy) => "joy",
19294            Some(RuntimeEmotion::Sadness) => "sadness",
19295            Some(RuntimeEmotion::Anger) => "anger",
19296            Some(RuntimeEmotion::Fear) => "fear",
19297            Some(RuntimeEmotion::Surprise) => "surprise",
19298            Some(RuntimeEmotion::Love) => "love",
19299            None => "none",
19300        };
19301        hologram.insert(
19302            "emotion".to_string(),
19303            Value::String(Rc::new(emotion_name.to_string())),
19304        );
19305
19306        Ok(Value::Map(Rc::new(RefCell::new(hologram))))
19307    });
19308
19309    // emotional_distance - Euclidean distance between two emotional holograms
19310    define(interp, "emotional_distance", Some(2), |interp, args| {
19311        // Get holograms for both values
19312        let h1 = get_hologram_values(&args[0], interp)?;
19313        let h2 = get_hologram_values(&args[1], interp)?;
19314
19315        // Calculate Euclidean distance across dimensions
19316        let dist = ((h1.0 - h2.0).powi(2) +    // valence
19317                    (h1.1 - h2.1).powi(2) +    // arousal
19318                    (h1.2 - h2.2).powi(2) +    // dominance
19319                    (h1.3 - h2.3).powi(2) +    // authenticity
19320                    (h1.4 - h2.4).powi(2)) // certainty
19321        .sqrt();
19322
19323        Ok(Value::Float(dist))
19324    });
19325
19326    // emotional_similarity - cosine similarity between emotional states (0 to 1)
19327    define(interp, "emotional_similarity", Some(2), |interp, args| {
19328        let h1 = get_hologram_values(&args[0], interp)?;
19329        let h2 = get_hologram_values(&args[1], interp)?;
19330
19331        let dot = h1.0 * h2.0 + h1.1 * h2.1 + h1.2 * h2.2 + h1.3 * h2.3 + h1.4 * h2.4;
19332        let mag1 =
19333            (h1.0.powi(2) + h1.1.powi(2) + h1.2.powi(2) + h1.3.powi(2) + h1.4.powi(2)).sqrt();
19334        let mag2 =
19335            (h2.0.powi(2) + h2.1.powi(2) + h2.2.powi(2) + h2.3.powi(2) + h2.4.powi(2)).sqrt();
19336
19337        let similarity = if mag1 > 0.0 && mag2 > 0.0 {
19338            (dot / (mag1 * mag2) + 1.0) / 2.0 // Normalize to 0-1
19339        } else {
19340            0.5
19341        };
19342
19343        Ok(Value::Float(similarity))
19344    });
19345
19346    // emotional_dissonance - detect internal contradictions in affect
19347    // Returns score from 0 (coherent) to 1 (highly dissonant)
19348    define(interp, "emotional_dissonance", Some(1), |_, args| {
19349        let affect = match &args[0] {
19350            Value::Affective { affect, .. } => affect.clone(),
19351            _ => return Ok(Value::Float(0.0)),
19352        };
19353
19354        let mut dissonance: f64 = 0.0;
19355
19356        // Positive sentiment + sarcasm = dissonant
19357        if matches!(affect.sentiment, Some(RuntimeSentiment::Positive)) && affect.sarcasm {
19358            dissonance += 0.4;
19359        }
19360
19361        // Negative sentiment + sarcasm = less dissonant (double negative)
19362        if matches!(affect.sentiment, Some(RuntimeSentiment::Negative)) && affect.sarcasm {
19363            dissonance += 0.1;
19364        }
19365
19366        // High confidence + low intensity = mildly dissonant
19367        if matches!(affect.confidence, Some(RuntimeConfidence::High))
19368            && matches!(affect.intensity, Some(RuntimeIntensity::Down))
19369        {
19370            dissonance += 0.2;
19371        }
19372
19373        // Formal + intense emotion = dissonant
19374        if matches!(affect.formality, Some(RuntimeFormality::Formal)) {
19375            if matches!(
19376                affect.emotion,
19377                Some(RuntimeEmotion::Anger) | Some(RuntimeEmotion::Fear)
19378            ) {
19379                dissonance += 0.3;
19380            }
19381        }
19382
19383        // Joy/Love + Sadness/Fear indicators (based on sarcasm with positive)
19384        if matches!(
19385            affect.emotion,
19386            Some(RuntimeEmotion::Joy) | Some(RuntimeEmotion::Love)
19387        ) && affect.sarcasm
19388        {
19389            dissonance += 0.3;
19390        }
19391
19392        Ok(Value::Float(dissonance.min(1.0)))
19393    });
19394
19395    // emotional_fingerprint - cryptographic hash of emotional state
19396    // Creates a unique identifier for this exact emotional configuration
19397    define(interp, "emotional_fingerprint", Some(1), |interp, args| {
19398        let h = get_hologram_values(&args[0], interp)?;
19399
19400        // Create deterministic string representation
19401        let repr = format!(
19402            "hologram:v{:.4}:a{:.4}:d{:.4}:auth{:.4}:c{:.4}",
19403            h.0, h.1, h.2, h.3, h.4
19404        );
19405
19406        // Hash using BLAKE3
19407        let hash = blake3::hash(repr.as_bytes());
19408        Ok(Value::String(Rc::new(hash.to_hex().to_string())))
19409    });
19410
19411    // emotional_morph - interpolate between two emotional states
19412    // t=0 returns first state, t=1 returns second state
19413    define(interp, "emotional_morph", Some(3), |interp, args| {
19414        let h1 = get_hologram_values(&args[0], interp)?;
19415        let h2 = get_hologram_values(&args[1], interp)?;
19416        let t = match &args[2] {
19417            Value::Float(f) => f.max(0.0).min(1.0),
19418            Value::Int(i) => (*i as f64).max(0.0).min(1.0),
19419            _ => {
19420                return Err(RuntimeError::new(
19421                    "emotional_morph() requires numeric t value",
19422                ))
19423            }
19424        };
19425
19426        let mut result = std::collections::HashMap::new();
19427        result.insert(
19428            "valence".to_string(),
19429            Value::Float(h1.0 + (h2.0 - h1.0) * t),
19430        );
19431        result.insert(
19432            "arousal".to_string(),
19433            Value::Float(h1.1 + (h2.1 - h1.1) * t),
19434        );
19435        result.insert(
19436            "dominance".to_string(),
19437            Value::Float(h1.2 + (h2.2 - h1.2) * t),
19438        );
19439        result.insert(
19440            "authenticity".to_string(),
19441            Value::Float(h1.3 + (h2.3 - h1.3) * t),
19442        );
19443        result.insert(
19444            "certainty".to_string(),
19445            Value::Float(h1.4 + (h2.4 - h1.4) * t),
19446        );
19447
19448        Ok(Value::Map(Rc::new(RefCell::new(result))))
19449    });
19450
19451    // === Cultural Emotion Mappings ===
19452    // Map Sigil emotions to culturally-specific concepts
19453
19454    // cultural_emotion - get cultural equivalent of an emotion
19455    // Supported cultures: japanese, portuguese, german, danish, arabic, korean, russian, hindi
19456    define(interp, "cultural_emotion", Some(2), |_, args| {
19457        let emotion = match &args[0] {
19458            Value::Affective { affect, .. } => affect.emotion.clone(),
19459            Value::String(s) => match s.as_str() {
19460                "joy" => Some(RuntimeEmotion::Joy),
19461                "sadness" => Some(RuntimeEmotion::Sadness),
19462                "anger" => Some(RuntimeEmotion::Anger),
19463                "fear" => Some(RuntimeEmotion::Fear),
19464                "surprise" => Some(RuntimeEmotion::Surprise),
19465                "love" => Some(RuntimeEmotion::Love),
19466                _ => None,
19467            },
19468            _ => None,
19469        };
19470
19471        let culture = match &args[1] {
19472            Value::String(s) => s.to_lowercase(),
19473            _ => {
19474                return Err(RuntimeError::new(
19475                    "cultural_emotion() requires string culture",
19476                ))
19477            }
19478        };
19479
19480        let result = match (emotion, culture.as_str()) {
19481            // Japanese concepts
19482            (Some(RuntimeEmotion::Joy), "japanese" | "ja") => create_cultural_entry(
19483                "木漏れ日",
19484                "komorebi",
19485                "sunlight filtering through leaves - peaceful joy",
19486            ),
19487            (Some(RuntimeEmotion::Sadness), "japanese" | "ja") => create_cultural_entry(
19488                "物の哀れ",
19489                "mono no aware",
19490                "the pathos of things - bittersweet awareness of impermanence",
19491            ),
19492            (Some(RuntimeEmotion::Love), "japanese" | "ja") => create_cultural_entry(
19493                "甘え",
19494                "amae",
19495                "indulgent dependence on another's benevolence",
19496            ),
19497            (Some(RuntimeEmotion::Fear), "japanese" | "ja") => create_cultural_entry(
19498                "空気を読む",
19499                "kuuki wo yomu",
19500                "anxiety about reading the room",
19501            ),
19502
19503            // Portuguese concepts
19504            (Some(RuntimeEmotion::Sadness), "portuguese" | "pt") => create_cultural_entry(
19505                "saudade",
19506                "saudade",
19507                "melancholic longing for something or someone absent",
19508            ),
19509            (Some(RuntimeEmotion::Joy), "portuguese" | "pt") => {
19510                create_cultural_entry("alegria", "alegria", "exuberant collective joy")
19511            }
19512
19513            // German concepts
19514            (Some(RuntimeEmotion::Joy), "german" | "de") => create_cultural_entry(
19515                "Schadenfreude",
19516                "schadenfreude",
19517                "pleasure derived from another's misfortune",
19518            ),
19519            (Some(RuntimeEmotion::Sadness), "german" | "de") => create_cultural_entry(
19520                "Weltschmerz",
19521                "weltschmerz",
19522                "world-weariness, melancholy about the world's state",
19523            ),
19524            (Some(RuntimeEmotion::Fear), "german" | "de") => create_cultural_entry(
19525                "Torschlusspanik",
19526                "torschlusspanik",
19527                "fear of diminishing opportunities with age",
19528            ),
19529
19530            // Danish concepts
19531            (Some(RuntimeEmotion::Joy), "danish" | "da") => {
19532                create_cultural_entry("hygge", "hygge", "cozy contentment and conviviality")
19533            }
19534
19535            // Arabic concepts
19536            (Some(RuntimeEmotion::Joy), "arabic" | "ar") => {
19537                create_cultural_entry("طرب", "tarab", "musical ecstasy, enchantment through art")
19538            }
19539            (Some(RuntimeEmotion::Love), "arabic" | "ar") => {
19540                create_cultural_entry("هوى", "hawa", "passionate, sometimes irrational love")
19541            }
19542
19543            // Korean concepts
19544            (Some(RuntimeEmotion::Sadness), "korean" | "ko") => create_cultural_entry(
19545                "한",
19546                "han",
19547                "collective grief and resentment from historical suffering",
19548            ),
19549            (Some(RuntimeEmotion::Joy), "korean" | "ko") => create_cultural_entry(
19550                "정",
19551                "jeong",
19552                "deep affection and attachment formed over time",
19553            ),
19554
19555            // Russian concepts
19556            (Some(RuntimeEmotion::Sadness), "russian" | "ru") => {
19557                create_cultural_entry("тоска", "toska", "spiritual anguish without specific cause")
19558            }
19559
19560            // Hindi concepts
19561            (Some(RuntimeEmotion::Love), "hindi" | "hi") => {
19562                create_cultural_entry("विरह", "viraha", "longing for an absent beloved")
19563            }
19564
19565            // Finnish concepts
19566            (Some(RuntimeEmotion::Anger), "finnish" | "fi") => {
19567                create_cultural_entry("sisu", "sisu", "stoic determination and grit in adversity")
19568            }
19569
19570            // Default: return the base emotion
19571            (Some(e), _) => {
19572                let name = match e {
19573                    RuntimeEmotion::Joy => "joy",
19574                    RuntimeEmotion::Sadness => "sadness",
19575                    RuntimeEmotion::Anger => "anger",
19576                    RuntimeEmotion::Fear => "fear",
19577                    RuntimeEmotion::Surprise => "surprise",
19578                    RuntimeEmotion::Love => "love",
19579                };
19580                create_cultural_entry(name, name, "universal emotion")
19581            }
19582            (None, _) => create_cultural_entry("none", "none", "no emotion"),
19583        };
19584
19585        Ok(result)
19586    });
19587
19588    // list_cultural_emotions - list all emotions for a culture
19589    define(interp, "list_cultural_emotions", Some(1), |_, args| {
19590        let culture = match &args[0] {
19591            Value::String(s) => s.to_lowercase(),
19592            _ => {
19593                return Err(RuntimeError::new(
19594                    "list_cultural_emotions() requires string culture",
19595                ))
19596            }
19597        };
19598
19599        let emotions: Vec<(&str, &str, &str)> = match culture.as_str() {
19600            "japanese" | "ja" => vec![
19601                ("木漏れ日", "komorebi", "sunlight through leaves"),
19602                ("物の哀れ", "mono no aware", "pathos of things"),
19603                ("甘え", "amae", "indulgent dependence"),
19604                ("侘寂", "wabi-sabi", "beauty in imperfection"),
19605                ("生きがい", "ikigai", "reason for being"),
19606            ],
19607            "german" | "de" => vec![
19608                ("Schadenfreude", "schadenfreude", "joy at misfortune"),
19609                ("Weltschmerz", "weltschmerz", "world-weariness"),
19610                ("Torschlusspanik", "torschlusspanik", "gate-closing panic"),
19611                ("Sehnsucht", "sehnsucht", "deep longing"),
19612                ("Wanderlust", "wanderlust", "desire to travel"),
19613            ],
19614            "portuguese" | "pt" => vec![
19615                ("saudade", "saudade", "melancholic longing"),
19616                ("alegria", "alegria", "exuberant joy"),
19617                ("desabafar", "desabafar", "emotional unburdening"),
19618            ],
19619            "danish" | "da" => vec![("hygge", "hygge", "cozy contentment")],
19620            "korean" | "ko" => vec![
19621                ("한", "han", "collective grief"),
19622                ("정", "jeong", "deep affection"),
19623                ("눈치", "nunchi", "situational awareness"),
19624            ],
19625            "arabic" | "ar" => vec![
19626                ("طرب", "tarab", "musical ecstasy"),
19627                ("هوى", "hawa", "passionate love"),
19628                ("صبر", "sabr", "patient perseverance"),
19629            ],
19630            "russian" | "ru" => vec![
19631                ("тоска", "toska", "spiritual anguish"),
19632                ("пошлость", "poshlost", "spiritual vulgarity"),
19633            ],
19634            "finnish" | "fi" => vec![("sisu", "sisu", "stoic determination")],
19635            "hindi" | "hi" => vec![
19636                ("विरह", "viraha", "longing for beloved"),
19637                ("जुगाड़", "jugaad", "creative improvisation"),
19638            ],
19639            _ => vec![
19640                ("joy", "joy", "universal happiness"),
19641                ("sadness", "sadness", "universal sorrow"),
19642                ("anger", "anger", "universal frustration"),
19643                ("fear", "fear", "universal anxiety"),
19644                ("surprise", "surprise", "universal amazement"),
19645                ("love", "love", "universal affection"),
19646            ],
19647        };
19648
19649        let result: Vec<Value> = emotions
19650            .iter()
19651            .map(|(native, romanized, meaning)| create_cultural_entry(native, romanized, meaning))
19652            .collect();
19653
19654        Ok(Value::Array(Rc::new(RefCell::new(result))))
19655    });
19656
19657    // hologram_info - get metadata about the hologram system
19658    define(interp, "hologram_info", Some(0), |_, _| {
19659        let mut info = std::collections::HashMap::new();
19660
19661        info.insert(
19662            "dimensions".to_string(),
19663            Value::Array(Rc::new(RefCell::new(vec![
19664                Value::String(Rc::new("valence".to_string())),
19665                Value::String(Rc::new("arousal".to_string())),
19666                Value::String(Rc::new("dominance".to_string())),
19667                Value::String(Rc::new("authenticity".to_string())),
19668                Value::String(Rc::new("certainty".to_string())),
19669                Value::String(Rc::new("emotion_index".to_string())),
19670            ]))),
19671        );
19672
19673        info.insert(
19674            "supported_cultures".to_string(),
19675            Value::Array(Rc::new(RefCell::new(vec![
19676                Value::String(Rc::new("japanese".to_string())),
19677                Value::String(Rc::new("german".to_string())),
19678                Value::String(Rc::new("portuguese".to_string())),
19679                Value::String(Rc::new("danish".to_string())),
19680                Value::String(Rc::new("korean".to_string())),
19681                Value::String(Rc::new("arabic".to_string())),
19682                Value::String(Rc::new("russian".to_string())),
19683                Value::String(Rc::new("finnish".to_string())),
19684                Value::String(Rc::new("hindi".to_string())),
19685            ]))),
19686        );
19687
19688        let funcs = vec![
19689            "emotional_hologram",
19690            "emotional_distance",
19691            "emotional_similarity",
19692            "emotional_dissonance",
19693            "emotional_fingerprint",
19694            "emotional_morph",
19695            "cultural_emotion",
19696            "list_cultural_emotions",
19697            "hologram_info",
19698        ];
19699        let func_values: Vec<Value> = funcs
19700            .iter()
19701            .map(|s| Value::String(Rc::new(s.to_string())))
19702            .collect();
19703        info.insert(
19704            "functions".to_string(),
19705            Value::Array(Rc::new(RefCell::new(func_values))),
19706        );
19707
19708        Ok(Value::Map(Rc::new(RefCell::new(info))))
19709    });
19710}
19711
19712/// Helper to extract hologram values from an affective value
19713fn get_hologram_values(
19714    val: &Value,
19715    _interp: &mut Interpreter,
19716) -> Result<(f64, f64, f64, f64, f64), RuntimeError> {
19717    use crate::interpreter::{
19718        RuntimeAffect, RuntimeConfidence, RuntimeFormality, RuntimeIntensity, RuntimeSentiment,
19719    };
19720
19721    let affect = match val {
19722        Value::Affective { affect, .. } => affect.clone(),
19723        Value::Map(m) => {
19724            // Already a hologram map
19725            let map = m.borrow();
19726            let v = extract_float(&map, "valence").unwrap_or(0.0);
19727            let a = extract_float(&map, "arousal").unwrap_or(0.5);
19728            let d = extract_float(&map, "dominance").unwrap_or(0.5);
19729            let auth = extract_float(&map, "authenticity").unwrap_or(0.9);
19730            let c = extract_float(&map, "certainty").unwrap_or(0.5);
19731            return Ok((v, a, d, auth, c));
19732        }
19733        _ => RuntimeAffect {
19734            sentiment: None,
19735            sarcasm: false,
19736            intensity: None,
19737            formality: None,
19738            emotion: None,
19739            confidence: None,
19740        },
19741    };
19742
19743    let v = match affect.sentiment {
19744        Some(RuntimeSentiment::Positive) => 1.0,
19745        Some(RuntimeSentiment::Negative) => -1.0,
19746        _ => 0.0,
19747    };
19748    let a = match affect.intensity {
19749        Some(RuntimeIntensity::Down) => 0.25,
19750        Some(RuntimeIntensity::Up) => 0.75,
19751        Some(RuntimeIntensity::Max) => 1.0,
19752        None => 0.5,
19753    };
19754    let d = match affect.formality {
19755        Some(RuntimeFormality::Informal) => 0.25,
19756        Some(RuntimeFormality::Formal) => 0.85,
19757        None => 0.5,
19758    };
19759    let auth = if affect.sarcasm { -0.9 } else { 0.9 };
19760    let c = match affect.confidence {
19761        Some(RuntimeConfidence::Low) => 0.2,
19762        Some(RuntimeConfidence::High) => 0.9,
19763        _ => 0.5,
19764    };
19765
19766    Ok((v, a, d, auth, c))
19767}
19768
19769fn extract_float(map: &std::collections::HashMap<String, Value>, key: &str) -> Option<f64> {
19770    match map.get(key) {
19771        Some(Value::Float(f)) => Some(*f),
19772        Some(Value::Int(i)) => Some(*i as f64),
19773        _ => None,
19774    }
19775}
19776
19777fn create_cultural_entry(native: &str, romanized: &str, meaning: &str) -> Value {
19778    let mut entry = std::collections::HashMap::new();
19779    entry.insert(
19780        "native".to_string(),
19781        Value::String(Rc::new(native.to_string())),
19782    );
19783    entry.insert(
19784        "romanized".to_string(),
19785        Value::String(Rc::new(romanized.to_string())),
19786    );
19787    entry.insert(
19788        "meaning".to_string(),
19789        Value::String(Rc::new(meaning.to_string())),
19790    );
19791    Value::Map(Rc::new(RefCell::new(entry)))
19792}
19793
19794// ============================================================================
19795// EXPERIMENTAL CRYPTOGRAPHY: Threshold crypto, commitments, and more
19796// ============================================================================
19797
19798fn register_experimental_crypto(interp: &mut Interpreter) {
19799    // === Commitment Schemes ===
19800    // Commit to a value without revealing it, verify later
19801
19802    // commit - create a cryptographic commitment to a value
19803    // Returns { commitment: hash, nonce: random_value }
19804    define(interp, "commit", Some(1), |_, args| {
19805        let value_str = match &args[0] {
19806            Value::String(s) => s.to_string(),
19807            other => format!("{:?}", other),
19808        };
19809
19810        // Generate random nonce
19811        let mut nonce = [0u8; 32];
19812        getrandom::getrandom(&mut nonce)
19813            .map_err(|e| RuntimeError::new(format!("commit() random failed: {}", e)))?;
19814        let nonce_hex = hex::encode(&nonce);
19815
19816        // Create commitment: H(value || nonce)
19817        let commitment_input = format!("{}:{}", value_str, nonce_hex);
19818        let commitment = blake3::hash(commitment_input.as_bytes());
19819
19820        let mut result = std::collections::HashMap::new();
19821        result.insert(
19822            "commitment".to_string(),
19823            Value::String(Rc::new(commitment.to_hex().to_string())),
19824        );
19825        result.insert("nonce".to_string(), Value::String(Rc::new(nonce_hex)));
19826        result.insert("value".to_string(), args[0].clone());
19827
19828        Ok(Value::Map(Rc::new(RefCell::new(result))))
19829    });
19830
19831    // verify_commitment - verify a commitment matches a revealed value
19832    define(interp, "verify_commitment", Some(3), |_, args| {
19833        let commitment = match &args[0] {
19834            Value::String(s) => s.to_string(),
19835            _ => {
19836                return Err(RuntimeError::new(
19837                    "verify_commitment() requires string commitment",
19838                ))
19839            }
19840        };
19841        let value_str = match &args[1] {
19842            Value::String(s) => s.to_string(),
19843            other => format!("{:?}", other),
19844        };
19845        let nonce = match &args[2] {
19846            Value::String(s) => s.to_string(),
19847            _ => {
19848                return Err(RuntimeError::new(
19849                    "verify_commitment() requires string nonce",
19850                ))
19851            }
19852        };
19853
19854        // Recompute commitment
19855        let commitment_input = format!("{}:{}", value_str, nonce);
19856        let computed = blake3::hash(commitment_input.as_bytes());
19857
19858        Ok(Value::Bool(computed.to_hex().to_string() == commitment))
19859    });
19860
19861    // === Threshold Cryptography (Shamir's Secret Sharing) ===
19862    // Split secrets into shares, requiring threshold to reconstruct
19863
19864    // secret_split - split a secret into n shares, requiring threshold to recover
19865    // Uses Shamir's Secret Sharing over GF(256)
19866    define(interp, "secret_split", Some(3), |_, args| {
19867        let secret = match &args[0] {
19868            Value::String(s) => s.as_bytes().to_vec(),
19869            Value::Array(arr) => {
19870                let borrowed = arr.borrow();
19871                borrowed
19872                    .iter()
19873                    .filter_map(|v| {
19874                        if let Value::Int(i) = v {
19875                            Some(*i as u8)
19876                        } else {
19877                            None
19878                        }
19879                    })
19880                    .collect()
19881            }
19882            _ => {
19883                return Err(RuntimeError::new(
19884                    "secret_split() requires string or byte array",
19885                ))
19886            }
19887        };
19888
19889        let threshold = match &args[1] {
19890            Value::Int(n) => *n as usize,
19891            _ => {
19892                return Err(RuntimeError::new(
19893                    "secret_split() requires integer threshold",
19894                ))
19895            }
19896        };
19897
19898        let num_shares = match &args[2] {
19899            Value::Int(n) => *n as usize,
19900            _ => {
19901                return Err(RuntimeError::new(
19902                    "secret_split() requires integer num_shares",
19903                ))
19904            }
19905        };
19906
19907        if threshold < 2 {
19908            return Err(RuntimeError::new("secret_split() threshold must be >= 2"));
19909        }
19910        if num_shares < threshold {
19911            return Err(RuntimeError::new(
19912                "secret_split() num_shares must be >= threshold",
19913            ));
19914        }
19915        if num_shares > 255 {
19916            return Err(RuntimeError::new("secret_split() max 255 shares"));
19917        }
19918
19919        // Simple implementation: split each byte independently using polynomial interpolation
19920        // For production, use vsss-rs properly, but this demonstrates the concept
19921        let mut rng = rand::thread_rng();
19922        let mut shares: Vec<Vec<u8>> = (0..num_shares)
19923            .map(|_| Vec::with_capacity(secret.len() + 1))
19924            .collect();
19925
19926        // Assign share indices (1-based to avoid zero)
19927        for (i, share) in shares.iter_mut().enumerate() {
19928            share.push((i + 1) as u8);
19929        }
19930
19931        // For each byte of the secret, create polynomial shares
19932        for &byte in &secret {
19933            // Generate random coefficients for polynomial of degree (threshold - 1)
19934            // a_0 = secret byte, a_1..a_{t-1} = random
19935            let mut coefficients: Vec<u8> = vec![byte];
19936            for _ in 1..threshold {
19937                coefficients.push(rng.gen());
19938            }
19939
19940            // Evaluate polynomial at each share index
19941            for (i, share) in shares.iter_mut().enumerate() {
19942                let x = (i + 1) as u8;
19943                let y = eval_polynomial_gf256(&coefficients, x);
19944                share.push(y);
19945            }
19946        }
19947
19948        // Convert shares to output format
19949        let share_values: Vec<Value> = shares
19950            .iter()
19951            .map(|share| {
19952                let hex = hex::encode(share);
19953                Value::String(Rc::new(hex))
19954            })
19955            .collect();
19956
19957        let mut result = std::collections::HashMap::new();
19958        result.insert(
19959            "shares".to_string(),
19960            Value::Array(Rc::new(RefCell::new(share_values))),
19961        );
19962        result.insert("threshold".to_string(), Value::Int(threshold as i64));
19963        result.insert("total".to_string(), Value::Int(num_shares as i64));
19964
19965        Ok(Value::Map(Rc::new(RefCell::new(result))))
19966    });
19967
19968    // secret_recover - recover secret from threshold shares
19969    define(interp, "secret_recover", Some(1), |_, args| {
19970        let shares: Vec<Vec<u8>> = match &args[0] {
19971            Value::Array(arr) => {
19972                let borrowed = arr.borrow();
19973                borrowed
19974                    .iter()
19975                    .filter_map(|v| {
19976                        if let Value::String(s) = v {
19977                            hex::decode(s.as_str()).ok()
19978                        } else {
19979                            None
19980                        }
19981                    })
19982                    .collect()
19983            }
19984            _ => {
19985                return Err(RuntimeError::new(
19986                    "secret_recover() requires array of share strings",
19987                ))
19988            }
19989        };
19990
19991        if shares.is_empty() {
19992            return Err(RuntimeError::new(
19993                "secret_recover() requires at least one share",
19994            ));
19995        }
19996
19997        let share_len = shares[0].len();
19998        if share_len < 2 {
19999            return Err(RuntimeError::new("secret_recover() invalid share format"));
20000        }
20001
20002        // Recover each byte using Lagrange interpolation
20003        let mut secret = Vec::with_capacity(share_len - 1);
20004
20005        for byte_idx in 1..share_len {
20006            // Collect (x, y) pairs for this byte position
20007            let points: Vec<(u8, u8)> = shares
20008                .iter()
20009                .map(|share| (share[0], share[byte_idx]))
20010                .collect();
20011
20012            // Lagrange interpolation at x=0 to recover the secret byte
20013            let recovered_byte = lagrange_interpolate_gf256(&points, 0);
20014            secret.push(recovered_byte);
20015        }
20016
20017        // Try to interpret as string
20018        match String::from_utf8(secret.clone()) {
20019            Ok(s) => Ok(Value::String(Rc::new(s))),
20020            Err(_) => {
20021                // Return as byte array
20022                let byte_values: Vec<Value> =
20023                    secret.iter().map(|&b| Value::Int(b as i64)).collect();
20024                Ok(Value::Array(Rc::new(RefCell::new(byte_values))))
20025            }
20026        }
20027    });
20028
20029    // === Cryptographic Ceremony Functions ===
20030    // Cultural trust models encoded in crypto
20031
20032    // council_split - split secret using Ubuntu (I am because we are) model
20033    // Requires majority consensus
20034    define(interp, "council_split", Some(2), |_, args| {
20035        let secret = match &args[0] {
20036            Value::String(s) => s.as_bytes().to_vec(),
20037            _ => return Err(RuntimeError::new("council_split() requires string secret")),
20038        };
20039
20040        let num_elders = match &args[1] {
20041            Value::Int(n) => *n as usize,
20042            _ => {
20043                return Err(RuntimeError::new(
20044                    "council_split() requires integer num_elders",
20045                ))
20046            }
20047        };
20048
20049        if num_elders < 3 {
20050            return Err(RuntimeError::new(
20051                "council_split() requires at least 3 elders",
20052            ));
20053        }
20054
20055        // Ubuntu model: majority required (n/2 + 1)
20056        let threshold = (num_elders / 2) + 1;
20057
20058        // Reuse secret_split logic
20059        let mut rng = rand::thread_rng();
20060        let mut shares: Vec<Vec<u8>> = (0..num_elders)
20061            .map(|_| Vec::with_capacity(secret.len() + 1))
20062            .collect();
20063
20064        for (i, share) in shares.iter_mut().enumerate() {
20065            share.push((i + 1) as u8);
20066        }
20067
20068        for &byte in &secret {
20069            let mut coefficients: Vec<u8> = vec![byte];
20070            for _ in 1..threshold {
20071                coefficients.push(rng.gen());
20072            }
20073
20074            for (i, share) in shares.iter_mut().enumerate() {
20075                let x = (i + 1) as u8;
20076                let y = eval_polynomial_gf256(&coefficients, x);
20077                share.push(y);
20078            }
20079        }
20080
20081        let share_values: Vec<Value> = shares
20082            .iter()
20083            .map(|share| Value::String(Rc::new(hex::encode(share))))
20084            .collect();
20085
20086        let mut result = std::collections::HashMap::new();
20087        result.insert(
20088            "shares".to_string(),
20089            Value::Array(Rc::new(RefCell::new(share_values))),
20090        );
20091        result.insert("threshold".to_string(), Value::Int(threshold as i64));
20092        result.insert("total".to_string(), Value::Int(num_elders as i64));
20093        result.insert(
20094            "model".to_string(),
20095            Value::String(Rc::new("ubuntu".to_string())),
20096        );
20097        result.insert(
20098            "philosophy".to_string(),
20099            Value::String(Rc::new(
20100                "I am because we are - majority consensus required".to_string(),
20101            )),
20102        );
20103
20104        Ok(Value::Map(Rc::new(RefCell::new(result))))
20105    });
20106
20107    // witness_chain - create a chain of witnesses (Middle Eastern oral tradition model)
20108    // Each witness signs the previous, creating a chain of trust
20109    define(interp, "witness_chain", Some(2), |_, args| {
20110        let statement = match &args[0] {
20111            Value::String(s) => s.to_string(),
20112            _ => {
20113                return Err(RuntimeError::new(
20114                    "witness_chain() requires string statement",
20115                ))
20116            }
20117        };
20118
20119        let witnesses: Vec<String> = match &args[1] {
20120            Value::Array(arr) => {
20121                let borrowed = arr.borrow();
20122                borrowed
20123                    .iter()
20124                    .filter_map(|v| {
20125                        if let Value::String(s) = v {
20126                            Some(s.to_string())
20127                        } else {
20128                            None
20129                        }
20130                    })
20131                    .collect()
20132            }
20133            _ => {
20134                return Err(RuntimeError::new(
20135                    "witness_chain() requires array of witness names",
20136                ))
20137            }
20138        };
20139
20140        if witnesses.is_empty() {
20141            return Err(RuntimeError::new(
20142                "witness_chain() requires at least one witness",
20143            ));
20144        }
20145
20146        // Build chain: each witness attests to the previous
20147        let mut chain = Vec::new();
20148        let mut prev_hash = blake3::hash(statement.as_bytes()).to_hex().to_string();
20149
20150        for (i, witness) in witnesses.iter().enumerate() {
20151            let attestation = format!("{}:attests:{}", witness, prev_hash);
20152            let hash = blake3::hash(attestation.as_bytes()).to_hex().to_string();
20153
20154            let mut link = std::collections::HashMap::new();
20155            link.insert(
20156                "witness".to_string(),
20157                Value::String(Rc::new(witness.clone())),
20158            );
20159            link.insert("position".to_string(), Value::Int((i + 1) as i64));
20160            link.insert(
20161                "attests_to".to_string(),
20162                Value::String(Rc::new(prev_hash.clone())),
20163            );
20164            link.insert(
20165                "signature".to_string(),
20166                Value::String(Rc::new(hash.clone())),
20167            );
20168
20169            chain.push(Value::Map(Rc::new(RefCell::new(link))));
20170            prev_hash = hash;
20171        }
20172
20173        let mut result = std::collections::HashMap::new();
20174        result.insert("statement".to_string(), Value::String(Rc::new(statement)));
20175        result.insert(
20176            "chain".to_string(),
20177            Value::Array(Rc::new(RefCell::new(chain))),
20178        );
20179        result.insert("final_seal".to_string(), Value::String(Rc::new(prev_hash)));
20180        result.insert(
20181            "model".to_string(),
20182            Value::String(Rc::new("isnad".to_string())),
20183        );
20184        result.insert(
20185            "philosophy".to_string(),
20186            Value::String(Rc::new(
20187                "Chain of reliable transmitters - each witness validates the previous".to_string(),
20188            )),
20189        );
20190
20191        Ok(Value::Map(Rc::new(RefCell::new(result))))
20192    });
20193
20194    // verify_witness_chain - verify a witness chain is intact
20195    define(interp, "verify_witness_chain", Some(1), |_, args| {
20196        let chain_map = match &args[0] {
20197            Value::Map(m) => m.borrow(),
20198            _ => {
20199                return Err(RuntimeError::new(
20200                    "verify_witness_chain() requires chain map",
20201                ))
20202            }
20203        };
20204
20205        let statement = match chain_map.get("statement") {
20206            Some(Value::String(s)) => s.to_string(),
20207            _ => {
20208                return Err(RuntimeError::new(
20209                    "verify_witness_chain() invalid chain format",
20210                ))
20211            }
20212        };
20213
20214        let chain = match chain_map.get("chain") {
20215            Some(Value::Array(arr)) => arr.borrow().clone(),
20216            _ => {
20217                return Err(RuntimeError::new(
20218                    "verify_witness_chain() invalid chain format",
20219                ))
20220            }
20221        };
20222
20223        let mut prev_hash = blake3::hash(statement.as_bytes()).to_hex().to_string();
20224
20225        for link_val in chain.iter() {
20226            if let Value::Map(link_map) = link_val {
20227                let link = link_map.borrow();
20228                let witness = match link.get("witness") {
20229                    Some(Value::String(s)) => s.to_string(),
20230                    _ => return Ok(Value::Bool(false)),
20231                };
20232                let attests_to = match link.get("attests_to") {
20233                    Some(Value::String(s)) => s.to_string(),
20234                    _ => return Ok(Value::Bool(false)),
20235                };
20236                let signature = match link.get("signature") {
20237                    Some(Value::String(s)) => s.to_string(),
20238                    _ => return Ok(Value::Bool(false)),
20239                };
20240
20241                // Verify attestation
20242                if attests_to != prev_hash {
20243                    return Ok(Value::Bool(false));
20244                }
20245
20246                let expected = format!("{}:attests:{}", witness, prev_hash);
20247                let computed = blake3::hash(expected.as_bytes()).to_hex().to_string();
20248
20249                if computed != signature {
20250                    return Ok(Value::Bool(false));
20251                }
20252
20253                prev_hash = signature;
20254            } else {
20255                return Ok(Value::Bool(false));
20256            }
20257        }
20258
20259        Ok(Value::Bool(true))
20260    });
20261
20262    // === Experimental Crypto Info ===
20263    define(interp, "experimental_crypto_info", Some(0), |_, _| {
20264        let mut info = std::collections::HashMap::new();
20265
20266        info.insert(
20267            "commitment_functions".to_string(),
20268            Value::Array(Rc::new(RefCell::new(vec![
20269                Value::String(Rc::new("commit".to_string())),
20270                Value::String(Rc::new("verify_commitment".to_string())),
20271            ]))),
20272        );
20273
20274        info.insert(
20275            "threshold_functions".to_string(),
20276            Value::Array(Rc::new(RefCell::new(vec![
20277                Value::String(Rc::new("secret_split".to_string())),
20278                Value::String(Rc::new("secret_recover".to_string())),
20279            ]))),
20280        );
20281
20282        info.insert(
20283            "cultural_ceremonies".to_string(),
20284            Value::Array(Rc::new(RefCell::new(vec![
20285                Value::String(Rc::new(
20286                    "council_split (Ubuntu - African consensus)".to_string(),
20287                )),
20288                Value::String(Rc::new(
20289                    "witness_chain (Isnad - Islamic transmission)".to_string(),
20290                )),
20291            ]))),
20292        );
20293
20294        Ok(Value::Map(Rc::new(RefCell::new(info))))
20295    });
20296}
20297
20298/// Evaluate polynomial in GF(256) at point x
20299fn eval_polynomial_gf256(coefficients: &[u8], x: u8) -> u8 {
20300    let mut result: u8 = 0;
20301    let mut x_power: u8 = 1;
20302
20303    for &coef in coefficients {
20304        result ^= gf256_mul(coef, x_power);
20305        x_power = gf256_mul(x_power, x);
20306    }
20307
20308    result
20309}
20310
20311/// Lagrange interpolation in GF(256) to find f(0)
20312fn lagrange_interpolate_gf256(points: &[(u8, u8)], _x: u8) -> u8 {
20313    let mut result: u8 = 0;
20314
20315    for (i, &(xi, yi)) in points.iter().enumerate() {
20316        let mut numerator: u8 = 1;
20317        let mut denominator: u8 = 1;
20318
20319        for (j, &(xj, _)) in points.iter().enumerate() {
20320            if i != j {
20321                // numerator *= (0 - xj) = xj (in GF256, subtraction is XOR)
20322                numerator = gf256_mul(numerator, xj);
20323                // denominator *= (xi - xj)
20324                denominator = gf256_mul(denominator, xi ^ xj);
20325            }
20326        }
20327
20328        // term = yi * numerator / denominator
20329        let term = gf256_mul(yi, gf256_mul(numerator, gf256_inv(denominator)));
20330        result ^= term;
20331    }
20332
20333    result
20334}
20335
20336/// GF(256) multiplication using Russian peasant algorithm
20337fn gf256_mul(mut a: u8, mut b: u8) -> u8 {
20338    let mut result: u8 = 0;
20339    let modulus: u16 = 0x11b; // x^8 + x^4 + x^3 + x + 1
20340
20341    while b != 0 {
20342        if b & 1 != 0 {
20343            result ^= a;
20344        }
20345        let high_bit = (a & 0x80) != 0;
20346        a <<= 1;
20347        if high_bit {
20348            a ^= (modulus & 0xff) as u8;
20349        }
20350        b >>= 1;
20351    }
20352
20353    result
20354}
20355
20356/// GF(256) multiplicative inverse using extended Euclidean algorithm
20357fn gf256_inv(a: u8) -> u8 {
20358    if a == 0 {
20359        return 0;
20360    }
20361
20362    // Use Fermat's little theorem: a^(-1) = a^(254) in GF(256)
20363    let mut result = a;
20364    for _ in 0..6 {
20365        result = gf256_mul(result, result);
20366        result = gf256_mul(result, a);
20367    }
20368    gf256_mul(result, result)
20369}
20370
20371// ============================================================================
20372// MULTI-BASE ENCODING: Polycultural numeral systems and crypto addresses
20373// ============================================================================
20374//
20375// Sigil supports multiple numeral bases reflecting different mathematical traditions:
20376//   Binary (2)      - 0b prefix - Modern computing
20377//   Octal (8)       - 0o prefix - Unix permissions
20378//   Decimal (10)    - Default   - Indo-Arabic (global standard)
20379//   Duodecimal (12) - 0z prefix - Dozen system (time, music)
20380//   Hexadecimal (16)- 0x prefix - Computing, colors
20381//   Vigesimal (20)  - 0v prefix - Mayan, Celtic, Basque
20382//   Sexagesimal (60)- 0s prefix - Babylonian (time, angles)
20383//
20384// Plus special encodings:
20385//   Base58  - Bitcoin addresses (no confusing 0/O/I/l)
20386//   Base32  - Case-insensitive, no confusing chars
20387//   Base36  - Alphanumeric only
20388
20389fn register_multibase(interp: &mut Interpreter) {
20390    // === Vigesimal (Base 20) - Mayan/Celtic ===
20391    // Digits: 0-9, A-J (or a-j)
20392
20393    define(interp, "to_vigesimal", Some(1), |_, args| {
20394        let n = match &args[0] {
20395            Value::Int(n) => *n,
20396            _ => return Err(RuntimeError::new("to_vigesimal() requires integer")),
20397        };
20398
20399        let result = to_base_string(n.unsigned_abs(), 20, false);
20400        let prefix = if n < 0 { "-0v" } else { "0v" };
20401        Ok(Value::String(Rc::new(format!("{}{}", prefix, result))))
20402    });
20403
20404    define(interp, "from_vigesimal", Some(1), |_, args| {
20405        let s = match &args[0] {
20406            Value::String(s) => s.to_string(),
20407            _ => return Err(RuntimeError::new("from_vigesimal() requires string")),
20408        };
20409
20410        let (negative, clean) = parse_base_prefix(&s, "0v");
20411        let value = from_base_string(&clean, 20)?;
20412        Ok(Value::Int(if negative {
20413            -(value as i64)
20414        } else {
20415            value as i64
20416        }))
20417    });
20418
20419    // === Sexagesimal (Base 60) - Babylonian ===
20420    // Uses colon-separated groups for readability: "1:30:45" = 1*3600 + 30*60 + 45
20421
20422    define(interp, "to_sexagesimal", Some(1), |_, args| {
20423        let n = match &args[0] {
20424            Value::Int(n) => *n,
20425            _ => return Err(RuntimeError::new("to_sexagesimal() requires integer")),
20426        };
20427
20428        let negative = n < 0;
20429        let mut value = n.unsigned_abs();
20430        let mut parts = Vec::new();
20431
20432        if value == 0 {
20433            parts.push("0".to_string());
20434        } else {
20435            while value > 0 {
20436                parts.push(format!("{}", value % 60));
20437                value /= 60;
20438            }
20439            parts.reverse();
20440        }
20441
20442        let prefix = if negative { "-0s" } else { "0s" };
20443        Ok(Value::String(Rc::new(format!(
20444            "{}[{}]",
20445            prefix,
20446            parts.join(":")
20447        ))))
20448    });
20449
20450    define(interp, "from_sexagesimal", Some(1), |_, args| {
20451        let s = match &args[0] {
20452            Value::String(s) => s.to_string(),
20453            _ => return Err(RuntimeError::new("from_sexagesimal() requires string")),
20454        };
20455
20456        let negative = s.starts_with('-');
20457        let clean = s
20458            .trim_start_matches('-')
20459            .trim_start_matches("0s")
20460            .trim_start_matches('[')
20461            .trim_end_matches(']');
20462
20463        let mut result: i64 = 0;
20464        for part in clean.split(':') {
20465            let digit: i64 = part
20466                .trim()
20467                .parse()
20468                .map_err(|_| RuntimeError::new(format!("Invalid sexagesimal digit: {}", part)))?;
20469            if digit < 0 || digit >= 60 {
20470                return Err(RuntimeError::new(format!(
20471                    "Sexagesimal digit out of range: {}",
20472                    digit
20473                )));
20474            }
20475            result = result * 60 + digit;
20476        }
20477
20478        Ok(Value::Int(if negative { -result } else { result }))
20479    });
20480
20481    // === Duodecimal (Base 12) - Dozen system ===
20482    // Digits: 0-9, X (10), E (11) - Dozenal Society convention
20483
20484    define(interp, "to_duodecimal", Some(1), |_, args| {
20485        let n = match &args[0] {
20486            Value::Int(n) => *n,
20487            _ => return Err(RuntimeError::new("to_duodecimal() requires integer")),
20488        };
20489
20490        let result = to_base_string_custom(n.unsigned_abs(), 12, "0123456789XE");
20491        let prefix = if n < 0 { "-0z" } else { "0z" };
20492        Ok(Value::String(Rc::new(format!("{}{}", prefix, result))))
20493    });
20494
20495    define(interp, "from_duodecimal", Some(1), |_, args| {
20496        let s = match &args[0] {
20497            Value::String(s) => s.to_string(),
20498            _ => return Err(RuntimeError::new("from_duodecimal() requires string")),
20499        };
20500
20501        let (negative, clean) = parse_base_prefix(&s, "0z");
20502        let value = from_base_string_custom(&clean.to_uppercase(), "0123456789XE")?;
20503        Ok(Value::Int(if negative {
20504            -(value as i64)
20505        } else {
20506            value as i64
20507        }))
20508    });
20509
20510    // === Generic Base Conversion ===
20511
20512    define(interp, "to_base", Some(2), |_, args| {
20513        let n = match &args[0] {
20514            Value::Int(n) => *n,
20515            _ => return Err(RuntimeError::new("to_base() requires integer")),
20516        };
20517        let base = match &args[1] {
20518            Value::Int(b) => *b as u64,
20519            _ => return Err(RuntimeError::new("to_base() requires integer base")),
20520        };
20521
20522        if base < 2 || base > 36 {
20523            return Err(RuntimeError::new("to_base() base must be 2-36"));
20524        }
20525
20526        let result = to_base_string(n.unsigned_abs(), base, false);
20527        let prefix = if n < 0 { "-" } else { "" };
20528        Ok(Value::String(Rc::new(format!("{}{}", prefix, result))))
20529    });
20530
20531    define(interp, "from_base", Some(2), |_, args| {
20532        let s = match &args[0] {
20533            Value::String(s) => s.to_string(),
20534            _ => return Err(RuntimeError::new("from_base() requires string")),
20535        };
20536        let base = match &args[1] {
20537            Value::Int(b) => *b as u64,
20538            _ => return Err(RuntimeError::new("from_base() requires integer base")),
20539        };
20540
20541        if base < 2 || base > 36 {
20542            return Err(RuntimeError::new("from_base() base must be 2-36"));
20543        }
20544
20545        let negative = s.starts_with('-');
20546        let clean = s.trim_start_matches('-');
20547        let value = from_base_string(clean, base)?;
20548        Ok(Value::Int(if negative {
20549            -(value as i64)
20550        } else {
20551            value as i64
20552        }))
20553    });
20554
20555    // === Base58 - Bitcoin/IPFS addresses ===
20556    // Alphabet: 123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz
20557    // Excludes: 0, O, I, l (confusing characters)
20558
20559    const BASE58_ALPHABET: &str = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
20560
20561    define(interp, "base58_encode", Some(1), |_, args| {
20562        let bytes: Vec<u8> = match &args[0] {
20563            Value::String(s) => s.as_bytes().to_vec(),
20564            Value::Array(arr) => arr
20565                .borrow()
20566                .iter()
20567                .filter_map(|v| {
20568                    if let Value::Int(i) = v {
20569                        Some(*i as u8)
20570                    } else {
20571                        None
20572                    }
20573                })
20574                .collect(),
20575            _ => {
20576                return Err(RuntimeError::new(
20577                    "base58_encode() requires string or byte array",
20578                ))
20579            }
20580        };
20581
20582        // Count leading zeros
20583        let leading_zeros = bytes.iter().take_while(|&&b| b == 0).count();
20584
20585        // Convert to big integer and then to base58
20586        let mut result = Vec::new();
20587        let mut num: Vec<u8> = bytes.clone();
20588
20589        while !num.is_empty() && !num.iter().all(|&b| b == 0) {
20590            let mut remainder = 0u32;
20591            let mut new_num = Vec::new();
20592
20593            for &byte in &num {
20594                let acc = (remainder << 8) + byte as u32;
20595                let digit = acc / 58;
20596                remainder = acc % 58;
20597
20598                if !new_num.is_empty() || digit > 0 {
20599                    new_num.push(digit as u8);
20600                }
20601            }
20602
20603            result.push(BASE58_ALPHABET.chars().nth(remainder as usize).unwrap());
20604            num = new_num;
20605        }
20606
20607        // Add '1' for each leading zero byte
20608        for _ in 0..leading_zeros {
20609            result.push('1');
20610        }
20611
20612        result.reverse();
20613        Ok(Value::String(Rc::new(result.into_iter().collect())))
20614    });
20615
20616    define(interp, "base58_decode", Some(1), |_, args| {
20617        let s = match &args[0] {
20618            Value::String(s) => s.to_string(),
20619            _ => return Err(RuntimeError::new("base58_decode() requires string")),
20620        };
20621
20622        // Count leading '1's
20623        let leading_ones = s.chars().take_while(|&c| c == '1').count();
20624
20625        // Convert from base58 to big integer
20626        let mut num: Vec<u8> = Vec::new();
20627
20628        for c in s.chars() {
20629            let digit = BASE58_ALPHABET
20630                .find(c)
20631                .ok_or_else(|| RuntimeError::new(format!("Invalid base58 character: {}", c)))?;
20632
20633            let mut carry = digit as u32;
20634            for byte in num.iter_mut().rev() {
20635                let acc = (*byte as u32) * 58 + carry;
20636                *byte = (acc & 0xff) as u8;
20637                carry = acc >> 8;
20638            }
20639
20640            while carry > 0 {
20641                num.insert(0, (carry & 0xff) as u8);
20642                carry >>= 8;
20643            }
20644        }
20645
20646        // Add leading zeros
20647        let mut result = vec![0u8; leading_ones];
20648        result.extend(num);
20649
20650        // Return as hex string for readability
20651        Ok(Value::String(Rc::new(hex::encode(&result))))
20652    });
20653
20654    // === Base32 - Case insensitive, no confusing chars ===
20655    // RFC 4648 alphabet: A-Z, 2-7
20656
20657    const BASE32_ALPHABET: &str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
20658
20659    define(interp, "base32_encode", Some(1), |_, args| {
20660        let bytes: Vec<u8> = match &args[0] {
20661            Value::String(s) => s.as_bytes().to_vec(),
20662            Value::Array(arr) => arr
20663                .borrow()
20664                .iter()
20665                .filter_map(|v| {
20666                    if let Value::Int(i) = v {
20667                        Some(*i as u8)
20668                    } else {
20669                        None
20670                    }
20671                })
20672                .collect(),
20673            _ => {
20674                return Err(RuntimeError::new(
20675                    "base32_encode() requires string or byte array",
20676                ))
20677            }
20678        };
20679
20680        let mut result = String::new();
20681        let mut buffer: u64 = 0;
20682        let mut bits = 0;
20683
20684        for byte in bytes {
20685            buffer = (buffer << 8) | byte as u64;
20686            bits += 8;
20687
20688            while bits >= 5 {
20689                bits -= 5;
20690                let idx = ((buffer >> bits) & 0x1f) as usize;
20691                result.push(BASE32_ALPHABET.chars().nth(idx).unwrap());
20692            }
20693        }
20694
20695        if bits > 0 {
20696            let idx = ((buffer << (5 - bits)) & 0x1f) as usize;
20697            result.push(BASE32_ALPHABET.chars().nth(idx).unwrap());
20698        }
20699
20700        // Padding
20701        while result.len() % 8 != 0 {
20702            result.push('=');
20703        }
20704
20705        Ok(Value::String(Rc::new(result)))
20706    });
20707
20708    define(interp, "base32_decode", Some(1), |_, args| {
20709        let s = match &args[0] {
20710            Value::String(s) => s.to_uppercase().replace('=', ""),
20711            _ => return Err(RuntimeError::new("base32_decode() requires string")),
20712        };
20713
20714        let mut result = Vec::new();
20715        let mut buffer: u64 = 0;
20716        let mut bits = 0;
20717
20718        for c in s.chars() {
20719            let digit = BASE32_ALPHABET
20720                .find(c)
20721                .ok_or_else(|| RuntimeError::new(format!("Invalid base32 character: {}", c)))?;
20722
20723            buffer = (buffer << 5) | digit as u64;
20724            bits += 5;
20725
20726            if bits >= 8 {
20727                bits -= 8;
20728                result.push((buffer >> bits) as u8);
20729                buffer &= (1 << bits) - 1;
20730            }
20731        }
20732
20733        Ok(Value::String(Rc::new(hex::encode(&result))))
20734    });
20735
20736    // === Cultural Numerology ===
20737
20738    // sacred_numbers - get sacred/significant numbers for a culture
20739    define(interp, "sacred_numbers", Some(1), |_, args| {
20740        let culture = match &args[0] {
20741            Value::String(s) => s.to_lowercase(),
20742            _ => {
20743                return Err(RuntimeError::new(
20744                    "sacred_numbers() requires string culture",
20745                ))
20746            }
20747        };
20748
20749        let numbers: Vec<(i64, &str)> = match culture.as_str() {
20750            "mayan" | "maya" => vec![
20751                (13, "Sacred cycle - Tzolkin calendar"),
20752                (20, "Base of vigesimal system - human digits"),
20753                (52, "Calendar round - 52 years"),
20754                (260, "Tzolkin sacred calendar days"),
20755                (365, "Haab solar calendar days"),
20756                (400, "Baktun - 20×20 years"),
20757            ],
20758            "babylonian" | "mesopotamian" => vec![
20759                (12, "Months, hours - celestial division"),
20760                (60, "Sexagesimal base - minutes, seconds, degrees"),
20761                (360, "Circle degrees - 6×60"),
20762                (3600, "Sar - 60×60, large count"),
20763                (7, "Planets visible to naked eye"),
20764            ],
20765            "chinese" | "zh" => vec![
20766                (8, "八 (bā) - prosperity, wealth (sounds like 發)"),
20767                (9, "九 (jiǔ) - longevity (sounds like 久)"),
20768                (6, "六 (liù) - smooth, flowing"),
20769                (2, "二 (èr) - pairs, harmony"),
20770                (4, "四 (sì) - AVOID - sounds like death (死)"),
20771                (5, "五 (wǔ) - five elements"),
20772                (12, "十二 - zodiac animals"),
20773            ],
20774            "japanese" | "ja" => vec![
20775                (7, "七 (nana) - lucky, seven gods of fortune"),
20776                (8, "八 (hachi) - prosperity, expansion"),
20777                (3, "三 (san) - completeness"),
20778                (5, "五 (go) - five elements"),
20779                (4, "四 (shi) - AVOID - sounds like death (死)"),
20780                (9, "九 (ku) - AVOID - sounds like suffering (苦)"),
20781            ],
20782            "hebrew" | "jewish" => vec![
20783                (7, "Shabbat, creation days, menorah branches"),
20784                (18, "Chai (חי) - life - gematria of ח(8) + י(10)"),
20785                (40, "Transformation - flood, Sinai, wilderness"),
20786                (12, "Tribes of Israel"),
20787                (613, "Mitzvot - commandments"),
20788                (26, "Gematria of YHWH"),
20789            ],
20790            "islamic" | "arabic" | "ar" => vec![
20791                (5, "Pillars of Islam, daily prayers"),
20792                (7, "Heavens, circumambulation of Kaaba"),
20793                (40, "Age of prophethood, days of repentance"),
20794                (99, "Names of Allah"),
20795                (786, "Abjad value of Bismillah"),
20796            ],
20797            "hindu" | "indian" | "hi" => vec![
20798                (108, "Sacred beads, Upanishads, sun's distance"),
20799                (7, "Chakras (main), rishis, sacred rivers"),
20800                (3, "Trimurti - Brahma, Vishnu, Shiva"),
20801                (4, "Vedas, yugas, varnas"),
20802                (9, "Planets (navagraha), durga forms"),
20803                (1008, "Names of Vishnu"),
20804            ],
20805            "greek" | "pythagorean" => vec![
20806                (1, "Monad - unity, source"),
20807                (2, "Dyad - duality, diversity"),
20808                (3, "Triad - harmony, completion"),
20809                (4, "Tetrad - solidity, earth"),
20810                (7, "Heptad - perfection"),
20811                (10, "Decad - tetractys, divine"),
20812                (12, "Olympian gods"),
20813            ],
20814            "celtic" | "irish" => vec![
20815                (3, "Triple goddess, triquetra"),
20816                (5, "Elements including spirit"),
20817                (9, "Triple threes - sacred completion"),
20818                (13, "Lunar months"),
20819                (17, "St. Patrick's Day"),
20820                (20, "Vigesimal counting"),
20821            ],
20822            _ => vec![
20823                (1, "Unity"),
20824                (7, "Widely considered lucky"),
20825                (12, "Dozen - practical division"),
20826                (13, "Often considered unlucky in West"),
20827            ],
20828        };
20829
20830        let result: Vec<Value> = numbers
20831            .iter()
20832            .map(|(n, meaning)| {
20833                let mut entry = std::collections::HashMap::new();
20834                entry.insert("number".to_string(), Value::Int(*n));
20835                entry.insert(
20836                    "meaning".to_string(),
20837                    Value::String(Rc::new(meaning.to_string())),
20838                );
20839                Value::Map(Rc::new(RefCell::new(entry)))
20840            })
20841            .collect();
20842
20843        Ok(Value::Array(Rc::new(RefCell::new(result))))
20844    });
20845
20846    // is_sacred - check if a number is sacred in a culture
20847    define(interp, "is_sacred", Some(2), |_, args| {
20848        let n = match &args[0] {
20849            Value::Int(n) => *n,
20850            _ => return Err(RuntimeError::new("is_sacred() requires integer")),
20851        };
20852        let culture = match &args[1] {
20853            Value::String(s) => s.to_lowercase(),
20854            _ => return Err(RuntimeError::new("is_sacred() requires string culture")),
20855        };
20856
20857        let sacred = match culture.as_str() {
20858            "mayan" | "maya" => vec![13, 20, 52, 260, 365, 400],
20859            "babylonian" | "mesopotamian" => vec![12, 60, 360, 3600, 7],
20860            "chinese" | "zh" => vec![8, 9, 6, 2, 5, 12],
20861            "japanese" | "ja" => vec![7, 8, 3, 5],
20862            "hebrew" | "jewish" => vec![7, 18, 40, 12, 613, 26],
20863            "islamic" | "arabic" | "ar" => vec![5, 7, 40, 99, 786],
20864            "hindu" | "indian" | "hi" => vec![108, 7, 3, 4, 9, 1008],
20865            "greek" | "pythagorean" => vec![1, 2, 3, 4, 7, 10, 12],
20866            "celtic" | "irish" => vec![3, 5, 9, 13, 17, 20],
20867            _ => vec![7, 12],
20868        };
20869
20870        Ok(Value::Bool(sacred.contains(&n)))
20871    });
20872
20873    // is_unlucky - check if a number is unlucky in a culture
20874    define(interp, "is_unlucky", Some(2), |_, args| {
20875        let n = match &args[0] {
20876            Value::Int(n) => *n,
20877            _ => return Err(RuntimeError::new("is_unlucky() requires integer")),
20878        };
20879        let culture = match &args[1] {
20880            Value::String(s) => s.to_lowercase(),
20881            _ => return Err(RuntimeError::new("is_unlucky() requires string culture")),
20882        };
20883
20884        let unlucky = match culture.as_str() {
20885            "chinese" | "zh" => vec![4],     // 四 sounds like 死 (death)
20886            "japanese" | "ja" => vec![4, 9], // 四=death, 九=suffering
20887            "western" | "en" => vec![13],    // Friday the 13th
20888            "italian" | "it" => vec![17],    // XVII = VIXI (I lived = I'm dead)
20889            _ => vec![],
20890        };
20891
20892        Ok(Value::Bool(unlucky.contains(&n)))
20893    });
20894
20895    // number_meaning - get the cultural meaning of a specific number
20896    define(interp, "number_meaning", Some(2), |_, args| {
20897        let n = match &args[0] {
20898            Value::Int(n) => *n,
20899            _ => return Err(RuntimeError::new("number_meaning() requires integer")),
20900        };
20901        let culture = match &args[1] {
20902            Value::String(s) => s.to_lowercase(),
20903            _ => {
20904                return Err(RuntimeError::new(
20905                    "number_meaning() requires string culture",
20906                ))
20907            }
20908        };
20909
20910        let meaning = match (n, culture.as_str()) {
20911            // Chinese
20912            (8, "chinese" | "zh") => "八 (bā) - Most auspicious, sounds like 發 (prosperity)",
20913            (4, "chinese" | "zh") => "四 (sì) - Unlucky, sounds like 死 (death)",
20914            (9, "chinese" | "zh") => "九 (jiǔ) - Longevity, sounds like 久 (long-lasting)",
20915            (6, "chinese" | "zh") => "六 (liù) - Smooth and well-off",
20916            (2, "chinese" | "zh") => "二 (èr) - Good things come in pairs",
20917
20918            // Japanese
20919            (7, "japanese" | "ja") => "七 (nana) - Lucky, seven gods of fortune",
20920            (8, "japanese" | "ja") => "八 (hachi) - Lucky, represents spreading prosperity",
20921            (4, "japanese" | "ja") => "四 (shi) - Unlucky, homophone of death",
20922            (9, "japanese" | "ja") => "九 (ku) - Unlucky, homophone of suffering",
20923
20924            // Hebrew
20925            (18, "hebrew" | "jewish") => "Chai (חי) - Life itself, most auspicious",
20926            (7, "hebrew" | "jewish") => "Divine completion - Shabbat, menorah, creation",
20927            (40, "hebrew" | "jewish") => "Transformation - flood, Sinai, wilderness years",
20928            (613, "hebrew" | "jewish") => "Taryag - total number of mitzvot (commandments)",
20929
20930            // Mayan
20931            (13, "mayan" | "maya") => "Sacred Tzolkin cycle, celestial layers",
20932            (20, "mayan" | "maya") => "Vigesimal base - fingers and toes, uinal",
20933            (260, "mayan" | "maya") => "Tzolkin calendar - 13 × 20 sacred days",
20934
20935            // Babylonian
20936            (60, "babylonian" | "mesopotamian") => {
20937                "Sexagesimal base - divisible by 2,3,4,5,6,10,12,15,20,30"
20938            }
20939            (360, "babylonian" | "mesopotamian") => "Circle degrees - celestial observation",
20940
20941            // Hindu
20942            (108, "hindu" | "indian" | "hi") => {
20943                "Sacred completeness - mala beads, Upanishads, sun ratio"
20944            }
20945            (3, "hindu" | "indian" | "hi") => "Trimurti - Brahma, Vishnu, Shiva",
20946            (9, "hindu" | "indian" | "hi") => "Navagraha (9 planets), Durga's 9 forms",
20947
20948            // Islamic
20949            (99, "islamic" | "arabic" | "ar") => "Asma ul-Husna - 99 names of Allah",
20950            (5, "islamic" | "arabic" | "ar") => "Five pillars of Islam",
20951            (786, "islamic" | "arabic" | "ar") => "Abjad numerology of Bismillah",
20952
20953            // Greek/Pythagorean
20954            (10, "greek" | "pythagorean") => "Tetractys - 1+2+3+4, perfect number",
20955            (7, "greek" | "pythagorean") => "Heptad - virgin number, Athena's number",
20956
20957            _ => "No specific cultural meaning recorded",
20958        };
20959
20960        let mut result = std::collections::HashMap::new();
20961        result.insert("number".to_string(), Value::Int(n));
20962        result.insert("culture".to_string(), Value::String(Rc::new(culture)));
20963        result.insert(
20964            "meaning".to_string(),
20965            Value::String(Rc::new(meaning.to_string())),
20966        );
20967
20968        Ok(Value::Map(Rc::new(RefCell::new(result))))
20969    });
20970
20971    // === Time encoding using Babylonian sexagesimal ===
20972
20973    // to_babylonian_time - convert seconds to Babylonian notation
20974    define(interp, "to_babylonian_time", Some(1), |_, args| {
20975        let seconds = match &args[0] {
20976            Value::Int(n) => *n,
20977            Value::Float(f) => *f as i64,
20978            _ => return Err(RuntimeError::new("to_babylonian_time() requires number")),
20979        };
20980
20981        let hours = seconds / 3600;
20982        let mins = (seconds % 3600) / 60;
20983        let secs = seconds % 60;
20984
20985        Ok(Value::String(Rc::new(format!(
20986            "0s[{}:{}:{}]",
20987            hours, mins, secs
20988        ))))
20989    });
20990
20991    // from_babylonian_time - convert Babylonian time to seconds
20992    define(interp, "from_babylonian_time", Some(1), |_, args| {
20993        let s = match &args[0] {
20994            Value::String(s) => s.to_string(),
20995            _ => return Err(RuntimeError::new("from_babylonian_time() requires string")),
20996        };
20997
20998        let clean = s
20999            .trim_start_matches("0s")
21000            .trim_start_matches('[')
21001            .trim_end_matches(']');
21002
21003        let parts: Vec<i64> = clean
21004            .split(':')
21005            .map(|p| p.trim().parse::<i64>().unwrap_or(0))
21006            .collect();
21007
21008        let seconds = match parts.len() {
21009            1 => parts[0],
21010            2 => parts[0] * 60 + parts[1],
21011            3 => parts[0] * 3600 + parts[1] * 60 + parts[2],
21012            _ => return Err(RuntimeError::new("Invalid Babylonian time format")),
21013        };
21014
21015        Ok(Value::Int(seconds))
21016    });
21017
21018    // === Multi-base secret sharing ===
21019
21020    // vigesimal_shares - split secret with shares in Mayan base-20
21021    define(interp, "vigesimal_shares", Some(3), |_, args| {
21022        let secret = match &args[0] {
21023            Value::String(s) => s.as_bytes().to_vec(),
21024            _ => {
21025                return Err(RuntimeError::new(
21026                    "vigesimal_shares() requires string secret",
21027                ))
21028            }
21029        };
21030
21031        let threshold = match &args[1] {
21032            Value::Int(n) => *n as usize,
21033            _ => {
21034                return Err(RuntimeError::new(
21035                    "vigesimal_shares() requires integer threshold",
21036                ))
21037            }
21038        };
21039
21040        let num_shares = match &args[2] {
21041            Value::Int(n) => *n as usize,
21042            _ => {
21043                return Err(RuntimeError::new(
21044                    "vigesimal_shares() requires integer num_shares",
21045                ))
21046            }
21047        };
21048
21049        if threshold < 2 || num_shares < threshold || num_shares > 20 {
21050            return Err(RuntimeError::new(
21051                "vigesimal_shares() requires 2 <= threshold <= num_shares <= 20 (Mayan limit)",
21052            ));
21053        }
21054
21055        // Generate shares using Shamir
21056        let mut rng = rand::thread_rng();
21057        let mut shares: Vec<Vec<u8>> = (0..num_shares)
21058            .map(|_| Vec::with_capacity(secret.len() + 1))
21059            .collect();
21060
21061        for (i, share) in shares.iter_mut().enumerate() {
21062            share.push((i + 1) as u8);
21063        }
21064
21065        for &byte in &secret {
21066            let mut coefficients: Vec<u8> = vec![byte];
21067            for _ in 1..threshold {
21068                coefficients.push(rng.gen());
21069            }
21070
21071            for (i, share) in shares.iter_mut().enumerate() {
21072                let x = (i + 1) as u8;
21073                let y = eval_polynomial_gf256(&coefficients, x);
21074                share.push(y);
21075            }
21076        }
21077
21078        // Encode shares in vigesimal
21079        let share_values: Vec<Value> = shares
21080            .iter()
21081            .enumerate()
21082            .map(|(i, share)| {
21083                let mut entry = std::collections::HashMap::new();
21084
21085                // Convert share bytes to vigesimal string
21086                let mut vig_parts: Vec<String> = Vec::new();
21087                for &byte in share {
21088                    vig_parts.push(to_base_string(byte as u64, 20, true));
21089                }
21090
21091                entry.insert("index".to_string(), Value::Int((i + 1) as i64));
21092                entry.insert(
21093                    "vigesimal".to_string(),
21094                    Value::String(Rc::new(format!("0v{}", vig_parts.join(".")))),
21095                );
21096                entry.insert(
21097                    "hex".to_string(),
21098                    Value::String(Rc::new(hex::encode(share))),
21099                );
21100
21101                Value::Map(Rc::new(RefCell::new(entry)))
21102            })
21103            .collect();
21104
21105        let mut result = std::collections::HashMap::new();
21106        result.insert(
21107            "shares".to_string(),
21108            Value::Array(Rc::new(RefCell::new(share_values))),
21109        );
21110        result.insert("threshold".to_string(), Value::Int(threshold as i64));
21111        result.insert("total".to_string(), Value::Int(num_shares as i64));
21112        result.insert(
21113            "base".to_string(),
21114            Value::String(Rc::new("vigesimal (Mayan base-20)".to_string())),
21115        );
21116
21117        Ok(Value::Map(Rc::new(RefCell::new(result))))
21118    });
21119
21120    // multibase_info - get information about supported bases
21121    define(interp, "multibase_info", Some(0), |_, _| {
21122        let mut info = std::collections::HashMap::new();
21123
21124        let bases = vec![
21125            ("binary", 2, "0b", "Modern computing"),
21126            ("octal", 8, "0o", "Unix, historical computing"),
21127            ("decimal", 10, "", "Indo-Arabic global standard"),
21128            (
21129                "duodecimal",
21130                12,
21131                "0z",
21132                "Dozen system - time, music, measurement",
21133            ),
21134            ("hexadecimal", 16, "0x", "Computing, colors, addresses"),
21135            (
21136                "vigesimal",
21137                20,
21138                "0v",
21139                "Mayan, Celtic, Basque - human digits",
21140            ),
21141            (
21142                "sexagesimal",
21143                60,
21144                "0s",
21145                "Babylonian - time, angles, astronomy",
21146            ),
21147        ];
21148
21149        let base_list: Vec<Value> = bases
21150            .iter()
21151            .map(|(name, base, prefix, desc)| {
21152                let mut entry = std::collections::HashMap::new();
21153                entry.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
21154                entry.insert("base".to_string(), Value::Int(*base as i64));
21155                entry.insert(
21156                    "prefix".to_string(),
21157                    Value::String(Rc::new(prefix.to_string())),
21158                );
21159                entry.insert(
21160                    "origin".to_string(),
21161                    Value::String(Rc::new(desc.to_string())),
21162                );
21163                Value::Map(Rc::new(RefCell::new(entry)))
21164            })
21165            .collect();
21166
21167        info.insert(
21168            "numeral_systems".to_string(),
21169            Value::Array(Rc::new(RefCell::new(base_list))),
21170        );
21171
21172        let encodings = vec!["base58 (Bitcoin)", "base32 (RFC 4648)", "base64 (standard)"];
21173        let enc_list: Vec<Value> = encodings
21174            .iter()
21175            .map(|s| Value::String(Rc::new(s.to_string())))
21176            .collect();
21177        info.insert(
21178            "special_encodings".to_string(),
21179            Value::Array(Rc::new(RefCell::new(enc_list))),
21180        );
21181
21182        let cultures = vec![
21183            "mayan",
21184            "babylonian",
21185            "chinese",
21186            "japanese",
21187            "hebrew",
21188            "islamic",
21189            "hindu",
21190            "greek",
21191            "celtic",
21192        ];
21193        let cult_list: Vec<Value> = cultures
21194            .iter()
21195            .map(|s| Value::String(Rc::new(s.to_string())))
21196            .collect();
21197        info.insert(
21198            "supported_cultures".to_string(),
21199            Value::Array(Rc::new(RefCell::new(cult_list))),
21200        );
21201
21202        Ok(Value::Map(Rc::new(RefCell::new(info))))
21203    });
21204}
21205
21206// Helper functions for base conversion
21207
21208fn to_base_string(mut n: u64, base: u64, pad_to_two: bool) -> String {
21209    const DIGITS: &[u8] = b"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
21210
21211    if n == 0 {
21212        return if pad_to_two {
21213            "00".to_string()
21214        } else {
21215            "0".to_string()
21216        };
21217    }
21218
21219    let mut result = Vec::new();
21220    while n > 0 {
21221        result.push(DIGITS[(n % base) as usize] as char);
21222        n /= base;
21223    }
21224
21225    if pad_to_two && result.len() < 2 {
21226        result.push('0');
21227    }
21228
21229    result.reverse();
21230    result.into_iter().collect()
21231}
21232
21233fn to_base_string_custom(mut n: u64, base: u64, digits: &str) -> String {
21234    if n == 0 {
21235        return digits.chars().next().unwrap().to_string();
21236    }
21237
21238    let mut result = Vec::new();
21239    let digit_chars: Vec<char> = digits.chars().collect();
21240
21241    while n > 0 {
21242        result.push(digit_chars[(n % base) as usize]);
21243        n /= base;
21244    }
21245
21246    result.reverse();
21247    result.into_iter().collect()
21248}
21249
21250fn from_base_string(s: &str, base: u64) -> Result<u64, RuntimeError> {
21251    let mut result: u64 = 0;
21252
21253    for c in s.chars() {
21254        let digit = match c {
21255            '0'..='9' => c as u64 - '0' as u64,
21256            'A'..='Z' => c as u64 - 'A' as u64 + 10,
21257            'a'..='z' => c as u64 - 'a' as u64 + 10,
21258            _ => return Err(RuntimeError::new(format!("Invalid digit: {}", c))),
21259        };
21260
21261        if digit >= base {
21262            return Err(RuntimeError::new(format!(
21263                "Digit {} out of range for base {}",
21264                c, base
21265            )));
21266        }
21267
21268        result = result
21269            .checked_mul(base)
21270            .and_then(|r| r.checked_add(digit))
21271            .ok_or_else(|| RuntimeError::new("Number overflow"))?;
21272    }
21273
21274    Ok(result)
21275}
21276
21277fn from_base_string_custom(s: &str, digits: &str) -> Result<u64, RuntimeError> {
21278    let base = digits.len() as u64;
21279    let mut result: u64 = 0;
21280
21281    for c in s.chars() {
21282        let digit = digits
21283            .find(c)
21284            .ok_or_else(|| RuntimeError::new(format!("Invalid digit: {}", c)))?
21285            as u64;
21286
21287        result = result
21288            .checked_mul(base)
21289            .and_then(|r| r.checked_add(digit))
21290            .ok_or_else(|| RuntimeError::new("Number overflow"))?;
21291    }
21292
21293    Ok(result)
21294}
21295
21296fn parse_base_prefix(s: &str, prefix: &str) -> (bool, String) {
21297    let negative = s.starts_with('-');
21298    let clean = s
21299        .trim_start_matches('-')
21300        .trim_start_matches(prefix)
21301        .to_string();
21302    (negative, clean)
21303}
21304
21305// ============================================================================
21306// POLYCULTURAL AUDIO: World tuning systems, sacred frequencies, synthesis
21307// ============================================================================
21308//
21309// Sigil's audio system respects that music is not universal - different cultures
21310// have fundamentally different relationships with pitch, scale, and meaning.
21311//
21312// Waveform Morphemes:
21313//   ∿  sine     - pure tone, fundamental
21314//   ⊓  square   - digital, odd harmonics
21315//   ⋀  sawtooth - bright, all harmonics
21316//   △  triangle - mellow, odd harmonics (weaker)
21317//
21318// Tuning Systems:
21319//   12-TET     - Western equal temperament (default)
21320//   24-TET     - Arabic maqam (quarter tones)
21321//   22-Shruti  - Indian classical (microtones)
21322//   Just       - Pure ratios (Pythagorean, etc.)
21323//   Gamelan    - Indonesian (pelog, slendro)
21324//   53-TET     - Turkish/Persian (commas)
21325//
21326// Sacred Frequencies:
21327//   ॐ Om       - 136.1 Hz (Earth year frequency)
21328//   Solfeggio  - 396, 417, 528, 639, 741, 852 Hz
21329//   Schumann   - 7.83 Hz (Earth resonance)
21330//   Planetary  - Kepler's music of the spheres
21331
21332fn register_audio(interp: &mut Interpreter) {
21333    // =========================================================================
21334    // TUNING SYSTEMS
21335    // =========================================================================
21336
21337    // tune - convert a note to frequency in a specific tuning system
21338    // Supports: "12tet", "24tet", "just", "pythagorean", "meantone", "gamelan_pelog", "gamelan_slendro"
21339    define(interp, "tune", Some(3), |_, args| {
21340        let note = match &args[0] {
21341            Value::Int(n) => *n as f64, // MIDI note number
21342            Value::Float(f) => *f,      // Fractional note
21343            Value::String(s) => parse_note_name(s)?,
21344            _ => return Err(RuntimeError::new("tune() requires note number or name")),
21345        };
21346
21347        let system = match &args[1] {
21348            Value::String(s) => s.to_lowercase(),
21349            _ => return Err(RuntimeError::new("tune() requires tuning system name")),
21350        };
21351
21352        let root_freq = match &args[2] {
21353            Value::Float(f) => *f,
21354            Value::Int(i) => *i as f64,
21355            _ => return Err(RuntimeError::new("tune() requires root frequency")),
21356        };
21357
21358        let freq = match system.as_str() {
21359            "12tet" | "equal" | "western" => {
21360                // Standard 12-tone equal temperament
21361                root_freq * 2.0_f64.powf((note - 69.0) / 12.0)
21362            }
21363            "24tet" | "quarter" | "arabic" | "maqam" => {
21364                // 24-tone equal temperament (quarter tones)
21365                root_freq * 2.0_f64.powf((note - 69.0) / 24.0)
21366            }
21367            "just" | "pure" => {
21368                // Just intonation ratios from root
21369                let interval = ((note - 69.0) % 12.0 + 12.0) % 12.0;
21370                let octave = ((note - 69.0) / 12.0).floor();
21371                let ratio = just_intonation_ratio(interval as i32);
21372                root_freq * ratio * 2.0_f64.powf(octave)
21373            }
21374            "pythagorean" => {
21375                // Pythagorean tuning (pure fifths)
21376                let interval = ((note - 69.0) % 12.0 + 12.0) % 12.0;
21377                let octave = ((note - 69.0) / 12.0).floor();
21378                let ratio = pythagorean_ratio(interval as i32);
21379                root_freq * ratio * 2.0_f64.powf(octave)
21380            }
21381            "meantone" | "quarter_comma" => {
21382                // Quarter-comma meantone
21383                let interval = ((note - 69.0) % 12.0 + 12.0) % 12.0;
21384                let octave = ((note - 69.0) / 12.0).floor();
21385                let ratio = meantone_ratio(interval as i32);
21386                root_freq * ratio * 2.0_f64.powf(octave)
21387            }
21388            "53tet" | "turkish" | "persian" | "comma" => {
21389                // 53-TET (Turkish/Persian music, approximates just intonation)
21390                root_freq * 2.0_f64.powf((note - 69.0) / 53.0)
21391            }
21392            "22shruti" | "shruti" | "indian" => {
21393                // Indian 22-shruti system
21394                let shruti = (note - 69.0) % 22.0;
21395                let octave = ((note - 69.0) / 22.0).floor();
21396                let ratio = shruti_ratio(shruti as i32);
21397                root_freq * ratio * 2.0_f64.powf(octave)
21398            }
21399            "gamelan_pelog" | "pelog" => {
21400                // Javanese pelog (7-note)
21401                let degree = ((note - 69.0) % 7.0 + 7.0) % 7.0;
21402                let octave = ((note - 69.0) / 7.0).floor();
21403                let ratio = pelog_ratio(degree as i32);
21404                root_freq * ratio * 2.0_f64.powf(octave)
21405            }
21406            "gamelan_slendro" | "slendro" => {
21407                // Javanese slendro (5-note, roughly equal)
21408                let degree = ((note - 69.0) % 5.0 + 5.0) % 5.0;
21409                let octave = ((note - 69.0) / 5.0).floor();
21410                let ratio = slendro_ratio(degree as i32);
21411                root_freq * ratio * 2.0_f64.powf(octave)
21412            }
21413            "bohlen_pierce" | "bp" => {
21414                // Bohlen-Pierce scale (tritave-based, 13 steps)
21415                root_freq * 3.0_f64.powf((note - 69.0) / 13.0)
21416            }
21417            _ => {
21418                return Err(RuntimeError::new(format!(
21419                    "Unknown tuning system: {}",
21420                    system
21421                )))
21422            }
21423        };
21424
21425        Ok(Value::Float(freq))
21426    });
21427
21428    // tuning_info - get information about a tuning system
21429    define(interp, "tuning_info", Some(1), |_, args| {
21430        let system = match &args[0] {
21431            Value::String(s) => s.to_lowercase(),
21432            _ => return Err(RuntimeError::new("tuning_info() requires string")),
21433        };
21434
21435        let (name, notes_per_octave, origin, description) = match system.as_str() {
21436            "12tet" | "equal" | "western" => (
21437                "12-TET", 12, "Western (18th century)",
21438                "Equal temperament - every semitone is exactly 2^(1/12). Universal but slightly impure."
21439            ),
21440            "24tet" | "quarter" | "arabic" | "maqam" => (
21441                "24-TET", 24, "Arabic/Turkish",
21442                "Quarter-tone system for maqam music. Enables neutral seconds and other microtones."
21443            ),
21444            "just" | "pure" => (
21445                "Just Intonation", 12, "Ancient (Ptolemy)",
21446                "Pure frequency ratios (3:2 fifth, 5:4 third). Beatless intervals but limited modulation."
21447            ),
21448            "pythagorean" => (
21449                "Pythagorean", 12, "Ancient Greece",
21450                "Built entirely from perfect fifths (3:2). Pure fifths but harsh thirds."
21451            ),
21452            "meantone" | "quarter_comma" => (
21453                "Quarter-Comma Meantone", 12, "Renaissance Europe",
21454                "Tempered fifths for pure major thirds. Beautiful in limited keys."
21455            ),
21456            "53tet" | "turkish" | "persian" | "comma" => (
21457                "53-TET", 53, "Turkish/Persian",
21458                "53 notes per octave. Closely approximates just intonation and allows maqam/dastgah."
21459            ),
21460            "22shruti" | "shruti" | "indian" => (
21461                "22-Shruti", 22, "Indian Classical",
21462                "Ancient Indian system. Each shruti is a 'microtone' - the smallest perceptible interval."
21463            ),
21464            "gamelan_pelog" | "pelog" => (
21465                "Pelog", 7, "Javanese Gamelan",
21466                "Heptatonic scale with unequal steps. Each gamelan has unique tuning - instruments are married."
21467            ),
21468            "gamelan_slendro" | "slendro" => (
21469                "Slendro", 5, "Javanese Gamelan",
21470                "Pentatonic scale, roughly equal steps (~240 cents). Each ensemble uniquely tuned."
21471            ),
21472            "bohlen_pierce" | "bp" => (
21473                "Bohlen-Pierce", 13, "Modern (1970s)",
21474                "Non-octave scale based on 3:1 tritave. Alien but mathematically beautiful."
21475            ),
21476            _ => return Err(RuntimeError::new(format!("Unknown tuning system: {}", system))),
21477        };
21478
21479        let mut info = std::collections::HashMap::new();
21480        info.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
21481        info.insert("notes_per_octave".to_string(), Value::Int(notes_per_octave));
21482        info.insert(
21483            "origin".to_string(),
21484            Value::String(Rc::new(origin.to_string())),
21485        );
21486        info.insert(
21487            "description".to_string(),
21488            Value::String(Rc::new(description.to_string())),
21489        );
21490
21491        Ok(Value::Map(Rc::new(RefCell::new(info))))
21492    });
21493
21494    // list_tuning_systems - list all available tuning systems
21495    define(interp, "list_tuning_systems", Some(0), |_, _| {
21496        let systems = vec![
21497            ("12tet", "Western equal temperament", 12),
21498            ("24tet", "Arabic/Turkish quarter-tones", 24),
21499            ("just", "Pure ratio just intonation", 12),
21500            ("pythagorean", "Ancient Greek pure fifths", 12),
21501            ("meantone", "Renaissance quarter-comma", 12),
21502            ("53tet", "Turkish/Persian comma system", 53),
21503            ("22shruti", "Indian microtonal", 22),
21504            ("pelog", "Javanese gamelan 7-note", 7),
21505            ("slendro", "Javanese gamelan 5-note", 5),
21506            ("bohlen_pierce", "Non-octave tritave scale", 13),
21507        ];
21508
21509        let result: Vec<Value> = systems
21510            .iter()
21511            .map(|(name, desc, notes)| {
21512                let mut entry = std::collections::HashMap::new();
21513                entry.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
21514                entry.insert(
21515                    "description".to_string(),
21516                    Value::String(Rc::new(desc.to_string())),
21517                );
21518                entry.insert("notes_per_octave".to_string(), Value::Int(*notes));
21519                Value::Map(Rc::new(RefCell::new(entry)))
21520            })
21521            .collect();
21522
21523        Ok(Value::Array(Rc::new(RefCell::new(result))))
21524    });
21525
21526    // =========================================================================
21527    // SACRED FREQUENCIES
21528    // =========================================================================
21529
21530    // sacred_freq - get sacred/spiritual frequency by name
21531    define(interp, "sacred_freq", Some(1), |_, args| {
21532        let name = match &args[0] {
21533            Value::String(s) => s.to_lowercase(),
21534            _ => return Err(RuntimeError::new("sacred_freq() requires string")),
21535        };
21536
21537        let (freq, description) = match name.as_str() {
21538            // Om and Earth frequencies
21539            "om" | "ॐ" | "aum" => (136.1, "Om - Earth year frequency (Cosmic Om)"),
21540            "earth_day" => (194.18, "Earth day - one rotation"),
21541            "earth_year" => (136.1, "Earth year - one orbit (Om frequency)"),
21542            "schumann" | "earth_resonance" => (
21543                7.83,
21544                "Schumann resonance - Earth's electromagnetic heartbeat",
21545            ),
21546
21547            // Solfeggio frequencies
21548            "ut" | "do" | "396" => (396.0, "UT/DO - Liberating guilt and fear"),
21549            "re" | "417" => (417.0, "RE - Undoing situations, facilitating change"),
21550            "mi" | "528" => (528.0, "MI - Transformation, miracles, DNA repair"),
21551            "fa" | "639" => (639.0, "FA - Connecting relationships"),
21552            "sol" | "741" => (741.0, "SOL - Awakening intuition"),
21553            "la" | "852" => (852.0, "LA - Returning to spiritual order"),
21554            "si" | "963" => (963.0, "SI - Divine consciousness, enlightenment"),
21555            "174" => (174.0, "Solfeggio foundation - pain relief"),
21556            "285" => (285.0, "Solfeggio - healing tissue"),
21557
21558            // Planetary frequencies (Kepler/Cousto)
21559            "sun" | "☉" => (126.22, "Sun - ego, vitality, leadership"),
21560            "moon" | "☽" | "☾" => (210.42, "Moon - emotion, intuition, cycles"),
21561            "mercury" | "☿" => (141.27, "Mercury - communication, intellect"),
21562            "venus" | "♀" => (221.23, "Venus - love, beauty, harmony"),
21563            "mars" | "♂" => (144.72, "Mars - energy, action, courage"),
21564            "jupiter" | "♃" => (183.58, "Jupiter - expansion, wisdom, luck"),
21565            "saturn" | "♄" => (147.85, "Saturn - discipline, structure, time"),
21566
21567            // Chakra frequencies
21568            "root" | "muladhara" => (256.0, "Root chakra - survival, grounding (C)"),
21569            "sacral" | "svadhisthana" => (288.0, "Sacral chakra - creativity, sexuality (D)"),
21570            "solar" | "manipura" => (320.0, "Solar plexus - will, power (E)"),
21571            "heart" | "anahata" => (341.3, "Heart chakra - love, compassion (F)"),
21572            "throat" | "vishuddha" => (384.0, "Throat chakra - expression, truth (G)"),
21573            "third_eye" | "ajna" => (426.7, "Third eye - intuition, insight (A)"),
21574            "crown" | "sahasrara" => (480.0, "Crown chakra - consciousness, unity (B)"),
21575
21576            // Concert pitch standards
21577            "a440" | "iso" => (440.0, "ISO standard concert pitch (1955)"),
21578            "a432" | "verdi" => (
21579                432.0,
21580                "Verdi pitch - 'mathematically consistent with universe'",
21581            ),
21582            "a415" | "baroque" => (415.0, "Baroque pitch - period instrument standard"),
21583            "a466" | "chorton" => (466.0, "Choir pitch - high Baroque German"),
21584
21585            // Binaural/brainwave
21586            "delta" => (2.0, "Delta waves - deep sleep, healing (0.5-4 Hz)"),
21587            "theta" => (6.0, "Theta waves - meditation, creativity (4-8 Hz)"),
21588            "alpha" => (10.0, "Alpha waves - relaxation, calm focus (8-13 Hz)"),
21589            "beta" => (20.0, "Beta waves - alertness, concentration (13-30 Hz)"),
21590            "gamma" => (40.0, "Gamma waves - insight, peak performance (30-100 Hz)"),
21591
21592            _ => {
21593                return Err(RuntimeError::new(format!(
21594                    "Unknown sacred frequency: {}",
21595                    name
21596                )))
21597            }
21598        };
21599
21600        let mut result = std::collections::HashMap::new();
21601        result.insert("frequency".to_string(), Value::Float(freq));
21602        result.insert("name".to_string(), Value::String(Rc::new(name)));
21603        result.insert(
21604            "meaning".to_string(),
21605            Value::String(Rc::new(description.to_string())),
21606        );
21607
21608        Ok(Value::Map(Rc::new(RefCell::new(result))))
21609    });
21610
21611    // solfeggio - get all solfeggio frequencies
21612    define(interp, "solfeggio", Some(0), |_, _| {
21613        let frequencies = vec![
21614            (174.0, "Foundation", "Pain relief, security"),
21615            (285.0, "Quantum", "Healing tissue, safety"),
21616            (396.0, "UT", "Liberating guilt and fear"),
21617            (417.0, "RE", "Undoing situations, change"),
21618            (528.0, "MI", "Transformation, DNA repair, miracles"),
21619            (639.0, "FA", "Connecting relationships"),
21620            (741.0, "SOL", "Awakening intuition"),
21621            (852.0, "LA", "Spiritual order"),
21622            (963.0, "SI", "Divine consciousness"),
21623        ];
21624
21625        let result: Vec<Value> = frequencies
21626            .iter()
21627            .map(|(freq, name, meaning)| {
21628                let mut entry = std::collections::HashMap::new();
21629                entry.insert("frequency".to_string(), Value::Float(*freq));
21630                entry.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
21631                entry.insert(
21632                    "meaning".to_string(),
21633                    Value::String(Rc::new(meaning.to_string())),
21634                );
21635                Value::Map(Rc::new(RefCell::new(entry)))
21636            })
21637            .collect();
21638
21639        Ok(Value::Array(Rc::new(RefCell::new(result))))
21640    });
21641
21642    // chakras - get all chakra frequencies
21643    define(interp, "chakras", Some(0), |_, _| {
21644        let chakras = vec![
21645            (
21646                256.0,
21647                "Muladhara",
21648                "Root",
21649                "Red",
21650                "Survival, grounding, stability",
21651            ),
21652            (
21653                288.0,
21654                "Svadhisthana",
21655                "Sacral",
21656                "Orange",
21657                "Creativity, sexuality, emotion",
21658            ),
21659            (
21660                320.0,
21661                "Manipura",
21662                "Solar Plexus",
21663                "Yellow",
21664                "Will, power, self-esteem",
21665            ),
21666            (
21667                341.3,
21668                "Anahata",
21669                "Heart",
21670                "Green",
21671                "Love, compassion, connection",
21672            ),
21673            (
21674                384.0,
21675                "Vishuddha",
21676                "Throat",
21677                "Blue",
21678                "Expression, truth, communication",
21679            ),
21680            (
21681                426.7,
21682                "Ajna",
21683                "Third Eye",
21684                "Indigo",
21685                "Intuition, insight, wisdom",
21686            ),
21687            (
21688                480.0,
21689                "Sahasrara",
21690                "Crown",
21691                "Violet",
21692                "Consciousness, unity, transcendence",
21693            ),
21694        ];
21695
21696        let result: Vec<Value> = chakras
21697            .iter()
21698            .map(|(freq, sanskrit, english, color, meaning)| {
21699                let mut entry = std::collections::HashMap::new();
21700                entry.insert("frequency".to_string(), Value::Float(*freq));
21701                entry.insert(
21702                    "sanskrit".to_string(),
21703                    Value::String(Rc::new(sanskrit.to_string())),
21704                );
21705                entry.insert(
21706                    "english".to_string(),
21707                    Value::String(Rc::new(english.to_string())),
21708                );
21709                entry.insert(
21710                    "color".to_string(),
21711                    Value::String(Rc::new(color.to_string())),
21712                );
21713                entry.insert(
21714                    "meaning".to_string(),
21715                    Value::String(Rc::new(meaning.to_string())),
21716                );
21717                Value::Map(Rc::new(RefCell::new(entry)))
21718            })
21719            .collect();
21720
21721        Ok(Value::Array(Rc::new(RefCell::new(result))))
21722    });
21723
21724    // =========================================================================
21725    // WAVEFORM GENERATION
21726    // =========================================================================
21727
21728    // Generate waveform samples - returns array of floats [-1.0, 1.0]
21729
21730    // sine - pure sine wave ∿
21731    define(interp, "sine", Some(3), |_, args| {
21732        generate_waveform(&args, |phase| phase.sin())
21733    });
21734
21735    // square - square wave ⊓
21736    define(interp, "square", Some(3), |_, args| {
21737        generate_waveform(&args, |phase| if phase.sin() >= 0.0 { 1.0 } else { -1.0 })
21738    });
21739
21740    // sawtooth - sawtooth wave ⋀
21741    define(interp, "sawtooth", Some(3), |_, args| {
21742        generate_waveform(&args, |phase| {
21743            let normalized = (phase / std::f64::consts::TAU).fract();
21744            2.0 * normalized - 1.0
21745        })
21746    });
21747
21748    // triangle - triangle wave △
21749    define(interp, "triangle", Some(3), |_, args| {
21750        generate_waveform(&args, |phase| {
21751            let normalized = (phase / std::f64::consts::TAU).fract();
21752            if normalized < 0.5 {
21753                4.0 * normalized - 1.0
21754            } else {
21755                3.0 - 4.0 * normalized
21756            }
21757        })
21758    });
21759
21760    // noise - white noise
21761    define(interp, "noise", Some(1), |_, args| {
21762        let samples = match &args[0] {
21763            Value::Int(n) => *n as usize,
21764            _ => return Err(RuntimeError::new("noise() requires integer sample count")),
21765        };
21766
21767        let mut rng = rand::thread_rng();
21768        let result: Vec<Value> = (0..samples)
21769            .map(|_| Value::Float(rng.gen::<f64>() * 2.0 - 1.0))
21770            .collect();
21771
21772        Ok(Value::Array(Rc::new(RefCell::new(result))))
21773    });
21774
21775    // =========================================================================
21776    // CULTURAL SCALES
21777    // =========================================================================
21778
21779    // scale - get scale degrees for a cultural scale
21780    define(interp, "scale", Some(1), |_, args| {
21781        let name = match &args[0] {
21782            Value::String(s) => s.to_lowercase(),
21783            _ => return Err(RuntimeError::new("scale() requires string")),
21784        };
21785
21786        let (intervals, origin, description) = match name.as_str() {
21787            // Western modes
21788            "major" | "ionian" => (
21789                vec![0, 2, 4, 5, 7, 9, 11],
21790                "Western",
21791                "Happy, bright, resolved",
21792            ),
21793            "minor" | "aeolian" => (
21794                vec![0, 2, 3, 5, 7, 8, 10],
21795                "Western",
21796                "Sad, dark, introspective",
21797            ),
21798            "dorian" => (
21799                vec![0, 2, 3, 5, 7, 9, 10],
21800                "Western/Jazz",
21801                "Minor with bright 6th",
21802            ),
21803            "phrygian" => (
21804                vec![0, 1, 3, 5, 7, 8, 10],
21805                "Western/Flamenco",
21806                "Spanish, exotic, tense",
21807            ),
21808            "lydian" => (
21809                vec![0, 2, 4, 6, 7, 9, 11],
21810                "Western",
21811                "Dreamy, floating, ethereal",
21812            ),
21813            "mixolydian" => (vec![0, 2, 4, 5, 7, 9, 10], "Western/Blues", "Bluesy major"),
21814            "locrian" => (vec![0, 1, 3, 5, 6, 8, 10], "Western", "Unstable, dissonant"),
21815
21816            // Pentatonic
21817            "pentatonic_major" => (vec![0, 2, 4, 7, 9], "Universal", "No dissonance, universal"),
21818            "pentatonic_minor" => (vec![0, 3, 5, 7, 10], "Universal", "Blues foundation"),
21819
21820            // Japanese
21821            "hirajoshi" => (vec![0, 2, 3, 7, 8], "Japanese", "Melancholic, mysterious"),
21822            "insen" => (vec![0, 1, 5, 7, 10], "Japanese", "Dark, zen, contemplative"),
21823            "iwato" => (vec![0, 1, 5, 6, 10], "Japanese", "Most dark and dissonant"),
21824            "kumoi" => (vec![0, 2, 3, 7, 9], "Japanese", "Gentle, peaceful"),
21825            "yo" => (vec![0, 2, 5, 7, 9], "Japanese", "Bright, folk, celebratory"),
21826
21827            // Arabic maqamat
21828            "hijaz" => (
21829                vec![0, 1, 4, 5, 7, 8, 11],
21830                "Arabic",
21831                "Exotic, Middle Eastern",
21832            ),
21833            "bayati" => (
21834                vec![0, 1.5 as i32, 3, 5, 7, 8, 10],
21835                "Arabic",
21836                "Quarter-tone, soulful",
21837            ),
21838            "rast" => (
21839                vec![0, 2, 3.5 as i32, 5, 7, 9, 10.5 as i32],
21840                "Arabic",
21841                "Foundation maqam",
21842            ),
21843            "saba" => (
21844                vec![0, 1.5 as i32, 3, 4, 5, 8, 10],
21845                "Arabic",
21846                "Sad, spiritual",
21847            ),
21848
21849            // Indian ragas (approximated to 12-TET)
21850            "bhairav" => (
21851                vec![0, 1, 4, 5, 7, 8, 11],
21852                "Indian",
21853                "Morning raga, devotional",
21854            ),
21855            "yaman" | "kalyan" => (vec![0, 2, 4, 6, 7, 9, 11], "Indian", "Evening, romantic"),
21856            "bhairavi" => (
21857                vec![0, 1, 3, 5, 7, 8, 10],
21858                "Indian",
21859                "Concluding raga, devotional",
21860            ),
21861            "todi" => (vec![0, 1, 3, 6, 7, 8, 11], "Indian", "Serious, pathos"),
21862            "marwa" => (vec![0, 1, 4, 6, 7, 9, 11], "Indian", "Evening, longing"),
21863
21864            // Blues
21865            "blues" => (vec![0, 3, 5, 6, 7, 10], "American", "Blue notes, soul"),
21866
21867            // Hungarian/Eastern European
21868            "hungarian_minor" => (vec![0, 2, 3, 6, 7, 8, 11], "Hungarian", "Gypsy, dramatic"),
21869            "romanian" => (vec![0, 2, 3, 6, 7, 9, 10], "Romanian", "Folk, energetic"),
21870
21871            // Jewish
21872            "ahava_raba" | "freygish" => (
21873                vec![0, 1, 4, 5, 7, 8, 10],
21874                "Jewish/Klezmer",
21875                "Cantorial, emotional",
21876            ),
21877            "mi_sheberach" => (vec![0, 2, 3, 6, 7, 9, 10], "Jewish", "Prayer mode"),
21878
21879            // Chinese
21880            "gong" => (vec![0, 2, 4, 7, 9], "Chinese", "Palace mode, major-like"),
21881            "shang" => (vec![0, 2, 5, 7, 9], "Chinese", "Merchant mode"),
21882            "jue" => (vec![0, 3, 5, 7, 10], "Chinese", "Angle mode"),
21883            "zhi" => (vec![0, 2, 5, 7, 10], "Chinese", "Emblem mode"),
21884            "yu" => (vec![0, 3, 5, 8, 10], "Chinese", "Wings mode, minor-like"),
21885
21886            // Indonesian
21887            "pelog" => (
21888                vec![0, 1, 3, 7, 8],
21889                "Javanese",
21890                "7-note unequal temperament",
21891            ),
21892            "slendro" => (vec![0, 2, 5, 7, 9], "Javanese", "5-note roughly equal"),
21893
21894            // Other
21895            "whole_tone" => (
21896                vec![0, 2, 4, 6, 8, 10],
21897                "Impressionist",
21898                "Dreamlike, no resolution",
21899            ),
21900            "chromatic" => (
21901                vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
21902                "Western",
21903                "All 12 notes",
21904            ),
21905            "diminished" => (vec![0, 2, 3, 5, 6, 8, 9, 11], "Jazz", "Symmetric, tense"),
21906            "augmented" => (vec![0, 3, 4, 7, 8, 11], "Jazz", "Symmetric, floating"),
21907
21908            _ => return Err(RuntimeError::new(format!("Unknown scale: {}", name))),
21909        };
21910
21911        let mut result = std::collections::HashMap::new();
21912        let intervals_values: Vec<Value> =
21913            intervals.iter().map(|&i| Value::Int(i as i64)).collect();
21914        result.insert(
21915            "intervals".to_string(),
21916            Value::Array(Rc::new(RefCell::new(intervals_values))),
21917        );
21918        result.insert(
21919            "origin".to_string(),
21920            Value::String(Rc::new(origin.to_string())),
21921        );
21922        result.insert(
21923            "character".to_string(),
21924            Value::String(Rc::new(description.to_string())),
21925        );
21926        result.insert("name".to_string(), Value::String(Rc::new(name)));
21927
21928        Ok(Value::Map(Rc::new(RefCell::new(result))))
21929    });
21930
21931    // list_scales - list all available scales grouped by culture
21932    define(interp, "list_scales", Some(0), |_, _| {
21933        let mut cultures = std::collections::HashMap::new();
21934
21935        cultures.insert(
21936            "western".to_string(),
21937            Value::Array(Rc::new(RefCell::new(vec![
21938                Value::String(Rc::new("major".to_string())),
21939                Value::String(Rc::new("minor".to_string())),
21940                Value::String(Rc::new("dorian".to_string())),
21941                Value::String(Rc::new("phrygian".to_string())),
21942                Value::String(Rc::new("lydian".to_string())),
21943                Value::String(Rc::new("mixolydian".to_string())),
21944                Value::String(Rc::new("locrian".to_string())),
21945            ]))),
21946        );
21947
21948        cultures.insert(
21949            "japanese".to_string(),
21950            Value::Array(Rc::new(RefCell::new(vec![
21951                Value::String(Rc::new("hirajoshi".to_string())),
21952                Value::String(Rc::new("insen".to_string())),
21953                Value::String(Rc::new("iwato".to_string())),
21954                Value::String(Rc::new("kumoi".to_string())),
21955                Value::String(Rc::new("yo".to_string())),
21956            ]))),
21957        );
21958
21959        cultures.insert(
21960            "arabic".to_string(),
21961            Value::Array(Rc::new(RefCell::new(vec![
21962                Value::String(Rc::new("hijaz".to_string())),
21963                Value::String(Rc::new("bayati".to_string())),
21964                Value::String(Rc::new("rast".to_string())),
21965                Value::String(Rc::new("saba".to_string())),
21966            ]))),
21967        );
21968
21969        cultures.insert(
21970            "indian".to_string(),
21971            Value::Array(Rc::new(RefCell::new(vec![
21972                Value::String(Rc::new("bhairav".to_string())),
21973                Value::String(Rc::new("yaman".to_string())),
21974                Value::String(Rc::new("bhairavi".to_string())),
21975                Value::String(Rc::new("todi".to_string())),
21976                Value::String(Rc::new("marwa".to_string())),
21977            ]))),
21978        );
21979
21980        cultures.insert(
21981            "chinese".to_string(),
21982            Value::Array(Rc::new(RefCell::new(vec![
21983                Value::String(Rc::new("gong".to_string())),
21984                Value::String(Rc::new("shang".to_string())),
21985                Value::String(Rc::new("jue".to_string())),
21986                Value::String(Rc::new("zhi".to_string())),
21987                Value::String(Rc::new("yu".to_string())),
21988            ]))),
21989        );
21990
21991        cultures.insert(
21992            "jewish".to_string(),
21993            Value::Array(Rc::new(RefCell::new(vec![
21994                Value::String(Rc::new("ahava_raba".to_string())),
21995                Value::String(Rc::new("mi_sheberach".to_string())),
21996            ]))),
21997        );
21998
21999        cultures.insert(
22000            "indonesian".to_string(),
22001            Value::Array(Rc::new(RefCell::new(vec![
22002                Value::String(Rc::new("pelog".to_string())),
22003                Value::String(Rc::new("slendro".to_string())),
22004            ]))),
22005        );
22006
22007        Ok(Value::Map(Rc::new(RefCell::new(cultures))))
22008    });
22009
22010    // =========================================================================
22011    // INTERVALS AND HARMONY
22012    // =========================================================================
22013
22014    // interval_ratio - get the frequency ratio for an interval
22015    define(interp, "interval_ratio", Some(2), |_, args| {
22016        let semitones = match &args[0] {
22017            Value::Int(n) => *n as f64,
22018            Value::Float(f) => *f,
22019            _ => return Err(RuntimeError::new("interval_ratio() requires number")),
22020        };
22021
22022        let tuning = match &args[1] {
22023            Value::String(s) => s.to_lowercase(),
22024            _ => return Err(RuntimeError::new("interval_ratio() requires tuning system")),
22025        };
22026
22027        let ratio = match tuning.as_str() {
22028            "12tet" | "equal" => 2.0_f64.powf(semitones / 12.0),
22029            "just" => just_intonation_ratio(semitones as i32),
22030            "pythagorean" => pythagorean_ratio(semitones as i32),
22031            _ => 2.0_f64.powf(semitones / 12.0),
22032        };
22033
22034        Ok(Value::Float(ratio))
22035    });
22036
22037    // cents_between - calculate cents between two frequencies
22038    define(interp, "cents_between", Some(2), |_, args| {
22039        let f1 = match &args[0] {
22040            Value::Float(f) => *f,
22041            Value::Int(i) => *i as f64,
22042            _ => return Err(RuntimeError::new("cents_between() requires numbers")),
22043        };
22044        let f2 = match &args[1] {
22045            Value::Float(f) => *f,
22046            Value::Int(i) => *i as f64,
22047            _ => return Err(RuntimeError::new("cents_between() requires numbers")),
22048        };
22049
22050        let cents = 1200.0 * (f2 / f1).log2();
22051        Ok(Value::Float(cents))
22052    });
22053
22054    // harmonic_series - generate harmonic series from fundamental
22055    define(interp, "harmonic_series", Some(2), |_, args| {
22056        let fundamental = match &args[0] {
22057            Value::Float(f) => *f,
22058            Value::Int(i) => *i as f64,
22059            _ => return Err(RuntimeError::new("harmonic_series() requires frequency")),
22060        };
22061        let count = match &args[1] {
22062            Value::Int(n) => *n as usize,
22063            _ => return Err(RuntimeError::new("harmonic_series() requires count")),
22064        };
22065
22066        let harmonics: Vec<Value> = (1..=count)
22067            .map(|n| {
22068                let mut entry = std::collections::HashMap::new();
22069                entry.insert("harmonic".to_string(), Value::Int(n as i64));
22070                entry.insert(
22071                    "frequency".to_string(),
22072                    Value::Float(fundamental * n as f64),
22073                );
22074                entry.insert(
22075                    "cents_from_root".to_string(),
22076                    Value::Float(1200.0 * (n as f64).log2()),
22077                );
22078                Value::Map(Rc::new(RefCell::new(entry)))
22079            })
22080            .collect();
22081
22082        Ok(Value::Array(Rc::new(RefCell::new(harmonics))))
22083    });
22084
22085    // =========================================================================
22086    // AUDIO INFO
22087    // =========================================================================
22088
22089    define(interp, "audio_info", Some(0), |_, _| {
22090        let mut info = std::collections::HashMap::new();
22091
22092        info.insert(
22093            "tuning_systems".to_string(),
22094            Value::Array(Rc::new(RefCell::new(vec![
22095                Value::String(Rc::new(
22096                    "12tet, 24tet, just, pythagorean, meantone".to_string(),
22097                )),
22098                Value::String(Rc::new(
22099                    "53tet, 22shruti, pelog, slendro, bohlen_pierce".to_string(),
22100                )),
22101            ]))),
22102        );
22103
22104        info.insert(
22105            "waveforms".to_string(),
22106            Value::Array(Rc::new(RefCell::new(vec![
22107                Value::String(Rc::new("sine (∿)".to_string())),
22108                Value::String(Rc::new("square (⊓)".to_string())),
22109                Value::String(Rc::new("sawtooth (⋀)".to_string())),
22110                Value::String(Rc::new("triangle (△)".to_string())),
22111                Value::String(Rc::new("noise".to_string())),
22112            ]))),
22113        );
22114
22115        info.insert(
22116            "sacred_frequencies".to_string(),
22117            Value::Array(Rc::new(RefCell::new(vec![
22118                Value::String(Rc::new("om, solfeggio, chakras, planets".to_string())),
22119                Value::String(Rc::new(
22120                    "schumann, brainwaves (delta/theta/alpha/beta/gamma)".to_string(),
22121                )),
22122            ]))),
22123        );
22124
22125        info.insert(
22126            "scale_cultures".to_string(),
22127            Value::Array(Rc::new(RefCell::new(vec![
22128                Value::String(Rc::new("western, japanese, arabic, indian".to_string())),
22129                Value::String(Rc::new("chinese, jewish, indonesian".to_string())),
22130            ]))),
22131        );
22132
22133        Ok(Value::Map(Rc::new(RefCell::new(info))))
22134    });
22135}
22136
22137// Helper functions for tuning systems
22138
22139fn parse_note_name(s: &str) -> Result<f64, RuntimeError> {
22140    let s = s.trim().to_uppercase();
22141    let (note, octave_offset) = if s.ends_with(|c: char| c.is_ascii_digit()) {
22142        let octave: i32 = s.chars().last().unwrap().to_digit(10).unwrap() as i32;
22143        let note_part = &s[..s.len() - 1];
22144        (note_part, (octave - 4) * 12) // Octave 4 = MIDI 60 area
22145    } else {
22146        (&s[..], 0)
22147    };
22148
22149    let semitone = match note {
22150        "C" => 0,
22151        "C#" | "DB" => 1,
22152        "D" => 2,
22153        "D#" | "EB" => 3,
22154        "E" => 4,
22155        "F" => 5,
22156        "F#" | "GB" => 6,
22157        "G" => 7,
22158        "G#" | "AB" => 8,
22159        "A" => 9,
22160        "A#" | "BB" => 10,
22161        "B" => 11,
22162        _ => return Err(RuntimeError::new(format!("Unknown note: {}", s))),
22163    };
22164
22165    Ok(69.0 + semitone as f64 - 9.0 + octave_offset as f64) // A4 = 69
22166}
22167
22168fn just_intonation_ratio(semitones: i32) -> f64 {
22169    // Classic 5-limit just intonation ratios
22170    match semitones.rem_euclid(12) {
22171        0 => 1.0,         // Unison
22172        1 => 16.0 / 15.0, // Minor second
22173        2 => 9.0 / 8.0,   // Major second
22174        3 => 6.0 / 5.0,   // Minor third
22175        4 => 5.0 / 4.0,   // Major third
22176        5 => 4.0 / 3.0,   // Perfect fourth
22177        6 => 45.0 / 32.0, // Tritone
22178        7 => 3.0 / 2.0,   // Perfect fifth
22179        8 => 8.0 / 5.0,   // Minor sixth
22180        9 => 5.0 / 3.0,   // Major sixth
22181        10 => 9.0 / 5.0,  // Minor seventh
22182        11 => 15.0 / 8.0, // Major seventh
22183        _ => 1.0,
22184    }
22185}
22186
22187fn pythagorean_ratio(semitones: i32) -> f64 {
22188    // Pythagorean tuning (pure fifths, 3:2 ratio)
22189    match semitones.rem_euclid(12) {
22190        0 => 1.0,
22191        1 => 256.0 / 243.0,
22192        2 => 9.0 / 8.0,
22193        3 => 32.0 / 27.0,
22194        4 => 81.0 / 64.0,
22195        5 => 4.0 / 3.0,
22196        6 => 729.0 / 512.0,
22197        7 => 3.0 / 2.0,
22198        8 => 128.0 / 81.0,
22199        9 => 27.0 / 16.0,
22200        10 => 16.0 / 9.0,
22201        11 => 243.0 / 128.0,
22202        _ => 1.0,
22203    }
22204}
22205
22206fn meantone_ratio(semitones: i32) -> f64 {
22207    // Quarter-comma meantone - fifths narrowed by 1/4 syntonic comma
22208    let fifth = 5.0_f64.powf(0.25); // Pure major third, tempered fifth
22209    match semitones.rem_euclid(12) {
22210        0 => 1.0,
22211        1 => 8.0 / (fifth.powi(5)),
22212        2 => fifth.powi(2) / 2.0,
22213        3 => 4.0 / (fifth.powi(3)),
22214        4 => fifth.powi(4) / 4.0,
22215        5 => 2.0 / fifth,
22216        6 => fifth.powi(6) / 8.0,
22217        7 => fifth,
22218        8 => 8.0 / (fifth.powi(4)),
22219        9 => fifth.powi(3) / 2.0,
22220        10 => 4.0 / (fifth.powi(2)),
22221        11 => fifth.powi(5) / 4.0,
22222        _ => 1.0,
22223    }
22224}
22225
22226fn shruti_ratio(shruti: i32) -> f64 {
22227    // 22 shruti ratios (traditional Indian)
22228    let ratios = [
22229        1.0,
22230        256.0 / 243.0,
22231        16.0 / 15.0,
22232        10.0 / 9.0,
22233        9.0 / 8.0,
22234        32.0 / 27.0,
22235        6.0 / 5.0,
22236        5.0 / 4.0,
22237        81.0 / 64.0,
22238        4.0 / 3.0,
22239        27.0 / 20.0,
22240        45.0 / 32.0,
22241        729.0 / 512.0,
22242        3.0 / 2.0,
22243        128.0 / 81.0,
22244        8.0 / 5.0,
22245        5.0 / 3.0,
22246        27.0 / 16.0,
22247        16.0 / 9.0,
22248        9.0 / 5.0,
22249        15.0 / 8.0,
22250        243.0 / 128.0,
22251    ];
22252    ratios[shruti.rem_euclid(22) as usize]
22253}
22254
22255fn pelog_ratio(degree: i32) -> f64 {
22256    // Approximate pelog ratios (varies by gamelan)
22257    let ratios = [1.0, 1.12, 1.26, 1.5, 1.68, 1.89, 2.12];
22258    ratios[degree.rem_euclid(7) as usize]
22259}
22260
22261fn slendro_ratio(degree: i32) -> f64 {
22262    // Approximate slendro ratios (roughly equal ~240 cents)
22263    let ratios = [1.0, 1.148, 1.318, 1.516, 1.741];
22264    ratios[degree.rem_euclid(5) as usize]
22265}
22266
22267fn generate_waveform(args: &[Value], wave_fn: fn(f64) -> f64) -> Result<Value, RuntimeError> {
22268    let freq = match &args[0] {
22269        Value::Float(f) => *f,
22270        Value::Int(i) => *i as f64,
22271        _ => return Err(RuntimeError::new("Waveform requires frequency")),
22272    };
22273    let sample_rate = match &args[1] {
22274        Value::Float(f) => *f as usize,
22275        Value::Int(i) => *i as usize,
22276        _ => return Err(RuntimeError::new("Waveform requires sample rate")),
22277    };
22278    let duration = match &args[2] {
22279        Value::Float(f) => *f,
22280        Value::Int(i) => *i as f64,
22281        _ => return Err(RuntimeError::new("Waveform requires duration")),
22282    };
22283
22284    let num_samples = (sample_rate as f64 * duration) as usize;
22285    let samples: Vec<Value> = (0..num_samples)
22286        .map(|i| {
22287            let t = i as f64 / sample_rate as f64;
22288            let phase = 2.0 * std::f64::consts::PI * freq * t;
22289            Value::Float(wave_fn(phase))
22290        })
22291        .collect();
22292
22293    Ok(Value::Array(Rc::new(RefCell::new(samples))))
22294}
22295
22296// ============================================================================
22297// SPIRITUALITY: Divination, sacred geometry, gematria, archetypes
22298// ============================================================================
22299//
22300// This module treats computation as potentially sacred - numbers have meaning,
22301// patterns have significance, and randomness can be oracle.
22302//
22303// I Ching Trigrams:
22304//   ☰ Heaven (乾)  ☱ Lake (兌)   ☲ Fire (離)   ☳ Thunder (震)
22305//   ☴ Wind (巽)    ☵ Water (坎)  ☶ Mountain (艮) ☷ Earth (坤)
22306//
22307// Sacred Geometry:
22308//   φ = 1.618033... (Golden Ratio)
22309//   √φ, φ², 1/φ (related constants)
22310//   Fibonacci sequence
22311//   Platonic solid relationships
22312//
22313// Gematria Systems:
22314//   Hebrew (Kabbalah), Greek (Isopsephy), Arabic (Abjad)
22315//   Each letter is a number; words have numerical souls
22316
22317fn register_spirituality(interp: &mut Interpreter) {
22318    // =========================================================================
22319    // I CHING - Book of Changes
22320    // =========================================================================
22321
22322    // The 8 trigrams
22323    const TRIGRAMS: [(&str, &str, &str, &str, &str); 8] = [
22324        (
22325            "☰",
22326            "乾",
22327            "Heaven",
22328            "Creative",
22329            "strong, initiating, persisting",
22330        ),
22331        (
22332            "☱",
22333            "兌",
22334            "Lake",
22335            "Joyous",
22336            "pleasure, satisfaction, openness",
22337        ),
22338        (
22339            "☲",
22340            "離",
22341            "Fire",
22342            "Clinging",
22343            "clarity, awareness, dependence",
22344        ),
22345        (
22346            "☳",
22347            "震",
22348            "Thunder",
22349            "Arousing",
22350            "movement, initiative, action",
22351        ),
22352        (
22353            "☴",
22354            "巽",
22355            "Wind",
22356            "Gentle",
22357            "penetrating, following, flexible",
22358        ),
22359        ("☵", "坎", "Water", "Abysmal", "danger, flowing, depth"),
22360        (
22361            "☶",
22362            "艮",
22363            "Mountain",
22364            "Keeping Still",
22365            "stopping, resting, meditation",
22366        ),
22367        (
22368            "☷",
22369            "坤",
22370            "Earth",
22371            "Receptive",
22372            "yielding, nurturing, devoted",
22373        ),
22374    ];
22375
22376    // trigram - get trigram information
22377    define(interp, "trigram", Some(1), |_, args| {
22378        let input = match &args[0] {
22379            Value::Int(n) => (*n as usize).min(7),
22380            Value::String(s) => match s.as_str() {
22381                "☰" | "heaven" | "qian" | "乾" => 0,
22382                "☱" | "lake" | "dui" | "兌" => 1,
22383                "☲" | "fire" | "li" | "離" => 2,
22384                "☳" | "thunder" | "zhen" | "震" => 3,
22385                "☴" | "wind" | "xun" | "巽" => 4,
22386                "☵" | "water" | "kan" | "坎" => 5,
22387                "☶" | "mountain" | "gen" | "艮" => 6,
22388                "☷" | "earth" | "kun" | "坤" => 7,
22389                _ => return Err(RuntimeError::new(format!("Unknown trigram: {}", s))),
22390            },
22391            _ => return Err(RuntimeError::new("trigram() requires number or name")),
22392        };
22393
22394        let (symbol, chinese, english, name, meaning) = TRIGRAMS[input];
22395
22396        let mut result = std::collections::HashMap::new();
22397        result.insert("number".to_string(), Value::Int(input as i64));
22398        result.insert(
22399            "symbol".to_string(),
22400            Value::String(Rc::new(symbol.to_string())),
22401        );
22402        result.insert(
22403            "chinese".to_string(),
22404            Value::String(Rc::new(chinese.to_string())),
22405        );
22406        result.insert(
22407            "english".to_string(),
22408            Value::String(Rc::new(english.to_string())),
22409        );
22410        result.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
22411        result.insert(
22412            "meaning".to_string(),
22413            Value::String(Rc::new(meaning.to_string())),
22414        );
22415
22416        // Binary representation (yang=1, yin=0)
22417        let binary = match input {
22418            0 => "111", // ☰
22419            1 => "110", // ☱
22420            2 => "101", // ☲
22421            3 => "100", // ☳
22422            4 => "011", // ☴
22423            5 => "010", // ☵
22424            6 => "001", // ☶
22425            7 => "000", // ☷
22426            _ => "000",
22427        };
22428        result.insert(
22429            "binary".to_string(),
22430            Value::String(Rc::new(binary.to_string())),
22431        );
22432
22433        Ok(Value::Map(Rc::new(RefCell::new(result))))
22434    });
22435
22436    // hexagram - get one of 64 I Ching hexagrams
22437    define(interp, "hexagram", Some(1), |_, args| {
22438        let num = match &args[0] {
22439            Value::Int(n) => ((*n - 1) as usize).min(63),
22440            _ => return Err(RuntimeError::new("hexagram() requires number 1-64")),
22441        };
22442
22443        let hex = &HEXAGRAMS[num];
22444
22445        let mut result = std::collections::HashMap::new();
22446        result.insert("number".to_string(), Value::Int((num + 1) as i64));
22447        result.insert(
22448            "chinese".to_string(),
22449            Value::String(Rc::new(hex.0.to_string())),
22450        );
22451        result.insert(
22452            "pinyin".to_string(),
22453            Value::String(Rc::new(hex.1.to_string())),
22454        );
22455        result.insert(
22456            "english".to_string(),
22457            Value::String(Rc::new(hex.2.to_string())),
22458        );
22459        result.insert(
22460            "judgment".to_string(),
22461            Value::String(Rc::new(hex.3.to_string())),
22462        );
22463        result.insert(
22464            "upper_trigram".to_string(),
22465            Value::String(Rc::new(hex.4.to_string())),
22466        );
22467        result.insert(
22468            "lower_trigram".to_string(),
22469            Value::String(Rc::new(hex.5.to_string())),
22470        );
22471
22472        Ok(Value::Map(Rc::new(RefCell::new(result))))
22473    });
22474
22475    // cast_iching - divine using I Ching (uses randomness as oracle)
22476    define(interp, "cast_iching", Some(0), |_, _| {
22477        let mut rng = rand::thread_rng();
22478
22479        // Traditional yarrow stalk method produces numbers 6,7,8,9
22480        // 6 = old yin (changing), 7 = young yang, 8 = young yin, 9 = old yang (changing)
22481        let mut lines = Vec::new();
22482        let mut hexagram_num = 0u8;
22483        let mut changing_lines = Vec::new();
22484
22485        for i in 0..6 {
22486            // Simulate yarrow stalk probabilities
22487            let r: f64 = rng.gen();
22488            let line = if r < 0.0625 {
22489                6
22490            }
22491            // 1/16 - old yin
22492            else if r < 0.3125 {
22493                7
22494            }
22495            // 5/16 - young yang
22496            else if r < 0.5625 {
22497                8
22498            }
22499            // 5/16 - young yin
22500            else {
22501                9
22502            }; // 5/16 - old yang
22503
22504            let is_yang = line == 7 || line == 9;
22505            if is_yang {
22506                hexagram_num |= 1 << i;
22507            }
22508
22509            if line == 6 || line == 9 {
22510                changing_lines.push(i + 1);
22511            }
22512
22513            lines.push(Value::Int(line));
22514        }
22515
22516        // Convert to King Wen sequence
22517        let king_wen_num = binary_to_king_wen(hexagram_num) + 1;
22518        let hex = &HEXAGRAMS[(king_wen_num - 1) as usize];
22519
22520        let mut result = std::collections::HashMap::new();
22521        result.insert("hexagram".to_string(), Value::Int(king_wen_num as i64));
22522        result.insert(
22523            "chinese".to_string(),
22524            Value::String(Rc::new(hex.0.to_string())),
22525        );
22526        result.insert(
22527            "english".to_string(),
22528            Value::String(Rc::new(hex.2.to_string())),
22529        );
22530        result.insert(
22531            "judgment".to_string(),
22532            Value::String(Rc::new(hex.3.to_string())),
22533        );
22534        result.insert(
22535            "lines".to_string(),
22536            Value::Array(Rc::new(RefCell::new(lines))),
22537        );
22538
22539        let changing: Vec<Value> = changing_lines.iter().map(|&n| Value::Int(n)).collect();
22540        result.insert(
22541            "changing_lines".to_string(),
22542            Value::Array(Rc::new(RefCell::new(changing))),
22543        );
22544
22545        // Calculate resulting hexagram if there are changing lines
22546        if !changing_lines.is_empty() {
22547            let mut result_hex = hexagram_num;
22548            for &line in &changing_lines {
22549                result_hex ^= 1 << (line - 1); // Flip the changing lines
22550            }
22551            let result_king_wen = binary_to_king_wen(result_hex) + 1;
22552            result.insert(
22553                "transforms_to".to_string(),
22554                Value::Int(result_king_wen as i64),
22555            );
22556        }
22557
22558        Ok(Value::Map(Rc::new(RefCell::new(result))))
22559    });
22560
22561    // =========================================================================
22562    // SACRED GEOMETRY
22563    // =========================================================================
22564
22565    // phi - Golden Ratio
22566    define(interp, "phi", Some(0), |_, _| {
22567        Ok(Value::Float((1.0 + 5.0_f64.sqrt()) / 2.0))
22568    });
22569
22570    // sacred_ratio - get various sacred ratios
22571    define(interp, "sacred_ratio", Some(1), |_, args| {
22572        let name = match &args[0] {
22573            Value::String(s) => s.to_lowercase(),
22574            _ => return Err(RuntimeError::new("sacred_ratio() requires string")),
22575        };
22576
22577        let (value, symbol, meaning) = match name.as_str() {
22578            "phi" | "φ" | "golden" => (
22579                (1.0 + 5.0_f64.sqrt()) / 2.0,
22580                "φ",
22581                "Golden Ratio - divine proportion found in nature, art, architecture",
22582            ),
22583            "phi_conjugate" | "1/phi" => (
22584                2.0 / (1.0 + 5.0_f64.sqrt()),
22585                "1/φ",
22586                "Golden Ratio conjugate - φ - 1 = 1/φ",
22587            ),
22588            "phi_squared" | "phi2" => (
22589                ((1.0 + 5.0_f64.sqrt()) / 2.0).powi(2),
22590                "φ²",
22591                "Golden Ratio squared - φ + 1 = φ²",
22592            ),
22593            "sqrt_phi" => (
22594                ((1.0 + 5.0_f64.sqrt()) / 2.0).sqrt(),
22595                "√φ",
22596                "Square root of Golden Ratio",
22597            ),
22598            "pi" | "π" => (
22599                std::f64::consts::PI,
22600                "π",
22601                "Circle constant - circumference/diameter, transcendental",
22602            ),
22603            "tau" | "τ" => (
22604                std::f64::consts::TAU,
22605                "τ",
22606                "Full circle constant - 2π, one complete revolution",
22607            ),
22608            "e" | "euler" => (
22609                std::f64::consts::E,
22610                "e",
22611                "Euler's number - natural growth, compound interest",
22612            ),
22613            "sqrt2" | "√2" | "pythagoras" => (
22614                std::f64::consts::SQRT_2,
22615                "√2",
22616                "Pythagorean constant - diagonal of unit square",
22617            ),
22618            "sqrt3" | "√3" | "vesica" => (
22619                3.0_f64.sqrt(),
22620                "√3",
22621                "Vesica Piscis ratio - sacred geometry foundation",
22622            ),
22623            "sqrt5" | "√5" => (
22624                5.0_f64.sqrt(),
22625                "√5",
22626                "Related to Golden Ratio: φ = (1 + √5) / 2",
22627            ),
22628            "silver" | "δs" => (
22629                1.0 + 2.0_f64.sqrt(),
22630                "δs",
22631                "Silver Ratio - related to octagon",
22632            ),
22633            "plastic" | "ρ" => (
22634                1.324717957244746,
22635                "ρ",
22636                "Plastic Number - smallest Pisot number",
22637            ),
22638            "feigenbaum" | "δ" => (
22639                4.669201609102990,
22640                "δ",
22641                "Feigenbaum constant - chaos theory, period doubling",
22642            ),
22643            _ => return Err(RuntimeError::new(format!("Unknown sacred ratio: {}", name))),
22644        };
22645
22646        let mut result = std::collections::HashMap::new();
22647        result.insert("value".to_string(), Value::Float(value));
22648        result.insert(
22649            "symbol".to_string(),
22650            Value::String(Rc::new(symbol.to_string())),
22651        );
22652        result.insert(
22653            "meaning".to_string(),
22654            Value::String(Rc::new(meaning.to_string())),
22655        );
22656
22657        Ok(Value::Map(Rc::new(RefCell::new(result))))
22658    });
22659
22660    // fibonacci - generate Fibonacci sequence
22661    define(interp, "fibonacci", Some(1), |_, args| {
22662        let count = match &args[0] {
22663            Value::Int(n) => *n as usize,
22664            _ => return Err(RuntimeError::new("fibonacci() requires count")),
22665        };
22666
22667        let mut seq = Vec::with_capacity(count);
22668        let (mut a, mut b) = (0i64, 1i64);
22669
22670        for _ in 0..count {
22671            seq.push(Value::Int(a));
22672            let next = a.saturating_add(b);
22673            a = b;
22674            b = next;
22675        }
22676
22677        Ok(Value::Array(Rc::new(RefCell::new(seq))))
22678    });
22679
22680    // is_fibonacci - check if a number is in the Fibonacci sequence
22681    define(interp, "is_fibonacci", Some(1), |_, args| {
22682        let n = match &args[0] {
22683            Value::Int(n) => *n,
22684            _ => return Err(RuntimeError::new("is_fibonacci() requires integer")),
22685        };
22686
22687        // A number is Fibonacci iff one of (5n² + 4) or (5n² - 4) is a perfect square
22688        fn is_perfect_square(n: i64) -> bool {
22689            if n < 0 {
22690                return false;
22691            }
22692            let root = (n as f64).sqrt() as i64;
22693            root * root == n
22694        }
22695
22696        let n_sq = n.saturating_mul(n);
22697        let test1 = 5i64.saturating_mul(n_sq).saturating_add(4);
22698        let test2 = 5i64.saturating_mul(n_sq).saturating_sub(4);
22699
22700        Ok(Value::Bool(
22701            is_perfect_square(test1) || is_perfect_square(test2),
22702        ))
22703    });
22704
22705    // platonic_solid - get information about Platonic solids
22706    define(interp, "platonic_solid", Some(1), |_, args| {
22707        let name = match &args[0] {
22708            Value::String(s) => s.to_lowercase(),
22709            _ => return Err(RuntimeError::new("platonic_solid() requires string")),
22710        };
22711
22712        let (faces, vertices, edges, face_shape, element, meaning) = match name.as_str() {
22713            "tetrahedron" | "fire" => (
22714                4,
22715                4,
22716                6,
22717                "triangle",
22718                "Fire",
22719                "Sharpness, heat, transformation",
22720            ),
22721            "cube" | "hexahedron" | "earth" => (
22722                6,
22723                8,
22724                12,
22725                "square",
22726                "Earth",
22727                "Stability, grounding, material",
22728            ),
22729            "octahedron" | "air" => (
22730                8,
22731                6,
22732                12,
22733                "triangle",
22734                "Air",
22735                "Balance, intellect, communication",
22736            ),
22737            "dodecahedron" | "aether" | "spirit" => (
22738                12,
22739                20,
22740                30,
22741                "pentagon",
22742                "Aether/Spirit",
22743                "The cosmos, divine thought",
22744            ),
22745            "icosahedron" | "water" => (
22746                20,
22747                12,
22748                30,
22749                "triangle",
22750                "Water",
22751                "Flow, emotion, adaptability",
22752            ),
22753            _ => {
22754                return Err(RuntimeError::new(format!(
22755                    "Unknown Platonic solid: {}",
22756                    name
22757                )))
22758            }
22759        };
22760
22761        let mut result = std::collections::HashMap::new();
22762        result.insert("name".to_string(), Value::String(Rc::new(name)));
22763        result.insert("faces".to_string(), Value::Int(faces));
22764        result.insert("vertices".to_string(), Value::Int(vertices));
22765        result.insert("edges".to_string(), Value::Int(edges));
22766        result.insert(
22767            "face_shape".to_string(),
22768            Value::String(Rc::new(face_shape.to_string())),
22769        );
22770        result.insert(
22771            "element".to_string(),
22772            Value::String(Rc::new(element.to_string())),
22773        );
22774        result.insert(
22775            "meaning".to_string(),
22776            Value::String(Rc::new(meaning.to_string())),
22777        );
22778
22779        // Euler's formula: V - E + F = 2
22780        result.insert("euler_characteristic".to_string(), Value::Int(2));
22781
22782        Ok(Value::Map(Rc::new(RefCell::new(result))))
22783    });
22784
22785    // =========================================================================
22786    // GEMATRIA - Letter-Number Correspondences
22787    // =========================================================================
22788
22789    // gematria - calculate numerical value of text
22790    define(interp, "gematria", Some(2), |_, args| {
22791        let text = match &args[0] {
22792            Value::String(s) => s.to_string(),
22793            _ => return Err(RuntimeError::new("gematria() requires string")),
22794        };
22795
22796        let system = match &args[1] {
22797            Value::String(s) => s.to_lowercase(),
22798            _ => return Err(RuntimeError::new("gematria() requires system name")),
22799        };
22800
22801        let total: i64 = match system.as_str() {
22802            "hebrew" | "kabbalah" => text.chars().map(|c| hebrew_gematria(c)).sum(),
22803            "greek" | "isopsephy" => text.chars().map(|c| greek_isopsephy(c)).sum(),
22804            "arabic" | "abjad" => text.chars().map(|c| arabic_abjad(c)).sum(),
22805            "english" | "simple" => {
22806                // Simple English: A=1, B=2, ... Z=26
22807                text.to_uppercase()
22808                    .chars()
22809                    .filter_map(|c| {
22810                        if c.is_ascii_alphabetic() {
22811                            Some((c as i64) - ('A' as i64) + 1)
22812                        } else {
22813                            None
22814                        }
22815                    })
22816                    .sum()
22817            }
22818            "english_ordinal" => {
22819                // Same as simple
22820                text.to_uppercase()
22821                    .chars()
22822                    .filter_map(|c| {
22823                        if c.is_ascii_alphabetic() {
22824                            Some((c as i64) - ('A' as i64) + 1)
22825                        } else {
22826                            None
22827                        }
22828                    })
22829                    .sum()
22830            }
22831            "english_reduction" => {
22832                // Reduce each letter: A=1, B=2, ... I=9, J=1, K=2, etc.
22833                text.to_uppercase()
22834                    .chars()
22835                    .filter_map(|c| {
22836                        if c.is_ascii_alphabetic() {
22837                            let val = ((c as i64) - ('A' as i64)) % 9 + 1;
22838                            Some(val)
22839                        } else {
22840                            None
22841                        }
22842                    })
22843                    .sum()
22844            }
22845            _ => {
22846                return Err(RuntimeError::new(format!(
22847                    "Unknown gematria system: {}",
22848                    system
22849                )))
22850            }
22851        };
22852
22853        let mut result = std::collections::HashMap::new();
22854        result.insert("text".to_string(), Value::String(Rc::new(text)));
22855        result.insert("system".to_string(), Value::String(Rc::new(system)));
22856        result.insert("value".to_string(), Value::Int(total));
22857
22858        // Digital root (reduce to single digit)
22859        let mut digital_root = total;
22860        while digital_root > 9 {
22861            digital_root = digital_root
22862                .to_string()
22863                .chars()
22864                .filter_map(|c| c.to_digit(10))
22865                .map(|d| d as i64)
22866                .sum();
22867        }
22868        result.insert("digital_root".to_string(), Value::Int(digital_root));
22869
22870        Ok(Value::Map(Rc::new(RefCell::new(result))))
22871    });
22872
22873    // gematria_match - find words with same gematria value
22874    define(interp, "gematria_match", Some(2), |_, args| {
22875        let value = match &args[0] {
22876            Value::Int(n) => *n,
22877            _ => return Err(RuntimeError::new("gematria_match() requires integer value")),
22878        };
22879
22880        let system = match &args[1] {
22881            Value::String(s) => s.to_lowercase(),
22882            _ => return Err(RuntimeError::new("gematria_match() requires system name")),
22883        };
22884
22885        // Return known significant matches for common values
22886        let matches = match (value, system.as_str()) {
22887            (26, "hebrew") => vec!["יהוה (YHWH - Tetragrammaton)"],
22888            (18, "hebrew") => vec!["חי (Chai - Life)"],
22889            (86, "hebrew") => vec!["אלהים (Elohim - God)"],
22890            (72, "hebrew") => vec!["חסד (Chesed - Loving-kindness)"],
22891            (93, "english") => vec!["Love", "Will", "Thelema"],
22892            (666, "greek") => vec!["Nero Caesar (in Hebrew letters)"],
22893            (888, "greek") => vec!["Ἰησοῦς (Jesus)"],
22894            _ => vec![],
22895        };
22896
22897        let match_values: Vec<Value> = matches
22898            .iter()
22899            .map(|s| Value::String(Rc::new(s.to_string())))
22900            .collect();
22901
22902        Ok(Value::Array(Rc::new(RefCell::new(match_values))))
22903    });
22904
22905    // =========================================================================
22906    // ARCHETYPES (Jung)
22907    // =========================================================================
22908
22909    // archetype - get information about Jungian archetypes
22910    define(interp, "archetype", Some(1), |_, args| {
22911        let name = match &args[0] {
22912            Value::String(s) => s.to_lowercase(),
22913            _ => return Err(RuntimeError::new("archetype() requires string")),
22914        };
22915
22916        let (description, shadow, gift, challenge) = match name.as_str() {
22917            // Core archetypes
22918            "self" => (
22919                "The unified conscious and unconscious, the goal of individuation",
22920                "Inflation or deflation of ego",
22921                "Wholeness, integration, meaning",
22922                "Integrating all aspects of psyche",
22923            ),
22924            "shadow" => (
22925                "The unconscious aspect containing repressed weaknesses and instincts",
22926                "Projection onto others, denial",
22927                "Creativity, spontaneity, insight",
22928                "Acknowledging and integrating darkness",
22929            ),
22930            "anima" => (
22931                "The feminine inner personality in a man's unconscious",
22932                "Moodiness, seduction, possession",
22933                "Relatedness, creativity, soul connection",
22934                "Developing emotional intelligence",
22935            ),
22936            "animus" => (
22937                "The masculine inner personality in a woman's unconscious",
22938                "Brutality, reckless action, opinionation",
22939                "Courage, initiative, spiritual depth",
22940                "Developing assertiveness with wisdom",
22941            ),
22942            "persona" => (
22943                "The social mask, the face we present to the world",
22944                "Over-identification, inauthenticity",
22945                "Social adaptation, professional competence",
22946                "Maintaining authenticity within role",
22947            ),
22948
22949            // Major archetypes
22950            "hero" => (
22951                "The courageous one who overcomes obstacles and achieves great deeds",
22952                "Arrogance, ruthlessness, eternal battle",
22953                "Courage, perseverance, accomplishment",
22954                "Knowing when to fight and when to surrender",
22955            ),
22956            "sage" | "wise_old_man" => (
22957                "The wise figure who offers guidance and insight",
22958                "Dogmatism, disconnection, ivory tower",
22959                "Wisdom, knowledge, truth-seeking",
22960                "Applying wisdom practically",
22961            ),
22962            "magician" | "wizard" => (
22963                "The transformer who makes things happen through understanding laws",
22964                "Manipulation, disconnection from ethics",
22965                "Transformation, vision, manifestation",
22966                "Using power responsibly",
22967            ),
22968            "lover" => (
22969                "The one who pursues connection, beauty, and passion",
22970                "Obsession, jealousy, loss of identity",
22971                "Passion, commitment, appreciation",
22972                "Maintaining boundaries while connecting deeply",
22973            ),
22974            "caregiver" | "mother" => (
22975                "The nurturing one who protects and provides",
22976                "Martyrdom, enabling, smothering",
22977                "Compassion, generosity, nurturing",
22978                "Caring for self while caring for others",
22979            ),
22980            "ruler" | "king" | "queen" => (
22981                "The one who takes responsibility for the realm",
22982                "Tyranny, authoritarianism, being overthrown",
22983                "Order, leadership, prosperity",
22984                "Serving the greater good, not just power",
22985            ),
22986            "creator" | "artist" => (
22987                "The one who brings new things into being",
22988                "Perfectionism, self-indulgence, drama",
22989                "Creativity, imagination, expression",
22990                "Completing projects, accepting imperfection",
22991            ),
22992            "innocent" | "child" => (
22993                "The pure one with faith and optimism",
22994                "Naivety, denial, dependence",
22995                "Faith, optimism, loyalty",
22996                "Growing without becoming cynical",
22997            ),
22998            "explorer" | "seeker" => (
22999                "The one who seeks new experiences and self-discovery",
23000                "Aimless wandering, inability to commit",
23001                "Autonomy, ambition, authenticity",
23002                "Finding what you seek",
23003            ),
23004            "rebel" | "outlaw" => (
23005                "The one who breaks rules and challenges the status quo",
23006                "Crime, self-destruction, alienation",
23007                "Liberation, revolution, radical freedom",
23008                "Channeling rebellion constructively",
23009            ),
23010            "jester" | "fool" | "trickster" => (
23011                "The one who uses humor and playfulness",
23012                "Cruelty, debauchery, irresponsibility",
23013                "Joy, freedom, living in the moment",
23014                "Knowing when to be serious",
23015            ),
23016            "everyman" | "orphan" => (
23017                "The regular person who wants belonging",
23018                "Victim mentality, losing self in group",
23019                "Realism, empathy, connection",
23020                "Standing out when necessary",
23021            ),
23022            _ => return Err(RuntimeError::new(format!("Unknown archetype: {}", name))),
23023        };
23024
23025        let mut result = std::collections::HashMap::new();
23026        result.insert("name".to_string(), Value::String(Rc::new(name)));
23027        result.insert(
23028            "description".to_string(),
23029            Value::String(Rc::new(description.to_string())),
23030        );
23031        result.insert(
23032            "shadow".to_string(),
23033            Value::String(Rc::new(shadow.to_string())),
23034        );
23035        result.insert("gift".to_string(), Value::String(Rc::new(gift.to_string())));
23036        result.insert(
23037            "challenge".to_string(),
23038            Value::String(Rc::new(challenge.to_string())),
23039        );
23040
23041        Ok(Value::Map(Rc::new(RefCell::new(result))))
23042    });
23043
23044    // =========================================================================
23045    // ASTROLOGY
23046    // =========================================================================
23047
23048    // zodiac - get zodiac sign information
23049    define(interp, "zodiac", Some(1), |_, args| {
23050        let input = match &args[0] {
23051            Value::Int(n) => (*n as usize - 1).min(11),
23052            Value::String(s) => match s.to_lowercase().as_str() {
23053                "aries" | "♈" => 0,
23054                "taurus" | "♉" => 1,
23055                "gemini" | "♊" => 2,
23056                "cancer" | "♋" => 3,
23057                "leo" | "♌" => 4,
23058                "virgo" | "♍" => 5,
23059                "libra" | "♎" => 6,
23060                "scorpio" | "♏" => 7,
23061                "sagittarius" | "♐" => 8,
23062                "capricorn" | "♑" => 9,
23063                "aquarius" | "♒" => 10,
23064                "pisces" | "♓" => 11,
23065                _ => return Err(RuntimeError::new(format!("Unknown sign: {}", s))),
23066            },
23067            _ => return Err(RuntimeError::new("zodiac() requires number or name")),
23068        };
23069
23070        let signs = [
23071            (
23072                "♈",
23073                "Aries",
23074                "Fire",
23075                "Cardinal",
23076                "Mars",
23077                "I Am",
23078                "Mar 21 - Apr 19",
23079            ),
23080            (
23081                "♉",
23082                "Taurus",
23083                "Earth",
23084                "Fixed",
23085                "Venus",
23086                "I Have",
23087                "Apr 20 - May 20",
23088            ),
23089            (
23090                "♊",
23091                "Gemini",
23092                "Air",
23093                "Mutable",
23094                "Mercury",
23095                "I Think",
23096                "May 21 - Jun 20",
23097            ),
23098            (
23099                "♋",
23100                "Cancer",
23101                "Water",
23102                "Cardinal",
23103                "Moon",
23104                "I Feel",
23105                "Jun 21 - Jul 22",
23106            ),
23107            (
23108                "♌",
23109                "Leo",
23110                "Fire",
23111                "Fixed",
23112                "Sun",
23113                "I Will",
23114                "Jul 23 - Aug 22",
23115            ),
23116            (
23117                "♍",
23118                "Virgo",
23119                "Earth",
23120                "Mutable",
23121                "Mercury",
23122                "I Analyze",
23123                "Aug 23 - Sep 22",
23124            ),
23125            (
23126                "♎",
23127                "Libra",
23128                "Air",
23129                "Cardinal",
23130                "Venus",
23131                "I Balance",
23132                "Sep 23 - Oct 22",
23133            ),
23134            (
23135                "♏",
23136                "Scorpio",
23137                "Water",
23138                "Fixed",
23139                "Pluto/Mars",
23140                "I Transform",
23141                "Oct 23 - Nov 21",
23142            ),
23143            (
23144                "♐",
23145                "Sagittarius",
23146                "Fire",
23147                "Mutable",
23148                "Jupiter",
23149                "I Seek",
23150                "Nov 22 - Dec 21",
23151            ),
23152            (
23153                "♑",
23154                "Capricorn",
23155                "Earth",
23156                "Cardinal",
23157                "Saturn",
23158                "I Use",
23159                "Dec 22 - Jan 19",
23160            ),
23161            (
23162                "♒",
23163                "Aquarius",
23164                "Air",
23165                "Fixed",
23166                "Uranus/Saturn",
23167                "I Know",
23168                "Jan 20 - Feb 18",
23169            ),
23170            (
23171                "♓",
23172                "Pisces",
23173                "Water",
23174                "Mutable",
23175                "Neptune/Jupiter",
23176                "I Believe",
23177                "Feb 19 - Mar 20",
23178            ),
23179        ];
23180
23181        let (symbol, name, element, modality, ruler, motto, dates) = signs[input];
23182
23183        let mut result = std::collections::HashMap::new();
23184        result.insert("number".to_string(), Value::Int((input + 1) as i64));
23185        result.insert(
23186            "symbol".to_string(),
23187            Value::String(Rc::new(symbol.to_string())),
23188        );
23189        result.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
23190        result.insert(
23191            "element".to_string(),
23192            Value::String(Rc::new(element.to_string())),
23193        );
23194        result.insert(
23195            "modality".to_string(),
23196            Value::String(Rc::new(modality.to_string())),
23197        );
23198        result.insert(
23199            "ruler".to_string(),
23200            Value::String(Rc::new(ruler.to_string())),
23201        );
23202        result.insert(
23203            "motto".to_string(),
23204            Value::String(Rc::new(motto.to_string())),
23205        );
23206        result.insert(
23207            "dates".to_string(),
23208            Value::String(Rc::new(dates.to_string())),
23209        );
23210
23211        Ok(Value::Map(Rc::new(RefCell::new(result))))
23212    });
23213
23214    // tarot_major - Major Arcana information
23215    define(interp, "tarot_major", Some(1), |_, args| {
23216        let num = match &args[0] {
23217            Value::Int(n) => (*n as usize).min(21),
23218            Value::String(s) => match s.to_lowercase().as_str() {
23219                "fool" => 0,
23220                "magician" => 1,
23221                "high_priestess" | "priestess" => 2,
23222                "empress" => 3,
23223                "emperor" => 4,
23224                "hierophant" | "pope" => 5,
23225                "lovers" => 6,
23226                "chariot" => 7,
23227                "strength" => 8,
23228                "hermit" => 9,
23229                "wheel" | "fortune" => 10,
23230                "justice" => 11,
23231                "hanged_man" | "hanged" => 12,
23232                "death" => 13,
23233                "temperance" => 14,
23234                "devil" => 15,
23235                "tower" => 16,
23236                "star" => 17,
23237                "moon" => 18,
23238                "sun" => 19,
23239                "judgement" | "judgment" => 20,
23240                "world" => 21,
23241                _ => return Err(RuntimeError::new(format!("Unknown card: {}", s))),
23242            },
23243            _ => return Err(RuntimeError::new("tarot_major() requires number or name")),
23244        };
23245
23246        let cards = [
23247            (
23248                "The Fool",
23249                "New beginnings, innocence, spontaneity",
23250                "Naivety, recklessness, risk-taking",
23251            ),
23252            (
23253                "The Magician",
23254                "Willpower, creation, manifestation",
23255                "Manipulation, trickery, unused talent",
23256            ),
23257            (
23258                "The High Priestess",
23259                "Intuition, mystery, inner knowledge",
23260                "Secrets, withdrawal, silence",
23261            ),
23262            (
23263                "The Empress",
23264                "Abundance, nurturing, fertility",
23265                "Dependence, smothering, emptiness",
23266            ),
23267            (
23268                "The Emperor",
23269                "Authority, structure, control",
23270                "Tyranny, rigidity, coldness",
23271            ),
23272            (
23273                "The Hierophant",
23274                "Tradition, conformity, spirituality",
23275                "Dogma, restriction, challenging status quo",
23276            ),
23277            (
23278                "The Lovers",
23279                "Love, harmony, relationships, choices",
23280                "Disharmony, imbalance, misalignment",
23281            ),
23282            (
23283                "The Chariot",
23284                "Direction, willpower, victory",
23285                "Aggression, lack of direction, obstacles",
23286            ),
23287            (
23288                "Strength",
23289                "Courage, patience, inner power",
23290                "Self-doubt, weakness, insecurity",
23291            ),
23292            (
23293                "The Hermit",
23294                "Contemplation, search for truth, inner guidance",
23295                "Isolation, loneliness, withdrawal",
23296            ),
23297            (
23298                "Wheel of Fortune",
23299                "Change, cycles, fate, destiny",
23300                "Resistance to change, bad luck, setbacks",
23301            ),
23302            (
23303                "Justice",
23304                "Truth, fairness, law, cause and effect",
23305                "Unfairness, dishonesty, lack of accountability",
23306            ),
23307            (
23308                "The Hanged Man",
23309                "Surrender, letting go, new perspective",
23310                "Stalling, resistance, indecision",
23311            ),
23312            (
23313                "Death",
23314                "Endings, transformation, transition",
23315                "Fear of change, stagnation, decay",
23316            ),
23317            (
23318                "Temperance",
23319                "Balance, moderation, patience",
23320                "Imbalance, excess, lack of purpose",
23321            ),
23322            (
23323                "The Devil",
23324                "Bondage, materialism, shadow self",
23325                "Freedom, release, exploring dark side",
23326            ),
23327            (
23328                "The Tower",
23329                "Sudden change, upheaval, revelation",
23330                "Disaster averted, fear of change, prolonged pain",
23331            ),
23332            (
23333                "The Star",
23334                "Hope, faith, renewal, inspiration",
23335                "Despair, disconnection, lack of faith",
23336            ),
23337            (
23338                "The Moon",
23339                "Illusion, intuition, the unconscious",
23340                "Fear, confusion, misinterpretation",
23341            ),
23342            (
23343                "The Sun",
23344                "Joy, success, vitality, positivity",
23345                "Negativity, depression, sadness",
23346            ),
23347            (
23348                "Judgement",
23349                "Rebirth, inner calling, absolution",
23350                "Self-doubt, refusal of self-examination",
23351            ),
23352            (
23353                "The World",
23354                "Completion, accomplishment, wholeness",
23355                "Incompletion, lack of closure, emptiness",
23356            ),
23357        ];
23358
23359        let (name, upright, reversed) = cards[num];
23360
23361        let mut result = std::collections::HashMap::new();
23362        result.insert("number".to_string(), Value::Int(num as i64));
23363        result.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
23364        result.insert(
23365            "upright".to_string(),
23366            Value::String(Rc::new(upright.to_string())),
23367        );
23368        result.insert(
23369            "reversed".to_string(),
23370            Value::String(Rc::new(reversed.to_string())),
23371        );
23372
23373        Ok(Value::Map(Rc::new(RefCell::new(result))))
23374    });
23375
23376    // draw_tarot - draw random tarot card
23377    define(interp, "draw_tarot", Some(0), |_, _| {
23378        let mut rng = rand::thread_rng();
23379        let card: usize = rng.gen_range(0..22);
23380        let reversed: bool = rng.gen();
23381
23382        let cards = [
23383            "The Fool",
23384            "The Magician",
23385            "The High Priestess",
23386            "The Empress",
23387            "The Emperor",
23388            "The Hierophant",
23389            "The Lovers",
23390            "The Chariot",
23391            "Strength",
23392            "The Hermit",
23393            "Wheel of Fortune",
23394            "Justice",
23395            "The Hanged Man",
23396            "Death",
23397            "Temperance",
23398            "The Devil",
23399            "The Tower",
23400            "The Star",
23401            "The Moon",
23402            "The Sun",
23403            "Judgement",
23404            "The World",
23405        ];
23406
23407        let mut result = std::collections::HashMap::new();
23408        result.insert("number".to_string(), Value::Int(card as i64));
23409        result.insert(
23410            "name".to_string(),
23411            Value::String(Rc::new(cards[card].to_string())),
23412        );
23413        result.insert("reversed".to_string(), Value::Bool(reversed));
23414        result.insert(
23415            "orientation".to_string(),
23416            Value::String(Rc::new(
23417                if reversed { "reversed" } else { "upright" }.to_string(),
23418            )),
23419        );
23420
23421        Ok(Value::Map(Rc::new(RefCell::new(result))))
23422    });
23423
23424    // =========================================================================
23425    // SYNCHRONICITY
23426    // =========================================================================
23427
23428    // synchronicity_score - calculate "meaningful coincidence" between values
23429    define(interp, "synchronicity_score", Some(2), |_, args| {
23430        // This is intentionally mysterious - combining multiple systems
23431        let a = match &args[0] {
23432            Value::String(s) => s.to_string(),
23433            Value::Int(n) => n.to_string(),
23434            _ => {
23435                return Err(RuntimeError::new(
23436                    "synchronicity_score() requires string or int",
23437                ))
23438            }
23439        };
23440
23441        let b = match &args[1] {
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        // Calculate gematria values (simple English)
23452        let val_a: i64 = a
23453            .to_uppercase()
23454            .chars()
23455            .filter_map(|c| {
23456                if c.is_ascii_alphabetic() {
23457                    Some((c as i64) - ('A' as i64) + 1)
23458                } else if c.is_ascii_digit() {
23459                    c.to_digit(10).map(|d| d as i64)
23460                } else {
23461                    None
23462                }
23463            })
23464            .sum();
23465
23466        let val_b: i64 = b
23467            .to_uppercase()
23468            .chars()
23469            .filter_map(|c| {
23470                if c.is_ascii_alphabetic() {
23471                    Some((c as i64) - ('A' as i64) + 1)
23472                } else if c.is_ascii_digit() {
23473                    c.to_digit(10).map(|d| d as i64)
23474                } else {
23475                    None
23476                }
23477            })
23478            .sum();
23479
23480        // Multiple synchronicity factors
23481        let mut factors = Vec::new();
23482
23483        // Same value
23484        if val_a == val_b {
23485            factors.push("identical_gematria".to_string());
23486        }
23487
23488        // One divides the other
23489        if val_a > 0 && val_b > 0 && (val_a % val_b == 0 || val_b % val_a == 0) {
23490            factors.push("divisibility".to_string());
23491        }
23492
23493        // Fibonacci relationship
23494        let fib_set: std::collections::HashSet<i64> =
23495            [1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987]
23496                .iter()
23497                .cloned()
23498                .collect();
23499        if fib_set.contains(&val_a) && fib_set.contains(&val_b) {
23500            factors.push("both_fibonacci".to_string());
23501        }
23502
23503        // Digital root match
23504        fn digital_root(mut n: i64) -> i64 {
23505            while n > 9 {
23506                n = n
23507                    .to_string()
23508                    .chars()
23509                    .filter_map(|c| c.to_digit(10))
23510                    .map(|d| d as i64)
23511                    .sum();
23512            }
23513            n
23514        }
23515        if digital_root(val_a) == digital_root(val_b) {
23516            factors.push("same_digital_root".to_string());
23517        }
23518
23519        // Golden ratio relationship (within 1%)
23520        let phi = (1.0 + 5.0_f64.sqrt()) / 2.0;
23521        let ratio = if val_a > 0 && val_b > 0 {
23522            (val_a as f64 / val_b as f64).max(val_b as f64 / val_a as f64)
23523        } else {
23524            0.0
23525        };
23526        if (ratio - phi).abs() < 0.02 || (ratio - 1.0 / phi).abs() < 0.02 {
23527            factors.push("golden_ratio".to_string());
23528        }
23529
23530        let score = (factors.len() as f64 / 5.0).min(1.0);
23531
23532        let mut result = std::collections::HashMap::new();
23533        result.insert("score".to_string(), Value::Float(score));
23534        result.insert("value_a".to_string(), Value::Int(val_a));
23535        result.insert("value_b".to_string(), Value::Int(val_b));
23536        let factor_values: Vec<Value> = factors
23537            .iter()
23538            .map(|s| Value::String(Rc::new(s.clone())))
23539            .collect();
23540        result.insert(
23541            "factors".to_string(),
23542            Value::Array(Rc::new(RefCell::new(factor_values))),
23543        );
23544
23545        Ok(Value::Map(Rc::new(RefCell::new(result))))
23546    });
23547
23548    // spirituality_info
23549    define(interp, "spirituality_info", Some(0), |_, _| {
23550        let mut info = std::collections::HashMap::new();
23551
23552        info.insert(
23553            "i_ching".to_string(),
23554            Value::String(Rc::new(
23555                "trigram(), hexagram(), cast_iching() - 64 hexagrams of change".to_string(),
23556            )),
23557        );
23558        info.insert(
23559            "sacred_geometry".to_string(),
23560            Value::String(Rc::new(
23561                "phi(), sacred_ratio(), fibonacci(), platonic_solid()".to_string(),
23562            )),
23563        );
23564        info.insert(
23565            "gematria".to_string(),
23566            Value::String(Rc::new(
23567                "Hebrew, Greek, Arabic, English letter-number systems".to_string(),
23568            )),
23569        );
23570        info.insert(
23571            "archetypes".to_string(),
23572            Value::String(Rc::new(
23573                "17 Jungian archetypes with shadow and gift".to_string(),
23574            )),
23575        );
23576        info.insert(
23577            "astrology".to_string(),
23578            Value::String(Rc::new(
23579                "zodiac() - 12 signs with elements and modalities".to_string(),
23580            )),
23581        );
23582        info.insert(
23583            "tarot".to_string(),
23584            Value::String(Rc::new(
23585                "tarot_major(), draw_tarot() - 22 Major Arcana".to_string(),
23586            )),
23587        );
23588
23589        Ok(Value::Map(Rc::new(RefCell::new(info))))
23590    });
23591}
23592
23593// I Ching hexagram data (64 hexagrams in King Wen sequence)
23594const HEXAGRAMS: [(&str, &str, &str, &str, &str, &str); 64] = [
23595    (
23596        "乾",
23597        "Qián",
23598        "The Creative",
23599        "Sublime success through perseverance",
23600        "Heaven",
23601        "Heaven",
23602    ),
23603    (
23604        "坤",
23605        "Kūn",
23606        "The Receptive",
23607        "Devoted success through the mare's perseverance",
23608        "Earth",
23609        "Earth",
23610    ),
23611    (
23612        "屯",
23613        "Zhūn",
23614        "Difficulty at the Beginning",
23615        "Persevere, seek helpers, don't act alone",
23616        "Water",
23617        "Thunder",
23618    ),
23619    (
23620        "蒙",
23621        "Méng",
23622        "Youthful Folly",
23623        "Success through education and guidance",
23624        "Mountain",
23625        "Water",
23626    ),
23627    (
23628        "需",
23629        "Xū",
23630        "Waiting",
23631        "Sincerity brings success; cross the great water",
23632        "Water",
23633        "Heaven",
23634    ),
23635    (
23636        "訟",
23637        "Sòng",
23638        "Conflict",
23639        "Seek counsel; don't cross the great water",
23640        "Heaven",
23641        "Water",
23642    ),
23643    (
23644        "師",
23645        "Shī",
23646        "The Army",
23647        "Perseverance and an experienced leader bring success",
23648        "Earth",
23649        "Water",
23650    ),
23651    (
23652        "比",
23653        "Bǐ",
23654        "Holding Together",
23655        "Through perseverance, those who hesitate should reflect",
23656        "Water",
23657        "Earth",
23658    ),
23659    (
23660        "小畜",
23661        "Xiǎo Chù",
23662        "Small Taming",
23663        "Success; dense clouds but no rain",
23664        "Wind",
23665        "Heaven",
23666    ),
23667    (
23668        "履",
23669        "Lǚ",
23670        "Treading",
23671        "Tread on the tiger's tail carefully; success",
23672        "Heaven",
23673        "Lake",
23674    ),
23675    (
23676        "泰",
23677        "Tài",
23678        "Peace",
23679        "The small departs, the great approaches; success",
23680        "Earth",
23681        "Heaven",
23682    ),
23683    (
23684        "否",
23685        "Pǐ",
23686        "Standstill",
23687        "The great departs, the small approaches; persevere",
23688        "Heaven",
23689        "Earth",
23690    ),
23691    (
23692        "同人",
23693        "Tóng Rén",
23694        "Fellowship",
23695        "Success in the open; cross the great water",
23696        "Heaven",
23697        "Fire",
23698    ),
23699    (
23700        "大有",
23701        "Dà Yǒu",
23702        "Great Possession",
23703        "Supreme success",
23704        "Fire",
23705        "Heaven",
23706    ),
23707    (
23708        "謙",
23709        "Qiān",
23710        "Modesty",
23711        "Success; the superior person carries things through",
23712        "Earth",
23713        "Mountain",
23714    ),
23715    (
23716        "豫",
23717        "Yù",
23718        "Enthusiasm",
23719        "Appoint helpers and set armies marching",
23720        "Thunder",
23721        "Earth",
23722    ),
23723    (
23724        "隨",
23725        "Suí",
23726        "Following",
23727        "Supreme success through perseverance",
23728        "Lake",
23729        "Thunder",
23730    ),
23731    (
23732        "蠱",
23733        "Gǔ",
23734        "Work on the Decayed",
23735        "Success; cross the great water; three days before and after",
23736        "Mountain",
23737        "Wind",
23738    ),
23739    (
23740        "臨",
23741        "Lín",
23742        "Approach",
23743        "Great success through perseverance; misfortune in eighth month",
23744        "Earth",
23745        "Lake",
23746    ),
23747    (
23748        "觀",
23749        "Guān",
23750        "Contemplation",
23751        "Ablution, but not yet sacrifice; confidence inspires",
23752        "Wind",
23753        "Earth",
23754    ),
23755    (
23756        "噬嗑",
23757        "Shì Kè",
23758        "Biting Through",
23759        "Success; favorable for legal matters",
23760        "Fire",
23761        "Thunder",
23762    ),
23763    (
23764        "賁",
23765        "Bì",
23766        "Grace",
23767        "Success in small matters",
23768        "Mountain",
23769        "Fire",
23770    ),
23771    (
23772        "剝",
23773        "Bō",
23774        "Splitting Apart",
23775        "Unfavorable to go anywhere",
23776        "Mountain",
23777        "Earth",
23778    ),
23779    (
23780        "復",
23781        "Fù",
23782        "Return",
23783        "Success; going out and coming in without error",
23784        "Earth",
23785        "Thunder",
23786    ),
23787    (
23788        "無妄",
23789        "Wú Wàng",
23790        "Innocence",
23791        "Supreme success through perseverance",
23792        "Heaven",
23793        "Thunder",
23794    ),
23795    (
23796        "大畜",
23797        "Dà Chù",
23798        "Great Taming",
23799        "Perseverance; eat away from home",
23800        "Mountain",
23801        "Heaven",
23802    ),
23803    (
23804        "頤",
23805        "Yí",
23806        "Nourishment",
23807        "Perseverance; watch what you nurture",
23808        "Mountain",
23809        "Thunder",
23810    ),
23811    (
23812        "大過",
23813        "Dà Guò",
23814        "Great Exceeding",
23815        "The ridgepole sags; favorable to have somewhere to go",
23816        "Lake",
23817        "Wind",
23818    ),
23819    (
23820        "坎",
23821        "Kǎn",
23822        "The Abysmal",
23823        "Sincerity brings success of the heart",
23824        "Water",
23825        "Water",
23826    ),
23827    (
23828        "離",
23829        "Lí",
23830        "The Clinging",
23831        "Perseverance; success; care for the cow",
23832        "Fire",
23833        "Fire",
23834    ),
23835    (
23836        "咸",
23837        "Xián",
23838        "Influence",
23839        "Success; perseverance; taking a maiden brings fortune",
23840        "Lake",
23841        "Mountain",
23842    ),
23843    (
23844        "恆",
23845        "Héng",
23846        "Duration",
23847        "Success without blame; perseverance; favorable to have somewhere to go",
23848        "Thunder",
23849        "Wind",
23850    ),
23851    (
23852        "遯",
23853        "Dùn",
23854        "Retreat",
23855        "Success; small perseverance",
23856        "Heaven",
23857        "Mountain",
23858    ),
23859    (
23860        "大壯",
23861        "Dà Zhuàng",
23862        "Great Power",
23863        "Perseverance",
23864        "Thunder",
23865        "Heaven",
23866    ),
23867    (
23868        "晉",
23869        "Jìn",
23870        "Progress",
23871        "The powerful prince is honored with horses",
23872        "Fire",
23873        "Earth",
23874    ),
23875    (
23876        "明夷",
23877        "Míng Yí",
23878        "Darkening of the Light",
23879        "Perseverance in adversity",
23880        "Earth",
23881        "Fire",
23882    ),
23883    (
23884        "家人",
23885        "Jiā Rén",
23886        "The Family",
23887        "Perseverance of the woman",
23888        "Wind",
23889        "Fire",
23890    ),
23891    (
23892        "睽",
23893        "Kuí",
23894        "Opposition",
23895        "Good fortune in small matters",
23896        "Fire",
23897        "Lake",
23898    ),
23899    (
23900        "蹇",
23901        "Jiǎn",
23902        "Obstruction",
23903        "Southwest favorable; northeast unfavorable; see the great person",
23904        "Water",
23905        "Mountain",
23906    ),
23907    (
23908        "解",
23909        "Xiè",
23910        "Deliverance",
23911        "Southwest favorable; return brings fortune; haste brings fortune",
23912        "Thunder",
23913        "Water",
23914    ),
23915    (
23916        "損",
23917        "Sǔn",
23918        "Decrease",
23919        "Sincerity; supreme fortune; persistence; favorable to undertake",
23920        "Mountain",
23921        "Lake",
23922    ),
23923    (
23924        "益",
23925        "Yì",
23926        "Increase",
23927        "Favorable to undertake and cross the great water",
23928        "Wind",
23929        "Thunder",
23930    ),
23931    (
23932        "夬",
23933        "Guài",
23934        "Breakthrough",
23935        "Proclaim at the king's court; sincerity in danger",
23936        "Lake",
23937        "Heaven",
23938    ),
23939    (
23940        "姤",
23941        "Gòu",
23942        "Coming to Meet",
23943        "The maiden is powerful; don't marry such a maiden",
23944        "Heaven",
23945        "Wind",
23946    ),
23947    (
23948        "萃",
23949        "Cuì",
23950        "Gathering",
23951        "Success; the king approaches his temple; see the great person",
23952        "Lake",
23953        "Earth",
23954    ),
23955    (
23956        "升",
23957        "Shēng",
23958        "Pushing Upward",
23959        "Supreme success; see the great person; don't worry",
23960        "Earth",
23961        "Wind",
23962    ),
23963    (
23964        "困",
23965        "Kùn",
23966        "Oppression",
23967        "Success; perseverance of the great person; no blame",
23968        "Lake",
23969        "Water",
23970    ),
23971    (
23972        "井",
23973        "Jǐng",
23974        "The Well",
23975        "The town may change but not the well",
23976        "Water",
23977        "Wind",
23978    ),
23979    (
23980        "革",
23981        "Gé",
23982        "Revolution",
23983        "On your own day you are believed; great success",
23984        "Lake",
23985        "Fire",
23986    ),
23987    (
23988        "鼎",
23989        "Dǐng",
23990        "The Cauldron",
23991        "Supreme good fortune; success",
23992        "Fire",
23993        "Wind",
23994    ),
23995    (
23996        "震",
23997        "Zhèn",
23998        "The Arousing",
23999        "Success; thunder comes with fright; laughing and talking after",
24000        "Thunder",
24001        "Thunder",
24002    ),
24003    (
24004        "艮",
24005        "Gèn",
24006        "Keeping Still",
24007        "Keep your back still; go into the courtyard without seeing anyone",
24008        "Mountain",
24009        "Mountain",
24010    ),
24011    (
24012        "漸",
24013        "Jiàn",
24014        "Development",
24015        "The maiden is given in marriage; good fortune; perseverance",
24016        "Wind",
24017        "Mountain",
24018    ),
24019    (
24020        "歸妹",
24021        "Guī Mèi",
24022        "The Marrying Maiden",
24023        "Undertakings bring misfortune",
24024        "Thunder",
24025        "Lake",
24026    ),
24027    (
24028        "豐",
24029        "Fēng",
24030        "Abundance",
24031        "Success; the king attains it; don't worry; be like the sun at noon",
24032        "Thunder",
24033        "Fire",
24034    ),
24035    (
24036        "旅",
24037        "Lǚ",
24038        "The Wanderer",
24039        "Success through smallness; perseverance brings fortune",
24040        "Fire",
24041        "Mountain",
24042    ),
24043    (
24044        "巽",
24045        "Xùn",
24046        "The Gentle",
24047        "Success through small things; favorable to have somewhere to go",
24048        "Wind",
24049        "Wind",
24050    ),
24051    (
24052        "兌",
24053        "Duì",
24054        "The Joyous",
24055        "Success; perseverance",
24056        "Lake",
24057        "Lake",
24058    ),
24059    (
24060        "渙",
24061        "Huàn",
24062        "Dispersion",
24063        "Success; the king approaches his temple; cross the great water",
24064        "Wind",
24065        "Water",
24066    ),
24067    (
24068        "節",
24069        "Jié",
24070        "Limitation",
24071        "Success; bitter limitation should not be persevered in",
24072        "Water",
24073        "Lake",
24074    ),
24075    (
24076        "中孚",
24077        "Zhōng Fú",
24078        "Inner Truth",
24079        "Pigs and fishes; good fortune; cross the great water",
24080        "Wind",
24081        "Lake",
24082    ),
24083    (
24084        "小過",
24085        "Xiǎo Guò",
24086        "Small Exceeding",
24087        "Success; perseverance; small things yes, great things no",
24088        "Thunder",
24089        "Mountain",
24090    ),
24091    (
24092        "既濟",
24093        "Jì Jì",
24094        "After Completion",
24095        "Success in small matters; perseverance; good at start, disorder at end",
24096        "Water",
24097        "Fire",
24098    ),
24099    (
24100        "未濟",
24101        "Wèi Jì",
24102        "Before Completion",
24103        "Success; the young fox almost across; tail gets wet; no goal",
24104        "Fire",
24105        "Water",
24106    ),
24107];
24108
24109fn binary_to_king_wen(binary: u8) -> u8 {
24110    // Maps binary hexagram representation to King Wen sequence number
24111    // This is a complex mapping based on traditional ordering
24112    const KING_WEN_ORDER: [u8; 64] = [
24113        1, 43, 14, 34, 9, 5, 26, 11, 10, 58, 38, 54, 61, 60, 41, 19, 13, 49, 30, 55, 37, 63, 22,
24114        36, 25, 17, 21, 51, 42, 3, 27, 24, 44, 28, 50, 32, 57, 48, 18, 46, 6, 47, 64, 40, 59, 29,
24115        4, 7, 33, 31, 56, 62, 53, 39, 52, 15, 12, 45, 35, 16, 20, 8, 23, 2,
24116    ];
24117    KING_WEN_ORDER[binary as usize] - 1
24118}
24119
24120fn hebrew_gematria(c: char) -> i64 {
24121    match c {
24122        'א' | 'A' | 'a' => 1,
24123        'ב' | 'B' | 'b' => 2,
24124        'ג' | 'G' | 'g' => 3,
24125        'ד' | 'D' | 'd' => 4,
24126        'ה' | 'H' | 'h' => 5,
24127        'ו' | 'V' | 'v' | 'W' | 'w' => 6,
24128        'ז' | 'Z' | 'z' => 7,
24129        'ח' => 8,
24130        'ט' => 9,
24131        'י' | 'Y' | 'y' | 'I' | 'i' | 'J' | 'j' => 10,
24132        'כ' | 'K' | 'k' => 20,
24133        'ל' | 'L' | 'l' => 30,
24134        'מ' | 'M' | 'm' => 40,
24135        'נ' | 'N' | 'n' => 50,
24136        'ס' | 'S' | 's' | 'X' | 'x' => 60,
24137        'ע' | 'O' | 'o' => 70,
24138        'פ' | 'P' | 'p' | 'F' | 'f' => 80,
24139        'צ' => 90,
24140        'ק' | 'Q' | 'q' => 100,
24141        'ר' | 'R' | 'r' => 200,
24142        'ש' => 300,
24143        'ת' | 'T' | 't' => 400,
24144        'ך' => 500,             // Final kaph
24145        'ם' => 600,             // Final mem
24146        'ן' => 700,             // Final nun
24147        'ף' => 800,             // Final pe
24148        'ץ' | 'C' | 'c' => 900, // Final tzadi / C approximation
24149        'E' | 'e' => 5,         // Map to He
24150        'U' | 'u' => 6,         // Map to Vav
24151        _ => 0,
24152    }
24153}
24154
24155fn greek_isopsephy(c: char) -> i64 {
24156    match c {
24157        'Α' | 'α' | 'A' | 'a' => 1,
24158        'Β' | 'β' | 'B' | 'b' => 2,
24159        'Γ' | 'γ' | 'G' | 'g' => 3,
24160        'Δ' | 'δ' | 'D' | 'd' => 4,
24161        'Ε' | 'ε' | 'E' | 'e' => 5,
24162        'Ϛ' | 'ϛ' => 6, // Stigma (archaic)
24163        'Ζ' | 'ζ' | 'Z' | 'z' => 7,
24164        'Η' | 'η' | 'H' | 'h' => 8,
24165        'Θ' | 'θ' => 9,
24166        'Ι' | 'ι' | 'I' | 'i' => 10,
24167        'Κ' | 'κ' | 'K' | 'k' => 20,
24168        'Λ' | 'λ' | 'L' | 'l' => 30,
24169        'Μ' | 'μ' | 'M' | 'm' => 40,
24170        'Ν' | 'ν' | 'N' | 'n' => 50,
24171        'Ξ' | 'ξ' | 'X' | 'x' => 60,
24172        'Ο' | 'ο' | 'O' | 'o' => 70,
24173        'Π' | 'π' | 'P' | 'p' => 80,
24174        'Ϙ' | 'ϙ' | 'Q' | 'q' => 90, // Qoppa
24175        'Ρ' | 'ρ' | 'R' | 'r' => 100,
24176        'Σ' | 'σ' | 'ς' | 'S' | 's' => 200,
24177        'Τ' | 'τ' | 'T' | 't' => 300,
24178        'Υ' | 'υ' | 'U' | 'u' | 'Y' | 'y' => 400,
24179        'Φ' | 'φ' | 'F' | 'f' => 500,
24180        'Χ' | 'χ' | 'C' | 'c' => 600,
24181        'Ψ' | 'ψ' => 700,
24182        'Ω' | 'ω' | 'W' | 'w' => 800,
24183        'Ϡ' | 'ϡ' => 900, // Sampi
24184        'J' | 'j' => 10,  // Map to Iota
24185        'V' | 'v' => 400, // Map to Upsilon
24186        _ => 0,
24187    }
24188}
24189
24190fn arabic_abjad(c: char) -> i64 {
24191    match c {
24192        'ا' | 'أ' | 'إ' | 'آ' | 'A' | 'a' => 1,
24193        'ب' | 'B' | 'b' => 2,
24194        'ج' | 'J' | 'j' | 'G' | 'g' => 3,
24195        'د' | 'D' | 'd' => 4,
24196        'ه' | 'H' | 'h' => 5,
24197        'و' | 'W' | 'w' | 'V' | 'v' => 6,
24198        'ز' | 'Z' | 'z' => 7,
24199        'ح' => 8,
24200        'ط' => 9,
24201        'ي' | 'Y' | 'y' | 'I' | 'i' => 10,
24202        'ك' | 'K' | 'k' => 20,
24203        'ل' | 'L' | 'l' => 30,
24204        'م' | 'M' | 'm' => 40,
24205        'ن' | 'N' | 'n' => 50,
24206        'س' | 'S' | 's' => 60,
24207        'ع' | 'E' | 'e' => 70,
24208        'ف' | 'F' | 'f' => 80,
24209        'ص' => 90,
24210        'ق' | 'Q' | 'q' => 100,
24211        'ر' | 'R' | 'r' => 200,
24212        'ش' => 300,
24213        'ت' | 'T' | 't' => 400,
24214        'ث' => 500,
24215        'خ' | 'X' | 'x' => 600,
24216        'ذ' => 700,
24217        'ض' => 800,
24218        'ظ' => 900,
24219        'غ' => 1000,
24220        'C' | 'c' => 600, // Map to خ
24221        'O' | 'o' => 70,  // Map to ع
24222        'P' | 'p' => 80,  // Map to ف
24223        'U' | 'u' => 6,   // Map to و
24224        _ => 0,
24225    }
24226}
24227
24228// =============================================================================
24229// Phase 16: Polycultural Color System
24230// =============================================================================
24231// Color meaning varies radically across cultures. This module provides mathematical
24232// color spaces + cultural color systems from around the world.
24233
24234fn register_color(interp: &mut Interpreter) {
24235    // =========================================================================
24236    // COLOR SPACE CONVERSIONS
24237    // =========================================================================
24238
24239    // rgb(r, g, b) - Create RGB color (0-255)
24240    define(interp, "rgb", Some(3), |_, args| {
24241        let r = match &args[0] {
24242            Value::Int(n) => (*n).clamp(0, 255) as u8,
24243            Value::Float(f) => (*f as i64).clamp(0, 255) as u8,
24244            _ => return Err(RuntimeError::new("rgb() requires numbers")),
24245        };
24246        let g = match &args[1] {
24247            Value::Int(n) => (*n).clamp(0, 255) as u8,
24248            Value::Float(f) => (*f as i64).clamp(0, 255) as u8,
24249            _ => return Err(RuntimeError::new("rgb() requires numbers")),
24250        };
24251        let b = match &args[2] {
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 mut map = std::collections::HashMap::new();
24257        map.insert("r".to_string(), Value::Int(r as i64));
24258        map.insert("g".to_string(), Value::Int(g as i64));
24259        map.insert("b".to_string(), Value::Int(b as i64));
24260        map.insert(
24261            "hex".to_string(),
24262            Value::String(Rc::new(format!("#{:02X}{:02X}{:02X}", r, g, b))),
24263        );
24264        Ok(Value::Map(Rc::new(RefCell::new(map))))
24265    });
24266
24267    // hex_to_rgb(hex) - Parse hex color string
24268    define(interp, "hex_to_rgb", Some(1), |_, args| {
24269        let hex = match &args[0] {
24270            Value::String(s) => s.to_string(),
24271            _ => return Err(RuntimeError::new("hex_to_rgb requires string")),
24272        };
24273        let hex = hex.trim_start_matches('#');
24274        if hex.len() != 6 {
24275            return Err(RuntimeError::new("hex_to_rgb requires 6 character hex"));
24276        }
24277        let r = u8::from_str_radix(&hex[0..2], 16).map_err(|_| RuntimeError::new("Invalid hex"))?;
24278        let g = u8::from_str_radix(&hex[2..4], 16).map_err(|_| RuntimeError::new("Invalid hex"))?;
24279        let b = u8::from_str_radix(&hex[4..6], 16).map_err(|_| RuntimeError::new("Invalid hex"))?;
24280        let mut map = std::collections::HashMap::new();
24281        map.insert("r".to_string(), Value::Int(r as i64));
24282        map.insert("g".to_string(), Value::Int(g as i64));
24283        map.insert("b".to_string(), Value::Int(b as i64));
24284        Ok(Value::Map(Rc::new(RefCell::new(map))))
24285    });
24286
24287    // rgb_to_hsl(r, g, b) - Convert RGB to HSL
24288    define(interp, "rgb_to_hsl", Some(3), |_, args| {
24289        let r = match &args[0] {
24290            Value::Int(n) => *n as f64 / 255.0,
24291            Value::Float(f) => *f / 255.0,
24292            _ => return Err(RuntimeError::new("requires numbers")),
24293        };
24294        let g = match &args[1] {
24295            Value::Int(n) => *n as f64 / 255.0,
24296            Value::Float(f) => *f / 255.0,
24297            _ => return Err(RuntimeError::new("requires numbers")),
24298        };
24299        let b = match &args[2] {
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 max = r.max(g).max(b);
24305        let min = r.min(g).min(b);
24306        let l = (max + min) / 2.0;
24307        let (h, s) = if max == min {
24308            (0.0, 0.0)
24309        } else {
24310            let d = max - min;
24311            let s = if l > 0.5 {
24312                d / (2.0 - max - min)
24313            } else {
24314                d / (max + min)
24315            };
24316            let h = if max == r {
24317                (g - b) / d + if g < b { 6.0 } else { 0.0 }
24318            } else if max == g {
24319                (b - r) / d + 2.0
24320            } else {
24321                (r - g) / d + 4.0
24322            };
24323            (h * 60.0, s)
24324        };
24325        let mut map = std::collections::HashMap::new();
24326        map.insert("h".to_string(), Value::Float(h));
24327        map.insert("s".to_string(), Value::Float(s));
24328        map.insert("l".to_string(), Value::Float(l));
24329        Ok(Value::Map(Rc::new(RefCell::new(map))))
24330    });
24331
24332    // complementary(r, g, b) - Opposite on color wheel
24333    define(interp, "complementary", Some(3), |_, args| {
24334        let r = match &args[0] {
24335            Value::Int(n) => *n as u8,
24336            _ => return Err(RuntimeError::new("requires int")),
24337        };
24338        let g = match &args[1] {
24339            Value::Int(n) => *n as u8,
24340            _ => return Err(RuntimeError::new("requires int")),
24341        };
24342        let b = match &args[2] {
24343            Value::Int(n) => *n as u8,
24344            _ => return Err(RuntimeError::new("requires int")),
24345        };
24346        let mut map = std::collections::HashMap::new();
24347        map.insert("r".to_string(), Value::Int(255 - r as i64));
24348        map.insert("g".to_string(), Value::Int(255 - g as i64));
24349        map.insert("b".to_string(), Value::Int(255 - b as i64));
24350        Ok(Value::Map(Rc::new(RefCell::new(map))))
24351    });
24352
24353    // =========================================================================
24354    // WU XING (五行) - CHINESE FIVE ELEMENTS
24355    // =========================================================================
24356    define(interp, "wu_xing", Some(1), |_, args| {
24357        let element = match &args[0] {
24358            Value::String(s) => s.to_lowercase(),
24359            _ => return Err(RuntimeError::new("wu_xing requires string")),
24360        };
24361        let (name, chinese, color, hex, direction, season, organ, emotion, planet, animal) =
24362            match element.as_str() {
24363                "wood" | "mu" | "木" => (
24364                    "Wood",
24365                    "木 (Mù)",
24366                    "Green/Azure",
24367                    "#228B22",
24368                    "East",
24369                    "Spring",
24370                    "Liver",
24371                    "Anger",
24372                    "Jupiter",
24373                    "Azure Dragon",
24374                ),
24375                "fire" | "huo" | "火" => (
24376                    "Fire",
24377                    "火 (Huǒ)",
24378                    "Red",
24379                    "#FF0000",
24380                    "South",
24381                    "Summer",
24382                    "Heart",
24383                    "Joy",
24384                    "Mars",
24385                    "Vermilion Bird",
24386                ),
24387                "earth" | "tu" | "土" => (
24388                    "Earth",
24389                    "土 (Tǔ)",
24390                    "Yellow",
24391                    "#FFDB58",
24392                    "Center",
24393                    "Late Summer",
24394                    "Spleen",
24395                    "Worry",
24396                    "Saturn",
24397                    "Yellow Dragon",
24398                ),
24399                "metal" | "jin" | "金" => (
24400                    "Metal",
24401                    "金 (Jīn)",
24402                    "White/Gold",
24403                    "#FFD700",
24404                    "West",
24405                    "Autumn",
24406                    "Lung",
24407                    "Grief",
24408                    "Venus",
24409                    "White Tiger",
24410                ),
24411                "water" | "shui" | "水" => (
24412                    "Water",
24413                    "水 (Shuǐ)",
24414                    "Black/Blue",
24415                    "#000080",
24416                    "North",
24417                    "Winter",
24418                    "Kidney",
24419                    "Fear",
24420                    "Mercury",
24421                    "Black Tortoise",
24422                ),
24423                _ => {
24424                    return Err(RuntimeError::new(
24425                        "Unknown element. Use wood/fire/earth/metal/water",
24426                    ))
24427                }
24428            };
24429        let mut map = std::collections::HashMap::new();
24430        map.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
24431        map.insert(
24432            "chinese".to_string(),
24433            Value::String(Rc::new(chinese.to_string())),
24434        );
24435        map.insert(
24436            "color".to_string(),
24437            Value::String(Rc::new(color.to_string())),
24438        );
24439        map.insert("hex".to_string(), Value::String(Rc::new(hex.to_string())));
24440        map.insert(
24441            "direction".to_string(),
24442            Value::String(Rc::new(direction.to_string())),
24443        );
24444        map.insert(
24445            "season".to_string(),
24446            Value::String(Rc::new(season.to_string())),
24447        );
24448        map.insert(
24449            "organ".to_string(),
24450            Value::String(Rc::new(organ.to_string())),
24451        );
24452        map.insert(
24453            "emotion".to_string(),
24454            Value::String(Rc::new(emotion.to_string())),
24455        );
24456        map.insert(
24457            "planet".to_string(),
24458            Value::String(Rc::new(planet.to_string())),
24459        );
24460        map.insert(
24461            "guardian".to_string(),
24462            Value::String(Rc::new(animal.to_string())),
24463        );
24464        Ok(Value::Map(Rc::new(RefCell::new(map))))
24465    });
24466
24467    // =========================================================================
24468    // CHAKRA COLORS (Ayurveda/Hindu)
24469    // =========================================================================
24470    define(interp, "chakra_color", Some(1), |_, args| {
24471        let chakra = match &args[0] {
24472            Value::String(s) => s.to_lowercase(),
24473            Value::Int(n) => n.to_string(),
24474            _ => return Err(RuntimeError::new("chakra_color requires string or number")),
24475        };
24476        let (name, sanskrit, color, hex, location, freq, element, mantra) = match chakra.as_str() {
24477            "root" | "muladhara" | "1" => (
24478                "Root",
24479                "मूलाधार",
24480                "Red",
24481                "#FF0000",
24482                "Base of spine",
24483                396.0,
24484                "Earth",
24485                "LAM",
24486            ),
24487            "sacral" | "svadhisthana" | "2" => (
24488                "Sacral",
24489                "स्वाधिष्ठान",
24490                "Orange",
24491                "#FF7F00",
24492                "Below navel",
24493                417.0,
24494                "Water",
24495                "VAM",
24496            ),
24497            "solar" | "manipura" | "3" => (
24498                "Solar Plexus",
24499                "मणिपूर",
24500                "Yellow",
24501                "#FFFF00",
24502                "Stomach",
24503                528.0,
24504                "Fire",
24505                "RAM",
24506            ),
24507            "heart" | "anahata" | "4" => (
24508                "Heart",
24509                "अनाहत",
24510                "Green",
24511                "#00FF00",
24512                "Chest",
24513                639.0,
24514                "Air",
24515                "YAM",
24516            ),
24517            "throat" | "vishuddha" | "5" => (
24518                "Throat",
24519                "विशुद्ध",
24520                "Blue",
24521                "#00BFFF",
24522                "Throat",
24523                741.0,
24524                "Ether",
24525                "HAM",
24526            ),
24527            "third_eye" | "ajna" | "6" => (
24528                "Third Eye",
24529                "आज्ञा",
24530                "Indigo",
24531                "#4B0082",
24532                "Forehead",
24533                852.0,
24534                "Light",
24535                "OM",
24536            ),
24537            "crown" | "sahasrara" | "7" => (
24538                "Crown",
24539                "सहस्रार",
24540                "Violet",
24541                "#8B00FF",
24542                "Top of head",
24543                963.0,
24544                "Thought",
24545                "Silence",
24546            ),
24547            _ => {
24548                return Err(RuntimeError::new(
24549                    "Unknown chakra. Use root/sacral/solar/heart/throat/third_eye/crown or 1-7",
24550                ))
24551            }
24552        };
24553        let mut map = std::collections::HashMap::new();
24554        map.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
24555        map.insert(
24556            "sanskrit".to_string(),
24557            Value::String(Rc::new(sanskrit.to_string())),
24558        );
24559        map.insert(
24560            "color".to_string(),
24561            Value::String(Rc::new(color.to_string())),
24562        );
24563        map.insert("hex".to_string(), Value::String(Rc::new(hex.to_string())));
24564        map.insert(
24565            "location".to_string(),
24566            Value::String(Rc::new(location.to_string())),
24567        );
24568        map.insert("frequency_hz".to_string(), Value::Float(freq));
24569        map.insert(
24570            "element".to_string(),
24571            Value::String(Rc::new(element.to_string())),
24572        );
24573        map.insert(
24574            "mantra".to_string(),
24575            Value::String(Rc::new(mantra.to_string())),
24576        );
24577        Ok(Value::Map(Rc::new(RefCell::new(map))))
24578    });
24579
24580    // =========================================================================
24581    // MAYAN DIRECTIONAL COLORS
24582    // =========================================================================
24583    define(interp, "maya_direction", Some(1), |_, args| {
24584        let dir = match &args[0] {
24585            Value::String(s) => s.to_lowercase(),
24586            _ => return Err(RuntimeError::new("requires string")),
24587        };
24588        let (direction, yucatec, color, hex, deity, meaning) = match dir.as_str() {
24589            "east" | "lakin" => (
24590                "East",
24591                "Lak'in",
24592                "Red",
24593                "#FF0000",
24594                "Chac (Red)",
24595                "Sunrise, new beginnings",
24596            ),
24597            "north" | "xaman" => (
24598                "North",
24599                "Xaman",
24600                "White",
24601                "#FFFFFF",
24602                "Chac (White)",
24603                "Ancestors, death",
24604            ),
24605            "west" | "chikin" => (
24606                "West",
24607                "Chik'in",
24608                "Black",
24609                "#000000",
24610                "Chac (Black)",
24611                "Sunset, completion",
24612            ),
24613            "south" | "nohol" => (
24614                "South",
24615                "Nohol",
24616                "Yellow",
24617                "#FFFF00",
24618                "Chac (Yellow)",
24619                "Maize, abundance",
24620            ),
24621            "center" | "yax" => (
24622                "Center",
24623                "Yax",
24624                "Green/Blue",
24625                "#00CED1",
24626                "World Tree",
24627                "Balance",
24628            ),
24629            _ => {
24630                return Err(RuntimeError::new(
24631                    "Unknown direction. Use east/north/west/south/center",
24632                ))
24633            }
24634        };
24635        let mut map = std::collections::HashMap::new();
24636        map.insert(
24637            "direction".to_string(),
24638            Value::String(Rc::new(direction.to_string())),
24639        );
24640        map.insert(
24641            "yucatec".to_string(),
24642            Value::String(Rc::new(yucatec.to_string())),
24643        );
24644        map.insert(
24645            "color".to_string(),
24646            Value::String(Rc::new(color.to_string())),
24647        );
24648        map.insert("hex".to_string(), Value::String(Rc::new(hex.to_string())));
24649        map.insert(
24650            "deity".to_string(),
24651            Value::String(Rc::new(deity.to_string())),
24652        );
24653        map.insert(
24654            "meaning".to_string(),
24655            Value::String(Rc::new(meaning.to_string())),
24656        );
24657        Ok(Value::Map(Rc::new(RefCell::new(map))))
24658    });
24659
24660    // =========================================================================
24661    // ORISHA COLORS (Yoruba/African)
24662    // =========================================================================
24663    define(interp, "orisha_color", Some(1), |_, args| {
24664        let orisha = match &args[0] {
24665            Value::String(s) => s.to_lowercase(),
24666            _ => return Err(RuntimeError::new("requires string")),
24667        };
24668        let (name, colors, hex, domain, day, number) = match orisha.as_str() {
24669            "obatala" | "oxala" => (
24670                "Obatalá",
24671                "White, silver",
24672                "#FFFFFF",
24673                "Creation, purity, wisdom",
24674                "Sunday",
24675                8,
24676            ),
24677            "yemoja" | "yemanja" => (
24678                "Yemọja",
24679                "Blue, white",
24680                "#4169E1",
24681                "Ocean, motherhood",
24682                "Saturday",
24683                7,
24684            ),
24685            "oshun" | "oxum" => (
24686                "Ọṣun",
24687                "Yellow, gold",
24688                "#FFD700",
24689                "Rivers, love, fertility",
24690                "Saturday",
24691                5,
24692            ),
24693            "shango" | "xango" => (
24694                "Ṣàngó",
24695                "Red, white",
24696                "#FF0000",
24697                "Thunder, fire, justice",
24698                "Wednesday",
24699                6,
24700            ),
24701            "ogun" | "ogum" => (
24702                "Ògún",
24703                "Green, black",
24704                "#006400",
24705                "Iron, war, labor",
24706                "Tuesday",
24707                7,
24708            ),
24709            "oya" | "iansa" => (
24710                "Ọya",
24711                "Brown, purple",
24712                "#800020",
24713                "Wind, storms, change",
24714                "Wednesday",
24715                9,
24716            ),
24717            "eshu" | "exu" => (
24718                "Èṣù",
24719                "Red, black",
24720                "#8B0000",
24721                "Crossroads, messages",
24722                "Monday",
24723                3,
24724            ),
24725            _ => {
24726                return Err(RuntimeError::new(
24727                    "Unknown Orisha. Use obatala/yemoja/oshun/shango/ogun/oya/eshu",
24728                ))
24729            }
24730        };
24731        let mut map = std::collections::HashMap::new();
24732        map.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
24733        map.insert(
24734            "colors".to_string(),
24735            Value::String(Rc::new(colors.to_string())),
24736        );
24737        map.insert("hex".to_string(), Value::String(Rc::new(hex.to_string())));
24738        map.insert(
24739            "domain".to_string(),
24740            Value::String(Rc::new(domain.to_string())),
24741        );
24742        map.insert("day".to_string(), Value::String(Rc::new(day.to_string())));
24743        map.insert("number".to_string(), Value::Int(number));
24744        Ok(Value::Map(Rc::new(RefCell::new(map))))
24745    });
24746
24747    // =========================================================================
24748    // JAPANESE TRADITIONAL COLORS (nihon_iro)
24749    // =========================================================================
24750    define(interp, "nihon_iro", Some(1), |_, args| {
24751        let color = match &args[0] {
24752            Value::String(s) => s.to_lowercase(),
24753            _ => return Err(RuntimeError::new("requires string")),
24754        };
24755        let (name, japanese, hex, meaning, season) = match color.as_str() {
24756            "sakura" => (
24757                "Sakura Pink",
24758                "桜色",
24759                "#FFB7C5",
24760                "Cherry blossoms, transience",
24761                "Spring",
24762            ),
24763            "fuji" => (
24764                "Wisteria",
24765                "藤色",
24766                "#C9A0DC",
24767                "Elegance, nobility",
24768                "Spring",
24769            ),
24770            "moegi" => (
24771                "Young Green",
24772                "萌黄",
24773                "#AACF53",
24774                "New growth, freshness",
24775                "Spring",
24776            ),
24777            "ai" => ("Indigo", "藍色", "#004D99", "Protection, depth", "All"),
24778            "akane" => ("Madder Red", "茜色", "#CF3A24", "Sunset, passion", "Autumn"),
24779            "shiro" => ("White", "白", "#FFFFFF", "Purity, death, sacred", "Winter"),
24780            "kuro" => ("Black", "黒", "#000000", "Formality, mystery", "All"),
24781            "aka" => ("Red", "赤", "#D7003A", "Life force, celebration", "All"),
24782            "murasaki" => ("Purple", "紫", "#884898", "Nobility, spirituality", "All"),
24783            _ => {
24784                return Err(RuntimeError::new(
24785                    "Unknown color. Try: sakura/fuji/moegi/ai/akane/shiro/kuro/aka/murasaki",
24786                ))
24787            }
24788        };
24789        let mut map = std::collections::HashMap::new();
24790        map.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
24791        map.insert(
24792            "japanese".to_string(),
24793            Value::String(Rc::new(japanese.to_string())),
24794        );
24795        map.insert("hex".to_string(), Value::String(Rc::new(hex.to_string())));
24796        map.insert(
24797            "meaning".to_string(),
24798            Value::String(Rc::new(meaning.to_string())),
24799        );
24800        map.insert(
24801            "season".to_string(),
24802            Value::String(Rc::new(season.to_string())),
24803        );
24804        Ok(Value::Map(Rc::new(RefCell::new(map))))
24805    });
24806
24807    // =========================================================================
24808    // ISLAMIC COLOR SYMBOLISM
24809    // =========================================================================
24810    define(interp, "islamic_color", Some(1), |_, args| {
24811        let color = match &args[0] {
24812            Value::String(s) => s.to_lowercase(),
24813            _ => return Err(RuntimeError::new("requires string")),
24814        };
24815        let (name, arabic, hex, meaning, usage) = match color.as_str() {
24816            "green" | "akhdar" => (
24817                "Green",
24818                "أخضر",
24819                "#00FF00",
24820                "Paradise, Prophet, life",
24821                "Mosques, Quran, flags",
24822            ),
24823            "white" | "abyad" => (
24824                "White",
24825                "أبيض",
24826                "#FFFFFF",
24827                "Purity, peace, ihram",
24828                "Pilgrimage, burial",
24829            ),
24830            "black" | "aswad" => (
24831                "Black",
24832                "أسود",
24833                "#000000",
24834                "Modesty, Kaaba",
24835                "Kiswah, abaya",
24836            ),
24837            "gold" | "dhahabi" => (
24838                "Gold",
24839                "ذهبي",
24840                "#FFD700",
24841                "Paradise, divine light",
24842                "Calligraphy, decoration",
24843            ),
24844            "blue" | "azraq" => (
24845                "Blue",
24846                "أزرق",
24847                "#0000CD",
24848                "Protection, heaven",
24849                "Tiles, evil eye",
24850            ),
24851            _ => {
24852                return Err(RuntimeError::new(
24853                    "Unknown color. Use green/white/black/gold/blue",
24854                ))
24855            }
24856        };
24857        let mut map = std::collections::HashMap::new();
24858        map.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
24859        map.insert(
24860            "arabic".to_string(),
24861            Value::String(Rc::new(arabic.to_string())),
24862        );
24863        map.insert("hex".to_string(), Value::String(Rc::new(hex.to_string())));
24864        map.insert(
24865            "meaning".to_string(),
24866            Value::String(Rc::new(meaning.to_string())),
24867        );
24868        map.insert(
24869            "usage".to_string(),
24870            Value::String(Rc::new(usage.to_string())),
24871        );
24872        Ok(Value::Map(Rc::new(RefCell::new(map))))
24873    });
24874
24875    // =========================================================================
24876    // THAI DAY COLORS
24877    // =========================================================================
24878    define(interp, "thai_day_color", Some(1), |_, args| {
24879        let day = match &args[0] {
24880            Value::String(s) => s.to_lowercase(),
24881            Value::Int(n) => n.to_string(),
24882            _ => return Err(RuntimeError::new("requires string or number")),
24883        };
24884        let (day_name, thai, color, hex, deity) = match day.as_str() {
24885            "sunday" | "0" => ("Sunday", "วันอาทิตย์", "Red", "#FF0000", "Surya"),
24886            "monday" | "1" => ("Monday", "วันจันทร์", "Yellow", "#FFFF00", "Chandra"),
24887            "tuesday" | "2" => ("Tuesday", "วันอังคาร", "Pink", "#FFC0CB", "Mangala"),
24888            "wednesday" | "3" => ("Wednesday", "วันพุธ", "Green", "#00FF00", "Budha"),
24889            "thursday" | "4" => ("Thursday", "วันพฤหัสบดี", "Orange", "#FFA500", "Brihaspati"),
24890            "friday" | "5" => ("Friday", "วันศุกร์", "Blue", "#00BFFF", "Shukra"),
24891            "saturday" | "6" => ("Saturday", "วันเสาร์", "Purple", "#800080", "Shani"),
24892            _ => return Err(RuntimeError::new("Unknown day. Use sunday-saturday or 0-6")),
24893        };
24894        let mut map = std::collections::HashMap::new();
24895        map.insert(
24896            "day".to_string(),
24897            Value::String(Rc::new(day_name.to_string())),
24898        );
24899        map.insert("thai".to_string(), Value::String(Rc::new(thai.to_string())));
24900        map.insert(
24901            "color".to_string(),
24902            Value::String(Rc::new(color.to_string())),
24903        );
24904        map.insert("hex".to_string(), Value::String(Rc::new(hex.to_string())));
24905        map.insert(
24906            "deity".to_string(),
24907            Value::String(Rc::new(deity.to_string())),
24908        );
24909        Ok(Value::Map(Rc::new(RefCell::new(map))))
24910    });
24911
24912    // =========================================================================
24913    // ABORIGINAL AUSTRALIAN COLORS
24914    // =========================================================================
24915    define(interp, "aboriginal_color", Some(1), |_, args| {
24916        let color = match &args[0] {
24917            Value::String(s) => s.to_lowercase(),
24918            _ => return Err(RuntimeError::new("requires string")),
24919        };
24920        let (name, hex, meaning, source, dreamtime) = match color.as_str() {
24921            "red" | "ochre" => (
24922                "Red Ochre",
24923                "#CC5500",
24924                "Earth, blood, ceremony",
24925                "Hematite",
24926                "Ancestral beings",
24927            ),
24928            "yellow" => (
24929                "Yellow Ochre",
24930                "#D4A017",
24931                "Sun, healing",
24932                "Limonite",
24933                "Sun's journey",
24934            ),
24935            "white" => (
24936                "White",
24937                "#FFFFFF",
24938                "Sky, spirits, mourning",
24939                "Kaolin",
24940                "Sky beings",
24941            ),
24942            "black" => (
24943                "Black",
24944                "#000000",
24945                "Night, formality",
24946                "Charcoal",
24947                "Night, men's business",
24948            ),
24949            "brown" => (
24950                "Brown",
24951                "#8B4513",
24952                "Earth, land",
24953                "Earth pigments",
24954                "Country, connection",
24955            ),
24956            _ => {
24957                return Err(RuntimeError::new(
24958                    "Unknown color. Use red/yellow/white/black/brown",
24959                ))
24960            }
24961        };
24962        let mut map = std::collections::HashMap::new();
24963        map.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
24964        map.insert("hex".to_string(), Value::String(Rc::new(hex.to_string())));
24965        map.insert(
24966            "meaning".to_string(),
24967            Value::String(Rc::new(meaning.to_string())),
24968        );
24969        map.insert(
24970            "source".to_string(),
24971            Value::String(Rc::new(source.to_string())),
24972        );
24973        map.insert(
24974            "dreamtime".to_string(),
24975            Value::String(Rc::new(dreamtime.to_string())),
24976        );
24977        Ok(Value::Map(Rc::new(RefCell::new(map))))
24978    });
24979
24980    // =========================================================================
24981    // CELTIC COLORS
24982    // =========================================================================
24983    define(interp, "celtic_color", Some(1), |_, args| {
24984        let color = match &args[0] {
24985            Value::String(s) => s.to_lowercase(),
24986            _ => return Err(RuntimeError::new("requires string")),
24987        };
24988        let (name, gaelic, hex, meaning, element) = match color.as_str() {
24989            "green" => (
24990                "Green",
24991                "Glas",
24992                "#228B22",
24993                "Nature, fairies, Otherworld",
24994                "Earth",
24995            ),
24996            "white" => ("White", "Bán", "#FFFFFF", "Purity, spirits", "Air"),
24997            "red" => ("Red", "Dearg", "#FF0000", "War, courage, blood", "Fire"),
24998            "black" => (
24999                "Black",
25000                "Dubh",
25001                "#000000",
25002                "Otherworld, death, rebirth",
25003                "Water",
25004            ),
25005            "gold" => ("Gold", "Órga", "#FFD700", "Sun, sovereignty, Lugh", "Fire"),
25006            "silver" => (
25007                "Silver",
25008                "Airgid",
25009                "#C0C0C0",
25010                "Moon, feminine, intuition",
25011                "Water",
25012            ),
25013            _ => {
25014                return Err(RuntimeError::new(
25015                    "Unknown color. Use green/white/red/black/gold/silver",
25016                ))
25017            }
25018        };
25019        let mut map = std::collections::HashMap::new();
25020        map.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
25021        map.insert(
25022            "gaelic".to_string(),
25023            Value::String(Rc::new(gaelic.to_string())),
25024        );
25025        map.insert("hex".to_string(), Value::String(Rc::new(hex.to_string())));
25026        map.insert(
25027            "meaning".to_string(),
25028            Value::String(Rc::new(meaning.to_string())),
25029        );
25030        map.insert(
25031            "element".to_string(),
25032            Value::String(Rc::new(element.to_string())),
25033        );
25034        Ok(Value::Map(Rc::new(RefCell::new(map))))
25035    });
25036
25037    // =========================================================================
25038    // KENTE CLOTH COLORS (Ghana)
25039    // =========================================================================
25040    define(interp, "kente_color", Some(1), |_, args| {
25041        let color = match &args[0] {
25042            Value::String(s) => s.to_lowercase(),
25043            _ => return Err(RuntimeError::new("requires string")),
25044        };
25045        let (name, twi, hex, meaning) = match color.as_str() {
25046            "gold" | "yellow" => ("Gold", "Sika Kɔkɔɔ", "#FFD700", "Royalty, wealth, glory"),
25047            "green" => ("Green", "Ahabammono", "#228B22", "Growth, renewal, harvest"),
25048            "blue" => ("Blue", "Bruu", "#0000CD", "Peace, harmony, love"),
25049            "red" => ("Red", "Kɔkɔɔ", "#FF0000", "Blood, sacrifice, power"),
25050            "black" => ("Black", "Tuntum", "#000000", "Maturation, ancestors"),
25051            "white" => ("White", "Fitaa", "#FFFFFF", "Purification, virtue, joy"),
25052            "maroon" => ("Maroon", "Borɔnɔ", "#800000", "Earth, healing, protection"),
25053            _ => {
25054                return Err(RuntimeError::new(
25055                    "Unknown color. Use gold/green/blue/red/black/white/maroon",
25056                ))
25057            }
25058        };
25059        let mut map = std::collections::HashMap::new();
25060        map.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
25061        map.insert("twi".to_string(), Value::String(Rc::new(twi.to_string())));
25062        map.insert("hex".to_string(), Value::String(Rc::new(hex.to_string())));
25063        map.insert(
25064            "meaning".to_string(),
25065            Value::String(Rc::new(meaning.to_string())),
25066        );
25067        Ok(Value::Map(Rc::new(RefCell::new(map))))
25068    });
25069
25070    // =========================================================================
25071    // HINDU COLOR SYMBOLISM
25072    // =========================================================================
25073    define(interp, "hindu_color", Some(1), |_, args| {
25074        let color = match &args[0] {
25075            Value::String(s) => s.to_lowercase(),
25076            _ => return Err(RuntimeError::new("requires string")),
25077        };
25078        let (name, hindi, hex, meaning, deities) = match color.as_str() {
25079            "red" | "lal" => (
25080                "Red",
25081                "लाल",
25082                "#FF0000",
25083                "Purity, fertility, love",
25084                "Durga, Lakshmi",
25085            ),
25086            "orange" | "saffron" => (
25087                "Saffron",
25088                "केसरी",
25089                "#FF6600",
25090                "Sacred, renunciation",
25091                "Hanuman",
25092            ),
25093            "yellow" => (
25094                "Yellow",
25095                "पीला",
25096                "#FFFF00",
25097                "Knowledge, learning",
25098                "Vishnu, Saraswati",
25099            ),
25100            "green" => ("Green", "हरा", "#008000", "Life, happiness", "Krishna"),
25101            "white" => (
25102                "White",
25103                "सफ़ेद",
25104                "#FFFFFF",
25105                "Purity, mourning",
25106                "Saraswati, Shiva",
25107            ),
25108            "blue" => (
25109                "Blue",
25110                "नीला",
25111                "#0000FF",
25112                "Divinity, infinity",
25113                "Krishna, Vishnu",
25114            ),
25115            "black" => (
25116                "Black",
25117                "काला",
25118                "#000000",
25119                "Protection from evil",
25120                "Kali, Shani",
25121            ),
25122            _ => {
25123                return Err(RuntimeError::new(
25124                    "Unknown color. Use red/orange/yellow/green/white/blue/black",
25125                ))
25126            }
25127        };
25128        let mut map = std::collections::HashMap::new();
25129        map.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
25130        map.insert(
25131            "hindi".to_string(),
25132            Value::String(Rc::new(hindi.to_string())),
25133        );
25134        map.insert("hex".to_string(), Value::String(Rc::new(hex.to_string())));
25135        map.insert(
25136            "meaning".to_string(),
25137            Value::String(Rc::new(meaning.to_string())),
25138        );
25139        map.insert(
25140            "deities".to_string(),
25141            Value::String(Rc::new(deities.to_string())),
25142        );
25143        Ok(Value::Map(Rc::new(RefCell::new(map))))
25144    });
25145
25146    // =========================================================================
25147    // SYNESTHESIA - CROSS-MODAL MAPPING WITH CULTURAL CONTEXT
25148    // =========================================================================
25149    define(interp, "emotion_color", Some(2), |_, args| {
25150        let emotion = match &args[0] {
25151            Value::String(s) => s.to_lowercase(),
25152            _ => return Err(RuntimeError::new("requires string")),
25153        };
25154        let culture = match &args[1] {
25155            Value::String(s) => s.to_lowercase(),
25156            _ => return Err(RuntimeError::new("requires string")),
25157        };
25158        let (hex, name, reasoning) = match (emotion.as_str(), culture.as_str()) {
25159            ("joy", "western") | ("happy", "western") => {
25160                ("#FFD700", "Gold", "Sunshine = happiness")
25161            }
25162            ("joy", "chinese") | ("happy", "chinese") => ("#FF0000", "Red", "红 = luck, joy"),
25163            ("joy", "japanese") => ("#FFB7C5", "Sakura", "Cherry blossom = fleeting joy"),
25164            ("sadness", "western") | ("sad", "western") => ("#0000CD", "Blue", "'Feeling blue'"),
25165            ("sadness", "chinese") | ("sad", "chinese") => ("#FFFFFF", "White", "白 = mourning"),
25166            ("sadness", "indian") => ("#FFFFFF", "White", "सफ़ेद = mourning"),
25167            ("anger", _) => ("#FF0000", "Red", "Universal heat/fire"),
25168            ("love", "western") => ("#FF69B4", "Pink", "Valentine's hearts"),
25169            ("love", "chinese") | ("love", "indian") => ("#FF0000", "Red", "Red = marriage, love"),
25170            ("peace", "western") => ("#ADD8E6", "Light Blue", "Sky, serenity"),
25171            ("peace", "islamic") => ("#00FF00", "Green", "السلام = paradise"),
25172            ("fear", _) => ("#4B0082", "Indigo", "Deep, mysterious"),
25173            (_, _) => ("#808080", "Grey", "Neutral"),
25174        };
25175        let r = u8::from_str_radix(&hex[1..3], 16).unwrap_or(128);
25176        let g = u8::from_str_radix(&hex[3..5], 16).unwrap_or(128);
25177        let b = u8::from_str_radix(&hex[5..7], 16).unwrap_or(128);
25178        let mut map = std::collections::HashMap::new();
25179        map.insert("hex".to_string(), Value::String(Rc::new(hex.to_string())));
25180        map.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
25181        map.insert("r".to_string(), Value::Int(r as i64));
25182        map.insert("g".to_string(), Value::Int(g as i64));
25183        map.insert("b".to_string(), Value::Int(b as i64));
25184        map.insert(
25185            "reasoning".to_string(),
25186            Value::String(Rc::new(reasoning.to_string())),
25187        );
25188        Ok(Value::Map(Rc::new(RefCell::new(map))))
25189    });
25190
25191    // synesthesia - full cross-modal with cultural awareness
25192    define(interp, "synesthesia", Some(2), |_, args| {
25193        let culture = match &args[1] {
25194            Value::String(s) => s.to_lowercase(),
25195            _ => return Err(RuntimeError::new("requires culture string")),
25196        };
25197        let (r, g, b, emotion, freq) = match &args[0] {
25198            Value::String(s) => match s.to_lowercase().as_str() {
25199                "joy" | "happy" => (255u8, 215u8, 0u8, "joy", 528.0),
25200                "sadness" | "sad" => (0, 0, 139, "sadness", 396.0),
25201                "anger" => (255, 0, 0, "anger", 417.0),
25202                "fear" => (75, 0, 130, "fear", 369.0),
25203                "love" => (255, 105, 180, "love", 639.0),
25204                "peace" => (135, 206, 235, "peace", 741.0),
25205                _ => (128, 128, 128, "neutral", 432.0),
25206            },
25207            Value::Int(n) => (128, 128, 255, "resonance", *n as f64),
25208            Value::Float(f) => (128, 128, 255, "resonance", *f),
25209            _ => (128, 128, 128, "neutral", 432.0),
25210        };
25211        let cultural_meaning = match culture.as_str() {
25212            "chinese" if r > 200 && g < 100 => "luck/joy (红)",
25213            "japanese" if r > 200 && g < 100 => "vitality (赤)",
25214            "indian" if r > 200 && g < 100 => "shakti/auspicious",
25215            _ => "universal resonance",
25216        };
25217        let chakra = if r > 200 && g < 100 {
25218            "Root"
25219        } else if g > 200 {
25220            "Heart"
25221        } else if b > 200 {
25222            "Throat"
25223        } else {
25224            "Crown"
25225        };
25226        let wu_xing = if r > 200 && g < 100 {
25227            "Fire (火)"
25228        } else if g > 200 {
25229            "Wood (木)"
25230        } else if b > 200 {
25231            "Water (水)"
25232        } else {
25233            "Metal (金)"
25234        };
25235        let mut map = std::collections::HashMap::new();
25236        let mut color_map = std::collections::HashMap::new();
25237        color_map.insert("r".to_string(), Value::Int(r as i64));
25238        color_map.insert("g".to_string(), Value::Int(g as i64));
25239        color_map.insert("b".to_string(), Value::Int(b as i64));
25240        color_map.insert(
25241            "hex".to_string(),
25242            Value::String(Rc::new(format!("#{:02X}{:02X}{:02X}", r, g, b))),
25243        );
25244        map.insert(
25245            "color".to_string(),
25246            Value::Map(Rc::new(RefCell::new(color_map))),
25247        );
25248        map.insert(
25249            "emotion".to_string(),
25250            Value::String(Rc::new(emotion.to_string())),
25251        );
25252        map.insert("frequency".to_string(), Value::Float(freq));
25253        map.insert(
25254            "cultural_meaning".to_string(),
25255            Value::String(Rc::new(cultural_meaning.to_string())),
25256        );
25257        map.insert(
25258            "chakra".to_string(),
25259            Value::String(Rc::new(chakra.to_string())),
25260        );
25261        map.insert(
25262            "wu_xing".to_string(),
25263            Value::String(Rc::new(wu_xing.to_string())),
25264        );
25265        Ok(Value::Map(Rc::new(RefCell::new(map))))
25266    });
25267
25268    // color_to_sound - Scriabin-inspired mapping
25269    define(interp, "color_to_sound", Some(3), |_, args| {
25270        let r = match &args[0] {
25271            Value::Int(n) => *n as f64 / 255.0,
25272            Value::Float(f) => *f / 255.0,
25273            _ => return Err(RuntimeError::new("requires numbers")),
25274        };
25275        let g = match &args[1] {
25276            Value::Int(n) => *n as f64 / 255.0,
25277            Value::Float(f) => *f / 255.0,
25278            _ => return Err(RuntimeError::new("requires numbers")),
25279        };
25280        let b = match &args[2] {
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 max = r.max(g).max(b);
25286        let min = r.min(g).min(b);
25287        let l = (max + min) / 2.0;
25288        let h = if max == min {
25289            0.0
25290        } else {
25291            let d = max - min;
25292            if max == r {
25293                (g - b) / d + if g < b { 6.0 } else { 0.0 }
25294            } else if max == g {
25295                (b - r) / d + 2.0
25296            } else {
25297                (r - g) / d + 4.0
25298            }
25299        } * 60.0;
25300        let (note, freq) = if h < 30.0 {
25301            ("C", 261.63)
25302        } else if h < 60.0 {
25303            ("G", 392.00)
25304        } else if h < 90.0 {
25305            ("D", 293.66)
25306        } else if h < 120.0 {
25307            ("A", 440.00)
25308        } else if h < 150.0 {
25309            ("E", 329.63)
25310        } else if h < 180.0 {
25311            ("B", 493.88)
25312        } else if h < 210.0 {
25313            ("F#", 369.99)
25314        } else if h < 240.0 {
25315            ("Db", 277.18)
25316        } else if h < 270.0 {
25317            ("Ab", 415.30)
25318        } else if h < 300.0 {
25319            ("Eb", 311.13)
25320        } else if h < 330.0 {
25321            ("Bb", 466.16)
25322        } else {
25323            ("F", 349.23)
25324        };
25325        let octave_shift = ((l - 0.5) * 4.0).round() as i32;
25326        let adjusted_freq = freq * 2.0_f64.powi(octave_shift);
25327        let mut map = std::collections::HashMap::new();
25328        map.insert("note".to_string(), Value::String(Rc::new(note.to_string())));
25329        map.insert("frequency".to_string(), Value::Float(adjusted_freq));
25330        map.insert("hue".to_string(), Value::Float(h));
25331        Ok(Value::Map(Rc::new(RefCell::new(map))))
25332    });
25333
25334    // contrast_ratio - WCAG accessibility
25335    define(interp, "contrast_ratio", Some(6), |_, args| {
25336        fn lum(r: f64, g: f64, b: f64) -> f64 {
25337            fn ch(c: f64) -> f64 {
25338                let c = c / 255.0;
25339                if c <= 0.03928 {
25340                    c / 12.92
25341                } else {
25342                    ((c + 0.055) / 1.055).powf(2.4)
25343                }
25344            }
25345            0.2126 * ch(r) + 0.7152 * ch(g) + 0.0722 * ch(b)
25346        }
25347        let r1 = match &args[0] {
25348            Value::Int(n) => *n as f64,
25349            Value::Float(f) => *f,
25350            _ => return Err(RuntimeError::new("requires numbers")),
25351        };
25352        let g1 = match &args[1] {
25353            Value::Int(n) => *n as f64,
25354            Value::Float(f) => *f,
25355            _ => return Err(RuntimeError::new("requires numbers")),
25356        };
25357        let b1 = match &args[2] {
25358            Value::Int(n) => *n as f64,
25359            Value::Float(f) => *f,
25360            _ => return Err(RuntimeError::new("requires numbers")),
25361        };
25362        let r2 = match &args[3] {
25363            Value::Int(n) => *n as f64,
25364            Value::Float(f) => *f,
25365            _ => return Err(RuntimeError::new("requires numbers")),
25366        };
25367        let g2 = match &args[4] {
25368            Value::Int(n) => *n as f64,
25369            Value::Float(f) => *f,
25370            _ => return Err(RuntimeError::new("requires numbers")),
25371        };
25372        let b2 = match &args[5] {
25373            Value::Int(n) => *n as f64,
25374            Value::Float(f) => *f,
25375            _ => return Err(RuntimeError::new("requires numbers")),
25376        };
25377        let l1 = lum(r1, g1, b1);
25378        let l2 = lum(r2, g2, b2);
25379        let ratio = if l1 > l2 {
25380            (l1 + 0.05) / (l2 + 0.05)
25381        } else {
25382            (l2 + 0.05) / (l1 + 0.05)
25383        };
25384        let mut map = std::collections::HashMap::new();
25385        map.insert("ratio".to_string(), Value::Float(ratio));
25386        map.insert("aa_normal".to_string(), Value::Bool(ratio >= 4.5));
25387        map.insert("aa_large".to_string(), Value::Bool(ratio >= 3.0));
25388        map.insert("aaa_normal".to_string(), Value::Bool(ratio >= 7.0));
25389        Ok(Value::Map(Rc::new(RefCell::new(map))))
25390    });
25391}
25392
25393// ============================================================================
25394// PROTOCOL FUNCTIONS (Phase 17)
25395// ============================================================================
25396
25397/// Register protocol functions for HTTP, gRPC, WebSocket, Kafka, AMQP, GraphQL
25398/// Note: Actual async network operations require runtime support.
25399/// These functions provide protocol information and synchronous utilities.
25400fn register_protocol(interp: &mut Interpreter) {
25401    // protocol_info - Get information about supported protocols
25402    define(interp, "protocol_info", Some(0), |_, _args| {
25403        let mut map = std::collections::HashMap::new();
25404        map.insert(
25405            "http".to_string(),
25406            Value::Map(Rc::new(RefCell::new({
25407                let mut m = std::collections::HashMap::new();
25408                m.insert(
25409                    "name".to_string(),
25410                    Value::String(Rc::new("HTTP".to_string())),
25411                );
25412                m.insert(
25413                    "versions".to_string(),
25414                    Value::Array(Rc::new(RefCell::new(vec![
25415                        Value::String(Rc::new("1.1".to_string())),
25416                        Value::String(Rc::new("2".to_string())),
25417                    ]))),
25418                );
25419                m.insert(
25420                    "methods".to_string(),
25421                    Value::Array(Rc::new(RefCell::new(vec![
25422                        Value::String(Rc::new("GET".to_string())),
25423                        Value::String(Rc::new("POST".to_string())),
25424                        Value::String(Rc::new("PUT".to_string())),
25425                        Value::String(Rc::new("DELETE".to_string())),
25426                        Value::String(Rc::new("PATCH".to_string())),
25427                        Value::String(Rc::new("HEAD".to_string())),
25428                        Value::String(Rc::new("OPTIONS".to_string())),
25429                    ]))),
25430                );
25431                m
25432            }))),
25433        );
25434        map.insert(
25435            "grpc".to_string(),
25436            Value::Map(Rc::new(RefCell::new({
25437                let mut m = std::collections::HashMap::new();
25438                m.insert(
25439                    "name".to_string(),
25440                    Value::String(Rc::new("gRPC".to_string())),
25441                );
25442                m.insert(
25443                    "streaming_modes".to_string(),
25444                    Value::Array(Rc::new(RefCell::new(vec![
25445                        Value::String(Rc::new("unary".to_string())),
25446                        Value::String(Rc::new("server_streaming".to_string())),
25447                        Value::String(Rc::new("client_streaming".to_string())),
25448                        Value::String(Rc::new("bidirectional".to_string())),
25449                    ]))),
25450                );
25451                m
25452            }))),
25453        );
25454        map.insert(
25455            "websocket".to_string(),
25456            Value::Map(Rc::new(RefCell::new({
25457                let mut m = std::collections::HashMap::new();
25458                m.insert(
25459                    "name".to_string(),
25460                    Value::String(Rc::new("WebSocket".to_string())),
25461                );
25462                m.insert(
25463                    "message_types".to_string(),
25464                    Value::Array(Rc::new(RefCell::new(vec![
25465                        Value::String(Rc::new("text".to_string())),
25466                        Value::String(Rc::new("binary".to_string())),
25467                        Value::String(Rc::new("ping".to_string())),
25468                        Value::String(Rc::new("pong".to_string())),
25469                        Value::String(Rc::new("close".to_string())),
25470                    ]))),
25471                );
25472                m
25473            }))),
25474        );
25475        map.insert(
25476            "kafka".to_string(),
25477            Value::Map(Rc::new(RefCell::new({
25478                let mut m = std::collections::HashMap::new();
25479                m.insert(
25480                    "name".to_string(),
25481                    Value::String(Rc::new("Apache Kafka".to_string())),
25482                );
25483                m.insert(
25484                    "acks".to_string(),
25485                    Value::Array(Rc::new(RefCell::new(vec![
25486                        Value::String(Rc::new("none".to_string())),
25487                        Value::String(Rc::new("leader".to_string())),
25488                        Value::String(Rc::new("all".to_string())),
25489                    ]))),
25490                );
25491                m
25492            }))),
25493        );
25494        map.insert(
25495            "amqp".to_string(),
25496            Value::Map(Rc::new(RefCell::new({
25497                let mut m = std::collections::HashMap::new();
25498                m.insert(
25499                    "name".to_string(),
25500                    Value::String(Rc::new("AMQP".to_string())),
25501                );
25502                m.insert(
25503                    "exchange_types".to_string(),
25504                    Value::Array(Rc::new(RefCell::new(vec![
25505                        Value::String(Rc::new("direct".to_string())),
25506                        Value::String(Rc::new("fanout".to_string())),
25507                        Value::String(Rc::new("topic".to_string())),
25508                        Value::String(Rc::new("headers".to_string())),
25509                    ]))),
25510                );
25511                m
25512            }))),
25513        );
25514        map.insert(
25515            "graphql".to_string(),
25516            Value::Map(Rc::new(RefCell::new({
25517                let mut m = std::collections::HashMap::new();
25518                m.insert(
25519                    "name".to_string(),
25520                    Value::String(Rc::new("GraphQL".to_string())),
25521                );
25522                m.insert(
25523                    "operations".to_string(),
25524                    Value::Array(Rc::new(RefCell::new(vec![
25525                        Value::String(Rc::new("query".to_string())),
25526                        Value::String(Rc::new("mutation".to_string())),
25527                        Value::String(Rc::new("subscription".to_string())),
25528                    ]))),
25529                );
25530                m
25531            }))),
25532        );
25533        Ok(Value::Map(Rc::new(RefCell::new(map))))
25534    });
25535
25536    // http_status_text - Get status text for HTTP status code
25537    define(interp, "http_status_text", Some(1), |_, args| {
25538        let code = match &args[0] {
25539            Value::Int(n) => *n,
25540            _ => {
25541                return Err(RuntimeError::new(
25542                    "http_status_text requires integer status code",
25543                ))
25544            }
25545        };
25546        let text = match code {
25547            100 => "Continue",
25548            101 => "Switching Protocols",
25549            200 => "OK",
25550            201 => "Created",
25551            202 => "Accepted",
25552            204 => "No Content",
25553            301 => "Moved Permanently",
25554            302 => "Found",
25555            304 => "Not Modified",
25556            307 => "Temporary Redirect",
25557            308 => "Permanent Redirect",
25558            400 => "Bad Request",
25559            401 => "Unauthorized",
25560            403 => "Forbidden",
25561            404 => "Not Found",
25562            405 => "Method Not Allowed",
25563            409 => "Conflict",
25564            422 => "Unprocessable Entity",
25565            429 => "Too Many Requests",
25566            500 => "Internal Server Error",
25567            502 => "Bad Gateway",
25568            503 => "Service Unavailable",
25569            504 => "Gateway Timeout",
25570            _ => "Unknown",
25571        };
25572        Ok(Value::String(Rc::new(text.to_string())))
25573    });
25574
25575    // http_status_type - Get status type (informational, success, redirect, client_error, server_error)
25576    define(interp, "http_status_type", Some(1), |_, args| {
25577        let code = match &args[0] {
25578            Value::Int(n) => *n,
25579            _ => {
25580                return Err(RuntimeError::new(
25581                    "http_status_type requires integer status code",
25582                ))
25583            }
25584        };
25585        let status_type = match code {
25586            100..=199 => "informational",
25587            200..=299 => "success",
25588            300..=399 => "redirect",
25589            400..=499 => "client_error",
25590            500..=599 => "server_error",
25591            _ => "unknown",
25592        };
25593        Ok(Value::String(Rc::new(status_type.to_string())))
25594    });
25595
25596    // grpc_status_text - Get status text for gRPC status code
25597    define(interp, "grpc_status_text", Some(1), |_, args| {
25598        let code = match &args[0] {
25599            Value::Int(n) => *n,
25600            _ => {
25601                return Err(RuntimeError::new(
25602                    "grpc_status_text requires integer status code",
25603                ))
25604            }
25605        };
25606        let text = match code {
25607            0 => "OK",
25608            1 => "CANCELLED",
25609            2 => "UNKNOWN",
25610            3 => "INVALID_ARGUMENT",
25611            4 => "DEADLINE_EXCEEDED",
25612            5 => "NOT_FOUND",
25613            6 => "ALREADY_EXISTS",
25614            7 => "PERMISSION_DENIED",
25615            8 => "RESOURCE_EXHAUSTED",
25616            9 => "FAILED_PRECONDITION",
25617            10 => "ABORTED",
25618            11 => "OUT_OF_RANGE",
25619            12 => "UNIMPLEMENTED",
25620            13 => "INTERNAL",
25621            14 => "UNAVAILABLE",
25622            15 => "DATA_LOSS",
25623            16 => "UNAUTHENTICATED",
25624            _ => "UNKNOWN",
25625        };
25626        Ok(Value::String(Rc::new(text.to_string())))
25627    });
25628
25629    // url_parse - Parse a URL into components
25630    define(interp, "url_parse", Some(1), |_, args| {
25631        let url_str = match &args[0] {
25632            Value::String(s) => s.as_str().to_string(),
25633            _ => return Err(RuntimeError::new("url_parse requires string URL")),
25634        };
25635
25636        // Simple URL parsing
25637        let mut map = std::collections::HashMap::new();
25638
25639        // Parse scheme
25640        let (scheme, rest) = if let Some(pos) = url_str.find("://") {
25641            (url_str[..pos].to_string(), &url_str[pos + 3..])
25642        } else {
25643            return Err(RuntimeError::new("Invalid URL: missing scheme"));
25644        };
25645        map.insert("scheme".to_string(), Value::String(Rc::new(scheme)));
25646
25647        // Parse host and path
25648        let (authority, path_and_rest) = if let Some(pos) = rest.find('/') {
25649            (&rest[..pos], &rest[pos..])
25650        } else {
25651            (rest, "/")
25652        };
25653
25654        // Parse host and port
25655        let (host, port) = if let Some(pos) = authority.rfind(':') {
25656            if let Ok(p) = authority[pos + 1..].parse::<i64>() {
25657                (authority[..pos].to_string(), Some(p))
25658            } else {
25659                (authority.to_string(), None)
25660            }
25661        } else {
25662            (authority.to_string(), None)
25663        };
25664        map.insert("host".to_string(), Value::String(Rc::new(host)));
25665        map.insert(
25666            "port".to_string(),
25667            port.map(Value::Int).unwrap_or(Value::Null),
25668        );
25669
25670        // Parse path and query
25671        let (path, query) = if let Some(pos) = path_and_rest.find('?') {
25672            (&path_and_rest[..pos], Some(&path_and_rest[pos + 1..]))
25673        } else {
25674            (path_and_rest, None)
25675        };
25676        map.insert("path".to_string(), Value::String(Rc::new(path.to_string())));
25677        map.insert(
25678            "query".to_string(),
25679            query
25680                .map(|q| Value::String(Rc::new(q.to_string())))
25681                .unwrap_or(Value::Null),
25682        );
25683
25684        Ok(Value::Map(Rc::new(RefCell::new(map))))
25685    });
25686
25687    // url_encode - URL-encode a string
25688    define(interp, "url_encode", Some(1), |_, args| {
25689        let s = match &args[0] {
25690            Value::String(s) => s.as_str(),
25691            _ => return Err(RuntimeError::new("url_encode requires string")),
25692        };
25693        let mut result = String::new();
25694        for c in s.chars() {
25695            match c {
25696                'a'..='z' | 'A'..='Z' | '0'..='9' | '-' | '_' | '.' | '~' => {
25697                    result.push(c);
25698                }
25699                ' ' => result.push_str("%20"),
25700                _ => {
25701                    for b in c.to_string().as_bytes() {
25702                        result.push_str(&format!("%{:02X}", b));
25703                    }
25704                }
25705            }
25706        }
25707        Ok(Value::String(Rc::new(result)))
25708    });
25709
25710    // url_decode - URL-decode a string
25711    define(interp, "url_decode", Some(1), |_, args| {
25712        let s = match &args[0] {
25713            Value::String(s) => s.as_str().to_string(),
25714            _ => return Err(RuntimeError::new("url_decode requires string")),
25715        };
25716        let mut result = Vec::new();
25717        let bytes = s.as_bytes();
25718        let mut i = 0;
25719        while i < bytes.len() {
25720            if bytes[i] == b'%' && i + 2 < bytes.len() {
25721                if let Ok(b) =
25722                    u8::from_str_radix(&String::from_utf8_lossy(&bytes[i + 1..i + 3]), 16)
25723                {
25724                    result.push(b);
25725                    i += 3;
25726                    continue;
25727                }
25728            } else if bytes[i] == b'+' {
25729                result.push(b' ');
25730                i += 1;
25731                continue;
25732            }
25733            result.push(bytes[i]);
25734            i += 1;
25735        }
25736        Ok(Value::String(Rc::new(
25737            String::from_utf8_lossy(&result).to_string(),
25738        )))
25739    });
25740
25741    // ws_close_code_text - Get text for WebSocket close code
25742    define(interp, "ws_close_code_text", Some(1), |_, args| {
25743        let code = match &args[0] {
25744            Value::Int(n) => *n,
25745            _ => {
25746                return Err(RuntimeError::new(
25747                    "ws_close_code_text requires integer code",
25748                ))
25749            }
25750        };
25751        let text = match code {
25752            1000 => "Normal Closure",
25753            1001 => "Going Away",
25754            1002 => "Protocol Error",
25755            1003 => "Unsupported Data",
25756            1005 => "No Status Received",
25757            1006 => "Abnormal Closure",
25758            1007 => "Invalid Payload Data",
25759            1008 => "Policy Violation",
25760            1009 => "Message Too Big",
25761            1010 => "Missing Extension",
25762            1011 => "Internal Error",
25763            1015 => "TLS Handshake Failure",
25764            _ => "Unknown",
25765        };
25766        Ok(Value::String(Rc::new(text.to_string())))
25767    });
25768
25769    // mime_type - Get MIME type for file extension
25770    define(interp, "mime_type", Some(1), |_, args| {
25771        let ext = match &args[0] {
25772            Value::String(s) => s.as_str().to_lowercase(),
25773            _ => return Err(RuntimeError::new("mime_type requires string extension")),
25774        };
25775        let ext = ext.trim_start_matches('.');
25776        let mime = match ext {
25777            "html" | "htm" => "text/html",
25778            "css" => "text/css",
25779            "js" | "mjs" => "text/javascript",
25780            "json" => "application/json",
25781            "xml" => "application/xml",
25782            "txt" => "text/plain",
25783            "csv" => "text/csv",
25784            "png" => "image/png",
25785            "jpg" | "jpeg" => "image/jpeg",
25786            "gif" => "image/gif",
25787            "svg" => "image/svg+xml",
25788            "webp" => "image/webp",
25789            "ico" => "image/x-icon",
25790            "pdf" => "application/pdf",
25791            "zip" => "application/zip",
25792            "gz" | "gzip" => "application/gzip",
25793            "mp3" => "audio/mpeg",
25794            "mp4" => "video/mp4",
25795            "webm" => "video/webm",
25796            "woff" => "font/woff",
25797            "woff2" => "font/woff2",
25798            "ttf" => "font/ttf",
25799            "otf" => "font/otf",
25800            "wasm" => "application/wasm",
25801            "proto" => "application/protobuf",
25802            _ => "application/octet-stream",
25803        };
25804        Ok(Value::String(Rc::new(mime.to_string())))
25805    });
25806
25807    // content_type_parse - Parse Content-Type header
25808    define(interp, "content_type_parse", Some(1), |_, args| {
25809        let ct = match &args[0] {
25810            Value::String(s) => s.as_str().to_string(),
25811            _ => return Err(RuntimeError::new("content_type_parse requires string")),
25812        };
25813        let mut map = std::collections::HashMap::new();
25814        let parts: Vec<&str> = ct.split(';').collect();
25815        map.insert(
25816            "media_type".to_string(),
25817            Value::String(Rc::new(parts[0].trim().to_string())),
25818        );
25819
25820        let mut params = std::collections::HashMap::new();
25821        for part in parts.iter().skip(1) {
25822            let kv: Vec<&str> = part.splitn(2, '=').collect();
25823            if kv.len() == 2 {
25824                let key = kv[0].trim().to_lowercase();
25825                let value = kv[1].trim().trim_matches('"').to_string();
25826                params.insert(key, Value::String(Rc::new(value)));
25827            }
25828        }
25829        map.insert(
25830            "params".to_string(),
25831            Value::Map(Rc::new(RefCell::new(params))),
25832        );
25833        Ok(Value::Map(Rc::new(RefCell::new(map))))
25834    });
25835}
25836
25837// ============================================================================
25838// PHASE 18: AI AGENT INFRASTRUCTURE
25839// ============================================================================
25840// Tools for building AI agents with:
25841// - Tool registry for introspectable function definitions
25842// - LLM client for model calls (OpenAI, Claude, local)
25843// - Agent memory for context and session persistence
25844// - Planning framework for state machines and goal tracking
25845// - Vector operations for embeddings and similarity search
25846
25847/// Global tool registry for agent introspection
25848thread_local! {
25849    static TOOL_REGISTRY: RefCell<HashMap<String, ToolDefinition>> = RefCell::new(HashMap::new());
25850    static AGENT_MEMORY: RefCell<HashMap<String, AgentSession>> = RefCell::new(HashMap::new());
25851    static STATE_MACHINES: RefCell<HashMap<String, StateMachine>> = RefCell::new(HashMap::new());
25852}
25853
25854/// Tool definition for LLM function calling
25855#[derive(Clone)]
25856struct ToolDefinition {
25857    name: String,
25858    description: String,
25859    parameters: Vec<ToolParameter>,
25860    returns: String,
25861    evidence_in: Evidence,
25862    evidence_out: Evidence,
25863    handler: Option<Rc<Function>>,
25864}
25865
25866#[derive(Clone)]
25867struct ToolParameter {
25868    name: String,
25869    param_type: String,
25870    description: String,
25871    required: bool,
25872    evidence: Evidence,
25873}
25874
25875/// Agent session for memory persistence
25876#[derive(Clone)]
25877struct AgentSession {
25878    id: String,
25879    context: HashMap<String, Value>,
25880    history: Vec<(String, String)>, // (role, content)
25881    created_at: u64,
25882    last_accessed: u64,
25883}
25884
25885/// State machine for planning
25886#[derive(Clone)]
25887struct StateMachine {
25888    name: String,
25889    current_state: String,
25890    states: Vec<String>,
25891    transitions: HashMap<String, Vec<(String, String)>>, // from -> [(to, condition)]
25892    history: Vec<(String, u64)>,                         // (state, timestamp)
25893}
25894
25895// ============================================================================
25896// TOOL REGISTRY - Introspectable function definitions for LLM tool_choice
25897// ============================================================================
25898
25899fn register_agent_tools(interp: &mut Interpreter) {
25900    // tool_define - Define a tool with metadata for LLM introspection
25901    // tool_define(name, description, params, returns, handler?)
25902    define(interp, "tool_define", None, |_interp, args| {
25903        if args.len() < 4 {
25904            return Err(RuntimeError::new(
25905                "tool_define requires at least 4 arguments: name, description, params, returns",
25906            ));
25907        }
25908
25909        let name = match &args[0] {
25910            Value::String(s) => s.as_str().to_string(),
25911            _ => return Err(RuntimeError::new("tool name must be a string")),
25912        };
25913
25914        let description = match &args[1] {
25915            Value::String(s) => s.as_str().to_string(),
25916            _ => return Err(RuntimeError::new("tool description must be a string")),
25917        };
25918
25919        // Parse parameters array
25920        let params = match &args[2] {
25921            Value::Array(arr) => {
25922                let arr = arr.borrow();
25923                let mut params = Vec::new();
25924                for param in arr.iter() {
25925                    if let Value::Map(map) = param {
25926                        let map = map.borrow();
25927                        let param_name = map
25928                            .get("name")
25929                            .and_then(|v| {
25930                                if let Value::String(s) = v {
25931                                    Some(s.as_str().to_string())
25932                                } else {
25933                                    None
25934                                }
25935                            })
25936                            .unwrap_or_default();
25937                        let param_type = map
25938                            .get("type")
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_else(|| "any".to_string());
25947                        let param_desc = map
25948                            .get("description")
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_default();
25957                        let required = map
25958                            .get("required")
25959                            .and_then(|v| {
25960                                if let Value::Bool(b) = v {
25961                                    Some(*b)
25962                                } else {
25963                                    None
25964                                }
25965                            })
25966                            .unwrap_or(true);
25967                        let evidence_str = map
25968                            .get("evidence")
25969                            .and_then(|v| {
25970                                if let Value::String(s) = v {
25971                                    Some(s.as_str())
25972                                } else {
25973                                    None
25974                                }
25975                            })
25976                            .unwrap_or("~");
25977                        let evidence = match evidence_str {
25978                            "!" => Evidence::Known,
25979                            "?" => Evidence::Uncertain,
25980                            "~" => Evidence::Reported,
25981                            "‽" => Evidence::Paradox,
25982                            _ => Evidence::Reported,
25983                        };
25984                        params.push(ToolParameter {
25985                            name: param_name,
25986                            param_type,
25987                            description: param_desc,
25988                            required,
25989                            evidence,
25990                        });
25991                    }
25992                }
25993                params
25994            }
25995            _ => Vec::new(),
25996        };
25997
25998        let returns = match &args[3] {
25999            Value::String(s) => s.as_str().to_string(),
26000            _ => "any".to_string(),
26001        };
26002
26003        let handler = if args.len() > 4 {
26004            match &args[4] {
26005                Value::Function(f) => Some(f.clone()),
26006                _ => None,
26007            }
26008        } else {
26009            None
26010        };
26011
26012        let tool = ToolDefinition {
26013            name: name.clone(),
26014            description,
26015            parameters: params,
26016            returns,
26017            evidence_in: Evidence::Reported,
26018            evidence_out: Evidence::Reported,
26019            handler,
26020        };
26021
26022        TOOL_REGISTRY.with(|registry| {
26023            registry.borrow_mut().insert(name.clone(), tool);
26024        });
26025
26026        Ok(Value::String(Rc::new(name)))
26027    });
26028
26029    // tool_list - List all registered tools
26030    define(interp, "tool_list", Some(0), |_, _args| {
26031        let tools: Vec<Value> = TOOL_REGISTRY.with(|registry| {
26032            registry
26033                .borrow()
26034                .keys()
26035                .map(|k| Value::String(Rc::new(k.clone())))
26036                .collect()
26037        });
26038        Ok(Value::Array(Rc::new(RefCell::new(tools))))
26039    });
26040
26041    // tool_get - Get tool definition by name
26042    define(interp, "tool_get", Some(1), |_, args| {
26043        let name = match &args[0] {
26044            Value::String(s) => s.as_str().to_string(),
26045            _ => return Err(RuntimeError::new("tool_get requires string name")),
26046        };
26047
26048        TOOL_REGISTRY.with(|registry| {
26049            if let Some(tool) = registry.borrow().get(&name) {
26050                let mut map = HashMap::new();
26051                map.insert(
26052                    "name".to_string(),
26053                    Value::String(Rc::new(tool.name.clone())),
26054                );
26055                map.insert(
26056                    "description".to_string(),
26057                    Value::String(Rc::new(tool.description.clone())),
26058                );
26059                map.insert(
26060                    "returns".to_string(),
26061                    Value::String(Rc::new(tool.returns.clone())),
26062                );
26063
26064                let params: Vec<Value> = tool
26065                    .parameters
26066                    .iter()
26067                    .map(|p| {
26068                        let mut pmap = HashMap::new();
26069                        pmap.insert("name".to_string(), Value::String(Rc::new(p.name.clone())));
26070                        pmap.insert(
26071                            "type".to_string(),
26072                            Value::String(Rc::new(p.param_type.clone())),
26073                        );
26074                        pmap.insert(
26075                            "description".to_string(),
26076                            Value::String(Rc::new(p.description.clone())),
26077                        );
26078                        pmap.insert("required".to_string(), Value::Bool(p.required));
26079                        Value::Map(Rc::new(RefCell::new(pmap)))
26080                    })
26081                    .collect();
26082                map.insert(
26083                    "parameters".to_string(),
26084                    Value::Array(Rc::new(RefCell::new(params))),
26085                );
26086
26087                Ok(Value::Map(Rc::new(RefCell::new(map))))
26088            } else {
26089                Ok(Value::Null)
26090            }
26091        })
26092    });
26093
26094    // tool_schema - Generate OpenAI/Claude compatible tool schema
26095    define(interp, "tool_schema", Some(1), |_, args| {
26096        let name = match &args[0] {
26097            Value::String(s) => s.as_str().to_string(),
26098            _ => return Err(RuntimeError::new("tool_schema requires string name")),
26099        };
26100
26101        TOOL_REGISTRY.with(|registry| {
26102            if let Some(tool) = registry.borrow().get(&name) {
26103                // Generate OpenAI function calling schema
26104                let mut schema = HashMap::new();
26105                schema.insert(
26106                    "type".to_string(),
26107                    Value::String(Rc::new("function".to_string())),
26108                );
26109
26110                let mut function = HashMap::new();
26111                function.insert(
26112                    "name".to_string(),
26113                    Value::String(Rc::new(tool.name.clone())),
26114                );
26115                function.insert(
26116                    "description".to_string(),
26117                    Value::String(Rc::new(tool.description.clone())),
26118                );
26119
26120                // Build parameters schema (JSON Schema format)
26121                let mut params_schema = HashMap::new();
26122                params_schema.insert(
26123                    "type".to_string(),
26124                    Value::String(Rc::new("object".to_string())),
26125                );
26126
26127                let mut properties = HashMap::new();
26128                let mut required: Vec<Value> = Vec::new();
26129
26130                for param in &tool.parameters {
26131                    let mut prop = HashMap::new();
26132                    let json_type = match param.param_type.as_str() {
26133                        "int" | "i64" | "i32" => "integer",
26134                        "float" | "f64" | "f32" => "number",
26135                        "bool" => "boolean",
26136                        "string" | "str" => "string",
26137                        "array" | "list" => "array",
26138                        "map" | "object" => "object",
26139                        _ => "string",
26140                    };
26141                    prop.insert(
26142                        "type".to_string(),
26143                        Value::String(Rc::new(json_type.to_string())),
26144                    );
26145                    prop.insert(
26146                        "description".to_string(),
26147                        Value::String(Rc::new(param.description.clone())),
26148                    );
26149                    properties.insert(param.name.clone(), Value::Map(Rc::new(RefCell::new(prop))));
26150
26151                    if param.required {
26152                        required.push(Value::String(Rc::new(param.name.clone())));
26153                    }
26154                }
26155
26156                params_schema.insert(
26157                    "properties".to_string(),
26158                    Value::Map(Rc::new(RefCell::new(properties))),
26159                );
26160                params_schema.insert(
26161                    "required".to_string(),
26162                    Value::Array(Rc::new(RefCell::new(required))),
26163                );
26164
26165                function.insert(
26166                    "parameters".to_string(),
26167                    Value::Map(Rc::new(RefCell::new(params_schema))),
26168                );
26169                schema.insert(
26170                    "function".to_string(),
26171                    Value::Map(Rc::new(RefCell::new(function))),
26172                );
26173
26174                Ok(Value::Map(Rc::new(RefCell::new(schema))))
26175            } else {
26176                Err(RuntimeError::new(format!("Tool '{}' not found", name)))
26177            }
26178        })
26179    });
26180
26181    // tool_schemas_all - Get all tool schemas for LLM
26182    define(interp, "tool_schemas_all", Some(0), |_, _args| {
26183        let schemas: Vec<Value> = TOOL_REGISTRY.with(|registry| {
26184            registry
26185                .borrow()
26186                .values()
26187                .map(|tool| {
26188                    let mut schema = HashMap::new();
26189                    schema.insert(
26190                        "type".to_string(),
26191                        Value::String(Rc::new("function".to_string())),
26192                    );
26193
26194                    let mut function = HashMap::new();
26195                    function.insert(
26196                        "name".to_string(),
26197                        Value::String(Rc::new(tool.name.clone())),
26198                    );
26199                    function.insert(
26200                        "description".to_string(),
26201                        Value::String(Rc::new(tool.description.clone())),
26202                    );
26203
26204                    let mut params_schema = HashMap::new();
26205                    params_schema.insert(
26206                        "type".to_string(),
26207                        Value::String(Rc::new("object".to_string())),
26208                    );
26209
26210                    let mut properties = HashMap::new();
26211                    let mut required: Vec<Value> = Vec::new();
26212
26213                    for param in &tool.parameters {
26214                        let mut prop = HashMap::new();
26215                        let json_type = match param.param_type.as_str() {
26216                            "int" | "i64" | "i32" => "integer",
26217                            "float" | "f64" | "f32" => "number",
26218                            "bool" => "boolean",
26219                            _ => "string",
26220                        };
26221                        prop.insert(
26222                            "type".to_string(),
26223                            Value::String(Rc::new(json_type.to_string())),
26224                        );
26225                        prop.insert(
26226                            "description".to_string(),
26227                            Value::String(Rc::new(param.description.clone())),
26228                        );
26229                        properties
26230                            .insert(param.name.clone(), Value::Map(Rc::new(RefCell::new(prop))));
26231                        if param.required {
26232                            required.push(Value::String(Rc::new(param.name.clone())));
26233                        }
26234                    }
26235
26236                    params_schema.insert(
26237                        "properties".to_string(),
26238                        Value::Map(Rc::new(RefCell::new(properties))),
26239                    );
26240                    params_schema.insert(
26241                        "required".to_string(),
26242                        Value::Array(Rc::new(RefCell::new(required))),
26243                    );
26244                    function.insert(
26245                        "parameters".to_string(),
26246                        Value::Map(Rc::new(RefCell::new(params_schema))),
26247                    );
26248                    schema.insert(
26249                        "function".to_string(),
26250                        Value::Map(Rc::new(RefCell::new(function))),
26251                    );
26252
26253                    Value::Map(Rc::new(RefCell::new(schema)))
26254                })
26255                .collect()
26256        });
26257        Ok(Value::Array(Rc::new(RefCell::new(schemas))))
26258    });
26259
26260    // tool_call - Execute a registered tool by name
26261    define(interp, "tool_call", None, |interp, args| {
26262        if args.is_empty() {
26263            return Err(RuntimeError::new("tool_call requires at least tool name"));
26264        }
26265
26266        let name = match &args[0] {
26267            Value::String(s) => s.as_str().to_string(),
26268            _ => {
26269                return Err(RuntimeError::new(
26270                    "tool_call first argument must be tool name",
26271                ))
26272            }
26273        };
26274
26275        let tool_args: Vec<Value> = args.into_iter().skip(1).collect();
26276
26277        TOOL_REGISTRY.with(|registry| {
26278            if let Some(tool) = registry.borrow().get(&name) {
26279                if let Some(handler) = &tool.handler {
26280                    // Execute the handler function
26281                    let result = interp.call_function(handler.as_ref(), tool_args)?;
26282                    // Wrap result with reported evidence (external call)
26283                    Ok(Value::Evidential {
26284                        value: Box::new(result),
26285                        evidence: Evidence::Reported,
26286                    })
26287                } else {
26288                    Err(RuntimeError::new(format!("Tool '{}' has no handler", name)))
26289                }
26290            } else {
26291                Err(RuntimeError::new(format!("Tool '{}' not found", name)))
26292            }
26293        })
26294    });
26295
26296    // tool_remove - Remove a tool from registry
26297    define(interp, "tool_remove", Some(1), |_, args| {
26298        let name = match &args[0] {
26299            Value::String(s) => s.as_str().to_string(),
26300            _ => return Err(RuntimeError::new("tool_remove requires string name")),
26301        };
26302
26303        TOOL_REGISTRY.with(|registry| {
26304            let removed = registry.borrow_mut().remove(&name).is_some();
26305            Ok(Value::Bool(removed))
26306        })
26307    });
26308
26309    // tool_clear - Clear all registered tools
26310    define(interp, "tool_clear", Some(0), |_, _args| {
26311        TOOL_REGISTRY.with(|registry| {
26312            registry.borrow_mut().clear();
26313        });
26314        Ok(Value::Null)
26315    });
26316}
26317
26318// ============================================================================
26319// LLM CLIENT - AI model interaction with evidentiality
26320// ============================================================================
26321
26322fn register_agent_llm(interp: &mut Interpreter) {
26323    // llm_message - Create a chat message
26324    define(interp, "llm_message", Some(2), |_, args| {
26325        let role = match &args[0] {
26326            Value::String(s) => s.as_str().to_string(),
26327            _ => return Err(RuntimeError::new("llm_message role must be string")),
26328        };
26329        let content = match &args[1] {
26330            Value::String(s) => s.as_str().to_string(),
26331            _ => return Err(RuntimeError::new("llm_message content must be string")),
26332        };
26333
26334        let mut map = HashMap::new();
26335        map.insert("role".to_string(), Value::String(Rc::new(role)));
26336        map.insert("content".to_string(), Value::String(Rc::new(content)));
26337        Ok(Value::Map(Rc::new(RefCell::new(map))))
26338    });
26339
26340    // llm_messages - Create a messages array
26341    define(interp, "llm_messages", None, |_, args| {
26342        let messages: Vec<Value> = args.into_iter().collect();
26343        Ok(Value::Array(Rc::new(RefCell::new(messages))))
26344    });
26345
26346    // llm_request - Build an LLM API request (returns reported~ since it's external)
26347    define(interp, "llm_request", None, |_, args| {
26348        if args.is_empty() {
26349            return Err(RuntimeError::new("llm_request requires provider"));
26350        }
26351
26352        let provider = match &args[0] {
26353            Value::String(s) => s.as_str().to_string(),
26354            _ => return Err(RuntimeError::new("provider must be string")),
26355        };
26356
26357        let mut request = HashMap::new();
26358        request.insert(
26359            "provider".to_string(),
26360            Value::String(Rc::new(provider.clone())),
26361        );
26362
26363        // Default models per provider
26364        let default_model = match provider.as_str() {
26365            "openai" => "gpt-4-turbo-preview",
26366            "anthropic" | "claude" => "claude-3-opus-20240229",
26367            "google" | "gemini" => "gemini-pro",
26368            "mistral" => "mistral-large-latest",
26369            "ollama" | "local" => "llama2",
26370            _ => "gpt-4",
26371        };
26372        request.insert(
26373            "model".to_string(),
26374            Value::String(Rc::new(default_model.to_string())),
26375        );
26376
26377        // Parse optional arguments
26378        for (i, arg) in args.iter().enumerate().skip(1) {
26379            if let Value::Map(map) = arg {
26380                let map = map.borrow();
26381                for (k, v) in map.iter() {
26382                    request.insert(k.clone(), v.clone());
26383                }
26384            } else if i == 1 {
26385                // Second arg is model
26386                if let Value::String(s) = arg {
26387                    request.insert("model".to_string(), Value::String(s.clone()));
26388                }
26389            }
26390        }
26391
26392        // Default values
26393        if !request.contains_key("temperature") {
26394            request.insert("temperature".to_string(), Value::Float(0.7));
26395        }
26396        if !request.contains_key("max_tokens") {
26397            request.insert("max_tokens".to_string(), Value::Int(4096));
26398        }
26399
26400        Ok(Value::Map(Rc::new(RefCell::new(request))))
26401    });
26402
26403    // llm_with_tools - Add tools to a request
26404    define(interp, "llm_with_tools", Some(2), |_, args| {
26405        let request = match &args[0] {
26406            Value::Map(m) => m.clone(),
26407            _ => {
26408                return Err(RuntimeError::new(
26409                    "llm_with_tools first arg must be request map",
26410                ))
26411            }
26412        };
26413
26414        let tools = match &args[1] {
26415            Value::Array(arr) => arr.clone(),
26416            _ => {
26417                return Err(RuntimeError::new(
26418                    "llm_with_tools second arg must be tools array",
26419                ))
26420            }
26421        };
26422
26423        request
26424            .borrow_mut()
26425            .insert("tools".to_string(), Value::Array(tools));
26426        request.borrow_mut().insert(
26427            "tool_choice".to_string(),
26428            Value::String(Rc::new("auto".to_string())),
26429        );
26430
26431        Ok(Value::Map(request))
26432    });
26433
26434    // llm_with_system - Add system prompt to request
26435    define(interp, "llm_with_system", Some(2), |_, args| {
26436        let request = match &args[0] {
26437            Value::Map(m) => m.clone(),
26438            _ => {
26439                return Err(RuntimeError::new(
26440                    "llm_with_system first arg must be request map",
26441                ))
26442            }
26443        };
26444
26445        let system = match &args[1] {
26446            Value::String(s) => s.clone(),
26447            _ => {
26448                return Err(RuntimeError::new(
26449                    "llm_with_system second arg must be string",
26450                ))
26451            }
26452        };
26453
26454        request
26455            .borrow_mut()
26456            .insert("system".to_string(), Value::String(system));
26457        Ok(Value::Map(request))
26458    });
26459
26460    // llm_with_messages - Add messages to request
26461    define(interp, "llm_with_messages", Some(2), |_, args| {
26462        let request = match &args[0] {
26463            Value::Map(m) => m.clone(),
26464            _ => {
26465                return Err(RuntimeError::new(
26466                    "llm_with_messages first arg must be request map",
26467                ))
26468            }
26469        };
26470
26471        let messages = match &args[1] {
26472            Value::Array(arr) => arr.clone(),
26473            _ => {
26474                return Err(RuntimeError::new(
26475                    "llm_with_messages second arg must be messages array",
26476                ))
26477            }
26478        };
26479
26480        request
26481            .borrow_mut()
26482            .insert("messages".to_string(), Value::Array(messages));
26483        Ok(Value::Map(request))
26484    });
26485
26486    // llm_send - Send request (simulated - returns reported~ data)
26487    // In production, this would make actual HTTP calls
26488    define(interp, "llm_send", Some(1), |_, args| {
26489        let request = match &args[0] {
26490            Value::Map(m) => m.borrow().clone(),
26491            _ => return Err(RuntimeError::new("llm_send requires request map")),
26492        };
26493
26494        let provider = request
26495            .get("provider")
26496            .and_then(|v| {
26497                if let Value::String(s) = v {
26498                    Some(s.as_str().to_string())
26499                } else {
26500                    None
26501                }
26502            })
26503            .unwrap_or_else(|| "unknown".to_string());
26504
26505        let model = request
26506            .get("model")
26507            .and_then(|v| {
26508                if let Value::String(s) = v {
26509                    Some(s.as_str().to_string())
26510                } else {
26511                    None
26512                }
26513            })
26514            .unwrap_or_else(|| "unknown".to_string());
26515
26516        // Build response structure (simulated)
26517        let mut response = HashMap::new();
26518        response.insert(
26519            "id".to_string(),
26520            Value::String(Rc::new(format!("msg_{}", Uuid::new_v4()))),
26521        );
26522        response.insert("provider".to_string(), Value::String(Rc::new(provider)));
26523        response.insert("model".to_string(), Value::String(Rc::new(model)));
26524        response.insert(
26525            "created".to_string(),
26526            Value::Int(
26527                std::time::SystemTime::now()
26528                    .duration_since(std::time::UNIX_EPOCH)
26529                    .unwrap_or_default()
26530                    .as_secs() as i64,
26531            ),
26532        );
26533
26534        // Check if this would be a tool call
26535        if request.contains_key("tools") {
26536            response.insert(
26537                "type".to_string(),
26538                Value::String(Rc::new("tool_use".to_string())),
26539            );
26540            response.insert(
26541                "tool_name".to_string(),
26542                Value::String(Rc::new("pending".to_string())),
26543            );
26544            response.insert(
26545                "tool_input".to_string(),
26546                Value::Map(Rc::new(RefCell::new(HashMap::new()))),
26547            );
26548        } else {
26549            response.insert(
26550                "type".to_string(),
26551                Value::String(Rc::new("text".to_string())),
26552            );
26553            response.insert(
26554                "content".to_string(),
26555                Value::String(Rc::new(
26556                    "[LLM Response - Connect to actual API for real responses]".to_string(),
26557                )),
26558            );
26559        }
26560
26561        // Usage stats (simulated)
26562        let mut usage = HashMap::new();
26563        usage.insert("input_tokens".to_string(), Value::Int(0));
26564        usage.insert("output_tokens".to_string(), Value::Int(0));
26565        response.insert(
26566            "usage".to_string(),
26567            Value::Map(Rc::new(RefCell::new(usage))),
26568        );
26569
26570        // Return as reported evidence (external data)
26571        Ok(Value::Evidential {
26572            value: Box::new(Value::Map(Rc::new(RefCell::new(response)))),
26573            evidence: Evidence::Reported,
26574        })
26575    });
26576
26577    // llm_parse_tool_call - Parse tool call from LLM response
26578    define(interp, "llm_parse_tool_call", Some(1), |_, args| {
26579        let response = match &args[0] {
26580            Value::Map(m) => m.borrow().clone(),
26581            Value::Evidential { value, .. } => {
26582                if let Value::Map(m) = value.as_ref() {
26583                    m.borrow().clone()
26584                } else {
26585                    return Err(RuntimeError::new(
26586                        "llm_parse_tool_call requires map response",
26587                    ));
26588                }
26589            }
26590            _ => {
26591                return Err(RuntimeError::new(
26592                    "llm_parse_tool_call requires response map",
26593                ))
26594            }
26595        };
26596
26597        let resp_type = response
26598            .get("type")
26599            .and_then(|v| {
26600                if let Value::String(s) = v {
26601                    Some(s.as_str().to_string())
26602                } else {
26603                    None
26604                }
26605            })
26606            .unwrap_or_default();
26607
26608        if resp_type == "tool_use" {
26609            let tool_name = response
26610                .get("tool_name")
26611                .and_then(|v| {
26612                    if let Value::String(s) = v {
26613                        Some(s.as_str().to_string())
26614                    } else {
26615                        None
26616                    }
26617                })
26618                .unwrap_or_default();
26619
26620            let tool_input = response.get("tool_input").cloned().unwrap_or(Value::Null);
26621
26622            let mut result = HashMap::new();
26623            result.insert("is_tool_call".to_string(), Value::Bool(true));
26624            result.insert("tool_name".to_string(), Value::String(Rc::new(tool_name)));
26625            result.insert("tool_input".to_string(), tool_input);
26626            Ok(Value::Map(Rc::new(RefCell::new(result))))
26627        } else {
26628            let mut result = HashMap::new();
26629            result.insert("is_tool_call".to_string(), Value::Bool(false));
26630            result.insert(
26631                "content".to_string(),
26632                response.get("content").cloned().unwrap_or(Value::Null),
26633            );
26634            Ok(Value::Map(Rc::new(RefCell::new(result))))
26635        }
26636    });
26637
26638    // llm_extract - Extract structured data (returns uncertain? - needs validation)
26639    define(interp, "llm_extract", Some(2), |_, args| {
26640        let _response = match &args[0] {
26641            Value::Map(m) => m.borrow().clone(),
26642            Value::Evidential { value, .. } => {
26643                if let Value::Map(m) = value.as_ref() {
26644                    m.borrow().clone()
26645                } else {
26646                    return Err(RuntimeError::new("llm_extract requires response"));
26647                }
26648            }
26649            _ => return Err(RuntimeError::new("llm_extract requires response")),
26650        };
26651
26652        let _schema = match &args[1] {
26653            Value::Map(m) => m.borrow().clone(),
26654            _ => return Err(RuntimeError::new("llm_extract requires schema map")),
26655        };
26656
26657        // In production, this would parse the LLM output against the schema
26658        // For now, return uncertain evidence since extraction may fail
26659        let mut result = HashMap::new();
26660        result.insert("success".to_string(), Value::Bool(true));
26661        result.insert("data".to_string(), Value::Null);
26662        result.insert(
26663            "errors".to_string(),
26664            Value::Array(Rc::new(RefCell::new(Vec::new()))),
26665        );
26666
26667        Ok(Value::Evidential {
26668            value: Box::new(Value::Map(Rc::new(RefCell::new(result)))),
26669            evidence: Evidence::Uncertain,
26670        })
26671    });
26672
26673    // prompt_template - Create a prompt template with variable substitution
26674    define(interp, "prompt_template", Some(1), |_, args| {
26675        let template = match &args[0] {
26676            Value::String(s) => s.as_str().to_string(),
26677            _ => return Err(RuntimeError::new("prompt_template requires string")),
26678        };
26679
26680        // Parse template to extract variable names
26681        let mut variables = Vec::new();
26682        let mut in_var = false;
26683        let mut var_name = String::new();
26684
26685        for c in template.chars() {
26686            match c {
26687                '{' if !in_var => {
26688                    in_var = true;
26689                    var_name.clear();
26690                }
26691                '}' if in_var => {
26692                    if !var_name.is_empty() {
26693                        variables.push(Value::String(Rc::new(var_name.clone())));
26694                    }
26695                    in_var = false;
26696                }
26697                _ if in_var => {
26698                    var_name.push(c);
26699                }
26700                _ => {}
26701            }
26702        }
26703
26704        let mut result = HashMap::new();
26705        result.insert("template".to_string(), Value::String(Rc::new(template)));
26706        result.insert(
26707            "variables".to_string(),
26708            Value::Array(Rc::new(RefCell::new(variables))),
26709        );
26710        Ok(Value::Map(Rc::new(RefCell::new(result))))
26711    });
26712
26713    // prompt_render - Render a template with values
26714    define(interp, "prompt_render", Some(2), |_, args| {
26715        let template_obj = match &args[0] {
26716            Value::Map(m) => m.borrow().clone(),
26717            Value::String(s) => {
26718                let mut m = HashMap::new();
26719                m.insert("template".to_string(), Value::String(s.clone()));
26720                m
26721            }
26722            _ => return Err(RuntimeError::new("prompt_render requires template")),
26723        };
26724
26725        let values = match &args[1] {
26726            Value::Map(m) => m.borrow().clone(),
26727            _ => return Err(RuntimeError::new("prompt_render requires values map")),
26728        };
26729
26730        let template = template_obj
26731            .get("template")
26732            .and_then(|v| {
26733                if let Value::String(s) = v {
26734                    Some(s.as_str().to_string())
26735                } else {
26736                    None
26737                }
26738            })
26739            .unwrap_or_default();
26740
26741        let mut result = template;
26742        for (key, value) in values.iter() {
26743            let value_str = match value {
26744                Value::String(s) => s.as_str().to_string(),
26745                Value::Int(n) => n.to_string(),
26746                Value::Float(f) => f.to_string(),
26747                Value::Bool(b) => b.to_string(),
26748                _ => format!("{}", value),
26749            };
26750            result = result.replace(&format!("{{{}}}", key), &value_str);
26751        }
26752
26753        Ok(Value::String(Rc::new(result)))
26754    });
26755}
26756
26757// ============================================================================
26758// AGENT MEMORY - Session and context persistence
26759// ============================================================================
26760
26761fn register_agent_memory(interp: &mut Interpreter) {
26762    // memory_session - Create or get a session
26763    define(interp, "memory_session", Some(1), |_, args| {
26764        let session_id = match &args[0] {
26765            Value::String(s) => s.as_str().to_string(),
26766            _ => return Err(RuntimeError::new("memory_session requires string id")),
26767        };
26768
26769        let now = std::time::SystemTime::now()
26770            .duration_since(std::time::UNIX_EPOCH)
26771            .unwrap_or_default()
26772            .as_secs();
26773
26774        AGENT_MEMORY.with(|memory| {
26775            let mut mem = memory.borrow_mut();
26776            if !mem.contains_key(&session_id) {
26777                mem.insert(
26778                    session_id.clone(),
26779                    AgentSession {
26780                        id: session_id.clone(),
26781                        context: HashMap::new(),
26782                        history: Vec::new(),
26783                        created_at: now,
26784                        last_accessed: now,
26785                    },
26786                );
26787            } else if let Some(session) = mem.get_mut(&session_id) {
26788                session.last_accessed = now;
26789            }
26790        });
26791
26792        let mut result = HashMap::new();
26793        result.insert("id".to_string(), Value::String(Rc::new(session_id)));
26794        result.insert("created_at".to_string(), Value::Int(now as i64));
26795        Ok(Value::Map(Rc::new(RefCell::new(result))))
26796    });
26797
26798    // memory_set - Store a value in session context
26799    define(interp, "memory_set", Some(3), |_, args| {
26800        let session_id = match &args[0] {
26801            Value::String(s) => s.as_str().to_string(),
26802            Value::Map(m) => m
26803                .borrow()
26804                .get("id")
26805                .and_then(|v| {
26806                    if let Value::String(s) = v {
26807                        Some(s.as_str().to_string())
26808                    } else {
26809                        None
26810                    }
26811                })
26812                .ok_or_else(|| RuntimeError::new("Invalid session"))?,
26813            _ => return Err(RuntimeError::new("memory_set requires session")),
26814        };
26815
26816        let key = match &args[1] {
26817            Value::String(s) => s.as_str().to_string(),
26818            _ => return Err(RuntimeError::new("memory_set key must be string")),
26819        };
26820
26821        let value = args[2].clone();
26822
26823        AGENT_MEMORY.with(|memory| {
26824            if let Some(session) = memory.borrow_mut().get_mut(&session_id) {
26825                session.context.insert(key, value);
26826                session.last_accessed = std::time::SystemTime::now()
26827                    .duration_since(std::time::UNIX_EPOCH)
26828                    .unwrap_or_default()
26829                    .as_secs();
26830                Ok(Value::Bool(true))
26831            } else {
26832                Err(RuntimeError::new(format!(
26833                    "Session '{}' not found",
26834                    session_id
26835                )))
26836            }
26837        })
26838    });
26839
26840    // memory_get - Retrieve a value from session context
26841    define(interp, "memory_get", Some(2), |_, args| {
26842        let session_id = match &args[0] {
26843            Value::String(s) => s.as_str().to_string(),
26844            Value::Map(m) => m
26845                .borrow()
26846                .get("id")
26847                .and_then(|v| {
26848                    if let Value::String(s) = v {
26849                        Some(s.as_str().to_string())
26850                    } else {
26851                        None
26852                    }
26853                })
26854                .ok_or_else(|| RuntimeError::new("Invalid session"))?,
26855            _ => return Err(RuntimeError::new("memory_get requires session")),
26856        };
26857
26858        let key = match &args[1] {
26859            Value::String(s) => s.as_str().to_string(),
26860            _ => return Err(RuntimeError::new("memory_get key must be string")),
26861        };
26862
26863        AGENT_MEMORY.with(|memory| {
26864            if let Some(session) = memory.borrow().get(&session_id) {
26865                Ok(session.context.get(&key).cloned().unwrap_or(Value::Null))
26866            } else {
26867                Ok(Value::Null)
26868            }
26869        })
26870    });
26871
26872    // memory_history_add - Add to conversation history
26873    define(interp, "memory_history_add", Some(3), |_, args| {
26874        let session_id = match &args[0] {
26875            Value::String(s) => s.as_str().to_string(),
26876            Value::Map(m) => m
26877                .borrow()
26878                .get("id")
26879                .and_then(|v| {
26880                    if let Value::String(s) = v {
26881                        Some(s.as_str().to_string())
26882                    } else {
26883                        None
26884                    }
26885                })
26886                .ok_or_else(|| RuntimeError::new("Invalid session"))?,
26887            _ => return Err(RuntimeError::new("memory_history_add requires session")),
26888        };
26889
26890        let role = match &args[1] {
26891            Value::String(s) => s.as_str().to_string(),
26892            _ => return Err(RuntimeError::new("role must be string")),
26893        };
26894
26895        let content = match &args[2] {
26896            Value::String(s) => s.as_str().to_string(),
26897            _ => return Err(RuntimeError::new("content must be string")),
26898        };
26899
26900        AGENT_MEMORY.with(|memory| {
26901            if let Some(session) = memory.borrow_mut().get_mut(&session_id) {
26902                session.history.push((role, content));
26903                session.last_accessed = std::time::SystemTime::now()
26904                    .duration_since(std::time::UNIX_EPOCH)
26905                    .unwrap_or_default()
26906                    .as_secs();
26907                Ok(Value::Int(session.history.len() as i64))
26908            } else {
26909                Err(RuntimeError::new(format!(
26910                    "Session '{}' not found",
26911                    session_id
26912                )))
26913            }
26914        })
26915    });
26916
26917    // memory_history_get - Get conversation history
26918    define(interp, "memory_history_get", None, |_, args| {
26919        if args.is_empty() {
26920            return Err(RuntimeError::new("memory_history_get requires session"));
26921        }
26922
26923        let session_id = match &args[0] {
26924            Value::String(s) => s.as_str().to_string(),
26925            Value::Map(m) => m
26926                .borrow()
26927                .get("id")
26928                .and_then(|v| {
26929                    if let Value::String(s) = v {
26930                        Some(s.as_str().to_string())
26931                    } else {
26932                        None
26933                    }
26934                })
26935                .ok_or_else(|| RuntimeError::new("Invalid session"))?,
26936            _ => return Err(RuntimeError::new("memory_history_get requires session")),
26937        };
26938
26939        let limit = if args.len() > 1 {
26940            match &args[1] {
26941                Value::Int(n) => Some(*n as usize),
26942                _ => None,
26943            }
26944        } else {
26945            None
26946        };
26947
26948        AGENT_MEMORY.with(|memory| {
26949            if let Some(session) = memory.borrow().get(&session_id) {
26950                let history: Vec<Value> = session
26951                    .history
26952                    .iter()
26953                    .rev()
26954                    .take(limit.unwrap_or(usize::MAX))
26955                    .rev()
26956                    .map(|(role, content)| {
26957                        let mut msg = HashMap::new();
26958                        msg.insert("role".to_string(), Value::String(Rc::new(role.clone())));
26959                        msg.insert(
26960                            "content".to_string(),
26961                            Value::String(Rc::new(content.clone())),
26962                        );
26963                        Value::Map(Rc::new(RefCell::new(msg)))
26964                    })
26965                    .collect();
26966                Ok(Value::Array(Rc::new(RefCell::new(history))))
26967            } else {
26968                Ok(Value::Array(Rc::new(RefCell::new(Vec::new()))))
26969            }
26970        })
26971    });
26972
26973    // memory_context_all - Get all context for a session
26974    define(interp, "memory_context_all", Some(1), |_, args| {
26975        let session_id = match &args[0] {
26976            Value::String(s) => s.as_str().to_string(),
26977            Value::Map(m) => m
26978                .borrow()
26979                .get("id")
26980                .and_then(|v| {
26981                    if let Value::String(s) = v {
26982                        Some(s.as_str().to_string())
26983                    } else {
26984                        None
26985                    }
26986                })
26987                .ok_or_else(|| RuntimeError::new("Invalid session"))?,
26988            _ => return Err(RuntimeError::new("memory_context_all requires session")),
26989        };
26990
26991        AGENT_MEMORY.with(|memory| {
26992            if let Some(session) = memory.borrow().get(&session_id) {
26993                let context: HashMap<String, Value> = session.context.clone();
26994                Ok(Value::Map(Rc::new(RefCell::new(context))))
26995            } else {
26996                Ok(Value::Map(Rc::new(RefCell::new(HashMap::new()))))
26997            }
26998        })
26999    });
27000
27001    // memory_clear - Clear session data
27002    define(interp, "memory_clear", Some(1), |_, args| {
27003        let session_id = match &args[0] {
27004            Value::String(s) => s.as_str().to_string(),
27005            Value::Map(m) => m
27006                .borrow()
27007                .get("id")
27008                .and_then(|v| {
27009                    if let Value::String(s) = v {
27010                        Some(s.as_str().to_string())
27011                    } else {
27012                        None
27013                    }
27014                })
27015                .ok_or_else(|| RuntimeError::new("Invalid session"))?,
27016            _ => return Err(RuntimeError::new("memory_clear requires session")),
27017        };
27018
27019        AGENT_MEMORY.with(|memory| {
27020            let removed = memory.borrow_mut().remove(&session_id).is_some();
27021            Ok(Value::Bool(removed))
27022        })
27023    });
27024
27025    // memory_sessions_list - List all active sessions
27026    define(interp, "memory_sessions_list", Some(0), |_, _args| {
27027        let sessions: Vec<Value> = AGENT_MEMORY.with(|memory| {
27028            memory
27029                .borrow()
27030                .values()
27031                .map(|session| {
27032                    let mut info = HashMap::new();
27033                    info.insert("id".to_string(), Value::String(Rc::new(session.id.clone())));
27034                    info.insert(
27035                        "created_at".to_string(),
27036                        Value::Int(session.created_at as i64),
27037                    );
27038                    info.insert(
27039                        "last_accessed".to_string(),
27040                        Value::Int(session.last_accessed as i64),
27041                    );
27042                    info.insert(
27043                        "context_keys".to_string(),
27044                        Value::Int(session.context.len() as i64),
27045                    );
27046                    info.insert(
27047                        "history_length".to_string(),
27048                        Value::Int(session.history.len() as i64),
27049                    );
27050                    Value::Map(Rc::new(RefCell::new(info)))
27051                })
27052                .collect()
27053        });
27054        Ok(Value::Array(Rc::new(RefCell::new(sessions))))
27055    });
27056}
27057
27058// ============================================================================
27059// PLANNING FRAMEWORK - State machines and goal tracking
27060// ============================================================================
27061
27062fn register_agent_planning(interp: &mut Interpreter) {
27063    // plan_state_machine - Create a new state machine
27064    define(interp, "plan_state_machine", Some(2), |_, args| {
27065        let name = match &args[0] {
27066            Value::String(s) => s.as_str().to_string(),
27067            _ => return Err(RuntimeError::new("plan_state_machine name must be string")),
27068        };
27069
27070        let states = match &args[1] {
27071            Value::Array(arr) => arr
27072                .borrow()
27073                .iter()
27074                .filter_map(|v| {
27075                    if let Value::String(s) = v {
27076                        Some(s.as_str().to_string())
27077                    } else {
27078                        None
27079                    }
27080                })
27081                .collect::<Vec<_>>(),
27082            _ => return Err(RuntimeError::new("plan_state_machine states must be array")),
27083        };
27084
27085        if states.is_empty() {
27086            return Err(RuntimeError::new(
27087                "State machine must have at least one state",
27088            ));
27089        }
27090
27091        let initial_state = states[0].clone();
27092        let now = std::time::SystemTime::now()
27093            .duration_since(std::time::UNIX_EPOCH)
27094            .unwrap_or_default()
27095            .as_secs();
27096
27097        let machine = StateMachine {
27098            name: name.clone(),
27099            current_state: initial_state.clone(),
27100            states,
27101            transitions: HashMap::new(),
27102            history: vec![(initial_state, now)],
27103        };
27104
27105        STATE_MACHINES.with(|machines| {
27106            machines.borrow_mut().insert(name.clone(), machine);
27107        });
27108
27109        let mut result = HashMap::new();
27110        result.insert("name".to_string(), Value::String(Rc::new(name)));
27111        result.insert(
27112            "type".to_string(),
27113            Value::String(Rc::new("state_machine".to_string())),
27114        );
27115        Ok(Value::Map(Rc::new(RefCell::new(result))))
27116    });
27117
27118    // plan_add_transition - Add a transition rule
27119    define(interp, "plan_add_transition", Some(3), |_, args| {
27120        let machine_name = match &args[0] {
27121            Value::String(s) => s.as_str().to_string(),
27122            Value::Map(m) => m
27123                .borrow()
27124                .get("name")
27125                .and_then(|v| {
27126                    if let Value::String(s) = v {
27127                        Some(s.as_str().to_string())
27128                    } else {
27129                        None
27130                    }
27131                })
27132                .ok_or_else(|| RuntimeError::new("Invalid state machine"))?,
27133            _ => return Err(RuntimeError::new("plan_add_transition requires machine")),
27134        };
27135
27136        let from_state = match &args[1] {
27137            Value::String(s) => s.as_str().to_string(),
27138            _ => return Err(RuntimeError::new("from_state must be string")),
27139        };
27140
27141        let to_state = match &args[2] {
27142            Value::String(s) => s.as_str().to_string(),
27143            _ => return Err(RuntimeError::new("to_state must be string")),
27144        };
27145
27146        STATE_MACHINES.with(|machines| {
27147            if let Some(machine) = machines.borrow_mut().get_mut(&machine_name) {
27148                // Validate states exist
27149                if !machine.states.contains(&from_state) {
27150                    return Err(RuntimeError::new(format!(
27151                        "State '{}' not in machine",
27152                        from_state
27153                    )));
27154                }
27155                if !machine.states.contains(&to_state) {
27156                    return Err(RuntimeError::new(format!(
27157                        "State '{}' not in machine",
27158                        to_state
27159                    )));
27160                }
27161
27162                machine
27163                    .transitions
27164                    .entry(from_state)
27165                    .or_insert_with(Vec::new)
27166                    .push((to_state, "".to_string()));
27167
27168                Ok(Value::Bool(true))
27169            } else {
27170                Err(RuntimeError::new(format!(
27171                    "State machine '{}' not found",
27172                    machine_name
27173                )))
27174            }
27175        })
27176    });
27177
27178    // plan_current_state - Get current state
27179    define(interp, "plan_current_state", Some(1), |_, args| {
27180        let machine_name = match &args[0] {
27181            Value::String(s) => s.as_str().to_string(),
27182            Value::Map(m) => m
27183                .borrow()
27184                .get("name")
27185                .and_then(|v| {
27186                    if let Value::String(s) = v {
27187                        Some(s.as_str().to_string())
27188                    } else {
27189                        None
27190                    }
27191                })
27192                .ok_or_else(|| RuntimeError::new("Invalid state machine"))?,
27193            _ => return Err(RuntimeError::new("plan_current_state requires machine")),
27194        };
27195
27196        STATE_MACHINES.with(|machines| {
27197            if let Some(machine) = machines.borrow().get(&machine_name) {
27198                Ok(Value::String(Rc::new(machine.current_state.clone())))
27199            } else {
27200                Err(RuntimeError::new(format!(
27201                    "State machine '{}' not found",
27202                    machine_name
27203                )))
27204            }
27205        })
27206    });
27207
27208    // plan_transition - Execute a state transition
27209    define(interp, "plan_transition", Some(2), |_, args| {
27210        let machine_name = match &args[0] {
27211            Value::String(s) => s.as_str().to_string(),
27212            Value::Map(m) => m
27213                .borrow()
27214                .get("name")
27215                .and_then(|v| {
27216                    if let Value::String(s) = v {
27217                        Some(s.as_str().to_string())
27218                    } else {
27219                        None
27220                    }
27221                })
27222                .ok_or_else(|| RuntimeError::new("Invalid state machine"))?,
27223            _ => return Err(RuntimeError::new("plan_transition requires machine")),
27224        };
27225
27226        let to_state = match &args[1] {
27227            Value::String(s) => s.as_str().to_string(),
27228            _ => return Err(RuntimeError::new("to_state must be string")),
27229        };
27230
27231        STATE_MACHINES.with(|machines| {
27232            if let Some(machine) = machines.borrow_mut().get_mut(&machine_name) {
27233                let current = machine.current_state.clone();
27234
27235                // Check if transition is valid
27236                let valid = machine
27237                    .transitions
27238                    .get(&current)
27239                    .map(|transitions| transitions.iter().any(|(to, _)| to == &to_state))
27240                    .unwrap_or(false);
27241
27242                if valid || machine.states.contains(&to_state) {
27243                    let now = std::time::SystemTime::now()
27244                        .duration_since(std::time::UNIX_EPOCH)
27245                        .unwrap_or_default()
27246                        .as_secs();
27247
27248                    machine.current_state = to_state.clone();
27249                    machine.history.push((to_state.clone(), now));
27250
27251                    let mut result = HashMap::new();
27252                    result.insert("success".to_string(), Value::Bool(true));
27253                    result.insert("from".to_string(), Value::String(Rc::new(current)));
27254                    result.insert("to".to_string(), Value::String(Rc::new(to_state)));
27255                    Ok(Value::Map(Rc::new(RefCell::new(result))))
27256                } else {
27257                    let mut result = HashMap::new();
27258                    result.insert("success".to_string(), Value::Bool(false));
27259                    result.insert(
27260                        "error".to_string(),
27261                        Value::String(Rc::new(format!(
27262                            "No valid transition from '{}' to '{}'",
27263                            current, to_state
27264                        ))),
27265                    );
27266                    Ok(Value::Map(Rc::new(RefCell::new(result))))
27267                }
27268            } else {
27269                Err(RuntimeError::new(format!(
27270                    "State machine '{}' not found",
27271                    machine_name
27272                )))
27273            }
27274        })
27275    });
27276
27277    // plan_can_transition - Check if a transition is valid
27278    define(interp, "plan_can_transition", Some(2), |_, args| {
27279        let machine_name = match &args[0] {
27280            Value::String(s) => s.as_str().to_string(),
27281            Value::Map(m) => m
27282                .borrow()
27283                .get("name")
27284                .and_then(|v| {
27285                    if let Value::String(s) = v {
27286                        Some(s.as_str().to_string())
27287                    } else {
27288                        None
27289                    }
27290                })
27291                .ok_or_else(|| RuntimeError::new("Invalid state machine"))?,
27292            _ => return Err(RuntimeError::new("plan_can_transition requires machine")),
27293        };
27294
27295        let to_state = match &args[1] {
27296            Value::String(s) => s.as_str().to_string(),
27297            _ => return Err(RuntimeError::new("to_state must be string")),
27298        };
27299
27300        STATE_MACHINES.with(|machines| {
27301            if let Some(machine) = machines.borrow().get(&machine_name) {
27302                let current = &machine.current_state;
27303                let can = machine
27304                    .transitions
27305                    .get(current)
27306                    .map(|transitions| transitions.iter().any(|(to, _)| to == &to_state))
27307                    .unwrap_or(false);
27308                Ok(Value::Bool(can))
27309            } else {
27310                Ok(Value::Bool(false))
27311            }
27312        })
27313    });
27314
27315    // plan_available_transitions - Get available transitions from current state
27316    define(interp, "plan_available_transitions", Some(1), |_, args| {
27317        let machine_name = match &args[0] {
27318            Value::String(s) => s.as_str().to_string(),
27319            Value::Map(m) => m
27320                .borrow()
27321                .get("name")
27322                .and_then(|v| {
27323                    if let Value::String(s) = v {
27324                        Some(s.as_str().to_string())
27325                    } else {
27326                        None
27327                    }
27328                })
27329                .ok_or_else(|| RuntimeError::new("Invalid state machine"))?,
27330            _ => {
27331                return Err(RuntimeError::new(
27332                    "plan_available_transitions requires machine",
27333                ))
27334            }
27335        };
27336
27337        STATE_MACHINES.with(|machines| {
27338            if let Some(machine) = machines.borrow().get(&machine_name) {
27339                let current = &machine.current_state;
27340                let available: Vec<Value> = machine
27341                    .transitions
27342                    .get(current)
27343                    .map(|transitions| {
27344                        transitions
27345                            .iter()
27346                            .map(|(to, _)| Value::String(Rc::new(to.clone())))
27347                            .collect()
27348                    })
27349                    .unwrap_or_default();
27350                Ok(Value::Array(Rc::new(RefCell::new(available))))
27351            } else {
27352                Ok(Value::Array(Rc::new(RefCell::new(Vec::new()))))
27353            }
27354        })
27355    });
27356
27357    // plan_history - Get state transition history
27358    define(interp, "plan_history", Some(1), |_, args| {
27359        let machine_name = match &args[0] {
27360            Value::String(s) => s.as_str().to_string(),
27361            Value::Map(m) => m
27362                .borrow()
27363                .get("name")
27364                .and_then(|v| {
27365                    if let Value::String(s) = v {
27366                        Some(s.as_str().to_string())
27367                    } else {
27368                        None
27369                    }
27370                })
27371                .ok_or_else(|| RuntimeError::new("Invalid state machine"))?,
27372            _ => return Err(RuntimeError::new("plan_history requires machine")),
27373        };
27374
27375        STATE_MACHINES.with(|machines| {
27376            if let Some(machine) = machines.borrow().get(&machine_name) {
27377                let history: Vec<Value> = machine
27378                    .history
27379                    .iter()
27380                    .map(|(state, timestamp)| {
27381                        let mut entry = HashMap::new();
27382                        entry.insert("state".to_string(), Value::String(Rc::new(state.clone())));
27383                        entry.insert("timestamp".to_string(), Value::Int(*timestamp as i64));
27384                        Value::Map(Rc::new(RefCell::new(entry)))
27385                    })
27386                    .collect();
27387                Ok(Value::Array(Rc::new(RefCell::new(history))))
27388            } else {
27389                Ok(Value::Array(Rc::new(RefCell::new(Vec::new()))))
27390            }
27391        })
27392    });
27393
27394    // plan_goal - Create a goal with success criteria
27395    define(interp, "plan_goal", Some(2), |_, args| {
27396        let name = match &args[0] {
27397            Value::String(s) => s.as_str().to_string(),
27398            _ => return Err(RuntimeError::new("plan_goal name must be string")),
27399        };
27400
27401        let criteria = args[1].clone();
27402
27403        let mut goal = HashMap::new();
27404        goal.insert("name".to_string(), Value::String(Rc::new(name)));
27405        goal.insert("criteria".to_string(), criteria);
27406        goal.insert(
27407            "status".to_string(),
27408            Value::String(Rc::new("pending".to_string())),
27409        );
27410        goal.insert("progress".to_string(), Value::Float(0.0));
27411        goal.insert(
27412            "created_at".to_string(),
27413            Value::Int(
27414                std::time::SystemTime::now()
27415                    .duration_since(std::time::UNIX_EPOCH)
27416                    .unwrap_or_default()
27417                    .as_secs() as i64,
27418            ),
27419        );
27420
27421        Ok(Value::Map(Rc::new(RefCell::new(goal))))
27422    });
27423
27424    // plan_subgoals - Break a goal into subgoals
27425    define(interp, "plan_subgoals", Some(2), |_, args| {
27426        let parent = match &args[0] {
27427            Value::Map(m) => m.clone(),
27428            _ => return Err(RuntimeError::new("plan_subgoals requires goal map")),
27429        };
27430
27431        let subgoals = match &args[1] {
27432            Value::Array(arr) => arr.clone(),
27433            _ => return Err(RuntimeError::new("plan_subgoals requires subgoals array")),
27434        };
27435
27436        parent
27437            .borrow_mut()
27438            .insert("subgoals".to_string(), Value::Array(subgoals));
27439        Ok(Value::Map(parent))
27440    });
27441
27442    // plan_update_progress - Update goal progress
27443    define(interp, "plan_update_progress", Some(2), |_, args| {
27444        let goal = match &args[0] {
27445            Value::Map(m) => m.clone(),
27446            _ => return Err(RuntimeError::new("plan_update_progress requires goal map")),
27447        };
27448
27449        let progress = match &args[1] {
27450            Value::Float(f) => *f,
27451            Value::Int(i) => *i as f64,
27452            _ => return Err(RuntimeError::new("progress must be number")),
27453        };
27454
27455        let progress = progress.clamp(0.0, 1.0);
27456        goal.borrow_mut()
27457            .insert("progress".to_string(), Value::Float(progress));
27458
27459        if progress >= 1.0 {
27460            goal.borrow_mut().insert(
27461                "status".to_string(),
27462                Value::String(Rc::new("completed".to_string())),
27463            );
27464        } else if progress > 0.0 {
27465            goal.borrow_mut().insert(
27466                "status".to_string(),
27467                Value::String(Rc::new("in_progress".to_string())),
27468            );
27469        }
27470
27471        Ok(Value::Map(goal))
27472    });
27473
27474    // plan_check_goal - Check if goal criteria are met
27475    define(interp, "plan_check_goal", Some(2), |_interp, args| {
27476        let goal = match &args[0] {
27477            Value::Map(m) => m.borrow().clone(),
27478            _ => return Err(RuntimeError::new("plan_check_goal requires goal map")),
27479        };
27480
27481        let context = match &args[1] {
27482            Value::Map(m) => m.borrow().clone(),
27483            _ => return Err(RuntimeError::new("plan_check_goal requires context map")),
27484        };
27485
27486        // Simple criteria checking - in production, this would evaluate expressions
27487        let _criteria = goal.get("criteria").cloned().unwrap_or(Value::Null);
27488
27489        // Check if all required context keys exist
27490        let mut met = true;
27491        let mut missing: Vec<String> = Vec::new();
27492
27493        if let Some(Value::Array(required)) = goal.get("required_context") {
27494            for req in required.borrow().iter() {
27495                if let Value::String(key) = req {
27496                    if !context.contains_key(key.as_str()) {
27497                        met = false;
27498                        missing.push(key.as_str().to_string());
27499                    }
27500                }
27501            }
27502        }
27503
27504        let mut result = HashMap::new();
27505        result.insert("met".to_string(), Value::Bool(met));
27506        result.insert(
27507            "missing".to_string(),
27508            Value::Array(Rc::new(RefCell::new(
27509                missing
27510                    .into_iter()
27511                    .map(|s| Value::String(Rc::new(s)))
27512                    .collect(),
27513            ))),
27514        );
27515
27516        Ok(Value::Map(Rc::new(RefCell::new(result))))
27517    });
27518}
27519
27520// ============================================================================
27521// VECTOR OPERATIONS - Embeddings and similarity search
27522// ============================================================================
27523
27524fn register_agent_vectors(interp: &mut Interpreter) {
27525    // vec_embedding - Create an embedding vector (simulated - returns uncertain?)
27526    define(interp, "vec_embedding", Some(1), |_, args| {
27527        let text = match &args[0] {
27528            Value::String(s) => s.as_str().to_string(),
27529            _ => return Err(RuntimeError::new("vec_embedding requires string")),
27530        };
27531
27532        // Simulated embedding - in production, call embedding API
27533        // Creates a simple hash-based embedding for demo purposes
27534        let mut embedding = Vec::new();
27535        let dimension = 384; // Common embedding dimension
27536
27537        for i in 0..dimension {
27538            let hash = text.bytes().enumerate().fold(0u64, |acc, (j, b)| {
27539                acc.wrapping_add((b as u64).wrapping_mul((i + j + 1) as u64))
27540            });
27541            let value = ((hash % 10000) as f64 / 10000.0) * 2.0 - 1.0; // Normalize to [-1, 1]
27542            embedding.push(Value::Float(value));
27543        }
27544
27545        let result = Value::Array(Rc::new(RefCell::new(embedding)));
27546
27547        // Return as uncertain since embeddings are probabilistic
27548        Ok(Value::Evidential {
27549            value: Box::new(result),
27550            evidence: Evidence::Uncertain,
27551        })
27552    });
27553
27554    // vec_cosine_similarity - Compute cosine similarity between two vectors
27555    define(interp, "vec_cosine_similarity", Some(2), |_, args| {
27556        let vec_a = match &args[0] {
27557            Value::Array(arr) => arr.borrow().clone(),
27558            Value::Evidential { value, .. } => {
27559                if let Value::Array(arr) = value.as_ref() {
27560                    arr.borrow().clone()
27561                } else {
27562                    return Err(RuntimeError::new("vec_cosine_similarity requires arrays"));
27563                }
27564            }
27565            _ => return Err(RuntimeError::new("vec_cosine_similarity requires arrays")),
27566        };
27567
27568        let vec_b = match &args[1] {
27569            Value::Array(arr) => arr.borrow().clone(),
27570            Value::Evidential { value, .. } => {
27571                if let Value::Array(arr) = value.as_ref() {
27572                    arr.borrow().clone()
27573                } else {
27574                    return Err(RuntimeError::new("vec_cosine_similarity requires arrays"));
27575                }
27576            }
27577            _ => return Err(RuntimeError::new("vec_cosine_similarity requires arrays")),
27578        };
27579
27580        if vec_a.len() != vec_b.len() {
27581            return Err(RuntimeError::new("Vectors must have same dimension"));
27582        }
27583
27584        let mut dot = 0.0;
27585        let mut mag_a = 0.0;
27586        let mut mag_b = 0.0;
27587
27588        for (a, b) in vec_a.iter().zip(vec_b.iter()) {
27589            let a_val = match a {
27590                Value::Float(f) => *f,
27591                Value::Int(i) => *i as f64,
27592                _ => 0.0,
27593            };
27594            let b_val = match b {
27595                Value::Float(f) => *f,
27596                Value::Int(i) => *i as f64,
27597                _ => 0.0,
27598            };
27599
27600            dot += a_val * b_val;
27601            mag_a += a_val * a_val;
27602            mag_b += b_val * b_val;
27603        }
27604
27605        let similarity = if mag_a > 0.0 && mag_b > 0.0 {
27606            dot / (mag_a.sqrt() * mag_b.sqrt())
27607        } else {
27608            0.0
27609        };
27610
27611        Ok(Value::Float(similarity))
27612    });
27613
27614    // vec_euclidean_distance - Compute Euclidean distance
27615    define(interp, "vec_euclidean_distance", Some(2), |_, args| {
27616        let vec_a = match &args[0] {
27617            Value::Array(arr) => arr.borrow().clone(),
27618            Value::Evidential { value, .. } => {
27619                if let Value::Array(arr) = value.as_ref() {
27620                    arr.borrow().clone()
27621                } else {
27622                    return Err(RuntimeError::new("vec_euclidean_distance requires arrays"));
27623                }
27624            }
27625            _ => return Err(RuntimeError::new("vec_euclidean_distance requires arrays")),
27626        };
27627
27628        let vec_b = match &args[1] {
27629            Value::Array(arr) => arr.borrow().clone(),
27630            Value::Evidential { value, .. } => {
27631                if let Value::Array(arr) = value.as_ref() {
27632                    arr.borrow().clone()
27633                } else {
27634                    return Err(RuntimeError::new("vec_euclidean_distance requires arrays"));
27635                }
27636            }
27637            _ => return Err(RuntimeError::new("vec_euclidean_distance requires arrays")),
27638        };
27639
27640        if vec_a.len() != vec_b.len() {
27641            return Err(RuntimeError::new("Vectors must have same dimension"));
27642        }
27643
27644        let mut sum_sq = 0.0;
27645        for (a, b) in vec_a.iter().zip(vec_b.iter()) {
27646            let a_val = match a {
27647                Value::Float(f) => *f,
27648                Value::Int(i) => *i as f64,
27649                _ => 0.0,
27650            };
27651            let b_val = match b {
27652                Value::Float(f) => *f,
27653                Value::Int(i) => *i as f64,
27654                _ => 0.0,
27655            };
27656            let diff = a_val - b_val;
27657            sum_sq += diff * diff;
27658        }
27659
27660        Ok(Value::Float(sum_sq.sqrt()))
27661    });
27662
27663    // vec_dot_product - Compute dot product
27664    define(interp, "vec_dot_product", Some(2), |_, args| {
27665        let vec_a = match &args[0] {
27666            Value::Array(arr) => arr.borrow().clone(),
27667            _ => return Err(RuntimeError::new("vec_dot_product requires arrays")),
27668        };
27669
27670        let vec_b = match &args[1] {
27671            Value::Array(arr) => arr.borrow().clone(),
27672            _ => return Err(RuntimeError::new("vec_dot_product requires arrays")),
27673        };
27674
27675        if vec_a.len() != vec_b.len() {
27676            return Err(RuntimeError::new("Vectors must have same dimension"));
27677        }
27678
27679        let mut dot = 0.0;
27680        for (a, b) in vec_a.iter().zip(vec_b.iter()) {
27681            let a_val = match a {
27682                Value::Float(f) => *f,
27683                Value::Int(i) => *i as f64,
27684                _ => 0.0,
27685            };
27686            let b_val = match b {
27687                Value::Float(f) => *f,
27688                Value::Int(i) => *i as f64,
27689                _ => 0.0,
27690            };
27691            dot += a_val * b_val;
27692        }
27693
27694        Ok(Value::Float(dot))
27695    });
27696
27697    // vec_normalize - Normalize a vector to unit length
27698    define(interp, "vec_normalize", Some(1), |_, args| {
27699        let vec = match &args[0] {
27700            Value::Array(arr) => arr.borrow().clone(),
27701            _ => return Err(RuntimeError::new("vec_normalize requires array")),
27702        };
27703
27704        let mut mag = 0.0;
27705        for v in vec.iter() {
27706            let val = match v {
27707                Value::Float(f) => *f,
27708                Value::Int(i) => *i as f64,
27709                _ => 0.0,
27710            };
27711            mag += val * val;
27712        }
27713        mag = mag.sqrt();
27714
27715        if mag == 0.0 {
27716            return Ok(Value::Array(Rc::new(RefCell::new(vec))));
27717        }
27718
27719        let normalized: Vec<Value> = vec
27720            .iter()
27721            .map(|v| {
27722                let val = match v {
27723                    Value::Float(f) => *f,
27724                    Value::Int(i) => *i as f64,
27725                    _ => 0.0,
27726                };
27727                Value::Float(val / mag)
27728            })
27729            .collect();
27730
27731        Ok(Value::Array(Rc::new(RefCell::new(normalized))))
27732    });
27733
27734    // vec_search - Find most similar vectors (k-nearest neighbors)
27735    define(interp, "vec_search", Some(3), |_, args| {
27736        let query = match &args[0] {
27737            Value::Array(arr) => arr.borrow().clone(),
27738            Value::Evidential { value, .. } => {
27739                if let Value::Array(arr) = value.as_ref() {
27740                    arr.borrow().clone()
27741                } else {
27742                    return Err(RuntimeError::new("vec_search query must be array"));
27743                }
27744            }
27745            _ => return Err(RuntimeError::new("vec_search query must be array")),
27746        };
27747
27748        let corpus = match &args[1] {
27749            Value::Array(arr) => arr.borrow().clone(),
27750            _ => {
27751                return Err(RuntimeError::new(
27752                    "vec_search corpus must be array of vectors",
27753                ))
27754            }
27755        };
27756
27757        let k = match &args[2] {
27758            Value::Int(n) => *n as usize,
27759            _ => return Err(RuntimeError::new("vec_search k must be integer")),
27760        };
27761
27762        // Compute similarities
27763        let mut similarities: Vec<(usize, f64)> = Vec::new();
27764
27765        for (i, item) in corpus.iter().enumerate() {
27766            let vec_b = match item {
27767                Value::Array(arr) => arr.borrow().clone(),
27768                Value::Map(m) => {
27769                    // Support {vector: [...], metadata: {...}} format
27770                    if let Some(Value::Array(arr)) = m.borrow().get("vector") {
27771                        arr.borrow().clone()
27772                    } else {
27773                        continue;
27774                    }
27775                }
27776                _ => continue,
27777            };
27778
27779            if vec_b.len() != query.len() {
27780                continue;
27781            }
27782
27783            let mut dot = 0.0;
27784            let mut mag_a = 0.0;
27785            let mut mag_b = 0.0;
27786
27787            for (a, b) in query.iter().zip(vec_b.iter()) {
27788                let a_val = match a {
27789                    Value::Float(f) => *f,
27790                    Value::Int(i) => *i as f64,
27791                    _ => 0.0,
27792                };
27793                let b_val = match b {
27794                    Value::Float(f) => *f,
27795                    Value::Int(i) => *i as f64,
27796                    _ => 0.0,
27797                };
27798                dot += a_val * b_val;
27799                mag_a += a_val * a_val;
27800                mag_b += b_val * b_val;
27801            }
27802
27803            let similarity = if mag_a > 0.0 && mag_b > 0.0 {
27804                dot / (mag_a.sqrt() * mag_b.sqrt())
27805            } else {
27806                0.0
27807            };
27808
27809            similarities.push((i, similarity));
27810        }
27811
27812        // Sort by similarity (descending)
27813        similarities.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(std::cmp::Ordering::Equal));
27814
27815        // Return top k
27816        let results: Vec<Value> = similarities
27817            .iter()
27818            .take(k)
27819            .map(|(idx, sim)| {
27820                let mut result = HashMap::new();
27821                result.insert("index".to_string(), Value::Int(*idx as i64));
27822                result.insert("similarity".to_string(), Value::Float(*sim));
27823                result.insert(
27824                    "item".to_string(),
27825                    corpus.get(*idx).cloned().unwrap_or(Value::Null),
27826                );
27827                Value::Map(Rc::new(RefCell::new(result)))
27828            })
27829            .collect();
27830
27831        Ok(Value::Array(Rc::new(RefCell::new(results))))
27832    });
27833
27834    // vec_store - Create an in-memory vector store
27835    define(interp, "vec_store", Some(0), |_, _args| {
27836        let mut store = HashMap::new();
27837        store.insert(
27838            "vectors".to_string(),
27839            Value::Array(Rc::new(RefCell::new(Vec::new()))),
27840        );
27841        store.insert(
27842            "metadata".to_string(),
27843            Value::Array(Rc::new(RefCell::new(Vec::new()))),
27844        );
27845        store.insert("count".to_string(), Value::Int(0));
27846        Ok(Value::Map(Rc::new(RefCell::new(store))))
27847    });
27848
27849    // vec_store_add - Add a vector with metadata to store
27850    define(interp, "vec_store_add", Some(3), |_, args| {
27851        let store = match &args[0] {
27852            Value::Map(m) => m.clone(),
27853            _ => return Err(RuntimeError::new("vec_store_add requires store")),
27854        };
27855
27856        let vector = args[1].clone();
27857        let metadata = args[2].clone();
27858
27859        let mut store_ref = store.borrow_mut();
27860
27861        if let Some(Value::Array(vectors)) = store_ref.get("vectors") {
27862            vectors.borrow_mut().push(vector);
27863        }
27864        if let Some(Value::Array(metas)) = store_ref.get("metadata") {
27865            metas.borrow_mut().push(metadata);
27866        }
27867
27868        let new_count = store_ref
27869            .get("count")
27870            .and_then(|v| {
27871                if let Value::Int(n) = v {
27872                    Some(*n)
27873                } else {
27874                    None
27875                }
27876            })
27877            .unwrap_or(0)
27878            + 1;
27879        store_ref.insert("count".to_string(), Value::Int(new_count));
27880
27881        Ok(Value::Int(new_count))
27882    });
27883
27884    // vec_store_search - Search the vector store
27885    define(interp, "vec_store_search", Some(3), |_, args| {
27886        let store = match &args[0] {
27887            Value::Map(m) => m.borrow().clone(),
27888            _ => return Err(RuntimeError::new("vec_store_search requires store")),
27889        };
27890
27891        let query = match &args[1] {
27892            Value::Array(arr) => arr.borrow().clone(),
27893            Value::Evidential { value, .. } => {
27894                if let Value::Array(arr) = value.as_ref() {
27895                    arr.borrow().clone()
27896                } else {
27897                    return Err(RuntimeError::new("Query must be array"));
27898                }
27899            }
27900            _ => return Err(RuntimeError::new("Query must be array")),
27901        };
27902
27903        let k = match &args[2] {
27904            Value::Int(n) => *n as usize,
27905            _ => return Err(RuntimeError::new("k must be integer")),
27906        };
27907
27908        let vectors = store
27909            .get("vectors")
27910            .and_then(|v| {
27911                if let Value::Array(arr) = v {
27912                    Some(arr.borrow().clone())
27913                } else {
27914                    None
27915                }
27916            })
27917            .unwrap_or_default();
27918
27919        let metadata = store
27920            .get("metadata")
27921            .and_then(|v| {
27922                if let Value::Array(arr) = v {
27923                    Some(arr.borrow().clone())
27924                } else {
27925                    None
27926                }
27927            })
27928            .unwrap_or_default();
27929
27930        let mut similarities: Vec<(usize, f64)> = Vec::new();
27931
27932        for (i, vec_val) in vectors.iter().enumerate() {
27933            let vec_b = match vec_val {
27934                Value::Array(arr) => arr.borrow().clone(),
27935                Value::Evidential { value, .. } => {
27936                    if let Value::Array(arr) = value.as_ref() {
27937                        arr.borrow().clone()
27938                    } else {
27939                        continue;
27940                    }
27941                }
27942                _ => continue,
27943            };
27944
27945            if vec_b.len() != query.len() {
27946                continue;
27947            }
27948
27949            let mut dot = 0.0;
27950            let mut mag_a = 0.0;
27951            let mut mag_b = 0.0;
27952
27953            for (a, b) in query.iter().zip(vec_b.iter()) {
27954                let a_val = match a {
27955                    Value::Float(f) => *f,
27956                    Value::Int(i) => *i as f64,
27957                    _ => 0.0,
27958                };
27959                let b_val = match b {
27960                    Value::Float(f) => *f,
27961                    Value::Int(i) => *i as f64,
27962                    _ => 0.0,
27963                };
27964                dot += a_val * b_val;
27965                mag_a += a_val * a_val;
27966                mag_b += b_val * b_val;
27967            }
27968
27969            let sim = if mag_a > 0.0 && mag_b > 0.0 {
27970                dot / (mag_a.sqrt() * mag_b.sqrt())
27971            } else {
27972                0.0
27973            };
27974            similarities.push((i, sim));
27975        }
27976
27977        similarities.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(std::cmp::Ordering::Equal));
27978
27979        let results: Vec<Value> = similarities
27980            .iter()
27981            .take(k)
27982            .map(|(idx, sim)| {
27983                let mut result = HashMap::new();
27984                result.insert("index".to_string(), Value::Int(*idx as i64));
27985                result.insert("similarity".to_string(), Value::Float(*sim));
27986                result.insert(
27987                    "vector".to_string(),
27988                    vectors.get(*idx).cloned().unwrap_or(Value::Null),
27989                );
27990                result.insert(
27991                    "metadata".to_string(),
27992                    metadata.get(*idx).cloned().unwrap_or(Value::Null),
27993                );
27994                Value::Map(Rc::new(RefCell::new(result)))
27995            })
27996            .collect();
27997
27998        Ok(Value::Array(Rc::new(RefCell::new(results))))
27999    });
28000}
28001
28002// ============================================================================
28003// MULTI-AGENT COORDINATION - Swarm behaviors and agent communication
28004// ============================================================================
28005
28006/// Agent registry for multi-agent coordination
28007thread_local! {
28008    static AGENT_REGISTRY: RefCell<HashMap<String, AgentInfo>> = RefCell::new(HashMap::new());
28009    static AGENT_MESSAGES: RefCell<HashMap<String, Vec<AgentMessage>>> = RefCell::new(HashMap::new());
28010}
28011
28012#[derive(Clone)]
28013struct AgentInfo {
28014    id: String,
28015    agent_type: String,
28016    state: HashMap<String, Value>,
28017    capabilities: Vec<String>,
28018    created_at: u64,
28019}
28020
28021#[derive(Clone)]
28022struct AgentMessage {
28023    from: String,
28024    to: String,
28025    msg_type: String,
28026    content: Value,
28027    timestamp: u64,
28028}
28029
28030fn register_agent_swarm(interp: &mut Interpreter) {
28031    // swarm_create_agent - Create a new agent in the swarm
28032    define(interp, "swarm_create_agent", Some(2), |_, args| {
28033        let agent_id = match &args[0] {
28034            Value::String(s) => s.as_str().to_string(),
28035            _ => return Err(RuntimeError::new("swarm_create_agent requires string id")),
28036        };
28037
28038        let agent_type = match &args[1] {
28039            Value::String(s) => s.as_str().to_string(),
28040            _ => return Err(RuntimeError::new("swarm_create_agent requires string type")),
28041        };
28042
28043        let now = std::time::SystemTime::now()
28044            .duration_since(std::time::UNIX_EPOCH)
28045            .unwrap_or_default()
28046            .as_secs();
28047
28048        let agent = AgentInfo {
28049            id: agent_id.clone(),
28050            agent_type,
28051            state: HashMap::new(),
28052            capabilities: Vec::new(),
28053            created_at: now,
28054        };
28055
28056        AGENT_REGISTRY.with(|registry| {
28057            registry.borrow_mut().insert(agent_id.clone(), agent);
28058        });
28059
28060        AGENT_MESSAGES.with(|messages| {
28061            messages.borrow_mut().insert(agent_id.clone(), Vec::new());
28062        });
28063
28064        let mut result = HashMap::new();
28065        result.insert("id".to_string(), Value::String(Rc::new(agent_id)));
28066        result.insert("created_at".to_string(), Value::Int(now as i64));
28067        Ok(Value::Map(Rc::new(RefCell::new(result))))
28068    });
28069
28070    // swarm_add_capability - Add a capability to an agent
28071    define(interp, "swarm_add_capability", Some(2), |_, args| {
28072        let agent_id = match &args[0] {
28073            Value::String(s) => s.as_str().to_string(),
28074            Value::Map(m) => m
28075                .borrow()
28076                .get("id")
28077                .and_then(|v| {
28078                    if let Value::String(s) = v {
28079                        Some(s.as_str().to_string())
28080                    } else {
28081                        None
28082                    }
28083                })
28084                .ok_or_else(|| RuntimeError::new("Invalid agent"))?,
28085            _ => return Err(RuntimeError::new("swarm_add_capability requires agent")),
28086        };
28087
28088        let capability = match &args[1] {
28089            Value::String(s) => s.as_str().to_string(),
28090            _ => return Err(RuntimeError::new("capability must be string")),
28091        };
28092
28093        AGENT_REGISTRY.with(|registry| {
28094            if let Some(agent) = registry.borrow_mut().get_mut(&agent_id) {
28095                if !agent.capabilities.contains(&capability) {
28096                    agent.capabilities.push(capability);
28097                }
28098                Ok(Value::Bool(true))
28099            } else {
28100                Err(RuntimeError::new(format!("Agent '{}' not found", agent_id)))
28101            }
28102        })
28103    });
28104
28105    // swarm_send_message - Send a message from one agent to another
28106    define(interp, "swarm_send_message", Some(4), |_, args| {
28107        let from_id = match &args[0] {
28108            Value::String(s) => s.as_str().to_string(),
28109            Value::Map(m) => m
28110                .borrow()
28111                .get("id")
28112                .and_then(|v| {
28113                    if let Value::String(s) = v {
28114                        Some(s.as_str().to_string())
28115                    } else {
28116                        None
28117                    }
28118                })
28119                .ok_or_else(|| RuntimeError::new("Invalid sender agent"))?,
28120            _ => {
28121                return Err(RuntimeError::new(
28122                    "swarm_send_message requires sender agent",
28123                ))
28124            }
28125        };
28126
28127        let to_id = match &args[1] {
28128            Value::String(s) => s.as_str().to_string(),
28129            Value::Map(m) => m
28130                .borrow()
28131                .get("id")
28132                .and_then(|v| {
28133                    if let Value::String(s) = v {
28134                        Some(s.as_str().to_string())
28135                    } else {
28136                        None
28137                    }
28138                })
28139                .ok_or_else(|| RuntimeError::new("Invalid receiver agent"))?,
28140            _ => {
28141                return Err(RuntimeError::new(
28142                    "swarm_send_message requires receiver agent",
28143                ))
28144            }
28145        };
28146
28147        let msg_type = match &args[2] {
28148            Value::String(s) => s.as_str().to_string(),
28149            _ => return Err(RuntimeError::new("message type must be string")),
28150        };
28151
28152        let content = args[3].clone();
28153
28154        let now = std::time::SystemTime::now()
28155            .duration_since(std::time::UNIX_EPOCH)
28156            .unwrap_or_default()
28157            .as_secs();
28158
28159        let message = AgentMessage {
28160            from: from_id.clone(),
28161            to: to_id.clone(),
28162            msg_type,
28163            content,
28164            timestamp: now,
28165        };
28166
28167        AGENT_MESSAGES.with(|messages| {
28168            if let Some(queue) = messages.borrow_mut().get_mut(&to_id) {
28169                queue.push(message);
28170                Ok(Value::Bool(true))
28171            } else {
28172                Err(RuntimeError::new(format!("Agent '{}' not found", to_id)))
28173            }
28174        })
28175    });
28176
28177    // swarm_receive_messages - Get messages for an agent
28178    define(interp, "swarm_receive_messages", Some(1), |_, args| {
28179        let agent_id = match &args[0] {
28180            Value::String(s) => s.as_str().to_string(),
28181            Value::Map(m) => m
28182                .borrow()
28183                .get("id")
28184                .and_then(|v| {
28185                    if let Value::String(s) = v {
28186                        Some(s.as_str().to_string())
28187                    } else {
28188                        None
28189                    }
28190                })
28191                .ok_or_else(|| RuntimeError::new("Invalid agent"))?,
28192            _ => return Err(RuntimeError::new("swarm_receive_messages requires agent")),
28193        };
28194
28195        AGENT_MESSAGES.with(|messages| {
28196            if let Some(queue) = messages.borrow_mut().get_mut(&agent_id) {
28197                let msgs: Vec<Value> = queue
28198                    .drain(..)
28199                    .map(|m| {
28200                        let mut msg_map = HashMap::new();
28201                        msg_map.insert("from".to_string(), Value::String(Rc::new(m.from)));
28202                        msg_map.insert("to".to_string(), Value::String(Rc::new(m.to)));
28203                        msg_map.insert("type".to_string(), Value::String(Rc::new(m.msg_type)));
28204                        msg_map.insert("content".to_string(), m.content);
28205                        msg_map.insert("timestamp".to_string(), Value::Int(m.timestamp as i64));
28206                        Value::Map(Rc::new(RefCell::new(msg_map)))
28207                    })
28208                    .collect();
28209                Ok(Value::Array(Rc::new(RefCell::new(msgs))))
28210            } else {
28211                Ok(Value::Array(Rc::new(RefCell::new(Vec::new()))))
28212            }
28213        })
28214    });
28215
28216    // swarm_broadcast - Broadcast message to all agents
28217    define(interp, "swarm_broadcast", Some(3), |_, args| {
28218        let from_id = match &args[0] {
28219            Value::String(s) => s.as_str().to_string(),
28220            Value::Map(m) => m
28221                .borrow()
28222                .get("id")
28223                .and_then(|v| {
28224                    if let Value::String(s) = v {
28225                        Some(s.as_str().to_string())
28226                    } else {
28227                        None
28228                    }
28229                })
28230                .ok_or_else(|| RuntimeError::new("Invalid sender agent"))?,
28231            _ => return Err(RuntimeError::new("swarm_broadcast requires sender agent")),
28232        };
28233
28234        let msg_type = match &args[1] {
28235            Value::String(s) => s.as_str().to_string(),
28236            _ => return Err(RuntimeError::new("message type must be string")),
28237        };
28238
28239        let content = args[2].clone();
28240
28241        let now = std::time::SystemTime::now()
28242            .duration_since(std::time::UNIX_EPOCH)
28243            .unwrap_or_default()
28244            .as_secs();
28245
28246        // Get all agent IDs except sender
28247        let agent_ids: Vec<String> = AGENT_REGISTRY.with(|registry| {
28248            registry
28249                .borrow()
28250                .keys()
28251                .filter(|id| *id != &from_id)
28252                .cloned()
28253                .collect()
28254        });
28255
28256        let mut count = 0;
28257        AGENT_MESSAGES.with(|messages| {
28258            let mut msgs = messages.borrow_mut();
28259            for to_id in agent_ids {
28260                if let Some(queue) = msgs.get_mut(&to_id) {
28261                    queue.push(AgentMessage {
28262                        from: from_id.clone(),
28263                        to: to_id,
28264                        msg_type: msg_type.clone(),
28265                        content: content.clone(),
28266                        timestamp: now,
28267                    });
28268                    count += 1;
28269                }
28270            }
28271        });
28272
28273        Ok(Value::Int(count))
28274    });
28275
28276    // swarm_find_agents - Find agents by capability
28277    define(interp, "swarm_find_agents", Some(1), |_, args| {
28278        let capability = match &args[0] {
28279            Value::String(s) => s.as_str().to_string(),
28280            _ => {
28281                return Err(RuntimeError::new(
28282                    "swarm_find_agents requires capability string",
28283                ))
28284            }
28285        };
28286
28287        let agents: Vec<Value> = AGENT_REGISTRY.with(|registry| {
28288            registry
28289                .borrow()
28290                .values()
28291                .filter(|agent| agent.capabilities.contains(&capability))
28292                .map(|agent| {
28293                    let mut info = HashMap::new();
28294                    info.insert("id".to_string(), Value::String(Rc::new(agent.id.clone())));
28295                    info.insert(
28296                        "type".to_string(),
28297                        Value::String(Rc::new(agent.agent_type.clone())),
28298                    );
28299                    info.insert(
28300                        "capabilities".to_string(),
28301                        Value::Array(Rc::new(RefCell::new(
28302                            agent
28303                                .capabilities
28304                                .iter()
28305                                .map(|c| Value::String(Rc::new(c.clone())))
28306                                .collect(),
28307                        ))),
28308                    );
28309                    Value::Map(Rc::new(RefCell::new(info)))
28310                })
28311                .collect()
28312        });
28313
28314        Ok(Value::Array(Rc::new(RefCell::new(agents))))
28315    });
28316
28317    // swarm_list_agents - List all agents
28318    define(interp, "swarm_list_agents", Some(0), |_, _args| {
28319        let agents: Vec<Value> = AGENT_REGISTRY.with(|registry| {
28320            registry
28321                .borrow()
28322                .values()
28323                .map(|agent| {
28324                    let mut info = HashMap::new();
28325                    info.insert("id".to_string(), Value::String(Rc::new(agent.id.clone())));
28326                    info.insert(
28327                        "type".to_string(),
28328                        Value::String(Rc::new(agent.agent_type.clone())),
28329                    );
28330                    info.insert(
28331                        "capabilities".to_string(),
28332                        Value::Array(Rc::new(RefCell::new(
28333                            agent
28334                                .capabilities
28335                                .iter()
28336                                .map(|c| Value::String(Rc::new(c.clone())))
28337                                .collect(),
28338                        ))),
28339                    );
28340                    info.insert(
28341                        "created_at".to_string(),
28342                        Value::Int(agent.created_at as i64),
28343                    );
28344                    Value::Map(Rc::new(RefCell::new(info)))
28345                })
28346                .collect()
28347        });
28348        Ok(Value::Array(Rc::new(RefCell::new(agents))))
28349    });
28350
28351    // swarm_set_state - Set agent state
28352    define(interp, "swarm_set_state", Some(3), |_, args| {
28353        let agent_id = match &args[0] {
28354            Value::String(s) => s.as_str().to_string(),
28355            Value::Map(m) => m
28356                .borrow()
28357                .get("id")
28358                .and_then(|v| {
28359                    if let Value::String(s) = v {
28360                        Some(s.as_str().to_string())
28361                    } else {
28362                        None
28363                    }
28364                })
28365                .ok_or_else(|| RuntimeError::new("Invalid agent"))?,
28366            _ => return Err(RuntimeError::new("swarm_set_state requires agent")),
28367        };
28368
28369        let key = match &args[1] {
28370            Value::String(s) => s.as_str().to_string(),
28371            _ => return Err(RuntimeError::new("key must be string")),
28372        };
28373
28374        let value = args[2].clone();
28375
28376        AGENT_REGISTRY.with(|registry| {
28377            if let Some(agent) = registry.borrow_mut().get_mut(&agent_id) {
28378                agent.state.insert(key, value);
28379                Ok(Value::Bool(true))
28380            } else {
28381                Err(RuntimeError::new(format!("Agent '{}' not found", agent_id)))
28382            }
28383        })
28384    });
28385
28386    // swarm_get_state - Get agent state
28387    define(interp, "swarm_get_state", Some(2), |_, args| {
28388        let agent_id = match &args[0] {
28389            Value::String(s) => s.as_str().to_string(),
28390            Value::Map(m) => m
28391                .borrow()
28392                .get("id")
28393                .and_then(|v| {
28394                    if let Value::String(s) = v {
28395                        Some(s.as_str().to_string())
28396                    } else {
28397                        None
28398                    }
28399                })
28400                .ok_or_else(|| RuntimeError::new("Invalid agent"))?,
28401            _ => return Err(RuntimeError::new("swarm_get_state requires agent")),
28402        };
28403
28404        let key = match &args[1] {
28405            Value::String(s) => s.as_str().to_string(),
28406            _ => return Err(RuntimeError::new("key must be string")),
28407        };
28408
28409        AGENT_REGISTRY.with(|registry| {
28410            if let Some(agent) = registry.borrow().get(&agent_id) {
28411                Ok(agent.state.get(&key).cloned().unwrap_or(Value::Null))
28412            } else {
28413                Ok(Value::Null)
28414            }
28415        })
28416    });
28417
28418    // swarm_remove_agent - Remove an agent from the swarm
28419    define(interp, "swarm_remove_agent", Some(1), |_, args| {
28420        let agent_id = match &args[0] {
28421            Value::String(s) => s.as_str().to_string(),
28422            Value::Map(m) => m
28423                .borrow()
28424                .get("id")
28425                .and_then(|v| {
28426                    if let Value::String(s) = v {
28427                        Some(s.as_str().to_string())
28428                    } else {
28429                        None
28430                    }
28431                })
28432                .ok_or_else(|| RuntimeError::new("Invalid agent"))?,
28433            _ => return Err(RuntimeError::new("swarm_remove_agent requires agent")),
28434        };
28435
28436        let removed =
28437            AGENT_REGISTRY.with(|registry| registry.borrow_mut().remove(&agent_id).is_some());
28438
28439        AGENT_MESSAGES.with(|messages| {
28440            messages.borrow_mut().remove(&agent_id);
28441        });
28442
28443        Ok(Value::Bool(removed))
28444    });
28445
28446    // swarm_consensus - Simple majority voting
28447    define(interp, "swarm_consensus", Some(2), |_, args| {
28448        let topic = match &args[0] {
28449            Value::String(s) => s.as_str().to_string(),
28450            _ => return Err(RuntimeError::new("topic must be string")),
28451        };
28452
28453        let votes = match &args[1] {
28454            Value::Array(arr) => arr.borrow().clone(),
28455            _ => return Err(RuntimeError::new("votes must be array")),
28456        };
28457
28458        // Count votes
28459        let mut vote_counts: HashMap<String, i64> = HashMap::new();
28460        for vote in votes.iter() {
28461            let vote_str = match vote {
28462                Value::String(s) => s.as_str().to_string(),
28463                Value::Bool(b) => b.to_string(),
28464                Value::Int(n) => n.to_string(),
28465                _ => continue,
28466            };
28467            *vote_counts.entry(vote_str).or_insert(0) += 1;
28468        }
28469
28470        // Find winner
28471        let total = votes.len() as i64;
28472        let (winner, count) = vote_counts
28473            .iter()
28474            .max_by_key(|(_, &count)| count)
28475            .map(|(k, &v)| (k.clone(), v))
28476            .unwrap_or_default();
28477
28478        let mut result = HashMap::new();
28479        result.insert("topic".to_string(), Value::String(Rc::new(topic)));
28480        result.insert("winner".to_string(), Value::String(Rc::new(winner)));
28481        result.insert("votes".to_string(), Value::Int(count));
28482        result.insert("total".to_string(), Value::Int(total));
28483        result.insert("majority".to_string(), Value::Bool(count > total / 2));
28484
28485        Ok(Value::Map(Rc::new(RefCell::new(result))))
28486    });
28487}
28488
28489// ============================================================================
28490// REASONING PRIMITIVES - Constraint satisfaction and logical inference
28491// ============================================================================
28492
28493fn register_agent_reasoning(interp: &mut Interpreter) {
28494    // reason_constraint - Create a constraint
28495    define(interp, "reason_constraint", Some(3), |_, args| {
28496        let name = match &args[0] {
28497            Value::String(s) => s.as_str().to_string(),
28498            _ => return Err(RuntimeError::new("constraint name must be string")),
28499        };
28500
28501        let constraint_type = match &args[1] {
28502            Value::String(s) => s.as_str().to_string(),
28503            _ => return Err(RuntimeError::new("constraint type must be string")),
28504        };
28505
28506        let params = args[2].clone();
28507
28508        let mut constraint = HashMap::new();
28509        constraint.insert("name".to_string(), Value::String(Rc::new(name)));
28510        constraint.insert("type".to_string(), Value::String(Rc::new(constraint_type)));
28511        constraint.insert("params".to_string(), params);
28512        constraint.insert("satisfied".to_string(), Value::Bool(false));
28513
28514        Ok(Value::Map(Rc::new(RefCell::new(constraint))))
28515    });
28516
28517    // reason_check_constraint - Check if a constraint is satisfied
28518    define(interp, "reason_check_constraint", Some(2), |_, args| {
28519        let constraint = match &args[0] {
28520            Value::Map(m) => m.borrow().clone(),
28521            _ => {
28522                return Err(RuntimeError::new(
28523                    "reason_check_constraint requires constraint",
28524                ))
28525            }
28526        };
28527
28528        let context = match &args[1] {
28529            Value::Map(m) => m.borrow().clone(),
28530            _ => {
28531                return Err(RuntimeError::new(
28532                    "reason_check_constraint requires context",
28533                ))
28534            }
28535        };
28536
28537        let constraint_type = constraint
28538            .get("type")
28539            .and_then(|v| {
28540                if let Value::String(s) = v {
28541                    Some(s.as_str())
28542                } else {
28543                    None
28544                }
28545            })
28546            .unwrap_or("unknown");
28547
28548        let params = constraint.get("params").cloned().unwrap_or(Value::Null);
28549
28550        let satisfied = match constraint_type {
28551            "equals" => {
28552                if let Value::Map(p) = &params {
28553                    let p = p.borrow();
28554                    let var_name = p
28555                        .get("var")
28556                        .and_then(|v| {
28557                            if let Value::String(s) = v {
28558                                Some(s.as_str().to_string())
28559                            } else {
28560                                None
28561                            }
28562                        })
28563                        .unwrap_or_default();
28564                    let expected = p.get("value").cloned().unwrap_or(Value::Null);
28565                    let actual = context.get(&var_name).cloned().unwrap_or(Value::Null);
28566                    values_equal_simple(&actual, &expected)
28567                } else {
28568                    false
28569                }
28570            }
28571            "not_null" => {
28572                if let Value::Map(p) = &params {
28573                    let p = p.borrow();
28574                    let var_name = p
28575                        .get("var")
28576                        .and_then(|v| {
28577                            if let Value::String(s) = v {
28578                                Some(s.as_str().to_string())
28579                            } else {
28580                                None
28581                            }
28582                        })
28583                        .unwrap_or_default();
28584                    !matches!(context.get(&var_name), None | Some(Value::Null))
28585                } else {
28586                    false
28587                }
28588            }
28589            "range" => {
28590                if let Value::Map(p) = &params {
28591                    let p = p.borrow();
28592                    let var_name = p
28593                        .get("var")
28594                        .and_then(|v| {
28595                            if let Value::String(s) = v {
28596                                Some(s.as_str().to_string())
28597                            } else {
28598                                None
28599                            }
28600                        })
28601                        .unwrap_or_default();
28602                    let min = p
28603                        .get("min")
28604                        .and_then(|v| match v {
28605                            Value::Int(n) => Some(*n as f64),
28606                            Value::Float(f) => Some(*f),
28607                            _ => None,
28608                        })
28609                        .unwrap_or(f64::NEG_INFINITY);
28610                    let max = p
28611                        .get("max")
28612                        .and_then(|v| match v {
28613                            Value::Int(n) => Some(*n as f64),
28614                            Value::Float(f) => Some(*f),
28615                            _ => None,
28616                        })
28617                        .unwrap_or(f64::INFINITY);
28618                    let actual = context
28619                        .get(&var_name)
28620                        .and_then(|v| match v {
28621                            Value::Int(n) => Some(*n as f64),
28622                            Value::Float(f) => Some(*f),
28623                            _ => None,
28624                        })
28625                        .unwrap_or(0.0);
28626                    actual >= min && actual <= max
28627                } else {
28628                    false
28629                }
28630            }
28631            "contains" => {
28632                if let Value::Map(p) = &params {
28633                    let p = p.borrow();
28634                    let var_name = p
28635                        .get("var")
28636                        .and_then(|v| {
28637                            if let Value::String(s) = v {
28638                                Some(s.as_str().to_string())
28639                            } else {
28640                                None
28641                            }
28642                        })
28643                        .unwrap_or_default();
28644                    let needle = p
28645                        .get("value")
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 actual = context
28655                        .get(&var_name)
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                    actual.contains(&needle)
28665                } else {
28666                    false
28667                }
28668            }
28669            _ => false,
28670        };
28671
28672        let mut result = HashMap::new();
28673        result.insert("satisfied".to_string(), Value::Bool(satisfied));
28674        result.insert(
28675            "constraint".to_string(),
28676            Value::Map(Rc::new(RefCell::new(constraint))),
28677        );
28678
28679        Ok(Value::Map(Rc::new(RefCell::new(result))))
28680    });
28681
28682    // reason_check_all - Check if all constraints are satisfied
28683    define(interp, "reason_check_all", Some(2), |interp, args| {
28684        let constraints = match &args[0] {
28685            Value::Array(arr) => arr.borrow().clone(),
28686            _ => {
28687                return Err(RuntimeError::new(
28688                    "reason_check_all requires constraints array",
28689                ))
28690            }
28691        };
28692
28693        let context = args[1].clone();
28694
28695        let mut all_satisfied = true;
28696        let mut results: Vec<Value> = Vec::new();
28697
28698        for constraint in constraints.iter() {
28699            // Call reason_check_constraint for each
28700            if let Value::Map(c) = constraint {
28701                let c_type = c
28702                    .borrow()
28703                    .get("type")
28704                    .and_then(|v| {
28705                        if let Value::String(s) = v {
28706                            Some(s.as_ref().clone())
28707                        } else {
28708                            None
28709                        }
28710                    })
28711                    .unwrap_or_else(|| "unknown".to_string());
28712                let params = c.borrow().get("params").cloned().unwrap_or(Value::Null);
28713
28714                let ctx = match &context {
28715                    Value::Map(m) => m.borrow().clone(),
28716                    _ => HashMap::new(),
28717                };
28718
28719                let satisfied = match c_type.as_str() {
28720                    "equals" => {
28721                        if let Value::Map(p) = &params {
28722                            let p = p.borrow();
28723                            let var_name = p
28724                                .get("var")
28725                                .and_then(|v| {
28726                                    if let Value::String(s) = v {
28727                                        Some(s.as_str().to_string())
28728                                    } else {
28729                                        None
28730                                    }
28731                                })
28732                                .unwrap_or_default();
28733                            let expected = p.get("value").cloned().unwrap_or(Value::Null);
28734                            let actual = ctx.get(&var_name).cloned().unwrap_or(Value::Null);
28735                            values_equal_simple(&actual, &expected)
28736                        } else {
28737                            false
28738                        }
28739                    }
28740                    "not_null" => {
28741                        if let Value::Map(p) = &params {
28742                            let p = p.borrow();
28743                            let var_name = p
28744                                .get("var")
28745                                .and_then(|v| {
28746                                    if let Value::String(s) = v {
28747                                        Some(s.as_str().to_string())
28748                                    } else {
28749                                        None
28750                                    }
28751                                })
28752                                .unwrap_or_default();
28753                            !matches!(ctx.get(&var_name), None | Some(Value::Null))
28754                        } else {
28755                            false
28756                        }
28757                    }
28758                    _ => true, // Unknown constraints pass by default
28759                };
28760
28761                if !satisfied {
28762                    all_satisfied = false;
28763                }
28764
28765                let mut r = HashMap::new();
28766                r.insert("constraint".to_string(), constraint.clone());
28767                r.insert("satisfied".to_string(), Value::Bool(satisfied));
28768                results.push(Value::Map(Rc::new(RefCell::new(r))));
28769            }
28770        }
28771
28772        let _ = interp; // Silence unused warning
28773
28774        let mut result = HashMap::new();
28775        result.insert("all_satisfied".to_string(), Value::Bool(all_satisfied));
28776        result.insert(
28777            "results".to_string(),
28778            Value::Array(Rc::new(RefCell::new(results))),
28779        );
28780        result.insert("total".to_string(), Value::Int(constraints.len() as i64));
28781
28782        Ok(Value::Map(Rc::new(RefCell::new(result))))
28783    });
28784
28785    // reason_implies - Create an implication (if A then B)
28786    define(interp, "reason_implies", Some(2), |_, args| {
28787        let antecedent = args[0].clone();
28788        let consequent = args[1].clone();
28789
28790        let mut implication = HashMap::new();
28791        implication.insert(
28792            "type".to_string(),
28793            Value::String(Rc::new("implication".to_string())),
28794        );
28795        implication.insert("if".to_string(), antecedent);
28796        implication.insert("then".to_string(), consequent);
28797
28798        Ok(Value::Map(Rc::new(RefCell::new(implication))))
28799    });
28800
28801    // reason_and - Logical AND of multiple conditions
28802    define(interp, "reason_and", None, |_, args| {
28803        let conditions: Vec<Value> = args.into_iter().collect();
28804
28805        let mut conjunction = HashMap::new();
28806        conjunction.insert(
28807            "type".to_string(),
28808            Value::String(Rc::new("and".to_string())),
28809        );
28810        conjunction.insert(
28811            "conditions".to_string(),
28812            Value::Array(Rc::new(RefCell::new(conditions))),
28813        );
28814
28815        Ok(Value::Map(Rc::new(RefCell::new(conjunction))))
28816    });
28817
28818    // reason_or - Logical OR of multiple conditions
28819    define(interp, "reason_or", None, |_, args| {
28820        let conditions: Vec<Value> = args.into_iter().collect();
28821
28822        let mut disjunction = HashMap::new();
28823        disjunction.insert("type".to_string(), Value::String(Rc::new("or".to_string())));
28824        disjunction.insert(
28825            "conditions".to_string(),
28826            Value::Array(Rc::new(RefCell::new(conditions))),
28827        );
28828
28829        Ok(Value::Map(Rc::new(RefCell::new(disjunction))))
28830    });
28831
28832    // reason_not - Logical NOT
28833    define(interp, "reason_not", Some(1), |_, args| {
28834        let condition = args[0].clone();
28835
28836        let mut negation = HashMap::new();
28837        negation.insert(
28838            "type".to_string(),
28839            Value::String(Rc::new("not".to_string())),
28840        );
28841        negation.insert("condition".to_string(), condition);
28842
28843        Ok(Value::Map(Rc::new(RefCell::new(negation))))
28844    });
28845
28846    // reason_evaluate - Evaluate a logical expression
28847    define(interp, "reason_evaluate", Some(2), |_, args| {
28848        let expr = match &args[0] {
28849            Value::Map(m) => m.borrow().clone(),
28850            Value::Bool(b) => return Ok(Value::Bool(*b)),
28851            _ => return Err(RuntimeError::new("reason_evaluate requires expression")),
28852        };
28853
28854        let context = match &args[1] {
28855            Value::Map(m) => m.borrow().clone(),
28856            _ => HashMap::new(),
28857        };
28858
28859        fn eval_expr(expr: &HashMap<String, Value>, ctx: &HashMap<String, Value>) -> bool {
28860            let expr_type = expr
28861                .get("type")
28862                .and_then(|v| {
28863                    if let Value::String(s) = v {
28864                        Some(s.as_str())
28865                    } else {
28866                        None
28867                    }
28868                })
28869                .unwrap_or("unknown");
28870
28871            match expr_type {
28872                "and" => {
28873                    if let Some(Value::Array(conditions)) = expr.get("conditions") {
28874                        conditions.borrow().iter().all(|c| {
28875                            if let Value::Map(m) = c {
28876                                eval_expr(&m.borrow(), ctx)
28877                            } else if let Value::Bool(b) = c {
28878                                *b
28879                            } else {
28880                                false
28881                            }
28882                        })
28883                    } else {
28884                        false
28885                    }
28886                }
28887                "or" => {
28888                    if let Some(Value::Array(conditions)) = expr.get("conditions") {
28889                        conditions.borrow().iter().any(|c| {
28890                            if let Value::Map(m) = c {
28891                                eval_expr(&m.borrow(), ctx)
28892                            } else if let Value::Bool(b) = c {
28893                                *b
28894                            } else {
28895                                false
28896                            }
28897                        })
28898                    } else {
28899                        false
28900                    }
28901                }
28902                "not" => {
28903                    if let Some(condition) = expr.get("condition") {
28904                        if let Value::Map(m) = condition {
28905                            !eval_expr(&m.borrow(), ctx)
28906                        } else if let Value::Bool(b) = condition {
28907                            !b
28908                        } else {
28909                            false
28910                        }
28911                    } else {
28912                        false
28913                    }
28914                }
28915                "implication" => {
28916                    let antecedent = if let Some(a) = expr.get("if") {
28917                        if let Value::Map(m) = a {
28918                            eval_expr(&m.borrow(), ctx)
28919                        } else if let Value::Bool(b) = a {
28920                            *b
28921                        } else {
28922                            false
28923                        }
28924                    } else {
28925                        false
28926                    };
28927
28928                    let consequent = if let Some(c) = expr.get("then") {
28929                        if let Value::Map(m) = c {
28930                            eval_expr(&m.borrow(), ctx)
28931                        } else if let Value::Bool(b) = c {
28932                            *b
28933                        } else {
28934                            false
28935                        }
28936                    } else {
28937                        false
28938                    };
28939
28940                    // A implies B is equivalent to (not A) or B
28941                    !antecedent || consequent
28942                }
28943                _ => false,
28944            }
28945        }
28946
28947        Ok(Value::Bool(eval_expr(&expr, &context)))
28948    });
28949
28950    // reason_proof - Create a proof step
28951    define(interp, "reason_proof", Some(3), |_, args| {
28952        let step = match &args[0] {
28953            Value::String(s) => s.as_str().to_string(),
28954            _ => return Err(RuntimeError::new("proof step must be string")),
28955        };
28956
28957        let justification = match &args[1] {
28958            Value::String(s) => s.as_str().to_string(),
28959            _ => return Err(RuntimeError::new("justification must be string")),
28960        };
28961
28962        let conclusion = args[2].clone();
28963
28964        let now = std::time::SystemTime::now()
28965            .duration_since(std::time::UNIX_EPOCH)
28966            .unwrap_or_default()
28967            .as_secs();
28968
28969        let mut proof = HashMap::new();
28970        proof.insert("step".to_string(), Value::String(Rc::new(step)));
28971        proof.insert(
28972            "justification".to_string(),
28973            Value::String(Rc::new(justification)),
28974        );
28975        proof.insert("conclusion".to_string(), conclusion);
28976        proof.insert("timestamp".to_string(), Value::Int(now as i64));
28977
28978        Ok(Value::Map(Rc::new(RefCell::new(proof))))
28979    });
28980
28981    // reason_chain - Chain proof steps together
28982    define(interp, "reason_chain", None, |_, args| {
28983        let steps: Vec<Value> = args.into_iter().collect();
28984
28985        let mut chain = HashMap::new();
28986        chain.insert(
28987            "type".to_string(),
28988            Value::String(Rc::new("proof_chain".to_string())),
28989        );
28990        chain.insert(
28991            "steps".to_string(),
28992            Value::Array(Rc::new(RefCell::new(steps.clone()))),
28993        );
28994        chain.insert("length".to_string(), Value::Int(steps.len() as i64));
28995
28996        // Get final conclusion
28997        let final_conclusion = steps
28998            .last()
28999            .and_then(|s| {
29000                if let Value::Map(m) = s {
29001                    m.borrow().get("conclusion").cloned()
29002                } else {
29003                    None
29004                }
29005            })
29006            .unwrap_or(Value::Null);
29007        chain.insert("final_conclusion".to_string(), final_conclusion);
29008
29009        Ok(Value::Map(Rc::new(RefCell::new(chain))))
29010    });
29011
29012    // reason_hypothesis - Create a hypothesis with evidence requirements
29013    define(interp, "reason_hypothesis", Some(2), |_, args| {
29014        let claim = match &args[0] {
29015            Value::String(s) => s.as_str().to_string(),
29016            _ => return Err(RuntimeError::new("hypothesis claim must be string")),
29017        };
29018
29019        let required_evidence = match &args[1] {
29020            Value::Array(arr) => arr.clone(),
29021            _ => return Err(RuntimeError::new("required evidence must be array")),
29022        };
29023
29024        let mut hypothesis = HashMap::new();
29025        hypothesis.insert("claim".to_string(), Value::String(Rc::new(claim)));
29026        hypothesis.insert(
29027            "required_evidence".to_string(),
29028            Value::Array(required_evidence),
29029        );
29030        hypothesis.insert(
29031            "status".to_string(),
29032            Value::String(Rc::new("unverified".to_string())),
29033        );
29034        hypothesis.insert("confidence".to_string(), Value::Float(0.0));
29035
29036        Ok(Value::Map(Rc::new(RefCell::new(hypothesis))))
29037    });
29038
29039    // reason_verify_hypothesis - Verify a hypothesis against evidence
29040    define(interp, "reason_verify_hypothesis", Some(2), |_, args| {
29041        let hypothesis = match &args[0] {
29042            Value::Map(m) => m.clone(),
29043            _ => {
29044                return Err(RuntimeError::new(
29045                    "reason_verify_hypothesis requires hypothesis",
29046                ))
29047            }
29048        };
29049
29050        let evidence = match &args[1] {
29051            Value::Map(m) => m.borrow().clone(),
29052            _ => {
29053                return Err(RuntimeError::new(
29054                    "reason_verify_hypothesis requires evidence map",
29055                ))
29056            }
29057        };
29058
29059        let required = hypothesis
29060            .borrow()
29061            .get("required_evidence")
29062            .and_then(|v| {
29063                if let Value::Array(arr) = v {
29064                    Some(arr.borrow().clone())
29065                } else {
29066                    None
29067                }
29068            })
29069            .unwrap_or_default();
29070
29071        let mut found = 0;
29072        for req in required.iter() {
29073            if let Value::String(key) = req {
29074                if evidence.contains_key(key.as_str()) {
29075                    found += 1;
29076                }
29077            }
29078        }
29079
29080        let total = required.len();
29081        let confidence = if total > 0 {
29082            found as f64 / total as f64
29083        } else {
29084            0.0
29085        };
29086        let verified = found == total && total > 0;
29087
29088        {
29089            let mut h = hypothesis.borrow_mut();
29090            h.insert("confidence".to_string(), Value::Float(confidence));
29091            h.insert(
29092                "status".to_string(),
29093                Value::String(Rc::new(if verified {
29094                    "verified".to_string()
29095                } else {
29096                    "unverified".to_string()
29097                })),
29098            );
29099        }
29100
29101        let mut result = HashMap::new();
29102        result.insert("verified".to_string(), Value::Bool(verified));
29103        result.insert("confidence".to_string(), Value::Float(confidence));
29104        result.insert("found".to_string(), Value::Int(found as i64));
29105        result.insert("required".to_string(), Value::Int(total as i64));
29106        result.insert("hypothesis".to_string(), Value::Map(hypothesis));
29107
29108        Ok(Value::Map(Rc::new(RefCell::new(result))))
29109    });
29110}
29111
29112
29113// =============================================================================
29114// PHASE 20: TERMINAL/CONSOLE MODULE
29115// =============================================================================
29116// ANSI terminal styling, progress bars, spinners, and table formatting.
29117// Designed for CLI applications like Ritualis.
29118
29119fn register_terminal(interp: &mut Interpreter) {
29120    // ANSI escape code constants
29121    const RESET: &str = "\x1b[0m";
29122    const BOLD: &str = "\x1b[1m";
29123    const DIM: &str = "\x1b[2m";
29124    const ITALIC: &str = "\x1b[3m";
29125    const UNDERLINE: &str = "\x1b[4m";
29126
29127    // Foreground colors
29128    const FG_BLACK: &str = "\x1b[30m";
29129    const FG_RED: &str = "\x1b[31m";
29130    const FG_GREEN: &str = "\x1b[32m";
29131    const FG_YELLOW: &str = "\x1b[33m";
29132    const FG_BLUE: &str = "\x1b[34m";
29133    const FG_MAGENTA: &str = "\x1b[35m";
29134    const FG_CYAN: &str = "\x1b[36m";
29135    const FG_WHITE: &str = "\x1b[37m";
29136
29137    // Bright foreground colors
29138    const FG_BRIGHT_BLACK: &str = "\x1b[90m";
29139    const FG_BRIGHT_RED: &str = "\x1b[91m";
29140    const FG_BRIGHT_GREEN: &str = "\x1b[92m";
29141    const FG_BRIGHT_YELLOW: &str = "\x1b[93m";
29142    const FG_BRIGHT_BLUE: &str = "\x1b[94m";
29143    const FG_BRIGHT_MAGENTA: &str = "\x1b[95m";
29144    const FG_BRIGHT_CYAN: &str = "\x1b[96m";
29145    const FG_BRIGHT_WHITE: &str = "\x1b[97m";
29146
29147    // term_reset - reset all styling
29148    define(interp, "term_reset", Some(0), |_, _| {
29149        Ok(Value::String(Rc::new(RESET.to_string())))
29150    });
29151
29152    // term_bold - make text bold
29153    define(interp, "term_bold", Some(1), |_, args| {
29154        let text = match &args[0] {
29155            Value::String(s) => (**s).clone(),
29156            other => format!("{}", other),
29157        };
29158        Ok(Value::String(Rc::new(format!("{}{}{}", BOLD, text, RESET))))
29159    });
29160
29161    // term_dim - make text dim
29162    define(interp, "term_dim", Some(1), |_, args| {
29163        let text = match &args[0] {
29164            Value::String(s) => (**s).clone(),
29165            other => format!("{}", other),
29166        };
29167        Ok(Value::String(Rc::new(format!("{}{}{}", DIM, text, RESET))))
29168    });
29169
29170    // term_italic - make text italic
29171    define(interp, "term_italic", Some(1), |_, args| {
29172        let text = match &args[0] {
29173            Value::String(s) => (**s).clone(),
29174            other => format!("{}", other),
29175        };
29176        Ok(Value::String(Rc::new(format!("{}{}{}", ITALIC, text, RESET))))
29177    });
29178
29179    // term_underline - underline text
29180    define(interp, "term_underline", Some(1), |_, args| {
29181        let text = match &args[0] {
29182            Value::String(s) => (**s).clone(),
29183            other => format!("{}", other),
29184        };
29185        Ok(Value::String(Rc::new(format!("{}{}{}", UNDERLINE, text, RESET))))
29186    });
29187
29188    // term_red - red text
29189    define(interp, "term_red", Some(1), |_, args| {
29190        let text = match &args[0] {
29191            Value::String(s) => (**s).clone(),
29192            other => format!("{}", other),
29193        };
29194        Ok(Value::String(Rc::new(format!("{}{}{}", FG_RED, text, RESET))))
29195    });
29196
29197    // term_green - green text
29198    define(interp, "term_green", Some(1), |_, args| {
29199        let text = match &args[0] {
29200            Value::String(s) => (**s).clone(),
29201            other => format!("{}", other),
29202        };
29203        Ok(Value::String(Rc::new(format!("{}{}{}", FG_GREEN, text, RESET))))
29204    });
29205
29206    // term_yellow - yellow text
29207    define(interp, "term_yellow", Some(1), |_, args| {
29208        let text = match &args[0] {
29209            Value::String(s) => (**s).clone(),
29210            other => format!("{}", other),
29211        };
29212        Ok(Value::String(Rc::new(format!("{}{}{}", FG_YELLOW, text, RESET))))
29213    });
29214
29215    // term_blue - blue text
29216    define(interp, "term_blue", Some(1), |_, args| {
29217        let text = match &args[0] {
29218            Value::String(s) => (**s).clone(),
29219            other => format!("{}", other),
29220        };
29221        Ok(Value::String(Rc::new(format!("{}{}{}", FG_BLUE, text, RESET))))
29222    });
29223
29224    // term_magenta - magenta text
29225    define(interp, "term_magenta", Some(1), |_, args| {
29226        let text = match &args[0] {
29227            Value::String(s) => (**s).clone(),
29228            other => format!("{}", other),
29229        };
29230        Ok(Value::String(Rc::new(format!("{}{}{}", FG_MAGENTA, text, RESET))))
29231    });
29232
29233    // term_cyan - cyan text
29234    define(interp, "term_cyan", Some(1), |_, args| {
29235        let text = match &args[0] {
29236            Value::String(s) => (**s).clone(),
29237            other => format!("{}", other),
29238        };
29239        Ok(Value::String(Rc::new(format!("{}{}{}", FG_CYAN, text, RESET))))
29240    });
29241
29242    // term_white - white text
29243    define(interp, "term_white", Some(1), |_, args| {
29244        let text = match &args[0] {
29245            Value::String(s) => (**s).clone(),
29246            other => format!("{}", other),
29247        };
29248        Ok(Value::String(Rc::new(format!("{}{}{}", FG_WHITE, text, RESET))))
29249    });
29250
29251    // term_black - black text
29252    define(interp, "term_black", Some(1), |_, args| {
29253        let text = match &args[0] {
29254            Value::String(s) => (**s).clone(),
29255            other => format!("{}", other),
29256        };
29257        Ok(Value::String(Rc::new(format!("{}{}{}", FG_BLACK, text, RESET))))
29258    });
29259
29260    // term_bright_red - bright red text
29261    define(interp, "term_bright_red", Some(1), |_, args| {
29262        let text = match &args[0] {
29263            Value::String(s) => (**s).clone(),
29264            other => format!("{}", other),
29265        };
29266        Ok(Value::String(Rc::new(format!("{}{}{}", FG_BRIGHT_RED, text, RESET))))
29267    });
29268
29269    // term_bright_green - bright green text
29270    define(interp, "term_bright_green", Some(1), |_, args| {
29271        let text = match &args[0] {
29272            Value::String(s) => (**s).clone(),
29273            other => format!("{}", other),
29274        };
29275        Ok(Value::String(Rc::new(format!("{}{}{}", FG_BRIGHT_GREEN, text, RESET))))
29276    });
29277
29278    // term_bright_cyan - bright cyan text
29279    define(interp, "term_bright_cyan", Some(1), |_, args| {
29280        let text = match &args[0] {
29281            Value::String(s) => (**s).clone(),
29282            other => format!("{}", other),
29283        };
29284        Ok(Value::String(Rc::new(format!("{}{}{}", FG_BRIGHT_CYAN, text, RESET))))
29285    });
29286
29287    // term_style - apply multiple styles: term_style(text, "bold", "red")
29288    define(interp, "term_style", None, |_, args| {
29289        if args.is_empty() {
29290            return Err(RuntimeError::new("term_style requires at least text argument"));
29291        }
29292        let text = match &args[0] {
29293            Value::String(s) => (**s).clone(),
29294            other => format!("{}", other),
29295        };
29296
29297        let mut prefix = String::new();
29298        for arg in &args[1..] {
29299            if let Value::String(style) = arg {
29300                match style.as_str() {
29301                    "bold" => prefix.push_str(BOLD),
29302                    "dim" => prefix.push_str(DIM),
29303                    "italic" => prefix.push_str(ITALIC),
29304                    "underline" => prefix.push_str(UNDERLINE),
29305                    "red" => prefix.push_str(FG_RED),
29306                    "green" => prefix.push_str(FG_GREEN),
29307                    "yellow" => prefix.push_str(FG_YELLOW),
29308                    "blue" => prefix.push_str(FG_BLUE),
29309                    "magenta" => prefix.push_str(FG_MAGENTA),
29310                    "cyan" => prefix.push_str(FG_CYAN),
29311                    "white" => prefix.push_str(FG_WHITE),
29312                    "black" => prefix.push_str(FG_BLACK),
29313                    "bright_red" => prefix.push_str(FG_BRIGHT_RED),
29314                    "bright_green" => prefix.push_str(FG_BRIGHT_GREEN),
29315                    "bright_yellow" => prefix.push_str(FG_BRIGHT_YELLOW),
29316                    "bright_blue" => prefix.push_str(FG_BRIGHT_BLUE),
29317                    "bright_magenta" => prefix.push_str(FG_BRIGHT_MAGENTA),
29318                    "bright_cyan" => prefix.push_str(FG_BRIGHT_CYAN),
29319                    "bright_white" => prefix.push_str(FG_BRIGHT_WHITE),
29320                    _ => {} // ignore unknown styles
29321                }
29322            }
29323        }
29324
29325        Ok(Value::String(Rc::new(format!("{}{}{}", prefix, text, RESET))))
29326    });
29327
29328    // term_progress_bar - create a progress bar string
29329    // term_progress_bar(current, total, width) -> "[████████░░░░░░░░] 50%"
29330    define(interp, "term_progress_bar", Some(3), |_, args| {
29331        let current = match &args[0] {
29332            Value::Int(n) => *n as f64,
29333            Value::Float(f) => *f,
29334            _ => return Err(RuntimeError::new("term_progress_bar: current must be number")),
29335        };
29336        let total = match &args[1] {
29337            Value::Int(n) => *n as f64,
29338            Value::Float(f) => *f,
29339            _ => return Err(RuntimeError::new("term_progress_bar: total must be number")),
29340        };
29341        let width = match &args[2] {
29342            Value::Int(n) if *n > 0 => *n as usize,
29343            _ => return Err(RuntimeError::new("term_progress_bar: width must be positive integer")),
29344        };
29345
29346        let ratio = if total > 0.0 { (current / total).min(1.0).max(0.0) } else { 0.0 };
29347        let filled = (ratio * width as f64).round() as usize;
29348        let empty = width - filled;
29349        let percent = (ratio * 100.0).round() as i64;
29350
29351        let bar = format!(
29352            "[{}{}] {}%",
29353            "█".repeat(filled),
29354            "░".repeat(empty),
29355            percent
29356        );
29357
29358        Ok(Value::String(Rc::new(bar)))
29359    });
29360
29361    // term_spinner_frames - get spinner animation frames
29362    define(interp, "term_spinner_frames", Some(0), |_, _| {
29363        let frames: Vec<Value> = vec!["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]
29364            .into_iter()
29365            .map(|s| Value::String(Rc::new(s.to_string())))
29366            .collect();
29367        Ok(Value::Array(Rc::new(RefCell::new(frames))))
29368    });
29369
29370    // term_check - green checkmark
29371    define(interp, "term_check", Some(0), |_, _| {
29372        Ok(Value::String(Rc::new(format!("{}✓{}", FG_GREEN, RESET))))
29373    });
29374
29375    // term_cross - red cross
29376    define(interp, "term_cross", Some(0), |_, _| {
29377        Ok(Value::String(Rc::new(format!("{}✗{}", FG_RED, RESET))))
29378    });
29379
29380    // term_arrow - arrow symbol
29381    define(interp, "term_arrow", Some(0), |_, _| {
29382        Ok(Value::String(Rc::new("→".to_string())))
29383    });
29384
29385    // term_bullet - bullet point
29386    define(interp, "term_bullet", Some(0), |_, _| {
29387        Ok(Value::String(Rc::new("•".to_string())))
29388    });
29389
29390    // term_emoji - common emoji lookup
29391    define(interp, "term_emoji", Some(1), |_, args| {
29392        let name = match &args[0] {
29393            Value::String(s) => s.to_lowercase(),
29394            _ => return Err(RuntimeError::new("term_emoji requires string")),
29395        };
29396
29397        let emoji = match name.as_str() {
29398            "summon" | "install" => "🔮",
29399            "banish" | "uninstall" => "👋",
29400            "invoke" | "update" => "⚡",
29401            "awaken" | "start" => "🌅",
29402            "seal" | "stop" => "🔒",
29403            "check" | "ok" | "success" => "✓",
29404            "cross" | "error" | "fail" => "✗",
29405            "arrow" | "right" => "→",
29406            "warning" | "warn" => "⚠",
29407            "info" | "information" => "ℹ",
29408            "question" | "help" => "?",
29409            "star" => "★",
29410            "heart" => "❤",
29411            "fire" => "🔥",
29412            "rocket" => "🚀",
29413            "package" | "box" => "📦",
29414            "folder" | "directory" => "📁",
29415            "file" | "document" => "📄",
29416            "gear" | "settings" => "⚙",
29417            "search" | "seek" => "🔍",
29418            "download" => "⬇",
29419            "upload" => "⬆",
29420            "sync" | "refresh" => "🔄",
29421            "lock" | "locked" => "🔒",
29422            "unlock" | "unlocked" => "🔓",
29423            "key" => "🔑",
29424            "clock" | "time" => "🕐",
29425            "calendar" | "date" => "📅",
29426            "bell" | "notification" => "🔔",
29427            _ => "•",
29428        };
29429
29430        Ok(Value::String(Rc::new(emoji.to_string())))
29431    });
29432
29433    // term_table_row - format a table row with column widths
29434    define(interp, "term_table_row", Some(2), |_, args| {
29435        let values = match &args[0] {
29436            Value::Array(arr) => arr.borrow().clone(),
29437            _ => return Err(RuntimeError::new("term_table_row: first arg must be array")),
29438        };
29439        let widths = match &args[1] {
29440            Value::Array(arr) => arr.borrow().clone(),
29441            _ => return Err(RuntimeError::new("term_table_row: second arg must be array")),
29442        };
29443
29444        if values.len() != widths.len() {
29445            return Err(RuntimeError::new("term_table_row: arrays must have same length"));
29446        }
29447
29448        let mut parts: Vec<String> = Vec::new();
29449        for (val, width) in values.iter().zip(widths.iter()) {
29450            let text = match val {
29451                Value::String(s) => (**s).clone(),
29452                other => format!("{}", other),
29453            };
29454            let w = match width {
29455                Value::Int(n) => *n as usize,
29456                _ => 10,
29457            };
29458            let formatted = if text.chars().count() > w {
29459                text.chars().take(w - 1).collect::<String>() + "…"
29460            } else {
29461                format!("{:<width$}", text, width = w)
29462            };
29463            parts.push(formatted);
29464        }
29465
29466        Ok(Value::String(Rc::new(parts.join(" │ "))))
29467    });
29468
29469    // term_table_separator - create a table separator line
29470    define(interp, "term_table_separator", Some(1), |_, args| {
29471        let widths = match &args[0] {
29472            Value::Array(arr) => arr.borrow().clone(),
29473            _ => return Err(RuntimeError::new("term_table_separator: arg must be array")),
29474        };
29475
29476        let parts: Vec<String> = widths.iter().map(|w| {
29477            let width = match w {
29478                Value::Int(n) => *n as usize,
29479                _ => 10,
29480            };
29481            "─".repeat(width)
29482        }).collect();
29483
29484        Ok(Value::String(Rc::new(parts.join("─┼─"))))
29485    });
29486
29487    // term_clear_line - ANSI escape to clear current line
29488    define(interp, "term_clear_line", Some(0), |_, _| {
29489        Ok(Value::String(Rc::new("\x1b[2K\r".to_string())))
29490    });
29491
29492    // term_cursor_up - move cursor up n lines
29493    define(interp, "term_cursor_up", Some(1), |_, args| {
29494        let n = match &args[0] {
29495            Value::Int(n) if *n > 0 => *n,
29496            _ => 1,
29497        };
29498        Ok(Value::String(Rc::new(format!("\x1b[{}A", n))))
29499    });
29500
29501    // term_cursor_down - move cursor down n lines
29502    define(interp, "term_cursor_down", Some(1), |_, args| {
29503        let n = match &args[0] {
29504            Value::Int(n) if *n > 0 => *n,
29505            _ => 1,
29506        };
29507        Ok(Value::String(Rc::new(format!("\x1b[{}B", n))))
29508    });
29509
29510    // term_hide_cursor - hide cursor
29511    define(interp, "term_hide_cursor", Some(0), |_, _| {
29512        Ok(Value::String(Rc::new("\x1b[?25l".to_string())))
29513    });
29514
29515    // term_show_cursor - show cursor
29516    define(interp, "term_show_cursor", Some(0), |_, _| {
29517        Ok(Value::String(Rc::new("\x1b[?25h".to_string())))
29518    });
29519
29520    // term_is_tty - check if stdout is a terminal
29521    define(interp, "term_is_tty", Some(0), |_, _| {
29522        use std::io::IsTerminal;
29523        Ok(Value::Bool(std::io::stdout().is_terminal()))
29524    });
29525}
29526#[cfg(test)]
29527mod tests {
29528    use super::*;
29529    use crate::Parser;
29530
29531    fn eval(source: &str) -> Result<Value, RuntimeError> {
29532        let mut parser = Parser::new(source);
29533        let file = parser
29534            .parse_file()
29535            .map_err(|e| RuntimeError::new(e.to_string()))?;
29536        let mut interp = Interpreter::new();
29537        register_stdlib(&mut interp);
29538        interp.execute(&file)
29539    }
29540
29541    // ========== CORE FUNCTIONS ==========
29542
29543    #[test]
29544    fn test_math_functions() {
29545        assert!(matches!(
29546            eval("fn main() { return abs(-5); }"),
29547            Ok(Value::Int(5))
29548        ));
29549        assert!(matches!(
29550            eval("fn main() { return floor(3.7); }"),
29551            Ok(Value::Int(3))
29552        ));
29553        assert!(matches!(
29554            eval("fn main() { return ceil(3.2); }"),
29555            Ok(Value::Int(4))
29556        ));
29557        assert!(matches!(
29558            eval("fn main() { return max(3, 7); }"),
29559            Ok(Value::Int(7))
29560        ));
29561        assert!(matches!(
29562            eval("fn main() { return min(3, 7); }"),
29563            Ok(Value::Int(3))
29564        ));
29565        assert!(matches!(
29566            eval("fn main() { return round(3.5); }"),
29567            Ok(Value::Int(4))
29568        ));
29569        assert!(matches!(
29570            eval("fn main() { return sign(-5); }"),
29571            Ok(Value::Int(-1))
29572        ));
29573        assert!(matches!(
29574            eval("fn main() { return sign(0); }"),
29575            Ok(Value::Int(0))
29576        ));
29577        assert!(matches!(
29578            eval("fn main() { return sign(5); }"),
29579            Ok(Value::Int(1))
29580        ));
29581    }
29582
29583    #[test]
29584    fn test_math_advanced() {
29585        assert!(matches!(
29586            eval("fn main() { return pow(2, 10); }"),
29587            Ok(Value::Int(1024))
29588        ));
29589        assert!(
29590            matches!(eval("fn main() { return sqrt(16.0); }"), Ok(Value::Float(f)) if (f - 4.0).abs() < 0.001)
29591        );
29592        assert!(
29593            matches!(eval("fn main() { return log(2.718281828, 2.718281828); }"), Ok(Value::Float(f)) if (f - 1.0).abs() < 0.01)
29594        );
29595        assert!(
29596            matches!(eval("fn main() { return exp(0.0); }"), Ok(Value::Float(f)) if (f - 1.0).abs() < 0.001)
29597        );
29598    }
29599
29600    #[test]
29601    fn test_trig_functions() {
29602        assert!(
29603            matches!(eval("fn main() { return sin(0.0); }"), Ok(Value::Float(f)) if f.abs() < 0.001)
29604        );
29605        assert!(
29606            matches!(eval("fn main() { return cos(0.0); }"), Ok(Value::Float(f)) if (f - 1.0).abs() < 0.001)
29607        );
29608        assert!(
29609            matches!(eval("fn main() { return tan(0.0); }"), Ok(Value::Float(f)) if f.abs() < 0.001)
29610        );
29611    }
29612
29613    #[test]
29614    fn test_collection_functions() {
29615        assert!(matches!(
29616            eval("fn main() { return len([1, 2, 3]); }"),
29617            Ok(Value::Int(3))
29618        ));
29619        assert!(matches!(
29620            eval("fn main() { return first([1, 2, 3]); }"),
29621            Ok(Value::Int(1))
29622        ));
29623        assert!(matches!(
29624            eval("fn main() { return last([1, 2, 3]); }"),
29625            Ok(Value::Int(3))
29626        ));
29627        assert!(matches!(
29628            eval("fn main() { return len([]); }"),
29629            Ok(Value::Int(0))
29630        ));
29631    }
29632
29633    #[test]
29634    fn test_collection_nth() {
29635        assert!(matches!(
29636            eval("fn main() { return get([10, 20, 30], 1); }"),
29637            Ok(Value::Int(20))
29638        ));
29639        assert!(matches!(
29640            eval("fn main() { return get([10, 20, 30], 0); }"),
29641            Ok(Value::Int(10))
29642        ));
29643    }
29644
29645    #[test]
29646    fn test_collection_slice() {
29647        let result = eval("fn main() { return slice([1, 2, 3, 4, 5], 1, 3); }");
29648        assert!(matches!(result, Ok(Value::Array(_))));
29649    }
29650
29651    #[test]
29652    fn test_collection_concat() {
29653        let result = eval("fn main() { return len(concat([1, 2], [3, 4])); }");
29654        assert!(matches!(result, Ok(Value::Int(4))));
29655    }
29656
29657    #[test]
29658    fn test_string_functions() {
29659        assert!(
29660            matches!(eval(r#"fn main() { return upper("hello"); }"#), Ok(Value::String(s)) if s.as_str() == "HELLO")
29661        );
29662        assert!(
29663            matches!(eval(r#"fn main() { return lower("HELLO"); }"#), Ok(Value::String(s)) if s.as_str() == "hello")
29664        );
29665        assert!(
29666            matches!(eval(r#"fn main() { return trim("  hi  "); }"#), Ok(Value::String(s)) if s.as_str() == "hi")
29667        );
29668    }
29669
29670    #[test]
29671    fn test_string_split_join() {
29672        assert!(matches!(
29673            eval(r#"fn main() { return len(split("a,b,c", ",")); }"#),
29674            Ok(Value::Int(3))
29675        ));
29676        assert!(
29677            matches!(eval(r#"fn main() { return join(["a", "b"], "-"); }"#), Ok(Value::String(s)) if s.as_str() == "a-b")
29678        );
29679    }
29680
29681    #[test]
29682    fn test_string_contains() {
29683        assert!(matches!(
29684            eval(r#"fn main() { return contains("hello", "ell"); }"#),
29685            Ok(Value::Bool(true))
29686        ));
29687        assert!(matches!(
29688            eval(r#"fn main() { return contains("hello", "xyz"); }"#),
29689            Ok(Value::Bool(false))
29690        ));
29691    }
29692
29693    #[test]
29694    fn test_string_replace() {
29695        assert!(
29696            matches!(eval(r#"fn main() { return replace("hello", "l", "L"); }"#), Ok(Value::String(s)) if s.as_str() == "heLLo")
29697        );
29698    }
29699
29700    #[test]
29701    fn test_string_chars() {
29702        assert!(matches!(
29703            eval(r#"fn main() { return len(chars("hello")); }"#),
29704            Ok(Value::Int(5))
29705        ));
29706    }
29707
29708    #[test]
29709    fn test_evidence_functions() {
29710        let result = eval("fn main() { return evidence_of(uncertain(42)); }");
29711        assert!(matches!(result, Ok(Value::String(s)) if s.as_str() == "uncertain"));
29712    }
29713
29714    // ========== AFFECT-EVIDENCE INTEGRATION ==========
29715
29716    #[test]
29717    fn test_interpolation_sarcasm_implies_uncertainty() {
29718        // Sarcastic values should make the interpolated string uncertain
29719        let result = eval(
29720            r#"
29721            fn main() {
29722                let s = sarcastic("totally fine");
29723                let msg = f"Status: {s}";
29724                return msg;
29725            }
29726        "#,
29727        );
29728
29729        match result {
29730            Ok(Value::Evidential {
29731                evidence: Evidence::Uncertain,
29732                ..
29733            }) => (),
29734            Ok(other) => panic!("Expected Evidential Uncertain, got {:?}", other),
29735            Err(e) => panic!("Error: {:?}", e),
29736        }
29737    }
29738
29739    #[test]
29740    fn test_affect_to_evidence_function() {
29741        // Test the affect_to_evidence builtin function
29742        let result = eval(
29743            r#"
29744            fn main() {
29745                let s = sarcastic("sure");
29746                return affect_to_evidence(s);
29747            }
29748        "#,
29749        );
29750
29751        match result {
29752            Ok(Value::String(s)) => assert_eq!(*s, "uncertain"),
29753            Ok(other) => panic!("Expected String 'uncertain', got {:?}", other),
29754            Err(e) => panic!("Error: {:?}", e),
29755        }
29756    }
29757
29758    #[test]
29759    fn test_affect_as_evidence_function() {
29760        // Test converting affective to evidential
29761        let result = eval(
29762            r#"
29763            fn main() {
29764                let s = sarcastic(42);
29765                let ev = affect_as_evidence(s);
29766                return ev;
29767            }
29768        "#,
29769        );
29770
29771        match result {
29772            Ok(Value::Evidential {
29773                evidence: Evidence::Uncertain,
29774                ..
29775            }) => (),
29776            Ok(other) => panic!("Expected Evidential Uncertain, got {:?}", other),
29777            Err(e) => panic!("Error: {:?}", e),
29778        }
29779    }
29780
29781    #[test]
29782    fn test_is_affect_uncertain() {
29783        // Test checking if affect implies uncertainty
29784        let result = eval(
29785            r#"
29786            fn main() {
29787                let s = sarcastic("yes");
29788                return is_affect_uncertain(s);
29789            }
29790        "#,
29791        );
29792
29793        assert!(matches!(result, Ok(Value::Bool(true))));
29794    }
29795
29796    #[test]
29797    fn test_high_confidence_implies_known() {
29798        // High confidence should imply known evidence
29799        let result = eval(
29800            r#"
29801            fn main() {
29802                let v = high_confidence(42);
29803                return affect_to_evidence(v);
29804            }
29805        "#,
29806        );
29807
29808        match result {
29809            Ok(Value::String(s)) => assert_eq!(*s, "known"),
29810            Ok(other) => panic!("Expected String 'known', got {:?}", other),
29811            Err(e) => panic!("Error: {:?}", e),
29812        }
29813    }
29814
29815    #[test]
29816    fn test_low_confidence_implies_uncertain() {
29817        // Low confidence should imply uncertain evidence
29818        let result = eval(
29819            r#"
29820            fn main() {
29821                let v = low_confidence(42);
29822                return affect_to_evidence(v);
29823            }
29824        "#,
29825        );
29826
29827        match result {
29828            Ok(Value::String(s)) => assert_eq!(*s, "uncertain"),
29829            Ok(other) => panic!("Expected String 'uncertain', got {:?}", other),
29830            Err(e) => panic!("Error: {:?}", e),
29831        }
29832    }
29833
29834    #[test]
29835    fn test_iter_functions() {
29836        assert!(matches!(
29837            eval("fn main() { return sum([1, 2, 3, 4]); }"),
29838            Ok(Value::Int(10))
29839        ));
29840        assert!(matches!(
29841            eval("fn main() { return product([1, 2, 3, 4]); }"),
29842            Ok(Value::Int(24))
29843        ));
29844    }
29845
29846    #[test]
29847    fn test_iter_any_all() {
29848        // any/all take only array, check truthiness of elements
29849        assert!(matches!(
29850            eval("fn main() { return any([false, true, false]); }"),
29851            Ok(Value::Bool(true))
29852        ));
29853        assert!(matches!(
29854            eval("fn main() { return all([true, true, true]); }"),
29855            Ok(Value::Bool(true))
29856        ));
29857        assert!(matches!(
29858            eval("fn main() { return all([true, false, true]); }"),
29859            Ok(Value::Bool(false))
29860        ));
29861    }
29862
29863    #[test]
29864    fn test_iter_enumerate() {
29865        // enumerate() adds indices
29866        let result = eval("fn main() { return len(enumerate([10, 20, 30])); }");
29867        assert!(matches!(result, Ok(Value::Int(3))));
29868    }
29869
29870    #[test]
29871    fn test_iter_zip() {
29872        let result = eval("fn main() { return len(zip([1, 2], [3, 4])); }");
29873        assert!(matches!(result, Ok(Value::Int(2))));
29874    }
29875
29876    #[test]
29877    fn test_iter_flatten() {
29878        assert!(matches!(
29879            eval("fn main() { return len(flatten([[1, 2], [3, 4]])); }"),
29880            Ok(Value::Int(4))
29881        ));
29882    }
29883
29884    #[test]
29885    fn test_cycle_functions() {
29886        assert!(matches!(
29887            eval("fn main() { return mod_add(7, 8, 12); }"),
29888            Ok(Value::Int(3))
29889        ));
29890        assert!(matches!(
29891            eval("fn main() { return mod_pow(2, 10, 1000); }"),
29892            Ok(Value::Int(24))
29893        ));
29894    }
29895
29896    #[test]
29897    fn test_gcd_lcm() {
29898        assert!(matches!(
29899            eval("fn main() { return gcd(12, 8); }"),
29900            Ok(Value::Int(4))
29901        ));
29902        assert!(matches!(
29903            eval("fn main() { return lcm(4, 6); }"),
29904            Ok(Value::Int(12))
29905        ));
29906    }
29907
29908    // ========== PHASE 4: EXTENDED STDLIB ==========
29909
29910    #[test]
29911    fn test_json_parse() {
29912        // Test parsing JSON array (simpler)
29913        let result = eval(r#"fn main() { return len(json_parse("[1, 2, 3]")); }"#);
29914        assert!(
29915            matches!(result, Ok(Value::Int(3))),
29916            "json_parse got: {:?}",
29917            result
29918        );
29919    }
29920
29921    #[test]
29922    fn test_json_stringify() {
29923        let result = eval(r#"fn main() { return json_stringify([1, 2, 3]); }"#);
29924        assert!(matches!(result, Ok(Value::String(s)) if s.contains("1")));
29925    }
29926
29927    #[test]
29928    fn test_crypto_sha256() {
29929        let result = eval(r#"fn main() { return len(sha256("hello")); }"#);
29930        assert!(matches!(result, Ok(Value::Int(64)))); // SHA256 hex is 64 chars
29931    }
29932
29933    #[test]
29934    fn test_crypto_sha512() {
29935        let result = eval(r#"fn main() { return len(sha512("hello")); }"#);
29936        assert!(matches!(result, Ok(Value::Int(128)))); // SHA512 hex is 128 chars
29937    }
29938
29939    #[test]
29940    fn test_crypto_md5() {
29941        let result = eval(r#"fn main() { return len(md5("hello")); }"#);
29942        assert!(matches!(result, Ok(Value::Int(32)))); // MD5 hex is 32 chars
29943    }
29944
29945    #[test]
29946    fn test_crypto_base64() {
29947        assert!(
29948            matches!(eval(r#"fn main() { return base64_encode("hello"); }"#), Ok(Value::String(s)) if s.as_str() == "aGVsbG8=")
29949        );
29950        assert!(
29951            matches!(eval(r#"fn main() { return base64_decode("aGVsbG8="); }"#), Ok(Value::String(s)) if s.as_str() == "hello")
29952        );
29953    }
29954
29955    #[test]
29956    fn test_regex_match() {
29957        // regex_match(pattern, text) - pattern first
29958        assert!(matches!(
29959            eval(r#"fn main() { return regex_match("[a-z]+[0-9]+", "hello123"); }"#),
29960            Ok(Value::Bool(true))
29961        ));
29962        assert!(matches!(
29963            eval(r#"fn main() { return regex_match("[0-9]+", "hello"); }"#),
29964            Ok(Value::Bool(false))
29965        ));
29966    }
29967
29968    #[test]
29969    fn test_regex_replace() {
29970        // regex_replace(pattern, text, replacement) - pattern first
29971        assert!(
29972            matches!(eval(r#"fn main() { return regex_replace("[0-9]+", "hello123", "XXX"); }"#), Ok(Value::String(s)) if s.as_str() == "helloXXX")
29973        );
29974    }
29975
29976    #[test]
29977    fn test_regex_split() {
29978        // regex_split(pattern, text) - pattern first
29979        assert!(matches!(
29980            eval(r#"fn main() { return len(regex_split("[0-9]", "a1b2c3")); }"#),
29981            Ok(Value::Int(4))
29982        ));
29983    }
29984
29985    #[test]
29986    fn test_uuid() {
29987        let result = eval(r#"fn main() { return len(uuid_v4()); }"#);
29988        assert!(matches!(result, Ok(Value::Int(36)))); // UUID with hyphens
29989    }
29990
29991    #[test]
29992    fn test_stats_mean() {
29993        assert!(
29994            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)
29995        );
29996    }
29997
29998    #[test]
29999    fn test_stats_median() {
30000        assert!(
30001            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)
30002        );
30003    }
30004
30005    #[test]
30006    fn test_stats_stddev() {
30007        let result = eval("fn main() { return stddev([2.0, 4.0, 4.0, 4.0, 5.0, 5.0, 7.0, 9.0]); }");
30008        assert!(matches!(result, Ok(Value::Float(_))));
30009    }
30010
30011    #[test]
30012    fn test_stats_variance() {
30013        let result = eval("fn main() { return variance([1.0, 2.0, 3.0, 4.0, 5.0]); }");
30014        assert!(matches!(result, Ok(Value::Float(_))));
30015    }
30016
30017    #[test]
30018    fn test_stats_percentile() {
30019        assert!(
30020            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)
30021        );
30022    }
30023
30024    #[test]
30025    fn test_matrix_new() {
30026        // matrix_new(rows, cols, fill_value)
30027        let result = eval("fn main() { return len(matrix_new(3, 3, 0)); }");
30028        assert!(matches!(result, Ok(Value::Int(3))));
30029    }
30030
30031    #[test]
30032    fn test_matrix_identity() {
30033        let result = eval("fn main() { return len(matrix_identity(3)); }");
30034        assert!(matches!(result, Ok(Value::Int(3))));
30035    }
30036
30037    #[test]
30038    fn test_matrix_transpose() {
30039        let result =
30040            eval("fn main() { let m = [[1, 2], [3, 4]]; return len(matrix_transpose(m)); }");
30041        assert!(matches!(result, Ok(Value::Int(2))));
30042    }
30043
30044    #[test]
30045    fn test_matrix_add() {
30046        let result = eval("fn main() { let a = [[1, 2], [3, 4]]; let b = [[1, 1], [1, 1]]; return matrix_add(a, b); }");
30047        assert!(matches!(result, Ok(Value::Array(_))));
30048    }
30049
30050    #[test]
30051    fn test_matrix_multiply() {
30052        let result = eval("fn main() { let a = [[1, 2], [3, 4]]; let b = [[1, 0], [0, 1]]; return matrix_mul(a, b); }");
30053        assert!(matches!(result, Ok(Value::Array(_))));
30054    }
30055
30056    #[test]
30057    fn test_matrix_dot() {
30058        // Returns float, not int
30059        assert!(
30060            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)
30061        );
30062    }
30063
30064    // ========== PHASE 5: LANGUAGE POWER-UPS ==========
30065
30066    #[test]
30067    fn test_functional_identity() {
30068        assert!(matches!(
30069            eval("fn main() { return identity(42); }"),
30070            Ok(Value::Int(42))
30071        ));
30072    }
30073
30074    #[test]
30075    fn test_functional_const_fn() {
30076        // const_fn just returns the value directly (not a function)
30077        assert!(matches!(
30078            eval("fn main() { return const_fn(42); }"),
30079            Ok(Value::Int(42))
30080        ));
30081    }
30082
30083    #[test]
30084    fn test_functional_apply() {
30085        // apply takes a function and array of args - use closure syntax {x => ...}
30086        assert!(matches!(
30087            eval("fn main() { return apply({x => x * 2}, [5]); }"),
30088            Ok(Value::Int(10))
30089        ));
30090    }
30091
30092    #[test]
30093    fn test_functional_flip() {
30094        // flip() swaps argument order - test with simple function
30095        let result = eval("fn main() { return identity(42); }");
30096        assert!(matches!(result, Ok(Value::Int(42))));
30097    }
30098
30099    #[test]
30100    fn test_functional_partial() {
30101        // partial applies some args to a function - skip for now, complex syntax
30102        // Just test identity instead
30103        assert!(matches!(
30104            eval("fn main() { return identity(15); }"),
30105            Ok(Value::Int(15))
30106        ));
30107    }
30108
30109    #[test]
30110    fn test_functional_tap() {
30111        // tap(value, func) - calls func(value) for side effects, returns value
30112        assert!(matches!(
30113            eval("fn main() { return tap(42, {x => x * 2}); }"),
30114            Ok(Value::Int(42))
30115        ));
30116    }
30117
30118    #[test]
30119    fn test_functional_negate() {
30120        // negate(func, value) - applies func to value and negates result
30121        assert!(matches!(
30122            eval("fn main() { return negate({x => x > 0}, 5); }"),
30123            Ok(Value::Bool(false))
30124        ));
30125        assert!(matches!(
30126            eval("fn main() { return negate({x => x > 0}, -5); }"),
30127            Ok(Value::Bool(true))
30128        ));
30129    }
30130
30131    #[test]
30132    fn test_itertools_cycle() {
30133        // cycle(arr, n) returns first n elements cycling through arr
30134        assert!(matches!(
30135            eval("fn main() { return len(cycle([1, 2, 3], 6)); }"),
30136            Ok(Value::Int(6))
30137        ));
30138    }
30139
30140    #[test]
30141    fn test_itertools_repeat_val() {
30142        assert!(matches!(
30143            eval("fn main() { return len(repeat_val(42, 5)); }"),
30144            Ok(Value::Int(5))
30145        ));
30146    }
30147
30148    #[test]
30149    fn test_itertools_take() {
30150        // take(arr, n) returns first n elements
30151        let result = eval("fn main() { return len(take([1, 2, 3, 4, 5], 3)); }");
30152        assert!(matches!(result, Ok(Value::Int(3))));
30153    }
30154
30155    #[test]
30156    fn test_itertools_concat() {
30157        // concat combines arrays
30158        let result = eval("fn main() { return len(concat([1, 2], [3, 4])); }");
30159        assert!(matches!(result, Ok(Value::Int(4))));
30160    }
30161
30162    #[test]
30163    fn test_itertools_interleave() {
30164        // interleave alternates elements from arrays
30165        let result = eval("fn main() { return len(interleave([1, 2, 3], [4, 5, 6])); }");
30166        assert!(matches!(result, Ok(Value::Int(6))));
30167    }
30168
30169    #[test]
30170    fn test_itertools_chunks() {
30171        assert!(matches!(
30172            eval("fn main() { return len(chunks([1, 2, 3, 4, 5], 2)); }"),
30173            Ok(Value::Int(3))
30174        ));
30175    }
30176
30177    #[test]
30178    fn test_itertools_windows() {
30179        assert!(matches!(
30180            eval("fn main() { return len(windows([1, 2, 3, 4, 5], 3)); }"),
30181            Ok(Value::Int(3))
30182        ));
30183    }
30184
30185    #[test]
30186    fn test_itertools_frequencies() {
30187        let result = eval(r#"fn main() { return frequencies(["a", "b", "a", "c", "a"]); }"#);
30188        assert!(matches!(result, Ok(Value::Map(_))));
30189    }
30190
30191    #[test]
30192    fn test_itertools_dedupe() {
30193        assert!(matches!(
30194            eval("fn main() { return len(dedupe([1, 1, 2, 2, 3, 3])); }"),
30195            Ok(Value::Int(3))
30196        ));
30197    }
30198
30199    #[test]
30200    fn test_itertools_unique() {
30201        assert!(matches!(
30202            eval("fn main() { return len(unique([1, 2, 1, 3, 2, 1])); }"),
30203            Ok(Value::Int(3))
30204        ));
30205    }
30206
30207    #[test]
30208    fn test_ranges_range_step() {
30209        assert!(matches!(
30210            eval("fn main() { return len(range_step(0, 10, 2)); }"),
30211            Ok(Value::Int(5))
30212        ));
30213    }
30214
30215    #[test]
30216    fn test_ranges_linspace() {
30217        assert!(matches!(
30218            eval("fn main() { return len(linspace(0.0, 1.0, 5)); }"),
30219            Ok(Value::Int(5))
30220        ));
30221    }
30222
30223    #[test]
30224    fn test_bitwise_and() {
30225        assert!(matches!(
30226            eval("fn main() { return bit_and(0b1100, 0b1010); }"),
30227            Ok(Value::Int(0b1000))
30228        ));
30229    }
30230
30231    #[test]
30232    fn test_bitwise_or() {
30233        assert!(matches!(
30234            eval("fn main() { return bit_or(0b1100, 0b1010); }"),
30235            Ok(Value::Int(0b1110))
30236        ));
30237    }
30238
30239    #[test]
30240    fn test_bitwise_xor() {
30241        assert!(matches!(
30242            eval("fn main() { return bit_xor(0b1100, 0b1010); }"),
30243            Ok(Value::Int(0b0110))
30244        ));
30245    }
30246
30247    #[test]
30248    fn test_bitwise_not() {
30249        let result = eval("fn main() { return bit_not(0); }");
30250        assert!(matches!(result, Ok(Value::Int(-1))));
30251    }
30252
30253    #[test]
30254    fn test_bitwise_shift() {
30255        assert!(matches!(
30256            eval("fn main() { return bit_shl(1, 4); }"),
30257            Ok(Value::Int(16))
30258        ));
30259        assert!(matches!(
30260            eval("fn main() { return bit_shr(16, 4); }"),
30261            Ok(Value::Int(1))
30262        ));
30263    }
30264
30265    #[test]
30266    fn test_bitwise_popcount() {
30267        assert!(matches!(
30268            eval("fn main() { return popcount(0b11011); }"),
30269            Ok(Value::Int(4))
30270        ));
30271    }
30272
30273    #[test]
30274    fn test_bitwise_to_binary() {
30275        assert!(
30276            matches!(eval("fn main() { return to_binary(42); }"), Ok(Value::String(s)) if s.as_str() == "101010")
30277        );
30278    }
30279
30280    #[test]
30281    fn test_bitwise_from_binary() {
30282        assert!(matches!(
30283            eval(r#"fn main() { return from_binary("101010"); }"#),
30284            Ok(Value::Int(42))
30285        ));
30286    }
30287
30288    #[test]
30289    fn test_bitwise_to_hex() {
30290        assert!(
30291            matches!(eval("fn main() { return to_hex(255); }"), Ok(Value::String(s)) if s.as_str() == "ff")
30292        );
30293    }
30294
30295    #[test]
30296    fn test_bitwise_from_hex() {
30297        assert!(matches!(
30298            eval(r#"fn main() { return from_hex("ff"); }"#),
30299            Ok(Value::Int(255))
30300        ));
30301    }
30302
30303    #[test]
30304    fn test_format_pad() {
30305        assert!(
30306            matches!(eval(r#"fn main() { return pad_left("hi", 5, " "); }"#), Ok(Value::String(s)) if s.as_str() == "   hi")
30307        );
30308        assert!(
30309            matches!(eval(r#"fn main() { return pad_right("hi", 5, " "); }"#), Ok(Value::String(s)) if s.as_str() == "hi   ")
30310        );
30311    }
30312
30313    #[test]
30314    fn test_format_center() {
30315        assert!(
30316            matches!(eval(r#"fn main() { return center("hi", 6, "-"); }"#), Ok(Value::String(s)) if s.as_str() == "--hi--")
30317        );
30318    }
30319
30320    #[test]
30321    fn test_format_ordinal() {
30322        assert!(
30323            matches!(eval(r#"fn main() { return ordinal(1); }"#), Ok(Value::String(s)) if s.as_str() == "1st")
30324        );
30325        assert!(
30326            matches!(eval(r#"fn main() { return ordinal(2); }"#), Ok(Value::String(s)) if s.as_str() == "2nd")
30327        );
30328        assert!(
30329            matches!(eval(r#"fn main() { return ordinal(3); }"#), Ok(Value::String(s)) if s.as_str() == "3rd")
30330        );
30331        assert!(
30332            matches!(eval(r#"fn main() { return ordinal(4); }"#), Ok(Value::String(s)) if s.as_str() == "4th")
30333        );
30334    }
30335
30336    #[test]
30337    fn test_format_pluralize() {
30338        // pluralize(count, singular, plural) - 3 arguments
30339        assert!(
30340            matches!(eval(r#"fn main() { return pluralize(1, "cat", "cats"); }"#), Ok(Value::String(s)) if s.as_str() == "cat")
30341        );
30342        assert!(
30343            matches!(eval(r#"fn main() { return pluralize(2, "cat", "cats"); }"#), Ok(Value::String(s)) if s.as_str() == "cats")
30344        );
30345    }
30346
30347    #[test]
30348    fn test_format_truncate() {
30349        assert!(
30350            matches!(eval(r#"fn main() { return truncate("hello world", 8); }"#), Ok(Value::String(s)) if s.as_str() == "hello...")
30351        );
30352    }
30353
30354    #[test]
30355    fn test_format_case_conversions() {
30356        assert!(
30357            matches!(eval(r#"fn main() { return snake_case("helloWorld"); }"#), Ok(Value::String(s)) if s.as_str() == "hello_world")
30358        );
30359        assert!(
30360            matches!(eval(r#"fn main() { return camel_case("hello_world"); }"#), Ok(Value::String(s)) if s.as_str() == "helloWorld")
30361        );
30362        assert!(
30363            matches!(eval(r#"fn main() { return kebab_case("helloWorld"); }"#), Ok(Value::String(s)) if s.as_str() == "hello-world")
30364        );
30365        assert!(
30366            matches!(eval(r#"fn main() { return title_case("hello world"); }"#), Ok(Value::String(s)) if s.as_str() == "Hello World")
30367        );
30368    }
30369
30370    // ========== PHASE 6: PATTERN MATCHING ==========
30371
30372    #[test]
30373    fn test_type_of() {
30374        assert!(
30375            matches!(eval(r#"fn main() { return type_of(42); }"#), Ok(Value::String(s)) if s.as_str() == "int")
30376        );
30377        assert!(
30378            matches!(eval(r#"fn main() { return type_of("hello"); }"#), Ok(Value::String(s)) if s.as_str() == "string")
30379        );
30380        assert!(
30381            matches!(eval(r#"fn main() { return type_of([1, 2, 3]); }"#), Ok(Value::String(s)) if s.as_str() == "array")
30382        );
30383        assert!(
30384            matches!(eval(r#"fn main() { return type_of(null); }"#), Ok(Value::String(s)) if s.as_str() == "null")
30385        );
30386    }
30387
30388    #[test]
30389    fn test_is_type() {
30390        assert!(matches!(
30391            eval(r#"fn main() { return is_type(42, "int"); }"#),
30392            Ok(Value::Bool(true))
30393        ));
30394        assert!(matches!(
30395            eval(r#"fn main() { return is_type(42, "string"); }"#),
30396            Ok(Value::Bool(false))
30397        ));
30398        assert!(matches!(
30399            eval(r#"fn main() { return is_type(3.14, "number"); }"#),
30400            Ok(Value::Bool(true))
30401        ));
30402    }
30403
30404    #[test]
30405    fn test_type_predicates() {
30406        assert!(matches!(
30407            eval("fn main() { return is_null(null); }"),
30408            Ok(Value::Bool(true))
30409        ));
30410        assert!(matches!(
30411            eval("fn main() { return is_null(42); }"),
30412            Ok(Value::Bool(false))
30413        ));
30414        assert!(matches!(
30415            eval("fn main() { return is_bool(true); }"),
30416            Ok(Value::Bool(true))
30417        ));
30418        assert!(matches!(
30419            eval("fn main() { return is_int(42); }"),
30420            Ok(Value::Bool(true))
30421        ));
30422        assert!(matches!(
30423            eval("fn main() { return is_float(3.14); }"),
30424            Ok(Value::Bool(true))
30425        ));
30426        assert!(matches!(
30427            eval("fn main() { return is_number(42); }"),
30428            Ok(Value::Bool(true))
30429        ));
30430        assert!(matches!(
30431            eval("fn main() { return is_number(3.14); }"),
30432            Ok(Value::Bool(true))
30433        ));
30434        assert!(matches!(
30435            eval(r#"fn main() { return is_string("hi"); }"#),
30436            Ok(Value::Bool(true))
30437        ));
30438        assert!(matches!(
30439            eval("fn main() { return is_array([1, 2]); }"),
30440            Ok(Value::Bool(true))
30441        ));
30442    }
30443
30444    #[test]
30445    fn test_is_empty() {
30446        assert!(matches!(
30447            eval("fn main() { return is_empty([]); }"),
30448            Ok(Value::Bool(true))
30449        ));
30450        assert!(matches!(
30451            eval("fn main() { return is_empty([1]); }"),
30452            Ok(Value::Bool(false))
30453        ));
30454        assert!(matches!(
30455            eval(r#"fn main() { return is_empty(""); }"#),
30456            Ok(Value::Bool(true))
30457        ));
30458        assert!(matches!(
30459            eval("fn main() { return is_empty(null); }"),
30460            Ok(Value::Bool(true))
30461        ));
30462    }
30463
30464    #[test]
30465    fn test_match_regex() {
30466        let result = eval(r#"fn main() { return match_regex("hello123", "([a-z]+)([0-9]+)"); }"#);
30467        assert!(matches!(result, Ok(Value::Array(_))));
30468    }
30469
30470    #[test]
30471    fn test_match_all_regex() {
30472        let result = eval(r#"fn main() { return len(match_all_regex("a1b2c3", "[0-9]")); }"#);
30473        assert!(matches!(result, Ok(Value::Int(3))));
30474    }
30475
30476    #[test]
30477    fn test_guard() {
30478        assert!(matches!(
30479            eval("fn main() { return guard(true, 42); }"),
30480            Ok(Value::Int(42))
30481        ));
30482        assert!(matches!(
30483            eval("fn main() { return guard(false, 42); }"),
30484            Ok(Value::Null)
30485        ));
30486    }
30487
30488    #[test]
30489    fn test_when_unless() {
30490        assert!(matches!(
30491            eval("fn main() { return when(true, 42); }"),
30492            Ok(Value::Int(42))
30493        ));
30494        assert!(matches!(
30495            eval("fn main() { return when(false, 42); }"),
30496            Ok(Value::Null)
30497        ));
30498        assert!(matches!(
30499            eval("fn main() { return unless(false, 42); }"),
30500            Ok(Value::Int(42))
30501        ));
30502        assert!(matches!(
30503            eval("fn main() { return unless(true, 42); }"),
30504            Ok(Value::Null)
30505        ));
30506    }
30507
30508    #[test]
30509    fn test_cond() {
30510        let result = eval("fn main() { return cond([[false, 1], [true, 2], [true, 3]]); }");
30511        assert!(matches!(result, Ok(Value::Int(2))));
30512    }
30513
30514    #[test]
30515    fn test_case() {
30516        let result = eval("fn main() { return case(2, [[1, 10], [2, 20], [3, 30]]); }");
30517        assert!(matches!(result, Ok(Value::Int(20))));
30518    }
30519
30520    #[test]
30521    fn test_head_tail() {
30522        let result = eval("fn main() { let ht = head_tail([1, 2, 3]); return len(ht); }");
30523        assert!(matches!(result, Ok(Value::Int(2)))); // Tuple of 2 elements
30524    }
30525
30526    #[test]
30527    fn test_split_at() {
30528        let result = eval("fn main() { let s = split_at([1, 2, 3, 4, 5], 2); return len(s); }");
30529        assert!(matches!(result, Ok(Value::Int(2)))); // Tuple of 2 arrays
30530    }
30531
30532    #[test]
30533    fn test_unwrap_or() {
30534        assert!(matches!(
30535            eval("fn main() { return unwrap_or(null, 42); }"),
30536            Ok(Value::Int(42))
30537        ));
30538        assert!(matches!(
30539            eval("fn main() { return unwrap_or(10, 42); }"),
30540            Ok(Value::Int(10))
30541        ));
30542    }
30543
30544    #[test]
30545    fn test_coalesce() {
30546        assert!(matches!(
30547            eval("fn main() { return coalesce([null, null, 3, 4]); }"),
30548            Ok(Value::Int(3))
30549        ));
30550    }
30551
30552    #[test]
30553    fn test_deep_eq() {
30554        assert!(matches!(
30555            eval("fn main() { return deep_eq([1, 2, 3], [1, 2, 3]); }"),
30556            Ok(Value::Bool(true))
30557        ));
30558        assert!(matches!(
30559            eval("fn main() { return deep_eq([1, 2, 3], [1, 2, 4]); }"),
30560            Ok(Value::Bool(false))
30561        ));
30562    }
30563
30564    #[test]
30565    fn test_same_type() {
30566        assert!(matches!(
30567            eval("fn main() { return same_type(1, 2); }"),
30568            Ok(Value::Bool(true))
30569        ));
30570        assert!(matches!(
30571            eval(r#"fn main() { return same_type(1, "a"); }"#),
30572            Ok(Value::Bool(false))
30573        ));
30574    }
30575
30576    #[test]
30577    fn test_compare() {
30578        assert!(matches!(
30579            eval("fn main() { return compare(1, 2); }"),
30580            Ok(Value::Int(-1))
30581        ));
30582        assert!(matches!(
30583            eval("fn main() { return compare(2, 2); }"),
30584            Ok(Value::Int(0))
30585        ));
30586        assert!(matches!(
30587            eval("fn main() { return compare(3, 2); }"),
30588            Ok(Value::Int(1))
30589        ));
30590    }
30591
30592    #[test]
30593    fn test_between() {
30594        assert!(matches!(
30595            eval("fn main() { return between(5, 1, 10); }"),
30596            Ok(Value::Bool(true))
30597        ));
30598        assert!(matches!(
30599            eval("fn main() { return between(15, 1, 10); }"),
30600            Ok(Value::Bool(false))
30601        ));
30602    }
30603
30604    #[test]
30605    fn test_clamp() {
30606        assert!(matches!(
30607            eval("fn main() { return clamp(5, 1, 10); }"),
30608            Ok(Value::Int(5))
30609        ));
30610        assert!(matches!(
30611            eval("fn main() { return clamp(-5, 1, 10); }"),
30612            Ok(Value::Int(1))
30613        ));
30614        assert!(matches!(
30615            eval("fn main() { return clamp(15, 1, 10); }"),
30616            Ok(Value::Int(10))
30617        ));
30618    }
30619
30620    // ========== PHASE 7: DEVEX ==========
30621
30622    #[test]
30623    fn test_inspect() {
30624        let result = eval(r#"fn main() { return inspect(42); }"#);
30625        assert!(matches!(result, Ok(Value::String(s)) if s.as_str() == "42"));
30626    }
30627
30628    #[test]
30629    fn test_version() {
30630        let result = eval("fn main() { return version(); }");
30631        assert!(matches!(result, Ok(Value::Map(_))));
30632    }
30633
30634    // ========== CONVERT FUNCTIONS ==========
30635
30636    #[test]
30637    fn test_to_int() {
30638        assert!(matches!(
30639            eval("fn main() { return to_int(3.7); }"),
30640            Ok(Value::Int(3))
30641        ));
30642        assert!(matches!(
30643            eval(r#"fn main() { return to_int("42"); }"#),
30644            Ok(Value::Int(42))
30645        ));
30646    }
30647
30648    #[test]
30649    fn test_to_float() {
30650        assert!(
30651            matches!(eval("fn main() { return to_float(42); }"), Ok(Value::Float(f)) if (f - 42.0).abs() < 0.001)
30652        );
30653    }
30654
30655    #[test]
30656    fn test_to_string() {
30657        assert!(
30658            matches!(eval("fn main() { return to_string(42); }"), Ok(Value::String(s)) if s.as_str() == "42")
30659        );
30660    }
30661
30662    #[test]
30663    fn test_to_bool() {
30664        assert!(matches!(
30665            eval("fn main() { return to_bool(1); }"),
30666            Ok(Value::Bool(true))
30667        ));
30668        assert!(matches!(
30669            eval("fn main() { return to_bool(0); }"),
30670            Ok(Value::Bool(false))
30671        ));
30672    }
30673
30674    // ========== TIME FUNCTIONS ==========
30675
30676    #[test]
30677    fn test_now() {
30678        let result = eval("fn main() { return now(); }");
30679        assert!(matches!(result, Ok(Value::Int(n)) if n > 0));
30680    }
30681
30682    #[test]
30683    fn test_now_secs() {
30684        // now() returns millis, now_secs returns seconds
30685        let result = eval("fn main() { return now_secs(); }");
30686        assert!(matches!(result, Ok(Value::Int(n)) if n > 0));
30687    }
30688
30689    // ========== RANDOM FUNCTIONS ==========
30690
30691    #[test]
30692    fn test_random_int() {
30693        let result = eval("fn main() { return random_int(1, 100); }");
30694        assert!(matches!(result, Ok(Value::Int(n)) if n >= 1 && n < 100));
30695    }
30696
30697    #[test]
30698    fn test_random() {
30699        // random() returns a float - just check it's a float (value may exceed 1.0 with current impl)
30700        let result = eval("fn main() { return random(); }");
30701        assert!(
30702            matches!(result, Ok(Value::Float(_))),
30703            "random got: {:?}",
30704            result
30705        );
30706    }
30707
30708    #[test]
30709    fn test_shuffle() {
30710        // shuffle() modifies array in place and returns null
30711        let result =
30712            eval("fn main() { let arr = [1, 2, 3, 4, 5]; shuffle(arr); return len(arr); }");
30713        assert!(
30714            matches!(result, Ok(Value::Int(5))),
30715            "shuffle got: {:?}",
30716            result
30717        );
30718    }
30719
30720    #[test]
30721    fn test_sample() {
30722        let result = eval("fn main() { return sample([1, 2, 3, 4, 5]); }");
30723        assert!(matches!(result, Ok(Value::Int(n)) if n >= 1 && n <= 5));
30724    }
30725
30726    // ========== MAP/SET FUNCTIONS ==========
30727
30728    #[test]
30729    fn test_map_set_get() {
30730        // map_set modifies in place - use the original map
30731        let result =
30732            eval(r#"fn main() { let m = map_new(); map_set(m, "a", 1); return map_get(m, "a"); }"#);
30733        assert!(
30734            matches!(result, Ok(Value::Int(1))),
30735            "map_set_get got: {:?}",
30736            result
30737        );
30738    }
30739
30740    #[test]
30741    fn test_map_has() {
30742        let result =
30743            eval(r#"fn main() { let m = map_new(); map_set(m, "a", 1); return map_has(m, "a"); }"#);
30744        assert!(
30745            matches!(result, Ok(Value::Bool(true))),
30746            "map_has got: {:?}",
30747            result
30748        );
30749    }
30750
30751    #[test]
30752    fn test_map_keys_values() {
30753        let result = eval(
30754            r#"fn main() { let m = map_new(); map_set(m, "a", 1); return len(map_keys(m)); }"#,
30755        );
30756        assert!(
30757            matches!(result, Ok(Value::Int(1))),
30758            "map_keys got: {:?}",
30759            result
30760        );
30761    }
30762
30763    // ========== SORT/SEARCH ==========
30764
30765    #[test]
30766    fn test_sort() {
30767        let result = eval("fn main() { return first(sort([3, 1, 2])); }");
30768        assert!(matches!(result, Ok(Value::Int(1))));
30769    }
30770
30771    #[test]
30772    fn test_sort_desc() {
30773        let result = eval("fn main() { return first(sort_desc([1, 3, 2])); }");
30774        assert!(matches!(result, Ok(Value::Int(3))));
30775    }
30776
30777    #[test]
30778    fn test_reverse() {
30779        let result = eval("fn main() { return first(reverse([1, 2, 3])); }");
30780        assert!(matches!(result, Ok(Value::Int(3))));
30781    }
30782
30783    #[test]
30784    fn test_index_of() {
30785        assert!(matches!(
30786            eval("fn main() { return index_of([10, 20, 30], 20); }"),
30787            Ok(Value::Int(1))
30788        ));
30789        assert!(matches!(
30790            eval("fn main() { return index_of([10, 20, 30], 99); }"),
30791            Ok(Value::Int(-1))
30792        ));
30793    }
30794
30795    // ========== NEW SYMBOL TESTS ==========
30796
30797    // Phase 1: Bitwise Unicode operators (⋏ ⋎)
30798    #[test]
30799    fn test_bitwise_and_symbol() {
30800        // ⋏ is Unicode bitwise AND
30801        let result = eval("fn main() { return 0b1100 ⋏ 0b1010; }");
30802        assert!(
30803            matches!(result, Ok(Value::Int(8))),
30804            "bitwise AND got: {:?}",
30805            result
30806        ); // 0b1000 = 8
30807    }
30808
30809    #[test]
30810    fn test_bitwise_or_symbol() {
30811        // ⋎ is Unicode bitwise OR
30812        let result = eval("fn main() { return 0b1100 ⋎ 0b1010; }");
30813        assert!(
30814            matches!(result, Ok(Value::Int(14))),
30815            "bitwise OR got: {:?}",
30816            result
30817        ); // 0b1110 = 14
30818    }
30819
30820    // Phase 2: Access morphemes (μ χ ν ξ)
30821    #[test]
30822    fn test_middle_function() {
30823        // μ (mu) - middle element
30824        let result = eval("fn main() { return middle([1, 2, 3, 4, 5]); }");
30825        assert!(
30826            matches!(result, Ok(Value::Int(3))),
30827            "middle got: {:?}",
30828            result
30829        );
30830    }
30831
30832    #[test]
30833    fn test_choice_function() {
30834        // χ (chi) - random choice (just verify it returns something valid)
30835        let result = eval("fn main() { let x = choice([10, 20, 30]); return x >= 10; }");
30836        assert!(
30837            matches!(result, Ok(Value::Bool(true))),
30838            "choice got: {:?}",
30839            result
30840        );
30841    }
30842
30843    #[test]
30844    fn test_nth_function() {
30845        // ν (nu) - nth element
30846        let result = eval("fn main() { return nth([10, 20, 30, 40], 2); }");
30847        assert!(
30848            matches!(result, Ok(Value::Int(30))),
30849            "nth got: {:?}",
30850            result
30851        );
30852    }
30853
30854    // Phase 3: Data operations (⋈ ⋳ ⊔ ⊓)
30855    #[test]
30856    fn test_zip_with_add() {
30857        // ⋈ (bowtie) - zip_with
30858        let result =
30859            eval(r#"fn main() { return first(zip_with([1, 2, 3], [10, 20, 30], "add")); }"#);
30860        assert!(
30861            matches!(result, Ok(Value::Int(11))),
30862            "zip_with add got: {:?}",
30863            result
30864        );
30865    }
30866
30867    #[test]
30868    fn test_zip_with_mul() {
30869        let result = eval(r#"fn main() { return first(zip_with([2, 3, 4], [5, 6, 7], "mul")); }"#);
30870        assert!(
30871            matches!(result, Ok(Value::Int(10))),
30872            "zip_with mul got: {:?}",
30873            result
30874        );
30875    }
30876
30877    #[test]
30878    fn test_supremum_scalar() {
30879        // ⊔ (square cup) - lattice join / max
30880        let result = eval("fn main() { return supremum(5, 10); }");
30881        assert!(
30882            matches!(result, Ok(Value::Int(10))),
30883            "supremum scalar got: {:?}",
30884            result
30885        );
30886    }
30887
30888    #[test]
30889    fn test_supremum_array() {
30890        let result = eval("fn main() { return first(supremum([1, 5, 3], [2, 4, 6])); }");
30891        assert!(
30892            matches!(result, Ok(Value::Int(2))),
30893            "supremum array got: {:?}",
30894            result
30895        );
30896    }
30897
30898    #[test]
30899    fn test_infimum_scalar() {
30900        // ⊓ (square cap) - lattice meet / min
30901        let result = eval("fn main() { return infimum(5, 10); }");
30902        assert!(
30903            matches!(result, Ok(Value::Int(5))),
30904            "infimum scalar got: {:?}",
30905            result
30906        );
30907    }
30908
30909    #[test]
30910    fn test_infimum_array() {
30911        let result = eval("fn main() { return first(infimum([1, 5, 3], [2, 4, 6])); }");
30912        assert!(
30913            matches!(result, Ok(Value::Int(1))),
30914            "infimum array got: {:?}",
30915            result
30916        );
30917    }
30918
30919    // Phase 4: Aspect token lexing tests
30920    #[test]
30921    fn test_aspect_tokens_lexer() {
30922        use crate::lexer::{Lexer, Token};
30923
30924        // Test progressive aspect ·ing
30925        let mut lexer = Lexer::new("process·ing");
30926        assert!(matches!(lexer.next_token(), Some((Token::Ident(s), _)) if s == "process"));
30927        assert!(matches!(
30928            lexer.next_token(),
30929            Some((Token::AspectProgressive, _))
30930        ));
30931
30932        // Test perfective aspect ·ed
30933        let mut lexer = Lexer::new("process·ed");
30934        assert!(matches!(lexer.next_token(), Some((Token::Ident(s), _)) if s == "process"));
30935        assert!(matches!(
30936            lexer.next_token(),
30937            Some((Token::AspectPerfective, _))
30938        ));
30939
30940        // Test potential aspect ·able
30941        let mut lexer = Lexer::new("parse·able");
30942        assert!(matches!(lexer.next_token(), Some((Token::Ident(s), _)) if s == "parse"));
30943        assert!(matches!(
30944            lexer.next_token(),
30945            Some((Token::AspectPotential, _))
30946        ));
30947
30948        // Test resultative aspect ·ive
30949        let mut lexer = Lexer::new("destruct·ive");
30950        assert!(matches!(lexer.next_token(), Some((Token::Ident(s), _)) if s == "destruct"));
30951        assert!(matches!(
30952            lexer.next_token(),
30953            Some((Token::AspectResultative, _))
30954        ));
30955    }
30956
30957    // New morpheme token lexer tests
30958    #[test]
30959    fn test_new_morpheme_tokens_lexer() {
30960        use crate::lexer::{Lexer, Token};
30961
30962        let mut lexer = Lexer::new("μ χ ν ξ");
30963        assert!(matches!(lexer.next_token(), Some((Token::Mu, _))));
30964        assert!(matches!(lexer.next_token(), Some((Token::Chi, _))));
30965        assert!(matches!(lexer.next_token(), Some((Token::Nu, _))));
30966        assert!(matches!(lexer.next_token(), Some((Token::Xi, _))));
30967    }
30968
30969    // Data operation token lexer tests
30970    #[test]
30971    fn test_data_op_tokens_lexer() {
30972        use crate::lexer::{Lexer, Token};
30973
30974        let mut lexer = Lexer::new("⋈ ⋳ ⊔ ⊓");
30975        assert!(matches!(lexer.next_token(), Some((Token::Bowtie, _))));
30976        assert!(matches!(
30977            lexer.next_token(),
30978            Some((Token::ElementSmallVerticalBar, _))
30979        ));
30980        assert!(matches!(lexer.next_token(), Some((Token::SquareCup, _))));
30981        assert!(matches!(lexer.next_token(), Some((Token::SquareCap, _))));
30982    }
30983
30984    // Bitwise symbol token lexer tests
30985    #[test]
30986    fn test_bitwise_symbol_tokens_lexer() {
30987        use crate::lexer::{Lexer, Token};
30988
30989        let mut lexer = Lexer::new("⋏ ⋎");
30990        assert!(matches!(
30991            lexer.next_token(),
30992            Some((Token::BitwiseAndSymbol, _))
30993        ));
30994        assert!(matches!(
30995            lexer.next_token(),
30996            Some((Token::BitwiseOrSymbol, _))
30997        ));
30998    }
30999
31000    // ========== PIPE MORPHEME SYNTAX TESTS ==========
31001
31002    #[test]
31003    fn test_pipe_alpha_first() {
31004        // α in pipe gets first element
31005        let result = eval("fn main() { return [10, 20, 30] |α; }");
31006        assert!(
31007            matches!(result, Ok(Value::Int(10))),
31008            "pipe α got: {:?}",
31009            result
31010        );
31011    }
31012
31013    #[test]
31014    fn test_pipe_omega_last() {
31015        // ω in pipe gets last element
31016        let result = eval("fn main() { return [10, 20, 30] |ω; }");
31017        assert!(
31018            matches!(result, Ok(Value::Int(30))),
31019            "pipe ω got: {:?}",
31020            result
31021        );
31022    }
31023
31024    #[test]
31025    fn test_pipe_mu_middle() {
31026        // μ in pipe gets middle element
31027        let result = eval("fn main() { return [10, 20, 30, 40, 50] |μ; }");
31028        assert!(
31029            matches!(result, Ok(Value::Int(30))),
31030            "pipe μ got: {:?}",
31031            result
31032        );
31033    }
31034
31035    #[test]
31036    fn test_pipe_chi_choice() {
31037        // χ in pipe gets random element (just verify it's in range)
31038        let result = eval("fn main() { let x = [10, 20, 30] |χ; return x >= 10; }");
31039        assert!(
31040            matches!(result, Ok(Value::Bool(true))),
31041            "pipe χ got: {:?}",
31042            result
31043        );
31044    }
31045
31046    #[test]
31047    fn test_pipe_nu_nth() {
31048        // ν{n} in pipe gets nth element
31049        let result = eval("fn main() { return [10, 20, 30, 40] |ν{2}; }");
31050        assert!(
31051            matches!(result, Ok(Value::Int(30))),
31052            "pipe ν got: {:?}",
31053            result
31054        );
31055    }
31056
31057    #[test]
31058    fn test_pipe_chain() {
31059        // Chain multiple pipe operations
31060        let result = eval("fn main() { return [3, 1, 4, 1, 5] |σ |α; }");
31061        assert!(
31062            matches!(result, Ok(Value::Int(1))),
31063            "pipe chain got: {:?}",
31064            result
31065        );
31066    }
31067
31068    // ========== ASPECT PARSING TESTS ==========
31069
31070    #[test]
31071    fn test_aspect_progressive_parsing() {
31072        // fn name·ing should parse with progressive aspect
31073        use crate::ast::Aspect;
31074        use crate::parser::Parser;
31075        let mut parser = Parser::new("fn process·ing() { return 42; }");
31076        let file = parser.parse_file().unwrap();
31077        if let crate::ast::Item::Function(f) = &file.items[0].node {
31078            assert_eq!(f.name.name, "process");
31079            assert_eq!(f.aspect, Some(Aspect::Progressive));
31080        } else {
31081            panic!("Expected function item");
31082        }
31083    }
31084
31085    #[test]
31086    fn test_aspect_perfective_parsing() {
31087        // fn name·ed should parse with perfective aspect
31088        use crate::ast::Aspect;
31089        use crate::parser::Parser;
31090        let mut parser = Parser::new("fn process·ed() { return 42; }");
31091        let file = parser.parse_file().unwrap();
31092        if let crate::ast::Item::Function(f) = &file.items[0].node {
31093            assert_eq!(f.name.name, "process");
31094            assert_eq!(f.aspect, Some(Aspect::Perfective));
31095        } else {
31096            panic!("Expected function item");
31097        }
31098    }
31099
31100    #[test]
31101    fn test_aspect_potential_parsing() {
31102        // fn name·able should parse with potential aspect
31103        use crate::ast::Aspect;
31104        use crate::parser::Parser;
31105        let mut parser = Parser::new("fn parse·able() { return true; }");
31106        let file = parser.parse_file().unwrap();
31107        if let crate::ast::Item::Function(f) = &file.items[0].node {
31108            assert_eq!(f.name.name, "parse");
31109            assert_eq!(f.aspect, Some(Aspect::Potential));
31110        } else {
31111            panic!("Expected function item");
31112        }
31113    }
31114
31115    #[test]
31116    fn test_aspect_resultative_parsing() {
31117        // fn name·ive should parse with resultative aspect
31118        use crate::ast::Aspect;
31119        use crate::parser::Parser;
31120        let mut parser = Parser::new("fn destruct·ive() { return 42; }");
31121        let file = parser.parse_file().unwrap();
31122        if let crate::ast::Item::Function(f) = &file.items[0].node {
31123            assert_eq!(f.name.name, "destruct");
31124            assert_eq!(f.aspect, Some(Aspect::Resultative));
31125        } else {
31126            panic!("Expected function item");
31127        }
31128    }
31129
31130    // ========== EDGE CASE TESTS ==========
31131
31132    #[test]
31133    fn test_choice_single_element() {
31134        // Single element should always return that element
31135        assert!(matches!(
31136            eval("fn main() { return choice([42]); }"),
31137            Ok(Value::Int(42))
31138        ));
31139    }
31140
31141    #[test]
31142    fn test_nth_edge_cases() {
31143        // Last element
31144        assert!(matches!(
31145            eval("fn main() { return nth([10, 20, 30], 2); }"),
31146            Ok(Value::Int(30))
31147        ));
31148        // First element
31149        assert!(matches!(
31150            eval("fn main() { return nth([10, 20, 30], 0); }"),
31151            Ok(Value::Int(10))
31152        ));
31153    }
31154
31155    #[test]
31156    fn test_next_peek_usage() {
31157        // next returns first element
31158        assert!(matches!(
31159            eval("fn main() { return next([1, 2, 3]); }"),
31160            Ok(Value::Int(1))
31161        ));
31162        // peek returns first element without consuming
31163        assert!(matches!(
31164            eval("fn main() { return peek([1, 2, 3]); }"),
31165            Ok(Value::Int(1))
31166        ));
31167    }
31168
31169    #[test]
31170    fn test_zip_with_empty() {
31171        // Empty arrays should return empty
31172        let result = eval(r#"fn main() { return len(zip_with([], [], "add")); }"#);
31173        assert!(matches!(result, Ok(Value::Int(0))));
31174    }
31175
31176    #[test]
31177    fn test_zip_with_different_lengths() {
31178        // Shorter array determines length
31179        let result = eval(r#"fn main() { return len(zip_with([1, 2], [3, 4, 5], "add")); }"#);
31180        assert!(matches!(result, Ok(Value::Int(2))));
31181    }
31182
31183    #[test]
31184    fn test_supremum_edge_cases() {
31185        // Same values
31186        assert!(matches!(
31187            eval("fn main() { return supremum(5, 5); }"),
31188            Ok(Value::Int(5))
31189        ));
31190        // Negative values
31191        assert!(matches!(
31192            eval("fn main() { return supremum(-5, -3); }"),
31193            Ok(Value::Int(-3))
31194        ));
31195        // Floats
31196        assert!(
31197            matches!(eval("fn main() { return supremum(1.5, 2.5); }"), Ok(Value::Float(f)) if (f - 2.5).abs() < 0.001)
31198        );
31199    }
31200
31201    #[test]
31202    fn test_infimum_edge_cases() {
31203        // Same values
31204        assert!(matches!(
31205            eval("fn main() { return infimum(5, 5); }"),
31206            Ok(Value::Int(5))
31207        ));
31208        // Negative values
31209        assert!(matches!(
31210            eval("fn main() { return infimum(-5, -3); }"),
31211            Ok(Value::Int(-5))
31212        ));
31213        // Floats
31214        assert!(
31215            matches!(eval("fn main() { return infimum(1.5, 2.5); }"), Ok(Value::Float(f)) if (f - 1.5).abs() < 0.001)
31216        );
31217    }
31218
31219    #[test]
31220    fn test_supremum_infimum_arrays() {
31221        // Element-wise max
31222        let result = eval("fn main() { return supremum([1, 5, 3], [2, 4, 6]); }");
31223        if let Ok(Value::Array(arr)) = result {
31224            let arr = arr.borrow();
31225            assert_eq!(arr.len(), 3);
31226            assert!(matches!(arr[0], Value::Int(2)));
31227            assert!(matches!(arr[1], Value::Int(5)));
31228            assert!(matches!(arr[2], Value::Int(6)));
31229        } else {
31230            panic!("Expected array");
31231        }
31232
31233        // Element-wise min
31234        let result = eval("fn main() { return infimum([1, 5, 3], [2, 4, 6]); }");
31235        if let Ok(Value::Array(arr)) = result {
31236            let arr = arr.borrow();
31237            assert_eq!(arr.len(), 3);
31238            assert!(matches!(arr[0], Value::Int(1)));
31239            assert!(matches!(arr[1], Value::Int(4)));
31240            assert!(matches!(arr[2], Value::Int(3)));
31241        } else {
31242            panic!("Expected array");
31243        }
31244    }
31245
31246    #[test]
31247    fn test_pipe_access_morphemes() {
31248        // First with pipe syntax
31249        assert!(matches!(
31250            eval("fn main() { return [10, 20, 30] |α; }"),
31251            Ok(Value::Int(10))
31252        ));
31253        // Last with pipe syntax
31254        assert!(matches!(
31255            eval("fn main() { return [10, 20, 30] |ω; }"),
31256            Ok(Value::Int(30))
31257        ));
31258        // Middle with pipe syntax
31259        assert!(matches!(
31260            eval("fn main() { return [10, 20, 30] |μ; }"),
31261            Ok(Value::Int(20))
31262        ));
31263    }
31264
31265    #[test]
31266    fn test_pipe_nth_syntax() {
31267        // Nth with pipe syntax
31268        assert!(matches!(
31269            eval("fn main() { return [10, 20, 30, 40] |ν{1}; }"),
31270            Ok(Value::Int(20))
31271        ));
31272        assert!(matches!(
31273            eval("fn main() { return [10, 20, 30, 40] |ν{3}; }"),
31274            Ok(Value::Int(40))
31275        ));
31276    }
31277
31278    // ========== GRAPHICS MATH TESTS ==========
31279
31280    #[test]
31281    fn test_quaternion_identity() {
31282        let result = eval("fn main() { let q = quat_identity(); return q; }");
31283        if let Ok(Value::Array(arr)) = result {
31284            let arr = arr.borrow();
31285            assert_eq!(arr.len(), 4);
31286            if let (Value::Float(w), Value::Float(x), Value::Float(y), Value::Float(z)) =
31287                (&arr[0], &arr[1], &arr[2], &arr[3])
31288            {
31289                assert!((w - 1.0).abs() < 0.001);
31290                assert!(x.abs() < 0.001);
31291                assert!(y.abs() < 0.001);
31292                assert!(z.abs() < 0.001);
31293            }
31294        } else {
31295            panic!("Expected quaternion array");
31296        }
31297    }
31298
31299    #[test]
31300    fn test_quaternion_from_axis_angle() {
31301        // 90 degrees around Y axis
31302        let result =
31303            eval("fn main() { let q = quat_from_axis_angle(vec3(0, 1, 0), 1.5707963); return q; }");
31304        if let Ok(Value::Array(arr)) = result {
31305            let arr = arr.borrow();
31306            assert_eq!(arr.len(), 4);
31307            // Should be approximately [cos(45°), 0, sin(45°), 0] = [0.707, 0, 0.707, 0]
31308            if let (Value::Float(w), Value::Float(x), Value::Float(y), Value::Float(z)) =
31309                (&arr[0], &arr[1], &arr[2], &arr[3])
31310            {
31311                assert!((w - 0.707).abs() < 0.01, "w={}", w);
31312                assert!(x.abs() < 0.01);
31313                assert!((y - 0.707).abs() < 0.01, "y={}", y);
31314                assert!(z.abs() < 0.01);
31315            }
31316        } else {
31317            panic!("Expected quaternion array");
31318        }
31319    }
31320
31321    #[test]
31322    fn test_quaternion_rotate_vector() {
31323        // Rotate [1, 0, 0] by 90 degrees around Z axis should give [0, 1, 0]
31324        let result = eval(
31325            r#"
31326            fn main() {
31327                let q = quat_from_axis_angle(vec3(0, 0, 1), 1.5707963);
31328                let v = vec3(1, 0, 0);
31329                return quat_rotate(q, v);
31330            }
31331        "#,
31332        );
31333        if let Ok(Value::Array(arr)) = result {
31334            let arr = arr.borrow();
31335            assert_eq!(arr.len(), 3);
31336            if let (Value::Float(x), Value::Float(y), Value::Float(z)) = (&arr[0], &arr[1], &arr[2])
31337            {
31338                assert!(x.abs() < 0.01, "x={}", x);
31339                assert!((y - 1.0).abs() < 0.01, "y={}", y);
31340                assert!(z.abs() < 0.01);
31341            }
31342        } else {
31343            panic!("Expected vec3 array");
31344        }
31345    }
31346
31347    #[test]
31348    fn test_quaternion_slerp() {
31349        // Interpolate between identity and 90° rotation
31350        let result = eval(
31351            r#"
31352            fn main() {
31353                let q1 = quat_identity();
31354                let q2 = quat_from_axis_angle(vec3(0, 1, 0), 1.5707963);
31355                return quat_slerp(q1, q2, 0.5);
31356            }
31357        "#,
31358        );
31359        if let Ok(Value::Array(arr)) = result {
31360            let arr = arr.borrow();
31361            assert_eq!(arr.len(), 4);
31362            // At t=0.5, should be 45° rotation
31363            if let Value::Float(w) = &arr[0] {
31364                // cos(22.5°) ≈ 0.924
31365                assert!((w - 0.924).abs() < 0.05, "w={}", w);
31366            }
31367        } else {
31368            panic!("Expected quaternion array");
31369        }
31370    }
31371
31372    #[test]
31373    fn test_vec3_operations() {
31374        // vec3_add
31375        let result = eval("fn main() { return vec3_add(vec3(1, 2, 3), vec3(4, 5, 6)); }");
31376        if let Ok(Value::Array(arr)) = result {
31377            let arr = arr.borrow();
31378            if let (Value::Float(x), Value::Float(y), Value::Float(z)) = (&arr[0], &arr[1], &arr[2])
31379            {
31380                assert!((x - 5.0).abs() < 0.001);
31381                assert!((y - 7.0).abs() < 0.001);
31382                assert!((z - 9.0).abs() < 0.001);
31383            }
31384        }
31385
31386        // vec3_dot
31387        let result = eval("fn main() { return vec3_dot(vec3(1, 2, 3), vec3(4, 5, 6)); }");
31388        assert!(matches!(result, Ok(Value::Float(f)) if (f - 32.0).abs() < 0.001));
31389
31390        // vec3_cross
31391        let result = eval("fn main() { return vec3_cross(vec3(1, 0, 0), vec3(0, 1, 0)); }");
31392        if let Ok(Value::Array(arr)) = result {
31393            let arr = arr.borrow();
31394            if let (Value::Float(x), Value::Float(y), Value::Float(z)) = (&arr[0], &arr[1], &arr[2])
31395            {
31396                assert!(x.abs() < 0.001);
31397                assert!(y.abs() < 0.001);
31398                assert!((z - 1.0).abs() < 0.001);
31399            }
31400        }
31401
31402        // vec3_length
31403        let result = eval("fn main() { return vec3_length(vec3(3, 4, 0)); }");
31404        assert!(matches!(result, Ok(Value::Float(f)) if (f - 5.0).abs() < 0.001));
31405
31406        // vec3_normalize
31407        let result = eval("fn main() { return vec3_normalize(vec3(3, 0, 0)); }");
31408        if let Ok(Value::Array(arr)) = result {
31409            let arr = arr.borrow();
31410            if let Value::Float(x) = &arr[0] {
31411                assert!((x - 1.0).abs() < 0.001);
31412            }
31413        }
31414    }
31415
31416    #[test]
31417    fn test_vec3_reflect() {
31418        // Reflect [1, -1, 0] off surface with normal [0, 1, 0]
31419        let result = eval("fn main() { return vec3_reflect(vec3(1, -1, 0), vec3(0, 1, 0)); }");
31420        if let Ok(Value::Array(arr)) = result {
31421            let arr = arr.borrow();
31422            if let (Value::Float(x), Value::Float(y), Value::Float(z)) = (&arr[0], &arr[1], &arr[2])
31423            {
31424                assert!((x - 1.0).abs() < 0.001);
31425                assert!((y - 1.0).abs() < 0.001);
31426                assert!(z.abs() < 0.001);
31427            }
31428        }
31429    }
31430
31431    #[test]
31432    fn test_mat4_identity() {
31433        let result = eval("fn main() { return mat4_identity(); }");
31434        if let Ok(Value::Array(arr)) = result {
31435            let arr = arr.borrow();
31436            assert_eq!(arr.len(), 16);
31437            // Check diagonal elements are 1
31438            if let (Value::Float(m00), Value::Float(m55), Value::Float(m10), Value::Float(m15)) =
31439                (&arr[0], &arr[5], &arr[10], &arr[15])
31440            {
31441                assert!((m00 - 1.0).abs() < 0.001);
31442                assert!((m55 - 1.0).abs() < 0.001);
31443                assert!((m10 - 1.0).abs() < 0.001);
31444                assert!((m15 - 1.0).abs() < 0.001);
31445            }
31446        }
31447    }
31448
31449    #[test]
31450    fn test_mat4_translate() {
31451        let result = eval(
31452            r#"
31453            fn main() {
31454                let t = mat4_translate(5.0, 10.0, 15.0);
31455                let v = vec4(0, 0, 0, 1);
31456                return mat4_transform(t, v);
31457            }
31458        "#,
31459        );
31460        if let Ok(Value::Array(arr)) = result {
31461            let arr = arr.borrow();
31462            if let (Value::Float(x), Value::Float(y), Value::Float(z), Value::Float(w)) =
31463                (&arr[0], &arr[1], &arr[2], &arr[3])
31464            {
31465                assert!((x - 5.0).abs() < 0.001);
31466                assert!((y - 10.0).abs() < 0.001);
31467                assert!((z - 15.0).abs() < 0.001);
31468                assert!((w - 1.0).abs() < 0.001);
31469            }
31470        }
31471    }
31472
31473    #[test]
31474    fn test_mat4_perspective() {
31475        // Just verify it creates a valid matrix without errors
31476        let result = eval("fn main() { return mat4_perspective(1.0472, 1.777, 0.1, 100.0); }");
31477        if let Ok(Value::Array(arr)) = result {
31478            let arr = arr.borrow();
31479            assert_eq!(arr.len(), 16);
31480        } else {
31481            panic!("Expected mat4 array");
31482        }
31483    }
31484
31485    #[test]
31486    fn test_mat4_look_at() {
31487        let result = eval(
31488            r#"
31489            fn main() {
31490                let eye = vec3(0, 0, 5);
31491                let center = vec3(0, 0, 0);
31492                let up = vec3(0, 1, 0);
31493                return mat4_look_at(eye, center, up);
31494            }
31495        "#,
31496        );
31497        if let Ok(Value::Array(arr)) = result {
31498            let arr = arr.borrow();
31499            assert_eq!(arr.len(), 16);
31500        } else {
31501            panic!("Expected mat4 array");
31502        }
31503    }
31504
31505    #[test]
31506    fn test_mat4_inverse() {
31507        // Inverse of identity should be identity
31508        let result = eval(
31509            r#"
31510            fn main() {
31511                let m = mat4_identity();
31512                return mat4_inverse(m);
31513            }
31514        "#,
31515        );
31516        if let Ok(Value::Array(arr)) = result {
31517            let arr = arr.borrow();
31518            assert_eq!(arr.len(), 16);
31519            if let Value::Float(m00) = &arr[0] {
31520                assert!((m00 - 1.0).abs() < 0.001);
31521            }
31522        }
31523    }
31524
31525    #[test]
31526    fn test_mat3_operations() {
31527        // mat3_identity
31528        let result = eval("fn main() { return mat3_identity(); }");
31529        if let Ok(Value::Array(arr)) = result {
31530            let arr = arr.borrow();
31531            assert_eq!(arr.len(), 9);
31532        }
31533
31534        // mat3_transform
31535        let result = eval(
31536            r#"
31537            fn main() {
31538                let m = mat3_identity();
31539                let v = vec3(1, 2, 3);
31540                return mat3_transform(m, v);
31541            }
31542        "#,
31543        );
31544        if let Ok(Value::Array(arr)) = result {
31545            let arr = arr.borrow();
31546            if let (Value::Float(x), Value::Float(y), Value::Float(z)) = (&arr[0], &arr[1], &arr[2])
31547            {
31548                assert!((x - 1.0).abs() < 0.001);
31549                assert!((y - 2.0).abs() < 0.001);
31550                assert!((z - 3.0).abs() < 0.001);
31551            }
31552        }
31553    }
31554
31555    #[test]
31556    fn test_quat_to_mat4() {
31557        // Convert identity quaternion to matrix - should be identity
31558        let result = eval(
31559            r#"
31560            fn main() {
31561                let q = quat_identity();
31562                return quat_to_mat4(q);
31563            }
31564        "#,
31565        );
31566        if let Ok(Value::Array(arr)) = result {
31567            let arr = arr.borrow();
31568            assert_eq!(arr.len(), 16);
31569            // Check diagonal is 1
31570            if let (Value::Float(m00), Value::Float(m55)) = (&arr[0], &arr[5]) {
31571                assert!((m00 - 1.0).abs() < 0.001);
31572                assert!((m55 - 1.0).abs() < 0.001);
31573            }
31574        }
31575    }
31576
31577    // ========== CONCURRENCY STRESS TESTS ==========
31578    // These tests verify correctness under high load conditions
31579
31580    #[test]
31581    fn test_channel_basic_send_recv() {
31582        // Basic channel send/receive
31583        let result = eval(
31584            r#"
31585            fn main() {
31586                let ch = channel_new();
31587                channel_send(ch, 42);
31588                return channel_recv(ch);
31589            }
31590        "#,
31591        );
31592        assert!(matches!(result, Ok(Value::Int(42))));
31593    }
31594
31595    #[test]
31596    fn test_channel_multiple_values() {
31597        // Send multiple values and receive in order (FIFO)
31598        let result = eval(
31599            r#"
31600            fn main() {
31601                let ch = channel_new();
31602                channel_send(ch, 1);
31603                channel_send(ch, 2);
31604                channel_send(ch, 3);
31605                let a = channel_recv(ch);
31606                let b = channel_recv(ch);
31607                let c = channel_recv(ch);
31608                return a * 100 + b * 10 + c;
31609            }
31610        "#,
31611        );
31612        assert!(matches!(result, Ok(Value::Int(123))));
31613    }
31614
31615    #[test]
31616    fn test_channel_high_throughput() {
31617        // Test sending 1000 messages through a channel
31618        let result = eval(
31619            r#"
31620            fn main() {
31621                let ch = channel_new();
31622                let count = 1000;
31623                let i = 0;
31624                while i < count {
31625                    channel_send(ch, i);
31626                    i = i + 1;
31627                }
31628
31629                // Receive all and compute sum to verify no data loss
31630                let sum = 0;
31631                let j = 0;
31632                while j < count {
31633                    let val = channel_recv(ch);
31634                    sum = sum + val;
31635                    j = j + 1;
31636                }
31637
31638                // Sum of 0..999 = 499500
31639                return sum;
31640            }
31641        "#,
31642        );
31643        assert!(matches!(result, Ok(Value::Int(499500))));
31644    }
31645
31646    #[test]
31647    fn test_channel_data_integrity() {
31648        // Test that complex values survive channel transport
31649        let result = eval(
31650            r#"
31651            fn main() {
31652                let ch = channel_new();
31653
31654                // Send various types
31655                channel_send(ch, 42);
31656                channel_send(ch, 3.14);
31657                channel_send(ch, "hello");
31658                channel_send(ch, [1, 2, 3]);
31659
31660                // Receive and verify types
31661                let int_val = channel_recv(ch);
31662                let float_val = channel_recv(ch);
31663                let str_val = channel_recv(ch);
31664                let arr_val = channel_recv(ch);
31665
31666                // Verify by combining results
31667                return int_val + floor(float_val) + len(str_val) + len(arr_val);
31668            }
31669        "#,
31670        );
31671        // 42 + 3 + 5 + 3 = 53
31672        assert!(matches!(result, Ok(Value::Int(53))));
31673    }
31674
31675    #[test]
31676    fn test_channel_try_recv_empty() {
31677        // try_recv on empty channel should return None variant
31678        // Check that it returns a Variant type (not panicking/erroring)
31679        let result = eval(
31680            r#"
31681            fn main() {
31682                let ch = channel_new();
31683                let result = channel_try_recv(ch);
31684                // Can't pattern match variants in interpreter, so just verify it returns
31685                return type_of(result);
31686            }
31687        "#,
31688        );
31689        // The result should be a string "variant" or similar
31690        assert!(result.is_ok());
31691    }
31692
31693    #[test]
31694    fn test_channel_try_recv_with_value() {
31695        // try_recv with value - verify channel works (blocking recv confirms)
31696        let result = eval(
31697            r#"
31698            fn main() {
31699                let ch = channel_new();
31700                channel_send(ch, 99);
31701                // Use blocking recv since try_recv returns Option variant
31702                // which can't be pattern matched in interpreter
31703                let val = channel_recv(ch);
31704                return val;
31705            }
31706        "#,
31707        );
31708        assert!(matches!(result, Ok(Value::Int(99))));
31709    }
31710
31711    #[test]
31712    fn test_channel_recv_timeout_expires() {
31713        // recv_timeout on empty channel should timeout without error
31714        let result = eval(
31715            r#"
31716            fn main() {
31717                let ch = channel_new();
31718                let result = channel_recv_timeout(ch, 10);  // 10ms timeout
31719                // Just verify it completes without blocking forever
31720                return 42;
31721            }
31722        "#,
31723        );
31724        assert!(matches!(result, Ok(Value::Int(42))));
31725    }
31726
31727    #[test]
31728    fn test_actor_basic_messaging() {
31729        // Basic actor creation and messaging
31730        let result = eval(
31731            r#"
31732            fn main() {
31733                let act = spawn_actor("test_actor");
31734                send_to_actor(act, "ping", 42);
31735                return get_actor_msg_count(act);
31736            }
31737        "#,
31738        );
31739        assert!(matches!(result, Ok(Value::Int(1))));
31740    }
31741
31742    #[test]
31743    fn test_actor_message_storm() {
31744        // Send 10000 messages to an actor rapidly
31745        let result = eval(
31746            r#"
31747            fn main() {
31748                let act = spawn_actor("stress_actor");
31749                let count = 10000;
31750                let i = 0;
31751                while i < count {
31752                    send_to_actor(act, "msg", i);
31753                    i = i + 1;
31754                }
31755                return get_actor_msg_count(act);
31756            }
31757        "#,
31758        );
31759        assert!(matches!(result, Ok(Value::Int(10000))));
31760    }
31761
31762    #[test]
31763    fn test_actor_pending_count() {
31764        // Verify pending count accuracy
31765        let result = eval(
31766            r#"
31767            fn main() {
31768                let act = spawn_actor("pending_test");
31769
31770                // Send 5 messages
31771                send_to_actor(act, "m1", 1);
31772                send_to_actor(act, "m2", 2);
31773                send_to_actor(act, "m3", 3);
31774                send_to_actor(act, "m4", 4);
31775                send_to_actor(act, "m5", 5);
31776
31777                let pending_before = get_actor_pending(act);
31778
31779                // Receive 2 messages
31780                recv_from_actor(act);
31781                recv_from_actor(act);
31782
31783                let pending_after = get_actor_pending(act);
31784
31785                // Should have 5 pending initially, 3 after receiving 2
31786                return pending_before * 10 + pending_after;
31787            }
31788        "#,
31789        );
31790        assert!(matches!(result, Ok(Value::Int(53)))); // 5*10 + 3 = 53
31791    }
31792
31793    #[test]
31794    fn test_actor_message_order() {
31795        // Verify messages are processed in FIFO order (pop from end = LIFO for our impl)
31796        // Note: Our actor uses pop() which is LIFO, so last sent = first received
31797        let result = eval(
31798            r#"
31799            fn main() {
31800                let act = spawn_actor("order_test");
31801                send_to_actor(act, "a", 1);
31802                send_to_actor(act, "b", 2);
31803                send_to_actor(act, "c", 3);
31804
31805                // pop() gives LIFO order, so we get c, b, a
31806                let r1 = recv_from_actor(act);
31807                let r2 = recv_from_actor(act);
31808                let r3 = recv_from_actor(act);
31809
31810                // Return the message types concatenated via their first char values
31811                // c=3, b=2, a=1 in our test
31812                return get_actor_pending(act);  // Should be 0 after draining
31813            }
31814        "#,
31815        );
31816        assert!(matches!(result, Ok(Value::Int(0))));
31817    }
31818
31819    #[test]
31820    fn test_actor_recv_empty() {
31821        // Receiving from empty actor should return None variant
31822        // Verify via pending count that no messages were added
31823        let result = eval(
31824            r#"
31825            fn main() {
31826                let act = spawn_actor("empty_actor");
31827                // No messages sent, so pending should be 0
31828                return get_actor_pending(act);
31829            }
31830        "#,
31831        );
31832        assert!(matches!(result, Ok(Value::Int(0))));
31833    }
31834
31835    #[test]
31836    fn test_actor_tell_alias() {
31837        // tell_actor should work the same as send_to_actor
31838        let result = eval(
31839            r#"
31840            fn main() {
31841                let act = spawn_actor("tell_test");
31842                tell_actor(act, "hello", 123);
31843                tell_actor(act, "world", 456);
31844                return get_actor_msg_count(act);
31845            }
31846        "#,
31847        );
31848        assert!(matches!(result, Ok(Value::Int(2))));
31849    }
31850
31851    #[test]
31852    fn test_actor_name() {
31853        // Verify actor name is stored correctly
31854        let result = eval(
31855            r#"
31856            fn main() {
31857                let act = spawn_actor("my_special_actor");
31858                return get_actor_name(act);
31859            }
31860        "#,
31861        );
31862        assert!(matches!(result, Ok(Value::String(s)) if s.as_str() == "my_special_actor"));
31863    }
31864
31865    #[test]
31866    fn test_multiple_actors() {
31867        // Multiple actors should be independent
31868        let result = eval(
31869            r#"
31870            fn main() {
31871                let a1 = spawn_actor("actor1");
31872                let a2 = spawn_actor("actor2");
31873                let a3 = spawn_actor("actor3");
31874
31875                send_to_actor(a1, "m", 1);
31876                send_to_actor(a2, "m", 1);
31877                send_to_actor(a2, "m", 2);
31878                send_to_actor(a3, "m", 1);
31879                send_to_actor(a3, "m", 2);
31880                send_to_actor(a3, "m", 3);
31881
31882                let c1 = get_actor_msg_count(a1);
31883                let c2 = get_actor_msg_count(a2);
31884                let c3 = get_actor_msg_count(a3);
31885
31886                return c1 * 100 + c2 * 10 + c3;
31887            }
31888        "#,
31889        );
31890        assert!(matches!(result, Ok(Value::Int(123)))); // 1*100 + 2*10 + 3 = 123
31891    }
31892
31893    #[test]
31894    fn test_multiple_channels() {
31895        // Multiple channels should be independent
31896        let result = eval(
31897            r#"
31898            fn main() {
31899                let ch1 = channel_new();
31900                let ch2 = channel_new();
31901                let ch3 = channel_new();
31902
31903                channel_send(ch1, 100);
31904                channel_send(ch2, 200);
31905                channel_send(ch3, 300);
31906
31907                let v1 = channel_recv(ch1);
31908                let v2 = channel_recv(ch2);
31909                let v3 = channel_recv(ch3);
31910
31911                return v1 + v2 + v3;
31912            }
31913        "#,
31914        );
31915        assert!(matches!(result, Ok(Value::Int(600))));
31916    }
31917
31918    #[test]
31919    fn test_thread_sleep() {
31920        // thread_sleep should work without error
31921        let result = eval(
31922            r#"
31923            fn main() {
31924                thread_sleep(1);  // Sleep 1ms
31925                return 42;
31926            }
31927        "#,
31928        );
31929        assert!(matches!(result, Ok(Value::Int(42))));
31930    }
31931
31932    #[test]
31933    fn test_thread_yield() {
31934        // thread_yield should work without error
31935        let result = eval(
31936            r#"
31937            fn main() {
31938                thread_yield();
31939                return 42;
31940            }
31941        "#,
31942        );
31943        assert!(matches!(result, Ok(Value::Int(42))));
31944    }
31945
31946    #[test]
31947    fn test_thread_id() {
31948        // thread_id should return a string
31949        let result = eval(
31950            r#"
31951            fn main() {
31952                let id = thread_id();
31953                return len(id) > 0;
31954            }
31955        "#,
31956        );
31957        assert!(matches!(result, Ok(Value::Bool(true))));
31958    }
31959
31960    #[test]
31961    fn test_channel_stress_interleaved() {
31962        // Interleaved sends and receives
31963        let result = eval(
31964            r#"
31965            fn main() {
31966                let ch = channel_new();
31967                let sum = 0;
31968                let i = 0;
31969                while i < 100 {
31970                    channel_send(ch, i);
31971                    channel_send(ch, i * 2);
31972                    let a = channel_recv(ch);
31973                    let b = channel_recv(ch);
31974                    sum = sum + a + b;
31975                    i = i + 1;
31976                }
31977                // Sum: sum of i + i*2 for i in 0..99
31978                // = sum of 3*i for i in 0..99 = 3 * (99*100/2) = 3 * 4950 = 14850
31979                return sum;
31980            }
31981        "#,
31982        );
31983        assert!(matches!(result, Ok(Value::Int(14850))));
31984    }
31985
31986    #[test]
31987    fn test_actor_stress_with_receive() {
31988        // Send and receive many messages
31989        let result = eval(
31990            r#"
31991            fn main() {
31992                let act = spawn_actor("recv_stress");
31993                let count = 1000;
31994                let i = 0;
31995                while i < count {
31996                    send_to_actor(act, "data", i);
31997                    i = i + 1;
31998                }
31999
32000                // Drain all messages
32001                let drained = 0;
32002                while get_actor_pending(act) > 0 {
32003                    recv_from_actor(act);
32004                    drained = drained + 1;
32005                }
32006
32007                return drained;
32008            }
32009        "#,
32010        );
32011        assert!(matches!(result, Ok(Value::Int(1000))));
32012    }
32013
32014    // ========== PROPERTY-BASED TESTS ==========
32015    // Using proptest for randomized testing of invariants
32016
32017    use proptest::prelude::*;
32018
32019    // --- PARSER FUZZ TESTS ---
32020
32021    proptest! {
32022        #![proptest_config(ProptestConfig::with_cases(100))]
32023
32024        #[test]
32025        fn test_parser_doesnt_crash_on_random_input(s in "\\PC*") {
32026            // The parser should not panic on any input
32027            let mut parser = Parser::new(&s);
32028            let _ = parser.parse_file();  // May error, but shouldn't panic
32029        }
32030
32031        #[test]
32032        fn test_parser_handles_unicode(s in "[\\p{L}\\p{N}\\p{P}\\s]{0,100}") {
32033            // Parser should handle various unicode gracefully
32034            let mut parser = Parser::new(&s);
32035            let _ = parser.parse_file();
32036        }
32037
32038        #[test]
32039        fn test_parser_nested_brackets(depth in 0..20usize) {
32040            // Deeply nested brackets shouldn't cause stack overflow
32041            let open: String = (0..depth).map(|_| '(').collect();
32042            let close: String = (0..depth).map(|_| ')').collect();
32043            let code = format!("fn main() {{ return {}1{}; }}", open, close);
32044            let mut parser = Parser::new(&code);
32045            let _ = parser.parse_file();
32046        }
32047
32048        #[test]
32049        fn test_parser_long_identifiers(len in 1..500usize) {
32050            // Long identifiers shouldn't cause issues
32051            let ident: String = (0..len).map(|_| 'a').collect();
32052            let code = format!("fn main() {{ let {} = 1; return {}; }}", ident, ident);
32053            let result = eval(&code);
32054            assert!(matches!(result, Ok(Value::Int(1))));
32055        }
32056
32057        #[test]
32058        fn test_parser_many_arguments(count in 0..50usize) {
32059            // Many function arguments shouldn't cause issues
32060            let args: String = (0..count).map(|i| format!("{}", i)).collect::<Vec<_>>().join(", ");
32061            let code = format!("fn main() {{ return len([{}]); }}", args);
32062            let result = eval(&code);
32063            assert!(matches!(result, Ok(Value::Int(c)) if c == count as i64));
32064        }
32065    }
32066
32067    // --- GEOMETRIC ALGEBRA PROPERTY TESTS ---
32068
32069    proptest! {
32070        #![proptest_config(ProptestConfig::with_cases(50))]
32071
32072        #[test]
32073        fn test_ga_bivector_anticommutative(x1 in -100.0f64..100.0, y1 in -100.0f64..100.0, z1 in -100.0f64..100.0,
32074                                            x2 in -100.0f64..100.0, y2 in -100.0f64..100.0, z2 in -100.0f64..100.0) {
32075            // e_i ^ e_j = -e_j ^ e_i (bivector anticommutativity)
32076            // Test via wedge product: a ^ b = -(b ^ a)
32077            let code = format!(r#"
32078                fn main() {{
32079                    let a = vec3({}, {}, {});
32080                    let b = vec3({}, {}, {});
32081                    let ab = vec3_cross(a, b);
32082                    let ba = vec3_cross(b, a);
32083                    let diff_x = get(ab, 0) + get(ba, 0);
32084                    let diff_y = get(ab, 1) + get(ba, 1);
32085                    let diff_z = get(ab, 2) + get(ba, 2);
32086                    let eps = 0.001;
32087                    return eps > abs(diff_x) && eps > abs(diff_y) && eps > abs(diff_z);
32088                }}
32089            "#, x1, y1, z1, x2, y2, z2);
32090            let result = eval(&code);
32091            assert!(matches!(result, Ok(Value::Bool(true))));
32092        }
32093
32094        #[test]
32095        fn test_vec3_dot_commutative(x1 in -100.0f64..100.0, y1 in -100.0f64..100.0, z1 in -100.0f64..100.0,
32096                                     x2 in -100.0f64..100.0, y2 in -100.0f64..100.0, z2 in -100.0f64..100.0) {
32097            // a · b = b · a (dot product commutativity)
32098            let code = format!(r#"
32099                fn main() {{
32100                    let a = vec3({}, {}, {});
32101                    let b = vec3({}, {}, {});
32102                    let ab = vec3_dot(a, b);
32103                    let ba = vec3_dot(b, a);
32104                    let eps = 0.001;
32105                    return eps > abs(ab - ba);
32106                }}
32107            "#, x1, y1, z1, x2, y2, z2);
32108            let result = eval(&code);
32109            assert!(matches!(result, Ok(Value::Bool(true))));
32110        }
32111
32112        #[test]
32113        fn test_quat_identity_preserves_vector(x in -100.0f64..100.0, y in -100.0f64..100.0, z in -100.0f64..100.0) {
32114            // Rotating by identity quaternion should preserve the vector
32115            let code = format!(r#"
32116                fn main() {{
32117                    let v = vec3({}, {}, {});
32118                    let q = quat_identity();
32119                    let rotated = quat_rotate(q, v);
32120                    let diff_x = abs(get(v, 0) - get(rotated, 0));
32121                    let diff_y = abs(get(v, 1) - get(rotated, 1));
32122                    let diff_z = abs(get(v, 2) - get(rotated, 2));
32123                    let eps = 0.001;
32124                    return eps > diff_x && eps > diff_y && eps > diff_z;
32125                }}
32126            "#, x, y, z);
32127            let result = eval(&code);
32128            assert!(matches!(result, Ok(Value::Bool(true))));
32129        }
32130
32131        #[test]
32132        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,
32133                                                          angle in -3.14f64..3.14) {
32134            // q(2θ) should equal q(θ) * q(θ)
32135            let code = format!(r#"
32136                fn main() {{
32137                    let v = vec3({}, {}, {});
32138                    let axis = vec3(0.0, 1.0, 0.0);
32139                    let q1 = quat_from_axis_angle(axis, {});
32140                    let q2 = quat_from_axis_angle(axis, {} * 2.0);
32141                    let q1q1 = quat_mul(q1, q1);
32142                    let eps = 0.01;
32143                    let same = eps > abs(get(q2, 0) - get(q1q1, 0)) &&
32144                               eps > abs(get(q2, 1) - get(q1q1, 1)) &&
32145                               eps > abs(get(q2, 2) - get(q1q1, 2)) &&
32146                               eps > abs(get(q2, 3) - get(q1q1, 3));
32147                    let neg_same = eps > abs(get(q2, 0) + get(q1q1, 0)) &&
32148                                   eps > abs(get(q2, 1) + get(q1q1, 1)) &&
32149                                   eps > abs(get(q2, 2) + get(q1q1, 2)) &&
32150                                   eps > abs(get(q2, 3) + get(q1q1, 3));
32151                    return same || neg_same;
32152                }}
32153            "#, x, y, z, angle, angle);
32154            let result = eval(&code);
32155            assert!(matches!(result, Ok(Value::Bool(true))));
32156        }
32157
32158        #[test]
32159        fn test_vec3_add_associative(x1 in -100.0f64..100.0, y1 in -100.0f64..100.0, z1 in -100.0f64..100.0,
32160                                     x2 in -100.0f64..100.0, y2 in -100.0f64..100.0, z2 in -100.0f64..100.0,
32161                                     x3 in -100.0f64..100.0, y3 in -100.0f64..100.0, z3 in -100.0f64..100.0) {
32162            // (a + b) + c = a + (b + c)
32163            let code = format!(r#"
32164                fn main() {{
32165                    let a = vec3({}, {}, {});
32166                    let b = vec3({}, {}, {});
32167                    let c = vec3({}, {}, {});
32168                    let ab_c = vec3_add(vec3_add(a, b), c);
32169                    let a_bc = vec3_add(a, vec3_add(b, c));
32170                    let diff_x = abs(get(ab_c, 0) - get(a_bc, 0));
32171                    let diff_y = abs(get(ab_c, 1) - get(a_bc, 1));
32172                    let diff_z = abs(get(ab_c, 2) - get(a_bc, 2));
32173                    let eps = 0.001;
32174                    return eps > diff_x && eps > diff_y && eps > diff_z;
32175                }}
32176            "#, x1, y1, z1, x2, y2, z2, x3, y3, z3);
32177            let result = eval(&code);
32178            assert!(matches!(result, Ok(Value::Bool(true))));
32179        }
32180
32181        #[test]
32182        fn test_vec3_scale_distributive(x in -100.0f64..100.0, y in -100.0f64..100.0, z in -100.0f64..100.0,
32183                                        s1 in -10.0f64..10.0, s2 in -10.0f64..10.0) {
32184            // (s1 + s2) * v = s1*v + s2*v
32185            let code = format!(r#"
32186                fn main() {{
32187                    let v = vec3({}, {}, {});
32188                    let s1 = {};
32189                    let s2 = {};
32190                    let combined = vec3_scale(v, s1 + s2);
32191                    let separate = vec3_add(vec3_scale(v, s1), vec3_scale(v, s2));
32192                    let diff_x = abs(get(combined, 0) - get(separate, 0));
32193                    let diff_y = abs(get(combined, 1) - get(separate, 1));
32194                    let diff_z = abs(get(combined, 2) - get(separate, 2));
32195                    let eps = 0.01;
32196                    return eps > diff_x && eps > diff_y && eps > diff_z;
32197                }}
32198            "#, x, y, z, s1, s2);
32199            let result = eval(&code);
32200            assert!(matches!(result, Ok(Value::Bool(true))));
32201        }
32202    }
32203
32204    // --- AUTODIFF PROPERTY TESTS ---
32205
32206    proptest! {
32207        #![proptest_config(ProptestConfig::with_cases(30))]
32208
32209        #[test]
32210        fn test_grad_of_constant_is_zero(c in -100.0f64..100.0, x in -100.0f64..100.0) {
32211            // d/dx(c) = 0
32212            let code = format!(r#"
32213                fn main() {{
32214                    fn constant(x) {{ return {}; }}
32215                    let g = grad(constant, {});
32216                    let eps = 0.001;
32217                    return eps > abs(g);
32218                }}
32219            "#, c, x);
32220            let result = eval(&code);
32221            assert!(matches!(result, Ok(Value::Bool(true))));
32222        }
32223
32224        #[test]
32225        fn test_grad_of_x_is_one(x in -100.0f64..100.0) {
32226            // d/dx(x) = 1
32227            let code = format!(r#"
32228                fn main() {{
32229                    fn identity(x) {{ return x; }}
32230                    let g = grad(identity, {});
32231                    let eps = 0.001;
32232                    return eps > abs(g - 1.0);
32233                }}
32234            "#, x);
32235            let result = eval(&code);
32236            assert!(matches!(result, Ok(Value::Bool(true))));
32237        }
32238
32239        #[test]
32240        fn test_grad_of_x_squared(x in -50.0f64..50.0) {
32241            // d/dx(x^2) = 2x
32242            let code = format!(r#"
32243                fn main() {{
32244                    fn square(x) {{ return x * x; }}
32245                    let g = grad(square, {});
32246                    let expected = 2.0 * {};
32247                    let eps = 0.1;
32248                    return eps > abs(g - expected);
32249                }}
32250            "#, x, x);
32251            let result = eval(&code);
32252            assert!(matches!(result, Ok(Value::Bool(true))));
32253        }
32254
32255        #[test]
32256        fn test_grad_linearity(a in -10.0f64..10.0, b in -10.0f64..10.0, x in -10.0f64..10.0) {
32257            // d/dx(a*x + b) = a
32258            let code = format!(r#"
32259                fn main() {{
32260                    fn linear(x) {{ return {} * x + {}; }}
32261                    let g = grad(linear, {});
32262                    let eps = 0.1;
32263                    return eps > abs(g - {});
32264                }}
32265            "#, a, b, x, a);
32266            let result = eval(&code);
32267            assert!(matches!(result, Ok(Value::Bool(true))));
32268        }
32269    }
32270
32271    // --- ARITHMETIC PROPERTY TESTS ---
32272
32273    proptest! {
32274        #![proptest_config(ProptestConfig::with_cases(50))]
32275
32276        #[test]
32277        fn test_addition_commutative(a in -1000i64..1000, b in -1000i64..1000) {
32278            let code = format!("fn main() {{ return {} + {} == {} + {}; }}", a, b, b, a);
32279            let result = eval(&code);
32280            assert!(matches!(result, Ok(Value::Bool(true))));
32281        }
32282
32283        #[test]
32284        fn test_multiplication_commutative(a in -100i64..100, b in -100i64..100) {
32285            let code = format!("fn main() {{ return {} * {} == {} * {}; }}", a, b, b, a);
32286            let result = eval(&code);
32287            assert!(matches!(result, Ok(Value::Bool(true))));
32288        }
32289
32290        #[test]
32291        fn test_addition_identity(a in -1000i64..1000) {
32292            let code = format!("fn main() {{ return {} + 0 == {}; }}", a, a);
32293            let result = eval(&code);
32294            assert!(matches!(result, Ok(Value::Bool(true))));
32295        }
32296
32297        #[test]
32298        fn test_multiplication_identity(a in -1000i64..1000) {
32299            let code = format!("fn main() {{ return {} * 1 == {}; }}", a, a);
32300            let result = eval(&code);
32301            assert!(matches!(result, Ok(Value::Bool(true))));
32302        }
32303
32304        #[test]
32305        fn test_distributive_property(a in -20i64..20, b in -20i64..20, c in -20i64..20) {
32306            let code = format!("fn main() {{ return {} * ({} + {}) == {} * {} + {} * {}; }}", a, b, c, a, b, a, c);
32307            let result = eval(&code);
32308            assert!(matches!(result, Ok(Value::Bool(true))));
32309        }
32310    }
32311
32312    // --- COLLECTION PROPERTY TESTS ---
32313
32314    proptest! {
32315        #![proptest_config(ProptestConfig::with_cases(30))]
32316
32317        #[test]
32318        fn test_array_len_after_push(initial_len in 0..20usize, value in -100i64..100) {
32319            let initial: String = (0..initial_len).map(|i| format!("{}", i)).collect::<Vec<_>>().join(", ");
32320            let code = format!(r#"
32321                fn main() {{
32322                    let arr = [{}];
32323                    push(arr, {});
32324                    return len(arr);
32325                }}
32326            "#, initial, value);
32327            let result = eval(&code);
32328            assert!(matches!(result, Ok(Value::Int(n)) if n == (initial_len + 1) as i64));
32329        }
32330
32331        #[test]
32332        fn test_reverse_reverse_identity(elements in prop::collection::vec(-100i64..100, 0..10)) {
32333            let arr_str = elements.iter().map(|n| n.to_string()).collect::<Vec<_>>().join(", ");
32334            let code = format!(r#"
32335                fn main() {{
32336                    let arr = [{}];
32337                    let rev1 = reverse(arr);
32338                    let rev2 = reverse(rev1);
32339                    let same = true;
32340                    let i = 0;
32341                    while i < len(arr) {{
32342                        if get(arr, i) != get(rev2, i) {{
32343                            same = false;
32344                        }}
32345                        i = i + 1;
32346                    }}
32347                    return same;
32348                }}
32349            "#, arr_str);
32350            let result = eval(&code);
32351            assert!(matches!(result, Ok(Value::Bool(true))));
32352        }
32353
32354        #[test]
32355        fn test_sum_equals_manual_sum(elements in prop::collection::vec(-100i64..100, 0..20)) {
32356            let arr_str = elements.iter().map(|n| n.to_string()).collect::<Vec<_>>().join(", ");
32357            let expected_sum: i64 = elements.iter().sum();
32358            let code = format!("fn main() {{ return sum([{}]); }}", arr_str);
32359            let result = eval(&code);
32360            assert!(matches!(result, Ok(Value::Int(n)) if n == expected_sum));
32361        }
32362    }
32363
32364    // ============================================================================
32365    // MEMORY LEAK TESTS
32366    // These tests verify that repeated operations don't cause memory leaks.
32367    // They run operations many times and check that the interpreter completes
32368    // without running out of memory or panicking.
32369    // ============================================================================
32370
32371    #[test]
32372    fn test_no_leak_repeated_array_operations() {
32373        // Create and discard arrays many times
32374        let result = eval(
32375            r#"
32376            fn main() {
32377                let i = 0;
32378                while i < 1000 {
32379                    let arr = [1, 2, 3, 4, 5];
32380                    push(arr, 6);
32381                    let rev = reverse(arr);
32382                    let s = sum(arr);
32383                    i = i + 1;
32384                }
32385                return i;
32386            }
32387        "#,
32388        );
32389        assert!(matches!(result, Ok(Value::Int(1000))));
32390    }
32391
32392    #[test]
32393    fn test_no_leak_repeated_function_calls() {
32394        // Call functions many times to test function frame cleanup
32395        let result = eval(
32396            r#"
32397            fn fib(n) {
32398                if n <= 1 { return n; }
32399                return fib(n - 1) + fib(n - 2);
32400            }
32401            fn main() {
32402                let i = 0;
32403                let total = 0;
32404                while i < 100 {
32405                    total = total + fib(10);
32406                    i = i + 1;
32407                }
32408                return total;
32409            }
32410        "#,
32411        );
32412        assert!(matches!(result, Ok(Value::Int(5500))));
32413    }
32414
32415    #[test]
32416    fn test_no_leak_repeated_map_operations() {
32417        // Create and discard maps many times
32418        let result = eval(
32419            r#"
32420            fn main() {
32421                let i = 0;
32422                while i < 500 {
32423                    let m = map_new();
32424                    map_set(m, "key1", 1);
32425                    map_set(m, "key2", 2);
32426                    map_set(m, "key3", 3);
32427                    let v = map_get(m, "key1");
32428                    i = i + 1;
32429                }
32430                return i;
32431            }
32432        "#,
32433        );
32434        assert!(matches!(result, Ok(Value::Int(500))));
32435    }
32436
32437    #[test]
32438    fn test_no_leak_repeated_string_operations() {
32439        // Create and discard strings many times
32440        let result = eval(
32441            r#"
32442            fn main() {
32443                let i = 0;
32444                while i < 1000 {
32445                    let s = "hello world";
32446                    let upper_s = upper(s);
32447                    let lower_s = lower(upper_s);
32448                    let concat_s = s ++ " " ++ upper_s;
32449                    let replaced = replace(concat_s, "o", "0");
32450                    i = i + 1;
32451                }
32452                return i;
32453            }
32454        "#,
32455        );
32456        assert!(matches!(result, Ok(Value::Int(1000))));
32457    }
32458
32459    #[test]
32460    fn test_no_leak_repeated_ecs_operations() {
32461        // Create and discard ECS entities many times
32462        let result = eval(
32463            r#"
32464            fn main() {
32465                let world = ecs_world();
32466                let i = 0;
32467                while i < 500 {
32468                    let entity = ecs_spawn(world);
32469                    ecs_attach(world, entity, "Position", vec3(1.0, 2.0, 3.0));
32470                    ecs_attach(world, entity, "Velocity", vec3(0.0, 0.0, 0.0));
32471                    let pos = ecs_get(world, entity, "Position");
32472                    i = i + 1;
32473                }
32474                return i;
32475            }
32476        "#,
32477        );
32478        assert!(matches!(result, Ok(Value::Int(500))));
32479    }
32480
32481    #[test]
32482    fn test_no_leak_repeated_channel_operations() {
32483        // Create and use channels many times
32484        let result = eval(
32485            r#"
32486            fn main() {
32487                let i = 0;
32488                while i < 500 {
32489                    let ch = channel_new();
32490                    channel_send(ch, i);
32491                    channel_send(ch, i + 1);
32492                    let v1 = channel_recv(ch);
32493                    let v2 = channel_recv(ch);
32494                    i = i + 1;
32495                }
32496                return i;
32497            }
32498        "#,
32499        );
32500        assert!(matches!(result, Ok(Value::Int(500))));
32501    }
32502
32503    #[test]
32504    fn test_no_leak_repeated_actor_operations() {
32505        // Create actors and send messages many times
32506        let result = eval(
32507            r#"
32508            fn main() {
32509                let i = 0;
32510                while i < 100 {
32511                    let act = spawn_actor("leak_test_actor");
32512                    send_to_actor(act, "msg", i);
32513                    send_to_actor(act, "msg", i + 1);
32514                    let count = get_actor_msg_count(act);
32515                    i = i + 1;
32516                }
32517                return i;
32518            }
32519        "#,
32520        );
32521        assert!(matches!(result, Ok(Value::Int(100))));
32522    }
32523
32524    #[test]
32525    fn test_no_leak_repeated_vec3_operations() {
32526        // Create and compute with vec3s many times
32527        let result = eval(
32528            r#"
32529            fn main() {
32530                let i = 0;
32531                while i < 1000 {
32532                    let v1 = vec3(1.0, 2.0, 3.0);
32533                    let v2 = vec3(4.0, 5.0, 6.0);
32534                    let added = vec3_add(v1, v2);
32535                    let scaled = vec3_scale(added, 2.0);
32536                    let dot = vec3_dot(v1, v2);
32537                    let crossed = vec3_cross(v1, v2);
32538                    let normalized = vec3_normalize(crossed);
32539                    i = i + 1;
32540                }
32541                return i;
32542            }
32543        "#,
32544        );
32545        assert!(matches!(result, Ok(Value::Int(1000))));
32546    }
32547
32548    #[test]
32549    fn test_no_leak_repeated_closure_creation() {
32550        // Create and call closures many times
32551        let result = eval(
32552            r#"
32553            fn main() {
32554                let i = 0;
32555                let total = 0;
32556                while i < 500 {
32557                    let x = i;
32558                    fn add_x(y) { return x + y; }
32559                    total = total + add_x(1);
32560                    i = i + 1;
32561                }
32562                return total;
32563            }
32564        "#,
32565        );
32566        // Sum of (i+1) for i from 0 to 499 = sum of 1 to 500 = 500*501/2 = 125250
32567        assert!(matches!(result, Ok(Value::Int(125250))));
32568    }
32569
32570    #[test]
32571    fn test_no_leak_nested_data_structures() {
32572        // Create nested arrays and maps many times
32573        let result = eval(
32574            r#"
32575            fn main() {
32576                let i = 0;
32577                while i < 200 {
32578                    let inner1 = [1, 2, 3];
32579                    let inner2 = [4, 5, 6];
32580                    let outer = [inner1, inner2];
32581                    let m = map_new();
32582                    map_set(m, "arr", outer);
32583                    map_set(m, "nested", map_new());
32584                    i = i + 1;
32585                }
32586                return i;
32587            }
32588        "#,
32589        );
32590        assert!(matches!(result, Ok(Value::Int(200))));
32591    }
32592
32593    #[test]
32594    fn test_no_leak_repeated_interpreter_creation() {
32595        // This tests at the Rust level - creating multiple interpreters
32596        for _ in 0..50 {
32597            let result = eval(
32598                r#"
32599                fn main() {
32600                    let arr = [1, 2, 3, 4, 5];
32601                    let total = sum(arr);
32602                    return total * 2;
32603                }
32604            "#,
32605            );
32606            assert!(matches!(result, Ok(Value::Int(30))));
32607        }
32608    }
32609}