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::rc::Rc;
52use std::sync::{mpsc, Arc, Mutex};
53use std::thread;
54use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
55
56// External crates for extended stdlib
57use base64::{engine::general_purpose, Engine as _};
58use md5::Md5;
59use regex::Regex;
60use sha2::{Digest, Sha256, Sha512};
61use unicode_normalization::UnicodeNormalization;
62use unicode_segmentation::UnicodeSegmentation;
63use uuid::Uuid;
64
65// Polycultural text processing
66use deunicode::deunicode;
67use icu_casemap::titlecase::TitlecaseOptions;
68use icu_casemap::CaseMapper;
69use icu_collator::{Collator, CollatorOptions};
70use icu_locid::{LanguageIdentifier, Locale};
71use icu_segmenter::{SentenceSegmenter, WordSegmenter};
72use unicode_bidi::BidiInfo;
73use unicode_script::{Script, UnicodeScript};
74use unicode_width::UnicodeWidthStr;
75
76// Text intelligence
77use rust_stemmers::{Algorithm as StemAlgorithm, Stemmer};
78use tiktoken_rs::{cl100k_base, p50k_base, r50k_base};
79use whatlang::{detect, Lang, Script as WhatLangScript};
80
81// Cryptographic primitives for experimental crypto
82use rand::Rng;
83
84/// Register all standard library functions
85pub fn register_stdlib(interp: &mut Interpreter) {
86    register_core(interp);
87    register_math(interp);
88    register_collections(interp);
89    register_string(interp);
90    register_evidence(interp);
91    register_affect(interp);
92    register_iter(interp);
93    register_io(interp);
94    register_time(interp);
95    register_random(interp);
96    register_convert(interp);
97    register_cycle(interp);
98    register_simd(interp);
99    register_graphics_math(interp);
100    register_concurrency(interp);
101    // Phase 4: Extended stdlib
102    register_json(interp);
103    register_fs(interp);
104    register_crypto(interp);
105    register_regex(interp);
106    register_uuid(interp);
107    register_system(interp);
108    register_stats(interp);
109    register_matrix(interp);
110    // Phase 5: Language power-ups
111    register_functional(interp);
112    register_benchmark(interp);
113    register_itertools(interp);
114    register_ranges(interp);
115    register_bitwise(interp);
116    register_format(interp);
117    // Phase 6: Pattern matching power-ups
118    register_pattern(interp);
119    // Phase 7: DevEx enhancements
120    register_devex(interp);
121    // Phase 8: Performance optimizations
122    register_soa(interp);
123    register_tensor(interp);
124    register_autodiff(interp);
125    register_spatial(interp);
126    register_physics(interp);
127    // Phase 9: Differentiating features
128    register_geometric_algebra(interp);
129    register_dimensional(interp);
130    register_ecs(interp);
131    // Phase 10: Polycultural text processing
132    register_polycultural_text(interp);
133    // Phase 11: Text intelligence (AI-native)
134    register_text_intelligence(interp);
135    // Phase 12: Emotional hologram and experimental crypto
136    register_hologram(interp);
137    register_experimental_crypto(interp);
138    // Phase 13: Multi-base encoding and cultural numerology
139    register_multibase(interp);
140    // Phase 14: Polycultural audio - world tuning, sacred frequencies, synthesis
141    register_audio(interp);
142    // Phase 15: Spirituality - divination, sacred geometry, gematria, archetypes
143    register_spirituality(interp);
144    // Phase 16: Polycultural color - synesthesia, cultural color systems, color spaces
145    register_color(interp);
146    // Phase 17: Protocol support - HTTP, gRPC, WebSocket, Kafka, AMQP, GraphQL
147    register_protocol(interp);
148    // Phase 18: AI Agent infrastructure - Tools, LLM, Planning, Memory, Vectors
149    register_agent_tools(interp);
150    register_agent_llm(interp);
151    register_agent_memory(interp);
152    register_agent_planning(interp);
153    register_agent_vectors(interp);
154    // Phase 19: Multi-Agent Coordination and Reasoning
155    register_agent_swarm(interp);
156    register_agent_reasoning(interp);
157}
158
159// Helper to define a builtin
160fn define(
161    interp: &mut Interpreter,
162    name: &str,
163    arity: Option<usize>,
164    func: fn(&mut Interpreter, Vec<Value>) -> Result<Value, RuntimeError>,
165) {
166    let builtin = Value::BuiltIn(Rc::new(BuiltInFn {
167        name: name.to_string(),
168        arity,
169        func,
170    }));
171    interp
172        .globals
173        .borrow_mut()
174        .define(name.to_string(), builtin);
175}
176
177// Helper function for value equality comparison
178fn values_equal_simple(a: &Value, b: &Value) -> bool {
179    match (a, b) {
180        (Value::Int(x), Value::Int(y)) => x == y,
181        (Value::Float(x), Value::Float(y)) => (x - y).abs() < f64::EPSILON,
182        (Value::Int(x), Value::Float(y)) | (Value::Float(y), Value::Int(x)) => {
183            (*x as f64 - y).abs() < f64::EPSILON
184        }
185        (Value::Bool(x), Value::Bool(y)) => x == y,
186        (Value::String(x), Value::String(y)) => x == y,
187        (Value::Char(x), Value::Char(y)) => x == y,
188        (Value::Null, Value::Null) => true,
189        (Value::Empty, Value::Empty) => true,
190        (Value::Infinity, Value::Infinity) => true,
191        _ => false,
192    }
193}
194
195// ============================================================================
196// CORE FUNCTIONS
197// ============================================================================
198
199fn register_core(interp: &mut Interpreter) {
200    // print - variadic print without newline
201    define(interp, "print", None, |interp, args| {
202        let output: Vec<String> = args.iter().map(|v| format!("{}", v)).collect();
203        let line = output.join(" ");
204        print!("{}", line);
205        std::io::stdout().flush().ok();
206        interp.output.push(line);
207        Ok(Value::Null)
208    });
209
210    // println - print with newline
211    define(interp, "println", None, |interp, args| {
212        let output: Vec<String> = args.iter().map(|v| format!("{}", v)).collect();
213        let line = output.join(" ");
214        println!("{}", line);
215        interp.output.push(line);
216        Ok(Value::Null)
217    });
218
219    // dbg - debug print with source info
220    define(interp, "dbg", Some(1), |interp, args| {
221        let output = format!("[DEBUG] {:?}", args[0]);
222        println!("{}", output);
223        interp.output.push(output);
224        Ok(args[0].clone())
225    });
226
227    // type_of - get type name
228    define(interp, "type_of", Some(1), |_, args| {
229        let type_name = match &args[0] {
230            Value::Null => "null",
231            Value::Bool(_) => "bool",
232            Value::Int(_) => "i64",
233            Value::Float(_) => "f64",
234            Value::String(_) => "str",
235            Value::Char(_) => "char",
236            Value::Array(_) => "array",
237            Value::Tuple(_) => "tuple",
238            Value::Struct { name, .. } => name,
239            Value::Variant { enum_name, .. } => enum_name,
240            Value::Function(_) => "fn",
241            Value::BuiltIn(_) => "builtin",
242            Value::Ref(_) => "ref",
243            Value::Infinity => "infinity",
244            Value::Empty => "empty",
245            Value::Evidential { evidence, .. } => match evidence {
246                Evidence::Known => "known",
247                Evidence::Uncertain => "uncertain",
248                Evidence::Reported => "reported",
249                Evidence::Paradox => "paradox",
250            },
251            Value::Affective { .. } => "affective",
252            Value::Map(_) => "map",
253            Value::Set(_) => "set",
254            Value::Channel(_) => "channel",
255            Value::ThreadHandle(_) => "thread",
256            Value::Actor(_) => "actor",
257            Value::Future(_) => "future",
258        };
259        Ok(Value::String(Rc::new(type_name.to_string())))
260    });
261
262    // assert - assertion with optional message
263    define(interp, "assert", None, |_, args| {
264        if args.is_empty() {
265            return Err(RuntimeError::new("assert() requires at least one argument"));
266        }
267        let condition = match &args[0] {
268            Value::Bool(b) => *b,
269            _ => return Err(RuntimeError::new("assert() condition must be bool")),
270        };
271        if !condition {
272            let msg = if args.len() > 1 {
273                format!("{}", args[1])
274            } else {
275                "assertion failed".to_string()
276            };
277            return Err(RuntimeError::new(format!("Assertion failed: {}", msg)));
278        }
279        Ok(Value::Null)
280    });
281
282    // panic - abort execution with message
283    define(interp, "panic", None, |_, args| {
284        let msg = if args.is_empty() {
285            "explicit panic".to_string()
286        } else {
287            args.iter()
288                .map(|v| format!("{}", v))
289                .collect::<Vec<_>>()
290                .join(" ")
291        };
292        Err(RuntimeError::new(format!("PANIC: {}", msg)))
293    });
294
295    // todo - mark unimplemented code
296    define(interp, "todo", None, |_, args| {
297        let msg = if args.is_empty() {
298            "not yet implemented".to_string()
299        } else {
300            format!("{}", args[0])
301        };
302        Err(RuntimeError::new(format!("TODO: {}", msg)))
303    });
304
305    // unreachable - mark code that should never execute
306    define(interp, "unreachable", None, |_, args| {
307        let msg = if args.is_empty() {
308            "entered unreachable code".to_string()
309        } else {
310            format!("{}", args[0])
311        };
312        Err(RuntimeError::new(format!("UNREACHABLE: {}", msg)))
313    });
314
315    // clone - deep clone a value
316    define(interp, "clone", Some(1), |_, args| Ok(deep_clone(&args[0])));
317
318    // identity - return value unchanged (useful in pipes)
319    define(interp, "id", Some(1), |_, args| Ok(args[0].clone()));
320
321    // default - return default value for a type
322    define(interp, "default", Some(1), |_, args| {
323        let type_name = match &args[0] {
324            Value::String(s) => s.as_str(),
325            _ => return Err(RuntimeError::new("default() requires type name string")),
326        };
327        match type_name {
328            "bool" => Ok(Value::Bool(false)),
329            "i64" | "int" => Ok(Value::Int(0)),
330            "f64" | "float" => Ok(Value::Float(0.0)),
331            "str" | "string" => Ok(Value::String(Rc::new(String::new()))),
332            "array" => Ok(Value::Array(Rc::new(RefCell::new(Vec::new())))),
333            _ => Err(RuntimeError::new(format!(
334                "no default for type: {}",
335                type_name
336            ))),
337        }
338    });
339}
340
341// Deep clone helper
342fn deep_clone(value: &Value) -> Value {
343    match value {
344        Value::Array(arr) => {
345            let cloned: Vec<Value> = arr.borrow().iter().map(deep_clone).collect();
346            Value::Array(Rc::new(RefCell::new(cloned)))
347        }
348        Value::Struct { name, fields } => {
349            let cloned: HashMap<String, Value> = fields
350                .borrow()
351                .iter()
352                .map(|(k, v)| (k.clone(), deep_clone(v)))
353                .collect();
354            Value::Struct {
355                name: name.clone(),
356                fields: Rc::new(RefCell::new(cloned)),
357            }
358        }
359        Value::Evidential { value, evidence } => Value::Evidential {
360            value: Box::new(deep_clone(value)),
361            evidence: *evidence,
362        },
363        other => other.clone(),
364    }
365}
366
367// ============================================================================
368// MATH FUNCTIONS
369// ============================================================================
370
371fn register_math(interp: &mut Interpreter) {
372    // Basic math
373    define(interp, "abs", Some(1), |_, args| match &args[0] {
374        Value::Int(n) => Ok(Value::Int(n.abs())),
375        Value::Float(n) => Ok(Value::Float(n.abs())),
376        _ => Err(RuntimeError::new("abs() requires number")),
377    });
378
379    define(interp, "neg", Some(1), |_, args| match &args[0] {
380        Value::Int(n) => Ok(Value::Int(-n)),
381        Value::Float(n) => Ok(Value::Float(-n)),
382        _ => Err(RuntimeError::new("neg() requires number")),
383    });
384
385    define(interp, "sqrt", Some(1), |_, args| match &args[0] {
386        Value::Int(n) => Ok(Value::Float((*n as f64).sqrt())),
387        Value::Float(n) => Ok(Value::Float(n.sqrt())),
388        _ => Err(RuntimeError::new("sqrt() requires number")),
389    });
390
391    define(interp, "cbrt", Some(1), |_, args| match &args[0] {
392        Value::Int(n) => Ok(Value::Float((*n as f64).cbrt())),
393        Value::Float(n) => Ok(Value::Float(n.cbrt())),
394        _ => Err(RuntimeError::new("cbrt() requires number")),
395    });
396
397    define(interp, "pow", Some(2), |_, args| {
398        match (&args[0], &args[1]) {
399            (Value::Int(base), Value::Int(exp)) => {
400                if *exp >= 0 {
401                    Ok(Value::Int(base.pow(*exp as u32)))
402                } else {
403                    Ok(Value::Float((*base as f64).powi(*exp as i32)))
404                }
405            }
406            (Value::Float(base), Value::Int(exp)) => Ok(Value::Float(base.powi(*exp as i32))),
407            (Value::Float(base), Value::Float(exp)) => Ok(Value::Float(base.powf(*exp))),
408            (Value::Int(base), Value::Float(exp)) => Ok(Value::Float((*base as f64).powf(*exp))),
409            _ => Err(RuntimeError::new("pow() requires numbers")),
410        }
411    });
412
413    define(interp, "exp", Some(1), |_, args| match &args[0] {
414        Value::Int(n) => Ok(Value::Float((*n as f64).exp())),
415        Value::Float(n) => Ok(Value::Float(n.exp())),
416        _ => Err(RuntimeError::new("exp() requires number")),
417    });
418
419    define(interp, "ln", Some(1), |_, args| match &args[0] {
420        Value::Int(n) => Ok(Value::Float((*n as f64).ln())),
421        Value::Float(n) => Ok(Value::Float(n.ln())),
422        _ => Err(RuntimeError::new("ln() requires number")),
423    });
424
425    define(interp, "log", Some(2), |_, args| {
426        let (value, base) = match (&args[0], &args[1]) {
427            (Value::Int(v), Value::Int(b)) => (*v as f64, *b as f64),
428            (Value::Float(v), Value::Int(b)) => (*v, *b as f64),
429            (Value::Int(v), Value::Float(b)) => (*v as f64, *b),
430            (Value::Float(v), Value::Float(b)) => (*v, *b),
431            _ => return Err(RuntimeError::new("log() requires numbers")),
432        };
433        Ok(Value::Float(value.log(base)))
434    });
435
436    define(interp, "log10", Some(1), |_, args| match &args[0] {
437        Value::Int(n) => Ok(Value::Float((*n as f64).log10())),
438        Value::Float(n) => Ok(Value::Float(n.log10())),
439        _ => Err(RuntimeError::new("log10() requires number")),
440    });
441
442    define(interp, "log2", Some(1), |_, args| match &args[0] {
443        Value::Int(n) => Ok(Value::Float((*n as f64).log2())),
444        Value::Float(n) => Ok(Value::Float(n.log2())),
445        _ => Err(RuntimeError::new("log2() requires number")),
446    });
447
448    // Trigonometry
449    define(interp, "sin", Some(1), |_, args| match &args[0] {
450        Value::Int(n) => Ok(Value::Float((*n as f64).sin())),
451        Value::Float(n) => Ok(Value::Float(n.sin())),
452        _ => Err(RuntimeError::new("sin() requires number")),
453    });
454
455    define(interp, "cos", Some(1), |_, args| match &args[0] {
456        Value::Int(n) => Ok(Value::Float((*n as f64).cos())),
457        Value::Float(n) => Ok(Value::Float(n.cos())),
458        _ => Err(RuntimeError::new("cos() requires number")),
459    });
460
461    define(interp, "tan", Some(1), |_, args| match &args[0] {
462        Value::Int(n) => Ok(Value::Float((*n as f64).tan())),
463        Value::Float(n) => Ok(Value::Float(n.tan())),
464        _ => Err(RuntimeError::new("tan() requires number")),
465    });
466
467    define(interp, "asin", Some(1), |_, args| match &args[0] {
468        Value::Int(n) => Ok(Value::Float((*n as f64).asin())),
469        Value::Float(n) => Ok(Value::Float(n.asin())),
470        _ => Err(RuntimeError::new("asin() requires number")),
471    });
472
473    define(interp, "acos", Some(1), |_, args| match &args[0] {
474        Value::Int(n) => Ok(Value::Float((*n as f64).acos())),
475        Value::Float(n) => Ok(Value::Float(n.acos())),
476        _ => Err(RuntimeError::new("acos() requires number")),
477    });
478
479    define(interp, "atan", Some(1), |_, args| match &args[0] {
480        Value::Int(n) => Ok(Value::Float((*n as f64).atan())),
481        Value::Float(n) => Ok(Value::Float(n.atan())),
482        _ => Err(RuntimeError::new("atan() requires number")),
483    });
484
485    define(interp, "atan2", Some(2), |_, args| {
486        let (y, x) = match (&args[0], &args[1]) {
487            (Value::Int(y), Value::Int(x)) => (*y as f64, *x as f64),
488            (Value::Float(y), Value::Int(x)) => (*y, *x as f64),
489            (Value::Int(y), Value::Float(x)) => (*y as f64, *x),
490            (Value::Float(y), Value::Float(x)) => (*y, *x),
491            _ => return Err(RuntimeError::new("atan2() requires numbers")),
492        };
493        Ok(Value::Float(y.atan2(x)))
494    });
495
496    // Hyperbolic
497    define(interp, "sinh", Some(1), |_, args| match &args[0] {
498        Value::Int(n) => Ok(Value::Float((*n as f64).sinh())),
499        Value::Float(n) => Ok(Value::Float(n.sinh())),
500        _ => Err(RuntimeError::new("sinh() requires number")),
501    });
502
503    define(interp, "cosh", Some(1), |_, args| match &args[0] {
504        Value::Int(n) => Ok(Value::Float((*n as f64).cosh())),
505        Value::Float(n) => Ok(Value::Float(n.cosh())),
506        _ => Err(RuntimeError::new("cosh() requires number")),
507    });
508
509    define(interp, "tanh", Some(1), |_, args| match &args[0] {
510        Value::Int(n) => Ok(Value::Float((*n as f64).tanh())),
511        Value::Float(n) => Ok(Value::Float(n.tanh())),
512        _ => Err(RuntimeError::new("tanh() requires number")),
513    });
514
515    // Rounding
516    define(interp, "floor", Some(1), |_, args| match &args[0] {
517        Value::Int(n) => Ok(Value::Int(*n)),
518        Value::Float(n) => Ok(Value::Int(n.floor() as i64)),
519        _ => Err(RuntimeError::new("floor() requires number")),
520    });
521
522    define(interp, "ceil", Some(1), |_, args| match &args[0] {
523        Value::Int(n) => Ok(Value::Int(*n)),
524        Value::Float(n) => Ok(Value::Int(n.ceil() as i64)),
525        _ => Err(RuntimeError::new("ceil() requires number")),
526    });
527
528    define(interp, "round", Some(1), |_, args| match &args[0] {
529        Value::Int(n) => Ok(Value::Int(*n)),
530        Value::Float(n) => Ok(Value::Int(n.round() as i64)),
531        _ => Err(RuntimeError::new("round() requires number")),
532    });
533
534    define(interp, "trunc", Some(1), |_, args| match &args[0] {
535        Value::Int(n) => Ok(Value::Int(*n)),
536        Value::Float(n) => Ok(Value::Int(n.trunc() as i64)),
537        _ => Err(RuntimeError::new("trunc() requires number")),
538    });
539
540    define(interp, "fract", Some(1), |_, args| match &args[0] {
541        Value::Int(_) => Ok(Value::Float(0.0)),
542        Value::Float(n) => Ok(Value::Float(n.fract())),
543        _ => Err(RuntimeError::new("fract() requires number")),
544    });
545
546    // Min/Max/Clamp
547    define(interp, "min", Some(2), |_, args| {
548        match (&args[0], &args[1]) {
549            (Value::Int(a), Value::Int(b)) => Ok(Value::Int(*a.min(b))),
550            (Value::Float(a), Value::Float(b)) => Ok(Value::Float(a.min(*b))),
551            (Value::Int(a), Value::Float(b)) => Ok(Value::Float((*a as f64).min(*b))),
552            (Value::Float(a), Value::Int(b)) => Ok(Value::Float(a.min(*b as f64))),
553            _ => Err(RuntimeError::new("min() requires numbers")),
554        }
555    });
556
557    define(interp, "max", Some(2), |_, args| {
558        match (&args[0], &args[1]) {
559            (Value::Int(a), Value::Int(b)) => Ok(Value::Int(*a.max(b))),
560            (Value::Float(a), Value::Float(b)) => Ok(Value::Float(a.max(*b))),
561            (Value::Int(a), Value::Float(b)) => Ok(Value::Float((*a as f64).max(*b))),
562            (Value::Float(a), Value::Int(b)) => Ok(Value::Float(a.max(*b as f64))),
563            _ => Err(RuntimeError::new("max() requires numbers")),
564        }
565    });
566
567    define(interp, "clamp", Some(3), |_, args| {
568        match (&args[0], &args[1], &args[2]) {
569            (Value::Int(val), Value::Int(min), Value::Int(max)) => {
570                Ok(Value::Int(*val.max(min).min(max)))
571            }
572            (Value::Float(val), Value::Float(min), Value::Float(max)) => {
573                Ok(Value::Float(val.max(*min).min(*max)))
574            }
575            _ => Err(RuntimeError::new("clamp() requires matching number types")),
576        }
577    });
578
579    // Sign
580    define(interp, "sign", Some(1), |_, args| match &args[0] {
581        Value::Int(n) => Ok(Value::Int(n.signum())),
582        Value::Float(n) => Ok(Value::Float(if *n > 0.0 {
583            1.0
584        } else if *n < 0.0 {
585            -1.0
586        } else {
587            0.0
588        })),
589        _ => Err(RuntimeError::new("sign() requires number")),
590    });
591
592    // Constants
593    define(interp, "PI", Some(0), |_, _| {
594        Ok(Value::Float(std::f64::consts::PI))
595    });
596    define(interp, "E", Some(0), |_, _| {
597        Ok(Value::Float(std::f64::consts::E))
598    });
599    define(interp, "TAU", Some(0), |_, _| {
600        Ok(Value::Float(std::f64::consts::TAU))
601    });
602    define(interp, "PHI", Some(0), |_, _| {
603        Ok(Value::Float(1.618033988749895))
604    }); // Golden ratio
605
606    // GCD/LCM
607    define(interp, "gcd", Some(2), |_, args| {
608        match (&args[0], &args[1]) {
609            (Value::Int(a), Value::Int(b)) => Ok(Value::Int(gcd(*a, *b))),
610            _ => Err(RuntimeError::new("gcd() requires integers")),
611        }
612    });
613
614    define(interp, "lcm", Some(2), |_, args| {
615        match (&args[0], &args[1]) {
616            (Value::Int(a), Value::Int(b)) => {
617                let g = gcd(*a, *b);
618                Ok(Value::Int((a * b).abs() / g))
619            }
620            _ => Err(RuntimeError::new("lcm() requires integers")),
621        }
622    });
623
624    // Factorial
625    define(interp, "factorial", Some(1), |_, args| match &args[0] {
626        Value::Int(n) if *n >= 0 => {
627            let mut result: i64 = 1;
628            for i in 2..=(*n as u64) {
629                result = result.saturating_mul(i as i64);
630            }
631            Ok(Value::Int(result))
632        }
633        Value::Int(_) => Err(RuntimeError::new(
634            "factorial() requires non-negative integer",
635        )),
636        _ => Err(RuntimeError::new("factorial() requires integer")),
637    });
638
639    // Is checks
640    define(interp, "is_nan", Some(1), |_, args| match &args[0] {
641        Value::Float(n) => Ok(Value::Bool(n.is_nan())),
642        Value::Int(_) => Ok(Value::Bool(false)),
643        _ => Err(RuntimeError::new("is_nan() requires number")),
644    });
645
646    define(interp, "is_infinite", Some(1), |_, args| match &args[0] {
647        Value::Float(n) => Ok(Value::Bool(n.is_infinite())),
648        Value::Int(_) => Ok(Value::Bool(false)),
649        Value::Infinity => Ok(Value::Bool(true)),
650        _ => Err(RuntimeError::new("is_infinite() requires number")),
651    });
652
653    define(interp, "is_finite", Some(1), |_, args| match &args[0] {
654        Value::Float(n) => Ok(Value::Bool(n.is_finite())),
655        Value::Int(_) => Ok(Value::Bool(true)),
656        Value::Infinity => Ok(Value::Bool(false)),
657        _ => Err(RuntimeError::new("is_finite() requires number")),
658    });
659
660    define(interp, "is_even", Some(1), |_, args| match &args[0] {
661        Value::Int(n) => Ok(Value::Bool(n % 2 == 0)),
662        _ => Err(RuntimeError::new("is_even() requires integer")),
663    });
664
665    define(interp, "is_odd", Some(1), |_, args| match &args[0] {
666        Value::Int(n) => Ok(Value::Bool(n % 2 != 0)),
667        _ => Err(RuntimeError::new("is_odd() requires integer")),
668    });
669
670    define(interp, "is_prime", Some(1), |_, args| match &args[0] {
671        Value::Int(n) => Ok(Value::Bool(is_prime(*n))),
672        _ => Err(RuntimeError::new("is_prime() requires integer")),
673    });
674}
675
676fn gcd(mut a: i64, mut b: i64) -> i64 {
677    a = a.abs();
678    b = b.abs();
679    while b != 0 {
680        let t = b;
681        b = a % b;
682        a = t;
683    }
684    a
685}
686
687fn is_prime(n: i64) -> bool {
688    if n < 2 {
689        return false;
690    }
691    if n == 2 {
692        return true;
693    }
694    if n % 2 == 0 {
695        return false;
696    }
697    let sqrt = (n as f64).sqrt() as i64;
698    for i in (3..=sqrt).step_by(2) {
699        if n % i == 0 {
700            return false;
701        }
702    }
703    true
704}
705
706// ============================================================================
707// COLLECTION FUNCTIONS
708// ============================================================================
709
710fn register_collections(interp: &mut Interpreter) {
711    // Basic operations
712    define(interp, "len", Some(1), |_, args| match &args[0] {
713        Value::Array(arr) => Ok(Value::Int(arr.borrow().len() as i64)),
714        Value::String(s) => Ok(Value::Int(s.chars().count() as i64)),
715        Value::Tuple(t) => Ok(Value::Int(t.len() as i64)),
716        Value::Map(m) => Ok(Value::Int(m.borrow().len() as i64)),
717        Value::Set(s) => Ok(Value::Int(s.borrow().len() as i64)),
718        _ => Err(RuntimeError::new(
719            "len() requires array, string, tuple, map, or set",
720        )),
721    });
722
723    define(interp, "is_empty", Some(1), |_, args| match &args[0] {
724        Value::Array(arr) => Ok(Value::Bool(arr.borrow().is_empty())),
725        Value::String(s) => Ok(Value::Bool(s.is_empty())),
726        Value::Tuple(t) => Ok(Value::Bool(t.is_empty())),
727        Value::Map(m) => Ok(Value::Bool(m.borrow().is_empty())),
728        Value::Set(s) => Ok(Value::Bool(s.borrow().is_empty())),
729        _ => Err(RuntimeError::new("is_empty() requires collection")),
730    });
731
732    // Array operations
733    define(interp, "push", Some(2), |_, args| match &args[0] {
734        Value::Array(arr) => {
735            arr.borrow_mut().push(args[1].clone());
736            Ok(Value::Null)
737        }
738        _ => Err(RuntimeError::new("push() requires array")),
739    });
740
741    define(interp, "pop", Some(1), |_, args| match &args[0] {
742        Value::Array(arr) => arr
743            .borrow_mut()
744            .pop()
745            .ok_or_else(|| RuntimeError::new("pop() on empty array")),
746        _ => Err(RuntimeError::new("pop() requires array")),
747    });
748
749    define(interp, "first", Some(1), |_, args| match &args[0] {
750        Value::Array(arr) => arr
751            .borrow()
752            .first()
753            .cloned()
754            .ok_or_else(|| RuntimeError::new("first() on empty array")),
755        Value::Tuple(t) => t
756            .first()
757            .cloned()
758            .ok_or_else(|| RuntimeError::new("first() on empty tuple")),
759        _ => Err(RuntimeError::new("first() requires array or tuple")),
760    });
761
762    define(interp, "last", Some(1), |_, args| match &args[0] {
763        Value::Array(arr) => arr
764            .borrow()
765            .last()
766            .cloned()
767            .ok_or_else(|| RuntimeError::new("last() on empty array")),
768        Value::Tuple(t) => t
769            .last()
770            .cloned()
771            .ok_or_else(|| RuntimeError::new("last() on empty tuple")),
772        _ => Err(RuntimeError::new("last() requires array or tuple")),
773    });
774
775    // μ (mu) - middle/median element
776    define(interp, "middle", Some(1), |_, args| match &args[0] {
777        Value::Array(arr) => {
778            let arr = arr.borrow();
779            if arr.is_empty() {
780                return Err(RuntimeError::new("middle() on empty array"));
781            }
782            let mid = arr.len() / 2;
783            Ok(arr[mid].clone())
784        }
785        Value::Tuple(t) => {
786            if t.is_empty() {
787                return Err(RuntimeError::new("middle() on empty tuple"));
788            }
789            let mid = t.len() / 2;
790            Ok(t[mid].clone())
791        }
792        _ => Err(RuntimeError::new("middle() requires array or tuple")),
793    });
794
795    // χ (chi) - random choice from collection
796    define(interp, "choice", Some(1), |_, args| {
797        use std::time::{SystemTime, UNIX_EPOCH};
798        match &args[0] {
799            Value::Array(arr) => {
800                let arr = arr.borrow();
801                if arr.is_empty() {
802                    return Err(RuntimeError::new("choice() on empty array"));
803                }
804                let seed = SystemTime::now()
805                    .duration_since(UNIX_EPOCH)
806                    .unwrap_or(std::time::Duration::ZERO)
807                    .as_nanos() as u64;
808                let idx = ((seed.wrapping_mul(1103515245).wrapping_add(12345)) >> 16) as usize
809                    % arr.len();
810                Ok(arr[idx].clone())
811            }
812            Value::Tuple(t) => {
813                if t.is_empty() {
814                    return Err(RuntimeError::new("choice() on empty tuple"));
815                }
816                let seed = SystemTime::now()
817                    .duration_since(UNIX_EPOCH)
818                    .unwrap_or(std::time::Duration::ZERO)
819                    .as_nanos() as u64;
820                let idx =
821                    ((seed.wrapping_mul(1103515245).wrapping_add(12345)) >> 16) as usize % t.len();
822                Ok(t[idx].clone())
823            }
824            _ => Err(RuntimeError::new("choice() requires array or tuple")),
825        }
826    });
827
828    // ν (nu) - nth element (alias for get with better semantics)
829    define(interp, "nth", Some(2), |_, args| {
830        let n = match &args[1] {
831            Value::Int(i) => *i,
832            _ => return Err(RuntimeError::new("nth() index must be integer")),
833        };
834        match &args[0] {
835            Value::Array(arr) => {
836                let arr = arr.borrow();
837                if n < 0 || n as usize >= arr.len() {
838                    return Err(RuntimeError::new("nth() index out of bounds"));
839                }
840                Ok(arr[n as usize].clone())
841            }
842            Value::Tuple(t) => {
843                if n < 0 || n as usize >= t.len() {
844                    return Err(RuntimeError::new("nth() index out of bounds"));
845                }
846                Ok(t[n as usize].clone())
847            }
848            _ => Err(RuntimeError::new("nth() requires array or tuple")),
849        }
850    });
851
852    // ξ (xi) - next: pop and return first element (advances iterator)
853    define(interp, "next", Some(1), |_, args| match &args[0] {
854        Value::Array(arr) => {
855            let mut arr = arr.borrow_mut();
856            if arr.is_empty() {
857                return Err(RuntimeError::new("next() on empty array"));
858            }
859            Ok(arr.remove(0))
860        }
861        _ => Err(RuntimeError::new("next() requires array")),
862    });
863
864    // peek - look at first element without consuming (for iterators)
865    define(interp, "peek", Some(1), |_, args| match &args[0] {
866        Value::Array(arr) => arr
867            .borrow()
868            .first()
869            .cloned()
870            .ok_or_else(|| RuntimeError::new("peek() on empty array")),
871        _ => Err(RuntimeError::new("peek() requires array")),
872    });
873
874    define(interp, "get", Some(2), |_, args| {
875        let index = match &args[1] {
876            Value::Int(i) => *i,
877            _ => return Err(RuntimeError::new("get() index must be integer")),
878        };
879        match &args[0] {
880            Value::Array(arr) => {
881                let arr = arr.borrow();
882                let idx = if index < 0 {
883                    arr.len() as i64 + index
884                } else {
885                    index
886                } as usize;
887                arr.get(idx)
888                    .cloned()
889                    .ok_or_else(|| RuntimeError::new("index out of bounds"))
890            }
891            Value::Tuple(t) => {
892                let idx = if index < 0 {
893                    t.len() as i64 + index
894                } else {
895                    index
896                } as usize;
897                t.get(idx)
898                    .cloned()
899                    .ok_or_else(|| RuntimeError::new("index out of bounds"))
900            }
901            _ => Err(RuntimeError::new("get() requires array or tuple")),
902        }
903    });
904
905    define(interp, "set", Some(3), |_, args| {
906        let index = match &args[1] {
907            Value::Int(i) => *i as usize,
908            _ => return Err(RuntimeError::new("set() index must be integer")),
909        };
910        match &args[0] {
911            Value::Array(arr) => {
912                let mut arr = arr.borrow_mut();
913                if index >= arr.len() {
914                    return Err(RuntimeError::new("index out of bounds"));
915                }
916                arr[index] = args[2].clone();
917                Ok(Value::Null)
918            }
919            _ => Err(RuntimeError::new("set() requires array")),
920        }
921    });
922
923    define(interp, "insert", Some(3), |_, args| {
924        let index = match &args[1] {
925            Value::Int(i) => *i as usize,
926            _ => return Err(RuntimeError::new("insert() index must be integer")),
927        };
928        match &args[0] {
929            Value::Array(arr) => {
930                let mut arr = arr.borrow_mut();
931                if index > arr.len() {
932                    return Err(RuntimeError::new("index out of bounds"));
933                }
934                arr.insert(index, args[2].clone());
935                Ok(Value::Null)
936            }
937            _ => Err(RuntimeError::new("insert() requires array")),
938        }
939    });
940
941    define(interp, "remove", Some(2), |_, args| {
942        let index = match &args[1] {
943            Value::Int(i) => *i as usize,
944            _ => return Err(RuntimeError::new("remove() index must be integer")),
945        };
946        match &args[0] {
947            Value::Array(arr) => {
948                let mut arr = arr.borrow_mut();
949                if index >= arr.len() {
950                    return Err(RuntimeError::new("index out of bounds"));
951                }
952                Ok(arr.remove(index))
953            }
954            _ => Err(RuntimeError::new("remove() requires array")),
955        }
956    });
957
958    define(interp, "clear", Some(1), |_, args| match &args[0] {
959        Value::Array(arr) => {
960            arr.borrow_mut().clear();
961            Ok(Value::Null)
962        }
963        _ => Err(RuntimeError::new("clear() requires array")),
964    });
965
966    // Searching
967    define(interp, "contains", Some(2), |_, args| match &args[0] {
968        Value::Array(arr) => Ok(Value::Bool(
969            arr.borrow().iter().any(|v| values_equal(v, &args[1])),
970        )),
971        Value::String(s) => match &args[1] {
972            Value::String(sub) => Ok(Value::Bool(s.contains(sub.as_str()))),
973            Value::Char(c) => Ok(Value::Bool(s.contains(*c))),
974            _ => Err(RuntimeError::new(
975                "string contains() requires string or char",
976            )),
977        },
978        _ => Err(RuntimeError::new("contains() requires array or string")),
979    });
980
981    define(interp, "index_of", Some(2), |_, args| match &args[0] {
982        Value::Array(arr) => {
983            let idx = arr.borrow().iter().position(|v| values_equal(v, &args[1]));
984            match idx {
985                Some(i) => Ok(Value::Int(i as i64)),
986                None => Ok(Value::Int(-1)),
987            }
988        }
989        Value::String(s) => match &args[1] {
990            Value::String(sub) => match s.find(sub.as_str()) {
991                Some(i) => Ok(Value::Int(i as i64)),
992                None => Ok(Value::Int(-1)),
993            },
994            Value::Char(c) => match s.find(*c) {
995                Some(i) => Ok(Value::Int(i as i64)),
996                None => Ok(Value::Int(-1)),
997            },
998            _ => Err(RuntimeError::new(
999                "string index_of() requires string or char",
1000            )),
1001        },
1002        _ => Err(RuntimeError::new("index_of() requires array or string")),
1003    });
1004
1005    // Transformations
1006    define(interp, "reverse", Some(1), |_, args| match &args[0] {
1007        Value::Array(arr) => {
1008            let mut reversed: Vec<Value> = arr.borrow().clone();
1009            reversed.reverse();
1010            Ok(Value::Array(Rc::new(RefCell::new(reversed))))
1011        }
1012        Value::String(s) => {
1013            let reversed: String = s.chars().rev().collect();
1014            Ok(Value::String(Rc::new(reversed)))
1015        }
1016        _ => Err(RuntimeError::new("reverse() requires array or string")),
1017    });
1018
1019    define(interp, "sort", Some(1), |_, args| match &args[0] {
1020        Value::Array(arr) => {
1021            let mut sorted: Vec<Value> = arr.borrow().clone();
1022            sorted.sort_by(compare_values);
1023            Ok(Value::Array(Rc::new(RefCell::new(sorted))))
1024        }
1025        _ => Err(RuntimeError::new("sort() requires array")),
1026    });
1027
1028    define(interp, "sort_desc", Some(1), |_, args| match &args[0] {
1029        Value::Array(arr) => {
1030            let mut sorted: Vec<Value> = arr.borrow().clone();
1031            sorted.sort_by(|a, b| compare_values(b, a));
1032            Ok(Value::Array(Rc::new(RefCell::new(sorted))))
1033        }
1034        _ => Err(RuntimeError::new("sort_desc() requires array")),
1035    });
1036
1037    define(interp, "unique", Some(1), |_, args| match &args[0] {
1038        Value::Array(arr) => {
1039            let arr = arr.borrow();
1040            let mut seen = Vec::new();
1041            let unique: Vec<Value> = arr
1042                .iter()
1043                .filter(|v| {
1044                    if seen.iter().any(|s| values_equal(s, v)) {
1045                        false
1046                    } else {
1047                        seen.push((*v).clone());
1048                        true
1049                    }
1050                })
1051                .cloned()
1052                .collect();
1053            Ok(Value::Array(Rc::new(RefCell::new(unique))))
1054        }
1055        _ => Err(RuntimeError::new("unique() requires array")),
1056    });
1057
1058    define(interp, "flatten", Some(1), |_, args| match &args[0] {
1059        Value::Array(arr) => {
1060            let mut flattened = Vec::new();
1061            for item in arr.borrow().iter() {
1062                match item {
1063                    Value::Array(inner) => flattened.extend(inner.borrow().clone()),
1064                    other => flattened.push(other.clone()),
1065                }
1066            }
1067            Ok(Value::Array(Rc::new(RefCell::new(flattened))))
1068        }
1069        _ => Err(RuntimeError::new("flatten() requires array")),
1070    });
1071
1072    // Combining
1073    define(interp, "concat", Some(2), |_, args| {
1074        match (&args[0], &args[1]) {
1075            (Value::Array(a), Value::Array(b)) => {
1076                let mut result = a.borrow().clone();
1077                result.extend(b.borrow().clone());
1078                Ok(Value::Array(Rc::new(RefCell::new(result))))
1079            }
1080            (Value::String(a), Value::String(b)) => {
1081                Ok(Value::String(Rc::new(format!("{}{}", a, b))))
1082            }
1083            _ => Err(RuntimeError::new(
1084                "concat() requires two arrays or two strings",
1085            )),
1086        }
1087    });
1088
1089    define(interp, "zip", Some(2), |_, args| {
1090        match (&args[0], &args[1]) {
1091            (Value::Array(a), Value::Array(b)) => {
1092                let a = a.borrow();
1093                let b = b.borrow();
1094                let zipped: Vec<Value> = a
1095                    .iter()
1096                    .zip(b.iter())
1097                    .map(|(x, y)| Value::Tuple(Rc::new(vec![x.clone(), y.clone()])))
1098                    .collect();
1099                Ok(Value::Array(Rc::new(RefCell::new(zipped))))
1100            }
1101            _ => Err(RuntimeError::new("zip() requires two arrays")),
1102        }
1103    });
1104
1105    define(interp, "enumerate", Some(1), |_, args| match &args[0] {
1106        Value::Array(arr) => {
1107            let enumerated: Vec<Value> = arr
1108                .borrow()
1109                .iter()
1110                .enumerate()
1111                .map(|(i, v)| Value::Tuple(Rc::new(vec![Value::Int(i as i64), v.clone()])))
1112                .collect();
1113            Ok(Value::Array(Rc::new(RefCell::new(enumerated))))
1114        }
1115        _ => Err(RuntimeError::new("enumerate() requires array")),
1116    });
1117
1118    // ⋈ (bowtie) - zip_with: combine two arrays with a function
1119    // Since closures are complex, provide a simple zip variant that takes a mode
1120    define(interp, "zip_with", Some(3), |_, args| {
1121        let mode = match &args[2] {
1122            Value::String(s) => s.as_str(),
1123            _ => return Err(RuntimeError::new("zip_with() mode must be string")),
1124        };
1125        match (&args[0], &args[1]) {
1126            (Value::Array(a), Value::Array(b)) => {
1127                let a = a.borrow();
1128                let b = b.borrow();
1129                let result: Result<Vec<Value>, RuntimeError> = a
1130                    .iter()
1131                    .zip(b.iter())
1132                    .map(|(x, y)| match (x, y, mode) {
1133                        (Value::Int(a), Value::Int(b), "add") => Ok(Value::Int(a + b)),
1134                        (Value::Int(a), Value::Int(b), "sub") => Ok(Value::Int(a - b)),
1135                        (Value::Int(a), Value::Int(b), "mul") => Ok(Value::Int(a * b)),
1136                        (Value::Float(a), Value::Float(b), "add") => Ok(Value::Float(a + b)),
1137                        (Value::Float(a), Value::Float(b), "sub") => Ok(Value::Float(a - b)),
1138                        (Value::Float(a), Value::Float(b), "mul") => Ok(Value::Float(a * b)),
1139                        (_, _, "pair") => Ok(Value::Tuple(Rc::new(vec![x.clone(), y.clone()]))),
1140                        _ => Err(RuntimeError::new("zip_with() incompatible types or mode")),
1141                    })
1142                    .collect();
1143                Ok(Value::Array(Rc::new(RefCell::new(result?))))
1144            }
1145            _ => Err(RuntimeError::new("zip_with() requires two arrays")),
1146        }
1147    });
1148
1149    // ⊔ (square cup) - lattice join / supremum (max of two values)
1150    define(interp, "supremum", Some(2), |_, args| {
1151        match (&args[0], &args[1]) {
1152            (Value::Int(a), Value::Int(b)) => Ok(Value::Int(*a.max(b))),
1153            (Value::Float(a), Value::Float(b)) => Ok(Value::Float(a.max(*b))),
1154            (Value::Array(a), Value::Array(b)) => {
1155                // Element-wise max
1156                let a = a.borrow();
1157                let b = b.borrow();
1158                let result: Result<Vec<Value>, RuntimeError> = a
1159                    .iter()
1160                    .zip(b.iter())
1161                    .map(|(x, y)| match (x, y) {
1162                        (Value::Int(a), Value::Int(b)) => Ok(Value::Int(*a.max(b))),
1163                        (Value::Float(a), Value::Float(b)) => Ok(Value::Float(a.max(*b))),
1164                        _ => Err(RuntimeError::new("supremum() requires numeric arrays")),
1165                    })
1166                    .collect();
1167                Ok(Value::Array(Rc::new(RefCell::new(result?))))
1168            }
1169            _ => Err(RuntimeError::new(
1170                "supremum() requires numeric values or arrays",
1171            )),
1172        }
1173    });
1174
1175    // ⊓ (square cap) - lattice meet / infimum (min of two values)
1176    define(interp, "infimum", Some(2), |_, args| {
1177        match (&args[0], &args[1]) {
1178            (Value::Int(a), Value::Int(b)) => Ok(Value::Int(*a.min(b))),
1179            (Value::Float(a), Value::Float(b)) => Ok(Value::Float(a.min(*b))),
1180            (Value::Array(a), Value::Array(b)) => {
1181                // Element-wise min
1182                let a = a.borrow();
1183                let b = b.borrow();
1184                let result: Result<Vec<Value>, RuntimeError> = a
1185                    .iter()
1186                    .zip(b.iter())
1187                    .map(|(x, y)| match (x, y) {
1188                        (Value::Int(a), Value::Int(b)) => Ok(Value::Int(*a.min(b))),
1189                        (Value::Float(a), Value::Float(b)) => Ok(Value::Float(a.min(*b))),
1190                        _ => Err(RuntimeError::new("infimum() requires numeric arrays")),
1191                    })
1192                    .collect();
1193                Ok(Value::Array(Rc::new(RefCell::new(result?))))
1194            }
1195            _ => Err(RuntimeError::new(
1196                "infimum() requires numeric values or arrays",
1197            )),
1198        }
1199    });
1200
1201    // Slicing
1202    define(interp, "slice", Some(3), |_, args| {
1203        let start = match &args[1] {
1204            Value::Int(i) => *i as usize,
1205            _ => return Err(RuntimeError::new("slice() start must be integer")),
1206        };
1207        let end = match &args[2] {
1208            Value::Int(i) => *i as usize,
1209            _ => return Err(RuntimeError::new("slice() end must be integer")),
1210        };
1211        match &args[0] {
1212            Value::Array(arr) => {
1213                let arr = arr.borrow();
1214                let end = end.min(arr.len());
1215                let sliced: Vec<Value> = arr[start..end].to_vec();
1216                Ok(Value::Array(Rc::new(RefCell::new(sliced))))
1217            }
1218            Value::String(s) => {
1219                let chars: Vec<char> = s.chars().collect();
1220                let end = end.min(chars.len());
1221                let sliced: String = chars[start..end].iter().collect();
1222                Ok(Value::String(Rc::new(sliced)))
1223            }
1224            _ => Err(RuntimeError::new("slice() requires array or string")),
1225        }
1226    });
1227
1228    define(interp, "take", Some(2), |_, args| {
1229        let n = match &args[1] {
1230            Value::Int(i) => *i as usize,
1231            _ => return Err(RuntimeError::new("take() n must be integer")),
1232        };
1233        match &args[0] {
1234            Value::Array(arr) => {
1235                let taken: Vec<Value> = arr.borrow().iter().take(n).cloned().collect();
1236                Ok(Value::Array(Rc::new(RefCell::new(taken))))
1237            }
1238            _ => Err(RuntimeError::new("take() requires array")),
1239        }
1240    });
1241
1242    define(interp, "skip", Some(2), |_, args| {
1243        let n = match &args[1] {
1244            Value::Int(i) => *i as usize,
1245            _ => return Err(RuntimeError::new("skip() n must be integer")),
1246        };
1247        match &args[0] {
1248            Value::Array(arr) => {
1249                let skipped: Vec<Value> = arr.borrow().iter().skip(n).cloned().collect();
1250                Ok(Value::Array(Rc::new(RefCell::new(skipped))))
1251            }
1252            _ => Err(RuntimeError::new("skip() requires array")),
1253        }
1254    });
1255
1256    define(interp, "chunk", Some(2), |_, args| {
1257        let size = match &args[1] {
1258            Value::Int(i) if *i > 0 => *i as usize,
1259            _ => return Err(RuntimeError::new("chunk() size must be positive integer")),
1260        };
1261        match &args[0] {
1262            Value::Array(arr) => {
1263                let chunks: Vec<Value> = arr
1264                    .borrow()
1265                    .chunks(size)
1266                    .map(|c| Value::Array(Rc::new(RefCell::new(c.to_vec()))))
1267                    .collect();
1268                Ok(Value::Array(Rc::new(RefCell::new(chunks))))
1269            }
1270            _ => Err(RuntimeError::new("chunk() requires array")),
1271        }
1272    });
1273
1274    // Range
1275    define(interp, "range", Some(2), |_, args| {
1276        let start = match &args[0] {
1277            Value::Int(n) => *n,
1278            _ => return Err(RuntimeError::new("range() requires integers")),
1279        };
1280        let end = match &args[1] {
1281            Value::Int(n) => *n,
1282            _ => return Err(RuntimeError::new("range() requires integers")),
1283        };
1284        let values: Vec<Value> = (start..end).map(Value::Int).collect();
1285        Ok(Value::Array(Rc::new(RefCell::new(values))))
1286    });
1287
1288    define(interp, "range_inclusive", Some(2), |_, args| {
1289        let start = match &args[0] {
1290            Value::Int(n) => *n,
1291            _ => return Err(RuntimeError::new("range_inclusive() requires integers")),
1292        };
1293        let end = match &args[1] {
1294            Value::Int(n) => *n,
1295            _ => return Err(RuntimeError::new("range_inclusive() requires integers")),
1296        };
1297        let values: Vec<Value> = (start..=end).map(Value::Int).collect();
1298        Ok(Value::Array(Rc::new(RefCell::new(values))))
1299    });
1300
1301    define(interp, "repeat", Some(2), |_, args| {
1302        let n = match &args[1] {
1303            Value::Int(i) if *i >= 0 => *i as usize,
1304            _ => {
1305                return Err(RuntimeError::new(
1306                    "repeat() count must be non-negative integer",
1307                ))
1308            }
1309        };
1310        let repeated: Vec<Value> = std::iter::repeat(args[0].clone()).take(n).collect();
1311        Ok(Value::Array(Rc::new(RefCell::new(repeated))))
1312    });
1313
1314    // ========================================
1315    // HashMap operations
1316    // ========================================
1317
1318    // map_new - create empty HashMap
1319    define(interp, "map_new", Some(0), |_, _| {
1320        Ok(Value::Map(Rc::new(RefCell::new(HashMap::new()))))
1321    });
1322
1323    // map_get - get value by key
1324    define(interp, "map_get", Some(2), |_, args| {
1325        let key = match &args[1] {
1326            Value::String(s) => s.to_string(),
1327            _ => return Err(RuntimeError::new("map_get() key must be string")),
1328        };
1329        match &args[0] {
1330            Value::Map(map) => Ok(map.borrow().get(&key).cloned().unwrap_or(Value::Null)),
1331            _ => Err(RuntimeError::new("map_get() requires map")),
1332        }
1333    });
1334
1335    // map_set - set key-value pair
1336    define(interp, "map_set", Some(3), |_, args| {
1337        let key = match &args[1] {
1338            Value::String(s) => s.to_string(),
1339            _ => return Err(RuntimeError::new("map_set() key must be string")),
1340        };
1341        match &args[0] {
1342            Value::Map(map) => {
1343                map.borrow_mut().insert(key, args[2].clone());
1344                Ok(Value::Null)
1345            }
1346            _ => Err(RuntimeError::new("map_set() requires map")),
1347        }
1348    });
1349
1350    // map_has - check if key exists
1351    define(interp, "map_has", Some(2), |_, args| {
1352        let key = match &args[1] {
1353            Value::String(s) => s.to_string(),
1354            _ => return Err(RuntimeError::new("map_has() key must be string")),
1355        };
1356        match &args[0] {
1357            Value::Map(map) => Ok(Value::Bool(map.borrow().contains_key(&key))),
1358            _ => Err(RuntimeError::new("map_has() requires map")),
1359        }
1360    });
1361
1362    // map_remove - remove key from map
1363    define(interp, "map_remove", Some(2), |_, args| {
1364        let key = match &args[1] {
1365            Value::String(s) => s.to_string(),
1366            _ => return Err(RuntimeError::new("map_remove() key must be string")),
1367        };
1368        match &args[0] {
1369            Value::Map(map) => Ok(map.borrow_mut().remove(&key).unwrap_or(Value::Null)),
1370            _ => Err(RuntimeError::new("map_remove() requires map")),
1371        }
1372    });
1373
1374    // map_keys - get all keys as array
1375    define(interp, "map_keys", Some(1), |_, args| match &args[0] {
1376        Value::Map(map) => {
1377            let keys: Vec<Value> = map
1378                .borrow()
1379                .keys()
1380                .map(|k| Value::String(Rc::new(k.clone())))
1381                .collect();
1382            Ok(Value::Array(Rc::new(RefCell::new(keys))))
1383        }
1384        _ => Err(RuntimeError::new("map_keys() requires map")),
1385    });
1386
1387    // map_values - get all values as array
1388    define(interp, "map_values", Some(1), |_, args| match &args[0] {
1389        Value::Map(map) => {
1390            let values: Vec<Value> = map.borrow().values().cloned().collect();
1391            Ok(Value::Array(Rc::new(RefCell::new(values))))
1392        }
1393        _ => Err(RuntimeError::new("map_values() requires map")),
1394    });
1395
1396    // map_len - get number of entries
1397    define(interp, "map_len", Some(1), |_, args| match &args[0] {
1398        Value::Map(map) => Ok(Value::Int(map.borrow().len() as i64)),
1399        _ => Err(RuntimeError::new("map_len() requires map")),
1400    });
1401
1402    // map_clear - remove all entries
1403    define(interp, "map_clear", Some(1), |_, args| match &args[0] {
1404        Value::Map(map) => {
1405            map.borrow_mut().clear();
1406            Ok(Value::Null)
1407        }
1408        _ => Err(RuntimeError::new("map_clear() requires map")),
1409    });
1410
1411    // ========================================
1412    // HashSet operations
1413    // ========================================
1414
1415    // set_new - create empty HashSet
1416    define(interp, "set_new", Some(0), |_, _| {
1417        Ok(Value::Set(Rc::new(RefCell::new(
1418            std::collections::HashSet::new(),
1419        ))))
1420    });
1421
1422    // set_add - add item to set
1423    define(interp, "set_add", Some(2), |_, args| {
1424        let item = match &args[1] {
1425            Value::String(s) => s.to_string(),
1426            _ => return Err(RuntimeError::new("set_add() item must be string")),
1427        };
1428        match &args[0] {
1429            Value::Set(set) => {
1430                set.borrow_mut().insert(item);
1431                Ok(Value::Null)
1432            }
1433            _ => Err(RuntimeError::new("set_add() requires set")),
1434        }
1435    });
1436
1437    // set_has - check if item exists
1438    define(interp, "set_has", Some(2), |_, args| {
1439        let item = match &args[1] {
1440            Value::String(s) => s.to_string(),
1441            _ => return Err(RuntimeError::new("set_has() item must be string")),
1442        };
1443        match &args[0] {
1444            Value::Set(set) => Ok(Value::Bool(set.borrow().contains(&item))),
1445            _ => Err(RuntimeError::new("set_has() requires set")),
1446        }
1447    });
1448
1449    // set_remove - remove item from set
1450    define(interp, "set_remove", Some(2), |_, args| {
1451        let item = match &args[1] {
1452            Value::String(s) => s.to_string(),
1453            _ => return Err(RuntimeError::new("set_remove() item must be string")),
1454        };
1455        match &args[0] {
1456            Value::Set(set) => Ok(Value::Bool(set.borrow_mut().remove(&item))),
1457            _ => Err(RuntimeError::new("set_remove() requires set")),
1458        }
1459    });
1460
1461    // set_to_array - convert set to array
1462    define(interp, "set_to_array", Some(1), |_, args| match &args[0] {
1463        Value::Set(set) => {
1464            let items: Vec<Value> = set
1465                .borrow()
1466                .iter()
1467                .map(|s| Value::String(Rc::new(s.clone())))
1468                .collect();
1469            Ok(Value::Array(Rc::new(RefCell::new(items))))
1470        }
1471        _ => Err(RuntimeError::new("set_to_array() requires set")),
1472    });
1473
1474    // set_len - get number of items
1475    define(interp, "set_len", Some(1), |_, args| match &args[0] {
1476        Value::Set(set) => Ok(Value::Int(set.borrow().len() as i64)),
1477        _ => Err(RuntimeError::new("set_len() requires set")),
1478    });
1479
1480    // set_clear - remove all items
1481    define(interp, "set_clear", Some(1), |_, args| match &args[0] {
1482        Value::Set(set) => {
1483            set.borrow_mut().clear();
1484            Ok(Value::Null)
1485        }
1486        _ => Err(RuntimeError::new("set_clear() requires set")),
1487    });
1488}
1489
1490fn values_equal(a: &Value, b: &Value) -> bool {
1491    match (a, b) {
1492        (Value::Null, Value::Null) => true,
1493        (Value::Bool(a), Value::Bool(b)) => a == b,
1494        (Value::Int(a), Value::Int(b)) => a == b,
1495        (Value::Float(a), Value::Float(b)) => (a - b).abs() < f64::EPSILON,
1496        (Value::String(a), Value::String(b)) => a == b,
1497        (Value::Char(a), Value::Char(b)) => a == b,
1498        (Value::Array(a), Value::Array(b)) => {
1499            let a = a.borrow();
1500            let b = b.borrow();
1501            a.len() == b.len() && a.iter().zip(b.iter()).all(|(x, y)| values_equal(x, y))
1502        }
1503        (Value::Tuple(a), Value::Tuple(b)) => {
1504            a.len() == b.len() && a.iter().zip(b.iter()).all(|(x, y)| values_equal(x, y))
1505        }
1506        _ => false,
1507    }
1508}
1509
1510fn compare_values(a: &Value, b: &Value) -> std::cmp::Ordering {
1511    match (a, b) {
1512        (Value::Int(a), Value::Int(b)) => a.cmp(b),
1513        (Value::Float(a), Value::Float(b)) => a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal),
1514        (Value::String(a), Value::String(b)) => a.cmp(b),
1515        (Value::Char(a), Value::Char(b)) => a.cmp(b),
1516        _ => std::cmp::Ordering::Equal,
1517    }
1518}
1519
1520// ============================================================================
1521// STRING FUNCTIONS
1522// ============================================================================
1523
1524fn register_string(interp: &mut Interpreter) {
1525    define(interp, "chars", Some(1), |_, args| match &args[0] {
1526        Value::String(s) => {
1527            let chars: Vec<Value> = s.chars().map(Value::Char).collect();
1528            Ok(Value::Array(Rc::new(RefCell::new(chars))))
1529        }
1530        _ => Err(RuntimeError::new("chars() requires string")),
1531    });
1532
1533    define(interp, "bytes", Some(1), |_, args| match &args[0] {
1534        Value::String(s) => {
1535            let bytes: Vec<Value> = s.bytes().map(|b| Value::Int(b as i64)).collect();
1536            Ok(Value::Array(Rc::new(RefCell::new(bytes))))
1537        }
1538        _ => Err(RuntimeError::new("bytes() requires string")),
1539    });
1540
1541    define(interp, "split", Some(2), |_, args| {
1542        match (&args[0], &args[1]) {
1543            (Value::String(s), Value::String(sep)) => {
1544                let parts: Vec<Value> = s
1545                    .split(sep.as_str())
1546                    .map(|p| Value::String(Rc::new(p.to_string())))
1547                    .collect();
1548                Ok(Value::Array(Rc::new(RefCell::new(parts))))
1549            }
1550            (Value::String(s), Value::Char(sep)) => {
1551                let parts: Vec<Value> = s
1552                    .split(*sep)
1553                    .map(|p| Value::String(Rc::new(p.to_string())))
1554                    .collect();
1555                Ok(Value::Array(Rc::new(RefCell::new(parts))))
1556            }
1557            _ => Err(RuntimeError::new("split() requires string and separator")),
1558        }
1559    });
1560
1561    define(interp, "join", Some(2), |_, args| {
1562        match (&args[0], &args[1]) {
1563            (Value::Array(arr), Value::String(sep)) => {
1564                let parts: Vec<String> = arr.borrow().iter().map(|v| format!("{}", v)).collect();
1565                Ok(Value::String(Rc::new(parts.join(sep.as_str()))))
1566            }
1567            _ => Err(RuntimeError::new(
1568                "join() requires array and separator string",
1569            )),
1570        }
1571    });
1572
1573    define(interp, "trim", Some(1), |_, args| match &args[0] {
1574        Value::String(s) => Ok(Value::String(Rc::new(s.trim().to_string()))),
1575        _ => Err(RuntimeError::new("trim() requires string")),
1576    });
1577
1578    define(interp, "trim_start", Some(1), |_, args| match &args[0] {
1579        Value::String(s) => Ok(Value::String(Rc::new(s.trim_start().to_string()))),
1580        _ => Err(RuntimeError::new("trim_start() requires string")),
1581    });
1582
1583    define(interp, "trim_end", Some(1), |_, args| match &args[0] {
1584        Value::String(s) => Ok(Value::String(Rc::new(s.trim_end().to_string()))),
1585        _ => Err(RuntimeError::new("trim_end() requires string")),
1586    });
1587
1588    define(interp, "upper", Some(1), |_, args| match &args[0] {
1589        Value::String(s) => Ok(Value::String(Rc::new(s.to_uppercase()))),
1590        Value::Char(c) => Ok(Value::Char(c.to_uppercase().next().unwrap_or(*c))),
1591        _ => Err(RuntimeError::new("upper() requires string or char")),
1592    });
1593
1594    define(interp, "lower", Some(1), |_, args| match &args[0] {
1595        Value::String(s) => Ok(Value::String(Rc::new(s.to_lowercase()))),
1596        Value::Char(c) => Ok(Value::Char(c.to_lowercase().next().unwrap_or(*c))),
1597        _ => Err(RuntimeError::new("lower() requires string or char")),
1598    });
1599
1600    define(interp, "capitalize", Some(1), |_, args| match &args[0] {
1601        Value::String(s) => {
1602            let mut chars = s.chars();
1603            let capitalized = match chars.next() {
1604                None => String::new(),
1605                Some(c) => c.to_uppercase().chain(chars).collect(),
1606            };
1607            Ok(Value::String(Rc::new(capitalized)))
1608        }
1609        _ => Err(RuntimeError::new("capitalize() requires string")),
1610    });
1611
1612    define(interp, "replace", Some(3), |_, args| {
1613        match (&args[0], &args[1], &args[2]) {
1614            (Value::String(s), Value::String(from), Value::String(to)) => Ok(Value::String(
1615                Rc::new(s.replace(from.as_str(), to.as_str())),
1616            )),
1617            _ => Err(RuntimeError::new("replace() requires three strings")),
1618        }
1619    });
1620
1621    define(interp, "starts_with", Some(2), |_, args| {
1622        match (&args[0], &args[1]) {
1623            (Value::String(s), Value::String(prefix)) => {
1624                Ok(Value::Bool(s.starts_with(prefix.as_str())))
1625            }
1626            _ => Err(RuntimeError::new("starts_with() requires two strings")),
1627        }
1628    });
1629
1630    define(interp, "ends_with", Some(2), |_, args| {
1631        match (&args[0], &args[1]) {
1632            (Value::String(s), Value::String(suffix)) => {
1633                Ok(Value::Bool(s.ends_with(suffix.as_str())))
1634            }
1635            _ => Err(RuntimeError::new("ends_with() requires two strings")),
1636        }
1637    });
1638
1639    define(interp, "repeat_str", Some(2), |_, args| {
1640        match (&args[0], &args[1]) {
1641            (Value::String(s), Value::Int(n)) if *n >= 0 => {
1642                Ok(Value::String(Rc::new(s.repeat(*n as usize))))
1643            }
1644            _ => Err(RuntimeError::new(
1645                "repeat_str() requires string and non-negative integer",
1646            )),
1647        }
1648    });
1649
1650    define(interp, "pad_left", Some(3), |_, args| {
1651        match (&args[0], &args[1], &args[2]) {
1652            (Value::String(s), Value::Int(width), Value::Char(c)) => {
1653                let width = *width as usize;
1654                if s.len() >= width {
1655                    Ok(Value::String(s.clone()))
1656                } else {
1657                    let padding: String = std::iter::repeat(*c).take(width - s.len()).collect();
1658                    Ok(Value::String(Rc::new(format!("{}{}", padding, s))))
1659                }
1660            }
1661            _ => Err(RuntimeError::new(
1662                "pad_left() requires string, width, and char",
1663            )),
1664        }
1665    });
1666
1667    define(interp, "pad_right", Some(3), |_, args| {
1668        match (&args[0], &args[1], &args[2]) {
1669            (Value::String(s), Value::Int(width), Value::Char(c)) => {
1670                let width = *width as usize;
1671                if s.len() >= width {
1672                    Ok(Value::String(s.clone()))
1673                } else {
1674                    let padding: String = std::iter::repeat(*c).take(width - s.len()).collect();
1675                    Ok(Value::String(Rc::new(format!("{}{}", s, padding))))
1676                }
1677            }
1678            _ => Err(RuntimeError::new(
1679                "pad_right() requires string, width, and char",
1680            )),
1681        }
1682    });
1683
1684    define(interp, "lines", Some(1), |_, args| match &args[0] {
1685        Value::String(s) => {
1686            let lines: Vec<Value> = s
1687                .lines()
1688                .map(|l| Value::String(Rc::new(l.to_string())))
1689                .collect();
1690            Ok(Value::Array(Rc::new(RefCell::new(lines))))
1691        }
1692        _ => Err(RuntimeError::new("lines() requires string")),
1693    });
1694
1695    define(interp, "words", Some(1), |_, args| match &args[0] {
1696        Value::String(s) => {
1697            let words: Vec<Value> = s
1698                .split_whitespace()
1699                .map(|w| Value::String(Rc::new(w.to_string())))
1700                .collect();
1701            Ok(Value::Array(Rc::new(RefCell::new(words))))
1702        }
1703        _ => Err(RuntimeError::new("words() requires string")),
1704    });
1705
1706    define(interp, "is_alpha", Some(1), |_, args| match &args[0] {
1707        Value::String(s) => Ok(Value::Bool(
1708            !s.is_empty() && s.chars().all(|c| c.is_alphabetic()),
1709        )),
1710        Value::Char(c) => Ok(Value::Bool(c.is_alphabetic())),
1711        _ => Err(RuntimeError::new("is_alpha() requires string or char")),
1712    });
1713
1714    define(interp, "is_digit", Some(1), |_, args| match &args[0] {
1715        Value::String(s) => Ok(Value::Bool(
1716            !s.is_empty() && s.chars().all(|c| c.is_ascii_digit()),
1717        )),
1718        Value::Char(c) => Ok(Value::Bool(c.is_ascii_digit())),
1719        _ => Err(RuntimeError::new("is_digit() requires string or char")),
1720    });
1721
1722    define(interp, "is_alnum", Some(1), |_, args| match &args[0] {
1723        Value::String(s) => Ok(Value::Bool(
1724            !s.is_empty() && s.chars().all(|c| c.is_alphanumeric()),
1725        )),
1726        Value::Char(c) => Ok(Value::Bool(c.is_alphanumeric())),
1727        _ => Err(RuntimeError::new("is_alnum() requires string or char")),
1728    });
1729
1730    define(interp, "is_space", Some(1), |_, args| match &args[0] {
1731        Value::String(s) => Ok(Value::Bool(
1732            !s.is_empty() && s.chars().all(|c| c.is_whitespace()),
1733        )),
1734        Value::Char(c) => Ok(Value::Bool(c.is_whitespace())),
1735        _ => Err(RuntimeError::new("is_space() requires string or char")),
1736    });
1737
1738    // =========================================================================
1739    // ADVANCED STRING FUNCTIONS
1740    // =========================================================================
1741
1742    // find - find first occurrence of substring, returns index or -1
1743    define(interp, "find", Some(2), |_, args| {
1744        match (&args[0], &args[1]) {
1745            (Value::String(s), Value::String(sub)) => {
1746                match s.find(sub.as_str()) {
1747                    Some(byte_idx) => {
1748                        // Convert byte index to character index
1749                        let char_idx = s[..byte_idx].chars().count() as i64;
1750                        Ok(Value::Int(char_idx))
1751                    }
1752                    None => Ok(Value::Int(-1)),
1753                }
1754            }
1755            (Value::String(s), Value::Char(c)) => match s.find(*c) {
1756                Some(byte_idx) => {
1757                    let char_idx = s[..byte_idx].chars().count() as i64;
1758                    Ok(Value::Int(char_idx))
1759                }
1760                None => Ok(Value::Int(-1)),
1761            },
1762            _ => Err(RuntimeError::new(
1763                "find() requires string and substring/char",
1764            )),
1765        }
1766    });
1767
1768    // index_of - find index of element in array or substring in string
1769    define(interp, "index_of", Some(2), |_, args| {
1770        match (&args[0], &args[1]) {
1771            (Value::String(s), Value::String(sub)) => match s.find(sub.as_str()) {
1772                Some(byte_idx) => {
1773                    let char_idx = s[..byte_idx].chars().count() as i64;
1774                    Ok(Value::Int(char_idx))
1775                }
1776                None => Ok(Value::Int(-1)),
1777            },
1778            (Value::String(s), Value::Char(c)) => match s.find(*c) {
1779                Some(byte_idx) => {
1780                    let char_idx = s[..byte_idx].chars().count() as i64;
1781                    Ok(Value::Int(char_idx))
1782                }
1783                None => Ok(Value::Int(-1)),
1784            },
1785            (Value::Array(arr), search) => {
1786                // Array index_of - use Value comparison
1787                for (i, v) in arr.borrow().iter().enumerate() {
1788                    if values_equal_simple(v, search) {
1789                        return Ok(Value::Int(i as i64));
1790                    }
1791                }
1792                Ok(Value::Int(-1))
1793            }
1794            _ => Err(RuntimeError::new(
1795                "index_of() requires array/string and element/substring",
1796            )),
1797        }
1798    });
1799
1800    // last_index_of - find last occurrence of substring
1801    define(interp, "last_index_of", Some(2), |_, args| {
1802        match (&args[0], &args[1]) {
1803            (Value::String(s), Value::String(sub)) => match s.rfind(sub.as_str()) {
1804                Some(byte_idx) => {
1805                    let char_idx = s[..byte_idx].chars().count() as i64;
1806                    Ok(Value::Int(char_idx))
1807                }
1808                None => Ok(Value::Int(-1)),
1809            },
1810            (Value::String(s), Value::Char(c)) => match s.rfind(*c) {
1811                Some(byte_idx) => {
1812                    let char_idx = s[..byte_idx].chars().count() as i64;
1813                    Ok(Value::Int(char_idx))
1814                }
1815                None => Ok(Value::Int(-1)),
1816            },
1817            _ => Err(RuntimeError::new(
1818                "last_index_of() requires string and substring/char",
1819            )),
1820        }
1821    });
1822
1823    // substring - extract substring by character indices
1824    define(interp, "substring", Some(3), |_, args| {
1825        let s = match &args[0] {
1826            Value::String(s) => (**s).clone(),
1827            _ => {
1828                return Err(RuntimeError::new(
1829                    "substring: first argument must be a string",
1830                ))
1831            }
1832        };
1833        let start = match &args[1] {
1834            Value::Int(n) if *n >= 0 => *n as usize,
1835            _ => {
1836                return Err(RuntimeError::new(
1837                    "substring: start must be a non-negative integer",
1838                ))
1839            }
1840        };
1841        let end = match &args[2] {
1842            Value::Int(n) if *n >= 0 => *n as usize,
1843            _ => {
1844                return Err(RuntimeError::new(
1845                    "substring: end must be a non-negative integer",
1846                ))
1847            }
1848        };
1849        let chars: Vec<char> = s.chars().collect();
1850        let len = chars.len();
1851        let actual_start = start.min(len);
1852        let actual_end = end.min(len);
1853        if actual_start >= actual_end {
1854            return Ok(Value::String(Rc::new(String::new())));
1855        }
1856        let result: String = chars[actual_start..actual_end].iter().collect();
1857        Ok(Value::String(Rc::new(result)))
1858    });
1859
1860    // count - count occurrences of substring
1861    define(interp, "count", Some(2), |_, args| {
1862        match (&args[0], &args[1]) {
1863            (Value::String(s), Value::String(sub)) => {
1864                if sub.is_empty() {
1865                    return Err(RuntimeError::new("count: cannot count empty string"));
1866                }
1867                let count = s.matches(sub.as_str()).count() as i64;
1868                Ok(Value::Int(count))
1869            }
1870            (Value::String(s), Value::Char(c)) => {
1871                let count = s.chars().filter(|&ch| ch == *c).count() as i64;
1872                Ok(Value::Int(count))
1873            }
1874            _ => Err(RuntimeError::new(
1875                "count() requires string and substring/char",
1876            )),
1877        }
1878    });
1879
1880    // char_at - get character at index (safer than indexing)
1881    define(interp, "char_at", Some(2), |_, args| {
1882        let s = match &args[0] {
1883            Value::String(s) => (**s).clone(),
1884            _ => {
1885                return Err(RuntimeError::new(
1886                    "char_at: first argument must be a string",
1887                ))
1888            }
1889        };
1890        let idx = match &args[1] {
1891            Value::Int(n) => *n,
1892            _ => {
1893                return Err(RuntimeError::new(
1894                    "char_at: second argument must be an integer",
1895                ))
1896            }
1897        };
1898        let chars: Vec<char> = s.chars().collect();
1899        let actual_idx = if idx < 0 {
1900            (chars.len() as i64 + idx) as usize
1901        } else {
1902            idx as usize
1903        };
1904        match chars.get(actual_idx) {
1905            Some(c) => Ok(Value::Char(*c)),
1906            None => Ok(Value::Null),
1907        }
1908    });
1909
1910    // char_code_at - get Unicode code point at index
1911    define(interp, "char_code_at", Some(2), |_, args| {
1912        let s = match &args[0] {
1913            Value::String(s) => (**s).clone(),
1914            _ => {
1915                return Err(RuntimeError::new(
1916                    "char_code_at: first argument must be a string",
1917                ))
1918            }
1919        };
1920        let idx = match &args[1] {
1921            Value::Int(n) => *n,
1922            _ => {
1923                return Err(RuntimeError::new(
1924                    "char_code_at: second argument must be an integer",
1925                ))
1926            }
1927        };
1928        let chars: Vec<char> = s.chars().collect();
1929        let actual_idx = if idx < 0 {
1930            (chars.len() as i64 + idx) as usize
1931        } else {
1932            idx as usize
1933        };
1934        match chars.get(actual_idx) {
1935            Some(c) => Ok(Value::Int(*c as i64)),
1936            None => Ok(Value::Null),
1937        }
1938    });
1939
1940    // from_char_code - create string from Unicode code point
1941    define(interp, "from_char_code", Some(1), |_, args| {
1942        let code = match &args[0] {
1943            Value::Int(n) => *n as u32,
1944            _ => {
1945                return Err(RuntimeError::new(
1946                    "from_char_code: argument must be an integer",
1947                ))
1948            }
1949        };
1950        match char::from_u32(code) {
1951            Some(c) => Ok(Value::String(Rc::new(c.to_string()))),
1952            None => Err(RuntimeError::new(
1953                "from_char_code: invalid Unicode code point",
1954            )),
1955        }
1956    });
1957
1958    // insert - insert string at index
1959    define(interp, "insert", Some(3), |_, args| {
1960        let s = match &args[0] {
1961            Value::String(s) => (**s).clone(),
1962            _ => return Err(RuntimeError::new("insert: first argument must be a string")),
1963        };
1964        let idx = match &args[1] {
1965            Value::Int(n) if *n >= 0 => *n as usize,
1966            _ => {
1967                return Err(RuntimeError::new(
1968                    "insert: index must be a non-negative integer",
1969                ))
1970            }
1971        };
1972        let insertion = match &args[2] {
1973            Value::String(s) => (**s).clone(),
1974            _ => return Err(RuntimeError::new("insert: third argument must be a string")),
1975        };
1976        let chars: Vec<char> = s.chars().collect();
1977        let actual_idx = idx.min(chars.len());
1978        let mut result: String = chars[..actual_idx].iter().collect();
1979        result.push_str(&insertion);
1980        result.extend(chars[actual_idx..].iter());
1981        Ok(Value::String(Rc::new(result)))
1982    });
1983
1984    // remove - remove range from string
1985    define(interp, "remove", Some(3), |_, args| {
1986        let s = match &args[0] {
1987            Value::String(s) => (**s).clone(),
1988            _ => return Err(RuntimeError::new("remove: first argument must be a string")),
1989        };
1990        let start = match &args[1] {
1991            Value::Int(n) if *n >= 0 => *n as usize,
1992            _ => {
1993                return Err(RuntimeError::new(
1994                    "remove: start must be a non-negative integer",
1995                ))
1996            }
1997        };
1998        let len = match &args[2] {
1999            Value::Int(n) if *n >= 0 => *n as usize,
2000            _ => {
2001                return Err(RuntimeError::new(
2002                    "remove: length must be a non-negative integer",
2003                ))
2004            }
2005        };
2006        let chars: Vec<char> = s.chars().collect();
2007        let str_len = chars.len();
2008        let actual_start = start.min(str_len);
2009        let actual_end = (start + len).min(str_len);
2010        let mut result: String = chars[..actual_start].iter().collect();
2011        result.extend(chars[actual_end..].iter());
2012        Ok(Value::String(Rc::new(result)))
2013    });
2014
2015    // compare - compare two strings, returns -1, 0, or 1
2016    define(interp, "compare", Some(2), |_, args| {
2017        match (&args[0], &args[1]) {
2018            (Value::String(a), Value::String(b)) => {
2019                let result = match a.cmp(b) {
2020                    std::cmp::Ordering::Less => -1,
2021                    std::cmp::Ordering::Equal => 0,
2022                    std::cmp::Ordering::Greater => 1,
2023                };
2024                Ok(Value::Int(result))
2025            }
2026            _ => Err(RuntimeError::new("compare() requires two strings")),
2027        }
2028    });
2029
2030    // compare_ignore_case - case-insensitive comparison
2031    define(interp, "compare_ignore_case", Some(2), |_, args| {
2032        match (&args[0], &args[1]) {
2033            (Value::String(a), Value::String(b)) => {
2034                let result = match a.to_lowercase().cmp(&b.to_lowercase()) {
2035                    std::cmp::Ordering::Less => -1,
2036                    std::cmp::Ordering::Equal => 0,
2037                    std::cmp::Ordering::Greater => 1,
2038                };
2039                Ok(Value::Int(result))
2040            }
2041            _ => Err(RuntimeError::new(
2042                "compare_ignore_case() requires two strings",
2043            )),
2044        }
2045    });
2046
2047    // char_count - get character count (not byte length)
2048    define(interp, "char_count", Some(1), |_, args| match &args[0] {
2049        Value::String(s) => Ok(Value::Int(s.chars().count() as i64)),
2050        _ => Err(RuntimeError::new("char_count() requires string")),
2051    });
2052
2053    // byte_count - get byte length (for UTF-8 awareness)
2054    define(interp, "byte_count", Some(1), |_, args| match &args[0] {
2055        Value::String(s) => Ok(Value::Int(s.len() as i64)),
2056        _ => Err(RuntimeError::new("byte_count() requires string")),
2057    });
2058
2059    // is_empty - check if string is empty
2060    define(interp, "is_empty", Some(1), |_, args| match &args[0] {
2061        Value::String(s) => Ok(Value::Bool(s.is_empty())),
2062        Value::Array(arr) => Ok(Value::Bool(arr.borrow().is_empty())),
2063        _ => Err(RuntimeError::new("is_empty() requires string or array")),
2064    });
2065
2066    // is_blank - check if string is empty or only whitespace
2067    define(interp, "is_blank", Some(1), |_, args| match &args[0] {
2068        Value::String(s) => Ok(Value::Bool(s.trim().is_empty())),
2069        _ => Err(RuntimeError::new("is_blank() requires string")),
2070    });
2071
2072    // =========================================================================
2073    // UNICODE NORMALIZATION FUNCTIONS
2074    // =========================================================================
2075
2076    // nfc - Unicode Normalization Form C (Canonical Decomposition, followed by Canonical Composition)
2077    define(interp, "nfc", Some(1), |_, args| match &args[0] {
2078        Value::String(s) => Ok(Value::String(Rc::new(s.nfc().collect()))),
2079        _ => Err(RuntimeError::new("nfc() requires string")),
2080    });
2081
2082    // nfd - Unicode Normalization Form D (Canonical Decomposition)
2083    define(interp, "nfd", Some(1), |_, args| match &args[0] {
2084        Value::String(s) => Ok(Value::String(Rc::new(s.nfd().collect()))),
2085        _ => Err(RuntimeError::new("nfd() requires string")),
2086    });
2087
2088    // nfkc - Unicode Normalization Form KC (Compatibility Decomposition, followed by Canonical Composition)
2089    define(interp, "nfkc", Some(1), |_, args| match &args[0] {
2090        Value::String(s) => Ok(Value::String(Rc::new(s.nfkc().collect()))),
2091        _ => Err(RuntimeError::new("nfkc() requires string")),
2092    });
2093
2094    // nfkd - Unicode Normalization Form KD (Compatibility Decomposition)
2095    define(interp, "nfkd", Some(1), |_, args| match &args[0] {
2096        Value::String(s) => Ok(Value::String(Rc::new(s.nfkd().collect()))),
2097        _ => Err(RuntimeError::new("nfkd() requires string")),
2098    });
2099
2100    // is_nfc - check if string is in NFC form
2101    define(interp, "is_nfc", Some(1), |_, args| match &args[0] {
2102        Value::String(s) => {
2103            let normalized: String = s.nfc().collect();
2104            Ok(Value::Bool(*s.as_ref() == normalized))
2105        }
2106        _ => Err(RuntimeError::new("is_nfc() requires string")),
2107    });
2108
2109    // is_nfd - check if string is in NFD form
2110    define(interp, "is_nfd", Some(1), |_, args| match &args[0] {
2111        Value::String(s) => {
2112            let normalized: String = s.nfd().collect();
2113            Ok(Value::Bool(*s.as_ref() == normalized))
2114        }
2115        _ => Err(RuntimeError::new("is_nfd() requires string")),
2116    });
2117
2118    // =========================================================================
2119    // GRAPHEME CLUSTER FUNCTIONS
2120    // =========================================================================
2121
2122    // graphemes - split string into grapheme clusters (user-perceived characters)
2123    define(interp, "graphemes", Some(1), |_, args| match &args[0] {
2124        Value::String(s) => {
2125            let graphemes: Vec<Value> = s
2126                .graphemes(true)
2127                .map(|g| Value::String(Rc::new(g.to_string())))
2128                .collect();
2129            Ok(Value::Array(Rc::new(RefCell::new(graphemes))))
2130        }
2131        _ => Err(RuntimeError::new("graphemes() requires string")),
2132    });
2133
2134    // grapheme_count - count grapheme clusters (correct for emoji, combining chars, etc.)
2135    define(interp, "grapheme_count", Some(1), |_, args| {
2136        match &args[0] {
2137            Value::String(s) => Ok(Value::Int(s.graphemes(true).count() as i64)),
2138            _ => Err(RuntimeError::new("grapheme_count() requires string")),
2139        }
2140    });
2141
2142    // grapheme_at - get grapheme cluster at index
2143    define(interp, "grapheme_at", Some(2), |_, args| {
2144        let s = match &args[0] {
2145            Value::String(s) => (**s).clone(),
2146            _ => {
2147                return Err(RuntimeError::new(
2148                    "grapheme_at: first argument must be a string",
2149                ))
2150            }
2151        };
2152        let idx = match &args[1] {
2153            Value::Int(n) => *n,
2154            _ => {
2155                return Err(RuntimeError::new(
2156                    "grapheme_at: second argument must be an integer",
2157                ))
2158            }
2159        };
2160        let graphemes: Vec<&str> = s.graphemes(true).collect();
2161        let actual_idx = if idx < 0 {
2162            (graphemes.len() as i64 + idx) as usize
2163        } else {
2164            idx as usize
2165        };
2166        match graphemes.get(actual_idx) {
2167            Some(g) => Ok(Value::String(Rc::new(g.to_string()))),
2168            None => Ok(Value::Null),
2169        }
2170    });
2171
2172    // grapheme_slice - slice string by grapheme indices (proper Unicode slicing)
2173    define(interp, "grapheme_slice", Some(3), |_, args| {
2174        let s = match &args[0] {
2175            Value::String(s) => (**s).clone(),
2176            _ => {
2177                return Err(RuntimeError::new(
2178                    "grapheme_slice: first argument must be a string",
2179                ))
2180            }
2181        };
2182        let start = match &args[1] {
2183            Value::Int(n) if *n >= 0 => *n as usize,
2184            _ => {
2185                return Err(RuntimeError::new(
2186                    "grapheme_slice: start must be a non-negative integer",
2187                ))
2188            }
2189        };
2190        let end = match &args[2] {
2191            Value::Int(n) if *n >= 0 => *n as usize,
2192            _ => {
2193                return Err(RuntimeError::new(
2194                    "grapheme_slice: end must be a non-negative integer",
2195                ))
2196            }
2197        };
2198        let graphemes: Vec<&str> = s.graphemes(true).collect();
2199        let len = graphemes.len();
2200        let actual_start = start.min(len);
2201        let actual_end = end.min(len);
2202        if actual_start >= actual_end {
2203            return Ok(Value::String(Rc::new(String::new())));
2204        }
2205        let result: String = graphemes[actual_start..actual_end].join("");
2206        Ok(Value::String(Rc::new(result)))
2207    });
2208
2209    // grapheme_reverse - reverse string by grapheme clusters (correct for emoji, etc.)
2210    define(interp, "grapheme_reverse", Some(1), |_, args| {
2211        match &args[0] {
2212            Value::String(s) => {
2213                let reversed: String = s.graphemes(true).rev().collect();
2214                Ok(Value::String(Rc::new(reversed)))
2215            }
2216            _ => Err(RuntimeError::new("grapheme_reverse() requires string")),
2217        }
2218    });
2219
2220    // word_indices - get word boundaries
2221    define(interp, "word_boundaries", Some(1), |_, args| {
2222        match &args[0] {
2223            Value::String(s) => {
2224                let words: Vec<Value> = s
2225                    .unicode_words()
2226                    .map(|w| Value::String(Rc::new(w.to_string())))
2227                    .collect();
2228                Ok(Value::Array(Rc::new(RefCell::new(words))))
2229            }
2230            _ => Err(RuntimeError::new("word_boundaries() requires string")),
2231        }
2232    });
2233
2234    // =========================================================================
2235    // STRING BUILDER
2236    // =========================================================================
2237
2238    // string_builder - create a new string builder (just returns empty string for now,
2239    // operations can be chained with concat)
2240    define(interp, "string_builder", Some(0), |_, _| {
2241        Ok(Value::String(Rc::new(String::new())))
2242    });
2243
2244    // concat_all - concatenate array of strings efficiently
2245    define(interp, "concat_all", Some(1), |_, args| match &args[0] {
2246        Value::Array(arr) => {
2247            let parts: Vec<String> = arr
2248                .borrow()
2249                .iter()
2250                .map(|v| match v {
2251                    Value::String(s) => (**s).clone(),
2252                    other => format!("{}", other),
2253                })
2254                .collect();
2255            Ok(Value::String(Rc::new(parts.join(""))))
2256        }
2257        _ => Err(RuntimeError::new("concat_all() requires array")),
2258    });
2259
2260    // repeat_join - repeat a string n times with a separator
2261    define(interp, "repeat_join", Some(3), |_, args| {
2262        let s = match &args[0] {
2263            Value::String(s) => (**s).clone(),
2264            _ => {
2265                return Err(RuntimeError::new(
2266                    "repeat_join: first argument must be a string",
2267                ))
2268            }
2269        };
2270        let n = match &args[1] {
2271            Value::Int(n) if *n >= 0 => *n as usize,
2272            _ => {
2273                return Err(RuntimeError::new(
2274                    "repeat_join: count must be a non-negative integer",
2275                ))
2276            }
2277        };
2278        let sep = match &args[2] {
2279            Value::String(s) => (**s).clone(),
2280            _ => return Err(RuntimeError::new("repeat_join: separator must be a string")),
2281        };
2282        if n == 0 {
2283            return Ok(Value::String(Rc::new(String::new())));
2284        }
2285        let parts: Vec<&str> = std::iter::repeat(s.as_str()).take(n).collect();
2286        Ok(Value::String(Rc::new(parts.join(&sep))))
2287    });
2288}
2289
2290// ============================================================================
2291// EVIDENCE FUNCTIONS
2292// ============================================================================
2293
2294fn register_evidence(interp: &mut Interpreter) {
2295    use crate::interpreter::RuntimeConfidence;
2296
2297    // Create evidential values
2298    define(interp, "known", Some(1), |_, args| {
2299        Ok(Value::Evidential {
2300            value: Box::new(args[0].clone()),
2301            evidence: Evidence::Known,
2302        })
2303    });
2304
2305    define(interp, "uncertain", Some(1), |_, args| {
2306        Ok(Value::Evidential {
2307            value: Box::new(args[0].clone()),
2308            evidence: Evidence::Uncertain,
2309        })
2310    });
2311
2312    define(interp, "reported", Some(1), |_, args| {
2313        Ok(Value::Evidential {
2314            value: Box::new(args[0].clone()),
2315            evidence: Evidence::Reported,
2316        })
2317    });
2318
2319    define(interp, "paradox", Some(1), |_, args| {
2320        Ok(Value::Evidential {
2321            value: Box::new(args[0].clone()),
2322            evidence: Evidence::Paradox,
2323        })
2324    });
2325
2326    // Query evidence
2327    define(interp, "evidence_of", Some(1), |_, args| {
2328        match &args[0] {
2329            Value::Evidential { evidence, .. } => {
2330                let level = match evidence {
2331                    Evidence::Known => "known",
2332                    Evidence::Uncertain => "uncertain",
2333                    Evidence::Reported => "reported",
2334                    Evidence::Paradox => "paradox",
2335                };
2336                Ok(Value::String(Rc::new(level.to_string())))
2337            }
2338            _ => Ok(Value::String(Rc::new("known".to_string()))), // Non-evidential values are known
2339        }
2340    });
2341
2342    define(interp, "is_known", Some(1), |_, args| {
2343        match &args[0] {
2344            Value::Evidential {
2345                evidence: Evidence::Known,
2346                ..
2347            } => Ok(Value::Bool(true)),
2348            Value::Evidential { .. } => Ok(Value::Bool(false)),
2349            _ => Ok(Value::Bool(true)), // Non-evidential values are known
2350        }
2351    });
2352
2353    define(interp, "is_uncertain", Some(1), |_, args| match &args[0] {
2354        Value::Evidential {
2355            evidence: Evidence::Uncertain,
2356            ..
2357        } => Ok(Value::Bool(true)),
2358        _ => Ok(Value::Bool(false)),
2359    });
2360
2361    define(interp, "is_reported", Some(1), |_, args| match &args[0] {
2362        Value::Evidential {
2363            evidence: Evidence::Reported,
2364            ..
2365        } => Ok(Value::Bool(true)),
2366        _ => Ok(Value::Bool(false)),
2367    });
2368
2369    define(interp, "is_paradox", Some(1), |_, args| match &args[0] {
2370        Value::Evidential {
2371            evidence: Evidence::Paradox,
2372            ..
2373        } => Ok(Value::Bool(true)),
2374        _ => Ok(Value::Bool(false)),
2375    });
2376
2377    // Extract inner value
2378    define(interp, "strip_evidence", Some(1), |_, args| {
2379        match &args[0] {
2380            Value::Evidential { value, .. } => Ok(*value.clone()),
2381            other => Ok(other.clone()),
2382        }
2383    });
2384
2385    // Trust operations
2386    define(interp, "trust", Some(1), |_, args| {
2387        // Upgrade reported/uncertain to known (with assertion)
2388        match &args[0] {
2389            Value::Evidential { value, .. } => Ok(Value::Evidential {
2390                value: value.clone(),
2391                evidence: Evidence::Known,
2392            }),
2393            other => Ok(other.clone()),
2394        }
2395    });
2396
2397    define(interp, "verify", Some(2), |_, args| {
2398        // Verify evidential value with predicate, upgrading if true
2399        let pred_result = match &args[1] {
2400            Value::Bool(b) => *b,
2401            _ => return Err(RuntimeError::new("verify() predicate must be bool")),
2402        };
2403
2404        if pred_result {
2405            match &args[0] {
2406                Value::Evidential { value, .. } => Ok(Value::Evidential {
2407                    value: value.clone(),
2408                    evidence: Evidence::Known,
2409                }),
2410                other => Ok(other.clone()),
2411            }
2412        } else {
2413            Ok(args[0].clone()) // Keep original evidence
2414        }
2415    });
2416
2417    // Combine evidence (join in lattice)
2418    define(interp, "combine_evidence", Some(2), |_, args| {
2419        let ev1 = match &args[0] {
2420            Value::Evidential { evidence, .. } => *evidence,
2421            _ => Evidence::Known,
2422        };
2423        let ev2 = match &args[1] {
2424            Value::Evidential { evidence, .. } => *evidence,
2425            _ => Evidence::Known,
2426        };
2427
2428        // Join: max of the two
2429        let combined = match (ev1, ev2) {
2430            (Evidence::Paradox, _) | (_, Evidence::Paradox) => Evidence::Paradox,
2431            (Evidence::Reported, _) | (_, Evidence::Reported) => Evidence::Reported,
2432            (Evidence::Uncertain, _) | (_, Evidence::Uncertain) => Evidence::Uncertain,
2433            _ => Evidence::Known,
2434        };
2435
2436        Ok(Value::String(Rc::new(
2437            match combined {
2438                Evidence::Known => "known",
2439                Evidence::Uncertain => "uncertain",
2440                Evidence::Reported => "reported",
2441                Evidence::Paradox => "paradox",
2442            }
2443            .to_string(),
2444        )))
2445    });
2446
2447    // === Affect-Evidence Integration ===
2448
2449    // Derive evidence from affect markers
2450    define(interp, "affect_to_evidence", Some(1), |_, args| {
2451        match &args[0] {
2452            Value::Affective { affect, .. } => {
2453                // Sarcasm implies uncertainty (meaning is inverted)
2454                if affect.sarcasm {
2455                    return Ok(Value::String(Rc::new("uncertain".to_string())));
2456                }
2457                // Confidence maps to evidence
2458                match affect.confidence {
2459                    Some(RuntimeConfidence::High) => {
2460                        Ok(Value::String(Rc::new("known".to_string())))
2461                    }
2462                    Some(RuntimeConfidence::Low) => {
2463                        Ok(Value::String(Rc::new("uncertain".to_string())))
2464                    }
2465                    _ => Ok(Value::String(Rc::new("known".to_string()))),
2466                }
2467            }
2468            _ => Ok(Value::String(Rc::new("known".to_string()))),
2469        }
2470    });
2471
2472    // Convert affective value to evidential based on affect markers
2473    define(
2474        interp,
2475        "affect_as_evidence",
2476        Some(1),
2477        |_, args| match &args[0] {
2478            Value::Affective { value, affect } => {
2479                let evidence = if affect.sarcasm {
2480                    Evidence::Uncertain
2481                } else {
2482                    match affect.confidence {
2483                        Some(RuntimeConfidence::High) => Evidence::Known,
2484                        Some(RuntimeConfidence::Low) => Evidence::Uncertain,
2485                        _ => Evidence::Known,
2486                    }
2487                };
2488                Ok(Value::Evidential {
2489                    value: value.clone(),
2490                    evidence,
2491                })
2492            }
2493            other => Ok(other.clone()),
2494        },
2495    );
2496
2497    // Check if affective value implies uncertainty
2498    define(
2499        interp,
2500        "is_affect_uncertain",
2501        Some(1),
2502        |_, args| match &args[0] {
2503            Value::Affective { affect, .. } => {
2504                let uncertain =
2505                    affect.sarcasm || matches!(affect.confidence, Some(RuntimeConfidence::Low));
2506                Ok(Value::Bool(uncertain))
2507            }
2508            _ => Ok(Value::Bool(false)),
2509        },
2510    );
2511
2512    // Combine affect and evidence (wrap evidential in affect or vice versa)
2513    define(interp, "with_affect_evidence", Some(2), |_, args| {
2514        // args[0] = affect source, args[1] = value to wrap
2515        match &args[0] {
2516            Value::Affective { affect, .. } => {
2517                let evidence = if affect.sarcasm {
2518                    Evidence::Uncertain
2519                } else {
2520                    match affect.confidence {
2521                        Some(RuntimeConfidence::High) => Evidence::Known,
2522                        Some(RuntimeConfidence::Low) => Evidence::Uncertain,
2523                        _ => Evidence::Known,
2524                    }
2525                };
2526                Ok(Value::Evidential {
2527                    value: Box::new(args[1].clone()),
2528                    evidence,
2529                })
2530            }
2531            Value::Evidential { evidence, .. } => {
2532                // Preserve evidence on the new value
2533                Ok(Value::Evidential {
2534                    value: Box::new(args[1].clone()),
2535                    evidence: *evidence,
2536                })
2537            }
2538            _ => Ok(args[1].clone()),
2539        }
2540    });
2541}
2542
2543// ============================================================================
2544// AFFECT FUNCTIONS (Sentiment, Emotion, Sarcasm markers)
2545// ============================================================================
2546
2547fn register_affect(interp: &mut Interpreter) {
2548    use crate::interpreter::{
2549        RuntimeAffect, RuntimeConfidence, RuntimeEmotion, RuntimeFormality, RuntimeIntensity,
2550        RuntimeSentiment,
2551    };
2552
2553    // === Create affective values ===
2554
2555    // Sentiment markers
2556    define(interp, "positive", Some(1), |_, args| {
2557        Ok(Value::Affective {
2558            value: Box::new(args[0].clone()),
2559            affect: RuntimeAffect {
2560                sentiment: Some(RuntimeSentiment::Positive),
2561                sarcasm: false,
2562                intensity: None,
2563                formality: None,
2564                emotion: None,
2565                confidence: None,
2566            },
2567        })
2568    });
2569
2570    define(interp, "negative", Some(1), |_, args| {
2571        Ok(Value::Affective {
2572            value: Box::new(args[0].clone()),
2573            affect: RuntimeAffect {
2574                sentiment: Some(RuntimeSentiment::Negative),
2575                sarcasm: false,
2576                intensity: None,
2577                formality: None,
2578                emotion: None,
2579                confidence: None,
2580            },
2581        })
2582    });
2583
2584    define(interp, "neutral", Some(1), |_, args| {
2585        Ok(Value::Affective {
2586            value: Box::new(args[0].clone()),
2587            affect: RuntimeAffect {
2588                sentiment: Some(RuntimeSentiment::Neutral),
2589                sarcasm: false,
2590                intensity: None,
2591                formality: None,
2592                emotion: None,
2593                confidence: None,
2594            },
2595        })
2596    });
2597
2598    // Sarcasm marker
2599    define(interp, "sarcastic", Some(1), |_, args| {
2600        Ok(Value::Affective {
2601            value: Box::new(args[0].clone()),
2602            affect: RuntimeAffect {
2603                sentiment: None,
2604                sarcasm: true,
2605                intensity: None,
2606                formality: None,
2607                emotion: None,
2608                confidence: None,
2609            },
2610        })
2611    });
2612
2613    // Intensity markers
2614    define(interp, "intensify", Some(1), |_, args| {
2615        Ok(Value::Affective {
2616            value: Box::new(args[0].clone()),
2617            affect: RuntimeAffect {
2618                sentiment: None,
2619                sarcasm: false,
2620                intensity: Some(RuntimeIntensity::Up),
2621                formality: None,
2622                emotion: None,
2623                confidence: None,
2624            },
2625        })
2626    });
2627
2628    define(interp, "dampen", Some(1), |_, args| {
2629        Ok(Value::Affective {
2630            value: Box::new(args[0].clone()),
2631            affect: RuntimeAffect {
2632                sentiment: None,
2633                sarcasm: false,
2634                intensity: Some(RuntimeIntensity::Down),
2635                formality: None,
2636                emotion: None,
2637                confidence: None,
2638            },
2639        })
2640    });
2641
2642    define(interp, "maximize", Some(1), |_, args| {
2643        Ok(Value::Affective {
2644            value: Box::new(args[0].clone()),
2645            affect: RuntimeAffect {
2646                sentiment: None,
2647                sarcasm: false,
2648                intensity: Some(RuntimeIntensity::Max),
2649                formality: None,
2650                emotion: None,
2651                confidence: None,
2652            },
2653        })
2654    });
2655
2656    // Formality markers
2657    define(interp, "formal", Some(1), |_, args| {
2658        Ok(Value::Affective {
2659            value: Box::new(args[0].clone()),
2660            affect: RuntimeAffect {
2661                sentiment: None,
2662                sarcasm: false,
2663                intensity: None,
2664                formality: Some(RuntimeFormality::Formal),
2665                emotion: None,
2666                confidence: None,
2667            },
2668        })
2669    });
2670
2671    define(interp, "informal", Some(1), |_, args| {
2672        Ok(Value::Affective {
2673            value: Box::new(args[0].clone()),
2674            affect: RuntimeAffect {
2675                sentiment: None,
2676                sarcasm: false,
2677                intensity: None,
2678                formality: Some(RuntimeFormality::Informal),
2679                emotion: None,
2680                confidence: None,
2681            },
2682        })
2683    });
2684
2685    // Emotion markers (Plutchik's wheel)
2686    define(interp, "joyful", Some(1), |_, args| {
2687        Ok(Value::Affective {
2688            value: Box::new(args[0].clone()),
2689            affect: RuntimeAffect {
2690                sentiment: None,
2691                sarcasm: false,
2692                intensity: None,
2693                formality: None,
2694                emotion: Some(RuntimeEmotion::Joy),
2695                confidence: None,
2696            },
2697        })
2698    });
2699
2700    define(interp, "sad", Some(1), |_, args| {
2701        Ok(Value::Affective {
2702            value: Box::new(args[0].clone()),
2703            affect: RuntimeAffect {
2704                sentiment: None,
2705                sarcasm: false,
2706                intensity: None,
2707                formality: None,
2708                emotion: Some(RuntimeEmotion::Sadness),
2709                confidence: None,
2710            },
2711        })
2712    });
2713
2714    define(interp, "angry", Some(1), |_, args| {
2715        Ok(Value::Affective {
2716            value: Box::new(args[0].clone()),
2717            affect: RuntimeAffect {
2718                sentiment: None,
2719                sarcasm: false,
2720                intensity: None,
2721                formality: None,
2722                emotion: Some(RuntimeEmotion::Anger),
2723                confidence: None,
2724            },
2725        })
2726    });
2727
2728    define(interp, "fearful", Some(1), |_, args| {
2729        Ok(Value::Affective {
2730            value: Box::new(args[0].clone()),
2731            affect: RuntimeAffect {
2732                sentiment: None,
2733                sarcasm: false,
2734                intensity: None,
2735                formality: None,
2736                emotion: Some(RuntimeEmotion::Fear),
2737                confidence: None,
2738            },
2739        })
2740    });
2741
2742    define(interp, "surprised", Some(1), |_, args| {
2743        Ok(Value::Affective {
2744            value: Box::new(args[0].clone()),
2745            affect: RuntimeAffect {
2746                sentiment: None,
2747                sarcasm: false,
2748                intensity: None,
2749                formality: None,
2750                emotion: Some(RuntimeEmotion::Surprise),
2751                confidence: None,
2752            },
2753        })
2754    });
2755
2756    define(interp, "loving", Some(1), |_, args| {
2757        Ok(Value::Affective {
2758            value: Box::new(args[0].clone()),
2759            affect: RuntimeAffect {
2760                sentiment: None,
2761                sarcasm: false,
2762                intensity: None,
2763                formality: None,
2764                emotion: Some(RuntimeEmotion::Love),
2765                confidence: None,
2766            },
2767        })
2768    });
2769
2770    // Confidence markers
2771    define(interp, "high_confidence", Some(1), |_, args| {
2772        Ok(Value::Affective {
2773            value: Box::new(args[0].clone()),
2774            affect: RuntimeAffect {
2775                sentiment: None,
2776                sarcasm: false,
2777                intensity: None,
2778                formality: None,
2779                emotion: None,
2780                confidence: Some(RuntimeConfidence::High),
2781            },
2782        })
2783    });
2784
2785    define(interp, "medium_confidence", Some(1), |_, args| {
2786        Ok(Value::Affective {
2787            value: Box::new(args[0].clone()),
2788            affect: RuntimeAffect {
2789                sentiment: None,
2790                sarcasm: false,
2791                intensity: None,
2792                formality: None,
2793                emotion: None,
2794                confidence: Some(RuntimeConfidence::Medium),
2795            },
2796        })
2797    });
2798
2799    define(interp, "low_confidence", Some(1), |_, args| {
2800        Ok(Value::Affective {
2801            value: Box::new(args[0].clone()),
2802            affect: RuntimeAffect {
2803                sentiment: None,
2804                sarcasm: false,
2805                intensity: None,
2806                formality: None,
2807                emotion: None,
2808                confidence: Some(RuntimeConfidence::Low),
2809            },
2810        })
2811    });
2812
2813    // === Query affect ===
2814
2815    define(interp, "affect_of", Some(1), |_, args| match &args[0] {
2816        Value::Affective { affect, .. } => {
2817            let mut parts = Vec::new();
2818            if let Some(s) = &affect.sentiment {
2819                parts.push(match s {
2820                    RuntimeSentiment::Positive => "positive",
2821                    RuntimeSentiment::Negative => "negative",
2822                    RuntimeSentiment::Neutral => "neutral",
2823                });
2824            }
2825            if affect.sarcasm {
2826                parts.push("sarcastic");
2827            }
2828            if let Some(i) = &affect.intensity {
2829                parts.push(match i {
2830                    RuntimeIntensity::Up => "intensified",
2831                    RuntimeIntensity::Down => "dampened",
2832                    RuntimeIntensity::Max => "maximized",
2833                });
2834            }
2835            if let Some(f) = &affect.formality {
2836                parts.push(match f {
2837                    RuntimeFormality::Formal => "formal",
2838                    RuntimeFormality::Informal => "informal",
2839                });
2840            }
2841            if let Some(e) = &affect.emotion {
2842                parts.push(match e {
2843                    RuntimeEmotion::Joy => "joyful",
2844                    RuntimeEmotion::Sadness => "sad",
2845                    RuntimeEmotion::Anger => "angry",
2846                    RuntimeEmotion::Fear => "fearful",
2847                    RuntimeEmotion::Surprise => "surprised",
2848                    RuntimeEmotion::Love => "loving",
2849                });
2850            }
2851            if let Some(c) = &affect.confidence {
2852                parts.push(match c {
2853                    RuntimeConfidence::High => "high_confidence",
2854                    RuntimeConfidence::Medium => "medium_confidence",
2855                    RuntimeConfidence::Low => "low_confidence",
2856                });
2857            }
2858            Ok(Value::String(Rc::new(parts.join(", "))))
2859        }
2860        _ => Ok(Value::String(Rc::new("none".to_string()))),
2861    });
2862
2863    define(interp, "is_sarcastic", Some(1), |_, args| match &args[0] {
2864        Value::Affective { affect, .. } => Ok(Value::Bool(affect.sarcasm)),
2865        _ => Ok(Value::Bool(false)),
2866    });
2867
2868    define(interp, "is_positive", Some(1), |_, args| match &args[0] {
2869        Value::Affective { affect, .. } => Ok(Value::Bool(matches!(
2870            affect.sentiment,
2871            Some(RuntimeSentiment::Positive)
2872        ))),
2873        _ => Ok(Value::Bool(false)),
2874    });
2875
2876    define(interp, "is_negative", Some(1), |_, args| match &args[0] {
2877        Value::Affective { affect, .. } => Ok(Value::Bool(matches!(
2878            affect.sentiment,
2879            Some(RuntimeSentiment::Negative)
2880        ))),
2881        _ => Ok(Value::Bool(false)),
2882    });
2883
2884    define(interp, "is_formal", Some(1), |_, args| match &args[0] {
2885        Value::Affective { affect, .. } => Ok(Value::Bool(matches!(
2886            affect.formality,
2887            Some(RuntimeFormality::Formal)
2888        ))),
2889        _ => Ok(Value::Bool(false)),
2890    });
2891
2892    define(interp, "is_informal", Some(1), |_, args| match &args[0] {
2893        Value::Affective { affect, .. } => Ok(Value::Bool(matches!(
2894            affect.formality,
2895            Some(RuntimeFormality::Informal)
2896        ))),
2897        _ => Ok(Value::Bool(false)),
2898    });
2899
2900    define(interp, "emotion_of", Some(1), |_, args| match &args[0] {
2901        Value::Affective { affect, .. } => {
2902            let emotion_str = match &affect.emotion {
2903                Some(RuntimeEmotion::Joy) => "joy",
2904                Some(RuntimeEmotion::Sadness) => "sadness",
2905                Some(RuntimeEmotion::Anger) => "anger",
2906                Some(RuntimeEmotion::Fear) => "fear",
2907                Some(RuntimeEmotion::Surprise) => "surprise",
2908                Some(RuntimeEmotion::Love) => "love",
2909                None => "none",
2910            };
2911            Ok(Value::String(Rc::new(emotion_str.to_string())))
2912        }
2913        _ => Ok(Value::String(Rc::new("none".to_string()))),
2914    });
2915
2916    define(interp, "confidence_of", Some(1), |_, args| match &args[0] {
2917        Value::Affective { affect, .. } => {
2918            let conf_str = match &affect.confidence {
2919                Some(RuntimeConfidence::High) => "high",
2920                Some(RuntimeConfidence::Medium) => "medium",
2921                Some(RuntimeConfidence::Low) => "low",
2922                None => "none",
2923            };
2924            Ok(Value::String(Rc::new(conf_str.to_string())))
2925        }
2926        _ => Ok(Value::String(Rc::new("none".to_string()))),
2927    });
2928
2929    // Extract inner value
2930    define(interp, "strip_affect", Some(1), |_, args| match &args[0] {
2931        Value::Affective { value, .. } => Ok(*value.clone()),
2932        other => Ok(other.clone()),
2933    });
2934
2935    // Create full affect with multiple markers
2936    define(interp, "with_affect", None, |_, args| {
2937        if args.is_empty() {
2938            return Err(RuntimeError::new(
2939                "with_affect requires at least one argument",
2940            ));
2941        }
2942
2943        let base_value = args[0].clone();
2944        let mut affect = RuntimeAffect {
2945            sentiment: None,
2946            sarcasm: false,
2947            intensity: None,
2948            formality: None,
2949            emotion: None,
2950            confidence: None,
2951        };
2952
2953        // Parse string markers from remaining args
2954        for arg in args.iter().skip(1) {
2955            if let Value::String(s) = arg {
2956                match s.as_str() {
2957                    "positive" | "⊕" => affect.sentiment = Some(RuntimeSentiment::Positive),
2958                    "negative" | "⊖" => affect.sentiment = Some(RuntimeSentiment::Negative),
2959                    "neutral" | "⊜" => affect.sentiment = Some(RuntimeSentiment::Neutral),
2960                    "sarcastic" | "⸮" => affect.sarcasm = true,
2961                    "intensify" | "↑" => affect.intensity = Some(RuntimeIntensity::Up),
2962                    "dampen" | "↓" => affect.intensity = Some(RuntimeIntensity::Down),
2963                    "maximize" | "⇈" => affect.intensity = Some(RuntimeIntensity::Max),
2964                    "formal" | "♔" => affect.formality = Some(RuntimeFormality::Formal),
2965                    "informal" | "♟" => affect.formality = Some(RuntimeFormality::Informal),
2966                    "joy" | "☺" => affect.emotion = Some(RuntimeEmotion::Joy),
2967                    "sadness" | "☹" => affect.emotion = Some(RuntimeEmotion::Sadness),
2968                    "anger" | "⚡" => affect.emotion = Some(RuntimeEmotion::Anger),
2969                    "fear" | "❄" => affect.emotion = Some(RuntimeEmotion::Fear),
2970                    "surprise" | "✦" => affect.emotion = Some(RuntimeEmotion::Surprise),
2971                    "love" | "♡" => affect.emotion = Some(RuntimeEmotion::Love),
2972                    "high" | "◉" => affect.confidence = Some(RuntimeConfidence::High),
2973                    "medium" | "◎" => affect.confidence = Some(RuntimeConfidence::Medium),
2974                    "low" | "○" => affect.confidence = Some(RuntimeConfidence::Low),
2975                    _ => {}
2976                }
2977            }
2978        }
2979
2980        Ok(Value::Affective {
2981            value: Box::new(base_value),
2982            affect,
2983        })
2984    });
2985}
2986
2987// ============================================================================
2988// ITERATOR-STYLE FUNCTIONS (for use in pipes)
2989// ============================================================================
2990
2991fn register_iter(interp: &mut Interpreter) {
2992    // sum - sum all elements
2993    define(interp, "sum", Some(1), |_, args| match &args[0] {
2994        Value::Array(arr) => {
2995            let mut sum_int: i64 = 0;
2996            let mut sum_float: f64 = 0.0;
2997            let mut is_float = false;
2998
2999            for val in arr.borrow().iter() {
3000                match val {
3001                    Value::Int(n) => {
3002                        if is_float {
3003                            sum_float += *n as f64;
3004                        } else {
3005                            sum_int += n;
3006                        }
3007                    }
3008                    Value::Float(n) => {
3009                        if !is_float {
3010                            sum_float = sum_int as f64;
3011                            is_float = true;
3012                        }
3013                        sum_float += n;
3014                    }
3015                    _ => return Err(RuntimeError::new("sum() requires array of numbers")),
3016                }
3017            }
3018
3019            if is_float {
3020                Ok(Value::Float(sum_float))
3021            } else {
3022                Ok(Value::Int(sum_int))
3023            }
3024        }
3025        _ => Err(RuntimeError::new("sum() requires array")),
3026    });
3027
3028    // product - multiply all elements
3029    define(interp, "product", Some(1), |_, args| match &args[0] {
3030        Value::Array(arr) => {
3031            let mut prod_int: i64 = 1;
3032            let mut prod_float: f64 = 1.0;
3033            let mut is_float = false;
3034
3035            for val in arr.borrow().iter() {
3036                match val {
3037                    Value::Int(n) => {
3038                        if is_float {
3039                            prod_float *= *n as f64;
3040                        } else {
3041                            prod_int *= n;
3042                        }
3043                    }
3044                    Value::Float(n) => {
3045                        if !is_float {
3046                            prod_float = prod_int as f64;
3047                            is_float = true;
3048                        }
3049                        prod_float *= n;
3050                    }
3051                    _ => return Err(RuntimeError::new("product() requires array of numbers")),
3052                }
3053            }
3054
3055            if is_float {
3056                Ok(Value::Float(prod_float))
3057            } else {
3058                Ok(Value::Int(prod_int))
3059            }
3060        }
3061        _ => Err(RuntimeError::new("product() requires array")),
3062    });
3063
3064    // mean - average of elements
3065    define(interp, "mean", Some(1), |_, args| match &args[0] {
3066        Value::Array(arr) => {
3067            let arr = arr.borrow();
3068            if arr.is_empty() {
3069                return Err(RuntimeError::new("mean() on empty array"));
3070            }
3071
3072            let mut sum: f64 = 0.0;
3073            for val in arr.iter() {
3074                match val {
3075                    Value::Int(n) => sum += *n as f64,
3076                    Value::Float(n) => sum += n,
3077                    _ => return Err(RuntimeError::new("mean() requires array of numbers")),
3078                }
3079            }
3080
3081            Ok(Value::Float(sum / arr.len() as f64))
3082        }
3083        _ => Err(RuntimeError::new("mean() requires array")),
3084    });
3085
3086    // median - middle value
3087    define(interp, "median", Some(1), |_, args| match &args[0] {
3088        Value::Array(arr) => {
3089            let arr = arr.borrow();
3090            if arr.is_empty() {
3091                return Err(RuntimeError::new("median() on empty array"));
3092            }
3093
3094            let mut nums: Vec<f64> = Vec::new();
3095            for val in arr.iter() {
3096                match val {
3097                    Value::Int(n) => nums.push(*n as f64),
3098                    Value::Float(n) => nums.push(*n),
3099                    _ => return Err(RuntimeError::new("median() requires array of numbers")),
3100                }
3101            }
3102
3103            nums.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
3104            let mid = nums.len() / 2;
3105
3106            if nums.len() % 2 == 0 {
3107                Ok(Value::Float((nums[mid - 1] + nums[mid]) / 2.0))
3108            } else {
3109                Ok(Value::Float(nums[mid]))
3110            }
3111        }
3112        _ => Err(RuntimeError::new("median() requires array")),
3113    });
3114
3115    // min_of - minimum of array
3116    define(interp, "min_of", Some(1), |_, args| match &args[0] {
3117        Value::Array(arr) => {
3118            let arr = arr.borrow();
3119            if arr.is_empty() {
3120                return Err(RuntimeError::new("min_of() on empty array"));
3121            }
3122
3123            let mut min = &arr[0];
3124            for val in arr.iter().skip(1) {
3125                if matches!(compare_values(val, min), std::cmp::Ordering::Less) {
3126                    min = val;
3127                }
3128            }
3129            Ok(min.clone())
3130        }
3131        _ => Err(RuntimeError::new("min_of() requires array")),
3132    });
3133
3134    // max_of - maximum of array
3135    define(interp, "max_of", Some(1), |_, args| match &args[0] {
3136        Value::Array(arr) => {
3137            let arr = arr.borrow();
3138            if arr.is_empty() {
3139                return Err(RuntimeError::new("max_of() on empty array"));
3140            }
3141
3142            let mut max = &arr[0];
3143            for val in arr.iter().skip(1) {
3144                if matches!(compare_values(val, max), std::cmp::Ordering::Greater) {
3145                    max = val;
3146                }
3147            }
3148            Ok(max.clone())
3149        }
3150        _ => Err(RuntimeError::new("max_of() requires array")),
3151    });
3152
3153    // count - count elements (optionally matching predicate)
3154    define(interp, "count", Some(1), |_, args| match &args[0] {
3155        Value::Array(arr) => Ok(Value::Int(arr.borrow().len() as i64)),
3156        Value::String(s) => Ok(Value::Int(s.chars().count() as i64)),
3157        _ => Err(RuntimeError::new("count() requires array or string")),
3158    });
3159
3160    // any - check if any element is truthy
3161    define(interp, "any", Some(1), |_, args| match &args[0] {
3162        Value::Array(arr) => {
3163            for val in arr.borrow().iter() {
3164                if is_truthy(val) {
3165                    return Ok(Value::Bool(true));
3166                }
3167            }
3168            Ok(Value::Bool(false))
3169        }
3170        _ => Err(RuntimeError::new("any() requires array")),
3171    });
3172
3173    // all - check if all elements are truthy
3174    define(interp, "all", Some(1), |_, args| match &args[0] {
3175        Value::Array(arr) => {
3176            for val in arr.borrow().iter() {
3177                if !is_truthy(val) {
3178                    return Ok(Value::Bool(false));
3179                }
3180            }
3181            Ok(Value::Bool(true))
3182        }
3183        _ => Err(RuntimeError::new("all() requires array")),
3184    });
3185
3186    // none - check if no elements are truthy
3187    define(interp, "none", Some(1), |_, args| match &args[0] {
3188        Value::Array(arr) => {
3189            for val in arr.borrow().iter() {
3190                if is_truthy(val) {
3191                    return Ok(Value::Bool(false));
3192                }
3193            }
3194            Ok(Value::Bool(true))
3195        }
3196        _ => Err(RuntimeError::new("none() requires array")),
3197    });
3198}
3199
3200fn is_truthy(val: &Value) -> bool {
3201    match val {
3202        Value::Null | Value::Empty => false,
3203        Value::Bool(b) => *b,
3204        Value::Int(n) => *n != 0,
3205        Value::Float(n) => *n != 0.0 && !n.is_nan(),
3206        Value::String(s) => !s.is_empty(),
3207        Value::Array(arr) => !arr.borrow().is_empty(),
3208        Value::Evidential { value, .. } => is_truthy(value),
3209        _ => true,
3210    }
3211}
3212
3213// ============================================================================
3214// I/O FUNCTIONS
3215// ============================================================================
3216
3217fn register_io(interp: &mut Interpreter) {
3218    // read_file - read entire file as string
3219    define(interp, "read_file", Some(1), |_, args| {
3220        match &args[0] {
3221            Value::String(path) => {
3222                match std::fs::read_to_string(path.as_str()) {
3223                    Ok(content) => Ok(Value::Evidential {
3224                        value: Box::new(Value::String(Rc::new(content))),
3225                        evidence: Evidence::Reported, // File contents are reported, not known
3226                    }),
3227                    Err(e) => Err(RuntimeError::new(format!("read_file failed: {}", e))),
3228                }
3229            }
3230            _ => Err(RuntimeError::new("read_file() requires path string")),
3231        }
3232    });
3233
3234    // write_file - write string to file
3235    define(interp, "write_file", Some(2), |_, args| {
3236        match (&args[0], &args[1]) {
3237            (Value::String(path), Value::String(content)) => {
3238                match std::fs::write(path.as_str(), content.as_str()) {
3239                    Ok(_) => Ok(Value::Bool(true)),
3240                    Err(e) => Err(RuntimeError::new(format!("write_file failed: {}", e))),
3241                }
3242            }
3243            _ => Err(RuntimeError::new(
3244                "write_file() requires path and content strings",
3245            )),
3246        }
3247    });
3248
3249    // append_file - append to file
3250    define(interp, "append_file", Some(2), |_, args| {
3251        match (&args[0], &args[1]) {
3252            (Value::String(path), Value::String(content)) => {
3253                use std::fs::OpenOptions;
3254                let result = OpenOptions::new()
3255                    .create(true)
3256                    .append(true)
3257                    .open(path.as_str())
3258                    .and_then(|mut f| f.write_all(content.as_bytes()));
3259                match result {
3260                    Ok(_) => Ok(Value::Bool(true)),
3261                    Err(e) => Err(RuntimeError::new(format!("append_file failed: {}", e))),
3262                }
3263            }
3264            _ => Err(RuntimeError::new(
3265                "append_file() requires path and content strings",
3266            )),
3267        }
3268    });
3269
3270    // file_exists - check if file exists
3271    define(interp, "file_exists", Some(1), |_, args| match &args[0] {
3272        Value::String(path) => Ok(Value::Bool(std::path::Path::new(path.as_str()).exists())),
3273        _ => Err(RuntimeError::new("file_exists() requires path string")),
3274    });
3275
3276    // read_lines - read file as array of lines
3277    define(interp, "read_lines", Some(1), |_, args| match &args[0] {
3278        Value::String(path) => match std::fs::read_to_string(path.as_str()) {
3279            Ok(content) => {
3280                let lines: Vec<Value> = content
3281                    .lines()
3282                    .map(|l| Value::String(Rc::new(l.to_string())))
3283                    .collect();
3284                Ok(Value::Evidential {
3285                    value: Box::new(Value::Array(Rc::new(RefCell::new(lines)))),
3286                    evidence: Evidence::Reported,
3287                })
3288            }
3289            Err(e) => Err(RuntimeError::new(format!("read_lines failed: {}", e))),
3290        },
3291        _ => Err(RuntimeError::new("read_lines() requires path string")),
3292    });
3293
3294    // env - get environment variable
3295    define(interp, "env", Some(1), |_, args| {
3296        match &args[0] {
3297            Value::String(name) => {
3298                match std::env::var(name.as_str()) {
3299                    Ok(value) => Ok(Value::Evidential {
3300                        value: Box::new(Value::String(Rc::new(value))),
3301                        evidence: Evidence::Reported, // Env vars are external
3302                    }),
3303                    Err(_) => Ok(Value::Null),
3304                }
3305            }
3306            _ => Err(RuntimeError::new("env() requires variable name string")),
3307        }
3308    });
3309
3310    // env_or - get environment variable with default
3311    define(interp, "env_or", Some(2), |_, args| {
3312        match (&args[0], &args[1]) {
3313            (Value::String(name), default) => match std::env::var(name.as_str()) {
3314                Ok(value) => Ok(Value::Evidential {
3315                    value: Box::new(Value::String(Rc::new(value))),
3316                    evidence: Evidence::Reported,
3317                }),
3318                Err(_) => Ok(default.clone()),
3319            },
3320            _ => Err(RuntimeError::new("env_or() requires variable name string")),
3321        }
3322    });
3323
3324    // cwd - current working directory
3325    define(interp, "cwd", Some(0), |_, _| {
3326        match std::env::current_dir() {
3327            Ok(path) => Ok(Value::String(Rc::new(path.to_string_lossy().to_string()))),
3328            Err(e) => Err(RuntimeError::new(format!("cwd() failed: {}", e))),
3329        }
3330    });
3331
3332    // args - command line arguments
3333    define(interp, "args", Some(0), |_, _| {
3334        let args: Vec<Value> = std::env::args()
3335            .map(|a| Value::String(Rc::new(a)))
3336            .collect();
3337        Ok(Value::Array(Rc::new(RefCell::new(args))))
3338    });
3339}
3340
3341// ============================================================================
3342// TIME FUNCTIONS
3343// ============================================================================
3344
3345fn register_time(interp: &mut Interpreter) {
3346    // now - current Unix timestamp in milliseconds
3347    define(interp, "now", Some(0), |_, _| {
3348        let duration = SystemTime::now()
3349            .duration_since(UNIX_EPOCH)
3350            .unwrap_or(Duration::ZERO);
3351        Ok(Value::Int(duration.as_millis() as i64))
3352    });
3353
3354    // now_secs - current Unix timestamp in seconds
3355    define(interp, "now_secs", Some(0), |_, _| {
3356        let duration = SystemTime::now()
3357            .duration_since(UNIX_EPOCH)
3358            .unwrap_or(Duration::ZERO);
3359        Ok(Value::Int(duration.as_secs() as i64))
3360    });
3361
3362    // now_micros - current Unix timestamp in microseconds
3363    define(interp, "now_micros", Some(0), |_, _| {
3364        let duration = SystemTime::now()
3365            .duration_since(UNIX_EPOCH)
3366            .unwrap_or(Duration::ZERO);
3367        Ok(Value::Int(duration.as_micros() as i64))
3368    });
3369
3370    // sleep - sleep for milliseconds
3371    define(interp, "sleep", Some(1), |_, args| match &args[0] {
3372        Value::Int(ms) if *ms >= 0 => {
3373            std::thread::sleep(Duration::from_millis(*ms as u64));
3374            Ok(Value::Null)
3375        }
3376        _ => Err(RuntimeError::new(
3377            "sleep() requires non-negative integer milliseconds",
3378        )),
3379    });
3380
3381    // measure - measure execution time of a thunk (returns ms)
3382    // Note: This would need closure support to work properly
3383    // For now, we provide a simple timer API
3384
3385    // timer_start - start a timer (returns opaque handle)
3386    define(interp, "timer_start", Some(0), |_, _| {
3387        let now = Instant::now();
3388        // Store as microseconds since we can't store Instant directly
3389        Ok(Value::Int(now.elapsed().as_nanos() as i64)) // This is a bit hacky
3390    });
3391}
3392
3393// ============================================================================
3394// RANDOM FUNCTIONS
3395// ============================================================================
3396
3397fn register_random(interp: &mut Interpreter) {
3398    // random - random float 0.0 to 1.0
3399    define(interp, "random", Some(0), |_, _| {
3400        // Simple LCG random - not cryptographically secure
3401        use std::time::SystemTime;
3402        let seed = SystemTime::now()
3403            .duration_since(UNIX_EPOCH)
3404            .unwrap_or(Duration::ZERO)
3405            .as_nanos() as u64;
3406        let rand = ((seed.wrapping_mul(1103515245).wrapping_add(12345)) >> 16) as f64;
3407        Ok(Value::Float(rand / u32::MAX as f64))
3408    });
3409
3410    // random_int - random integer in range [min, max)
3411    define(interp, "random_int", Some(2), |_, args| {
3412        match (&args[0], &args[1]) {
3413            (Value::Int(min), Value::Int(max)) if max > min => {
3414                use std::time::SystemTime;
3415                let seed = SystemTime::now()
3416                    .duration_since(UNIX_EPOCH)
3417                    .unwrap_or(Duration::ZERO)
3418                    .as_nanos() as u64;
3419                let range = (max - min) as u64;
3420                let rand = ((seed.wrapping_mul(1103515245).wrapping_add(12345)) >> 16) % range;
3421                Ok(Value::Int(*min + rand as i64))
3422            }
3423            _ => Err(RuntimeError::new(
3424                "random_int() requires min < max integers",
3425            )),
3426        }
3427    });
3428
3429    // shuffle - shuffle array in place (Fisher-Yates)
3430    define(interp, "shuffle", Some(1), |_, args| match &args[0] {
3431        Value::Array(arr) => {
3432            let mut arr = arr.borrow_mut();
3433            use std::time::SystemTime;
3434            let mut seed = SystemTime::now()
3435                .duration_since(UNIX_EPOCH)
3436                .unwrap_or(Duration::ZERO)
3437                .as_nanos() as u64;
3438
3439            for i in (1..arr.len()).rev() {
3440                seed = seed.wrapping_mul(1103515245).wrapping_add(12345);
3441                let j = ((seed >> 16) as usize) % (i + 1);
3442                arr.swap(i, j);
3443            }
3444            Ok(Value::Null)
3445        }
3446        _ => Err(RuntimeError::new("shuffle() requires array")),
3447    });
3448
3449    // sample - random sample from array
3450    define(interp, "sample", Some(1), |_, args| match &args[0] {
3451        Value::Array(arr) => {
3452            let arr = arr.borrow();
3453            if arr.is_empty() {
3454                return Err(RuntimeError::new("sample() on empty array"));
3455            }
3456
3457            use std::time::SystemTime;
3458            let seed = SystemTime::now()
3459                .duration_since(UNIX_EPOCH)
3460                .unwrap_or(Duration::ZERO)
3461                .as_nanos() as u64;
3462            let idx =
3463                ((seed.wrapping_mul(1103515245).wrapping_add(12345)) >> 16) as usize % arr.len();
3464            Ok(arr[idx].clone())
3465        }
3466        _ => Err(RuntimeError::new("sample() requires array")),
3467    });
3468}
3469
3470// ============================================================================
3471// CONVERSION FUNCTIONS
3472// ============================================================================
3473
3474fn register_convert(interp: &mut Interpreter) {
3475    // to_string - convert to string
3476    define(interp, "to_string", Some(1), |_, args| {
3477        Ok(Value::String(Rc::new(format!("{}", args[0]))))
3478    });
3479
3480    // to_int - convert to integer
3481    define(interp, "to_int", Some(1), |_, args| match &args[0] {
3482        Value::Int(n) => Ok(Value::Int(*n)),
3483        Value::Float(n) => Ok(Value::Int(*n as i64)),
3484        Value::Bool(b) => Ok(Value::Int(if *b { 1 } else { 0 })),
3485        Value::Char(c) => Ok(Value::Int(*c as i64)),
3486        Value::String(s) => s
3487            .parse::<i64>()
3488            .map(Value::Int)
3489            .map_err(|_| RuntimeError::new(format!("cannot parse '{}' as integer", s))),
3490        _ => Err(RuntimeError::new("to_int() cannot convert this type")),
3491    });
3492
3493    // to_float - convert to float
3494    define(interp, "to_float", Some(1), |_, args| match &args[0] {
3495        Value::Int(n) => Ok(Value::Float(*n as f64)),
3496        Value::Float(n) => Ok(Value::Float(*n)),
3497        Value::Bool(b) => Ok(Value::Float(if *b { 1.0 } else { 0.0 })),
3498        Value::String(s) => s
3499            .parse::<f64>()
3500            .map(Value::Float)
3501            .map_err(|_| RuntimeError::new(format!("cannot parse '{}' as float", s))),
3502        _ => Err(RuntimeError::new("to_float() cannot convert this type")),
3503    });
3504
3505    // to_bool - convert to boolean
3506    define(interp, "to_bool", Some(1), |_, args| {
3507        Ok(Value::Bool(is_truthy(&args[0])))
3508    });
3509
3510    // to_char - convert to character
3511    define(interp, "to_char", Some(1), |_, args| match &args[0] {
3512        Value::Char(c) => Ok(Value::Char(*c)),
3513        Value::Int(n) => char::from_u32(*n as u32)
3514            .map(Value::Char)
3515            .ok_or_else(|| RuntimeError::new(format!("invalid char code: {}", n))),
3516        Value::String(s) => s
3517            .chars()
3518            .next()
3519            .map(Value::Char)
3520            .ok_or_else(|| RuntimeError::new("to_char() on empty string")),
3521        _ => Err(RuntimeError::new("to_char() cannot convert this type")),
3522    });
3523
3524    // to_array - convert to array
3525    define(interp, "to_array", Some(1), |_, args| match &args[0] {
3526        Value::Array(arr) => Ok(Value::Array(arr.clone())),
3527        Value::Tuple(t) => Ok(Value::Array(Rc::new(RefCell::new(t.as_ref().clone())))),
3528        Value::String(s) => {
3529            let chars: Vec<Value> = s.chars().map(Value::Char).collect();
3530            Ok(Value::Array(Rc::new(RefCell::new(chars))))
3531        }
3532        _ => Ok(Value::Array(Rc::new(RefCell::new(vec![args[0].clone()])))),
3533    });
3534
3535    // to_tuple - convert to tuple
3536    define(interp, "to_tuple", Some(1), |_, args| match &args[0] {
3537        Value::Tuple(t) => Ok(Value::Tuple(t.clone())),
3538        Value::Array(arr) => Ok(Value::Tuple(Rc::new(arr.borrow().clone()))),
3539        _ => Ok(Value::Tuple(Rc::new(vec![args[0].clone()]))),
3540    });
3541
3542    // char_code - get unicode code point
3543    define(interp, "char_code", Some(1), |_, args| match &args[0] {
3544        Value::Char(c) => Ok(Value::Int(*c as i64)),
3545        _ => Err(RuntimeError::new("char_code() requires char")),
3546    });
3547
3548    // from_char_code - create char from code point
3549    define(interp, "from_char_code", Some(1), |_, args| {
3550        match &args[0] {
3551            Value::Int(n) => char::from_u32(*n as u32)
3552                .map(Value::Char)
3553                .ok_or_else(|| RuntimeError::new(format!("invalid char code: {}", n))),
3554            _ => Err(RuntimeError::new("from_char_code() requires integer")),
3555        }
3556    });
3557
3558    // hex - convert to hex string
3559    define(interp, "hex", Some(1), |_, args| match &args[0] {
3560        Value::Int(n) => Ok(Value::String(Rc::new(format!("{:x}", n)))),
3561        _ => Err(RuntimeError::new("hex() requires integer")),
3562    });
3563
3564    // oct - convert to octal string
3565    define(interp, "oct", Some(1), |_, args| match &args[0] {
3566        Value::Int(n) => Ok(Value::String(Rc::new(format!("{:o}", n)))),
3567        _ => Err(RuntimeError::new("oct() requires integer")),
3568    });
3569
3570    // bin - convert to binary string
3571    define(interp, "bin", Some(1), |_, args| match &args[0] {
3572        Value::Int(n) => Ok(Value::String(Rc::new(format!("{:b}", n)))),
3573        _ => Err(RuntimeError::new("bin() requires integer")),
3574    });
3575
3576    // parse_int - parse string as integer with optional base
3577    define(interp, "parse_int", Some(2), |_, args| {
3578        match (&args[0], &args[1]) {
3579            (Value::String(s), Value::Int(base)) if *base >= 2 && *base <= 36 => {
3580                i64::from_str_radix(s.trim(), *base as u32)
3581                    .map(Value::Int)
3582                    .map_err(|_| {
3583                        RuntimeError::new(format!("cannot parse '{}' as base-{} integer", s, base))
3584                    })
3585            }
3586            _ => Err(RuntimeError::new(
3587                "parse_int() requires string and base 2-36",
3588            )),
3589        }
3590    });
3591}
3592
3593// ============================================================================
3594// CYCLE (MODULAR ARITHMETIC) FUNCTIONS
3595// For poly-cultural mathematics
3596// ============================================================================
3597
3598fn register_cycle(interp: &mut Interpreter) {
3599    // cycle - create a cycle value (modular)
3600    define(interp, "cycle", Some(2), |_, args| {
3601        match (&args[0], &args[1]) {
3602            (Value::Int(value), Value::Int(modulus)) if *modulus > 0 => {
3603                let normalized = value.rem_euclid(*modulus);
3604                Ok(Value::Tuple(Rc::new(vec![
3605                    Value::Int(normalized),
3606                    Value::Int(*modulus),
3607                ])))
3608            }
3609            _ => Err(RuntimeError::new(
3610                "cycle() requires value and positive modulus",
3611            )),
3612        }
3613    });
3614
3615    // mod_add - modular addition
3616    define(interp, "mod_add", Some(3), |_, args| {
3617        match (&args[0], &args[1], &args[2]) {
3618            (Value::Int(a), Value::Int(b), Value::Int(m)) if *m > 0 => {
3619                Ok(Value::Int((a + b).rem_euclid(*m)))
3620            }
3621            _ => Err(RuntimeError::new(
3622                "mod_add() requires two integers and positive modulus",
3623            )),
3624        }
3625    });
3626
3627    // mod_sub - modular subtraction
3628    define(interp, "mod_sub", Some(3), |_, args| {
3629        match (&args[0], &args[1], &args[2]) {
3630            (Value::Int(a), Value::Int(b), Value::Int(m)) if *m > 0 => {
3631                Ok(Value::Int((a - b).rem_euclid(*m)))
3632            }
3633            _ => Err(RuntimeError::new(
3634                "mod_sub() requires two integers and positive modulus",
3635            )),
3636        }
3637    });
3638
3639    // mod_mul - modular multiplication
3640    define(interp, "mod_mul", Some(3), |_, args| {
3641        match (&args[0], &args[1], &args[2]) {
3642            (Value::Int(a), Value::Int(b), Value::Int(m)) if *m > 0 => {
3643                Ok(Value::Int((a * b).rem_euclid(*m)))
3644            }
3645            _ => Err(RuntimeError::new(
3646                "mod_mul() requires two integers and positive modulus",
3647            )),
3648        }
3649    });
3650
3651    // mod_pow - modular exponentiation (fast)
3652    define(interp, "mod_pow", Some(3), |_, args| {
3653        match (&args[0], &args[1], &args[2]) {
3654            (Value::Int(base), Value::Int(exp), Value::Int(m)) if *m > 0 && *exp >= 0 => {
3655                Ok(Value::Int(mod_pow(*base, *exp as u64, *m)))
3656            }
3657            _ => Err(RuntimeError::new(
3658                "mod_pow() requires base, non-negative exp, and positive modulus",
3659            )),
3660        }
3661    });
3662
3663    // mod_inv - modular multiplicative inverse (if exists)
3664    define(interp, "mod_inv", Some(2), |_, args| {
3665        match (&args[0], &args[1]) {
3666            (Value::Int(a), Value::Int(m)) if *m > 0 => match mod_inverse(*a, *m) {
3667                Some(inv) => Ok(Value::Int(inv)),
3668                None => Err(RuntimeError::new(format!(
3669                    "no modular inverse of {} mod {}",
3670                    a, m
3671                ))),
3672            },
3673            _ => Err(RuntimeError::new(
3674                "mod_inv() requires integer and positive modulus",
3675            )),
3676        }
3677    });
3678
3679    // Musical cycles (for tuning systems)
3680    // octave - normalize to octave (pitch class)
3681    define(interp, "octave", Some(1), |_, args| {
3682        match &args[0] {
3683            Value::Int(note) => Ok(Value::Int(note.rem_euclid(12))),
3684            Value::Float(freq) => {
3685                // Normalize frequency to octave starting at A4=440Hz
3686                let semitones = 12.0 * (freq / 440.0).log2();
3687                Ok(Value::Float(semitones.rem_euclid(12.0)))
3688            }
3689            _ => Err(RuntimeError::new("octave() requires number")),
3690        }
3691    });
3692
3693    // interval - musical interval (semitones)
3694    define(interp, "interval", Some(2), |_, args| {
3695        match (&args[0], &args[1]) {
3696            (Value::Int(a), Value::Int(b)) => Ok(Value::Int((b - a).rem_euclid(12))),
3697            _ => Err(RuntimeError::new("interval() requires two integers")),
3698        }
3699    });
3700
3701    // cents - convert semitones to cents or vice versa
3702    define(interp, "cents", Some(1), |_, args| match &args[0] {
3703        Value::Int(semitones) => Ok(Value::Int(*semitones * 100)),
3704        Value::Float(semitones) => Ok(Value::Float(*semitones * 100.0)),
3705        _ => Err(RuntimeError::new("cents() requires number")),
3706    });
3707
3708    // freq - convert MIDI note number to frequency
3709    define(interp, "freq", Some(1), |_, args| match &args[0] {
3710        Value::Int(midi) => {
3711            let freq = 440.0 * 2.0_f64.powf((*midi as f64 - 69.0) / 12.0);
3712            Ok(Value::Float(freq))
3713        }
3714        _ => Err(RuntimeError::new("freq() requires integer MIDI note")),
3715    });
3716
3717    // midi - convert frequency to MIDI note number
3718    define(interp, "midi", Some(1), |_, args| match &args[0] {
3719        Value::Float(freq) if *freq > 0.0 => {
3720            let midi = 69.0 + 12.0 * (freq / 440.0).log2();
3721            Ok(Value::Int(midi.round() as i64))
3722        }
3723        Value::Int(freq) if *freq > 0 => {
3724            let midi = 69.0 + 12.0 * (*freq as f64 / 440.0).log2();
3725            Ok(Value::Int(midi.round() as i64))
3726        }
3727        _ => Err(RuntimeError::new("midi() requires positive frequency")),
3728    });
3729}
3730
3731// Fast modular exponentiation
3732fn mod_pow(mut base: i64, mut exp: u64, modulus: i64) -> i64 {
3733    if modulus == 1 {
3734        return 0;
3735    }
3736    let mut result: i64 = 1;
3737    base = base.rem_euclid(modulus);
3738    while exp > 0 {
3739        if exp % 2 == 1 {
3740            result = (result * base).rem_euclid(modulus);
3741        }
3742        exp /= 2;
3743        base = (base * base).rem_euclid(modulus);
3744    }
3745    result
3746}
3747
3748// ============================================================================
3749// SIMD VECTOR FUNCTIONS
3750// High-performance vector operations for game/graphics math
3751// ============================================================================
3752
3753fn register_simd(interp: &mut Interpreter) {
3754    // simd_new - create a SIMD 4-component vector
3755    define(interp, "simd_new", Some(4), |_, args| {
3756        let values: Result<Vec<f64>, _> = args
3757            .iter()
3758            .map(|v| match v {
3759                Value::Float(f) => Ok(*f),
3760                Value::Int(i) => Ok(*i as f64),
3761                _ => Err(RuntimeError::new("simd_new() requires numbers")),
3762            })
3763            .collect();
3764        let values = values?;
3765        Ok(Value::Array(Rc::new(RefCell::new(vec![
3766            Value::Float(values[0]),
3767            Value::Float(values[1]),
3768            Value::Float(values[2]),
3769            Value::Float(values[3]),
3770        ]))))
3771    });
3772
3773    // simd_splat - create vector with all same components
3774    define(interp, "simd_splat", Some(1), |_, args| {
3775        let v = match &args[0] {
3776            Value::Float(f) => *f,
3777            Value::Int(i) => *i as f64,
3778            _ => return Err(RuntimeError::new("simd_splat() requires number")),
3779        };
3780        Ok(Value::Array(Rc::new(RefCell::new(vec![
3781            Value::Float(v),
3782            Value::Float(v),
3783            Value::Float(v),
3784            Value::Float(v),
3785        ]))))
3786    });
3787
3788    // simd_add - component-wise addition
3789    define(interp, "simd_add", Some(2), |_, args| {
3790        simd_binary_op(&args[0], &args[1], |a, b| a + b, "simd_add")
3791    });
3792
3793    // simd_sub - component-wise subtraction
3794    define(interp, "simd_sub", Some(2), |_, args| {
3795        simd_binary_op(&args[0], &args[1], |a, b| a - b, "simd_sub")
3796    });
3797
3798    // simd_mul - component-wise multiplication
3799    define(interp, "simd_mul", Some(2), |_, args| {
3800        simd_binary_op(&args[0], &args[1], |a, b| a * b, "simd_mul")
3801    });
3802
3803    // simd_div - component-wise division
3804    define(interp, "simd_div", Some(2), |_, args| {
3805        simd_binary_op(&args[0], &args[1], |a, b| a / b, "simd_div")
3806    });
3807
3808    // simd_dot - dot product of two vectors
3809    define(interp, "simd_dot", Some(2), |_, args| {
3810        let a = extract_simd(&args[0], "simd_dot")?;
3811        let b = extract_simd(&args[1], "simd_dot")?;
3812        let dot = a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
3813        Ok(Value::Float(dot))
3814    });
3815
3816    // simd_cross - 3D cross product (w component set to 0)
3817    define(interp, "simd_cross", Some(2), |_, args| {
3818        let a = extract_simd(&args[0], "simd_cross")?;
3819        let b = extract_simd(&args[1], "simd_cross")?;
3820        Ok(Value::Array(Rc::new(RefCell::new(vec![
3821            Value::Float(a[1] * b[2] - a[2] * b[1]),
3822            Value::Float(a[2] * b[0] - a[0] * b[2]),
3823            Value::Float(a[0] * b[1] - a[1] * b[0]),
3824            Value::Float(0.0),
3825        ]))))
3826    });
3827
3828    // simd_length - vector length (magnitude)
3829    define(interp, "simd_length", Some(1), |_, args| {
3830        let v = extract_simd(&args[0], "simd_length")?;
3831        let len_sq = v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3];
3832        Ok(Value::Float(len_sq.sqrt()))
3833    });
3834
3835    // simd_normalize - normalize vector to unit length
3836    define(interp, "simd_normalize", Some(1), |_, args| {
3837        let v = extract_simd(&args[0], "simd_normalize")?;
3838        let len_sq = v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3];
3839        let len = len_sq.sqrt();
3840        if len < 1e-10 {
3841            return Ok(Value::Array(Rc::new(RefCell::new(vec![
3842                Value::Float(0.0),
3843                Value::Float(0.0),
3844                Value::Float(0.0),
3845                Value::Float(0.0),
3846            ]))));
3847        }
3848        let inv_len = 1.0 / len;
3849        Ok(Value::Array(Rc::new(RefCell::new(vec![
3850            Value::Float(v[0] * inv_len),
3851            Value::Float(v[1] * inv_len),
3852            Value::Float(v[2] * inv_len),
3853            Value::Float(v[3] * inv_len),
3854        ]))))
3855    });
3856
3857    // simd_min - component-wise minimum
3858    define(interp, "simd_min", Some(2), |_, args| {
3859        simd_binary_op(&args[0], &args[1], |a, b| a.min(b), "simd_min")
3860    });
3861
3862    // simd_max - component-wise maximum
3863    define(interp, "simd_max", Some(2), |_, args| {
3864        simd_binary_op(&args[0], &args[1], |a, b| a.max(b), "simd_max")
3865    });
3866
3867    // simd_hadd - horizontal add (sum all components)
3868    define(interp, "simd_hadd", Some(1), |_, args| {
3869        let v = extract_simd(&args[0], "simd_hadd")?;
3870        Ok(Value::Float(v[0] + v[1] + v[2] + v[3]))
3871    });
3872
3873    // simd_extract - extract single component (0-3)
3874    define(interp, "simd_extract", Some(2), |_, args| {
3875        let v = extract_simd(&args[0], "simd_extract")?;
3876        let idx = match &args[1] {
3877            Value::Int(i) => *i as usize,
3878            _ => return Err(RuntimeError::new("simd_extract() requires integer index")),
3879        };
3880        if idx > 3 {
3881            return Err(RuntimeError::new("simd_extract() index must be 0-3"));
3882        }
3883        Ok(Value::Float(v[idx]))
3884    });
3885
3886    // simd_free - no-op in interpreter (for JIT compatibility)
3887    define(interp, "simd_free", Some(1), |_, _| Ok(Value::Null));
3888
3889    // simd_lerp - linear interpolation between vectors
3890    define(interp, "simd_lerp", Some(3), |_, args| {
3891        let a = extract_simd(&args[0], "simd_lerp")?;
3892        let b = extract_simd(&args[1], "simd_lerp")?;
3893        let t = match &args[2] {
3894            Value::Float(f) => *f,
3895            Value::Int(i) => *i as f64,
3896            _ => return Err(RuntimeError::new("simd_lerp() requires float t")),
3897        };
3898        let one_t = 1.0 - t;
3899        Ok(Value::Array(Rc::new(RefCell::new(vec![
3900            Value::Float(a[0] * one_t + b[0] * t),
3901            Value::Float(a[1] * one_t + b[1] * t),
3902            Value::Float(a[2] * one_t + b[2] * t),
3903            Value::Float(a[3] * one_t + b[3] * t),
3904        ]))))
3905    });
3906}
3907
3908// Helper to extract SIMD values from array
3909fn extract_simd(val: &Value, fn_name: &str) -> Result<[f64; 4], RuntimeError> {
3910    match val {
3911        Value::Array(arr) => {
3912            let arr = arr.borrow();
3913            if arr.len() < 4 {
3914                return Err(RuntimeError::new(format!(
3915                    "{}() requires 4-element array",
3916                    fn_name
3917                )));
3918            }
3919            let mut result = [0.0; 4];
3920            for (i, v) in arr.iter().take(4).enumerate() {
3921                result[i] = match v {
3922                    Value::Float(f) => *f,
3923                    Value::Int(n) => *n as f64,
3924                    _ => {
3925                        return Err(RuntimeError::new(format!(
3926                            "{}() requires numeric array",
3927                            fn_name
3928                        )))
3929                    }
3930                };
3931            }
3932            Ok(result)
3933        }
3934        _ => Err(RuntimeError::new(format!(
3935            "{}() requires array argument",
3936            fn_name
3937        ))),
3938    }
3939}
3940
3941// Helper for binary SIMD operations
3942fn simd_binary_op<F>(a: &Value, b: &Value, op: F, fn_name: &str) -> Result<Value, RuntimeError>
3943where
3944    F: Fn(f64, f64) -> f64,
3945{
3946    let a = extract_simd(a, fn_name)?;
3947    let b = extract_simd(b, fn_name)?;
3948    Ok(Value::Array(Rc::new(RefCell::new(vec![
3949        Value::Float(op(a[0], b[0])),
3950        Value::Float(op(a[1], b[1])),
3951        Value::Float(op(a[2], b[2])),
3952        Value::Float(op(a[3], b[3])),
3953    ]))))
3954}
3955
3956// ============================================================================
3957// GRAPHICS MATH LIBRARY
3958// ============================================================================
3959// Comprehensive 3D graphics mathematics for physics and rendering:
3960// - Quaternions for rotation without gimbal lock
3961// - vec2/vec3/vec4 vector types with swizzling
3962// - mat3/mat4 matrices with projection/view/model operations
3963// - Affine transforms, Euler angles, and interpolation
3964// ============================================================================
3965
3966fn register_graphics_math(interp: &mut Interpreter) {
3967    // -------------------------------------------------------------------------
3968    // QUATERNIONS - Essential for 3D rotations
3969    // -------------------------------------------------------------------------
3970    // Quaternion format: [w, x, y, z] where w is scalar, (x,y,z) is vector part
3971    // This follows the convention: q = w + xi + yj + zk
3972
3973    // quat_new(w, x, y, z) - create a quaternion
3974    define(interp, "quat_new", Some(4), |_, args| {
3975        let w = extract_number(&args[0], "quat_new")?;
3976        let x = extract_number(&args[1], "quat_new")?;
3977        let y = extract_number(&args[2], "quat_new")?;
3978        let z = extract_number(&args[3], "quat_new")?;
3979        Ok(make_vec4(w, x, y, z))
3980    });
3981
3982    // quat_identity() - identity quaternion (no rotation)
3983    define(interp, "quat_identity", Some(0), |_, _| {
3984        Ok(make_vec4(1.0, 0.0, 0.0, 0.0))
3985    });
3986
3987    // quat_from_axis_angle(axis_vec3, angle_radians) - create from axis-angle
3988    define(interp, "quat_from_axis_angle", Some(2), |_, args| {
3989        let axis = extract_vec3(&args[0], "quat_from_axis_angle")?;
3990        let angle = extract_number(&args[1], "quat_from_axis_angle")?;
3991
3992        // Normalize axis
3993        let len = (axis[0] * axis[0] + axis[1] * axis[1] + axis[2] * axis[2]).sqrt();
3994        if len < 1e-10 {
3995            return Ok(make_vec4(1.0, 0.0, 0.0, 0.0)); // Identity for zero axis
3996        }
3997        let ax = axis[0] / len;
3998        let ay = axis[1] / len;
3999        let az = axis[2] / len;
4000
4001        let half_angle = angle / 2.0;
4002        let s = half_angle.sin();
4003        let c = half_angle.cos();
4004
4005        Ok(make_vec4(c, ax * s, ay * s, az * s))
4006    });
4007
4008    // quat_from_euler(pitch, yaw, roll) - create from Euler angles (radians)
4009    // Uses XYZ order (pitch around X, yaw around Y, roll around Z)
4010    define(interp, "quat_from_euler", Some(3), |_, args| {
4011        let pitch = extract_number(&args[0], "quat_from_euler")?; // X
4012        let yaw = extract_number(&args[1], "quat_from_euler")?; // Y
4013        let roll = extract_number(&args[2], "quat_from_euler")?; // Z
4014
4015        let (sp, cp) = (pitch / 2.0).sin_cos();
4016        let (sy, cy) = (yaw / 2.0).sin_cos();
4017        let (sr, cr) = (roll / 2.0).sin_cos();
4018
4019        // Combined quaternion (XYZ order)
4020        let w = cp * cy * cr + sp * sy * sr;
4021        let x = sp * cy * cr - cp * sy * sr;
4022        let y = cp * sy * cr + sp * cy * sr;
4023        let z = cp * cy * sr - sp * sy * cr;
4024
4025        Ok(make_vec4(w, x, y, z))
4026    });
4027
4028    // quat_mul(q1, q2) - quaternion multiplication (q1 * q2)
4029    define(interp, "quat_mul", Some(2), |_, args| {
4030        let q1 = extract_vec4(&args[0], "quat_mul")?;
4031        let q2 = extract_vec4(&args[1], "quat_mul")?;
4032
4033        // Hamilton product
4034        let w = q1[0] * q2[0] - q1[1] * q2[1] - q1[2] * q2[2] - q1[3] * q2[3];
4035        let x = q1[0] * q2[1] + q1[1] * q2[0] + q1[2] * q2[3] - q1[3] * q2[2];
4036        let y = q1[0] * q2[2] - q1[1] * q2[3] + q1[2] * q2[0] + q1[3] * q2[1];
4037        let z = q1[0] * q2[3] + q1[1] * q2[2] - q1[2] * q2[1] + q1[3] * q2[0];
4038
4039        Ok(make_vec4(w, x, y, z))
4040    });
4041
4042    // quat_conjugate(q) - quaternion conjugate (inverse for unit quaternions)
4043    define(interp, "quat_conjugate", Some(1), |_, args| {
4044        let q = extract_vec4(&args[0], "quat_conjugate")?;
4045        Ok(make_vec4(q[0], -q[1], -q[2], -q[3]))
4046    });
4047
4048    // quat_inverse(q) - quaternion inverse (handles non-unit quaternions)
4049    define(interp, "quat_inverse", Some(1), |_, args| {
4050        let q = extract_vec4(&args[0], "quat_inverse")?;
4051        let norm_sq = q[0] * q[0] + q[1] * q[1] + q[2] * q[2] + q[3] * q[3];
4052        if norm_sq < 1e-10 {
4053            return Err(RuntimeError::new(
4054                "quat_inverse: cannot invert zero quaternion",
4055            ));
4056        }
4057        Ok(make_vec4(
4058            q[0] / norm_sq,
4059            -q[1] / norm_sq,
4060            -q[2] / norm_sq,
4061            -q[3] / norm_sq,
4062        ))
4063    });
4064
4065    // quat_normalize(q) - normalize to unit quaternion
4066    define(interp, "quat_normalize", Some(1), |_, args| {
4067        let q = extract_vec4(&args[0], "quat_normalize")?;
4068        let len = (q[0] * q[0] + q[1] * q[1] + q[2] * q[2] + q[3] * q[3]).sqrt();
4069        if len < 1e-10 {
4070            return Ok(make_vec4(1.0, 0.0, 0.0, 0.0));
4071        }
4072        Ok(make_vec4(q[0] / len, q[1] / len, q[2] / len, q[3] / len))
4073    });
4074
4075    // quat_rotate(q, vec3) - rotate a 3D vector by quaternion
4076    define(interp, "quat_rotate", Some(2), |_, args| {
4077        let q = extract_vec4(&args[0], "quat_rotate")?;
4078        let v = extract_vec3(&args[1], "quat_rotate")?;
4079
4080        // q * v * q^-1 optimized formula
4081        let qw = q[0];
4082        let qx = q[1];
4083        let qy = q[2];
4084        let qz = q[3];
4085        let vx = v[0];
4086        let vy = v[1];
4087        let vz = v[2];
4088
4089        // t = 2 * cross(q.xyz, v)
4090        let tx = 2.0 * (qy * vz - qz * vy);
4091        let ty = 2.0 * (qz * vx - qx * vz);
4092        let tz = 2.0 * (qx * vy - qy * vx);
4093
4094        // result = v + q.w * t + cross(q.xyz, t)
4095        let rx = vx + qw * tx + (qy * tz - qz * ty);
4096        let ry = vy + qw * ty + (qz * tx - qx * tz);
4097        let rz = vz + qw * tz + (qx * ty - qy * tx);
4098
4099        Ok(make_vec3(rx, ry, rz))
4100    });
4101
4102    // quat_slerp(q1, q2, t) - spherical linear interpolation
4103    define(interp, "quat_slerp", Some(3), |_, args| {
4104        let q1 = extract_vec4(&args[0], "quat_slerp")?;
4105        let mut q2 = extract_vec4(&args[1], "quat_slerp")?;
4106        let t = extract_number(&args[2], "quat_slerp")?;
4107
4108        // Compute dot product
4109        let mut dot = q1[0] * q2[0] + q1[1] * q2[1] + q1[2] * q2[2] + q1[3] * q2[3];
4110
4111        // If dot < 0, negate q2 to take shorter path
4112        if dot < 0.0 {
4113            q2 = [-q2[0], -q2[1], -q2[2], -q2[3]];
4114            dot = -dot;
4115        }
4116
4117        // If quaternions are very close, use linear interpolation
4118        if dot > 0.9995 {
4119            let w = q1[0] + t * (q2[0] - q1[0]);
4120            let x = q1[1] + t * (q2[1] - q1[1]);
4121            let y = q1[2] + t * (q2[2] - q1[2]);
4122            let z = q1[3] + t * (q2[3] - q1[3]);
4123            let len = (w * w + x * x + y * y + z * z).sqrt();
4124            return Ok(make_vec4(w / len, x / len, y / len, z / len));
4125        }
4126
4127        // Spherical interpolation
4128        let theta_0 = dot.acos();
4129        let theta = theta_0 * t;
4130        let sin_theta = theta.sin();
4131        let sin_theta_0 = theta_0.sin();
4132
4133        let s0 = (theta_0 - theta).cos() - dot * sin_theta / sin_theta_0;
4134        let s1 = sin_theta / sin_theta_0;
4135
4136        Ok(make_vec4(
4137            s0 * q1[0] + s1 * q2[0],
4138            s0 * q1[1] + s1 * q2[1],
4139            s0 * q1[2] + s1 * q2[2],
4140            s0 * q1[3] + s1 * q2[3],
4141        ))
4142    });
4143
4144    // quat_to_euler(q) - convert quaternion to Euler angles [pitch, yaw, roll]
4145    define(interp, "quat_to_euler", Some(1), |_, args| {
4146        let q = extract_vec4(&args[0], "quat_to_euler")?;
4147        let (w, x, y, z) = (q[0], q[1], q[2], q[3]);
4148
4149        // Roll (X-axis rotation)
4150        let sinr_cosp = 2.0 * (w * x + y * z);
4151        let cosr_cosp = 1.0 - 2.0 * (x * x + y * y);
4152        let roll = sinr_cosp.atan2(cosr_cosp);
4153
4154        // Pitch (Y-axis rotation)
4155        let sinp = 2.0 * (w * y - z * x);
4156        let pitch = if sinp.abs() >= 1.0 {
4157            std::f64::consts::FRAC_PI_2.copysign(sinp)
4158        } else {
4159            sinp.asin()
4160        };
4161
4162        // Yaw (Z-axis rotation)
4163        let siny_cosp = 2.0 * (w * z + x * y);
4164        let cosy_cosp = 1.0 - 2.0 * (y * y + z * z);
4165        let yaw = siny_cosp.atan2(cosy_cosp);
4166
4167        Ok(make_vec3(pitch, yaw, roll))
4168    });
4169
4170    // quat_to_mat4(q) - convert quaternion to 4x4 rotation matrix
4171    define(interp, "quat_to_mat4", Some(1), |_, args| {
4172        let q = extract_vec4(&args[0], "quat_to_mat4")?;
4173        let (w, x, y, z) = (q[0], q[1], q[2], q[3]);
4174
4175        let xx = x * x;
4176        let yy = y * y;
4177        let zz = z * z;
4178        let xy = x * y;
4179        let xz = x * z;
4180        let yz = y * z;
4181        let wx = w * x;
4182        let wy = w * y;
4183        let wz = w * z;
4184
4185        // Column-major 4x4 rotation matrix
4186        Ok(make_mat4([
4187            1.0 - 2.0 * (yy + zz),
4188            2.0 * (xy + wz),
4189            2.0 * (xz - wy),
4190            0.0,
4191            2.0 * (xy - wz),
4192            1.0 - 2.0 * (xx + zz),
4193            2.0 * (yz + wx),
4194            0.0,
4195            2.0 * (xz + wy),
4196            2.0 * (yz - wx),
4197            1.0 - 2.0 * (xx + yy),
4198            0.0,
4199            0.0,
4200            0.0,
4201            0.0,
4202            1.0,
4203        ]))
4204    });
4205
4206    // -------------------------------------------------------------------------
4207    // VECTOR TYPES - vec2, vec3, vec4
4208    // -------------------------------------------------------------------------
4209
4210    // vec2(x, y)
4211    define(interp, "vec2", Some(2), |_, args| {
4212        let x = extract_number(&args[0], "vec2")?;
4213        let y = extract_number(&args[1], "vec2")?;
4214        Ok(make_vec2(x, y))
4215    });
4216
4217    // vec3(x, y, z)
4218    define(interp, "vec3", Some(3), |_, args| {
4219        let x = extract_number(&args[0], "vec3")?;
4220        let y = extract_number(&args[1], "vec3")?;
4221        let z = extract_number(&args[2], "vec3")?;
4222        Ok(make_vec3(x, y, z))
4223    });
4224
4225    // vec4(x, y, z, w)
4226    define(interp, "vec4", Some(4), |_, args| {
4227        let x = extract_number(&args[0], "vec4")?;
4228        let y = extract_number(&args[1], "vec4")?;
4229        let z = extract_number(&args[2], "vec4")?;
4230        let w = extract_number(&args[3], "vec4")?;
4231        Ok(make_vec4(x, y, z, w))
4232    });
4233
4234    // vec3_add(a, b)
4235    define(interp, "vec3_add", Some(2), |_, args| {
4236        let a = extract_vec3(&args[0], "vec3_add")?;
4237        let b = extract_vec3(&args[1], "vec3_add")?;
4238        Ok(make_vec3(a[0] + b[0], a[1] + b[1], a[2] + b[2]))
4239    });
4240
4241    // vec3_sub(a, b)
4242    define(interp, "vec3_sub", Some(2), |_, args| {
4243        let a = extract_vec3(&args[0], "vec3_sub")?;
4244        let b = extract_vec3(&args[1], "vec3_sub")?;
4245        Ok(make_vec3(a[0] - b[0], a[1] - b[1], a[2] - b[2]))
4246    });
4247
4248    // vec3_scale(v, scalar)
4249    define(interp, "vec3_scale", Some(2), |_, args| {
4250        let v = extract_vec3(&args[0], "vec3_scale")?;
4251        let s = extract_number(&args[1], "vec3_scale")?;
4252        Ok(make_vec3(v[0] * s, v[1] * s, v[2] * s))
4253    });
4254
4255    // vec3_dot(a, b)
4256    define(interp, "vec3_dot", Some(2), |_, args| {
4257        let a = extract_vec3(&args[0], "vec3_dot")?;
4258        let b = extract_vec3(&args[1], "vec3_dot")?;
4259        Ok(Value::Float(a[0] * b[0] + a[1] * b[1] + a[2] * b[2]))
4260    });
4261
4262    // vec3_cross(a, b)
4263    define(interp, "vec3_cross", Some(2), |_, args| {
4264        let a = extract_vec3(&args[0], "vec3_cross")?;
4265        let b = extract_vec3(&args[1], "vec3_cross")?;
4266        Ok(make_vec3(
4267            a[1] * b[2] - a[2] * b[1],
4268            a[2] * b[0] - a[0] * b[2],
4269            a[0] * b[1] - a[1] * b[0],
4270        ))
4271    });
4272
4273    // vec3_length(v)
4274    define(interp, "vec3_length", Some(1), |_, args| {
4275        let v = extract_vec3(&args[0], "vec3_length")?;
4276        Ok(Value::Float(
4277            (v[0] * v[0] + v[1] * v[1] + v[2] * v[2]).sqrt(),
4278        ))
4279    });
4280
4281    // vec3_normalize(v)
4282    define(interp, "vec3_normalize", Some(1), |_, args| {
4283        let v = extract_vec3(&args[0], "vec3_normalize")?;
4284        let len = (v[0] * v[0] + v[1] * v[1] + v[2] * v[2]).sqrt();
4285        if len < 1e-10 {
4286            return Ok(make_vec3(0.0, 0.0, 0.0));
4287        }
4288        Ok(make_vec3(v[0] / len, v[1] / len, v[2] / len))
4289    });
4290
4291    // vec3_lerp(a, b, t) - linear interpolation
4292    define(interp, "vec3_lerp", Some(3), |_, args| {
4293        let a = extract_vec3(&args[0], "vec3_lerp")?;
4294        let b = extract_vec3(&args[1], "vec3_lerp")?;
4295        let t = extract_number(&args[2], "vec3_lerp")?;
4296        Ok(make_vec3(
4297            a[0] + t * (b[0] - a[0]),
4298            a[1] + t * (b[1] - a[1]),
4299            a[2] + t * (b[2] - a[2]),
4300        ))
4301    });
4302
4303    // vec3_reflect(incident, normal) - reflection vector
4304    define(interp, "vec3_reflect", Some(2), |_, args| {
4305        let i = extract_vec3(&args[0], "vec3_reflect")?;
4306        let n = extract_vec3(&args[1], "vec3_reflect")?;
4307        let dot = i[0] * n[0] + i[1] * n[1] + i[2] * n[2];
4308        Ok(make_vec3(
4309            i[0] - 2.0 * dot * n[0],
4310            i[1] - 2.0 * dot * n[1],
4311            i[2] - 2.0 * dot * n[2],
4312        ))
4313    });
4314
4315    // vec3_refract(incident, normal, eta) - refraction vector
4316    define(interp, "vec3_refract", Some(3), |_, args| {
4317        let i = extract_vec3(&args[0], "vec3_refract")?;
4318        let n = extract_vec3(&args[1], "vec3_refract")?;
4319        let eta = extract_number(&args[2], "vec3_refract")?;
4320
4321        let dot = i[0] * n[0] + i[1] * n[1] + i[2] * n[2];
4322        let k = 1.0 - eta * eta * (1.0 - dot * dot);
4323
4324        if k < 0.0 {
4325            // Total internal reflection
4326            return Ok(make_vec3(0.0, 0.0, 0.0));
4327        }
4328
4329        let coeff = eta * dot + k.sqrt();
4330        Ok(make_vec3(
4331            eta * i[0] - coeff * n[0],
4332            eta * i[1] - coeff * n[1],
4333            eta * i[2] - coeff * n[2],
4334        ))
4335    });
4336
4337    // vec4_dot(a, b)
4338    define(interp, "vec4_dot", Some(2), |_, args| {
4339        let a = extract_vec4(&args[0], "vec4_dot")?;
4340        let b = extract_vec4(&args[1], "vec4_dot")?;
4341        Ok(Value::Float(
4342            a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3],
4343        ))
4344    });
4345
4346    // -------------------------------------------------------------------------
4347    // MAT4 - 4x4 MATRICES (Column-major for OpenGL compatibility)
4348    // -------------------------------------------------------------------------
4349
4350    // mat4_identity() - 4x4 identity matrix
4351    define(interp, "mat4_identity", Some(0), |_, _| {
4352        Ok(make_mat4([
4353            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,
4354        ]))
4355    });
4356
4357    // mat4_mul(a, b) - matrix multiplication
4358    define(interp, "mat4_mul", Some(2), |_, args| {
4359        let a = extract_mat4(&args[0], "mat4_mul")?;
4360        let b = extract_mat4(&args[1], "mat4_mul")?;
4361
4362        let mut result = [0.0f64; 16];
4363        for col in 0..4 {
4364            for row in 0..4 {
4365                let mut sum = 0.0;
4366                for k in 0..4 {
4367                    sum += a[k * 4 + row] * b[col * 4 + k];
4368                }
4369                result[col * 4 + row] = sum;
4370            }
4371        }
4372        Ok(make_mat4(result))
4373    });
4374
4375    // mat4_transform(mat4, vec4) - transform vector by matrix
4376    define(interp, "mat4_transform", Some(2), |_, args| {
4377        let m = extract_mat4(&args[0], "mat4_transform")?;
4378        let v = extract_vec4(&args[1], "mat4_transform")?;
4379
4380        Ok(make_vec4(
4381            m[0] * v[0] + m[4] * v[1] + m[8] * v[2] + m[12] * v[3],
4382            m[1] * v[0] + m[5] * v[1] + m[9] * v[2] + m[13] * v[3],
4383            m[2] * v[0] + m[6] * v[1] + m[10] * v[2] + m[14] * v[3],
4384            m[3] * v[0] + m[7] * v[1] + m[11] * v[2] + m[15] * v[3],
4385        ))
4386    });
4387
4388    // mat4_translate(tx, ty, tz) - translation matrix
4389    define(interp, "mat4_translate", Some(3), |_, args| {
4390        let tx = extract_number(&args[0], "mat4_translate")?;
4391        let ty = extract_number(&args[1], "mat4_translate")?;
4392        let tz = extract_number(&args[2], "mat4_translate")?;
4393        Ok(make_mat4([
4394            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,
4395        ]))
4396    });
4397
4398    // mat4_scale(sx, sy, sz) - scale matrix
4399    define(interp, "mat4_scale", Some(3), |_, args| {
4400        let sx = extract_number(&args[0], "mat4_scale")?;
4401        let sy = extract_number(&args[1], "mat4_scale")?;
4402        let sz = extract_number(&args[2], "mat4_scale")?;
4403        Ok(make_mat4([
4404            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,
4405        ]))
4406    });
4407
4408    // mat4_rotate_x(angle) - rotation around X axis
4409    define(interp, "mat4_rotate_x", Some(1), |_, args| {
4410        let angle = extract_number(&args[0], "mat4_rotate_x")?;
4411        let (s, c) = angle.sin_cos();
4412        Ok(make_mat4([
4413            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,
4414        ]))
4415    });
4416
4417    // mat4_rotate_y(angle) - rotation around Y axis
4418    define(interp, "mat4_rotate_y", Some(1), |_, args| {
4419        let angle = extract_number(&args[0], "mat4_rotate_y")?;
4420        let (s, c) = angle.sin_cos();
4421        Ok(make_mat4([
4422            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,
4423        ]))
4424    });
4425
4426    // mat4_rotate_z(angle) - rotation around Z axis
4427    define(interp, "mat4_rotate_z", Some(1), |_, args| {
4428        let angle = extract_number(&args[0], "mat4_rotate_z")?;
4429        let (s, c) = angle.sin_cos();
4430        Ok(make_mat4([
4431            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,
4432        ]))
4433    });
4434
4435    // mat4_perspective(fov_y, aspect, near, far) - perspective projection
4436    define(interp, "mat4_perspective", Some(4), |_, args| {
4437        let fov_y = extract_number(&args[0], "mat4_perspective")?;
4438        let aspect = extract_number(&args[1], "mat4_perspective")?;
4439        let near = extract_number(&args[2], "mat4_perspective")?;
4440        let far = extract_number(&args[3], "mat4_perspective")?;
4441
4442        let f = 1.0 / (fov_y / 2.0).tan();
4443        let nf = 1.0 / (near - far);
4444
4445        Ok(make_mat4([
4446            f / aspect,
4447            0.0,
4448            0.0,
4449            0.0,
4450            0.0,
4451            f,
4452            0.0,
4453            0.0,
4454            0.0,
4455            0.0,
4456            (far + near) * nf,
4457            -1.0,
4458            0.0,
4459            0.0,
4460            2.0 * far * near * nf,
4461            0.0,
4462        ]))
4463    });
4464
4465    // mat4_ortho(left, right, bottom, top, near, far) - orthographic projection
4466    define(interp, "mat4_ortho", Some(6), |_, args| {
4467        let left = extract_number(&args[0], "mat4_ortho")?;
4468        let right = extract_number(&args[1], "mat4_ortho")?;
4469        let bottom = extract_number(&args[2], "mat4_ortho")?;
4470        let top = extract_number(&args[3], "mat4_ortho")?;
4471        let near = extract_number(&args[4], "mat4_ortho")?;
4472        let far = extract_number(&args[5], "mat4_ortho")?;
4473
4474        let lr = 1.0 / (left - right);
4475        let bt = 1.0 / (bottom - top);
4476        let nf = 1.0 / (near - far);
4477
4478        Ok(make_mat4([
4479            -2.0 * lr,
4480            0.0,
4481            0.0,
4482            0.0,
4483            0.0,
4484            -2.0 * bt,
4485            0.0,
4486            0.0,
4487            0.0,
4488            0.0,
4489            2.0 * nf,
4490            0.0,
4491            (left + right) * lr,
4492            (top + bottom) * bt,
4493            (far + near) * nf,
4494            1.0,
4495        ]))
4496    });
4497
4498    // mat4_look_at(eye, center, up) - view matrix (camera)
4499    define(interp, "mat4_look_at", Some(3), |_, args| {
4500        let eye = extract_vec3(&args[0], "mat4_look_at")?;
4501        let center = extract_vec3(&args[1], "mat4_look_at")?;
4502        let up = extract_vec3(&args[2], "mat4_look_at")?;
4503
4504        // Forward vector (z)
4505        let fx = center[0] - eye[0];
4506        let fy = center[1] - eye[1];
4507        let fz = center[2] - eye[2];
4508        let flen = (fx * fx + fy * fy + fz * fz).sqrt();
4509        let (fx, fy, fz) = (fx / flen, fy / flen, fz / flen);
4510
4511        // Right vector (x) = forward × up
4512        let rx = fy * up[2] - fz * up[1];
4513        let ry = fz * up[0] - fx * up[2];
4514        let rz = fx * up[1] - fy * up[0];
4515        let rlen = (rx * rx + ry * ry + rz * rz).sqrt();
4516        let (rx, ry, rz) = (rx / rlen, ry / rlen, rz / rlen);
4517
4518        // True up vector (y) = right × forward
4519        let ux = ry * fz - rz * fy;
4520        let uy = rz * fx - rx * fz;
4521        let uz = rx * fy - ry * fx;
4522
4523        Ok(make_mat4([
4524            rx,
4525            ux,
4526            -fx,
4527            0.0,
4528            ry,
4529            uy,
4530            -fy,
4531            0.0,
4532            rz,
4533            uz,
4534            -fz,
4535            0.0,
4536            -(rx * eye[0] + ry * eye[1] + rz * eye[2]),
4537            -(ux * eye[0] + uy * eye[1] + uz * eye[2]),
4538            -(-fx * eye[0] - fy * eye[1] - fz * eye[2]),
4539            1.0,
4540        ]))
4541    });
4542
4543    // mat4_inverse(m) - matrix inverse (for transformation matrices)
4544    define(interp, "mat4_inverse", Some(1), |_, args| {
4545        let m = extract_mat4(&args[0], "mat4_inverse")?;
4546
4547        // Optimized 4x4 matrix inverse using cofactors
4548        let a00 = m[0];
4549        let a01 = m[1];
4550        let a02 = m[2];
4551        let a03 = m[3];
4552        let a10 = m[4];
4553        let a11 = m[5];
4554        let a12 = m[6];
4555        let a13 = m[7];
4556        let a20 = m[8];
4557        let a21 = m[9];
4558        let a22 = m[10];
4559        let a23 = m[11];
4560        let a30 = m[12];
4561        let a31 = m[13];
4562        let a32 = m[14];
4563        let a33 = m[15];
4564
4565        let b00 = a00 * a11 - a01 * a10;
4566        let b01 = a00 * a12 - a02 * a10;
4567        let b02 = a00 * a13 - a03 * a10;
4568        let b03 = a01 * a12 - a02 * a11;
4569        let b04 = a01 * a13 - a03 * a11;
4570        let b05 = a02 * a13 - a03 * a12;
4571        let b06 = a20 * a31 - a21 * a30;
4572        let b07 = a20 * a32 - a22 * a30;
4573        let b08 = a20 * a33 - a23 * a30;
4574        let b09 = a21 * a32 - a22 * a31;
4575        let b10 = a21 * a33 - a23 * a31;
4576        let b11 = a22 * a33 - a23 * a32;
4577
4578        let det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
4579
4580        if det.abs() < 1e-10 {
4581            return Err(RuntimeError::new("mat4_inverse: singular matrix"));
4582        }
4583
4584        let inv_det = 1.0 / det;
4585
4586        Ok(make_mat4([
4587            (a11 * b11 - a12 * b10 + a13 * b09) * inv_det,
4588            (a02 * b10 - a01 * b11 - a03 * b09) * inv_det,
4589            (a31 * b05 - a32 * b04 + a33 * b03) * inv_det,
4590            (a22 * b04 - a21 * b05 - a23 * b03) * inv_det,
4591            (a12 * b08 - a10 * b11 - a13 * b07) * inv_det,
4592            (a00 * b11 - a02 * b08 + a03 * b07) * inv_det,
4593            (a32 * b02 - a30 * b05 - a33 * b01) * inv_det,
4594            (a20 * b05 - a22 * b02 + a23 * b01) * inv_det,
4595            (a10 * b10 - a11 * b08 + a13 * b06) * inv_det,
4596            (a01 * b08 - a00 * b10 - a03 * b06) * inv_det,
4597            (a30 * b04 - a31 * b02 + a33 * b00) * inv_det,
4598            (a21 * b02 - a20 * b04 - a23 * b00) * inv_det,
4599            (a11 * b07 - a10 * b09 - a12 * b06) * inv_det,
4600            (a00 * b09 - a01 * b07 + a02 * b06) * inv_det,
4601            (a31 * b01 - a30 * b03 - a32 * b00) * inv_det,
4602            (a20 * b03 - a21 * b01 + a22 * b00) * inv_det,
4603        ]))
4604    });
4605
4606    // mat4_transpose(m) - transpose matrix
4607    define(interp, "mat4_transpose", Some(1), |_, args| {
4608        let m = extract_mat4(&args[0], "mat4_transpose")?;
4609        Ok(make_mat4([
4610            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],
4611            m[11], m[15],
4612        ]))
4613    });
4614
4615    // -------------------------------------------------------------------------
4616    // MAT3 - 3x3 MATRICES (for normals, 2D transforms)
4617    // -------------------------------------------------------------------------
4618
4619    // mat3_identity() - 3x3 identity matrix
4620    define(interp, "mat3_identity", Some(0), |_, _| {
4621        Ok(make_mat3([1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0]))
4622    });
4623
4624    // mat3_from_mat4(m) - extract upper-left 3x3 from 4x4 (for normal matrix)
4625    define(interp, "mat3_from_mat4", Some(1), |_, args| {
4626        let m = extract_mat4(&args[0], "mat3_from_mat4")?;
4627        Ok(make_mat3([
4628            m[0], m[1], m[2], m[4], m[5], m[6], m[8], m[9], m[10],
4629        ]))
4630    });
4631
4632    // mat3_mul(a, b) - 3x3 matrix multiplication
4633    define(interp, "mat3_mul", Some(2), |_, args| {
4634        let a = extract_mat3(&args[0], "mat3_mul")?;
4635        let b = extract_mat3(&args[1], "mat3_mul")?;
4636
4637        let mut result = [0.0f64; 9];
4638        for col in 0..3 {
4639            for row in 0..3 {
4640                let mut sum = 0.0;
4641                for k in 0..3 {
4642                    sum += a[k * 3 + row] * b[col * 3 + k];
4643                }
4644                result[col * 3 + row] = sum;
4645            }
4646        }
4647        Ok(make_mat3(result))
4648    });
4649
4650    // mat3_transform(mat3, vec3) - transform 3D vector by 3x3 matrix
4651    define(interp, "mat3_transform", Some(2), |_, args| {
4652        let m = extract_mat3(&args[0], "mat3_transform")?;
4653        let v = extract_vec3(&args[1], "mat3_transform")?;
4654
4655        Ok(make_vec3(
4656            m[0] * v[0] + m[3] * v[1] + m[6] * v[2],
4657            m[1] * v[0] + m[4] * v[1] + m[7] * v[2],
4658            m[2] * v[0] + m[5] * v[1] + m[8] * v[2],
4659        ))
4660    });
4661
4662    // mat3_inverse(m) - 3x3 matrix inverse
4663    define(interp, "mat3_inverse", Some(1), |_, args| {
4664        let m = extract_mat3(&args[0], "mat3_inverse")?;
4665
4666        let det = m[0] * (m[4] * m[8] - m[5] * m[7]) - m[3] * (m[1] * m[8] - m[2] * m[7])
4667            + m[6] * (m[1] * m[5] - m[2] * m[4]);
4668
4669        if det.abs() < 1e-10 {
4670            return Err(RuntimeError::new("mat3_inverse: singular matrix"));
4671        }
4672
4673        let inv_det = 1.0 / det;
4674
4675        Ok(make_mat3([
4676            (m[4] * m[8] - m[5] * m[7]) * inv_det,
4677            (m[2] * m[7] - m[1] * m[8]) * inv_det,
4678            (m[1] * m[5] - m[2] * m[4]) * inv_det,
4679            (m[5] * m[6] - m[3] * m[8]) * inv_det,
4680            (m[0] * m[8] - m[2] * m[6]) * inv_det,
4681            (m[2] * m[3] - m[0] * m[5]) * inv_det,
4682            (m[3] * m[7] - m[4] * m[6]) * inv_det,
4683            (m[1] * m[6] - m[0] * m[7]) * inv_det,
4684            (m[0] * m[4] - m[1] * m[3]) * inv_det,
4685        ]))
4686    });
4687
4688    // mat3_transpose(m)
4689    define(interp, "mat3_transpose", Some(1), |_, args| {
4690        let m = extract_mat3(&args[0], "mat3_transpose")?;
4691        Ok(make_mat3([
4692            m[0], m[3], m[6], m[1], m[4], m[7], m[2], m[5], m[8],
4693        ]))
4694    });
4695}
4696
4697// Helper functions for graphics math
4698fn extract_number(v: &Value, fn_name: &str) -> Result<f64, RuntimeError> {
4699    match v {
4700        Value::Float(f) => Ok(*f),
4701        Value::Int(i) => Ok(*i as f64),
4702        _ => Err(RuntimeError::new(format!(
4703            "{}() requires number argument",
4704            fn_name
4705        ))),
4706    }
4707}
4708
4709fn extract_vec2(v: &Value, fn_name: &str) -> Result<[f64; 2], RuntimeError> {
4710    match v {
4711        Value::Array(arr) => {
4712            let arr = arr.borrow();
4713            if arr.len() < 2 {
4714                return Err(RuntimeError::new(format!(
4715                    "{}() requires vec2 (2 elements)",
4716                    fn_name
4717                )));
4718            }
4719            Ok([
4720                extract_number(&arr[0], fn_name)?,
4721                extract_number(&arr[1], fn_name)?,
4722            ])
4723        }
4724        _ => Err(RuntimeError::new(format!(
4725            "{}() requires vec2 array",
4726            fn_name
4727        ))),
4728    }
4729}
4730
4731fn extract_vec3(v: &Value, fn_name: &str) -> Result<[f64; 3], RuntimeError> {
4732    match v {
4733        Value::Array(arr) => {
4734            let arr = arr.borrow();
4735            if arr.len() < 3 {
4736                return Err(RuntimeError::new(format!(
4737                    "{}() requires vec3 (3 elements)",
4738                    fn_name
4739                )));
4740            }
4741            Ok([
4742                extract_number(&arr[0], fn_name)?,
4743                extract_number(&arr[1], fn_name)?,
4744                extract_number(&arr[2], fn_name)?,
4745            ])
4746        }
4747        _ => Err(RuntimeError::new(format!(
4748            "{}() requires vec3 array",
4749            fn_name
4750        ))),
4751    }
4752}
4753
4754fn extract_vec4(v: &Value, fn_name: &str) -> Result<[f64; 4], RuntimeError> {
4755    match v {
4756        Value::Array(arr) => {
4757            let arr = arr.borrow();
4758            if arr.len() < 4 {
4759                return Err(RuntimeError::new(format!(
4760                    "{}() requires vec4 (4 elements)",
4761                    fn_name
4762                )));
4763            }
4764            Ok([
4765                extract_number(&arr[0], fn_name)?,
4766                extract_number(&arr[1], fn_name)?,
4767                extract_number(&arr[2], fn_name)?,
4768                extract_number(&arr[3], fn_name)?,
4769            ])
4770        }
4771        _ => Err(RuntimeError::new(format!(
4772            "{}() requires vec4 array",
4773            fn_name
4774        ))),
4775    }
4776}
4777
4778fn extract_mat3(v: &Value, fn_name: &str) -> Result<[f64; 9], RuntimeError> {
4779    match v {
4780        Value::Array(arr) => {
4781            let arr = arr.borrow();
4782            if arr.len() < 9 {
4783                return Err(RuntimeError::new(format!(
4784                    "{}() requires mat3 (9 elements)",
4785                    fn_name
4786                )));
4787            }
4788            let mut result = [0.0f64; 9];
4789            for i in 0..9 {
4790                result[i] = extract_number(&arr[i], fn_name)?;
4791            }
4792            Ok(result)
4793        }
4794        _ => Err(RuntimeError::new(format!(
4795            "{}() requires mat3 array",
4796            fn_name
4797        ))),
4798    }
4799}
4800
4801fn extract_mat4(v: &Value, fn_name: &str) -> Result<[f64; 16], RuntimeError> {
4802    match v {
4803        Value::Array(arr) => {
4804            let arr = arr.borrow();
4805            if arr.len() < 16 {
4806                return Err(RuntimeError::new(format!(
4807                    "{}() requires mat4 (16 elements)",
4808                    fn_name
4809                )));
4810            }
4811            let mut result = [0.0f64; 16];
4812            for i in 0..16 {
4813                result[i] = extract_number(&arr[i], fn_name)?;
4814            }
4815            Ok(result)
4816        }
4817        _ => Err(RuntimeError::new(format!(
4818            "{}() requires mat4 array",
4819            fn_name
4820        ))),
4821    }
4822}
4823
4824fn make_vec2(x: f64, y: f64) -> Value {
4825    Value::Array(Rc::new(RefCell::new(vec![
4826        Value::Float(x),
4827        Value::Float(y),
4828    ])))
4829}
4830
4831fn make_vec3(x: f64, y: f64, z: f64) -> Value {
4832    Value::Array(Rc::new(RefCell::new(vec![
4833        Value::Float(x),
4834        Value::Float(y),
4835        Value::Float(z),
4836    ])))
4837}
4838
4839// Helper for making vec3 from array
4840fn make_vec3_arr(v: [f64; 3]) -> Value {
4841    make_vec3(v[0], v[1], v[2])
4842}
4843
4844fn make_vec4(x: f64, y: f64, z: f64, w: f64) -> Value {
4845    Value::Array(Rc::new(RefCell::new(vec![
4846        Value::Float(x),
4847        Value::Float(y),
4848        Value::Float(z),
4849        Value::Float(w),
4850    ])))
4851}
4852
4853fn make_mat3(m: [f64; 9]) -> Value {
4854    Value::Array(Rc::new(RefCell::new(
4855        m.iter().map(|&v| Value::Float(v)).collect(),
4856    )))
4857}
4858
4859fn make_mat4(m: [f64; 16]) -> Value {
4860    Value::Array(Rc::new(RefCell::new(
4861        m.iter().map(|&v| Value::Float(v)).collect(),
4862    )))
4863}
4864
4865// ============================================================================
4866// CONCURRENCY FUNCTIONS
4867// ============================================================================
4868// WARNING: Interpreter Limitations
4869// ---------------------------------
4870// The interpreter uses Rc<RefCell<>> which is NOT thread-safe (not Send/Sync).
4871// This means:
4872// - Channels work but block the main thread
4873// - Actors run single-threaded with message queuing
4874// - Thread primitives simulate behavior but don't provide true parallelism
4875// - Atomics work correctly for single-threaded access patterns
4876//
4877// For true parallel execution, compile with the JIT backend (--jit flag).
4878// The JIT uses Arc/Mutex and compiles to native code with proper threading.
4879// ============================================================================
4880
4881fn register_concurrency(interp: &mut Interpreter) {
4882    // --- CHANNELS ---
4883
4884    // channel_new - create a new channel for message passing
4885    define(interp, "channel_new", Some(0), |_, _| {
4886        let (sender, receiver) = mpsc::channel();
4887        let inner = ChannelInner {
4888            sender: Mutex::new(sender),
4889            receiver: Mutex::new(receiver),
4890        };
4891        Ok(Value::Channel(Arc::new(inner)))
4892    });
4893
4894    // channel_send - send a value on a channel (blocking)
4895    define(interp, "channel_send", Some(2), |_, args| {
4896        let channel = match &args[0] {
4897            Value::Channel(ch) => ch.clone(),
4898            _ => {
4899                return Err(RuntimeError::new(
4900                    "channel_send() requires channel as first argument",
4901                ))
4902            }
4903        };
4904        let value = args[1].clone();
4905
4906        let sender = channel
4907            .sender
4908            .lock()
4909            .map_err(|_| RuntimeError::new("channel mutex poisoned"))?;
4910        sender
4911            .send(value)
4912            .map_err(|_| RuntimeError::new("channel_send() failed: receiver dropped"))?;
4913
4914        Ok(Value::Null)
4915    });
4916
4917    // channel_recv - receive a value from a channel (blocking)
4918    define(interp, "channel_recv", Some(1), |_, args| {
4919        let channel = match &args[0] {
4920            Value::Channel(ch) => ch.clone(),
4921            _ => {
4922                return Err(RuntimeError::new(
4923                    "channel_recv() requires channel argument",
4924                ))
4925            }
4926        };
4927
4928        let receiver = channel
4929            .receiver
4930            .lock()
4931            .map_err(|_| RuntimeError::new("channel mutex poisoned"))?;
4932        match receiver.recv() {
4933            Ok(value) => Ok(value),
4934            Err(_) => Err(RuntimeError::new("channel_recv() failed: sender dropped")),
4935        }
4936    });
4937
4938    // channel_try_recv - non-blocking receive, returns Option
4939    define(interp, "channel_try_recv", Some(1), |_, args| {
4940        let channel = match &args[0] {
4941            Value::Channel(ch) => ch.clone(),
4942            _ => {
4943                return Err(RuntimeError::new(
4944                    "channel_try_recv() requires channel argument",
4945                ))
4946            }
4947        };
4948
4949        let receiver = channel
4950            .receiver
4951            .lock()
4952            .map_err(|_| RuntimeError::new("channel mutex poisoned"))?;
4953        match receiver.try_recv() {
4954            Ok(value) => {
4955                // Return Some(value) as a variant
4956                Ok(Value::Variant {
4957                    enum_name: "Option".to_string(),
4958                    variant_name: "Some".to_string(),
4959                    fields: Some(Rc::new(vec![value])),
4960                })
4961            }
4962            Err(mpsc::TryRecvError::Empty) => {
4963                // Return None
4964                Ok(Value::Variant {
4965                    enum_name: "Option".to_string(),
4966                    variant_name: "None".to_string(),
4967                    fields: None,
4968                })
4969            }
4970            Err(mpsc::TryRecvError::Disconnected) => Err(RuntimeError::new(
4971                "channel_try_recv() failed: sender dropped",
4972            )),
4973        }
4974    });
4975
4976    // channel_recv_timeout - receive with timeout in milliseconds
4977    define(interp, "channel_recv_timeout", Some(2), |_, args| {
4978        let channel = match &args[0] {
4979            Value::Channel(ch) => ch.clone(),
4980            _ => {
4981                return Err(RuntimeError::new(
4982                    "channel_recv_timeout() requires a channel as first argument.\n\
4983                 Create a channel with channel_new():\n\
4984                   let ch = channel_new();\n\
4985                   channel_send(ch, value);\n\
4986                   let result = channel_recv_timeout(ch, 1000);  // 1 second timeout",
4987                ))
4988            }
4989        };
4990        let timeout_ms = match &args[1] {
4991            Value::Int(ms) => *ms as u64,
4992            _ => {
4993                return Err(RuntimeError::new(
4994                    "channel_recv_timeout() requires timeout in milliseconds (integer).\n\
4995                 Example: channel_recv_timeout(ch, 1000)  // Wait up to 1 second",
4996                ))
4997            }
4998        };
4999
5000        let receiver = channel
5001            .receiver
5002            .lock()
5003            .map_err(|_| RuntimeError::new("channel mutex poisoned"))?;
5004        match receiver.recv_timeout(std::time::Duration::from_millis(timeout_ms)) {
5005            Ok(value) => Ok(Value::Variant {
5006                enum_name: "Option".to_string(),
5007                variant_name: "Some".to_string(),
5008                fields: Some(Rc::new(vec![value])),
5009            }),
5010            Err(mpsc::RecvTimeoutError::Timeout) => Ok(Value::Variant {
5011                enum_name: "Option".to_string(),
5012                variant_name: "None".to_string(),
5013                fields: None,
5014            }),
5015            Err(mpsc::RecvTimeoutError::Disconnected) => Err(RuntimeError::new(
5016                "channel_recv_timeout() failed: sender dropped",
5017            )),
5018        }
5019    });
5020
5021    // --- THREADS ---
5022    // Note: The interpreter's Value type uses Rc which is not Send.
5023    // For true threading, use channels to communicate primitive types.
5024    // These functions provide basic thread primitives.
5025
5026    // thread_spawn_detached - spawn a detached thread (no join)
5027    // Useful for background work, results communicated via channels
5028    define(interp, "thread_spawn_detached", Some(0), |_, _| {
5029        // Spawn a simple detached thread that does nothing
5030        // Real work should be done via channels
5031        thread::spawn(|| {
5032            // Background thread
5033        });
5034        Ok(Value::Null)
5035    });
5036
5037    // thread_join - placeholder for join semantics
5038    // In interpreter, actual work is done via channels
5039    define(interp, "thread_join", Some(1), |_, args| {
5040        match &args[0] {
5041            Value::ThreadHandle(h) => {
5042                let mut guard = h
5043                    .lock()
5044                    .map_err(|_| RuntimeError::new("thread handle mutex poisoned"))?;
5045                if let Some(handle) = guard.take() {
5046                    match handle.join() {
5047                        Ok(v) => Ok(v),
5048                        Err(_) => Err(RuntimeError::new("thread panicked")),
5049                    }
5050                } else {
5051                    Err(RuntimeError::new("thread already joined"))
5052                }
5053            }
5054            // For non-handles, just return the value
5055            _ => Ok(args[0].clone()),
5056        }
5057    });
5058
5059    // thread_sleep - sleep for specified milliseconds
5060    define(interp, "thread_sleep", Some(1), |_, args| {
5061        let ms = match &args[0] {
5062            Value::Int(ms) => *ms as u64,
5063            Value::Float(ms) => *ms as u64,
5064            _ => {
5065                return Err(RuntimeError::new(
5066                    "thread_sleep() requires integer milliseconds",
5067                ))
5068            }
5069        };
5070
5071        thread::sleep(std::time::Duration::from_millis(ms));
5072        Ok(Value::Null)
5073    });
5074
5075    // thread_yield - yield the current thread
5076    define(interp, "thread_yield", Some(0), |_, _| {
5077        thread::yield_now();
5078        Ok(Value::Null)
5079    });
5080
5081    // thread_id - get current thread id as string
5082    define(interp, "thread_id", Some(0), |_, _| {
5083        let id = thread::current().id();
5084        Ok(Value::String(Rc::new(format!("{:?}", id))))
5085    });
5086
5087    // --- ACTORS ---
5088    // Single-threaded actor model for the interpreter.
5089    // Messages are queued and processed synchronously.
5090    // For true async actors with background threads, use the JIT backend.
5091
5092    // spawn_actor - create a new actor with given name
5093    define(interp, "spawn_actor", Some(1), |_, args| {
5094        let name = match &args[0] {
5095            Value::String(s) => s.to_string(),
5096            _ => return Err(RuntimeError::new("actor_spawn() requires string name")),
5097        };
5098
5099        let inner = ActorInner {
5100            name,
5101            message_queue: Mutex::new(Vec::new()),
5102            message_count: std::sync::atomic::AtomicUsize::new(0),
5103        };
5104
5105        Ok(Value::Actor(Arc::new(inner)))
5106    });
5107
5108    // send_to_actor - send a message to an actor
5109    // Messages are queued for later processing
5110    define(interp, "send_to_actor", Some(3), |_, args| {
5111        let actor = match &args[0] {
5112            Value::Actor(a) => a.clone(),
5113            _ => {
5114                return Err(RuntimeError::new(
5115                    "actor_send() requires actor as first argument",
5116                ))
5117            }
5118        };
5119        let msg_type = match &args[1] {
5120            Value::String(s) => s.to_string(),
5121            _ => {
5122                return Err(RuntimeError::new(
5123                    "actor_send() requires string message type",
5124                ))
5125            }
5126        };
5127        let msg_data = format!("{}", args[2]);
5128
5129        let mut queue = actor
5130            .message_queue
5131            .lock()
5132            .map_err(|_| RuntimeError::new("actor queue poisoned"))?;
5133        queue.push((msg_type, msg_data));
5134        actor
5135            .message_count
5136            .fetch_add(1, std::sync::atomic::Ordering::SeqCst);
5137
5138        Ok(Value::Null)
5139    });
5140
5141    // tell_actor - alias for send_to_actor (Erlang/Akka style)
5142    define(interp, "tell_actor", Some(3), |_, args| {
5143        let actor = match &args[0] {
5144            Value::Actor(a) => a.clone(),
5145            _ => {
5146                return Err(RuntimeError::new(
5147                    "actor_tell() requires actor as first argument",
5148                ))
5149            }
5150        };
5151        let msg_type = match &args[1] {
5152            Value::String(s) => s.to_string(),
5153            _ => {
5154                return Err(RuntimeError::new(
5155                    "actor_tell() requires string message type",
5156                ))
5157            }
5158        };
5159        let msg_data = format!("{}", args[2]);
5160
5161        let mut queue = actor
5162            .message_queue
5163            .lock()
5164            .map_err(|_| RuntimeError::new("actor queue poisoned"))?;
5165        queue.push((msg_type, msg_data));
5166        actor
5167            .message_count
5168            .fetch_add(1, std::sync::atomic::Ordering::SeqCst);
5169
5170        Ok(Value::Null)
5171    });
5172
5173    // recv_from_actor - receive (pop) a message from the actor's queue
5174    // Returns Option<(type, data)>
5175    define(interp, "recv_from_actor", Some(1), |_, args| {
5176        let actor = match &args[0] {
5177            Value::Actor(a) => a.clone(),
5178            _ => return Err(RuntimeError::new("actor_recv() requires actor argument")),
5179        };
5180
5181        let mut queue = actor
5182            .message_queue
5183            .lock()
5184            .map_err(|_| RuntimeError::new("actor queue poisoned"))?;
5185        match queue.pop() {
5186            Some((msg_type, msg_data)) => {
5187                // Return Some((type, data))
5188                Ok(Value::Variant {
5189                    enum_name: "Option".to_string(),
5190                    variant_name: "Some".to_string(),
5191                    fields: Some(Rc::new(vec![Value::Tuple(Rc::new(vec![
5192                        Value::String(Rc::new(msg_type)),
5193                        Value::String(Rc::new(msg_data)),
5194                    ]))])),
5195                })
5196            }
5197            None => Ok(Value::Variant {
5198                enum_name: "Option".to_string(),
5199                variant_name: "None".to_string(),
5200                fields: None,
5201            }),
5202        }
5203    });
5204
5205    // get_actor_msg_count - get total messages ever sent to actor
5206    define(interp, "get_actor_msg_count", Some(1), |_, args| {
5207        let a = match &args[0] {
5208            Value::Actor(a) => a.clone(),
5209            _ => {
5210                return Err(RuntimeError::new(
5211                    "get_actor_msg_count() requires actor argument",
5212                ))
5213            }
5214        };
5215
5216        let count = a.message_count.load(std::sync::atomic::Ordering::SeqCst);
5217        Ok(Value::Int(count as i64))
5218    });
5219
5220    // get_actor_name - get actor's name
5221    define(interp, "get_actor_name", Some(1), |_, args| {
5222        let a = match &args[0] {
5223            Value::Actor(a) => a.clone(),
5224            _ => {
5225                return Err(RuntimeError::new(
5226                    "get_actor_name() requires actor argument",
5227                ))
5228            }
5229        };
5230
5231        Ok(Value::String(Rc::new(a.name.clone())))
5232    });
5233
5234    // get_actor_pending - get number of pending messages
5235    define(interp, "get_actor_pending", Some(1), |_, args| {
5236        let a = match &args[0] {
5237            Value::Actor(a) => a.clone(),
5238            _ => {
5239                return Err(RuntimeError::new(
5240                    "get_actor_pending() requires actor argument",
5241                ))
5242            }
5243        };
5244
5245        let queue = a
5246            .message_queue
5247            .lock()
5248            .map_err(|_| RuntimeError::new("actor queue poisoned"))?;
5249        Ok(Value::Int(queue.len() as i64))
5250    });
5251
5252    // --- SYNCHRONIZATION PRIMITIVES ---
5253
5254    // mutex_new - create a new mutex wrapping a value
5255    define(interp, "mutex_new", Some(1), |_, args| {
5256        let value = args[0].clone();
5257        // Store as a Map with special key for mutex semantics
5258        let mut map = std::collections::HashMap::new();
5259        map.insert("__mutex_value".to_string(), value);
5260        map.insert("__mutex_locked".to_string(), Value::Bool(false));
5261        Ok(Value::Map(Rc::new(RefCell::new(map))))
5262    });
5263
5264    // mutex_lock - lock a mutex and get the value
5265    define(interp, "mutex_lock", Some(1), |_, args| {
5266        let mutex = match &args[0] {
5267            Value::Map(m) => m.clone(),
5268            _ => return Err(RuntimeError::new("mutex_lock() requires mutex")),
5269        };
5270
5271        let mut map = mutex.borrow_mut();
5272        // Simple spin-wait for interpreter (not true mutex, but demonstrates concept)
5273        map.insert("__mutex_locked".to_string(), Value::Bool(true));
5274
5275        match map.get("__mutex_value") {
5276            Some(v) => Ok(v.clone()),
5277            None => Err(RuntimeError::new("invalid mutex")),
5278        }
5279    });
5280
5281    // mutex_unlock - unlock a mutex, optionally setting new value
5282    define(interp, "mutex_unlock", Some(2), |_, args| {
5283        let mutex = match &args[0] {
5284            Value::Map(m) => m.clone(),
5285            _ => return Err(RuntimeError::new("mutex_unlock() requires mutex")),
5286        };
5287        let new_value = args[1].clone();
5288
5289        let mut map = mutex.borrow_mut();
5290        map.insert("__mutex_value".to_string(), new_value);
5291        map.insert("__mutex_locked".to_string(), Value::Bool(false));
5292
5293        Ok(Value::Null)
5294    });
5295
5296    // atomic_new - create an atomic integer
5297    define(interp, "atomic_new", Some(1), |_, args| {
5298        let value = match &args[0] {
5299            Value::Int(i) => *i,
5300            _ => return Err(RuntimeError::new("atomic_new() requires integer")),
5301        };
5302
5303        // Wrap in Map with atomic semantics
5304        let mut map = std::collections::HashMap::new();
5305        map.insert("__atomic_value".to_string(), Value::Int(value));
5306        Ok(Value::Map(Rc::new(RefCell::new(map))))
5307    });
5308
5309    // atomic_load - atomically load value
5310    define(interp, "atomic_load", Some(1), |_, args| {
5311        let atomic = match &args[0] {
5312            Value::Map(m) => m.clone(),
5313            _ => return Err(RuntimeError::new("atomic_load() requires atomic")),
5314        };
5315
5316        let map = atomic.borrow();
5317        match map.get("__atomic_value") {
5318            Some(v) => Ok(v.clone()),
5319            None => Err(RuntimeError::new("invalid atomic")),
5320        }
5321    });
5322
5323    // atomic_store - atomically store value
5324    define(interp, "atomic_store", Some(2), |_, args| {
5325        let atomic = match &args[0] {
5326            Value::Map(m) => m.clone(),
5327            _ => return Err(RuntimeError::new("atomic_store() requires atomic")),
5328        };
5329        let value = match &args[1] {
5330            Value::Int(i) => *i,
5331            _ => return Err(RuntimeError::new("atomic_store() requires integer value")),
5332        };
5333
5334        let mut map = atomic.borrow_mut();
5335        map.insert("__atomic_value".to_string(), Value::Int(value));
5336        Ok(Value::Null)
5337    });
5338
5339    // atomic_add - atomically add and return old value
5340    define(interp, "atomic_add", Some(2), |_, args| {
5341        let atomic = match &args[0] {
5342            Value::Map(m) => m.clone(),
5343            _ => return Err(RuntimeError::new("atomic_add() requires atomic")),
5344        };
5345        let delta = match &args[1] {
5346            Value::Int(i) => *i,
5347            _ => return Err(RuntimeError::new("atomic_add() requires integer delta")),
5348        };
5349
5350        let mut map = atomic.borrow_mut();
5351        let old = match map.get("__atomic_value") {
5352            Some(Value::Int(i)) => *i,
5353            _ => return Err(RuntimeError::new("invalid atomic")),
5354        };
5355        map.insert("__atomic_value".to_string(), Value::Int(old + delta));
5356        Ok(Value::Int(old))
5357    });
5358
5359    // atomic_cas - compare and swap, returns bool success
5360    define(interp, "atomic_cas", Some(3), |_, args| {
5361        let atomic = match &args[0] {
5362            Value::Map(m) => m.clone(),
5363            _ => return Err(RuntimeError::new("atomic_cas() requires atomic")),
5364        };
5365        let expected = match &args[1] {
5366            Value::Int(i) => *i,
5367            _ => return Err(RuntimeError::new("atomic_cas() requires integer expected")),
5368        };
5369        let new_value = match &args[2] {
5370            Value::Int(i) => *i,
5371            _ => return Err(RuntimeError::new("atomic_cas() requires integer new value")),
5372        };
5373
5374        let mut map = atomic.borrow_mut();
5375        let current = match map.get("__atomic_value") {
5376            Some(Value::Int(i)) => *i,
5377            _ => return Err(RuntimeError::new("invalid atomic")),
5378        };
5379
5380        if current == expected {
5381            map.insert("__atomic_value".to_string(), Value::Int(new_value));
5382            Ok(Value::Bool(true))
5383        } else {
5384            Ok(Value::Bool(false))
5385        }
5386    });
5387
5388    // --- PARALLEL ITERATION ---
5389
5390    // parallel_map - map function over array in parallel (simplified)
5391    define(interp, "parallel_map", Some(2), |_, args| {
5392        let arr = match &args[0] {
5393            Value::Array(a) => a.borrow().clone(),
5394            _ => return Err(RuntimeError::new("parallel_map() requires array")),
5395        };
5396        let _func = args[1].clone();
5397
5398        // For interpreter, just return original array
5399        // Real parallelism needs thread-safe interpreter
5400        Ok(Value::Array(Rc::new(RefCell::new(arr))))
5401    });
5402
5403    // parallel_for - parallel for loop (simplified)
5404    define(interp, "parallel_for", Some(3), |_, args| {
5405        let start = match &args[0] {
5406            Value::Int(i) => *i,
5407            _ => return Err(RuntimeError::new("parallel_for() requires integer start")),
5408        };
5409        let end = match &args[1] {
5410            Value::Int(i) => *i,
5411            _ => return Err(RuntimeError::new("parallel_for() requires integer end")),
5412        };
5413        let _func = args[2].clone();
5414
5415        // For interpreter, execute sequentially
5416        // Returns range as array
5417        let range: Vec<Value> = (start..end).map(|i| Value::Int(i)).collect();
5418        Ok(Value::Array(Rc::new(RefCell::new(range))))
5419    });
5420
5421    // ============================================================================
5422    // ASYNC/AWAIT FUNCTIONS
5423    // ============================================================================
5424    // WARNING: Interpreter Blocking Behavior
5425    // --------------------------------------
5426    // In the interpreter, async operations use cooperative scheduling but
5427    // execute on the main thread. This means:
5428    // - async_sleep() blocks the interpreter for the specified duration
5429    // - await() polls futures but may block waiting for completion
5430    // - No true concurrent I/O - operations execute sequentially
5431    // - Future combinators (race, all) work but don't provide parallelism
5432    //
5433    // The async model is designed for composability and clean code structure.
5434    // For non-blocking async with true concurrency, use the JIT backend.
5435    // ============================================================================
5436
5437    // async_sleep - create a future that completes after specified milliseconds
5438    define(interp, "async_sleep", Some(1), |interp, args| {
5439        let ms = match &args[0] {
5440            Value::Int(ms) => *ms as u64,
5441            Value::Float(ms) => *ms as u64,
5442            _ => {
5443                return Err(RuntimeError::new(
5444                    "async_sleep() requires integer milliseconds",
5445                ))
5446            }
5447        };
5448
5449        Ok(interp.make_future_timer(std::time::Duration::from_millis(ms)))
5450    });
5451
5452    // future_ready - create an immediately resolved future
5453    define(interp, "future_ready", Some(1), |interp, args| {
5454        Ok(interp.make_future_immediate(args[0].clone()))
5455    });
5456
5457    // future_pending - create a pending future (never resolves)
5458    define(interp, "future_pending", Some(0), |_, _| {
5459        Ok(Value::Future(Rc::new(RefCell::new(
5460            crate::interpreter::FutureInner {
5461                state: crate::interpreter::FutureState::Pending,
5462                computation: None,
5463                complete_at: None,
5464            },
5465        ))))
5466    });
5467
5468    // is_future - check if a value is a future
5469    define(interp, "is_future", Some(1), |_, args| {
5470        Ok(Value::Bool(matches!(&args[0], Value::Future(_))))
5471    });
5472
5473    // is_ready - check if a future is ready
5474    define(interp, "is_ready", Some(1), |_, args| {
5475        match &args[0] {
5476            Value::Future(fut) => {
5477                let f = fut.borrow();
5478                Ok(Value::Bool(matches!(
5479                    f.state,
5480                    crate::interpreter::FutureState::Ready(_)
5481                )))
5482            }
5483            _ => Ok(Value::Bool(true)), // Non-futures are always "ready"
5484        }
5485    });
5486
5487    // join_futures - join multiple futures into one that resolves to array
5488    define(interp, "join_futures", Some(1), |_, args| {
5489        let futures = match &args[0] {
5490            Value::Array(arr) => {
5491                let arr = arr.borrow();
5492                let mut futs = Vec::new();
5493                for v in arr.iter() {
5494                    match v {
5495                        Value::Future(f) => futs.push(f.clone()),
5496                        _ => {
5497                            return Err(RuntimeError::new(
5498                                "join_futures() requires array of futures",
5499                            ))
5500                        }
5501                    }
5502                }
5503                futs
5504            }
5505            _ => {
5506                return Err(RuntimeError::new(
5507                    "join_futures() requires array of futures",
5508                ))
5509            }
5510        };
5511
5512        Ok(Value::Future(Rc::new(RefCell::new(
5513            crate::interpreter::FutureInner {
5514                state: crate::interpreter::FutureState::Pending,
5515                computation: Some(crate::interpreter::FutureComputation::Join(futures)),
5516                complete_at: None,
5517            },
5518        ))))
5519    });
5520
5521    // race_futures - return first future to complete
5522    define(interp, "race_futures", Some(1), |_, args| {
5523        let futures = match &args[0] {
5524            Value::Array(arr) => {
5525                let arr = arr.borrow();
5526                let mut futs = Vec::new();
5527                for v in arr.iter() {
5528                    match v {
5529                        Value::Future(f) => futs.push(f.clone()),
5530                        _ => {
5531                            return Err(RuntimeError::new(
5532                                "race_futures() requires array of futures",
5533                            ))
5534                        }
5535                    }
5536                }
5537                futs
5538            }
5539            _ => {
5540                return Err(RuntimeError::new(
5541                    "race_futures() requires array of futures",
5542                ))
5543            }
5544        };
5545
5546        Ok(Value::Future(Rc::new(RefCell::new(
5547            crate::interpreter::FutureInner {
5548                state: crate::interpreter::FutureState::Pending,
5549                computation: Some(crate::interpreter::FutureComputation::Race(futures)),
5550                complete_at: None,
5551            },
5552        ))))
5553    });
5554
5555    // poll_future - try to resolve a future without blocking (returns Option)
5556    define(interp, "poll_future", Some(1), |_, args| {
5557        match &args[0] {
5558            Value::Future(fut) => {
5559                let f = fut.borrow();
5560                match &f.state {
5561                    crate::interpreter::FutureState::Ready(v) => Ok(Value::Variant {
5562                        enum_name: "Option".to_string(),
5563                        variant_name: "Some".to_string(),
5564                        fields: Some(Rc::new(vec![(**v).clone()])),
5565                    }),
5566                    _ => Ok(Value::Variant {
5567                        enum_name: "Option".to_string(),
5568                        variant_name: "None".to_string(),
5569                        fields: None,
5570                    }),
5571                }
5572            }
5573            // Non-futures return Some(value)
5574            other => Ok(Value::Variant {
5575                enum_name: "Option".to_string(),
5576                variant_name: "Some".to_string(),
5577                fields: Some(Rc::new(vec![other.clone()])),
5578            }),
5579        }
5580    });
5581}
5582
5583// ============================================================================
5584// JSON FUNCTIONS
5585// ============================================================================
5586
5587fn register_json(interp: &mut Interpreter) {
5588    // json_parse - parse JSON string into Sigil value
5589    define(interp, "json_parse", Some(1), |_, args| {
5590        let json_str = match &args[0] {
5591            Value::String(s) => s.as_str(),
5592            _ => return Err(RuntimeError::new("json_parse() requires string argument")),
5593        };
5594
5595        fn json_to_value(json: &serde_json::Value) -> Value {
5596            match json {
5597                serde_json::Value::Null => Value::Null,
5598                serde_json::Value::Bool(b) => Value::Bool(*b),
5599                serde_json::Value::Number(n) => {
5600                    if let Some(i) = n.as_i64() {
5601                        Value::Int(i)
5602                    } else if let Some(f) = n.as_f64() {
5603                        Value::Float(f)
5604                    } else {
5605                        Value::Null
5606                    }
5607                }
5608                serde_json::Value::String(s) => Value::String(Rc::new(s.clone())),
5609                serde_json::Value::Array(arr) => {
5610                    let values: Vec<Value> = arr.iter().map(json_to_value).collect();
5611                    Value::Array(Rc::new(RefCell::new(values)))
5612                }
5613                serde_json::Value::Object(obj) => {
5614                    let mut map = HashMap::new();
5615                    for (k, v) in obj {
5616                        map.insert(k.clone(), json_to_value(v));
5617                    }
5618                    Value::Map(Rc::new(RefCell::new(map)))
5619                }
5620            }
5621        }
5622
5623        match serde_json::from_str(json_str) {
5624            Ok(json) => Ok(json_to_value(&json)),
5625            Err(e) => Err(RuntimeError::new(format!("JSON parse error: {}", e))),
5626        }
5627    });
5628
5629    // json_stringify - convert Sigil value to JSON string
5630    define(interp, "json_stringify", Some(1), |_, args| {
5631        fn value_to_json(val: &Value) -> serde_json::Value {
5632            match val {
5633                Value::Null => serde_json::Value::Null,
5634                Value::Bool(b) => serde_json::Value::Bool(*b),
5635                Value::Int(n) => serde_json::Value::Number(serde_json::Number::from(*n)),
5636                Value::Float(f) => serde_json::Number::from_f64(*f)
5637                    .map(serde_json::Value::Number)
5638                    .unwrap_or(serde_json::Value::Null),
5639                Value::String(s) => serde_json::Value::String(s.to_string()),
5640                Value::Array(arr) => {
5641                    let arr = arr.borrow();
5642                    serde_json::Value::Array(arr.iter().map(value_to_json).collect())
5643                }
5644                Value::Tuple(t) => serde_json::Value::Array(t.iter().map(value_to_json).collect()),
5645                Value::Map(map) => {
5646                    let map = map.borrow();
5647                    let obj: serde_json::Map<String, serde_json::Value> = map
5648                        .iter()
5649                        .map(|(k, v)| (k.clone(), value_to_json(v)))
5650                        .collect();
5651                    serde_json::Value::Object(obj)
5652                }
5653                Value::Struct { fields, .. } => {
5654                    let fields = fields.borrow();
5655                    let obj: serde_json::Map<String, serde_json::Value> = fields
5656                        .iter()
5657                        .map(|(k, v)| (k.clone(), value_to_json(v)))
5658                        .collect();
5659                    serde_json::Value::Object(obj)
5660                }
5661                _ => serde_json::Value::String(format!("{}", val)),
5662            }
5663        }
5664
5665        let json = value_to_json(&args[0]);
5666        Ok(Value::String(Rc::new(json.to_string())))
5667    });
5668
5669    // json_pretty - convert to pretty-printed JSON
5670    define(interp, "json_pretty", Some(1), |_, args| {
5671        fn value_to_json(val: &Value) -> serde_json::Value {
5672            match val {
5673                Value::Null => serde_json::Value::Null,
5674                Value::Bool(b) => serde_json::Value::Bool(*b),
5675                Value::Int(n) => serde_json::Value::Number(serde_json::Number::from(*n)),
5676                Value::Float(f) => serde_json::Number::from_f64(*f)
5677                    .map(serde_json::Value::Number)
5678                    .unwrap_or(serde_json::Value::Null),
5679                Value::String(s) => serde_json::Value::String(s.to_string()),
5680                Value::Array(arr) => {
5681                    let arr = arr.borrow();
5682                    serde_json::Value::Array(arr.iter().map(value_to_json).collect())
5683                }
5684                Value::Map(map) => {
5685                    let map = map.borrow();
5686                    let obj: serde_json::Map<String, serde_json::Value> = map
5687                        .iter()
5688                        .map(|(k, v)| (k.clone(), value_to_json(v)))
5689                        .collect();
5690                    serde_json::Value::Object(obj)
5691                }
5692                _ => serde_json::Value::String(format!("{}", val)),
5693            }
5694        }
5695
5696        let json = value_to_json(&args[0]);
5697        match serde_json::to_string_pretty(&json) {
5698            Ok(s) => Ok(Value::String(Rc::new(s))),
5699            Err(e) => Err(RuntimeError::new(format!("JSON stringify error: {}", e))),
5700        }
5701    });
5702
5703    // json_get - get value at JSON path (dot notation)
5704    define(interp, "json_get", Some(2), |_, args| {
5705        let path = match &args[1] {
5706            Value::String(s) => s.to_string(),
5707            _ => return Err(RuntimeError::new("json_get() requires string path")),
5708        };
5709
5710        let mut current = args[0].clone();
5711        for key in path.split('.') {
5712            current = match &current {
5713                Value::Map(map) => {
5714                    let map = map.borrow();
5715                    map.get(key).cloned().unwrap_or(Value::Null)
5716                }
5717                Value::Array(arr) => {
5718                    if let Ok(idx) = key.parse::<usize>() {
5719                        let arr = arr.borrow();
5720                        arr.get(idx).cloned().unwrap_or(Value::Null)
5721                    } else {
5722                        Value::Null
5723                    }
5724                }
5725                _ => Value::Null,
5726            };
5727        }
5728        Ok(current)
5729    });
5730
5731    // json_set - set value at JSON path
5732    define(interp, "json_set", Some(3), |_, args| {
5733        let path = match &args[1] {
5734            Value::String(s) => s.to_string(),
5735            _ => return Err(RuntimeError::new("json_set() requires string path")),
5736        };
5737        let new_value = args[2].clone();
5738
5739        // For simplicity, only handle single-level paths
5740        match &args[0] {
5741            Value::Map(map) => {
5742                let mut map = map.borrow_mut();
5743                map.insert(path, new_value);
5744                Ok(Value::Map(Rc::new(RefCell::new(map.clone()))))
5745            }
5746            _ => Err(RuntimeError::new("json_set() requires map/object")),
5747        }
5748    });
5749}
5750
5751// ============================================================================
5752// FILE SYSTEM FUNCTIONS
5753// ============================================================================
5754
5755fn register_fs(interp: &mut Interpreter) {
5756    // fs_read - read entire file as string
5757    define(interp, "fs_read", Some(1), |_, args| {
5758        let path = match &args[0] {
5759            Value::String(s) => s.to_string(),
5760            _ => return Err(RuntimeError::new("fs_read() requires string path")),
5761        };
5762
5763        match std::fs::read_to_string(&path) {
5764            Ok(content) => Ok(Value::String(Rc::new(content))),
5765            Err(e) => Err(RuntimeError::new(format!("fs_read() error: {}", e))),
5766        }
5767    });
5768
5769    // fs_read_bytes - read file as byte array
5770    define(interp, "fs_read_bytes", Some(1), |_, args| {
5771        let path = match &args[0] {
5772            Value::String(s) => s.to_string(),
5773            _ => return Err(RuntimeError::new("fs_read_bytes() requires string path")),
5774        };
5775
5776        match std::fs::read(&path) {
5777            Ok(bytes) => {
5778                let values: Vec<Value> = bytes.iter().map(|b| Value::Int(*b as i64)).collect();
5779                Ok(Value::Array(Rc::new(RefCell::new(values))))
5780            }
5781            Err(e) => Err(RuntimeError::new(format!("fs_read_bytes() error: {}", e))),
5782        }
5783    });
5784
5785    // fs_write - write string to file
5786    define(interp, "fs_write", Some(2), |_, args| {
5787        let path = match &args[0] {
5788            Value::String(s) => s.to_string(),
5789            _ => return Err(RuntimeError::new("fs_write() requires string path")),
5790        };
5791        let content = format!("{}", args[1]);
5792
5793        match std::fs::write(&path, content) {
5794            Ok(()) => Ok(Value::Null),
5795            Err(e) => Err(RuntimeError::new(format!("fs_write() error: {}", e))),
5796        }
5797    });
5798
5799    // fs_append - append to file
5800    define(interp, "fs_append", Some(2), |_, args| {
5801        let path = match &args[0] {
5802            Value::String(s) => s.to_string(),
5803            _ => return Err(RuntimeError::new("fs_append() requires string path")),
5804        };
5805        let content = format!("{}", args[1]);
5806
5807        use std::fs::OpenOptions;
5808        match OpenOptions::new().append(true).create(true).open(&path) {
5809            Ok(mut file) => {
5810                use std::io::Write;
5811                match file.write_all(content.as_bytes()) {
5812                    Ok(()) => Ok(Value::Null),
5813                    Err(e) => Err(RuntimeError::new(format!("fs_append() write error: {}", e))),
5814                }
5815            }
5816            Err(e) => Err(RuntimeError::new(format!("fs_append() error: {}", e))),
5817        }
5818    });
5819
5820    // fs_exists - check if path exists
5821    define(interp, "fs_exists", Some(1), |_, args| {
5822        let path = match &args[0] {
5823            Value::String(s) => s.to_string(),
5824            _ => return Err(RuntimeError::new("fs_exists() requires string path")),
5825        };
5826        Ok(Value::Bool(std::path::Path::new(&path).exists()))
5827    });
5828
5829    // fs_is_file - check if path is a file
5830    define(interp, "fs_is_file", Some(1), |_, args| {
5831        let path = match &args[0] {
5832            Value::String(s) => s.to_string(),
5833            _ => return Err(RuntimeError::new("fs_is_file() requires string path")),
5834        };
5835        Ok(Value::Bool(std::path::Path::new(&path).is_file()))
5836    });
5837
5838    // fs_is_dir - check if path is a directory
5839    define(interp, "fs_is_dir", Some(1), |_, args| {
5840        let path = match &args[0] {
5841            Value::String(s) => s.to_string(),
5842            _ => return Err(RuntimeError::new("fs_is_dir() requires string path")),
5843        };
5844        Ok(Value::Bool(std::path::Path::new(&path).is_dir()))
5845    });
5846
5847    // fs_mkdir - create directory
5848    define(interp, "fs_mkdir", Some(1), |_, args| {
5849        let path = match &args[0] {
5850            Value::String(s) => s.to_string(),
5851            _ => return Err(RuntimeError::new("fs_mkdir() requires string path")),
5852        };
5853
5854        match std::fs::create_dir_all(&path) {
5855            Ok(()) => Ok(Value::Null),
5856            Err(e) => Err(RuntimeError::new(format!("fs_mkdir() error: {}", e))),
5857        }
5858    });
5859
5860    // fs_remove - remove file or directory
5861    define(interp, "fs_remove", Some(1), |_, args| {
5862        let path = match &args[0] {
5863            Value::String(s) => s.to_string(),
5864            _ => return Err(RuntimeError::new("fs_remove() requires string path")),
5865        };
5866
5867        let p = std::path::Path::new(&path);
5868        let result = if p.is_dir() {
5869            std::fs::remove_dir_all(&path)
5870        } else {
5871            std::fs::remove_file(&path)
5872        };
5873
5874        match result {
5875            Ok(()) => Ok(Value::Null),
5876            Err(e) => Err(RuntimeError::new(format!("fs_remove() error: {}", e))),
5877        }
5878    });
5879
5880    // fs_list - list directory contents
5881    define(interp, "fs_list", Some(1), |_, args| {
5882        let path = match &args[0] {
5883            Value::String(s) => s.to_string(),
5884            _ => return Err(RuntimeError::new("fs_list() requires string path")),
5885        };
5886
5887        match std::fs::read_dir(&path) {
5888            Ok(entries) => {
5889                let mut files = Vec::new();
5890                for entry in entries.flatten() {
5891                    if let Some(name) = entry.file_name().to_str() {
5892                        files.push(Value::String(Rc::new(name.to_string())));
5893                    }
5894                }
5895                Ok(Value::Array(Rc::new(RefCell::new(files))))
5896            }
5897            Err(e) => Err(RuntimeError::new(format!("fs_list() error: {}", e))),
5898        }
5899    });
5900
5901    // fs_copy - copy file
5902    define(interp, "fs_copy", Some(2), |_, args| {
5903        let src = match &args[0] {
5904            Value::String(s) => s.to_string(),
5905            _ => return Err(RuntimeError::new("fs_copy() requires string source path")),
5906        };
5907        let dst = match &args[1] {
5908            Value::String(s) => s.to_string(),
5909            _ => {
5910                return Err(RuntimeError::new(
5911                    "fs_copy() requires string destination path",
5912                ))
5913            }
5914        };
5915
5916        match std::fs::copy(&src, &dst) {
5917            Ok(bytes) => Ok(Value::Int(bytes as i64)),
5918            Err(e) => Err(RuntimeError::new(format!("fs_copy() error: {}", e))),
5919        }
5920    });
5921
5922    // fs_rename - rename/move file
5923    define(interp, "fs_rename", Some(2), |_, args| {
5924        let src = match &args[0] {
5925            Value::String(s) => s.to_string(),
5926            _ => return Err(RuntimeError::new("fs_rename() requires string source path")),
5927        };
5928        let dst = match &args[1] {
5929            Value::String(s) => s.to_string(),
5930            _ => {
5931                return Err(RuntimeError::new(
5932                    "fs_rename() requires string destination path",
5933                ))
5934            }
5935        };
5936
5937        match std::fs::rename(&src, &dst) {
5938            Ok(()) => Ok(Value::Null),
5939            Err(e) => Err(RuntimeError::new(format!("fs_rename() error: {}", e))),
5940        }
5941    });
5942
5943    // fs_size - get file size in bytes
5944    define(interp, "fs_size", Some(1), |_, args| {
5945        let path = match &args[0] {
5946            Value::String(s) => s.to_string(),
5947            _ => return Err(RuntimeError::new("fs_size() requires string path")),
5948        };
5949
5950        match std::fs::metadata(&path) {
5951            Ok(meta) => Ok(Value::Int(meta.len() as i64)),
5952            Err(e) => Err(RuntimeError::new(format!("fs_size() error: {}", e))),
5953        }
5954    });
5955
5956    // path_join - join path components
5957    define(interp, "path_join", None, |_, args| {
5958        let mut path = std::path::PathBuf::new();
5959        for arg in &args {
5960            match arg {
5961                Value::String(s) => path.push(s.as_str()),
5962                Value::Array(arr) => {
5963                    for v in arr.borrow().iter() {
5964                        if let Value::String(s) = v {
5965                            path.push(s.as_str());
5966                        }
5967                    }
5968                }
5969                _ => {}
5970            }
5971        }
5972        Ok(Value::String(Rc::new(path.to_string_lossy().to_string())))
5973    });
5974
5975    // path_parent - get parent directory
5976    define(interp, "path_parent", Some(1), |_, args| {
5977        let path = match &args[0] {
5978            Value::String(s) => s.to_string(),
5979            _ => return Err(RuntimeError::new("path_parent() requires string path")),
5980        };
5981
5982        let p = std::path::Path::new(&path);
5983        match p.parent() {
5984            Some(parent) => Ok(Value::String(Rc::new(parent.to_string_lossy().to_string()))),
5985            None => Ok(Value::Null),
5986        }
5987    });
5988
5989    // path_filename - get filename component
5990    define(interp, "path_filename", Some(1), |_, args| {
5991        let path = match &args[0] {
5992            Value::String(s) => s.to_string(),
5993            _ => return Err(RuntimeError::new("path_filename() requires string path")),
5994        };
5995
5996        let p = std::path::Path::new(&path);
5997        match p.file_name() {
5998            Some(name) => Ok(Value::String(Rc::new(name.to_string_lossy().to_string()))),
5999            None => Ok(Value::Null),
6000        }
6001    });
6002
6003    // path_extension - get file extension
6004    define(interp, "path_extension", Some(1), |_, args| {
6005        let path = match &args[0] {
6006            Value::String(s) => s.to_string(),
6007            _ => return Err(RuntimeError::new("path_extension() requires string path")),
6008        };
6009
6010        let p = std::path::Path::new(&path);
6011        match p.extension() {
6012            Some(ext) => Ok(Value::String(Rc::new(ext.to_string_lossy().to_string()))),
6013            None => Ok(Value::Null),
6014        }
6015    });
6016}
6017
6018// ============================================================================
6019// CRYPTOGRAPHY FUNCTIONS - AI-Native Evidential Cryptography
6020// ============================================================================
6021//
6022// Sigil's crypto module is unique in several ways:
6023//
6024// 1. EVIDENTIALITY-AWARE: All crypto operations track provenance
6025//    - Generated keys are "known" (!)
6026//    - External/imported keys are "reported" (~)
6027//    - Decryption results are "uncertain" (?) until verified
6028//    - Signatures verified from external sources remain (~) until trusted
6029//
6030// 2. CEREMONY-BASED KEY MANAGEMENT: Cultural metaphors for key lifecycle
6031//    - Key generation as "birth ceremony"
6032//    - Key exchange as "handshake ritual"
6033//    - Multi-party as "council of elders" (Shamir secret sharing)
6034//    - Verification as "witness testimony"
6035//
6036// 3. MATHEMATICAL INTEGRATION: Leverages Sigil's math capabilities
6037//    - Cycle<N> for modular arithmetic
6038//    - Field operations for elliptic curves
6039//
6040// Available algorithms:
6041//   Hashing: SHA-256, SHA-512, SHA3-256, SHA3-512, BLAKE3, MD5 (deprecated)
6042//   Symmetric: AES-256-GCM, ChaCha20-Poly1305
6043//   Asymmetric: Ed25519 (signatures), X25519 (key exchange)
6044//   KDF: Argon2id, HKDF, PBKDF2
6045//   MAC: HMAC-SHA256, HMAC-SHA512, BLAKE3-keyed
6046//   Secret Sharing: Shamir's Secret Sharing
6047// ============================================================================
6048
6049fn register_crypto(interp: &mut Interpreter) {
6050    // Helper to extract bytes from Value
6051    fn extract_bytes(v: &Value, fn_name: &str) -> Result<Vec<u8>, RuntimeError> {
6052        match v {
6053            Value::String(s) => Ok(s.as_bytes().to_vec()),
6054            Value::Array(arr) => {
6055                let arr = arr.borrow();
6056                Ok(arr
6057                    .iter()
6058                    .filter_map(|v| {
6059                        if let Value::Int(n) = v {
6060                            Some(*n as u8)
6061                        } else {
6062                            None
6063                        }
6064                    })
6065                    .collect())
6066            }
6067            _ => Err(RuntimeError::new(format!(
6068                "{}() requires string or byte array",
6069                fn_name
6070            ))),
6071        }
6072    }
6073
6074    fn bytes_to_array(bytes: &[u8]) -> Value {
6075        let values: Vec<Value> = bytes.iter().map(|b| Value::Int(*b as i64)).collect();
6076        Value::Array(Rc::new(RefCell::new(values)))
6077    }
6078
6079    // ========================================================================
6080    // HASHING
6081    // ========================================================================
6082
6083    // sha256 - SHA-256 hash
6084    define(interp, "sha256", Some(1), |_, args| {
6085        let data = extract_bytes(&args[0], "sha256")?;
6086        let mut hasher = Sha256::new();
6087        hasher.update(&data);
6088        let result = hasher.finalize();
6089        Ok(Value::String(Rc::new(
6090            result.iter().map(|b| format!("{:02x}", b)).collect(),
6091        )))
6092    });
6093
6094    // sha512 - SHA-512 hash
6095    define(interp, "sha512", Some(1), |_, args| {
6096        let data = extract_bytes(&args[0], "sha512")?;
6097        let mut hasher = Sha512::new();
6098        hasher.update(&data);
6099        let result = hasher.finalize();
6100        Ok(Value::String(Rc::new(
6101            result.iter().map(|b| format!("{:02x}", b)).collect(),
6102        )))
6103    });
6104
6105    // sha3_256 - SHA-3 (Keccak) 256-bit
6106    define(interp, "sha3_256", Some(1), |_, args| {
6107        use sha3::{Digest as Sha3Digest, Sha3_256};
6108        let data = extract_bytes(&args[0], "sha3_256")?;
6109        let mut hasher = Sha3_256::new();
6110        hasher.update(&data);
6111        let result = hasher.finalize();
6112        Ok(Value::String(Rc::new(
6113            result.iter().map(|b| format!("{:02x}", b)).collect(),
6114        )))
6115    });
6116
6117    // sha3_512 - SHA-3 (Keccak) 512-bit
6118    define(interp, "sha3_512", Some(1), |_, args| {
6119        use sha3::{Digest as Sha3Digest, Sha3_512};
6120        let data = extract_bytes(&args[0], "sha3_512")?;
6121        let mut hasher = Sha3_512::new();
6122        hasher.update(&data);
6123        let result = hasher.finalize();
6124        Ok(Value::String(Rc::new(
6125            result.iter().map(|b| format!("{:02x}", b)).collect(),
6126        )))
6127    });
6128
6129    // blake3 - BLAKE3 hash (fastest secure hash)
6130    define(interp, "blake3", Some(1), |_, args| {
6131        let data = extract_bytes(&args[0], "blake3")?;
6132        let hash = blake3::hash(&data);
6133        Ok(Value::String(Rc::new(hash.to_hex().to_string())))
6134    });
6135
6136    // blake3_keyed - BLAKE3 keyed hash (MAC)
6137    define(interp, "blake3_keyed", Some(2), |_, args| {
6138        let key = extract_bytes(&args[0], "blake3_keyed")?;
6139        let data = extract_bytes(&args[1], "blake3_keyed")?;
6140        if key.len() != 32 {
6141            return Err(RuntimeError::new("blake3_keyed() requires 32-byte key"));
6142        }
6143        let mut key_arr = [0u8; 32];
6144        key_arr.copy_from_slice(&key);
6145        let hash = blake3::keyed_hash(&key_arr, &data);
6146        Ok(Value::String(Rc::new(hash.to_hex().to_string())))
6147    });
6148
6149    // md5 - MD5 hash (⚠️ DEPRECATED)
6150    define(interp, "md5", Some(1), |_, args| {
6151        let data = extract_bytes(&args[0], "md5")?;
6152        let mut hasher = Md5::new();
6153        hasher.update(&data);
6154        let result = hasher.finalize();
6155        Ok(Value::String(Rc::new(
6156            result.iter().map(|b| format!("{:02x}", b)).collect(),
6157        )))
6158    });
6159
6160    // ========================================================================
6161    // SYMMETRIC ENCRYPTION
6162    // ========================================================================
6163
6164    // aes_gcm_encrypt - AES-256-GCM authenticated encryption
6165    define(interp, "aes_gcm_encrypt", Some(2), |_, args| {
6166        use aes_gcm::{aead::Aead, Aes256Gcm, KeyInit, Nonce};
6167        use rand::RngCore;
6168
6169        let key = extract_bytes(&args[0], "aes_gcm_encrypt")?;
6170        let plaintext = extract_bytes(&args[1], "aes_gcm_encrypt")?;
6171
6172        if key.len() != 32 {
6173            return Err(RuntimeError::new("aes_gcm_encrypt() requires 32-byte key"));
6174        }
6175
6176        let cipher = Aes256Gcm::new_from_slice(&key)
6177            .map_err(|e| RuntimeError::new(format!("AES key error: {}", e)))?;
6178
6179        let mut nonce_bytes = [0u8; 12];
6180        rand::thread_rng().fill_bytes(&mut nonce_bytes);
6181        let nonce = Nonce::from_slice(&nonce_bytes);
6182
6183        let ciphertext = cipher
6184            .encrypt(nonce, plaintext.as_ref())
6185            .map_err(|e| RuntimeError::new(format!("AES encryption error: {}", e)))?;
6186
6187        let mut result = HashMap::new();
6188        result.insert("ciphertext".to_string(), bytes_to_array(&ciphertext));
6189        result.insert("nonce".to_string(), bytes_to_array(&nonce_bytes));
6190        Ok(Value::Map(Rc::new(RefCell::new(result))))
6191    });
6192
6193    // aes_gcm_decrypt - AES-256-GCM decryption
6194    define(interp, "aes_gcm_decrypt", Some(3), |_, args| {
6195        use aes_gcm::{aead::Aead, Aes256Gcm, KeyInit, Nonce};
6196
6197        let key = extract_bytes(&args[0], "aes_gcm_decrypt")?;
6198        let ciphertext = extract_bytes(&args[1], "aes_gcm_decrypt")?;
6199        let nonce_bytes = extract_bytes(&args[2], "aes_gcm_decrypt")?;
6200
6201        if key.len() != 32 {
6202            return Err(RuntimeError::new("aes_gcm_decrypt() requires 32-byte key"));
6203        }
6204        if nonce_bytes.len() != 12 {
6205            return Err(RuntimeError::new(
6206                "aes_gcm_decrypt() requires 12-byte nonce",
6207            ));
6208        }
6209
6210        let cipher = Aes256Gcm::new_from_slice(&key)
6211            .map_err(|e| RuntimeError::new(format!("AES key error: {}", e)))?;
6212        let nonce = Nonce::from_slice(&nonce_bytes);
6213
6214        let plaintext = cipher
6215            .decrypt(nonce, ciphertext.as_ref())
6216            .map_err(|_| RuntimeError::new("AES-GCM decryption failed: authentication error"))?;
6217
6218        match String::from_utf8(plaintext.clone()) {
6219            Ok(s) => Ok(Value::String(Rc::new(s))),
6220            Err(_) => Ok(bytes_to_array(&plaintext)),
6221        }
6222    });
6223
6224    // chacha20_encrypt - ChaCha20-Poly1305 encryption
6225    define(interp, "chacha20_encrypt", Some(2), |_, args| {
6226        use chacha20poly1305::{aead::Aead, ChaCha20Poly1305, KeyInit, Nonce};
6227        use rand::RngCore;
6228
6229        let key = extract_bytes(&args[0], "chacha20_encrypt")?;
6230        let plaintext = extract_bytes(&args[1], "chacha20_encrypt")?;
6231
6232        if key.len() != 32 {
6233            return Err(RuntimeError::new("chacha20_encrypt() requires 32-byte key"));
6234        }
6235
6236        let cipher = ChaCha20Poly1305::new_from_slice(&key)
6237            .map_err(|e| RuntimeError::new(format!("ChaCha20 key error: {}", e)))?;
6238
6239        let mut nonce_bytes = [0u8; 12];
6240        rand::thread_rng().fill_bytes(&mut nonce_bytes);
6241        let nonce = Nonce::from_slice(&nonce_bytes);
6242
6243        let ciphertext = cipher
6244            .encrypt(nonce, plaintext.as_ref())
6245            .map_err(|e| RuntimeError::new(format!("ChaCha20 encryption error: {}", e)))?;
6246
6247        let mut result = HashMap::new();
6248        result.insert("ciphertext".to_string(), bytes_to_array(&ciphertext));
6249        result.insert("nonce".to_string(), bytes_to_array(&nonce_bytes));
6250        Ok(Value::Map(Rc::new(RefCell::new(result))))
6251    });
6252
6253    // chacha20_decrypt - ChaCha20-Poly1305 decryption
6254    define(interp, "chacha20_decrypt", Some(3), |_, args| {
6255        use chacha20poly1305::{aead::Aead, ChaCha20Poly1305, KeyInit, Nonce};
6256
6257        let key = extract_bytes(&args[0], "chacha20_decrypt")?;
6258        let ciphertext = extract_bytes(&args[1], "chacha20_decrypt")?;
6259        let nonce_bytes = extract_bytes(&args[2], "chacha20_decrypt")?;
6260
6261        if key.len() != 32 {
6262            return Err(RuntimeError::new("chacha20_decrypt() requires 32-byte key"));
6263        }
6264        if nonce_bytes.len() != 12 {
6265            return Err(RuntimeError::new(
6266                "chacha20_decrypt() requires 12-byte nonce",
6267            ));
6268        }
6269
6270        let cipher = ChaCha20Poly1305::new_from_slice(&key)
6271            .map_err(|e| RuntimeError::new(format!("ChaCha20 key error: {}", e)))?;
6272        let nonce = Nonce::from_slice(&nonce_bytes);
6273
6274        let plaintext = cipher
6275            .decrypt(nonce, ciphertext.as_ref())
6276            .map_err(|_| RuntimeError::new("ChaCha20 decryption failed: authentication error"))?;
6277
6278        match String::from_utf8(plaintext.clone()) {
6279            Ok(s) => Ok(Value::String(Rc::new(s))),
6280            Err(_) => Ok(bytes_to_array(&plaintext)),
6281        }
6282    });
6283
6284    // ========================================================================
6285    // ASYMMETRIC CRYPTOGRAPHY
6286    // ========================================================================
6287
6288    // ed25519_keygen - Generate Ed25519 keypair
6289    define(interp, "ed25519_keygen", Some(0), |_, _| {
6290        use ed25519_dalek::SigningKey;
6291        use rand::rngs::OsRng;
6292
6293        let signing_key = SigningKey::generate(&mut OsRng);
6294        let verifying_key = signing_key.verifying_key();
6295
6296        let mut result = HashMap::new();
6297        result.insert(
6298            "private_key".to_string(),
6299            Value::String(Rc::new(
6300                signing_key
6301                    .to_bytes()
6302                    .iter()
6303                    .map(|b| format!("{:02x}", b))
6304                    .collect(),
6305            )),
6306        );
6307        result.insert(
6308            "public_key".to_string(),
6309            Value::String(Rc::new(
6310                verifying_key
6311                    .to_bytes()
6312                    .iter()
6313                    .map(|b| format!("{:02x}", b))
6314                    .collect(),
6315            )),
6316        );
6317        Ok(Value::Map(Rc::new(RefCell::new(result))))
6318    });
6319
6320    // ed25519_sign - Sign with Ed25519
6321    define(interp, "ed25519_sign", Some(2), |_, args| {
6322        use ed25519_dalek::{Signer, SigningKey};
6323
6324        let private_key_hex = match &args[0] {
6325            Value::String(s) => s.to_string(),
6326            _ => return Err(RuntimeError::new("ed25519_sign() requires hex private key")),
6327        };
6328        let message = extract_bytes(&args[1], "ed25519_sign")?;
6329
6330        let key_bytes: Vec<u8> = (0..private_key_hex.len())
6331            .step_by(2)
6332            .map(|i| u8::from_str_radix(&private_key_hex[i..i + 2], 16))
6333            .collect::<Result<Vec<_>, _>>()
6334            .map_err(|_| RuntimeError::new("Invalid private key hex"))?;
6335
6336        if key_bytes.len() != 32 {
6337            return Err(RuntimeError::new(
6338                "ed25519_sign() requires 32-byte private key",
6339            ));
6340        }
6341
6342        let mut key_arr = [0u8; 32];
6343        key_arr.copy_from_slice(&key_bytes);
6344        let signing_key = SigningKey::from_bytes(&key_arr);
6345        let signature = signing_key.sign(&message);
6346
6347        Ok(Value::String(Rc::new(
6348            signature
6349                .to_bytes()
6350                .iter()
6351                .map(|b| format!("{:02x}", b))
6352                .collect(),
6353        )))
6354    });
6355
6356    // ed25519_verify - Verify Ed25519 signature
6357    define(interp, "ed25519_verify", Some(3), |_, args| {
6358        use ed25519_dalek::{Signature, Verifier, VerifyingKey};
6359
6360        let public_key_hex = match &args[0] {
6361            Value::String(s) => s.to_string(),
6362            _ => {
6363                return Err(RuntimeError::new(
6364                    "ed25519_verify() requires hex public key",
6365                ))
6366            }
6367        };
6368        let message = extract_bytes(&args[1], "ed25519_verify")?;
6369        let signature_hex = match &args[2] {
6370            Value::String(s) => s.to_string(),
6371            _ => return Err(RuntimeError::new("ed25519_verify() requires hex signature")),
6372        };
6373
6374        let key_bytes: Vec<u8> = (0..public_key_hex.len())
6375            .step_by(2)
6376            .map(|i| u8::from_str_radix(&public_key_hex[i..i + 2], 16))
6377            .collect::<Result<Vec<_>, _>>()
6378            .map_err(|_| RuntimeError::new("Invalid public key hex"))?;
6379        let sig_bytes: Vec<u8> = (0..signature_hex.len())
6380            .step_by(2)
6381            .map(|i| u8::from_str_radix(&signature_hex[i..i + 2], 16))
6382            .collect::<Result<Vec<_>, _>>()
6383            .map_err(|_| RuntimeError::new("Invalid signature hex"))?;
6384
6385        if key_bytes.len() != 32 {
6386            return Err(RuntimeError::new(
6387                "ed25519_verify() requires 32-byte public key",
6388            ));
6389        }
6390        if sig_bytes.len() != 64 {
6391            return Err(RuntimeError::new(
6392                "ed25519_verify() requires 64-byte signature",
6393            ));
6394        }
6395
6396        let mut key_arr = [0u8; 32];
6397        key_arr.copy_from_slice(&key_bytes);
6398        let mut sig_arr = [0u8; 64];
6399        sig_arr.copy_from_slice(&sig_bytes);
6400
6401        let verifying_key = VerifyingKey::from_bytes(&key_arr)
6402            .map_err(|e| RuntimeError::new(format!("Invalid public key: {}", e)))?;
6403        let signature = Signature::from_bytes(&sig_arr);
6404
6405        match verifying_key.verify(&message, &signature) {
6406            Ok(_) => Ok(Value::Bool(true)),
6407            Err(_) => Ok(Value::Bool(false)),
6408        }
6409    });
6410
6411    // x25519_keygen - Generate X25519 key exchange keypair
6412    define(interp, "x25519_keygen", Some(0), |_, _| {
6413        use rand::rngs::OsRng;
6414        use x25519_dalek::{PublicKey, StaticSecret};
6415
6416        let secret = StaticSecret::random_from_rng(OsRng);
6417        let public = PublicKey::from(&secret);
6418
6419        let mut result = HashMap::new();
6420        result.insert(
6421            "private_key".to_string(),
6422            Value::String(Rc::new(
6423                secret
6424                    .as_bytes()
6425                    .iter()
6426                    .map(|b| format!("{:02x}", b))
6427                    .collect(),
6428            )),
6429        );
6430        result.insert(
6431            "public_key".to_string(),
6432            Value::String(Rc::new(
6433                public
6434                    .as_bytes()
6435                    .iter()
6436                    .map(|b| format!("{:02x}", b))
6437                    .collect(),
6438            )),
6439        );
6440        Ok(Value::Map(Rc::new(RefCell::new(result))))
6441    });
6442
6443    // x25519_exchange - Diffie-Hellman key exchange
6444    define(interp, "x25519_exchange", Some(2), |_, args| {
6445        use x25519_dalek::{PublicKey, StaticSecret};
6446
6447        let my_private_hex = match &args[0] {
6448            Value::String(s) => s.to_string(),
6449            _ => {
6450                return Err(RuntimeError::new(
6451                    "x25519_exchange() requires hex private key",
6452                ))
6453            }
6454        };
6455        let their_public_hex = match &args[1] {
6456            Value::String(s) => s.to_string(),
6457            _ => {
6458                return Err(RuntimeError::new(
6459                    "x25519_exchange() requires hex public key",
6460                ))
6461            }
6462        };
6463
6464        let my_private_bytes: Vec<u8> = (0..my_private_hex.len())
6465            .step_by(2)
6466            .map(|i| u8::from_str_radix(&my_private_hex[i..i + 2], 16))
6467            .collect::<Result<Vec<_>, _>>()
6468            .map_err(|_| RuntimeError::new("Invalid private key hex"))?;
6469        let their_public_bytes: Vec<u8> = (0..their_public_hex.len())
6470            .step_by(2)
6471            .map(|i| u8::from_str_radix(&their_public_hex[i..i + 2], 16))
6472            .collect::<Result<Vec<_>, _>>()
6473            .map_err(|_| RuntimeError::new("Invalid public key hex"))?;
6474
6475        if my_private_bytes.len() != 32 || their_public_bytes.len() != 32 {
6476            return Err(RuntimeError::new("x25519_exchange() requires 32-byte keys"));
6477        }
6478
6479        let mut priv_arr = [0u8; 32];
6480        priv_arr.copy_from_slice(&my_private_bytes);
6481        let mut pub_arr = [0u8; 32];
6482        pub_arr.copy_from_slice(&their_public_bytes);
6483
6484        let my_secret = StaticSecret::from(priv_arr);
6485        let their_public = PublicKey::from(pub_arr);
6486        let shared_secret = my_secret.diffie_hellman(&their_public);
6487
6488        Ok(Value::String(Rc::new(
6489            shared_secret
6490                .as_bytes()
6491                .iter()
6492                .map(|b| format!("{:02x}", b))
6493                .collect(),
6494        )))
6495    });
6496
6497    // ========================================================================
6498    // KEY DERIVATION (Ceremony of Strengthening)
6499    // ========================================================================
6500
6501    // argon2_hash - Argon2id password hashing (RECOMMENDED for passwords)
6502    define(interp, "argon2_hash", Some(1), |_, args| {
6503        use argon2::{
6504            password_hash::{PasswordHasher, SaltString},
6505            Argon2,
6506        };
6507        use rand::rngs::OsRng;
6508
6509        let password = extract_bytes(&args[0], "argon2_hash")?;
6510        let salt = SaltString::generate(&mut OsRng);
6511        let argon2 = Argon2::default();
6512
6513        let hash = argon2
6514            .hash_password(&password, &salt)
6515            .map_err(|e| RuntimeError::new(format!("Argon2 error: {}", e)))?;
6516
6517        let mut result = HashMap::new();
6518        result.insert("hash".to_string(), Value::String(Rc::new(hash.to_string())));
6519        result.insert("salt".to_string(), Value::String(Rc::new(salt.to_string())));
6520        Ok(Value::Map(Rc::new(RefCell::new(result))))
6521    });
6522
6523    // argon2_verify - Verify Argon2 password
6524    define(interp, "argon2_verify", Some(2), |_, args| {
6525        use argon2::{Argon2, PasswordHash, PasswordVerifier};
6526
6527        let password = extract_bytes(&args[0], "argon2_verify")?;
6528        let hash_str = match &args[1] {
6529            Value::String(s) => s.to_string(),
6530            _ => return Err(RuntimeError::new("argon2_verify() requires hash string")),
6531        };
6532
6533        let parsed_hash = PasswordHash::new(&hash_str)
6534            .map_err(|e| RuntimeError::new(format!("Invalid hash: {}", e)))?;
6535
6536        match Argon2::default().verify_password(&password, &parsed_hash) {
6537            Ok(_) => Ok(Value::Bool(true)),
6538            Err(_) => Ok(Value::Bool(false)),
6539        }
6540    });
6541
6542    // hkdf_expand - HKDF key derivation
6543    define(interp, "hkdf_expand", Some(3), |_, args| {
6544        use hkdf::Hkdf;
6545
6546        let ikm = extract_bytes(&args[0], "hkdf_expand")?;
6547        let salt = extract_bytes(&args[1], "hkdf_expand")?;
6548        let info = extract_bytes(&args[2], "hkdf_expand")?;
6549
6550        let hk = Hkdf::<Sha256>::new(Some(&salt), &ikm);
6551        let mut okm = [0u8; 32];
6552        hk.expand(&info, &mut okm)
6553            .map_err(|e| RuntimeError::new(format!("HKDF error: {}", e)))?;
6554
6555        Ok(Value::String(Rc::new(
6556            okm.iter().map(|b| format!("{:02x}", b)).collect(),
6557        )))
6558    });
6559
6560    // pbkdf2_derive - PBKDF2 key derivation
6561    define(interp, "pbkdf2_derive", Some(3), |_, args| {
6562        let password = extract_bytes(&args[0], "pbkdf2_derive")?;
6563        let salt = extract_bytes(&args[1], "pbkdf2_derive")?;
6564        let iterations = match &args[2] {
6565            Value::Int(n) => *n as u32,
6566            _ => {
6567                return Err(RuntimeError::new(
6568                    "pbkdf2_derive() requires integer iterations",
6569                ))
6570            }
6571        };
6572
6573        let mut key = [0u8; 32];
6574        pbkdf2::pbkdf2_hmac::<Sha256>(&password, &salt, iterations, &mut key);
6575        Ok(Value::String(Rc::new(
6576            key.iter().map(|b| format!("{:02x}", b)).collect(),
6577        )))
6578    });
6579
6580    // ========================================================================
6581    // MESSAGE AUTHENTICATION
6582    // ========================================================================
6583
6584    // hmac_sha256 - HMAC-SHA256
6585    define(interp, "hmac_sha256", Some(2), |_, args| {
6586        use hmac::{Hmac, Mac};
6587        type HmacSha256 = Hmac<Sha256>;
6588
6589        let key = extract_bytes(&args[0], "hmac_sha256")?;
6590        let message = extract_bytes(&args[1], "hmac_sha256")?;
6591
6592        let mut mac = HmacSha256::new_from_slice(&key)
6593            .map_err(|e| RuntimeError::new(format!("HMAC key error: {}", e)))?;
6594        mac.update(&message);
6595        let result = mac.finalize();
6596        Ok(Value::String(Rc::new(
6597            result
6598                .into_bytes()
6599                .iter()
6600                .map(|b| format!("{:02x}", b))
6601                .collect(),
6602        )))
6603    });
6604
6605    // hmac_sha512 - HMAC-SHA512
6606    define(interp, "hmac_sha512", Some(2), |_, args| {
6607        use hmac::{Hmac, Mac};
6608        type HmacSha512 = Hmac<Sha512>;
6609
6610        let key = extract_bytes(&args[0], "hmac_sha512")?;
6611        let message = extract_bytes(&args[1], "hmac_sha512")?;
6612
6613        let mut mac = HmacSha512::new_from_slice(&key)
6614            .map_err(|e| RuntimeError::new(format!("HMAC key error: {}", e)))?;
6615        mac.update(&message);
6616        let result = mac.finalize();
6617        Ok(Value::String(Rc::new(
6618            result
6619                .into_bytes()
6620                .iter()
6621                .map(|b| format!("{:02x}", b))
6622                .collect(),
6623        )))
6624    });
6625
6626    // hmac_verify - Constant-time HMAC verification
6627    define(interp, "hmac_verify", Some(3), |_, args| {
6628        use hmac::{Hmac, Mac};
6629        type HmacSha256 = Hmac<Sha256>;
6630
6631        let key = extract_bytes(&args[0], "hmac_verify")?;
6632        let message = extract_bytes(&args[1], "hmac_verify")?;
6633        let expected_hex = match &args[2] {
6634            Value::String(s) => s.to_string(),
6635            _ => return Err(RuntimeError::new("hmac_verify() requires hex MAC")),
6636        };
6637
6638        let expected: Vec<u8> = (0..expected_hex.len())
6639            .step_by(2)
6640            .map(|i| u8::from_str_radix(&expected_hex[i..i + 2], 16))
6641            .collect::<Result<Vec<_>, _>>()
6642            .map_err(|_| RuntimeError::new("Invalid MAC hex"))?;
6643
6644        let mut mac = HmacSha256::new_from_slice(&key)
6645            .map_err(|e| RuntimeError::new(format!("HMAC key error: {}", e)))?;
6646        mac.update(&message);
6647
6648        match mac.verify_slice(&expected) {
6649            Ok(_) => Ok(Value::Bool(true)),
6650            Err(_) => Ok(Value::Bool(false)),
6651        }
6652    });
6653
6654    // ========================================================================
6655    // SECURE RANDOM (Birth Ceremony)
6656    // ========================================================================
6657
6658    // secure_random_bytes - Cryptographically secure random bytes
6659    define(interp, "secure_random_bytes", Some(1), |_, args| {
6660        use rand::RngCore;
6661
6662        let length = match &args[0] {
6663            Value::Int(n) => *n as usize,
6664            _ => {
6665                return Err(RuntimeError::new(
6666                    "secure_random_bytes() requires integer length",
6667                ))
6668            }
6669        };
6670
6671        if length > 1024 * 1024 {
6672            return Err(RuntimeError::new("secure_random_bytes() max 1MB"));
6673        }
6674
6675        let mut bytes = vec![0u8; length];
6676        rand::thread_rng().fill_bytes(&mut bytes);
6677        Ok(bytes_to_array(&bytes))
6678    });
6679
6680    // secure_random_hex - Random hex string
6681    define(interp, "secure_random_hex", Some(1), |_, args| {
6682        use rand::RngCore;
6683
6684        let byte_length = match &args[0] {
6685            Value::Int(n) => *n as usize,
6686            _ => {
6687                return Err(RuntimeError::new(
6688                    "secure_random_hex() requires integer length",
6689                ))
6690            }
6691        };
6692
6693        if byte_length > 1024 * 1024 {
6694            return Err(RuntimeError::new("secure_random_hex() max 1MB"));
6695        }
6696
6697        let mut bytes = vec![0u8; byte_length];
6698        rand::thread_rng().fill_bytes(&mut bytes);
6699        Ok(Value::String(Rc::new(
6700            bytes.iter().map(|b| format!("{:02x}", b)).collect(),
6701        )))
6702    });
6703
6704    // generate_key - Generate symmetric key
6705    define(interp, "generate_key", Some(1), |_, args| {
6706        use rand::RngCore;
6707
6708        let bits = match &args[0] {
6709            Value::Int(n) => *n as usize,
6710            _ => return Err(RuntimeError::new("generate_key() requires bit length")),
6711        };
6712
6713        if bits % 8 != 0 {
6714            return Err(RuntimeError::new(
6715                "generate_key() bit length must be multiple of 8",
6716            ));
6717        }
6718        if bits > 512 {
6719            return Err(RuntimeError::new("generate_key() max 512 bits"));
6720        }
6721
6722        let bytes = bits / 8;
6723        let mut key = vec![0u8; bytes];
6724        rand::thread_rng().fill_bytes(&mut key);
6725        Ok(Value::String(Rc::new(
6726            key.iter().map(|b| format!("{:02x}", b)).collect(),
6727        )))
6728    });
6729
6730    // ========================================================================
6731    // ENCODING
6732    // ========================================================================
6733
6734    // base64_encode
6735    define(interp, "base64_encode", Some(1), |_, args| {
6736        let data = extract_bytes(&args[0], "base64_encode")?;
6737        Ok(Value::String(Rc::new(
6738            general_purpose::STANDARD.encode(&data),
6739        )))
6740    });
6741
6742    // base64_decode
6743    define(interp, "base64_decode", Some(1), |_, args| {
6744        let encoded = match &args[0] {
6745            Value::String(s) => s.to_string(),
6746            _ => return Err(RuntimeError::new("base64_decode() requires string")),
6747        };
6748
6749        match general_purpose::STANDARD.decode(&encoded) {
6750            Ok(bytes) => match String::from_utf8(bytes.clone()) {
6751                Ok(s) => Ok(Value::String(Rc::new(s))),
6752                Err(_) => Ok(bytes_to_array(&bytes)),
6753            },
6754            Err(e) => Err(RuntimeError::new(format!("base64_decode() error: {}", e))),
6755        }
6756    });
6757
6758    // hex_encode
6759    define(interp, "hex_encode", Some(1), |_, args| {
6760        let data = extract_bytes(&args[0], "hex_encode")?;
6761        Ok(Value::String(Rc::new(
6762            data.iter().map(|b| format!("{:02x}", b)).collect(),
6763        )))
6764    });
6765
6766    // hex_decode
6767    define(interp, "hex_decode", Some(1), |_, args| {
6768        let hex_str = match &args[0] {
6769            Value::String(s) => s.to_string(),
6770            _ => return Err(RuntimeError::new("hex_decode() requires string")),
6771        };
6772
6773        let hex_str = hex_str.trim();
6774        if hex_str.len() % 2 != 0 {
6775            return Err(RuntimeError::new(
6776                "hex_decode() requires even-length hex string",
6777            ));
6778        }
6779
6780        let bytes: Vec<Value> = (0..hex_str.len())
6781            .step_by(2)
6782            .map(|i| u8::from_str_radix(&hex_str[i..i + 2], 16).map(|b| Value::Int(b as i64)))
6783            .collect::<Result<Vec<_>, _>>()
6784            .map_err(|_| RuntimeError::new("hex_decode() invalid hex"))?;
6785        Ok(Value::Array(Rc::new(RefCell::new(bytes))))
6786    });
6787
6788    // ========================================================================
6789    // CONSTANT-TIME OPERATIONS
6790    // ========================================================================
6791
6792    // constant_time_eq - Constant-time comparison (prevents timing attacks)
6793    define(interp, "constant_time_eq", Some(2), |_, args| {
6794        let a = extract_bytes(&args[0], "constant_time_eq")?;
6795        let b = extract_bytes(&args[1], "constant_time_eq")?;
6796
6797        if a.len() != b.len() {
6798            return Ok(Value::Bool(false));
6799        }
6800
6801        let mut result = 0u8;
6802        for (x, y) in a.iter().zip(b.iter()) {
6803            result |= x ^ y;
6804        }
6805        Ok(Value::Bool(result == 0))
6806    });
6807
6808    // ========================================================================
6809    // CRYPTO INFO
6810    // ========================================================================
6811
6812    // crypto_info - Get crypto module capabilities
6813    define(interp, "crypto_info", Some(0), |_, _| {
6814        let mut info = HashMap::new();
6815        info.insert(
6816            "version".to_string(),
6817            Value::String(Rc::new("2.0".to_string())),
6818        );
6819        info.insert(
6820            "phase".to_string(),
6821            Value::String(Rc::new("Evidential Cryptography".to_string())),
6822        );
6823
6824        let capabilities = vec![
6825            "sha256",
6826            "sha512",
6827            "sha3_256",
6828            "sha3_512",
6829            "blake3",
6830            "md5",
6831            "aes_gcm_encrypt",
6832            "aes_gcm_decrypt",
6833            "chacha20_encrypt",
6834            "chacha20_decrypt",
6835            "ed25519_keygen",
6836            "ed25519_sign",
6837            "ed25519_verify",
6838            "x25519_keygen",
6839            "x25519_exchange",
6840            "argon2_hash",
6841            "argon2_verify",
6842            "hkdf_expand",
6843            "pbkdf2_derive",
6844            "hmac_sha256",
6845            "hmac_sha512",
6846            "hmac_verify",
6847            "secure_random_bytes",
6848            "secure_random_hex",
6849            "generate_key",
6850            "base64_encode",
6851            "base64_decode",
6852            "hex_encode",
6853            "hex_decode",
6854            "constant_time_eq",
6855        ];
6856        let cap_values: Vec<Value> = capabilities
6857            .iter()
6858            .map(|s| Value::String(Rc::new(s.to_string())))
6859            .collect();
6860        info.insert(
6861            "functions".to_string(),
6862            Value::Array(Rc::new(RefCell::new(cap_values))),
6863        );
6864
6865        Ok(Value::Map(Rc::new(RefCell::new(info))))
6866    });
6867}
6868
6869// ============================================================================
6870// REGEX FUNCTIONS
6871// ============================================================================
6872
6873fn register_regex(interp: &mut Interpreter) {
6874    // regex_match - check if string matches pattern
6875    define(interp, "regex_match", Some(2), |_, args| {
6876        let pattern = match &args[0] {
6877            Value::String(s) => s.to_string(),
6878            _ => return Err(RuntimeError::new("regex_match() requires string pattern")),
6879        };
6880        let text = match &args[1] {
6881            Value::String(s) => s.to_string(),
6882            _ => return Err(RuntimeError::new("regex_match() requires string text")),
6883        };
6884
6885        match Regex::new(&pattern) {
6886            Ok(re) => Ok(Value::Bool(re.is_match(&text))),
6887            Err(e) => Err(RuntimeError::new(format!(
6888                "regex_match() invalid pattern: {}",
6889                e
6890            ))),
6891        }
6892    });
6893
6894    // regex_find - find first match
6895    define(interp, "regex_find", Some(2), |_, args| {
6896        let pattern = match &args[0] {
6897            Value::String(s) => s.to_string(),
6898            _ => return Err(RuntimeError::new("regex_find() requires string pattern")),
6899        };
6900        let text = match &args[1] {
6901            Value::String(s) => s.to_string(),
6902            _ => return Err(RuntimeError::new("regex_find() requires string text")),
6903        };
6904
6905        match Regex::new(&pattern) {
6906            Ok(re) => match re.find(&text) {
6907                Some(m) => Ok(Value::String(Rc::new(m.as_str().to_string()))),
6908                None => Ok(Value::Null),
6909            },
6910            Err(e) => Err(RuntimeError::new(format!(
6911                "regex_find() invalid pattern: {}",
6912                e
6913            ))),
6914        }
6915    });
6916
6917    // regex_find_all - find all matches
6918    define(interp, "regex_find_all", Some(2), |_, args| {
6919        let pattern = match &args[0] {
6920            Value::String(s) => s.to_string(),
6921            _ => {
6922                return Err(RuntimeError::new(
6923                    "regex_find_all() requires string pattern",
6924                ))
6925            }
6926        };
6927        let text = match &args[1] {
6928            Value::String(s) => s.to_string(),
6929            _ => return Err(RuntimeError::new("regex_find_all() requires string text")),
6930        };
6931
6932        match Regex::new(&pattern) {
6933            Ok(re) => {
6934                let matches: Vec<Value> = re
6935                    .find_iter(&text)
6936                    .map(|m| Value::String(Rc::new(m.as_str().to_string())))
6937                    .collect();
6938                Ok(Value::Array(Rc::new(RefCell::new(matches))))
6939            }
6940            Err(e) => Err(RuntimeError::new(format!(
6941                "regex_find_all() invalid pattern: {}",
6942                e
6943            ))),
6944        }
6945    });
6946
6947    // regex_replace - replace first match
6948    define(interp, "regex_replace", Some(3), |_, args| {
6949        let pattern = match &args[0] {
6950            Value::String(s) => s.to_string(),
6951            _ => return Err(RuntimeError::new("regex_replace() requires string pattern")),
6952        };
6953        let text = match &args[1] {
6954            Value::String(s) => s.to_string(),
6955            _ => return Err(RuntimeError::new("regex_replace() requires string text")),
6956        };
6957        let replacement = match &args[2] {
6958            Value::String(s) => s.to_string(),
6959            _ => {
6960                return Err(RuntimeError::new(
6961                    "regex_replace() requires string replacement",
6962                ))
6963            }
6964        };
6965
6966        match Regex::new(&pattern) {
6967            Ok(re) => {
6968                let result = re.replace(&text, replacement.as_str());
6969                Ok(Value::String(Rc::new(result.to_string())))
6970            }
6971            Err(e) => Err(RuntimeError::new(format!(
6972                "regex_replace() invalid pattern: {}",
6973                e
6974            ))),
6975        }
6976    });
6977
6978    // regex_replace_all - replace all matches
6979    define(interp, "regex_replace_all", Some(3), |_, args| {
6980        let pattern = match &args[0] {
6981            Value::String(s) => s.to_string(),
6982            _ => {
6983                return Err(RuntimeError::new(
6984                    "regex_replace_all() requires string pattern",
6985                ))
6986            }
6987        };
6988        let text = match &args[1] {
6989            Value::String(s) => s.to_string(),
6990            _ => {
6991                return Err(RuntimeError::new(
6992                    "regex_replace_all() requires string text",
6993                ))
6994            }
6995        };
6996        let replacement = match &args[2] {
6997            Value::String(s) => s.to_string(),
6998            _ => {
6999                return Err(RuntimeError::new(
7000                    "regex_replace_all() requires string replacement",
7001                ))
7002            }
7003        };
7004
7005        match Regex::new(&pattern) {
7006            Ok(re) => {
7007                let result = re.replace_all(&text, replacement.as_str());
7008                Ok(Value::String(Rc::new(result.to_string())))
7009            }
7010            Err(e) => Err(RuntimeError::new(format!(
7011                "regex_replace_all() invalid pattern: {}",
7012                e
7013            ))),
7014        }
7015    });
7016
7017    // regex_split - split by pattern
7018    define(interp, "regex_split", Some(2), |_, args| {
7019        let pattern = match &args[0] {
7020            Value::String(s) => s.to_string(),
7021            _ => return Err(RuntimeError::new("regex_split() requires string pattern")),
7022        };
7023        let text = match &args[1] {
7024            Value::String(s) => s.to_string(),
7025            _ => return Err(RuntimeError::new("regex_split() requires string text")),
7026        };
7027
7028        match Regex::new(&pattern) {
7029            Ok(re) => {
7030                let parts: Vec<Value> = re
7031                    .split(&text)
7032                    .map(|s| Value::String(Rc::new(s.to_string())))
7033                    .collect();
7034                Ok(Value::Array(Rc::new(RefCell::new(parts))))
7035            }
7036            Err(e) => Err(RuntimeError::new(format!(
7037                "regex_split() invalid pattern: {}",
7038                e
7039            ))),
7040        }
7041    });
7042
7043    // regex_captures - capture groups
7044    define(interp, "regex_captures", Some(2), |_, args| {
7045        let pattern = match &args[0] {
7046            Value::String(s) => s.to_string(),
7047            _ => {
7048                return Err(RuntimeError::new(
7049                    "regex_captures() requires string pattern",
7050                ))
7051            }
7052        };
7053        let text = match &args[1] {
7054            Value::String(s) => s.to_string(),
7055            _ => return Err(RuntimeError::new("regex_captures() requires string text")),
7056        };
7057
7058        match Regex::new(&pattern) {
7059            Ok(re) => match re.captures(&text) {
7060                Some(caps) => {
7061                    let captures: Vec<Value> = caps
7062                        .iter()
7063                        .map(|m| {
7064                            m.map(|m| Value::String(Rc::new(m.as_str().to_string())))
7065                                .unwrap_or(Value::Null)
7066                        })
7067                        .collect();
7068                    Ok(Value::Array(Rc::new(RefCell::new(captures))))
7069                }
7070                None => Ok(Value::Null),
7071            },
7072            Err(e) => Err(RuntimeError::new(format!(
7073                "regex_captures() invalid pattern: {}",
7074                e
7075            ))),
7076        }
7077    });
7078}
7079
7080// ============================================================================
7081// UUID FUNCTIONS
7082// ============================================================================
7083
7084fn register_uuid(interp: &mut Interpreter) {
7085    // uuid_v4 - generate random UUID v4
7086    define(interp, "uuid_v4", Some(0), |_, _| {
7087        let id = Uuid::new_v4();
7088        Ok(Value::String(Rc::new(id.to_string())))
7089    });
7090
7091    // uuid_nil - get nil UUID (all zeros)
7092    define(interp, "uuid_nil", Some(0), |_, _| {
7093        Ok(Value::String(Rc::new(Uuid::nil().to_string())))
7094    });
7095
7096    // uuid_parse - parse UUID string
7097    define(interp, "uuid_parse", Some(1), |_, args| {
7098        let s = match &args[0] {
7099            Value::String(s) => s.to_string(),
7100            _ => return Err(RuntimeError::new("uuid_parse() requires string")),
7101        };
7102
7103        match Uuid::parse_str(&s) {
7104            Ok(id) => Ok(Value::String(Rc::new(id.to_string()))),
7105            Err(e) => Err(RuntimeError::new(format!("uuid_parse() error: {}", e))),
7106        }
7107    });
7108
7109    // uuid_is_valid - check if string is valid UUID
7110    define(interp, "uuid_is_valid", Some(1), |_, args| {
7111        let s = match &args[0] {
7112            Value::String(s) => s.to_string(),
7113            _ => return Ok(Value::Bool(false)),
7114        };
7115        Ok(Value::Bool(Uuid::parse_str(&s).is_ok()))
7116    });
7117}
7118
7119// ============================================================================
7120// SYSTEM FUNCTIONS
7121// ============================================================================
7122
7123fn register_system(interp: &mut Interpreter) {
7124    // env_get - get environment variable
7125    define(interp, "env_get", Some(1), |_, args| {
7126        let key = match &args[0] {
7127            Value::String(s) => s.to_string(),
7128            _ => return Err(RuntimeError::new("env_get() requires string key")),
7129        };
7130
7131        match std::env::var(&key) {
7132            Ok(val) => Ok(Value::String(Rc::new(val))),
7133            Err(_) => Ok(Value::Null),
7134        }
7135    });
7136
7137    // env_set - set environment variable
7138    define(interp, "env_set", Some(2), |_, args| {
7139        let key = match &args[0] {
7140            Value::String(s) => s.to_string(),
7141            _ => return Err(RuntimeError::new("env_set() requires string key")),
7142        };
7143        let val = match &args[1] {
7144            Value::String(s) => s.to_string(),
7145            _ => format!("{}", args[1]),
7146        };
7147
7148        std::env::set_var(&key, &val);
7149        Ok(Value::Null)
7150    });
7151
7152    // env_remove - remove environment variable
7153    define(interp, "env_remove", Some(1), |_, args| {
7154        let key = match &args[0] {
7155            Value::String(s) => s.to_string(),
7156            _ => return Err(RuntimeError::new("env_remove() requires string key")),
7157        };
7158
7159        std::env::remove_var(&key);
7160        Ok(Value::Null)
7161    });
7162
7163    // env_vars - get all environment variables as map
7164    define(interp, "env_vars", Some(0), |_, _| {
7165        let mut map = HashMap::new();
7166        for (key, val) in std::env::vars() {
7167            map.insert(key, Value::String(Rc::new(val)));
7168        }
7169        Ok(Value::Map(Rc::new(RefCell::new(map))))
7170    });
7171
7172    // args - get command line arguments
7173    define(interp, "args", Some(0), |_, _| {
7174        let args: Vec<Value> = std::env::args()
7175            .map(|s| Value::String(Rc::new(s)))
7176            .collect();
7177        Ok(Value::Array(Rc::new(RefCell::new(args))))
7178    });
7179
7180    // cwd - get current working directory
7181    define(interp, "cwd", Some(0), |_, _| {
7182        match std::env::current_dir() {
7183            Ok(path) => Ok(Value::String(Rc::new(path.to_string_lossy().to_string()))),
7184            Err(e) => Err(RuntimeError::new(format!("cwd() error: {}", e))),
7185        }
7186    });
7187
7188    // chdir - change current directory
7189    define(interp, "chdir", Some(1), |_, args| {
7190        let path = match &args[0] {
7191            Value::String(s) => s.to_string(),
7192            _ => return Err(RuntimeError::new("chdir() requires string path")),
7193        };
7194
7195        match std::env::set_current_dir(&path) {
7196            Ok(()) => Ok(Value::Null),
7197            Err(e) => Err(RuntimeError::new(format!("chdir() error: {}", e))),
7198        }
7199    });
7200
7201    // hostname - get system hostname
7202    define(interp, "hostname", Some(0), |_, _| {
7203        // Try to read from /etc/hostname or use fallback
7204        match std::fs::read_to_string("/etc/hostname") {
7205            Ok(name) => Ok(Value::String(Rc::new(name.trim().to_string()))),
7206            Err(_) => Ok(Value::String(Rc::new("unknown".to_string()))),
7207        }
7208    });
7209
7210    // pid - get current process ID
7211    define(interp, "pid", Some(0), |_, _| {
7212        Ok(Value::Int(std::process::id() as i64))
7213    });
7214
7215    // exit - exit the program with code
7216    define(interp, "exit", Some(1), |_, args| {
7217        let code = match &args[0] {
7218            Value::Int(n) => *n as i32,
7219            _ => 0,
7220        };
7221        std::process::exit(code);
7222    });
7223
7224    // shell - execute shell command and return output
7225    define(interp, "shell", Some(1), |_, args| {
7226        let cmd = match &args[0] {
7227            Value::String(s) => s.to_string(),
7228            _ => return Err(RuntimeError::new("shell() requires string command")),
7229        };
7230
7231        match std::process::Command::new("sh")
7232            .arg("-c")
7233            .arg(&cmd)
7234            .output()
7235        {
7236            Ok(output) => {
7237                let stdout = String::from_utf8_lossy(&output.stdout).to_string();
7238                let stderr = String::from_utf8_lossy(&output.stderr).to_string();
7239                let code = output.status.code().unwrap_or(-1);
7240
7241                let mut result = HashMap::new();
7242                result.insert("stdout".to_string(), Value::String(Rc::new(stdout)));
7243                result.insert("stderr".to_string(), Value::String(Rc::new(stderr)));
7244                result.insert("code".to_string(), Value::Int(code as i64));
7245                result.insert("success".to_string(), Value::Bool(output.status.success()));
7246
7247                Ok(Value::Map(Rc::new(RefCell::new(result))))
7248            }
7249            Err(e) => Err(RuntimeError::new(format!("shell() error: {}", e))),
7250        }
7251    });
7252
7253    // platform - get OS name
7254    define(interp, "platform", Some(0), |_, _| {
7255        Ok(Value::String(Rc::new(std::env::consts::OS.to_string())))
7256    });
7257
7258    // arch - get CPU architecture
7259    define(interp, "arch", Some(0), |_, _| {
7260        Ok(Value::String(Rc::new(std::env::consts::ARCH.to_string())))
7261    });
7262}
7263
7264// ============================================================================
7265// STATISTICS FUNCTIONS
7266// ============================================================================
7267
7268fn register_stats(interp: &mut Interpreter) {
7269    // Helper to extract numbers from array
7270    fn extract_numbers(val: &Value) -> Result<Vec<f64>, RuntimeError> {
7271        match val {
7272            Value::Array(arr) => {
7273                let arr = arr.borrow();
7274                let mut nums = Vec::new();
7275                for v in arr.iter() {
7276                    match v {
7277                        Value::Int(n) => nums.push(*n as f64),
7278                        Value::Float(f) => nums.push(*f),
7279                        _ => {
7280                            return Err(RuntimeError::new("stats functions require numeric array"))
7281                        }
7282                    }
7283                }
7284                Ok(nums)
7285            }
7286            _ => Err(RuntimeError::new("stats functions require array")),
7287        }
7288    }
7289
7290    // mean - arithmetic mean
7291    define(interp, "mean", Some(1), |_, args| {
7292        let nums = extract_numbers(&args[0])?;
7293        if nums.is_empty() {
7294            return Ok(Value::Float(0.0));
7295        }
7296        let sum: f64 = nums.iter().sum();
7297        Ok(Value::Float(sum / nums.len() as f64))
7298    });
7299
7300    // median - middle value
7301    define(interp, "median", Some(1), |_, args| {
7302        let mut nums = extract_numbers(&args[0])?;
7303        if nums.is_empty() {
7304            return Ok(Value::Float(0.0));
7305        }
7306        nums.sort_by(|a, b| a.partial_cmp(b).unwrap());
7307        let len = nums.len();
7308        if len % 2 == 0 {
7309            Ok(Value::Float((nums[len / 2 - 1] + nums[len / 2]) / 2.0))
7310        } else {
7311            Ok(Value::Float(nums[len / 2]))
7312        }
7313    });
7314
7315    // mode - most frequent value
7316    define(interp, "mode", Some(1), |_, args| {
7317        let nums = extract_numbers(&args[0])?;
7318        if nums.is_empty() {
7319            return Ok(Value::Null);
7320        }
7321
7322        let mut counts: HashMap<String, usize> = HashMap::new();
7323        for n in &nums {
7324            let key = format!("{:.10}", n);
7325            *counts.entry(key).or_insert(0) += 1;
7326        }
7327
7328        let max_count = counts.values().max().unwrap_or(&0);
7329        for n in &nums {
7330            let key = format!("{:.10}", n);
7331            if counts.get(&key) == Some(max_count) {
7332                return Ok(Value::Float(*n));
7333            }
7334        }
7335        Ok(Value::Null)
7336    });
7337
7338    // variance - population variance
7339    define(interp, "variance", Some(1), |_, args| {
7340        let nums = extract_numbers(&args[0])?;
7341        if nums.is_empty() {
7342            return Ok(Value::Float(0.0));
7343        }
7344        let mean: f64 = nums.iter().sum::<f64>() / nums.len() as f64;
7345        let variance: f64 =
7346            nums.iter().map(|x| (x - mean).powi(2)).sum::<f64>() / nums.len() as f64;
7347        Ok(Value::Float(variance))
7348    });
7349
7350    // stddev - standard deviation
7351    define(interp, "stddev", Some(1), |_, args| {
7352        let nums = extract_numbers(&args[0])?;
7353        if nums.is_empty() {
7354            return Ok(Value::Float(0.0));
7355        }
7356        let mean: f64 = nums.iter().sum::<f64>() / nums.len() as f64;
7357        let variance: f64 =
7358            nums.iter().map(|x| (x - mean).powi(2)).sum::<f64>() / nums.len() as f64;
7359        Ok(Value::Float(variance.sqrt()))
7360    });
7361
7362    // percentile - compute nth percentile
7363    define(interp, "percentile", Some(2), |_, args| {
7364        let mut nums = extract_numbers(&args[0])?;
7365        let p = match &args[1] {
7366            Value::Int(n) => *n as f64,
7367            Value::Float(f) => *f,
7368            _ => {
7369                return Err(RuntimeError::new(
7370                    "percentile() requires numeric percentile",
7371                ))
7372            }
7373        };
7374
7375        if nums.is_empty() {
7376            return Ok(Value::Float(0.0));
7377        }
7378
7379        nums.sort_by(|a, b| a.partial_cmp(b).unwrap());
7380        let idx = (p / 100.0 * (nums.len() - 1) as f64).round() as usize;
7381        Ok(Value::Float(nums[idx.min(nums.len() - 1)]))
7382    });
7383
7384    // correlation - Pearson correlation coefficient
7385    define(interp, "correlation", Some(2), |_, args| {
7386        let x = extract_numbers(&args[0])?;
7387        let y = extract_numbers(&args[1])?;
7388
7389        if x.len() != y.len() || x.is_empty() {
7390            return Err(RuntimeError::new(
7391                "correlation() requires equal-length non-empty arrays",
7392            ));
7393        }
7394
7395        let n = x.len() as f64;
7396        let mean_x: f64 = x.iter().sum::<f64>() / n;
7397        let mean_y: f64 = y.iter().sum::<f64>() / n;
7398
7399        let mut cov = 0.0;
7400        let mut var_x = 0.0;
7401        let mut var_y = 0.0;
7402
7403        for i in 0..x.len() {
7404            let dx = x[i] - mean_x;
7405            let dy = y[i] - mean_y;
7406            cov += dx * dy;
7407            var_x += dx * dx;
7408            var_y += dy * dy;
7409        }
7410
7411        if var_x == 0.0 || var_y == 0.0 {
7412            return Ok(Value::Float(0.0));
7413        }
7414
7415        Ok(Value::Float(cov / (var_x.sqrt() * var_y.sqrt())))
7416    });
7417
7418    // range - difference between max and min
7419    define(interp, "range", Some(1), |_, args| {
7420        let nums = extract_numbers(&args[0])?;
7421        if nums.is_empty() {
7422            return Ok(Value::Float(0.0));
7423        }
7424        let min = nums.iter().cloned().fold(f64::INFINITY, f64::min);
7425        let max = nums.iter().cloned().fold(f64::NEG_INFINITY, f64::max);
7426        Ok(Value::Float(max - min))
7427    });
7428
7429    // zscore - compute z-scores for array
7430    define(interp, "zscore", Some(1), |_, args| {
7431        let nums = extract_numbers(&args[0])?;
7432        if nums.is_empty() {
7433            return Ok(Value::Array(Rc::new(RefCell::new(vec![]))));
7434        }
7435
7436        let mean: f64 = nums.iter().sum::<f64>() / nums.len() as f64;
7437        let variance: f64 =
7438            nums.iter().map(|x| (x - mean).powi(2)).sum::<f64>() / nums.len() as f64;
7439        let stddev = variance.sqrt();
7440
7441        if stddev == 0.0 {
7442            let zeros: Vec<Value> = nums.iter().map(|_| Value::Float(0.0)).collect();
7443            return Ok(Value::Array(Rc::new(RefCell::new(zeros))));
7444        }
7445
7446        let zscores: Vec<Value> = nums
7447            .iter()
7448            .map(|x| Value::Float((x - mean) / stddev))
7449            .collect();
7450        Ok(Value::Array(Rc::new(RefCell::new(zscores))))
7451    });
7452}
7453
7454// ============================================================================
7455// MATRIX FUNCTIONS
7456// ============================================================================
7457
7458fn register_matrix(interp: &mut Interpreter) {
7459    // Helper to extract 2D matrix from nested arrays
7460    fn extract_matrix(val: &Value) -> Result<Vec<Vec<f64>>, RuntimeError> {
7461        match val {
7462            Value::Array(arr) => {
7463                let arr = arr.borrow();
7464                let mut matrix = Vec::new();
7465                for row in arr.iter() {
7466                    match row {
7467                        Value::Array(row_arr) => {
7468                            let row_arr = row_arr.borrow();
7469                            let mut row_vec = Vec::new();
7470                            for v in row_arr.iter() {
7471                                match v {
7472                                    Value::Int(n) => row_vec.push(*n as f64),
7473                                    Value::Float(f) => row_vec.push(*f),
7474                                    _ => {
7475                                        return Err(RuntimeError::new(
7476                                            "matrix requires numeric values",
7477                                        ))
7478                                    }
7479                                }
7480                            }
7481                            matrix.push(row_vec);
7482                        }
7483                        _ => return Err(RuntimeError::new("matrix requires 2D array")),
7484                    }
7485                }
7486                Ok(matrix)
7487            }
7488            _ => Err(RuntimeError::new("matrix requires array")),
7489        }
7490    }
7491
7492    fn matrix_to_value(m: Vec<Vec<f64>>) -> Value {
7493        let rows: Vec<Value> = m
7494            .into_iter()
7495            .map(|row| {
7496                let cols: Vec<Value> = row.into_iter().map(Value::Float).collect();
7497                Value::Array(Rc::new(RefCell::new(cols)))
7498            })
7499            .collect();
7500        Value::Array(Rc::new(RefCell::new(rows)))
7501    }
7502
7503    // matrix_new - create matrix filled with value
7504    define(interp, "matrix_new", Some(3), |_, args| {
7505        let rows = match &args[0] {
7506            Value::Int(n) => *n as usize,
7507            _ => return Err(RuntimeError::new("matrix_new() requires integer rows")),
7508        };
7509        let cols = match &args[1] {
7510            Value::Int(n) => *n as usize,
7511            _ => return Err(RuntimeError::new("matrix_new() requires integer cols")),
7512        };
7513        let fill = match &args[2] {
7514            Value::Int(n) => *n as f64,
7515            Value::Float(f) => *f,
7516            _ => 0.0,
7517        };
7518
7519        let matrix = vec![vec![fill; cols]; rows];
7520        Ok(matrix_to_value(matrix))
7521    });
7522
7523    // matrix_identity - create identity matrix
7524    define(interp, "matrix_identity", Some(1), |_, args| {
7525        let size = match &args[0] {
7526            Value::Int(n) => *n as usize,
7527            _ => return Err(RuntimeError::new("matrix_identity() requires integer size")),
7528        };
7529
7530        let mut matrix = vec![vec![0.0; size]; size];
7531        for i in 0..size {
7532            matrix[i][i] = 1.0;
7533        }
7534        Ok(matrix_to_value(matrix))
7535    });
7536
7537    // matrix_add - add two matrices
7538    define(interp, "matrix_add", Some(2), |_, args| {
7539        let a = extract_matrix(&args[0])?;
7540        let b = extract_matrix(&args[1])?;
7541
7542        if a.len() != b.len() || a.is_empty() || a[0].len() != b[0].len() {
7543            return Err(RuntimeError::new(
7544                "matrix_add() requires same-size matrices",
7545            ));
7546        }
7547
7548        let result: Vec<Vec<f64>> = a
7549            .iter()
7550            .zip(b.iter())
7551            .map(|(row_a, row_b)| row_a.iter().zip(row_b.iter()).map(|(x, y)| x + y).collect())
7552            .collect();
7553
7554        Ok(matrix_to_value(result))
7555    });
7556
7557    // matrix_sub - subtract two matrices
7558    define(interp, "matrix_sub", Some(2), |_, args| {
7559        let a = extract_matrix(&args[0])?;
7560        let b = extract_matrix(&args[1])?;
7561
7562        if a.len() != b.len() || a.is_empty() || a[0].len() != b[0].len() {
7563            return Err(RuntimeError::new(
7564                "matrix_sub() requires same-size matrices",
7565            ));
7566        }
7567
7568        let result: Vec<Vec<f64>> = a
7569            .iter()
7570            .zip(b.iter())
7571            .map(|(row_a, row_b)| row_a.iter().zip(row_b.iter()).map(|(x, y)| x - y).collect())
7572            .collect();
7573
7574        Ok(matrix_to_value(result))
7575    });
7576
7577    // matrix_mul - multiply two matrices
7578    define(interp, "matrix_mul", Some(2), |_, args| {
7579        let a = extract_matrix(&args[0])?;
7580        let b = extract_matrix(&args[1])?;
7581
7582        if a.is_empty() || b.is_empty() || a[0].len() != b.len() {
7583            return Err(RuntimeError::new(
7584                "matrix_mul() requires compatible matrices (a.cols == b.rows)",
7585            ));
7586        }
7587
7588        let rows = a.len();
7589        let cols = b[0].len();
7590        let inner = b.len();
7591
7592        let mut result = vec![vec![0.0; cols]; rows];
7593        for i in 0..rows {
7594            for j in 0..cols {
7595                for k in 0..inner {
7596                    result[i][j] += a[i][k] * b[k][j];
7597                }
7598            }
7599        }
7600
7601        Ok(matrix_to_value(result))
7602    });
7603
7604    // matrix_scale - multiply matrix by scalar
7605    define(interp, "matrix_scale", Some(2), |_, args| {
7606        let m = extract_matrix(&args[0])?;
7607        let scale = match &args[1] {
7608            Value::Int(n) => *n as f64,
7609            Value::Float(f) => *f,
7610            _ => return Err(RuntimeError::new("matrix_scale() requires numeric scalar")),
7611        };
7612
7613        let result: Vec<Vec<f64>> = m
7614            .iter()
7615            .map(|row| row.iter().map(|x| x * scale).collect())
7616            .collect();
7617
7618        Ok(matrix_to_value(result))
7619    });
7620
7621    // matrix_transpose - transpose matrix
7622    define(interp, "matrix_transpose", Some(1), |_, args| {
7623        let m = extract_matrix(&args[0])?;
7624        if m.is_empty() {
7625            return Ok(Value::Array(Rc::new(RefCell::new(vec![]))));
7626        }
7627
7628        let rows = m.len();
7629        let cols = m[0].len();
7630        let mut result = vec![vec![0.0; rows]; cols];
7631
7632        for i in 0..rows {
7633            for j in 0..cols {
7634                result[j][i] = m[i][j];
7635            }
7636        }
7637
7638        Ok(matrix_to_value(result))
7639    });
7640
7641    // matrix_det - determinant (for 2x2 and 3x3)
7642    define(interp, "matrix_det", Some(1), |_, args| {
7643        let m = extract_matrix(&args[0])?;
7644
7645        if m.is_empty() || m.len() != m[0].len() {
7646            return Err(RuntimeError::new("matrix_det() requires square matrix"));
7647        }
7648
7649        let n = m.len();
7650        match n {
7651            1 => Ok(Value::Float(m[0][0])),
7652            2 => Ok(Value::Float(m[0][0] * m[1][1] - m[0][1] * m[1][0])),
7653            3 => {
7654                let det = m[0][0] * (m[1][1] * m[2][2] - m[1][2] * m[2][1])
7655                    - m[0][1] * (m[1][0] * m[2][2] - m[1][2] * m[2][0])
7656                    + m[0][2] * (m[1][0] * m[2][1] - m[1][1] * m[2][0]);
7657                Ok(Value::Float(det))
7658            }
7659            _ => Err(RuntimeError::new(
7660                "matrix_det() only supports up to 3x3 matrices",
7661            )),
7662        }
7663    });
7664
7665    // matrix_trace - trace (sum of diagonal)
7666    define(interp, "matrix_trace", Some(1), |_, args| {
7667        let m = extract_matrix(&args[0])?;
7668
7669        let size = m.len().min(if m.is_empty() { 0 } else { m[0].len() });
7670        let trace: f64 = (0..size).map(|i| m[i][i]).sum();
7671
7672        Ok(Value::Float(trace))
7673    });
7674
7675    // matrix_dot - dot product of vectors (1D arrays)
7676    define(interp, "matrix_dot", Some(2), |_, args| {
7677        fn extract_vector(val: &Value) -> Result<Vec<f64>, RuntimeError> {
7678            match val {
7679                Value::Array(arr) => {
7680                    let arr = arr.borrow();
7681                    let mut vec = Vec::new();
7682                    for v in arr.iter() {
7683                        match v {
7684                            Value::Int(n) => vec.push(*n as f64),
7685                            Value::Float(f) => vec.push(*f),
7686                            _ => {
7687                                return Err(RuntimeError::new(
7688                                    "dot product requires numeric vectors",
7689                                ))
7690                            }
7691                        }
7692                    }
7693                    Ok(vec)
7694                }
7695                _ => Err(RuntimeError::new("dot product requires arrays")),
7696            }
7697        }
7698
7699        let a = extract_vector(&args[0])?;
7700        let b = extract_vector(&args[1])?;
7701
7702        if a.len() != b.len() {
7703            return Err(RuntimeError::new(
7704                "matrix_dot() requires same-length vectors",
7705            ));
7706        }
7707
7708        let dot: f64 = a.iter().zip(b.iter()).map(|(x, y)| x * y).sum();
7709        Ok(Value::Float(dot))
7710    });
7711}
7712
7713// Extended Euclidean algorithm for modular inverse
7714fn mod_inverse(a: i64, m: i64) -> Option<i64> {
7715    let (mut old_r, mut r) = (a, m);
7716    let (mut old_s, mut s) = (1i64, 0i64);
7717
7718    while r != 0 {
7719        let q = old_r / r;
7720        (old_r, r) = (r, old_r - q * r);
7721        (old_s, s) = (s, old_s - q * s);
7722    }
7723
7724    if old_r != 1 {
7725        None // No inverse exists
7726    } else {
7727        Some(old_s.rem_euclid(m))
7728    }
7729}
7730
7731// ============================================================================
7732// Phase 5: Language Power-Ups
7733// ============================================================================
7734
7735/// Functional programming utilities
7736fn register_functional(interp: &mut Interpreter) {
7737    // identity - returns its argument unchanged
7738    define(interp, "identity", Some(1), |_, args| Ok(args[0].clone()));
7739
7740    // const_fn - returns a function that always returns the given value
7741    define(interp, "const_fn", Some(1), |_, args| Ok(args[0].clone()));
7742
7743    // apply - apply a function to an array of arguments
7744    define(interp, "apply", Some(2), |interp, args| {
7745        let func = match &args[0] {
7746            Value::Function(f) => f.clone(),
7747            _ => {
7748                return Err(RuntimeError::new(
7749                    "apply: first argument must be a function",
7750                ))
7751            }
7752        };
7753        let fn_args = match &args[1] {
7754            Value::Array(arr) => arr.borrow().clone(),
7755            _ => return Err(RuntimeError::new("apply: second argument must be an array")),
7756        };
7757        interp.call_function(&func, fn_args)
7758    });
7759
7760    // flip - swap the first two arguments of a binary function
7761    define(interp, "flip", Some(3), |interp, args| {
7762        let func = match &args[0] {
7763            Value::Function(f) => f.clone(),
7764            _ => return Err(RuntimeError::new("flip: first argument must be a function")),
7765        };
7766        let flipped_args = vec![args[2].clone(), args[1].clone()];
7767        interp.call_function(&func, flipped_args)
7768    });
7769
7770    // tap - execute a function for side effects, return original value
7771    define(interp, "tap", Some(2), |interp, args| {
7772        let val = args[0].clone();
7773        let func = match &args[1] {
7774            Value::Function(f) => f.clone(),
7775            _ => return Err(RuntimeError::new("tap: second argument must be a function")),
7776        };
7777        let _ = interp.call_function(&func, vec![val.clone()]);
7778        Ok(val)
7779    });
7780
7781    // thunk - create a delayed computation (wrap in array for later forcing)
7782    define(interp, "thunk", Some(1), |_, args| {
7783        Ok(Value::Array(Rc::new(RefCell::new(vec![args[0].clone()]))))
7784    });
7785
7786    // force - force evaluation of a thunk
7787    define(interp, "force", Some(1), |interp, args| match &args[0] {
7788        Value::Array(arr) => {
7789            let arr = arr.borrow();
7790            if arr.len() == 1 {
7791                if let Value::Function(f) = &arr[0] {
7792                    return interp.call_function(f, vec![]);
7793                }
7794            }
7795            Ok(arr.get(0).cloned().unwrap_or(Value::Null))
7796        }
7797        v => Ok(v.clone()),
7798    });
7799
7800    // negate - negate a predicate function result
7801    define(interp, "negate", Some(2), |interp, args| {
7802        let func = match &args[0] {
7803            Value::Function(f) => f.clone(),
7804            _ => {
7805                return Err(RuntimeError::new(
7806                    "negate: first argument must be a function",
7807                ))
7808            }
7809        };
7810        let result = interp.call_function(&func, vec![args[1].clone()])?;
7811        Ok(Value::Bool(!is_truthy(&result)))
7812    });
7813
7814    // complement - same as negate
7815    define(interp, "complement", Some(2), |interp, args| {
7816        let func = match &args[0] {
7817            Value::Function(f) => f.clone(),
7818            _ => {
7819                return Err(RuntimeError::new(
7820                    "complement: first argument must be a function",
7821                ))
7822            }
7823        };
7824        let result = interp.call_function(&func, vec![args[1].clone()])?;
7825        Ok(Value::Bool(!is_truthy(&result)))
7826    });
7827
7828    // partial - partially apply a function with some arguments
7829    define(interp, "partial", None, |interp, args| {
7830        if args.len() < 2 {
7831            return Err(RuntimeError::new(
7832                "partial: requires at least function and one argument",
7833            ));
7834        }
7835        let func = match &args[0] {
7836            Value::Function(f) => f.clone(),
7837            _ => {
7838                return Err(RuntimeError::new(
7839                    "partial: first argument must be a function",
7840                ))
7841            }
7842        };
7843        let partial_args: Vec<Value> = args[1..].to_vec();
7844        interp.call_function(&func, partial_args)
7845    });
7846
7847    // juxt - apply multiple functions to same args, return array of results
7848    define(interp, "juxt", None, |interp, args| {
7849        if args.len() < 2 {
7850            return Err(RuntimeError::new("juxt: requires functions and a value"));
7851        }
7852        let val = args.last().unwrap().clone();
7853        let results: Result<Vec<Value>, _> = args[..args.len() - 1]
7854            .iter()
7855            .map(|f| match f {
7856                Value::Function(func) => interp.call_function(func, vec![val.clone()]),
7857                _ => Err(RuntimeError::new(
7858                    "juxt: all but last argument must be functions",
7859                )),
7860            })
7861            .collect();
7862        Ok(Value::Array(Rc::new(RefCell::new(results?))))
7863    });
7864}
7865
7866/// Benchmarking and profiling utilities
7867fn register_benchmark(interp: &mut Interpreter) {
7868    // bench - run a function N times and return average time in ms
7869    define(interp, "bench", Some(2), |interp, args| {
7870        let func = match &args[0] {
7871            Value::Function(f) => f.clone(),
7872            _ => {
7873                return Err(RuntimeError::new(
7874                    "bench: first argument must be a function",
7875                ))
7876            }
7877        };
7878        let iterations = match &args[1] {
7879            Value::Int(n) => *n as usize,
7880            _ => {
7881                return Err(RuntimeError::new(
7882                    "bench: second argument must be an integer",
7883                ))
7884            }
7885        };
7886
7887        let start = std::time::Instant::now();
7888        for _ in 0..iterations {
7889            let _ = interp.call_function(&func, vec![])?;
7890        }
7891        let elapsed = start.elapsed();
7892        let avg_ms = elapsed.as_secs_f64() * 1000.0 / iterations as f64;
7893        Ok(Value::Float(avg_ms))
7894    });
7895
7896    // time_it - run a function once and return (result, time_ms) tuple
7897    define(interp, "time_it", Some(1), |interp, args| {
7898        let func = match &args[0] {
7899            Value::Function(f) => f.clone(),
7900            _ => return Err(RuntimeError::new("time_it: argument must be a function")),
7901        };
7902
7903        let start = std::time::Instant::now();
7904        let result = interp.call_function(&func, vec![])?;
7905        let elapsed_ms = start.elapsed().as_secs_f64() * 1000.0;
7906
7907        Ok(Value::Tuple(Rc::new(vec![
7908            result,
7909            Value::Float(elapsed_ms),
7910        ])))
7911    });
7912
7913    // stopwatch_start - return current time in ms
7914    define(interp, "stopwatch_start", Some(0), |_, _| {
7915        let elapsed = std::time::SystemTime::now()
7916            .duration_since(std::time::UNIX_EPOCH)
7917            .unwrap_or_default();
7918        Ok(Value::Float(elapsed.as_secs_f64() * 1000.0))
7919    });
7920
7921    // stopwatch_elapsed - get elapsed time since a stopwatch start
7922    define(interp, "stopwatch_elapsed", Some(1), |_, args| {
7923        let start_ms = match &args[0] {
7924            Value::Float(f) => *f,
7925            Value::Int(n) => *n as f64,
7926            _ => {
7927                return Err(RuntimeError::new(
7928                    "stopwatch_elapsed: argument must be a number",
7929                ))
7930            }
7931        };
7932        let now = std::time::SystemTime::now()
7933            .duration_since(std::time::UNIX_EPOCH)
7934            .unwrap_or_default();
7935        let now_ms = now.as_secs_f64() * 1000.0;
7936        Ok(Value::Float(now_ms - start_ms))
7937    });
7938
7939    // compare_bench - compare two functions, return speedup ratio
7940    define(interp, "compare_bench", Some(3), |interp, args| {
7941        let func1 = match &args[0] {
7942            Value::Function(f) => f.clone(),
7943            _ => {
7944                return Err(RuntimeError::new(
7945                    "compare_bench: first argument must be a function",
7946                ))
7947            }
7948        };
7949        let func2 = match &args[1] {
7950            Value::Function(f) => f.clone(),
7951            _ => {
7952                return Err(RuntimeError::new(
7953                    "compare_bench: second argument must be a function",
7954                ))
7955            }
7956        };
7957        let iterations = match &args[2] {
7958            Value::Int(n) => *n as usize,
7959            _ => {
7960                return Err(RuntimeError::new(
7961                    "compare_bench: third argument must be an integer",
7962                ))
7963            }
7964        };
7965
7966        let start1 = std::time::Instant::now();
7967        for _ in 0..iterations {
7968            let _ = interp.call_function(&func1, vec![])?;
7969        }
7970        let time1 = start1.elapsed().as_secs_f64();
7971
7972        let start2 = std::time::Instant::now();
7973        for _ in 0..iterations {
7974            let _ = interp.call_function(&func2, vec![])?;
7975        }
7976        let time2 = start2.elapsed().as_secs_f64();
7977
7978        let mut results = std::collections::HashMap::new();
7979        results.insert("time1_ms".to_string(), Value::Float(time1 * 1000.0));
7980        results.insert("time2_ms".to_string(), Value::Float(time2 * 1000.0));
7981        results.insert("speedup".to_string(), Value::Float(time1 / time2));
7982        results.insert("iterations".to_string(), Value::Int(iterations as i64));
7983
7984        Ok(Value::Struct {
7985            name: "BenchResult".to_string(),
7986            fields: Rc::new(RefCell::new(results)),
7987        })
7988    });
7989
7990    // memory_usage - placeholder
7991    define(interp, "memory_usage", Some(0), |_, _| Ok(Value::Int(0)));
7992}
7993
7994/// Extended iterator utilities (itertools-inspired)
7995fn register_itertools(interp: &mut Interpreter) {
7996    // cycle - create infinite cycle of array elements (returns first N)
7997    define(interp, "cycle", Some(2), |_, args| {
7998        let arr = match &args[0] {
7999            Value::Array(a) => a.borrow().clone(),
8000            _ => return Err(RuntimeError::new("cycle: first argument must be an array")),
8001        };
8002        let n = match &args[1] {
8003            Value::Int(n) => *n as usize,
8004            _ => {
8005                return Err(RuntimeError::new(
8006                    "cycle: second argument must be an integer",
8007                ))
8008            }
8009        };
8010
8011        if arr.is_empty() {
8012            return Ok(Value::Array(Rc::new(RefCell::new(vec![]))));
8013        }
8014
8015        let result: Vec<Value> = (0..n).map(|i| arr[i % arr.len()].clone()).collect();
8016        Ok(Value::Array(Rc::new(RefCell::new(result))))
8017    });
8018
8019    // repeat_val - repeat a value N times
8020    define(interp, "repeat_val", Some(2), |_, args| {
8021        let val = args[0].clone();
8022        let n = match &args[1] {
8023            Value::Int(n) => *n as usize,
8024            _ => {
8025                return Err(RuntimeError::new(
8026                    "repeat_val: second argument must be an integer",
8027                ))
8028            }
8029        };
8030
8031        let result: Vec<Value> = std::iter::repeat(val).take(n).collect();
8032        Ok(Value::Array(Rc::new(RefCell::new(result))))
8033    });
8034
8035    // take_while - take elements while predicate is true
8036    define(interp, "take_while", Some(2), |interp, args| {
8037        let arr = match &args[0] {
8038            Value::Array(a) => a.borrow().clone(),
8039            _ => {
8040                return Err(RuntimeError::new(
8041                    "take_while: first argument must be an array",
8042                ))
8043            }
8044        };
8045        let pred = match &args[1] {
8046            Value::Function(f) => f.clone(),
8047            _ => {
8048                return Err(RuntimeError::new(
8049                    "take_while: second argument must be a function",
8050                ))
8051            }
8052        };
8053
8054        let mut result = Vec::new();
8055        for item in arr {
8056            let keep = interp.call_function(&pred, vec![item.clone()])?;
8057            if is_truthy(&keep) {
8058                result.push(item);
8059            } else {
8060                break;
8061            }
8062        }
8063        Ok(Value::Array(Rc::new(RefCell::new(result))))
8064    });
8065
8066    // drop_while - drop elements while predicate is true
8067    define(interp, "drop_while", Some(2), |interp, args| {
8068        let arr = match &args[0] {
8069            Value::Array(a) => a.borrow().clone(),
8070            _ => {
8071                return Err(RuntimeError::new(
8072                    "drop_while: first argument must be an array",
8073                ))
8074            }
8075        };
8076        let pred = match &args[1] {
8077            Value::Function(f) => f.clone(),
8078            _ => {
8079                return Err(RuntimeError::new(
8080                    "drop_while: second argument must be a function",
8081                ))
8082            }
8083        };
8084
8085        let mut dropping = true;
8086        let mut result = Vec::new();
8087        for item in arr {
8088            if dropping {
8089                let drop = interp.call_function(&pred, vec![item.clone()])?;
8090                if !is_truthy(&drop) {
8091                    dropping = false;
8092                    result.push(item);
8093                }
8094            } else {
8095                result.push(item);
8096            }
8097        }
8098        Ok(Value::Array(Rc::new(RefCell::new(result))))
8099    });
8100
8101    // group_by - group consecutive elements by key function
8102    define(interp, "group_by", Some(2), |interp, args| {
8103        let arr = match &args[0] {
8104            Value::Array(a) => a.borrow().clone(),
8105            _ => {
8106                return Err(RuntimeError::new(
8107                    "group_by: first argument must be an array",
8108                ))
8109            }
8110        };
8111        let key_fn = match &args[1] {
8112            Value::Function(f) => f.clone(),
8113            _ => {
8114                return Err(RuntimeError::new(
8115                    "group_by: second argument must be a function",
8116                ))
8117            }
8118        };
8119
8120        let mut groups: Vec<Value> = Vec::new();
8121        let mut current_group: Vec<Value> = Vec::new();
8122        let mut current_key: Option<Value> = None;
8123
8124        for item in arr {
8125            let key = interp.call_function(&key_fn, vec![item.clone()])?;
8126            match &current_key {
8127                Some(k) if value_eq(k, &key) => {
8128                    current_group.push(item);
8129                }
8130                _ => {
8131                    if !current_group.is_empty() {
8132                        groups.push(Value::Array(Rc::new(RefCell::new(current_group))));
8133                    }
8134                    current_group = vec![item];
8135                    current_key = Some(key);
8136                }
8137            }
8138        }
8139        if !current_group.is_empty() {
8140            groups.push(Value::Array(Rc::new(RefCell::new(current_group))));
8141        }
8142
8143        Ok(Value::Array(Rc::new(RefCell::new(groups))))
8144    });
8145
8146    // partition - split array by predicate into (true_items, false_items)
8147    define(interp, "partition", Some(2), |interp, args| {
8148        let arr = match &args[0] {
8149            Value::Array(a) => a.borrow().clone(),
8150            _ => {
8151                return Err(RuntimeError::new(
8152                    "partition: first argument must be an array",
8153                ))
8154            }
8155        };
8156        let pred = match &args[1] {
8157            Value::Function(f) => f.clone(),
8158            _ => {
8159                return Err(RuntimeError::new(
8160                    "partition: second argument must be a function",
8161                ))
8162            }
8163        };
8164
8165        let mut true_items = Vec::new();
8166        let mut false_items = Vec::new();
8167
8168        for item in arr {
8169            let result = interp.call_function(&pred, vec![item.clone()])?;
8170            if is_truthy(&result) {
8171                true_items.push(item);
8172            } else {
8173                false_items.push(item);
8174            }
8175        }
8176
8177        Ok(Value::Tuple(Rc::new(vec![
8178            Value::Array(Rc::new(RefCell::new(true_items))),
8179            Value::Array(Rc::new(RefCell::new(false_items))),
8180        ])))
8181    });
8182
8183    // interleave - interleave two arrays
8184    define(interp, "interleave", Some(2), |_, args| {
8185        let arr1 = match &args[0] {
8186            Value::Array(a) => a.borrow().clone(),
8187            _ => {
8188                return Err(RuntimeError::new(
8189                    "interleave: first argument must be an array",
8190                ))
8191            }
8192        };
8193        let arr2 = match &args[1] {
8194            Value::Array(a) => a.borrow().clone(),
8195            _ => {
8196                return Err(RuntimeError::new(
8197                    "interleave: second argument must be an array",
8198                ))
8199            }
8200        };
8201
8202        let mut result = Vec::new();
8203        let mut i1 = arr1.into_iter();
8204        let mut i2 = arr2.into_iter();
8205
8206        loop {
8207            match (i1.next(), i2.next()) {
8208                (Some(a), Some(b)) => {
8209                    result.push(a);
8210                    result.push(b);
8211                }
8212                (Some(a), None) => {
8213                    result.push(a);
8214                    result.extend(i1);
8215                    break;
8216                }
8217                (None, Some(b)) => {
8218                    result.push(b);
8219                    result.extend(i2);
8220                    break;
8221                }
8222                (None, None) => break,
8223            }
8224        }
8225
8226        Ok(Value::Array(Rc::new(RefCell::new(result))))
8227    });
8228
8229    // chunks - split array into chunks of size N
8230    define(interp, "chunks", Some(2), |_, args| {
8231        let arr = match &args[0] {
8232            Value::Array(a) => a.borrow().clone(),
8233            _ => return Err(RuntimeError::new("chunks: first argument must be an array")),
8234        };
8235        let size = match &args[1] {
8236            Value::Int(n) if *n > 0 => *n as usize,
8237            _ => {
8238                return Err(RuntimeError::new(
8239                    "chunks: second argument must be a positive integer",
8240                ))
8241            }
8242        };
8243
8244        let chunks: Vec<Value> = arr
8245            .chunks(size)
8246            .map(|chunk| Value::Array(Rc::new(RefCell::new(chunk.to_vec()))))
8247            .collect();
8248
8249        Ok(Value::Array(Rc::new(RefCell::new(chunks))))
8250    });
8251
8252    // windows - sliding windows of size N
8253    define(interp, "windows", Some(2), |_, args| {
8254        let arr = match &args[0] {
8255            Value::Array(a) => a.borrow().clone(),
8256            _ => {
8257                return Err(RuntimeError::new(
8258                    "windows: first argument must be an array",
8259                ))
8260            }
8261        };
8262        let size = match &args[1] {
8263            Value::Int(n) if *n > 0 => *n as usize,
8264            _ => {
8265                return Err(RuntimeError::new(
8266                    "windows: second argument must be a positive integer",
8267                ))
8268            }
8269        };
8270
8271        if arr.len() < size {
8272            return Ok(Value::Array(Rc::new(RefCell::new(vec![]))));
8273        }
8274
8275        let windows: Vec<Value> = arr
8276            .windows(size)
8277            .map(|window| Value::Array(Rc::new(RefCell::new(window.to_vec()))))
8278            .collect();
8279
8280        Ok(Value::Array(Rc::new(RefCell::new(windows))))
8281    });
8282
8283    // scan - like fold but returns all intermediate values
8284    define(interp, "scan", Some(3), |interp, args| {
8285        let arr = match &args[0] {
8286            Value::Array(a) => a.borrow().clone(),
8287            _ => return Err(RuntimeError::new("scan: first argument must be an array")),
8288        };
8289        let init = args[1].clone();
8290        let func = match &args[2] {
8291            Value::Function(f) => f.clone(),
8292            _ => return Err(RuntimeError::new("scan: third argument must be a function")),
8293        };
8294
8295        let mut results = vec![init.clone()];
8296        let mut acc = init;
8297
8298        for item in arr {
8299            acc = interp.call_function(&func, vec![acc, item])?;
8300            results.push(acc.clone());
8301        }
8302
8303        Ok(Value::Array(Rc::new(RefCell::new(results))))
8304    });
8305
8306    // frequencies - count occurrences of each element
8307    define(interp, "frequencies", Some(1), |_, args| {
8308        let arr = match &args[0] {
8309            Value::Array(a) => a.borrow().clone(),
8310            _ => return Err(RuntimeError::new("frequencies: argument must be an array")),
8311        };
8312
8313        let mut counts: std::collections::HashMap<String, i64> = std::collections::HashMap::new();
8314        for item in &arr {
8315            let key = format!("{}", item);
8316            *counts.entry(key).or_insert(0) += 1;
8317        }
8318
8319        let result: std::collections::HashMap<String, Value> = counts
8320            .into_iter()
8321            .map(|(k, v)| (k, Value::Int(v)))
8322            .collect();
8323
8324        Ok(Value::Map(Rc::new(RefCell::new(result))))
8325    });
8326
8327    // dedupe - remove consecutive duplicates
8328    define(interp, "dedupe", Some(1), |_, args| {
8329        let arr = match &args[0] {
8330            Value::Array(a) => a.borrow().clone(),
8331            _ => return Err(RuntimeError::new("dedupe: argument must be an array")),
8332        };
8333
8334        let mut result = Vec::new();
8335        let mut prev: Option<Value> = None;
8336
8337        for item in arr {
8338            match &prev {
8339                Some(p) if value_eq(p, &item) => continue,
8340                _ => {
8341                    result.push(item.clone());
8342                    prev = Some(item);
8343                }
8344            }
8345        }
8346
8347        Ok(Value::Array(Rc::new(RefCell::new(result))))
8348    });
8349
8350    // unique - remove all duplicates (not just consecutive)
8351    define(interp, "unique", Some(1), |_, args| {
8352        let arr = match &args[0] {
8353            Value::Array(a) => a.borrow().clone(),
8354            _ => return Err(RuntimeError::new("unique: argument must be an array")),
8355        };
8356
8357        let mut seen = std::collections::HashSet::new();
8358        let mut result = Vec::new();
8359
8360        for item in arr {
8361            let key = format!("{}", item);
8362            if seen.insert(key) {
8363                result.push(item);
8364            }
8365        }
8366
8367        Ok(Value::Array(Rc::new(RefCell::new(result))))
8368    });
8369}
8370
8371/// Advanced range utilities
8372fn register_ranges(interp: &mut Interpreter) {
8373    // range_step - range with custom step
8374    define(interp, "range_step", Some(3), |_, args| {
8375        let start = match &args[0] {
8376            Value::Int(n) => *n,
8377            Value::Float(f) => *f as i64,
8378            _ => return Err(RuntimeError::new("range_step: start must be a number")),
8379        };
8380        let end = match &args[1] {
8381            Value::Int(n) => *n,
8382            Value::Float(f) => *f as i64,
8383            _ => return Err(RuntimeError::new("range_step: end must be a number")),
8384        };
8385        let step = match &args[2] {
8386            Value::Int(n) if *n != 0 => *n,
8387            Value::Float(f) if *f != 0.0 => *f as i64,
8388            _ => {
8389                return Err(RuntimeError::new(
8390                    "range_step: step must be a non-zero number",
8391                ))
8392            }
8393        };
8394
8395        let mut result = Vec::new();
8396        if step > 0 {
8397            let mut i = start;
8398            while i < end {
8399                result.push(Value::Int(i));
8400                i += step;
8401            }
8402        } else {
8403            let mut i = start;
8404            while i > end {
8405                result.push(Value::Int(i));
8406                i += step;
8407            }
8408        }
8409
8410        Ok(Value::Array(Rc::new(RefCell::new(result))))
8411    });
8412
8413    // linspace - N evenly spaced values from start to end (inclusive)
8414    define(interp, "linspace", Some(3), |_, args| {
8415        let start = match &args[0] {
8416            Value::Int(n) => *n as f64,
8417            Value::Float(f) => *f,
8418            _ => return Err(RuntimeError::new("linspace: start must be a number")),
8419        };
8420        let end = match &args[1] {
8421            Value::Int(n) => *n as f64,
8422            Value::Float(f) => *f,
8423            _ => return Err(RuntimeError::new("linspace: end must be a number")),
8424        };
8425        let n = match &args[2] {
8426            Value::Int(n) if *n > 0 => *n as usize,
8427            _ => {
8428                return Err(RuntimeError::new(
8429                    "linspace: count must be a positive integer",
8430                ))
8431            }
8432        };
8433
8434        if n == 1 {
8435            return Ok(Value::Array(Rc::new(RefCell::new(vec![Value::Float(
8436                start,
8437            )]))));
8438        }
8439
8440        let step = (end - start) / (n - 1) as f64;
8441        let result: Vec<Value> = (0..n)
8442            .map(|i| Value::Float(start + step * i as f64))
8443            .collect();
8444
8445        Ok(Value::Array(Rc::new(RefCell::new(result))))
8446    });
8447
8448    // logspace - N logarithmically spaced values
8449    define(interp, "logspace", Some(3), |_, args| {
8450        let start_exp = match &args[0] {
8451            Value::Int(n) => *n as f64,
8452            Value::Float(f) => *f,
8453            _ => {
8454                return Err(RuntimeError::new(
8455                    "logspace: start exponent must be a number",
8456                ))
8457            }
8458        };
8459        let end_exp = match &args[1] {
8460            Value::Int(n) => *n as f64,
8461            Value::Float(f) => *f,
8462            _ => return Err(RuntimeError::new("logspace: end exponent must be a number")),
8463        };
8464        let n = match &args[2] {
8465            Value::Int(n) if *n > 0 => *n as usize,
8466            _ => {
8467                return Err(RuntimeError::new(
8468                    "logspace: count must be a positive integer",
8469                ))
8470            }
8471        };
8472
8473        if n == 1 {
8474            return Ok(Value::Array(Rc::new(RefCell::new(vec![Value::Float(
8475                10f64.powf(start_exp),
8476            )]))));
8477        }
8478
8479        let step = (end_exp - start_exp) / (n - 1) as f64;
8480        let result: Vec<Value> = (0..n)
8481            .map(|i| Value::Float(10f64.powf(start_exp + step * i as f64)))
8482            .collect();
8483
8484        Ok(Value::Array(Rc::new(RefCell::new(result))))
8485    });
8486
8487    // arange - like numpy arange (start, stop, step with float support)
8488    define(interp, "arange", Some(3), |_, args| {
8489        let start = match &args[0] {
8490            Value::Int(n) => *n as f64,
8491            Value::Float(f) => *f,
8492            _ => return Err(RuntimeError::new("arange: start must be a number")),
8493        };
8494        let stop = match &args[1] {
8495            Value::Int(n) => *n as f64,
8496            Value::Float(f) => *f,
8497            _ => return Err(RuntimeError::new("arange: stop must be a number")),
8498        };
8499        let step = match &args[2] {
8500            Value::Int(n) if *n != 0 => *n as f64,
8501            Value::Float(f) if *f != 0.0 => *f,
8502            _ => return Err(RuntimeError::new("arange: step must be a non-zero number")),
8503        };
8504
8505        let mut result = Vec::new();
8506        if step > 0.0 {
8507            let mut x = start;
8508            while x < stop {
8509                result.push(Value::Float(x));
8510                x += step;
8511            }
8512        } else {
8513            let mut x = start;
8514            while x > stop {
8515                result.push(Value::Float(x));
8516                x += step;
8517            }
8518        }
8519
8520        Ok(Value::Array(Rc::new(RefCell::new(result))))
8521    });
8522
8523    // geomspace - geometrically spaced values (like logspace but using actual values)
8524    define(interp, "geomspace", Some(3), |_, args| {
8525        let start = match &args[0] {
8526            Value::Int(n) if *n > 0 => *n as f64,
8527            Value::Float(f) if *f > 0.0 => *f,
8528            _ => {
8529                return Err(RuntimeError::new(
8530                    "geomspace: start must be a positive number",
8531                ))
8532            }
8533        };
8534        let end = match &args[1] {
8535            Value::Int(n) if *n > 0 => *n as f64,
8536            Value::Float(f) if *f > 0.0 => *f,
8537            _ => {
8538                return Err(RuntimeError::new(
8539                    "geomspace: end must be a positive number",
8540                ))
8541            }
8542        };
8543        let n = match &args[2] {
8544            Value::Int(n) if *n > 0 => *n as usize,
8545            _ => {
8546                return Err(RuntimeError::new(
8547                    "geomspace: count must be a positive integer",
8548                ))
8549            }
8550        };
8551
8552        if n == 1 {
8553            return Ok(Value::Array(Rc::new(RefCell::new(vec![Value::Float(
8554                start,
8555            )]))));
8556        }
8557
8558        let ratio = (end / start).powf(1.0 / (n - 1) as f64);
8559        let result: Vec<Value> = (0..n)
8560            .map(|i| Value::Float(start * ratio.powi(i as i32)))
8561            .collect();
8562
8563        Ok(Value::Array(Rc::new(RefCell::new(result))))
8564    });
8565}
8566
8567/// Bitwise operations
8568fn register_bitwise(interp: &mut Interpreter) {
8569    define(interp, "bit_and", Some(2), |_, args| {
8570        let a = match &args[0] {
8571            Value::Int(n) => *n,
8572            _ => return Err(RuntimeError::new("bit_and: arguments must be integers")),
8573        };
8574        let b = match &args[1] {
8575            Value::Int(n) => *n,
8576            _ => return Err(RuntimeError::new("bit_and: arguments must be integers")),
8577        };
8578        Ok(Value::Int(a & b))
8579    });
8580
8581    define(interp, "bit_or", Some(2), |_, args| {
8582        let a = match &args[0] {
8583            Value::Int(n) => *n,
8584            _ => return Err(RuntimeError::new("bit_or: arguments must be integers")),
8585        };
8586        let b = match &args[1] {
8587            Value::Int(n) => *n,
8588            _ => return Err(RuntimeError::new("bit_or: arguments must be integers")),
8589        };
8590        Ok(Value::Int(a | b))
8591    });
8592
8593    define(interp, "bit_xor", Some(2), |_, args| {
8594        let a = match &args[0] {
8595            Value::Int(n) => *n,
8596            _ => return Err(RuntimeError::new("bit_xor: arguments must be integers")),
8597        };
8598        let b = match &args[1] {
8599            Value::Int(n) => *n,
8600            _ => return Err(RuntimeError::new("bit_xor: arguments must be integers")),
8601        };
8602        Ok(Value::Int(a ^ b))
8603    });
8604
8605    define(interp, "bit_not", Some(1), |_, args| {
8606        let a = match &args[0] {
8607            Value::Int(n) => *n,
8608            _ => return Err(RuntimeError::new("bit_not: argument must be an integer")),
8609        };
8610        Ok(Value::Int(!a))
8611    });
8612
8613    define(interp, "bit_shl", Some(2), |_, args| {
8614        let a = match &args[0] {
8615            Value::Int(n) => *n,
8616            _ => {
8617                return Err(RuntimeError::new(
8618                    "bit_shl: first argument must be an integer",
8619                ))
8620            }
8621        };
8622        let b = match &args[1] {
8623            Value::Int(n) if *n >= 0 && *n < 64 => *n as u32,
8624            _ => return Err(RuntimeError::new("bit_shl: shift amount must be 0-63")),
8625        };
8626        Ok(Value::Int(a << b))
8627    });
8628
8629    define(interp, "bit_shr", Some(2), |_, args| {
8630        let a = match &args[0] {
8631            Value::Int(n) => *n,
8632            _ => {
8633                return Err(RuntimeError::new(
8634                    "bit_shr: first argument must be an integer",
8635                ))
8636            }
8637        };
8638        let b = match &args[1] {
8639            Value::Int(n) if *n >= 0 && *n < 64 => *n as u32,
8640            _ => return Err(RuntimeError::new("bit_shr: shift amount must be 0-63")),
8641        };
8642        Ok(Value::Int(a >> b))
8643    });
8644
8645    define(interp, "popcount", Some(1), |_, args| {
8646        let a = match &args[0] {
8647            Value::Int(n) => *n,
8648            _ => return Err(RuntimeError::new("popcount: argument must be an integer")),
8649        };
8650        Ok(Value::Int(a.count_ones() as i64))
8651    });
8652
8653    define(interp, "leading_zeros", Some(1), |_, args| {
8654        let a = match &args[0] {
8655            Value::Int(n) => *n,
8656            _ => {
8657                return Err(RuntimeError::new(
8658                    "leading_zeros: argument must be an integer",
8659                ))
8660            }
8661        };
8662        Ok(Value::Int(a.leading_zeros() as i64))
8663    });
8664
8665    define(interp, "trailing_zeros", Some(1), |_, args| {
8666        let a = match &args[0] {
8667            Value::Int(n) => *n,
8668            _ => {
8669                return Err(RuntimeError::new(
8670                    "trailing_zeros: argument must be an integer",
8671                ))
8672            }
8673        };
8674        Ok(Value::Int(a.trailing_zeros() as i64))
8675    });
8676
8677    define(interp, "bit_test", Some(2), |_, args| {
8678        let a = match &args[0] {
8679            Value::Int(n) => *n,
8680            _ => {
8681                return Err(RuntimeError::new(
8682                    "bit_test: first argument must be an integer",
8683                ))
8684            }
8685        };
8686        let pos = match &args[1] {
8687            Value::Int(n) if *n >= 0 && *n < 64 => *n as u32,
8688            _ => return Err(RuntimeError::new("bit_test: position must be 0-63")),
8689        };
8690        Ok(Value::Bool((a >> pos) & 1 == 1))
8691    });
8692
8693    define(interp, "bit_set", Some(2), |_, args| {
8694        let a = match &args[0] {
8695            Value::Int(n) => *n,
8696            _ => {
8697                return Err(RuntimeError::new(
8698                    "bit_set: first argument must be an integer",
8699                ))
8700            }
8701        };
8702        let pos = match &args[1] {
8703            Value::Int(n) if *n >= 0 && *n < 64 => *n as u32,
8704            _ => return Err(RuntimeError::new("bit_set: position must be 0-63")),
8705        };
8706        Ok(Value::Int(a | (1 << pos)))
8707    });
8708
8709    define(interp, "bit_clear", Some(2), |_, args| {
8710        let a = match &args[0] {
8711            Value::Int(n) => *n,
8712            _ => {
8713                return Err(RuntimeError::new(
8714                    "bit_clear: first argument must be an integer",
8715                ))
8716            }
8717        };
8718        let pos = match &args[1] {
8719            Value::Int(n) if *n >= 0 && *n < 64 => *n as u32,
8720            _ => return Err(RuntimeError::new("bit_clear: position must be 0-63")),
8721        };
8722        Ok(Value::Int(a & !(1 << pos)))
8723    });
8724
8725    define(interp, "bit_toggle", Some(2), |_, args| {
8726        let a = match &args[0] {
8727            Value::Int(n) => *n,
8728            _ => {
8729                return Err(RuntimeError::new(
8730                    "bit_toggle: first argument must be an integer",
8731                ))
8732            }
8733        };
8734        let pos = match &args[1] {
8735            Value::Int(n) if *n >= 0 && *n < 64 => *n as u32,
8736            _ => return Err(RuntimeError::new("bit_toggle: position must be 0-63")),
8737        };
8738        Ok(Value::Int(a ^ (1 << pos)))
8739    });
8740
8741    define(interp, "to_binary", Some(1), |_, args| {
8742        let a = match &args[0] {
8743            Value::Int(n) => *n,
8744            _ => return Err(RuntimeError::new("to_binary: argument must be an integer")),
8745        };
8746        Ok(Value::String(Rc::new(format!("{:b}", a))))
8747    });
8748
8749    define(interp, "from_binary", Some(1), |_, args| {
8750        let s = match &args[0] {
8751            Value::String(s) => (**s).clone(),
8752            _ => return Err(RuntimeError::new("from_binary: argument must be a string")),
8753        };
8754        match i64::from_str_radix(&s, 2) {
8755            Ok(n) => Ok(Value::Int(n)),
8756            Err(_) => Err(RuntimeError::new("from_binary: invalid binary string")),
8757        }
8758    });
8759
8760    define(interp, "to_hex", Some(1), |_, args| {
8761        let a = match &args[0] {
8762            Value::Int(n) => *n,
8763            _ => return Err(RuntimeError::new("to_hex: argument must be an integer")),
8764        };
8765        Ok(Value::String(Rc::new(format!("{:x}", a))))
8766    });
8767
8768    define(interp, "from_hex", Some(1), |_, args| {
8769        let s = match &args[0] {
8770            Value::String(s) => s.trim_start_matches("0x").to_string(),
8771            _ => return Err(RuntimeError::new("from_hex: argument must be a string")),
8772        };
8773        match i64::from_str_radix(&s, 16) {
8774            Ok(n) => Ok(Value::Int(n)),
8775            Err(_) => Err(RuntimeError::new("from_hex: invalid hex string")),
8776        }
8777    });
8778
8779    define(interp, "to_octal", Some(1), |_, args| {
8780        let a = match &args[0] {
8781            Value::Int(n) => *n,
8782            _ => return Err(RuntimeError::new("to_octal: argument must be an integer")),
8783        };
8784        Ok(Value::String(Rc::new(format!("{:o}", a))))
8785    });
8786
8787    define(interp, "from_octal", Some(1), |_, args| {
8788        let s = match &args[0] {
8789            Value::String(s) => s.trim_start_matches("0o").to_string(),
8790            _ => return Err(RuntimeError::new("from_octal: argument must be a string")),
8791        };
8792        match i64::from_str_radix(&s, 8) {
8793            Ok(n) => Ok(Value::Int(n)),
8794            Err(_) => Err(RuntimeError::new("from_octal: invalid octal string")),
8795        }
8796    });
8797}
8798
8799/// String formatting utilities
8800fn register_format(interp: &mut Interpreter) {
8801    // format - basic string formatting with {} placeholders
8802    define(interp, "format", None, |_, args| {
8803        if args.is_empty() {
8804            return Err(RuntimeError::new(
8805                "format: requires at least a format string",
8806            ));
8807        }
8808        let template = match &args[0] {
8809            Value::String(s) => (**s).clone(),
8810            _ => return Err(RuntimeError::new("format: first argument must be a string")),
8811        };
8812        let mut result = template;
8813        for arg in &args[1..] {
8814            if let Some(pos) = result.find("{}") {
8815                result = format!("{}{}{}", &result[..pos], arg, &result[pos + 2..]);
8816            }
8817        }
8818        Ok(Value::String(Rc::new(result)))
8819    });
8820
8821    // pad_left - left-pad string to length with char (uses character count, not bytes)
8822    define(interp, "pad_left", Some(3), |_, args| {
8823        let s = match &args[0] {
8824            Value::String(s) => (**s).clone(),
8825            _ => {
8826                return Err(RuntimeError::new(
8827                    "pad_left: first argument must be a string",
8828                ))
8829            }
8830        };
8831        let width = match &args[1] {
8832            Value::Int(n) if *n >= 0 => *n as usize,
8833            _ => {
8834                return Err(RuntimeError::new(
8835                    "pad_left: width must be a non-negative integer",
8836                ))
8837            }
8838        };
8839        let pad_char = match &args[2] {
8840            Value::String(s) if !s.is_empty() => s.chars().next().unwrap(),
8841            Value::Char(c) => *c,
8842            _ => {
8843                return Err(RuntimeError::new(
8844                    "pad_left: pad character must be a non-empty string or char",
8845                ))
8846            }
8847        };
8848        let char_count = s.chars().count();
8849        if char_count >= width {
8850            return Ok(Value::String(Rc::new(s)));
8851        }
8852        let padding: String = std::iter::repeat(pad_char)
8853            .take(width - char_count)
8854            .collect();
8855        Ok(Value::String(Rc::new(format!("{}{}", padding, s))))
8856    });
8857
8858    // pad_right - right-pad string to length with char (uses character count, not bytes)
8859    define(interp, "pad_right", Some(3), |_, args| {
8860        let s = match &args[0] {
8861            Value::String(s) => (**s).clone(),
8862            _ => {
8863                return Err(RuntimeError::new(
8864                    "pad_right: first argument must be a string",
8865                ))
8866            }
8867        };
8868        let width = match &args[1] {
8869            Value::Int(n) if *n >= 0 => *n as usize,
8870            _ => {
8871                return Err(RuntimeError::new(
8872                    "pad_right: width must be a non-negative integer",
8873                ))
8874            }
8875        };
8876        let pad_char = match &args[2] {
8877            Value::String(s) if !s.is_empty() => s.chars().next().unwrap(),
8878            Value::Char(c) => *c,
8879            _ => {
8880                return Err(RuntimeError::new(
8881                    "pad_right: pad character must be a non-empty string or char",
8882                ))
8883            }
8884        };
8885        let char_count = s.chars().count();
8886        if char_count >= width {
8887            return Ok(Value::String(Rc::new(s)));
8888        }
8889        let padding: String = std::iter::repeat(pad_char)
8890            .take(width - char_count)
8891            .collect();
8892        Ok(Value::String(Rc::new(format!("{}{}", s, padding))))
8893    });
8894
8895    // center - center string with padding (uses character count, not bytes)
8896    define(interp, "center", Some(3), |_, args| {
8897        let s = match &args[0] {
8898            Value::String(s) => (**s).clone(),
8899            _ => return Err(RuntimeError::new("center: first argument must be a string")),
8900        };
8901        let width = match &args[1] {
8902            Value::Int(n) if *n >= 0 => *n as usize,
8903            _ => {
8904                return Err(RuntimeError::new(
8905                    "center: width must be a non-negative integer",
8906                ))
8907            }
8908        };
8909        let pad_char = match &args[2] {
8910            Value::String(s) if !s.is_empty() => s.chars().next().unwrap(),
8911            Value::Char(c) => *c,
8912            _ => {
8913                return Err(RuntimeError::new(
8914                    "center: pad character must be a non-empty string or char",
8915                ))
8916            }
8917        };
8918        let char_count = s.chars().count();
8919        if char_count >= width {
8920            return Ok(Value::String(Rc::new(s)));
8921        }
8922        let total_padding = width - char_count;
8923        let left_padding = total_padding / 2;
8924        let right_padding = total_padding - left_padding;
8925        let left: String = std::iter::repeat(pad_char).take(left_padding).collect();
8926        let right: String = std::iter::repeat(pad_char).take(right_padding).collect();
8927        Ok(Value::String(Rc::new(format!("{}{}{}", left, s, right))))
8928    });
8929
8930    // number_format - format number with thousand separators
8931    define(interp, "number_format", Some(1), |_, args| {
8932        let n = match &args[0] {
8933            Value::Int(n) => *n,
8934            Value::Float(f) => *f as i64,
8935            _ => {
8936                return Err(RuntimeError::new(
8937                    "number_format: argument must be a number",
8938                ))
8939            }
8940        };
8941        let s = n.abs().to_string();
8942        let mut result = String::new();
8943        for (i, c) in s.chars().rev().enumerate() {
8944            if i > 0 && i % 3 == 0 {
8945                result.push(',');
8946            }
8947            result.push(c);
8948        }
8949        let formatted: String = result.chars().rev().collect();
8950        if n < 0 {
8951            Ok(Value::String(Rc::new(format!("-{}", formatted))))
8952        } else {
8953            Ok(Value::String(Rc::new(formatted)))
8954        }
8955    });
8956
8957    // ordinal - convert number to ordinal string (1st, 2nd, 3rd, etc)
8958    define(interp, "ordinal", Some(1), |_, args| {
8959        let n = match &args[0] {
8960            Value::Int(n) => *n,
8961            _ => return Err(RuntimeError::new("ordinal: argument must be an integer")),
8962        };
8963        let suffix = match (n % 10, n % 100) {
8964            (1, 11) => "th",
8965            (2, 12) => "th",
8966            (3, 13) => "th",
8967            (1, _) => "st",
8968            (2, _) => "nd",
8969            (3, _) => "rd",
8970            _ => "th",
8971        };
8972        Ok(Value::String(Rc::new(format!("{}{}", n, suffix))))
8973    });
8974
8975    // pluralize - simple pluralization
8976    define(interp, "pluralize", Some(3), |_, args| {
8977        let count = match &args[0] {
8978            Value::Int(n) => *n,
8979            _ => {
8980                return Err(RuntimeError::new(
8981                    "pluralize: first argument must be an integer",
8982                ))
8983            }
8984        };
8985        let singular = match &args[1] {
8986            Value::String(s) => s.clone(),
8987            _ => {
8988                return Err(RuntimeError::new(
8989                    "pluralize: second argument must be a string",
8990                ))
8991            }
8992        };
8993        let plural = match &args[2] {
8994            Value::String(s) => s.clone(),
8995            _ => {
8996                return Err(RuntimeError::new(
8997                    "pluralize: third argument must be a string",
8998                ))
8999            }
9000        };
9001        if count == 1 || count == -1 {
9002            Ok(Value::String(singular))
9003        } else {
9004            Ok(Value::String(plural))
9005        }
9006    });
9007
9008    // truncate - truncate string with ellipsis (uses character count, not bytes)
9009    define(interp, "truncate", Some(2), |_, args| {
9010        let s = match &args[0] {
9011            Value::String(s) => (**s).clone(),
9012            _ => {
9013                return Err(RuntimeError::new(
9014                    "truncate: first argument must be a string",
9015                ))
9016            }
9017        };
9018        let max_len = match &args[1] {
9019            Value::Int(n) if *n >= 0 => *n as usize,
9020            _ => {
9021                return Err(RuntimeError::new(
9022                    "truncate: max length must be a non-negative integer",
9023                ))
9024            }
9025        };
9026        let char_count = s.chars().count();
9027        if char_count <= max_len {
9028            return Ok(Value::String(Rc::new(s)));
9029        }
9030        if max_len <= 3 {
9031            return Ok(Value::String(Rc::new(s.chars().take(max_len).collect())));
9032        }
9033        let truncated: String = s.chars().take(max_len - 3).collect();
9034        Ok(Value::String(Rc::new(format!("{}...", truncated))))
9035    });
9036
9037    // word_wrap - wrap text at specified width
9038    define(interp, "word_wrap", Some(2), |_, args| {
9039        let s = match &args[0] {
9040            Value::String(s) => (**s).clone(),
9041            _ => {
9042                return Err(RuntimeError::new(
9043                    "word_wrap: first argument must be a string",
9044                ))
9045            }
9046        };
9047        let width = match &args[1] {
9048            Value::Int(n) if *n > 0 => *n as usize,
9049            _ => {
9050                return Err(RuntimeError::new(
9051                    "word_wrap: width must be a positive integer",
9052                ))
9053            }
9054        };
9055        let mut result = String::new();
9056        let mut line_len = 0;
9057        for word in s.split_whitespace() {
9058            if line_len > 0 && line_len + 1 + word.len() > width {
9059                result.push('\n');
9060                line_len = 0;
9061            } else if line_len > 0 {
9062                result.push(' ');
9063                line_len += 1;
9064            }
9065            result.push_str(word);
9066            line_len += word.len();
9067        }
9068        Ok(Value::String(Rc::new(result)))
9069    });
9070
9071    // snake_case - convert string to snake_case
9072    define(interp, "snake_case", Some(1), |_, args| {
9073        let s = match &args[0] {
9074            Value::String(s) => (**s).clone(),
9075            _ => return Err(RuntimeError::new("snake_case: argument must be a string")),
9076        };
9077        let mut result = String::new();
9078        for (i, c) in s.chars().enumerate() {
9079            if c.is_uppercase() {
9080                if i > 0 {
9081                    result.push('_');
9082                }
9083                result.push(c.to_lowercase().next().unwrap());
9084            } else if c == ' ' || c == '-' {
9085                result.push('_');
9086            } else {
9087                result.push(c);
9088            }
9089        }
9090        Ok(Value::String(Rc::new(result)))
9091    });
9092
9093    // camel_case - convert string to camelCase
9094    define(interp, "camel_case", Some(1), |_, args| {
9095        let s = match &args[0] {
9096            Value::String(s) => (**s).clone(),
9097            _ => return Err(RuntimeError::new("camel_case: argument must be a string")),
9098        };
9099        let mut result = String::new();
9100        let mut capitalize_next = false;
9101        for (i, c) in s.chars().enumerate() {
9102            if c == '_' || c == '-' || c == ' ' {
9103                capitalize_next = true;
9104            } else if capitalize_next {
9105                result.push(c.to_uppercase().next().unwrap());
9106                capitalize_next = false;
9107            } else if i == 0 {
9108                result.push(c.to_lowercase().next().unwrap());
9109            } else {
9110                result.push(c);
9111            }
9112        }
9113        Ok(Value::String(Rc::new(result)))
9114    });
9115
9116    // kebab_case - convert string to kebab-case
9117    define(interp, "kebab_case", Some(1), |_, args| {
9118        let s = match &args[0] {
9119            Value::String(s) => (**s).clone(),
9120            _ => return Err(RuntimeError::new("kebab_case: argument must be a string")),
9121        };
9122        let mut result = String::new();
9123        for (i, c) in s.chars().enumerate() {
9124            if c.is_uppercase() {
9125                if i > 0 {
9126                    result.push('-');
9127                }
9128                result.push(c.to_lowercase().next().unwrap());
9129            } else if c == '_' || c == ' ' {
9130                result.push('-');
9131            } else {
9132                result.push(c);
9133            }
9134        }
9135        Ok(Value::String(Rc::new(result)))
9136    });
9137
9138    // title_case - convert string to Title Case
9139    define(interp, "title_case", Some(1), |_, args| {
9140        let s = match &args[0] {
9141            Value::String(s) => (**s).clone(),
9142            _ => return Err(RuntimeError::new("title_case: argument must be a string")),
9143        };
9144        let result: String = s
9145            .split_whitespace()
9146            .map(|word| {
9147                let mut chars = word.chars();
9148                match chars.next() {
9149                    None => String::new(),
9150                    Some(first) => {
9151                        first.to_uppercase().collect::<String>() + &chars.as_str().to_lowercase()
9152                    }
9153                }
9154            })
9155            .collect::<Vec<_>>()
9156            .join(" ");
9157        Ok(Value::String(Rc::new(result)))
9158    });
9159}
9160
9161// ============================================================================
9162// PATTERN MATCHING FUNCTIONS (Phase 6)
9163// ============================================================================
9164// Advanced pattern matching utilities for expressive data manipulation.
9165// These complement Sigil's match expressions with functional alternatives.
9166// ============================================================================
9167
9168fn register_pattern(interp: &mut Interpreter) {
9169    // --- TYPE MATCHING ---
9170
9171    // type_of - get the type name as a string
9172    define(interp, "type_of", Some(1), |_, args| {
9173        let type_name = match &args[0] {
9174            Value::Null => "null",
9175            Value::Bool(_) => "bool",
9176            Value::Int(_) => "int",
9177            Value::Float(_) => "float",
9178            Value::String(_) => "string",
9179            Value::Char(_) => "char",
9180            Value::Array(_) => "array",
9181            Value::Tuple(_) => "tuple",
9182            Value::Map(_) => "map",
9183            Value::Set(_) => "set",
9184            Value::Struct { name, .. } => {
9185                return Ok(Value::String(Rc::new(format!("struct:{}", name))))
9186            }
9187            Value::Variant {
9188                enum_name,
9189                variant_name,
9190                ..
9191            } => {
9192                return Ok(Value::String(Rc::new(format!(
9193                    "{}::{}",
9194                    enum_name, variant_name
9195                ))))
9196            }
9197            Value::Function(_) => "function",
9198            Value::BuiltIn(_) => "builtin",
9199            Value::Ref(_) => "ref",
9200            Value::Infinity => "infinity",
9201            Value::Empty => "empty",
9202            Value::Evidential { .. } => "evidential",
9203            Value::Affective { .. } => "affective",
9204            Value::Channel(_) => "channel",
9205            Value::ThreadHandle(_) => "thread",
9206            Value::Actor(_) => "actor",
9207            Value::Future(_) => "future",
9208        };
9209        Ok(Value::String(Rc::new(type_name.to_string())))
9210    });
9211
9212    // is_type - check if value matches type name
9213    define(interp, "is_type", Some(2), |_, args| {
9214        let type_name = match &args[1] {
9215            Value::String(s) => s.to_lowercase(),
9216            _ => {
9217                return Err(RuntimeError::new(
9218                    "is_type: second argument must be type name string",
9219                ))
9220            }
9221        };
9222        let matches = match (&args[0], type_name.as_str()) {
9223            (Value::Null, "null") => true,
9224            (Value::Bool(_), "bool") => true,
9225            (Value::Int(_), "int") | (Value::Int(_), "integer") => true,
9226            (Value::Float(_), "float") | (Value::Float(_), "number") => true,
9227            (Value::Int(_), "number") => true,
9228            (Value::String(_), "string") => true,
9229            (Value::Array(_), "array") | (Value::Array(_), "list") => true,
9230            (Value::Tuple(_), "tuple") => true,
9231            (Value::Map(_), "map") | (Value::Map(_), "dict") | (Value::Map(_), "object") => true,
9232            (Value::Set(_), "set") => true,
9233            (Value::Function(_), "function") | (Value::Function(_), "fn") => true,
9234            (Value::BuiltIn(_), "function") | (Value::BuiltIn(_), "builtin") => true,
9235            (Value::Struct { name, .. }, t) => t == "struct" || t == &name.to_lowercase(),
9236            (Value::Variant { enum_name, .. }, t) => {
9237                t == "variant" || t == "enum" || t == &enum_name.to_lowercase()
9238            }
9239            (Value::Channel(_), "channel") => true,
9240            (Value::ThreadHandle(_), "thread") => true,
9241            (Value::Actor(_), "actor") => true,
9242            (Value::Future(_), "future") => true,
9243            _ => false,
9244        };
9245        Ok(Value::Bool(matches))
9246    });
9247
9248    // is_null, is_bool, is_int, is_float, is_string, is_array, is_map - type predicates
9249    define(interp, "is_null", Some(1), |_, args| {
9250        Ok(Value::Bool(matches!(&args[0], Value::Null)))
9251    });
9252    define(interp, "is_bool", Some(1), |_, args| {
9253        Ok(Value::Bool(matches!(&args[0], Value::Bool(_))))
9254    });
9255    define(interp, "is_int", Some(1), |_, args| {
9256        Ok(Value::Bool(matches!(&args[0], Value::Int(_))))
9257    });
9258    define(interp, "is_float", Some(1), |_, args| {
9259        Ok(Value::Bool(matches!(&args[0], Value::Float(_))))
9260    });
9261    define(interp, "is_number", Some(1), |_, args| {
9262        Ok(Value::Bool(matches!(
9263            &args[0],
9264            Value::Int(_) | Value::Float(_)
9265        )))
9266    });
9267    define(interp, "is_string", Some(1), |_, args| {
9268        Ok(Value::Bool(matches!(&args[0], Value::String(_))))
9269    });
9270    define(interp, "is_array", Some(1), |_, args| {
9271        Ok(Value::Bool(matches!(&args[0], Value::Array(_))))
9272    });
9273    define(interp, "is_tuple", Some(1), |_, args| {
9274        Ok(Value::Bool(matches!(&args[0], Value::Tuple(_))))
9275    });
9276    define(interp, "is_map", Some(1), |_, args| {
9277        Ok(Value::Bool(matches!(&args[0], Value::Map(_))))
9278    });
9279    define(interp, "is_set", Some(1), |_, args| {
9280        Ok(Value::Bool(matches!(&args[0], Value::Set(_))))
9281    });
9282    define(interp, "is_function", Some(1), |_, args| {
9283        Ok(Value::Bool(matches!(
9284            &args[0],
9285            Value::Function(_) | Value::BuiltIn(_)
9286        )))
9287    });
9288    define(interp, "is_struct", Some(1), |_, args| {
9289        Ok(Value::Bool(matches!(&args[0], Value::Struct { .. })))
9290    });
9291    define(interp, "is_variant", Some(1), |_, args| {
9292        Ok(Value::Bool(matches!(&args[0], Value::Variant { .. })))
9293    });
9294    define(interp, "is_future", Some(1), |_, args| {
9295        Ok(Value::Bool(matches!(&args[0], Value::Future(_))))
9296    });
9297    define(interp, "is_channel", Some(1), |_, args| {
9298        Ok(Value::Bool(matches!(&args[0], Value::Channel(_))))
9299    });
9300
9301    // is_empty - check if collection is empty
9302    define(interp, "is_empty", Some(1), |_, args| {
9303        let empty = match &args[0] {
9304            Value::Null => true,
9305            Value::String(s) => s.is_empty(),
9306            Value::Array(a) => a.borrow().is_empty(),
9307            Value::Tuple(t) => t.is_empty(),
9308            Value::Map(m) => m.borrow().is_empty(),
9309            Value::Set(s) => s.borrow().is_empty(),
9310            _ => false,
9311        };
9312        Ok(Value::Bool(empty))
9313    });
9314
9315    // --- REGEX PATTERN MATCHING ---
9316
9317    // match_regex - match string against regex, return captures or null
9318    define(interp, "match_regex", Some(2), |_, args| {
9319        let text = match &args[0] {
9320            Value::String(s) => (**s).clone(),
9321            _ => {
9322                return Err(RuntimeError::new(
9323                    "match_regex: first argument must be a string",
9324                ))
9325            }
9326        };
9327        let pattern = match &args[1] {
9328            Value::String(s) => (**s).clone(),
9329            _ => {
9330                return Err(RuntimeError::new(
9331                    "match_regex: second argument must be a regex pattern string",
9332                ))
9333            }
9334        };
9335
9336        let re = match Regex::new(&pattern) {
9337            Ok(r) => r,
9338            Err(e) => {
9339                return Err(RuntimeError::new(format!(
9340                    "match_regex: invalid regex: {}",
9341                    e
9342                )))
9343            }
9344        };
9345
9346        match re.captures(&text) {
9347            Some(caps) => {
9348                let mut captures: Vec<Value> = Vec::new();
9349                for i in 0..caps.len() {
9350                    if let Some(m) = caps.get(i) {
9351                        captures.push(Value::String(Rc::new(m.as_str().to_string())));
9352                    } else {
9353                        captures.push(Value::Null);
9354                    }
9355                }
9356                Ok(Value::Array(Rc::new(RefCell::new(captures))))
9357            }
9358            None => Ok(Value::Null),
9359        }
9360    });
9361
9362    // match_all_regex - find all matches of regex in string
9363    define(interp, "match_all_regex", Some(2), |_, args| {
9364        let text = match &args[0] {
9365            Value::String(s) => (**s).clone(),
9366            _ => {
9367                return Err(RuntimeError::new(
9368                    "match_all_regex: first argument must be a string",
9369                ))
9370            }
9371        };
9372        let pattern = match &args[1] {
9373            Value::String(s) => (**s).clone(),
9374            _ => {
9375                return Err(RuntimeError::new(
9376                    "match_all_regex: second argument must be a regex pattern string",
9377                ))
9378            }
9379        };
9380
9381        let re = match Regex::new(&pattern) {
9382            Ok(r) => r,
9383            Err(e) => {
9384                return Err(RuntimeError::new(format!(
9385                    "match_all_regex: invalid regex: {}",
9386                    e
9387                )))
9388            }
9389        };
9390
9391        let matches: Vec<Value> = re
9392            .find_iter(&text)
9393            .map(|m| Value::String(Rc::new(m.as_str().to_string())))
9394            .collect();
9395        Ok(Value::Array(Rc::new(RefCell::new(matches))))
9396    });
9397
9398    // capture_named - extract named captures from regex match
9399    define(interp, "capture_named", Some(2), |_, args| {
9400        let text = match &args[0] {
9401            Value::String(s) => (**s).clone(),
9402            _ => {
9403                return Err(RuntimeError::new(
9404                    "capture_named: first argument must be a string",
9405                ))
9406            }
9407        };
9408        let pattern = match &args[1] {
9409            Value::String(s) => (**s).clone(),
9410            _ => {
9411                return Err(RuntimeError::new(
9412                    "capture_named: second argument must be a regex pattern string",
9413                ))
9414            }
9415        };
9416
9417        let re = match Regex::new(&pattern) {
9418            Ok(r) => r,
9419            Err(e) => {
9420                return Err(RuntimeError::new(format!(
9421                    "capture_named: invalid regex: {}",
9422                    e
9423                )))
9424            }
9425        };
9426
9427        match re.captures(&text) {
9428            Some(caps) => {
9429                let mut result: HashMap<String, Value> = HashMap::new();
9430                for name in re.capture_names().flatten() {
9431                    if let Some(m) = caps.name(name) {
9432                        result.insert(
9433                            name.to_string(),
9434                            Value::String(Rc::new(m.as_str().to_string())),
9435                        );
9436                    }
9437                }
9438                Ok(Value::Map(Rc::new(RefCell::new(result))))
9439            }
9440            None => Ok(Value::Null),
9441        }
9442    });
9443
9444    // --- STRUCTURAL PATTERN MATCHING ---
9445
9446    // match_struct - check if value is a struct with given name
9447    define(interp, "match_struct", Some(2), |_, args| {
9448        let expected_name = match &args[1] {
9449            Value::String(s) => (**s).clone(),
9450            _ => {
9451                return Err(RuntimeError::new(
9452                    "match_struct: second argument must be struct name string",
9453                ))
9454            }
9455        };
9456        match &args[0] {
9457            Value::Struct { name, .. } => Ok(Value::Bool(name == &expected_name)),
9458            _ => Ok(Value::Bool(false)),
9459        }
9460    });
9461
9462    // match_variant - check if value is a variant with given enum and variant name
9463    define(interp, "match_variant", Some(3), |_, args| {
9464        let expected_enum = match &args[1] {
9465            Value::String(s) => (**s).clone(),
9466            _ => {
9467                return Err(RuntimeError::new(
9468                    "match_variant: second argument must be enum name string",
9469                ))
9470            }
9471        };
9472        let expected_variant = match &args[2] {
9473            Value::String(s) => (**s).clone(),
9474            _ => {
9475                return Err(RuntimeError::new(
9476                    "match_variant: third argument must be variant name string",
9477                ))
9478            }
9479        };
9480        match &args[0] {
9481            Value::Variant {
9482                enum_name,
9483                variant_name,
9484                ..
9485            } => Ok(Value::Bool(
9486                enum_name == &expected_enum && variant_name == &expected_variant,
9487            )),
9488            _ => Ok(Value::Bool(false)),
9489        }
9490    });
9491
9492    // get_field - get field from struct by name (returns null if not found)
9493    define(interp, "get_field", Some(2), |_, args| {
9494        let field_name = match &args[1] {
9495            Value::String(s) => (**s).clone(),
9496            _ => {
9497                return Err(RuntimeError::new(
9498                    "get_field: second argument must be field name string",
9499                ))
9500            }
9501        };
9502        match &args[0] {
9503            Value::Struct { fields, .. } => Ok(fields
9504                .borrow()
9505                .get(&field_name)
9506                .cloned()
9507                .unwrap_or(Value::Null)),
9508            Value::Map(m) => Ok(m.borrow().get(&field_name).cloned().unwrap_or(Value::Null)),
9509            _ => Ok(Value::Null),
9510        }
9511    });
9512
9513    // has_field - check if struct/map has a field
9514    define(interp, "has_field", Some(2), |_, args| {
9515        let field_name = match &args[1] {
9516            Value::String(s) => (**s).clone(),
9517            _ => {
9518                return Err(RuntimeError::new(
9519                    "has_field: second argument must be field name string",
9520                ))
9521            }
9522        };
9523        match &args[0] {
9524            Value::Struct { fields, .. } => {
9525                Ok(Value::Bool(fields.borrow().contains_key(&field_name)))
9526            }
9527            Value::Map(m) => Ok(Value::Bool(m.borrow().contains_key(&field_name))),
9528            _ => Ok(Value::Bool(false)),
9529        }
9530    });
9531
9532    // get_fields - get all field names from struct/map
9533    define(interp, "get_fields", Some(1), |_, args| {
9534        let fields: Vec<Value> = match &args[0] {
9535            Value::Struct { fields, .. } => fields
9536                .borrow()
9537                .keys()
9538                .map(|k| Value::String(Rc::new(k.clone())))
9539                .collect(),
9540            Value::Map(m) => m
9541                .borrow()
9542                .keys()
9543                .map(|k| Value::String(Rc::new(k.clone())))
9544                .collect(),
9545            _ => {
9546                return Err(RuntimeError::new(
9547                    "get_fields: argument must be struct or map",
9548                ))
9549            }
9550        };
9551        Ok(Value::Array(Rc::new(RefCell::new(fields))))
9552    });
9553
9554    // struct_name - get the name of a struct
9555    define(interp, "struct_name", Some(1), |_, args| match &args[0] {
9556        Value::Struct { name, .. } => Ok(Value::String(Rc::new(name.clone()))),
9557        _ => Ok(Value::Null),
9558    });
9559
9560    // variant_name - get the variant name of an enum value
9561    define(interp, "variant_name", Some(1), |_, args| match &args[0] {
9562        Value::Variant { variant_name, .. } => Ok(Value::String(Rc::new(variant_name.clone()))),
9563        _ => Ok(Value::Null),
9564    });
9565
9566    // variant_data - get the data payload of a variant
9567    define(interp, "variant_data", Some(1), |_, args| match &args[0] {
9568        Value::Variant { fields, .. } => match fields {
9569            Some(f) => Ok(Value::Array(Rc::new(RefCell::new((**f).clone())))),
9570            None => Ok(Value::Null),
9571        },
9572        _ => Ok(Value::Null),
9573    });
9574
9575    // --- GUARDS AND CONDITIONALS ---
9576
9577    // guard - conditionally return value or null (for pattern guard chains)
9578    define(interp, "guard", Some(2), |_, args| {
9579        if is_truthy(&args[0]) {
9580            Ok(args[1].clone())
9581        } else {
9582            Ok(Value::Null)
9583        }
9584    });
9585
9586    // when - like guard but evaluates a function if condition is true
9587    define(interp, "when", Some(2), |interp, args| {
9588        if is_truthy(&args[0]) {
9589            match &args[1] {
9590                Value::Function(f) => interp.call_function(f, vec![]),
9591                other => Ok(other.clone()),
9592            }
9593        } else {
9594            Ok(Value::Null)
9595        }
9596    });
9597
9598    // unless - opposite of when
9599    define(interp, "unless", Some(2), |interp, args| {
9600        if !is_truthy(&args[0]) {
9601            match &args[1] {
9602                Value::Function(f) => interp.call_function(f, vec![]),
9603                other => Ok(other.clone()),
9604            }
9605        } else {
9606            Ok(Value::Null)
9607        }
9608    });
9609
9610    // cond - evaluate conditions in order, return first matching result
9611    // cond([[cond1, val1], [cond2, val2], ...])
9612    define(interp, "cond", Some(1), |interp, args| {
9613        let clauses = match &args[0] {
9614            Value::Array(a) => a.borrow().clone(),
9615            _ => {
9616                return Err(RuntimeError::new(
9617                    "cond: argument must be array of [condition, value] pairs",
9618                ))
9619            }
9620        };
9621
9622        for clause in clauses {
9623            let pair = match &clause {
9624                Value::Array(a) => a.borrow().clone(),
9625                Value::Tuple(t) => (**t).clone(),
9626                _ => {
9627                    return Err(RuntimeError::new(
9628                        "cond: each clause must be [condition, value] pair",
9629                    ))
9630                }
9631            };
9632            if pair.len() != 2 {
9633                return Err(RuntimeError::new(
9634                    "cond: each clause must have exactly 2 elements",
9635                ));
9636            }
9637
9638            if is_truthy(&pair[0]) {
9639                return match &pair[1] {
9640                    Value::Function(f) => interp.call_function(f, vec![]),
9641                    other => Ok(other.clone()),
9642                };
9643            }
9644        }
9645        Ok(Value::Null)
9646    });
9647
9648    // case - match value against patterns, return matching result
9649    // case(val, [[pattern1, result1], [pattern2, result2], ...])
9650    define(interp, "case", Some(2), |interp, args| {
9651        let value = &args[0];
9652        let clauses = match &args[1] {
9653            Value::Array(a) => a.borrow().clone(),
9654            _ => {
9655                return Err(RuntimeError::new(
9656                    "case: second argument must be array of [pattern, result] pairs",
9657                ))
9658            }
9659        };
9660
9661        for clause in clauses {
9662            let pair = match &clause {
9663                Value::Array(a) => a.borrow().clone(),
9664                Value::Tuple(t) => (**t).clone(),
9665                _ => {
9666                    return Err(RuntimeError::new(
9667                        "case: each clause must be [pattern, result] pair",
9668                    ))
9669                }
9670            };
9671            if pair.len() != 2 {
9672                return Err(RuntimeError::new(
9673                    "case: each clause must have exactly 2 elements",
9674                ));
9675            }
9676
9677            if value_eq(value, &pair[0]) {
9678                return match &pair[1] {
9679                    Value::Function(f) => interp.call_function(f, vec![value.clone()]),
9680                    other => Ok(other.clone()),
9681                };
9682            }
9683        }
9684        Ok(Value::Null)
9685    });
9686
9687    // --- DESTRUCTURING ---
9688
9689    // destructure_array - extract elements at specified indices
9690    define(interp, "destructure_array", Some(2), |_, args| {
9691        let arr = match &args[0] {
9692            Value::Array(a) => a.borrow().clone(),
9693            Value::Tuple(t) => (**t).clone(),
9694            _ => {
9695                return Err(RuntimeError::new(
9696                    "destructure_array: first argument must be array or tuple",
9697                ))
9698            }
9699        };
9700        let indices = match &args[1] {
9701            Value::Array(a) => a.borrow().clone(),
9702            _ => {
9703                return Err(RuntimeError::new(
9704                    "destructure_array: second argument must be array of indices",
9705                ))
9706            }
9707        };
9708
9709        let mut result = Vec::new();
9710        for idx in indices {
9711            match idx {
9712                Value::Int(i) => {
9713                    let i = if i < 0 { arr.len() as i64 + i } else { i } as usize;
9714                    result.push(arr.get(i).cloned().unwrap_or(Value::Null));
9715                }
9716                _ => result.push(Value::Null),
9717            }
9718        }
9719        Ok(Value::Array(Rc::new(RefCell::new(result))))
9720    });
9721
9722    // destructure_map - extract values for specified keys
9723    define(interp, "destructure_map", Some(2), |_, args| {
9724        let map = match &args[0] {
9725            Value::Map(m) => m.borrow().clone(),
9726            Value::Struct { fields, .. } => fields.borrow().clone(),
9727            _ => {
9728                return Err(RuntimeError::new(
9729                    "destructure_map: first argument must be map or struct",
9730                ))
9731            }
9732        };
9733        let keys = match &args[1] {
9734            Value::Array(a) => a.borrow().clone(),
9735            _ => {
9736                return Err(RuntimeError::new(
9737                    "destructure_map: second argument must be array of keys",
9738                ))
9739            }
9740        };
9741
9742        let mut result = Vec::new();
9743        for key in keys {
9744            match key {
9745                Value::String(k) => {
9746                    result.push(map.get(&*k).cloned().unwrap_or(Value::Null));
9747                }
9748                _ => result.push(Value::Null),
9749            }
9750        }
9751        Ok(Value::Array(Rc::new(RefCell::new(result))))
9752    });
9753
9754    // head_tail - split array into [head, tail]
9755    define(interp, "head_tail", Some(1), |_, args| {
9756        let arr = match &args[0] {
9757            Value::Array(a) => a.borrow().clone(),
9758            _ => return Err(RuntimeError::new("head_tail: argument must be array")),
9759        };
9760
9761        if arr.is_empty() {
9762            Ok(Value::Tuple(Rc::new(vec![
9763                Value::Null,
9764                Value::Array(Rc::new(RefCell::new(vec![]))),
9765            ])))
9766        } else {
9767            let head = arr[0].clone();
9768            let tail = arr[1..].to_vec();
9769            Ok(Value::Tuple(Rc::new(vec![
9770                head,
9771                Value::Array(Rc::new(RefCell::new(tail))),
9772            ])))
9773        }
9774    });
9775
9776    // init_last - split array into [init, last]
9777    define(interp, "init_last", Some(1), |_, args| {
9778        let arr = match &args[0] {
9779            Value::Array(a) => a.borrow().clone(),
9780            _ => return Err(RuntimeError::new("init_last: argument must be array")),
9781        };
9782
9783        if arr.is_empty() {
9784            Ok(Value::Tuple(Rc::new(vec![
9785                Value::Array(Rc::new(RefCell::new(vec![]))),
9786                Value::Null,
9787            ])))
9788        } else {
9789            let last = arr[arr.len() - 1].clone();
9790            let init = arr[..arr.len() - 1].to_vec();
9791            Ok(Value::Tuple(Rc::new(vec![
9792                Value::Array(Rc::new(RefCell::new(init))),
9793                last,
9794            ])))
9795        }
9796    });
9797
9798    // split_at - split array at index into [left, right]
9799    define(interp, "split_at", Some(2), |_, args| {
9800        let arr = match &args[0] {
9801            Value::Array(a) => a.borrow().clone(),
9802            _ => return Err(RuntimeError::new("split_at: first argument must be array")),
9803        };
9804        let idx = match &args[1] {
9805            Value::Int(i) => *i as usize,
9806            _ => {
9807                return Err(RuntimeError::new(
9808                    "split_at: second argument must be integer",
9809                ))
9810            }
9811        };
9812
9813        let idx = idx.min(arr.len());
9814        let left = arr[..idx].to_vec();
9815        let right = arr[idx..].to_vec();
9816        Ok(Value::Tuple(Rc::new(vec![
9817            Value::Array(Rc::new(RefCell::new(left))),
9818            Value::Array(Rc::new(RefCell::new(right))),
9819        ])))
9820    });
9821
9822    // --- OPTIONAL/NULLABLE HELPERS ---
9823
9824    // unwrap_or - return value if not null, else default
9825    define(interp, "unwrap_or", Some(2), |_, args| {
9826        if matches!(&args[0], Value::Null) {
9827            Ok(args[1].clone())
9828        } else {
9829            Ok(args[0].clone())
9830        }
9831    });
9832
9833    // unwrap_or_else - return value if not null, else call function
9834    define(interp, "unwrap_or_else", Some(2), |interp, args| {
9835        if matches!(&args[0], Value::Null) {
9836            match &args[1] {
9837                Value::Function(f) => interp.call_function(f, vec![]),
9838                other => Ok(other.clone()),
9839            }
9840        } else {
9841            Ok(args[0].clone())
9842        }
9843    });
9844
9845    // map_or - if value is not null, apply function, else return default
9846    define(interp, "map_or", Some(3), |interp, args| {
9847        if matches!(&args[0], Value::Null) {
9848            Ok(args[1].clone())
9849        } else {
9850            match &args[2] {
9851                Value::Function(f) => interp.call_function(f, vec![args[0].clone()]),
9852                _ => Err(RuntimeError::new(
9853                    "map_or: third argument must be a function",
9854                )),
9855            }
9856        }
9857    });
9858
9859    // coalesce - return first non-null value from array
9860    define(interp, "coalesce", Some(1), |_, args| {
9861        let values = match &args[0] {
9862            Value::Array(a) => a.borrow().clone(),
9863            _ => return Err(RuntimeError::new("coalesce: argument must be array")),
9864        };
9865
9866        for v in values {
9867            if !matches!(v, Value::Null) {
9868                return Ok(v);
9869            }
9870        }
9871        Ok(Value::Null)
9872    });
9873
9874    // --- EQUALITY AND COMPARISON ---
9875
9876    // deep_eq - deep structural equality check
9877    define(interp, "deep_eq", Some(2), |_, args| {
9878        Ok(Value::Bool(deep_value_eq(&args[0], &args[1])))
9879    });
9880
9881    // same_type - check if two values have the same type
9882    define(interp, "same_type", Some(2), |_, args| {
9883        let same = match (&args[0], &args[1]) {
9884            (Value::Null, Value::Null) => true,
9885            (Value::Bool(_), Value::Bool(_)) => true,
9886            (Value::Int(_), Value::Int(_)) => true,
9887            (Value::Float(_), Value::Float(_)) => true,
9888            (Value::String(_), Value::String(_)) => true,
9889            (Value::Array(_), Value::Array(_)) => true,
9890            (Value::Tuple(_), Value::Tuple(_)) => true,
9891            (Value::Map(_), Value::Map(_)) => true,
9892            (Value::Set(_), Value::Set(_)) => true,
9893            (Value::Function(_), Value::Function(_)) => true,
9894            (Value::BuiltIn(_), Value::BuiltIn(_)) => true,
9895            (Value::Struct { name: n1, .. }, Value::Struct { name: n2, .. }) => n1 == n2,
9896            (Value::Variant { enum_name: e1, .. }, Value::Variant { enum_name: e2, .. }) => {
9897                e1 == e2
9898            }
9899            _ => false,
9900        };
9901        Ok(Value::Bool(same))
9902    });
9903
9904    // compare - three-way comparison: -1, 0, or 1
9905    define(interp, "compare", Some(2), |_, args| {
9906        let cmp = match (&args[0], &args[1]) {
9907            (Value::Int(a), Value::Int(b)) => a.cmp(b),
9908            (Value::Float(a), Value::Float(b)) => {
9909                a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal)
9910            }
9911            (Value::Int(a), Value::Float(b)) => (*a as f64)
9912                .partial_cmp(b)
9913                .unwrap_or(std::cmp::Ordering::Equal),
9914            (Value::Float(a), Value::Int(b)) => a
9915                .partial_cmp(&(*b as f64))
9916                .unwrap_or(std::cmp::Ordering::Equal),
9917            (Value::String(a), Value::String(b)) => a.cmp(b),
9918            _ => {
9919                return Err(RuntimeError::new(
9920                    "compare: can only compare numbers or strings",
9921                ))
9922            }
9923        };
9924        Ok(Value::Int(match cmp {
9925            std::cmp::Ordering::Less => -1,
9926            std::cmp::Ordering::Equal => 0,
9927            std::cmp::Ordering::Greater => 1,
9928        }))
9929    });
9930
9931    // between - check if value is between min and max (inclusive)
9932    define(interp, "between", Some(3), |_, args| {
9933        let in_range = match (&args[0], &args[1], &args[2]) {
9934            (Value::Int(v), Value::Int(min), Value::Int(max)) => v >= min && v <= max,
9935            (Value::Float(v), Value::Float(min), Value::Float(max)) => v >= min && v <= max,
9936            (Value::Int(v), Value::Int(min), Value::Float(max)) => {
9937                (*v as f64) >= (*min as f64) && (*v as f64) <= *max
9938            }
9939            (Value::Int(v), Value::Float(min), Value::Int(max)) => {
9940                (*v as f64) >= *min && (*v as f64) <= (*max as f64)
9941            }
9942            (Value::Float(v), Value::Int(min), Value::Int(max)) => {
9943                *v >= (*min as f64) && *v <= (*max as f64)
9944            }
9945            (Value::String(v), Value::String(min), Value::String(max)) => v >= min && v <= max,
9946            _ => {
9947                return Err(RuntimeError::new(
9948                    "between: arguments must be comparable (numbers or strings)",
9949                ))
9950            }
9951        };
9952        Ok(Value::Bool(in_range))
9953    });
9954
9955    // clamp - constrain value to range
9956    define(interp, "clamp", Some(3), |_, args| {
9957        match (&args[0], &args[1], &args[2]) {
9958            (Value::Int(v), Value::Int(min), Value::Int(max)) => {
9959                Ok(Value::Int((*v).max(*min).min(*max)))
9960            }
9961            (Value::Float(v), Value::Float(min), Value::Float(max)) => {
9962                Ok(Value::Float(v.max(*min).min(*max)))
9963            }
9964            (Value::Int(v), Value::Int(min), Value::Float(max)) => {
9965                Ok(Value::Float((*v as f64).max(*min as f64).min(*max)))
9966            }
9967            _ => Err(RuntimeError::new("clamp: arguments must be numbers")),
9968        }
9969    });
9970}
9971
9972// Deep value equality for nested structures
9973fn deep_value_eq(a: &Value, b: &Value) -> bool {
9974    match (a, b) {
9975        (Value::Null, Value::Null) => true,
9976        (Value::Bool(a), Value::Bool(b)) => a == b,
9977        (Value::Int(a), Value::Int(b)) => a == b,
9978        (Value::Float(a), Value::Float(b)) => (a - b).abs() < f64::EPSILON,
9979        (Value::Int(a), Value::Float(b)) | (Value::Float(b), Value::Int(a)) => {
9980            (*a as f64 - b).abs() < f64::EPSILON
9981        }
9982        (Value::String(a), Value::String(b)) => a == b,
9983        (Value::Array(a), Value::Array(b)) => {
9984            let a = a.borrow();
9985            let b = b.borrow();
9986            a.len() == b.len() && a.iter().zip(b.iter()).all(|(x, y)| deep_value_eq(x, y))
9987        }
9988        (Value::Tuple(a), Value::Tuple(b)) => {
9989            a.len() == b.len() && a.iter().zip(b.iter()).all(|(x, y)| deep_value_eq(x, y))
9990        }
9991        (Value::Map(a), Value::Map(b)) => {
9992            let a = a.borrow();
9993            let b = b.borrow();
9994            a.len() == b.len()
9995                && a.iter()
9996                    .all(|(k, v)| b.get(k).map_or(false, |bv| deep_value_eq(v, bv)))
9997        }
9998        (Value::Set(a), Value::Set(b)) => {
9999            let a = a.borrow();
10000            let b = b.borrow();
10001            a.len() == b.len() && a.iter().all(|k| b.contains(k))
10002        }
10003        (
10004            Value::Struct {
10005                name: n1,
10006                fields: f1,
10007            },
10008            Value::Struct {
10009                name: n2,
10010                fields: f2,
10011            },
10012        ) => {
10013            let f1 = f1.borrow();
10014            let f2 = f2.borrow();
10015            n1 == n2
10016                && f1.len() == f2.len()
10017                && f1
10018                    .iter()
10019                    .all(|(k, v)| f2.get(k).map_or(false, |v2| deep_value_eq(v, v2)))
10020        }
10021        (
10022            Value::Variant {
10023                enum_name: e1,
10024                variant_name: v1,
10025                fields: d1,
10026            },
10027            Value::Variant {
10028                enum_name: e2,
10029                variant_name: v2,
10030                fields: d2,
10031            },
10032        ) => {
10033            if e1 != e2 || v1 != v2 {
10034                return false;
10035            }
10036            match (d1, d2) {
10037                (Some(f1), Some(f2)) => {
10038                    f1.len() == f2.len()
10039                        && f1.iter().zip(f2.iter()).all(|(x, y)| deep_value_eq(x, y))
10040                }
10041                (None, None) => true,
10042                _ => false,
10043            }
10044        }
10045        _ => false,
10046    }
10047}
10048
10049// Helper for value equality comparison
10050fn value_eq(a: &Value, b: &Value) -> bool {
10051    match (a, b) {
10052        (Value::Null, Value::Null) => true,
10053        (Value::Bool(a), Value::Bool(b)) => a == b,
10054        (Value::Int(a), Value::Int(b)) => a == b,
10055        (Value::Float(a), Value::Float(b)) => (a - b).abs() < f64::EPSILON,
10056        (Value::String(a), Value::String(b)) => a == b,
10057        (Value::Int(a), Value::Float(b)) | (Value::Float(b), Value::Int(a)) => {
10058            (*a as f64 - b).abs() < f64::EPSILON
10059        }
10060        _ => false,
10061    }
10062}
10063
10064// ============================================================================
10065// DEVEX FUNCTIONS (Phase 7)
10066// ============================================================================
10067// Developer experience enhancements: debugging, assertions, profiling,
10068// documentation, and introspection utilities.
10069// ============================================================================
10070
10071fn register_devex(interp: &mut Interpreter) {
10072    // --- DEBUGGING AND INTROSPECTION ---
10073
10074    // debug - print value with type info for debugging
10075    define(interp, "debug", Some(1), |_, args| {
10076        let type_name = match &args[0] {
10077            Value::Null => "null".to_string(),
10078            Value::Bool(_) => "bool".to_string(),
10079            Value::Int(_) => "int".to_string(),
10080            Value::Float(_) => "float".to_string(),
10081            Value::String(_) => "string".to_string(),
10082            Value::Char(_) => "char".to_string(),
10083            Value::Array(a) => format!("array[{}]", a.borrow().len()),
10084            Value::Tuple(t) => format!("tuple[{}]", t.len()),
10085            Value::Map(m) => format!("map[{}]", m.borrow().len()),
10086            Value::Set(s) => format!("set[{}]", s.borrow().len()),
10087            Value::Struct { name, fields } => format!("struct {}[{}]", name, fields.borrow().len()),
10088            Value::Variant {
10089                enum_name,
10090                variant_name,
10091                ..
10092            } => format!("{}::{}", enum_name, variant_name),
10093            Value::Function(_) => "function".to_string(),
10094            Value::BuiltIn(_) => "builtin".to_string(),
10095            Value::Ref(_) => "ref".to_string(),
10096            Value::Infinity => "infinity".to_string(),
10097            Value::Empty => "empty".to_string(),
10098            Value::Evidential { evidence, .. } => format!("evidential[{:?}]", evidence),
10099            Value::Affective { affect, .. } => format!("affective[sarcasm={}]", affect.sarcasm),
10100            Value::Channel(_) => "channel".to_string(),
10101            Value::ThreadHandle(_) => "thread".to_string(),
10102            Value::Actor(_) => "actor".to_string(),
10103            Value::Future(_) => "future".to_string(),
10104        };
10105        let value_repr = format_value_debug(&args[0]);
10106        println!("[DEBUG] {}: {}", type_name, value_repr);
10107        Ok(args[0].clone())
10108    });
10109
10110    // inspect - return detailed string representation of value
10111    define(interp, "inspect", Some(1), |_, args| {
10112        Ok(Value::String(Rc::new(format_value_debug(&args[0]))))
10113    });
10114
10115    // dbg - print and return value (tap for debugging)
10116    define(interp, "dbg", Some(1), |_, args| {
10117        println!("{}", format_value_debug(&args[0]));
10118        Ok(args[0].clone())
10119    });
10120
10121    // trace - print message and value, return value
10122    define(interp, "trace", Some(2), |_, args| {
10123        let label = match &args[0] {
10124            Value::String(s) => (**s).clone(),
10125            _ => format_value_debug(&args[0]),
10126        };
10127        println!("[TRACE] {}: {}", label, format_value_debug(&args[1]));
10128        Ok(args[1].clone())
10129    });
10130
10131    // pp - pretty print with indentation
10132    define(interp, "pp", Some(1), |_, args| {
10133        println!("{}", pretty_print_value(&args[0], 0));
10134        Ok(Value::Null)
10135    });
10136
10137    // --- RICH ASSERTIONS ---
10138
10139    // assert_eq - assert two values are equal
10140    define(interp, "assert_eq", Some(2), |_, args| {
10141        if deep_value_eq(&args[0], &args[1]) {
10142            Ok(Value::Bool(true))
10143        } else {
10144            Err(RuntimeError::new(format!(
10145                "Assertion failed: expected {} to equal {}",
10146                format_value_debug(&args[0]),
10147                format_value_debug(&args[1])
10148            )))
10149        }
10150    });
10151
10152    // assert_ne - assert two values are not equal
10153    define(interp, "assert_ne", Some(2), |_, args| {
10154        if !deep_value_eq(&args[0], &args[1]) {
10155            Ok(Value::Bool(true))
10156        } else {
10157            Err(RuntimeError::new(format!(
10158                "Assertion failed: expected {} to not equal {}",
10159                format_value_debug(&args[0]),
10160                format_value_debug(&args[1])
10161            )))
10162        }
10163    });
10164
10165    // assert_lt - assert first value is less than second
10166    define(interp, "assert_lt", Some(2), |_, args| {
10167        let cmp = devex_compare(&args[0], &args[1])?;
10168        if cmp < 0 {
10169            Ok(Value::Bool(true))
10170        } else {
10171            Err(RuntimeError::new(format!(
10172                "Assertion failed: expected {} < {}",
10173                format_value_debug(&args[0]),
10174                format_value_debug(&args[1])
10175            )))
10176        }
10177    });
10178
10179    // assert_le - assert first value is less than or equal to second
10180    define(interp, "assert_le", Some(2), |_, args| {
10181        let cmp = devex_compare(&args[0], &args[1])?;
10182        if cmp <= 0 {
10183            Ok(Value::Bool(true))
10184        } else {
10185            Err(RuntimeError::new(format!(
10186                "Assertion failed: expected {} <= {}",
10187                format_value_debug(&args[0]),
10188                format_value_debug(&args[1])
10189            )))
10190        }
10191    });
10192
10193    // assert_gt - assert first value is greater than second
10194    define(interp, "assert_gt", Some(2), |_, args| {
10195        let cmp = devex_compare(&args[0], &args[1])?;
10196        if cmp > 0 {
10197            Ok(Value::Bool(true))
10198        } else {
10199            Err(RuntimeError::new(format!(
10200                "Assertion failed: expected {} > {}",
10201                format_value_debug(&args[0]),
10202                format_value_debug(&args[1])
10203            )))
10204        }
10205    });
10206
10207    // assert_ge - assert first value is greater than or equal to second
10208    define(interp, "assert_ge", Some(2), |_, args| {
10209        let cmp = devex_compare(&args[0], &args[1])?;
10210        if cmp >= 0 {
10211            Ok(Value::Bool(true))
10212        } else {
10213            Err(RuntimeError::new(format!(
10214                "Assertion failed: expected {} >= {}",
10215                format_value_debug(&args[0]),
10216                format_value_debug(&args[1])
10217            )))
10218        }
10219    });
10220
10221    // assert_true - assert value is truthy
10222    define(interp, "assert_true", Some(1), |_, args| {
10223        if is_truthy(&args[0]) {
10224            Ok(Value::Bool(true))
10225        } else {
10226            Err(RuntimeError::new(format!(
10227                "Assertion failed: expected {} to be truthy",
10228                format_value_debug(&args[0])
10229            )))
10230        }
10231    });
10232
10233    // assert_false - assert value is falsy
10234    define(interp, "assert_false", Some(1), |_, args| {
10235        if !is_truthy(&args[0]) {
10236            Ok(Value::Bool(true))
10237        } else {
10238            Err(RuntimeError::new(format!(
10239                "Assertion failed: expected {} to be falsy",
10240                format_value_debug(&args[0])
10241            )))
10242        }
10243    });
10244
10245    // assert_null - assert value is null
10246    define(interp, "assert_null", Some(1), |_, args| {
10247        if matches!(&args[0], Value::Null) {
10248            Ok(Value::Bool(true))
10249        } else {
10250            Err(RuntimeError::new(format!(
10251                "Assertion failed: expected null, got {}",
10252                format_value_debug(&args[0])
10253            )))
10254        }
10255    });
10256
10257    // assert_not_null - assert value is not null
10258    define(interp, "assert_not_null", Some(1), |_, args| {
10259        if !matches!(&args[0], Value::Null) {
10260            Ok(Value::Bool(true))
10261        } else {
10262            Err(RuntimeError::new(
10263                "Assertion failed: expected non-null value, got null",
10264            ))
10265        }
10266    });
10267
10268    // assert_type - assert value has expected type
10269    define(interp, "assert_type", Some(2), |_, args| {
10270        let expected = match &args[1] {
10271            Value::String(s) => s.to_lowercase(),
10272            _ => {
10273                return Err(RuntimeError::new(
10274                    "assert_type: second argument must be type name string",
10275                ))
10276            }
10277        };
10278        let actual = get_type_name(&args[0]).to_lowercase();
10279        if actual == expected || matches_type_alias(&args[0], &expected) {
10280            Ok(Value::Bool(true))
10281        } else {
10282            Err(RuntimeError::new(format!(
10283                "Assertion failed: expected type '{}', got '{}'",
10284                expected, actual
10285            )))
10286        }
10287    });
10288
10289    // assert_contains - assert collection contains value
10290    define(interp, "assert_contains", Some(2), |_, args| {
10291        let contains = match &args[0] {
10292            Value::Array(a) => a.borrow().iter().any(|v| deep_value_eq(v, &args[1])),
10293            Value::String(s) => {
10294                if let Value::String(sub) = &args[1] {
10295                    s.contains(&**sub)
10296                } else {
10297                    false
10298                }
10299            }
10300            Value::Map(m) => {
10301                if let Value::String(k) = &args[1] {
10302                    m.borrow().contains_key(&**k)
10303                } else {
10304                    false
10305                }
10306            }
10307            Value::Set(s) => {
10308                if let Value::String(k) = &args[1] {
10309                    s.borrow().contains(&**k)
10310                } else {
10311                    false
10312                }
10313            }
10314            _ => false,
10315        };
10316        if contains {
10317            Ok(Value::Bool(true))
10318        } else {
10319            Err(RuntimeError::new(format!(
10320                "Assertion failed: {} does not contain {}",
10321                format_value_debug(&args[0]),
10322                format_value_debug(&args[1])
10323            )))
10324        }
10325    });
10326
10327    // assert_len - assert collection has expected length
10328    define(interp, "assert_len", Some(2), |_, args| {
10329        let expected = match &args[1] {
10330            Value::Int(n) => *n as usize,
10331            _ => {
10332                return Err(RuntimeError::new(
10333                    "assert_len: second argument must be integer",
10334                ))
10335            }
10336        };
10337        let actual = match &args[0] {
10338            Value::String(s) => s.len(),
10339            Value::Array(a) => a.borrow().len(),
10340            Value::Tuple(t) => t.len(),
10341            Value::Map(m) => m.borrow().len(),
10342            Value::Set(s) => s.borrow().len(),
10343            _ => {
10344                return Err(RuntimeError::new(
10345                    "assert_len: first argument must be a collection",
10346                ))
10347            }
10348        };
10349        if actual == expected {
10350            Ok(Value::Bool(true))
10351        } else {
10352            Err(RuntimeError::new(format!(
10353                "Assertion failed: expected length {}, got {}",
10354                expected, actual
10355            )))
10356        }
10357    });
10358
10359    // assert_match - assert string matches regex
10360    define(interp, "assert_match", Some(2), |_, args| {
10361        let text = match &args[0] {
10362            Value::String(s) => (**s).clone(),
10363            _ => {
10364                return Err(RuntimeError::new(
10365                    "assert_match: first argument must be string",
10366                ))
10367            }
10368        };
10369        let pattern = match &args[1] {
10370            Value::String(s) => (**s).clone(),
10371            _ => {
10372                return Err(RuntimeError::new(
10373                    "assert_match: second argument must be regex pattern",
10374                ))
10375            }
10376        };
10377        let re =
10378            Regex::new(&pattern).map_err(|e| RuntimeError::new(format!("Invalid regex: {}", e)))?;
10379        if re.is_match(&text) {
10380            Ok(Value::Bool(true))
10381        } else {
10382            Err(RuntimeError::new(format!(
10383                "Assertion failed: '{}' does not match pattern '{}'",
10384                text, pattern
10385            )))
10386        }
10387    });
10388
10389    // --- TESTING UTILITIES ---
10390
10391    // test - run a test function and report result
10392    define(interp, "test", Some(2), |interp, args| {
10393        let name = match &args[0] {
10394            Value::String(s) => (**s).clone(),
10395            _ => {
10396                return Err(RuntimeError::new(
10397                    "test: first argument must be test name string",
10398                ))
10399            }
10400        };
10401        let func = match &args[1] {
10402            Value::Function(f) => f.clone(),
10403            _ => {
10404                return Err(RuntimeError::new(
10405                    "test: second argument must be test function",
10406                ))
10407            }
10408        };
10409
10410        let start = Instant::now();
10411        let result = interp.call_function(&func, vec![]);
10412        let elapsed = start.elapsed();
10413
10414        match result {
10415            Ok(_) => {
10416                println!("✓ {} ({:.2}ms)", name, elapsed.as_secs_f64() * 1000.0);
10417                Ok(Value::Bool(true))
10418            }
10419            Err(e) => {
10420                println!(
10421                    "✗ {} ({:.2}ms): {}",
10422                    name,
10423                    elapsed.as_secs_f64() * 1000.0,
10424                    e
10425                );
10426                Ok(Value::Bool(false))
10427            }
10428        }
10429    });
10430
10431    // skip - mark a test as skipped
10432    define(interp, "skip", Some(1), |_, args| {
10433        let reason = match &args[0] {
10434            Value::String(s) => (**s).clone(),
10435            _ => "skipped".to_string(),
10436        };
10437        println!("⊘ {}", reason);
10438        Ok(Value::Null)
10439    });
10440
10441    // --- PROFILING ---
10442
10443    // profile - profile a function call and return [result, timing_info]
10444    define(interp, "profile", Some(1), |interp, args| {
10445        let func = match &args[0] {
10446            Value::Function(f) => f.clone(),
10447            _ => return Err(RuntimeError::new("profile: argument must be function")),
10448        };
10449
10450        let start = Instant::now();
10451        let result = interp.call_function(&func, vec![])?;
10452        let elapsed = start.elapsed();
10453
10454        let mut timing = HashMap::new();
10455        timing.insert(
10456            "ms".to_string(),
10457            Value::Float(elapsed.as_secs_f64() * 1000.0),
10458        );
10459        timing.insert("us".to_string(), Value::Float(elapsed.as_micros() as f64));
10460        timing.insert("ns".to_string(), Value::Int(elapsed.as_nanos() as i64));
10461
10462        Ok(Value::Tuple(Rc::new(vec![
10463            result,
10464            Value::Map(Rc::new(RefCell::new(timing))),
10465        ])))
10466    });
10467
10468    // measure - measure execution time of function N times
10469    define(interp, "measure", Some(2), |interp, args| {
10470        let func = match &args[0] {
10471            Value::Function(f) => f.clone(),
10472            _ => {
10473                return Err(RuntimeError::new(
10474                    "measure: first argument must be function",
10475                ))
10476            }
10477        };
10478        let iterations = match &args[1] {
10479            Value::Int(n) => *n as usize,
10480            _ => {
10481                return Err(RuntimeError::new(
10482                    "measure: second argument must be iteration count",
10483                ))
10484            }
10485        };
10486
10487        let mut times: Vec<f64> = Vec::new();
10488        let mut last_result = Value::Null;
10489
10490        for _ in 0..iterations {
10491            let start = Instant::now();
10492            last_result = interp.call_function(&func, vec![])?;
10493            times.push(start.elapsed().as_secs_f64() * 1000.0);
10494        }
10495
10496        let sum: f64 = times.iter().sum();
10497        let avg = sum / iterations as f64;
10498        let min = times.iter().cloned().fold(f64::INFINITY, f64::min);
10499        let max = times.iter().cloned().fold(f64::NEG_INFINITY, f64::max);
10500
10501        let variance: f64 =
10502            times.iter().map(|t| (t - avg).powi(2)).sum::<f64>() / iterations as f64;
10503        let stddev = variance.sqrt();
10504
10505        let mut stats = HashMap::new();
10506        stats.insert("iterations".to_string(), Value::Int(iterations as i64));
10507        stats.insert("total_ms".to_string(), Value::Float(sum));
10508        stats.insert("avg_ms".to_string(), Value::Float(avg));
10509        stats.insert("min_ms".to_string(), Value::Float(min));
10510        stats.insert("max_ms".to_string(), Value::Float(max));
10511        stats.insert("stddev_ms".to_string(), Value::Float(stddev));
10512
10513        Ok(Value::Tuple(Rc::new(vec![
10514            last_result,
10515            Value::Map(Rc::new(RefCell::new(stats))),
10516        ])))
10517    });
10518
10519    // --- DOCUMENTATION ---
10520
10521    // help - get help text for a builtin function
10522    define(interp, "help", Some(1), |_, args| {
10523        let name = match &args[0] {
10524            Value::String(s) => (**s).clone(),
10525            Value::BuiltIn(f) => f.name.clone(),
10526            _ => {
10527                return Err(RuntimeError::new(
10528                    "help: argument must be function name or builtin",
10529                ))
10530            }
10531        };
10532
10533        // Return documentation for known functions
10534        let doc = get_function_doc(&name);
10535        Ok(Value::String(Rc::new(doc)))
10536    });
10537
10538    // list_builtins - list common builtin functions (categories)
10539    define(interp, "list_builtins", Some(0), |_, _| {
10540        let categories = vec![
10541            "Core: print, println, assert, panic, len, type_of",
10542            "Math: abs, floor, ceil, round, sqrt, pow, log, sin, cos, tan",
10543            "Collections: map, filter, reduce, zip, flatten, first, last, sort, reverse",
10544            "Strings: upper, lower, trim, split, join, contains, replace, format",
10545            "IO: read_file, write_file, file_exists, read_line",
10546            "Time: now, sleep, timestamp, format_time",
10547            "JSON: json_parse, json_stringify",
10548            "Crypto: sha256, sha512, md5, base64_encode, base64_decode",
10549            "Regex: regex_match, regex_replace, regex_split",
10550            "Pattern: type_of, is_type, match_regex, match_struct, guard, when",
10551            "DevEx: debug, inspect, trace, assert_eq, assert_ne, test, profile",
10552        ];
10553        let values: Vec<Value> = categories
10554            .iter()
10555            .map(|s| Value::String(Rc::new(s.to_string())))
10556            .collect();
10557        Ok(Value::Array(Rc::new(RefCell::new(values))))
10558    });
10559
10560    // --- UTILITY ---
10561
10562    // todo - placeholder that throws with message
10563    define(interp, "todo", Some(0), |_, _| {
10564        Err(RuntimeError::new("not yet implemented"))
10565    });
10566
10567    // unreachable - mark code as unreachable
10568    define(interp, "unreachable", Some(0), |_, _| {
10569        Err(RuntimeError::new("reached unreachable code"))
10570    });
10571
10572    // unimplemented - mark feature as unimplemented
10573    define(interp, "unimplemented", Some(1), |_, args| {
10574        let msg = match &args[0] {
10575            Value::String(s) => (**s).clone(),
10576            _ => "unimplemented".to_string(),
10577        };
10578        Err(RuntimeError::new(format!("unimplemented: {}", msg)))
10579    });
10580
10581    // deprecated - warn about deprecated usage and return value
10582    define(interp, "deprecated", Some(2), |_, args| {
10583        let msg = match &args[0] {
10584            Value::String(s) => (**s).clone(),
10585            _ => "deprecated".to_string(),
10586        };
10587        eprintln!("[DEPRECATED] {}", msg);
10588        Ok(args[1].clone())
10589    });
10590
10591    // version - return Sigil version info
10592    define(interp, "version", Some(0), |_, _| {
10593        let mut info = HashMap::new();
10594        info.insert(
10595            "sigil".to_string(),
10596            Value::String(Rc::new("0.1.0".to_string())),
10597        );
10598        info.insert(
10599            "stdlib".to_string(),
10600            Value::String(Rc::new("7.0".to_string())),
10601        );
10602        info.insert(
10603            "phase".to_string(),
10604            Value::String(Rc::new("Phase 7 - DevEx".to_string())),
10605        );
10606        Ok(Value::Map(Rc::new(RefCell::new(info))))
10607    });
10608}
10609
10610// Helper to format value for debug output
10611fn format_value_debug(value: &Value) -> String {
10612    match value {
10613        Value::Null => "null".to_string(),
10614        Value::Bool(b) => b.to_string(),
10615        Value::Int(n) => n.to_string(),
10616        Value::Float(f) => format!("{:.6}", f),
10617        Value::String(s) => format!("\"{}\"", s),
10618        Value::Char(c) => format!("'{}'", c),
10619        Value::Array(a) => {
10620            let items: Vec<String> = a.borrow().iter().take(10).map(format_value_debug).collect();
10621            if a.borrow().len() > 10 {
10622                format!(
10623                    "[{}, ... ({} more)]",
10624                    items.join(", "),
10625                    a.borrow().len() - 10
10626                )
10627            } else {
10628                format!("[{}]", items.join(", "))
10629            }
10630        }
10631        Value::Tuple(t) => {
10632            let items: Vec<String> = t.iter().map(format_value_debug).collect();
10633            format!("({})", items.join(", "))
10634        }
10635        Value::Map(m) => {
10636            let items: Vec<String> = m
10637                .borrow()
10638                .iter()
10639                .take(5)
10640                .map(|(k, v)| format!("{}: {}", k, format_value_debug(v)))
10641                .collect();
10642            if m.borrow().len() > 5 {
10643                format!(
10644                    "{{{}, ... ({} more)}}",
10645                    items.join(", "),
10646                    m.borrow().len() - 5
10647                )
10648            } else {
10649                format!("{{{}}}", items.join(", "))
10650            }
10651        }
10652        Value::Set(s) => {
10653            let items: Vec<String> = s.borrow().iter().take(5).cloned().collect();
10654            if s.borrow().len() > 5 {
10655                format!(
10656                    "#{{{}, ... ({} more)}}",
10657                    items.join(", "),
10658                    s.borrow().len() - 5
10659                )
10660            } else {
10661                format!("#{{{}}}", items.join(", "))
10662            }
10663        }
10664        Value::Struct { name, fields } => {
10665            let items: Vec<String> = fields
10666                .borrow()
10667                .iter()
10668                .map(|(k, v)| format!("{}: {}", k, format_value_debug(v)))
10669                .collect();
10670            format!("{} {{{}}}", name, items.join(", "))
10671        }
10672        Value::Variant {
10673            enum_name,
10674            variant_name,
10675            fields,
10676        } => match fields {
10677            Some(f) => {
10678                let items: Vec<String> = f.iter().map(format_value_debug).collect();
10679                format!("{}::{}({})", enum_name, variant_name, items.join(", "))
10680            }
10681            None => format!("{}::{}", enum_name, variant_name),
10682        },
10683        Value::Function(_) => "<function>".to_string(),
10684        Value::BuiltIn(f) => format!("<builtin:{}>", f.name),
10685        Value::Ref(r) => format!("&{}", format_value_debug(&r.borrow())),
10686        Value::Infinity => "∞".to_string(),
10687        Value::Empty => "∅".to_string(),
10688        Value::Evidential { value, evidence } => {
10689            format!("{:?}({})", evidence, format_value_debug(value))
10690        }
10691        Value::Affective { value, affect } => {
10692            let mut markers = Vec::new();
10693            if let Some(s) = &affect.sentiment {
10694                markers.push(format!("{:?}", s));
10695            }
10696            if affect.sarcasm {
10697                markers.push("sarcasm".to_string());
10698            }
10699            if let Some(i) = &affect.intensity {
10700                markers.push(format!("{:?}", i));
10701            }
10702            if let Some(f) = &affect.formality {
10703                markers.push(format!("{:?}", f));
10704            }
10705            if let Some(e) = &affect.emotion {
10706                markers.push(format!("{:?}", e));
10707            }
10708            if let Some(c) = &affect.confidence {
10709                markers.push(format!("{:?}", c));
10710            }
10711            format!("{}[{}]", format_value_debug(value), markers.join(","))
10712        }
10713        Value::Channel(_) => "<channel>".to_string(),
10714        Value::ThreadHandle(_) => "<thread>".to_string(),
10715        Value::Actor(_) => "<actor>".to_string(),
10716        Value::Future(_) => "<future>".to_string(),
10717    }
10718}
10719
10720// Helper for pretty printing with indentation
10721fn pretty_print_value(value: &Value, indent: usize) -> String {
10722    let prefix = "  ".repeat(indent);
10723    match value {
10724        Value::Array(a) => {
10725            if a.borrow().is_empty() {
10726                "[]".to_string()
10727            } else {
10728                let items: Vec<String> = a
10729                    .borrow()
10730                    .iter()
10731                    .map(|v| {
10732                        format!(
10733                            "{}{}",
10734                            "  ".repeat(indent + 1),
10735                            pretty_print_value(v, indent + 1)
10736                        )
10737                    })
10738                    .collect();
10739                format!("[\n{}\n{}]", items.join(",\n"), prefix)
10740            }
10741        }
10742        Value::Map(m) => {
10743            if m.borrow().is_empty() {
10744                "{}".to_string()
10745            } else {
10746                let items: Vec<String> = m
10747                    .borrow()
10748                    .iter()
10749                    .map(|(k, v)| {
10750                        format!(
10751                            "{}\"{}\": {}",
10752                            "  ".repeat(indent + 1),
10753                            k,
10754                            pretty_print_value(v, indent + 1)
10755                        )
10756                    })
10757                    .collect();
10758                format!("{{\n{}\n{}}}", items.join(",\n"), prefix)
10759            }
10760        }
10761        Value::Struct { name, fields } => {
10762            if fields.borrow().is_empty() {
10763                format!("{} {{}}", name)
10764            } else {
10765                let items: Vec<String> = fields
10766                    .borrow()
10767                    .iter()
10768                    .map(|(k, v)| {
10769                        format!(
10770                            "{}{}: {}",
10771                            "  ".repeat(indent + 1),
10772                            k,
10773                            pretty_print_value(v, indent + 1)
10774                        )
10775                    })
10776                    .collect();
10777                format!("{} {{\n{}\n{}}}", name, items.join(",\n"), prefix)
10778            }
10779        }
10780        _ => format_value_debug(value),
10781    }
10782}
10783
10784// Helper to compare values for ordering (DevEx assertions)
10785fn devex_compare(a: &Value, b: &Value) -> Result<i64, RuntimeError> {
10786    match (a, b) {
10787        (Value::Int(a), Value::Int(b)) => Ok(if a < b {
10788            -1
10789        } else if a > b {
10790            1
10791        } else {
10792            0
10793        }),
10794        (Value::Float(a), Value::Float(b)) => Ok(if a < b {
10795            -1
10796        } else if a > b {
10797            1
10798        } else {
10799            0
10800        }),
10801        (Value::Int(a), Value::Float(b)) => {
10802            let a = *a as f64;
10803            Ok(if a < *b {
10804                -1
10805            } else if a > *b {
10806                1
10807            } else {
10808                0
10809            })
10810        }
10811        (Value::Float(a), Value::Int(b)) => {
10812            let b = *b as f64;
10813            Ok(if *a < b {
10814                -1
10815            } else if *a > b {
10816                1
10817            } else {
10818                0
10819            })
10820        }
10821        (Value::String(a), Value::String(b)) => Ok(if a < b {
10822            -1
10823        } else if a > b {
10824            1
10825        } else {
10826            0
10827        }),
10828        _ => Err(RuntimeError::new("cannot compare these types")),
10829    }
10830}
10831
10832// Helper to get type name
10833fn get_type_name(value: &Value) -> String {
10834    match value {
10835        Value::Null => "null".to_string(),
10836        Value::Bool(_) => "bool".to_string(),
10837        Value::Int(_) => "int".to_string(),
10838        Value::Float(_) => "float".to_string(),
10839        Value::String(_) => "string".to_string(),
10840        Value::Char(_) => "char".to_string(),
10841        Value::Array(_) => "array".to_string(),
10842        Value::Tuple(_) => "tuple".to_string(),
10843        Value::Map(_) => "map".to_string(),
10844        Value::Set(_) => "set".to_string(),
10845        Value::Struct { name, .. } => name.clone(),
10846        Value::Variant { enum_name, .. } => enum_name.clone(),
10847        Value::Function(_) => "function".to_string(),
10848        Value::BuiltIn(_) => "builtin".to_string(),
10849        Value::Ref(_) => "ref".to_string(),
10850        Value::Infinity => "infinity".to_string(),
10851        Value::Empty => "empty".to_string(),
10852        Value::Evidential { .. } => "evidential".to_string(),
10853        Value::Affective { .. } => "affective".to_string(),
10854        Value::Channel(_) => "channel".to_string(),
10855        Value::ThreadHandle(_) => "thread".to_string(),
10856        Value::Actor(_) => "actor".to_string(),
10857        Value::Future(_) => "future".to_string(),
10858    }
10859}
10860
10861// Helper to check type aliases
10862fn matches_type_alias(value: &Value, type_name: &str) -> bool {
10863    match (value, type_name) {
10864        (Value::Int(_), "number") | (Value::Float(_), "number") => true,
10865        (Value::Int(_), "integer") => true,
10866        (Value::Array(_), "list") => true,
10867        (Value::Map(_), "dict") | (Value::Map(_), "object") => true,
10868        (Value::Function(_), "fn") | (Value::BuiltIn(_), "fn") => true,
10869        (Value::BuiltIn(_), "function") => true,
10870        _ => false,
10871    }
10872}
10873
10874// Helper to get function documentation
10875fn get_function_doc(name: &str) -> String {
10876    match name {
10877        "print" => "print(value) - Print value to stdout".to_string(),
10878        "println" => "println(value) - Print value with newline".to_string(),
10879        "len" => "len(collection) - Get length of string, array, map, or set".to_string(),
10880        "type_of" => "type_of(value) - Get type name as string".to_string(),
10881        "assert" => "assert(condition) - Assert condition is truthy, panic if false".to_string(),
10882        "assert_eq" => "assert_eq(a, b) - Assert two values are deeply equal".to_string(),
10883        "debug" => "debug(value) - Print value with type info and return it".to_string(),
10884        "map" => "map(array, fn) - Apply function to each element".to_string(),
10885        "filter" => "filter(array, fn) - Keep elements where predicate is true".to_string(),
10886        "reduce" => "reduce(array, init, fn) - Fold array with function".to_string(),
10887        "range" => "range(start, end) - Create array of integers from start to end".to_string(),
10888        "sum" => "sum(array) - Sum all numeric elements".to_string(),
10889        "product" => "product(array) - Multiply all numeric elements".to_string(),
10890        "sort" => "sort(array) - Sort array in ascending order".to_string(),
10891        "reverse" => "reverse(array) - Reverse array order".to_string(),
10892        "join" => "join(array, sep) - Join array elements with separator".to_string(),
10893        "split" => "split(string, sep) - Split string by separator".to_string(),
10894        "trim" => "trim(string) - Remove leading/trailing whitespace".to_string(),
10895        "upper" => "upper(string) - Convert to uppercase".to_string(),
10896        "lower" => "lower(string) - Convert to lowercase".to_string(),
10897        _ => format!("No documentation available for '{}'", name),
10898    }
10899}
10900
10901// ============================================================================
10902// PHASE 8: PERFORMANCE OPTIMIZATIONS
10903// ============================================================================
10904// SoA transforms, tensor ops, autodiff, spatial hashing, constraint solving
10905
10906// ============================================================================
10907// SOA (STRUCT OF ARRAYS) TRANSFORMS
10908// ============================================================================
10909// Convert between AoS (Array of Structs) and SoA (Struct of Arrays) layouts
10910// Critical for SIMD and cache-friendly physics/graphics computations
10911
10912fn register_soa(interp: &mut Interpreter) {
10913    // aos_to_soa(array, keys) - Convert Array of Structs to Struct of Arrays
10914    // Example: aos_to_soa([{x:1,y:2}, {x:3,y:4}], ["x","y"]) -> {x:[1,3], y:[2,4]}
10915    define(interp, "aos_to_soa", Some(2), |_, args| {
10916        let arr = match &args[0] {
10917            Value::Array(arr) => arr.borrow().clone(),
10918            _ => {
10919                return Err(RuntimeError::new(
10920                    "aos_to_soa: first argument must be array",
10921                ))
10922            }
10923        };
10924        let keys = match &args[1] {
10925            Value::Array(keys) => keys.borrow().clone(),
10926            _ => {
10927                return Err(RuntimeError::new(
10928                    "aos_to_soa: second argument must be array of keys",
10929                ))
10930            }
10931        };
10932
10933        if arr.is_empty() {
10934            // Return empty SoA
10935            let mut result = HashMap::new();
10936            for key in &keys {
10937                if let Value::String(k) = key {
10938                    result.insert((**k).clone(), Value::Array(Rc::new(RefCell::new(vec![]))));
10939                }
10940            }
10941            return Ok(Value::Map(Rc::new(RefCell::new(result))));
10942        }
10943
10944        // Extract key names
10945        let key_names: Vec<String> = keys
10946            .iter()
10947            .filter_map(|k| {
10948                if let Value::String(s) = k {
10949                    Some((**s).clone())
10950                } else {
10951                    None
10952                }
10953            })
10954            .collect();
10955
10956        // Build arrays for each key
10957        let mut soa: HashMap<String, Vec<Value>> = HashMap::new();
10958        for key in &key_names {
10959            soa.insert(key.clone(), Vec::with_capacity(arr.len()));
10960        }
10961
10962        // Extract values from each struct
10963        for item in &arr {
10964            match item {
10965                Value::Map(map) => {
10966                    let map = map.borrow();
10967                    for key in &key_names {
10968                        let val = map.get(key).cloned().unwrap_or(Value::Null);
10969                        soa.get_mut(key).unwrap().push(val);
10970                    }
10971                }
10972                Value::Struct { fields, .. } => {
10973                    let fields = fields.borrow();
10974                    for key in &key_names {
10975                        let val = fields.get(key).cloned().unwrap_or(Value::Null);
10976                        soa.get_mut(key).unwrap().push(val);
10977                    }
10978                }
10979                _ => {
10980                    return Err(RuntimeError::new(
10981                        "aos_to_soa: array must contain structs or maps",
10982                    ))
10983                }
10984            }
10985        }
10986
10987        // Convert to Value::Map
10988        let result: HashMap<String, Value> = soa
10989            .into_iter()
10990            .map(|(k, v)| (k, Value::Array(Rc::new(RefCell::new(v)))))
10991            .collect();
10992
10993        Ok(Value::Map(Rc::new(RefCell::new(result))))
10994    });
10995
10996    // soa_to_aos(soa) - Convert Struct of Arrays back to Array of Structs
10997    // Example: soa_to_aos({x:[1,3], y:[2,4]}) -> [{x:1,y:2}, {x:3,y:4}]
10998    define(interp, "soa_to_aos", Some(1), |_, args| {
10999        let soa = match &args[0] {
11000            Value::Map(map) => map.borrow().clone(),
11001            _ => return Err(RuntimeError::new("soa_to_aos: argument must be map")),
11002        };
11003
11004        if soa.is_empty() {
11005            return Ok(Value::Array(Rc::new(RefCell::new(vec![]))));
11006        }
11007
11008        // Get the length from first array
11009        let len = soa
11010            .values()
11011            .next()
11012            .and_then(|v| {
11013                if let Value::Array(arr) = v {
11014                    Some(arr.borrow().len())
11015                } else {
11016                    None
11017                }
11018            })
11019            .unwrap_or(0);
11020
11021        // Build array of structs
11022        let mut aos: Vec<Value> = Vec::with_capacity(len);
11023        for i in 0..len {
11024            let mut fields = HashMap::new();
11025            for (key, value) in &soa {
11026                if let Value::Array(arr) = value {
11027                    let arr = arr.borrow();
11028                    if i < arr.len() {
11029                        fields.insert(key.clone(), arr[i].clone());
11030                    }
11031                }
11032            }
11033            aos.push(Value::Map(Rc::new(RefCell::new(fields))));
11034        }
11035
11036        Ok(Value::Array(Rc::new(RefCell::new(aos))))
11037    });
11038
11039    // soa_map(soa, key, fn) - Apply function to a single array in SoA
11040    // Allows SIMD-friendly operations on one field at a time
11041    define(interp, "soa_map", Some(3), |interp, args| {
11042        let mut soa = match &args[0] {
11043            Value::Map(map) => map.borrow().clone(),
11044            _ => return Err(RuntimeError::new("soa_map: first argument must be SoA map")),
11045        };
11046        let key = match &args[1] {
11047            Value::String(s) => (**s).clone(),
11048            _ => {
11049                return Err(RuntimeError::new(
11050                    "soa_map: second argument must be key string",
11051                ))
11052            }
11053        };
11054        let func = match &args[2] {
11055            Value::Function(f) => f.clone(),
11056            _ => {
11057                return Err(RuntimeError::new(
11058                    "soa_map: third argument must be a function",
11059                ))
11060            }
11061        };
11062
11063        // Get the array for this key
11064        let arr = soa
11065            .get(&key)
11066            .ok_or_else(|| RuntimeError::new(format!("soa_map: key '{}' not found", key)))?;
11067
11068        let arr_vals = match arr {
11069            Value::Array(a) => a.borrow().clone(),
11070            _ => return Err(RuntimeError::new("soa_map: key must map to array")),
11071        };
11072
11073        // Apply function to each element
11074        let results: Vec<Value> = arr_vals
11075            .iter()
11076            .map(|val| interp.call_function(&func, vec![val.clone()]))
11077            .collect::<Result<_, _>>()?;
11078
11079        // Update SoA
11080        soa.insert(key, Value::Array(Rc::new(RefCell::new(results))));
11081
11082        Ok(Value::Map(Rc::new(RefCell::new(soa))))
11083    });
11084
11085    // soa_zip(soa, keys, fn) - Apply function to multiple fields in parallel
11086    // Example: soa_zip(soa, ["x", "y"], fn(x, y) { sqrt(x*x + y*y) }) -> array of magnitudes
11087    define(interp, "soa_zip", Some(3), |interp, args| {
11088        let soa = match &args[0] {
11089            Value::Map(map) => map.borrow().clone(),
11090            _ => return Err(RuntimeError::new("soa_zip: first argument must be SoA map")),
11091        };
11092        let keys = match &args[1] {
11093            Value::Array(keys) => keys.borrow().clone(),
11094            _ => {
11095                return Err(RuntimeError::new(
11096                    "soa_zip: second argument must be array of keys",
11097                ))
11098            }
11099        };
11100        let func = match &args[2] {
11101            Value::Function(f) => f.clone(),
11102            _ => {
11103                return Err(RuntimeError::new(
11104                    "soa_zip: third argument must be a function",
11105                ))
11106            }
11107        };
11108
11109        // Extract arrays for each key
11110        let arrays: Vec<Vec<Value>> = keys
11111            .iter()
11112            .filter_map(|k| {
11113                if let Value::String(s) = k {
11114                    if let Some(Value::Array(arr)) = soa.get(&**s) {
11115                        return Some(arr.borrow().clone());
11116                    }
11117                }
11118                None
11119            })
11120            .collect();
11121
11122        if arrays.is_empty() {
11123            return Ok(Value::Array(Rc::new(RefCell::new(vec![]))));
11124        }
11125
11126        let len = arrays[0].len();
11127
11128        // Apply function with zipped values
11129        let results: Vec<Value> = (0..len)
11130            .map(|i| {
11131                let fn_args: Vec<Value> = arrays
11132                    .iter()
11133                    .filter_map(|arr| arr.get(i).cloned())
11134                    .collect();
11135                interp.call_function(&func, fn_args)
11136            })
11137            .collect::<Result<_, _>>()?;
11138
11139        Ok(Value::Array(Rc::new(RefCell::new(results))))
11140    });
11141
11142    // interleave(arrays...) - Interleave multiple arrays (for position/normal/uv vertices)
11143    // Example: interleave([x1,x2], [y1,y2], [z1,z2]) -> [x1,y1,z1,x2,y2,z2]
11144    define(interp, "interleave", None, |_, args| {
11145        if args.is_empty() {
11146            return Ok(Value::Array(Rc::new(RefCell::new(vec![]))));
11147        }
11148
11149        let arrays: Vec<Vec<Value>> = args
11150            .iter()
11151            .filter_map(|arg| {
11152                if let Value::Array(arr) = arg {
11153                    Some(arr.borrow().clone())
11154                } else {
11155                    None
11156                }
11157            })
11158            .collect();
11159
11160        if arrays.is_empty() {
11161            return Ok(Value::Array(Rc::new(RefCell::new(vec![]))));
11162        }
11163
11164        let len = arrays[0].len();
11165        let stride = arrays.len();
11166        let mut result = Vec::with_capacity(len * stride);
11167
11168        for i in 0..len {
11169            for arr in &arrays {
11170                if let Some(val) = arr.get(i) {
11171                    result.push(val.clone());
11172                }
11173            }
11174        }
11175
11176        Ok(Value::Array(Rc::new(RefCell::new(result))))
11177    });
11178
11179    // deinterleave(array, stride) - Deinterleave an array (inverse of interleave)
11180    // Example: deinterleave([x1,y1,z1,x2,y2,z2], 3) -> [[x1,x2], [y1,y2], [z1,z2]]
11181    define(interp, "deinterleave", Some(2), |_, args| {
11182        let arr = match &args[0] {
11183            Value::Array(arr) => arr.borrow().clone(),
11184            _ => {
11185                return Err(RuntimeError::new(
11186                    "deinterleave: first argument must be array",
11187                ))
11188            }
11189        };
11190        let stride = match &args[1] {
11191            Value::Int(n) => *n as usize,
11192            _ => {
11193                return Err(RuntimeError::new(
11194                    "deinterleave: second argument must be integer stride",
11195                ))
11196            }
11197        };
11198
11199        if stride == 0 {
11200            return Err(RuntimeError::new("deinterleave: stride must be > 0"));
11201        }
11202
11203        let mut result: Vec<Vec<Value>> = (0..stride).map(|_| Vec::new()).collect();
11204
11205        for (i, val) in arr.iter().enumerate() {
11206            result[i % stride].push(val.clone());
11207        }
11208
11209        Ok(Value::Array(Rc::new(RefCell::new(
11210            result
11211                .into_iter()
11212                .map(|v| Value::Array(Rc::new(RefCell::new(v))))
11213                .collect(),
11214        ))))
11215    });
11216}
11217
11218// ============================================================================
11219// TENSOR OPERATIONS
11220// ============================================================================
11221// Outer products, contractions, tensor transpose for advanced linear algebra
11222
11223fn register_tensor(interp: &mut Interpreter) {
11224    // outer_product(a, b) - Tensor outer product: a ⊗ b
11225    // vec × vec -> matrix, mat × vec -> rank-3 tensor
11226    define(interp, "outer_product", Some(2), |_, args| {
11227        let a = match &args[0] {
11228            Value::Array(arr) => arr.borrow().clone(),
11229            _ => return Err(RuntimeError::new("outer_product: arguments must be arrays")),
11230        };
11231        let b = match &args[1] {
11232            Value::Array(arr) => arr.borrow().clone(),
11233            _ => return Err(RuntimeError::new("outer_product: arguments must be arrays")),
11234        };
11235
11236        // vec ⊗ vec -> matrix
11237        let mut result: Vec<Value> = Vec::with_capacity(a.len() * b.len());
11238        for ai in &a {
11239            for bi in &b {
11240                let product = match (ai, bi) {
11241                    (Value::Float(x), Value::Float(y)) => Value::Float(x * y),
11242                    (Value::Int(x), Value::Int(y)) => Value::Int(x * y),
11243                    (Value::Float(x), Value::Int(y)) => Value::Float(x * (*y as f64)),
11244                    (Value::Int(x), Value::Float(y)) => Value::Float((*x as f64) * y),
11245                    _ => return Err(RuntimeError::new("outer_product: elements must be numeric")),
11246                };
11247                result.push(product);
11248            }
11249        }
11250
11251        Ok(Value::Array(Rc::new(RefCell::new(result))))
11252    });
11253
11254    // tensor_contract(a, b, axis_a, axis_b) - Contract tensors along specified axes
11255    // Generalized matrix multiplication and index contraction
11256    define(interp, "tensor_contract", Some(4), |_, args| {
11257        let a = match &args[0] {
11258            Value::Array(arr) => arr.borrow().clone(),
11259            _ => {
11260                return Err(RuntimeError::new(
11261                    "tensor_contract: first argument must be array",
11262                ))
11263            }
11264        };
11265        let b = match &args[1] {
11266            Value::Array(arr) => arr.borrow().clone(),
11267            _ => {
11268                return Err(RuntimeError::new(
11269                    "tensor_contract: second argument must be array",
11270                ))
11271            }
11272        };
11273        let _axis_a = match &args[2] {
11274            Value::Int(n) => *n as usize,
11275            _ => return Err(RuntimeError::new("tensor_contract: axis must be integer")),
11276        };
11277        let _axis_b = match &args[3] {
11278            Value::Int(n) => *n as usize,
11279            _ => return Err(RuntimeError::new("tensor_contract: axis must be integer")),
11280        };
11281
11282        // Simple dot product for 1D tensors (vectors)
11283        if a.len() != b.len() {
11284            return Err(RuntimeError::new(
11285                "tensor_contract: vectors must have same length for contraction",
11286            ));
11287        }
11288
11289        let mut sum = 0.0f64;
11290        for (ai, bi) in a.iter().zip(b.iter()) {
11291            let product = match (ai, bi) {
11292                (Value::Float(x), Value::Float(y)) => x * y,
11293                (Value::Int(x), Value::Int(y)) => (*x as f64) * (*y as f64),
11294                (Value::Float(x), Value::Int(y)) => x * (*y as f64),
11295                (Value::Int(x), Value::Float(y)) => (*x as f64) * y,
11296                _ => {
11297                    return Err(RuntimeError::new(
11298                        "tensor_contract: elements must be numeric",
11299                    ))
11300                }
11301            };
11302            sum += product;
11303        }
11304
11305        Ok(Value::Float(sum))
11306    });
11307
11308    // kronecker_product(a, b) - Kronecker tensor product
11309    // Used in quantum computing and multi-linear algebra
11310    define(interp, "kronecker_product", Some(2), |_, args| {
11311        let a = match &args[0] {
11312            Value::Array(arr) => arr.borrow().clone(),
11313            _ => {
11314                return Err(RuntimeError::new(
11315                    "kronecker_product: arguments must be arrays",
11316                ))
11317            }
11318        };
11319        let b = match &args[1] {
11320            Value::Array(arr) => arr.borrow().clone(),
11321            _ => {
11322                return Err(RuntimeError::new(
11323                    "kronecker_product: arguments must be arrays",
11324                ))
11325            }
11326        };
11327
11328        // For 1D vectors: same as outer product
11329        let mut result: Vec<Value> = Vec::with_capacity(a.len() * b.len());
11330        for ai in &a {
11331            for bi in &b {
11332                let product = match (ai, bi) {
11333                    (Value::Float(x), Value::Float(y)) => Value::Float(x * y),
11334                    (Value::Int(x), Value::Int(y)) => Value::Int(x * y),
11335                    (Value::Float(x), Value::Int(y)) => Value::Float(x * (*y as f64)),
11336                    (Value::Int(x), Value::Float(y)) => Value::Float((*x as f64) * y),
11337                    _ => {
11338                        return Err(RuntimeError::new(
11339                            "kronecker_product: elements must be numeric",
11340                        ))
11341                    }
11342                };
11343                result.push(product);
11344            }
11345        }
11346
11347        Ok(Value::Array(Rc::new(RefCell::new(result))))
11348    });
11349
11350    // hadamard_product(a, b) - Element-wise product (Hadamard/Schur product)
11351    define(interp, "hadamard_product", Some(2), |_, args| {
11352        let a = match &args[0] {
11353            Value::Array(arr) => arr.borrow().clone(),
11354            _ => {
11355                return Err(RuntimeError::new(
11356                    "hadamard_product: arguments must be arrays",
11357                ))
11358            }
11359        };
11360        let b = match &args[1] {
11361            Value::Array(arr) => arr.borrow().clone(),
11362            _ => {
11363                return Err(RuntimeError::new(
11364                    "hadamard_product: arguments must be arrays",
11365                ))
11366            }
11367        };
11368
11369        if a.len() != b.len() {
11370            return Err(RuntimeError::new(
11371                "hadamard_product: arrays must have same length",
11372            ));
11373        }
11374
11375        let result: Vec<Value> = a
11376            .iter()
11377            .zip(b.iter())
11378            .map(|(ai, bi)| match (ai, bi) {
11379                (Value::Float(x), Value::Float(y)) => Ok(Value::Float(x * y)),
11380                (Value::Int(x), Value::Int(y)) => Ok(Value::Int(x * y)),
11381                (Value::Float(x), Value::Int(y)) => Ok(Value::Float(x * (*y as f64))),
11382                (Value::Int(x), Value::Float(y)) => Ok(Value::Float((*x as f64) * y)),
11383                _ => Err(RuntimeError::new(
11384                    "hadamard_product: elements must be numeric",
11385                )),
11386            })
11387            .collect::<Result<_, _>>()?;
11388
11389        Ok(Value::Array(Rc::new(RefCell::new(result))))
11390    });
11391
11392    // trace(matrix, size) - Trace of square matrix (sum of diagonal)
11393    define(interp, "trace", Some(2), |_, args| {
11394        let arr = match &args[0] {
11395            Value::Array(arr) => arr.borrow().clone(),
11396            _ => return Err(RuntimeError::new("trace: first argument must be array")),
11397        };
11398        let size = match &args[1] {
11399            Value::Int(n) => *n as usize,
11400            _ => {
11401                return Err(RuntimeError::new(
11402                    "trace: second argument must be matrix size",
11403                ))
11404            }
11405        };
11406
11407        let mut sum = 0.0f64;
11408        for i in 0..size {
11409            let idx = i * size + i;
11410            if idx < arr.len() {
11411                sum += match &arr[idx] {
11412                    Value::Float(f) => *f,
11413                    Value::Int(n) => *n as f64,
11414                    _ => return Err(RuntimeError::new("trace: elements must be numeric")),
11415                };
11416            }
11417        }
11418
11419        Ok(Value::Float(sum))
11420    });
11421}
11422
11423// ============================================================================
11424// AUTOMATIC DIFFERENTIATION
11425// ============================================================================
11426//
11427// This module provides numerical differentiation using finite differences.
11428// While not as accurate as symbolic or dual-number autodiff, it's simple
11429// and works for any function without special annotations.
11430//
11431// ## Available Functions
11432//
11433// | Function | Description | Complexity |
11434// |----------|-------------|------------|
11435// | `grad(f, x, [h])` | Gradient of f at x | O(n) function calls |
11436// | `jacobian(f, x, [h])` | Jacobian matrix | O(m*n) function calls |
11437// | `hessian(f, x, [h])` | Hessian matrix | O(n²) function calls |
11438// | `directional_derivative(f, x, v, [h])` | Derivative along v | O(1) |
11439// | `laplacian(f, x, [h])` | Sum of second partials | O(n) |
11440//
11441// ## Algorithm Details
11442//
11443// All functions use central differences: (f(x+h) - f(x-h)) / 2h
11444// Default step size h = 1e-7 (optimized for f64 precision)
11445//
11446// ## Usage Examples
11447//
11448// ```sigil
11449// // Scalar function gradient
11450// fn f(x) { return x * x; }
11451// let df = grad(f, 3.0);  // Returns 6.0 (derivative of x² at x=3)
11452//
11453// // Multi-variable gradient
11454// fn g(x) { return get(x, 0)*get(x, 0) + get(x, 1)*get(x, 1); }
11455// let dg = grad(g, [1.0, 2.0]);  // Returns [2.0, 4.0]
11456//
11457// // Hessian of f at point x
11458// let H = hessian(f, [x, y]);  // Returns 2D array of second derivatives
11459// ```
11460//
11461// ## Performance Notes
11462//
11463// - grad: 2n function evaluations for n-dimensional input
11464// - jacobian: 2mn evaluations for m-output, n-input function
11465// - hessian: 4n² evaluations (computed from gradient)
11466// - For performance-critical code, consider symbolic differentiation
11467
11468fn register_autodiff(interp: &mut Interpreter) {
11469    // grad(f, x, h) - Numerical gradient of f at x using finite differences
11470    // h is optional step size (default 1e-7)
11471    define(interp, "grad", None, |interp, args| {
11472        if args.len() < 2 {
11473            return Err(RuntimeError::new(
11474                "grad() requires function and point arguments.\n\
11475                 Usage: grad(f, x) or grad(f, x, step_size)\n\
11476                 Example:\n\
11477                   fn f(x) { return x * x; }\n\
11478                   let derivative = grad(f, 3.0);  // Returns 6.0",
11479            ));
11480        }
11481
11482        let func = match &args[0] {
11483            Value::Function(f) => f.clone(),
11484            _ => {
11485                return Err(RuntimeError::new(
11486                    "grad() first argument must be a function.\n\
11487                 Got non-function value. Define a function first:\n\
11488                   fn my_func(x) { return x * x; }\n\
11489                   grad(my_func, 2.0)",
11490                ))
11491            }
11492        };
11493        let x = match &args[1] {
11494            Value::Float(f) => *f,
11495            Value::Int(n) => *n as f64,
11496            Value::Array(arr) => {
11497                // Multi-variable gradient
11498                let arr = arr.borrow().clone();
11499                let h = if args.len() > 2 {
11500                    match &args[2] {
11501                        Value::Float(f) => *f,
11502                        Value::Int(n) => *n as f64,
11503                        _ => 1e-7,
11504                    }
11505                } else {
11506                    1e-7
11507                };
11508
11509                let mut gradient = Vec::with_capacity(arr.len());
11510                for (i, xi) in arr.iter().enumerate() {
11511                    let xi_val = match xi {
11512                        Value::Float(f) => *f,
11513                        Value::Int(n) => *n as f64,
11514                        _ => continue,
11515                    };
11516
11517                    // f(x + h*ei) - f(x - h*ei) / 2h
11518                    let mut x_plus = arr.clone();
11519                    let mut x_minus = arr.clone();
11520                    x_plus[i] = Value::Float(xi_val + h);
11521                    x_minus[i] = Value::Float(xi_val - h);
11522
11523                    let f_plus = interp
11524                        .call_function(&func, vec![Value::Array(Rc::new(RefCell::new(x_plus)))])?;
11525                    let f_minus = interp
11526                        .call_function(&func, vec![Value::Array(Rc::new(RefCell::new(x_minus)))])?;
11527
11528                    let grad_i = match (f_plus, f_minus) {
11529                        (Value::Float(fp), Value::Float(fm)) => (fp - fm) / (2.0 * h),
11530                        (Value::Int(fp), Value::Int(fm)) => (fp - fm) as f64 / (2.0 * h),
11531                        _ => return Err(RuntimeError::new("grad: function must return numeric")),
11532                    };
11533
11534                    gradient.push(Value::Float(grad_i));
11535                }
11536
11537                return Ok(Value::Array(Rc::new(RefCell::new(gradient))));
11538            }
11539            _ => return Err(RuntimeError::new("grad: x must be numeric or array")),
11540        };
11541
11542        let h = if args.len() > 2 {
11543            match &args[2] {
11544                Value::Float(f) => *f,
11545                Value::Int(n) => *n as f64,
11546                _ => 1e-7,
11547            }
11548        } else {
11549            1e-7
11550        };
11551
11552        // Single variable derivative using central difference
11553        let f_plus = interp.call_function(&func, vec![Value::Float(x + h)])?;
11554        let f_minus = interp.call_function(&func, vec![Value::Float(x - h)])?;
11555
11556        let derivative = match (f_plus, f_minus) {
11557            (Value::Float(fp), Value::Float(fm)) => (fp - fm) / (2.0 * h),
11558            (Value::Int(fp), Value::Int(fm)) => (fp - fm) as f64 / (2.0 * h),
11559            _ => return Err(RuntimeError::new("grad: function must return numeric")),
11560        };
11561
11562        Ok(Value::Float(derivative))
11563    });
11564
11565    // jacobian(f, x) - Compute Jacobian matrix for vector function
11566    define(interp, "jacobian", Some(2), |interp, args| {
11567        let func = match &args[0] {
11568            Value::Function(f) => f.clone(),
11569            _ => {
11570                return Err(RuntimeError::new(
11571                    "jacobian: first argument must be a function",
11572                ))
11573            }
11574        };
11575        let x = match &args[1] {
11576            Value::Array(arr) => arr.borrow().clone(),
11577            _ => return Err(RuntimeError::new("jacobian: second argument must be array")),
11578        };
11579
11580        let h = 1e-7;
11581        let n = x.len();
11582
11583        // Evaluate f at x to get output dimension
11584        let f_x =
11585            interp.call_function(&func, vec![Value::Array(Rc::new(RefCell::new(x.clone())))])?;
11586        let m = match &f_x {
11587            Value::Array(arr) => arr.borrow().len(),
11588            _ => 1,
11589        };
11590
11591        // Build Jacobian matrix (m x n)
11592        let mut jacobian: Vec<Value> = Vec::with_capacity(m * n);
11593
11594        for j in 0..n {
11595            let xj = match &x[j] {
11596                Value::Float(f) => *f,
11597                Value::Int(i) => *i as f64,
11598                _ => continue,
11599            };
11600
11601            let mut x_plus = x.clone();
11602            let mut x_minus = x.clone();
11603            x_plus[j] = Value::Float(xj + h);
11604            x_minus[j] = Value::Float(xj - h);
11605
11606            let f_plus =
11607                interp.call_function(&func, vec![Value::Array(Rc::new(RefCell::new(x_plus)))])?;
11608            let f_minus =
11609                interp.call_function(&func, vec![Value::Array(Rc::new(RefCell::new(x_minus)))])?;
11610
11611            // Extract derivatives for each output component
11612            match (&f_plus, &f_minus) {
11613                (Value::Array(fp), Value::Array(fm)) => {
11614                    let fp = fp.borrow();
11615                    let fm = fm.borrow();
11616                    for i in 0..m {
11617                        let dfi_dxj = match (&fp[i], &fm[i]) {
11618                            (Value::Float(a), Value::Float(b)) => (*a - *b) / (2.0 * h),
11619                            (Value::Int(a), Value::Int(b)) => (*a - *b) as f64 / (2.0 * h),
11620                            _ => 0.0,
11621                        };
11622                        jacobian.push(Value::Float(dfi_dxj));
11623                    }
11624                }
11625                (Value::Float(fp), Value::Float(fm)) => {
11626                    jacobian.push(Value::Float((fp - fm) / (2.0 * h)));
11627                }
11628                _ => {
11629                    return Err(RuntimeError::new(
11630                        "jacobian: function must return array or numeric",
11631                    ))
11632                }
11633            }
11634        }
11635
11636        Ok(Value::Array(Rc::new(RefCell::new(jacobian))))
11637    });
11638
11639    // hessian(f, x) - Compute Hessian matrix (second derivatives)
11640    define(interp, "hessian", Some(2), |interp, args| {
11641        let func = match &args[0] {
11642            Value::Function(f) => f.clone(),
11643            _ => {
11644                return Err(RuntimeError::new(
11645                    "hessian: first argument must be a function",
11646                ))
11647            }
11648        };
11649        let x = match &args[1] {
11650            Value::Array(arr) => arr.borrow().clone(),
11651            _ => return Err(RuntimeError::new("hessian: second argument must be array")),
11652        };
11653
11654        let h = 1e-5; // Larger h for second derivatives
11655        let n = x.len();
11656
11657        let mut hessian: Vec<Value> = Vec::with_capacity(n * n);
11658
11659        for i in 0..n {
11660            for j in 0..n {
11661                let xi = match &x[i] {
11662                    Value::Float(f) => *f,
11663                    Value::Int(k) => *k as f64,
11664                    _ => continue,
11665                };
11666                let xj = match &x[j] {
11667                    Value::Float(f) => *f,
11668                    Value::Int(k) => *k as f64,
11669                    _ => continue,
11670                };
11671
11672                // Second partial derivative using finite differences
11673                let mut x_pp = x.clone();
11674                let mut x_pm = x.clone();
11675                let mut x_mp = x.clone();
11676                let mut x_mm = x.clone();
11677
11678                x_pp[i] = Value::Float(xi + h);
11679                x_pp[j] = Value::Float(if i == j { xi + 2.0 * h } else { xj + h });
11680                x_pm[i] = Value::Float(xi + h);
11681                x_pm[j] = Value::Float(if i == j { xi } else { xj - h });
11682                x_mp[i] = Value::Float(xi - h);
11683                x_mp[j] = Value::Float(if i == j { xi } else { xj + h });
11684                x_mm[i] = Value::Float(xi - h);
11685                x_mm[j] = Value::Float(if i == j { xi - 2.0 * h } else { xj - h });
11686
11687                let f_pp =
11688                    interp.call_function(&func, vec![Value::Array(Rc::new(RefCell::new(x_pp)))])?;
11689                let f_pm =
11690                    interp.call_function(&func, vec![Value::Array(Rc::new(RefCell::new(x_pm)))])?;
11691                let f_mp =
11692                    interp.call_function(&func, vec![Value::Array(Rc::new(RefCell::new(x_mp)))])?;
11693                let f_mm =
11694                    interp.call_function(&func, vec![Value::Array(Rc::new(RefCell::new(x_mm)))])?;
11695
11696                let d2f = match (f_pp, f_pm, f_mp, f_mm) {
11697                    (
11698                        Value::Float(fpp),
11699                        Value::Float(fpm),
11700                        Value::Float(fmp),
11701                        Value::Float(fmm),
11702                    ) => (fpp - fpm - fmp + fmm) / (4.0 * h * h),
11703                    _ => 0.0,
11704                };
11705
11706                hessian.push(Value::Float(d2f));
11707            }
11708        }
11709
11710        Ok(Value::Array(Rc::new(RefCell::new(hessian))))
11711    });
11712
11713    // divergence(f, x) - Compute divergence of vector field (∇·F)
11714    define(interp, "divergence", Some(2), |interp, args| {
11715        let func = match &args[0] {
11716            Value::Function(f) => f.clone(),
11717            _ => {
11718                return Err(RuntimeError::new(
11719                    "divergence: first argument must be a function",
11720                ))
11721            }
11722        };
11723        let x = match &args[1] {
11724            Value::Array(arr) => arr.borrow().clone(),
11725            _ => {
11726                return Err(RuntimeError::new(
11727                    "divergence: second argument must be array",
11728                ))
11729            }
11730        };
11731
11732        let h = 1e-7;
11733        let mut div = 0.0f64;
11734
11735        for (i, xi) in x.iter().enumerate() {
11736            let xi_val = match xi {
11737                Value::Float(f) => *f,
11738                Value::Int(n) => *n as f64,
11739                _ => continue,
11740            };
11741
11742            let mut x_plus = x.clone();
11743            let mut x_minus = x.clone();
11744            x_plus[i] = Value::Float(xi_val + h);
11745            x_minus[i] = Value::Float(xi_val - h);
11746
11747            let f_plus =
11748                interp.call_function(&func, vec![Value::Array(Rc::new(RefCell::new(x_plus)))])?;
11749            let f_minus =
11750                interp.call_function(&func, vec![Value::Array(Rc::new(RefCell::new(x_minus)))])?;
11751
11752            // Extract i-th component
11753            let df_i = match (&f_plus, &f_minus) {
11754                (Value::Array(fp), Value::Array(fm)) => {
11755                    let fp = fp.borrow();
11756                    let fm = fm.borrow();
11757                    if i < fp.len() && i < fm.len() {
11758                        match (&fp[i], &fm[i]) {
11759                            (Value::Float(a), Value::Float(b)) => (*a - *b) / (2.0 * h),
11760                            (Value::Int(a), Value::Int(b)) => (*a - *b) as f64 / (2.0 * h),
11761                            _ => 0.0,
11762                        }
11763                    } else {
11764                        0.0
11765                    }
11766                }
11767                _ => 0.0,
11768            };
11769
11770            div += df_i;
11771        }
11772
11773        Ok(Value::Float(div))
11774    });
11775}
11776
11777// ============================================================================
11778// SPATIAL HASHING / ACCELERATION STRUCTURES
11779// ============================================================================
11780// BVH, octrees, spatial hashing for efficient collision detection and queries
11781
11782fn register_spatial(interp: &mut Interpreter) {
11783    // spatial_hash_new(cell_size) - Create new spatial hash grid
11784    define(interp, "spatial_hash_new", Some(1), |_, args| {
11785        let cell_size = match &args[0] {
11786            Value::Float(f) => *f,
11787            Value::Int(n) => *n as f64,
11788            _ => {
11789                return Err(RuntimeError::new(
11790                    "spatial_hash_new: cell_size must be numeric",
11791                ))
11792            }
11793        };
11794
11795        let mut config = HashMap::new();
11796        config.insert("cell_size".to_string(), Value::Float(cell_size));
11797        config.insert(
11798            "buckets".to_string(),
11799            Value::Map(Rc::new(RefCell::new(HashMap::new()))),
11800        );
11801
11802        Ok(Value::Map(Rc::new(RefCell::new(config))))
11803    });
11804
11805    // spatial_hash_insert(hash, id, position) - Insert object at position
11806    define(interp, "spatial_hash_insert", Some(3), |_, args| {
11807        let hash = match &args[0] {
11808            Value::Map(map) => map.clone(),
11809            _ => {
11810                return Err(RuntimeError::new(
11811                    "spatial_hash_insert: first argument must be spatial hash",
11812                ))
11813            }
11814        };
11815        let id = args[1].clone();
11816        let pos = match &args[2] {
11817            Value::Array(arr) => arr.borrow().clone(),
11818            _ => {
11819                return Err(RuntimeError::new(
11820                    "spatial_hash_insert: position must be array",
11821                ))
11822            }
11823        };
11824
11825        let cell_size = {
11826            let h = hash.borrow();
11827            match h.get("cell_size") {
11828                Some(Value::Float(f)) => *f,
11829                _ => 1.0,
11830            }
11831        };
11832
11833        // Compute cell key
11834        let key = pos
11835            .iter()
11836            .filter_map(|v| match v {
11837                Value::Float(f) => Some((*f / cell_size).floor() as i64),
11838                Value::Int(n) => Some(*n / (cell_size as i64)),
11839                _ => None,
11840            })
11841            .map(|n| n.to_string())
11842            .collect::<Vec<_>>()
11843            .join(",");
11844
11845        // Insert into bucket
11846        {
11847            let mut h = hash.borrow_mut();
11848            let buckets = h
11849                .entry("buckets".to_string())
11850                .or_insert_with(|| Value::Map(Rc::new(RefCell::new(HashMap::new()))));
11851
11852            if let Value::Map(buckets_map) = buckets {
11853                let mut bm = buckets_map.borrow_mut();
11854                let bucket = bm
11855                    .entry(key)
11856                    .or_insert_with(|| Value::Array(Rc::new(RefCell::new(vec![]))));
11857
11858                if let Value::Array(arr) = bucket {
11859                    arr.borrow_mut().push(id);
11860                }
11861            }
11862        }
11863
11864        Ok(Value::Map(hash))
11865    });
11866
11867    // spatial_hash_query(hash, position, radius) - Query objects near position
11868    define(interp, "spatial_hash_query", Some(3), |_, args| {
11869        let hash = match &args[0] {
11870            Value::Map(map) => map.borrow().clone(),
11871            _ => {
11872                return Err(RuntimeError::new(
11873                    "spatial_hash_query: first argument must be spatial hash",
11874                ))
11875            }
11876        };
11877        let pos = match &args[1] {
11878            Value::Array(arr) => arr.borrow().clone(),
11879            _ => {
11880                return Err(RuntimeError::new(
11881                    "spatial_hash_query: position must be array",
11882                ))
11883            }
11884        };
11885        let radius = match &args[2] {
11886            Value::Float(f) => *f,
11887            Value::Int(n) => *n as f64,
11888            _ => {
11889                return Err(RuntimeError::new(
11890                    "spatial_hash_query: radius must be numeric",
11891                ))
11892            }
11893        };
11894
11895        let cell_size = match hash.get("cell_size") {
11896            Some(Value::Float(f)) => *f,
11897            _ => 1.0,
11898        };
11899
11900        // Get center cell
11901        let center: Vec<i64> = pos
11902            .iter()
11903            .filter_map(|v| match v {
11904                Value::Float(f) => Some((*f / cell_size).floor() as i64),
11905                Value::Int(n) => Some(*n / (cell_size as i64)),
11906                _ => None,
11907            })
11908            .collect();
11909
11910        // Compute cell range to check
11911        let cells_to_check = (radius / cell_size).ceil() as i64;
11912
11913        let mut results: Vec<Value> = Vec::new();
11914
11915        if let Some(Value::Map(buckets)) = hash.get("buckets") {
11916            let buckets = buckets.borrow();
11917
11918            // Check neighboring cells
11919            if center.len() >= 2 {
11920                for dx in -cells_to_check..=cells_to_check {
11921                    for dy in -cells_to_check..=cells_to_check {
11922                        let key = format!("{},{}", center[0] + dx, center[1] + dy);
11923                        if let Some(Value::Array(bucket)) = buckets.get(&key) {
11924                            for item in bucket.borrow().iter() {
11925                                // Push without duplicate check since Value doesn't impl PartialEq
11926                                // For production use, would need to track IDs separately
11927                                results.push(item.clone());
11928                            }
11929                        }
11930                    }
11931                }
11932            }
11933        }
11934
11935        Ok(Value::Array(Rc::new(RefCell::new(results))))
11936    });
11937
11938    // aabb_new(min, max) - Create axis-aligned bounding box
11939    define(interp, "aabb_new", Some(2), |_, args| {
11940        let min = match &args[0] {
11941            Value::Array(arr) => arr.borrow().clone(),
11942            _ => return Err(RuntimeError::new("aabb_new: min must be array")),
11943        };
11944        let max = match &args[1] {
11945            Value::Array(arr) => arr.borrow().clone(),
11946            _ => return Err(RuntimeError::new("aabb_new: max must be array")),
11947        };
11948
11949        let mut aabb = HashMap::new();
11950        aabb.insert("min".to_string(), Value::Array(Rc::new(RefCell::new(min))));
11951        aabb.insert("max".to_string(), Value::Array(Rc::new(RefCell::new(max))));
11952
11953        Ok(Value::Map(Rc::new(RefCell::new(aabb))))
11954    });
11955
11956    // aabb_intersects(a, b) - Test if two AABBs intersect
11957    define(interp, "aabb_intersects", Some(2), |_, args| {
11958        let a = match &args[0] {
11959            Value::Map(map) => map.borrow().clone(),
11960            _ => {
11961                return Err(RuntimeError::new(
11962                    "aabb_intersects: arguments must be AABBs",
11963                ))
11964            }
11965        };
11966        let b = match &args[1] {
11967            Value::Map(map) => map.borrow().clone(),
11968            _ => {
11969                return Err(RuntimeError::new(
11970                    "aabb_intersects: arguments must be AABBs",
11971                ))
11972            }
11973        };
11974
11975        let a_min = extract_vec_from_map(&a, "min")?;
11976        let a_max = extract_vec_from_map(&a, "max")?;
11977        let b_min = extract_vec_from_map(&b, "min")?;
11978        let b_max = extract_vec_from_map(&b, "max")?;
11979
11980        // Check overlap in each dimension
11981        for i in 0..a_min
11982            .len()
11983            .min(a_max.len())
11984            .min(b_min.len())
11985            .min(b_max.len())
11986        {
11987            if a_max[i] < b_min[i] || b_max[i] < a_min[i] {
11988                return Ok(Value::Bool(false));
11989            }
11990        }
11991
11992        Ok(Value::Bool(true))
11993    });
11994
11995    // aabb_contains(aabb, point) - Test if AABB contains point
11996    define(interp, "aabb_contains", Some(2), |_, args| {
11997        let aabb = match &args[0] {
11998            Value::Map(map) => map.borrow().clone(),
11999            _ => {
12000                return Err(RuntimeError::new(
12001                    "aabb_contains: first argument must be AABB",
12002                ))
12003            }
12004        };
12005        let point = match &args[1] {
12006            Value::Array(arr) => arr.borrow().clone(),
12007            _ => {
12008                return Err(RuntimeError::new(
12009                    "aabb_contains: second argument must be point array",
12010                ))
12011            }
12012        };
12013
12014        let min = extract_vec_from_map(&aabb, "min")?;
12015        let max = extract_vec_from_map(&aabb, "max")?;
12016
12017        for (i, p) in point.iter().enumerate() {
12018            let p_val = match p {
12019                Value::Float(f) => *f,
12020                Value::Int(n) => *n as f64,
12021                _ => continue,
12022            };
12023
12024            if i < min.len() && p_val < min[i] {
12025                return Ok(Value::Bool(false));
12026            }
12027            if i < max.len() && p_val > max[i] {
12028                return Ok(Value::Bool(false));
12029            }
12030        }
12031
12032        Ok(Value::Bool(true))
12033    });
12034}
12035
12036// Helper for extracting vector from AABB map
12037fn extract_vec_from_map(map: &HashMap<String, Value>, key: &str) -> Result<Vec<f64>, RuntimeError> {
12038    match map.get(key) {
12039        Some(Value::Array(arr)) => arr
12040            .borrow()
12041            .iter()
12042            .map(|v| match v {
12043                Value::Float(f) => Ok(*f),
12044                Value::Int(n) => Ok(*n as f64),
12045                _ => Err(RuntimeError::new("Expected numeric value")),
12046            })
12047            .collect(),
12048        _ => Err(RuntimeError::new(format!(
12049            "Missing or invalid '{}' in AABB",
12050            key
12051        ))),
12052    }
12053}
12054
12055// ============================================================================
12056// PHYSICS / CONSTRAINT SOLVER
12057// ============================================================================
12058// Verlet integration, constraint solving, spring systems
12059
12060fn register_physics(interp: &mut Interpreter) {
12061    // verlet_integrate(pos, prev_pos, accel, dt) - Verlet integration step
12062    // Returns new position: pos + (pos - prev_pos) + accel * dt^2
12063    define(interp, "verlet_integrate", Some(4), |_, args| {
12064        let pos = extract_vec3(&args[0], "verlet_integrate")?;
12065        let prev = extract_vec3(&args[1], "verlet_integrate")?;
12066        let accel = extract_vec3(&args[2], "verlet_integrate")?;
12067        let dt = match &args[3] {
12068            Value::Float(f) => *f,
12069            Value::Int(n) => *n as f64,
12070            _ => return Err(RuntimeError::new("verlet_integrate: dt must be numeric")),
12071        };
12072
12073        let dt2 = dt * dt;
12074        let new_pos = [
12075            pos[0] + (pos[0] - prev[0]) + accel[0] * dt2,
12076            pos[1] + (pos[1] - prev[1]) + accel[1] * dt2,
12077            pos[2] + (pos[2] - prev[2]) + accel[2] * dt2,
12078        ];
12079
12080        Ok(make_vec3_arr(new_pos))
12081    });
12082
12083    // spring_force(p1, p2, rest_length, stiffness) - Compute spring force
12084    define(interp, "spring_force", Some(4), |_, args| {
12085        let p1 = extract_vec3(&args[0], "spring_force")?;
12086        let p2 = extract_vec3(&args[1], "spring_force")?;
12087        let rest_length = match &args[2] {
12088            Value::Float(f) => *f,
12089            Value::Int(n) => *n as f64,
12090            _ => {
12091                return Err(RuntimeError::new(
12092                    "spring_force: rest_length must be numeric",
12093                ))
12094            }
12095        };
12096        let stiffness = match &args[3] {
12097            Value::Float(f) => *f,
12098            Value::Int(n) => *n as f64,
12099            _ => return Err(RuntimeError::new("spring_force: stiffness must be numeric")),
12100        };
12101
12102        let delta = [p2[0] - p1[0], p2[1] - p1[1], p2[2] - p1[2]];
12103        let length = (delta[0] * delta[0] + delta[1] * delta[1] + delta[2] * delta[2]).sqrt();
12104
12105        if length < 1e-10 {
12106            return Ok(make_vec3_arr([0.0, 0.0, 0.0]));
12107        }
12108
12109        let displacement = length - rest_length;
12110        let force_mag = stiffness * displacement;
12111        let normalized = [delta[0] / length, delta[1] / length, delta[2] / length];
12112
12113        Ok(make_vec3_arr([
12114            normalized[0] * force_mag,
12115            normalized[1] * force_mag,
12116            normalized[2] * force_mag,
12117        ]))
12118    });
12119
12120    // distance_constraint(p1, p2, target_distance) - Apply distance constraint
12121    // Returns tuple of (new_p1, new_p2) that satisfy the constraint
12122    define(interp, "distance_constraint", Some(3), |_, args| {
12123        let p1 = extract_vec3(&args[0], "distance_constraint")?;
12124        let p2 = extract_vec3(&args[1], "distance_constraint")?;
12125        let target = match &args[2] {
12126            Value::Float(f) => *f,
12127            Value::Int(n) => *n as f64,
12128            _ => {
12129                return Err(RuntimeError::new(
12130                    "distance_constraint: target must be numeric",
12131                ))
12132            }
12133        };
12134
12135        let delta = [p2[0] - p1[0], p2[1] - p1[1], p2[2] - p1[2]];
12136        let length = (delta[0] * delta[0] + delta[1] * delta[1] + delta[2] * delta[2]).sqrt();
12137
12138        if length < 1e-10 {
12139            return Ok(Value::Tuple(Rc::new(vec![
12140                make_vec3_arr(p1),
12141                make_vec3_arr(p2),
12142            ])));
12143        }
12144
12145        let correction = (length - target) / length * 0.5;
12146        let corr_vec = [
12147            delta[0] * correction,
12148            delta[1] * correction,
12149            delta[2] * correction,
12150        ];
12151
12152        let new_p1 = [
12153            p1[0] + corr_vec[0],
12154            p1[1] + corr_vec[1],
12155            p1[2] + corr_vec[2],
12156        ];
12157        let new_p2 = [
12158            p2[0] - corr_vec[0],
12159            p2[1] - corr_vec[1],
12160            p2[2] - corr_vec[2],
12161        ];
12162
12163        Ok(Value::Tuple(Rc::new(vec![
12164            make_vec3_arr(new_p1),
12165            make_vec3_arr(new_p2),
12166        ])))
12167    });
12168
12169    // solve_constraints(points, constraints, iterations) - Iterative constraint solver
12170    // constraints: array of {type, indices, params}
12171    define(interp, "solve_constraints", Some(3), |_, args| {
12172        let mut points = match &args[0] {
12173            Value::Array(arr) => arr.borrow().clone(),
12174            _ => {
12175                return Err(RuntimeError::new(
12176                    "solve_constraints: first argument must be array of points",
12177                ))
12178            }
12179        };
12180        let constraints = match &args[1] {
12181            Value::Array(arr) => arr.borrow().clone(),
12182            _ => {
12183                return Err(RuntimeError::new(
12184                    "solve_constraints: second argument must be array of constraints",
12185                ))
12186            }
12187        };
12188        let iterations = match &args[2] {
12189            Value::Int(n) => *n as usize,
12190            _ => {
12191                return Err(RuntimeError::new(
12192                    "solve_constraints: iterations must be integer",
12193                ))
12194            }
12195        };
12196
12197        for _ in 0..iterations {
12198            for constraint in &constraints {
12199                match constraint {
12200                    Value::Map(c) => {
12201                        let c = c.borrow();
12202                        let constraint_type = c
12203                            .get("type")
12204                            .and_then(|v| {
12205                                if let Value::String(s) = v {
12206                                    Some((**s).clone())
12207                                } else {
12208                                    None
12209                                }
12210                            })
12211                            .unwrap_or_default();
12212
12213                        match constraint_type.as_str() {
12214                            "distance" => {
12215                                let indices = match c.get("indices") {
12216                                    Some(Value::Array(arr)) => arr.borrow().clone(),
12217                                    _ => continue,
12218                                };
12219                                let target = match c.get("distance") {
12220                                    Some(Value::Float(f)) => *f,
12221                                    Some(Value::Int(n)) => *n as f64,
12222                                    _ => continue,
12223                                };
12224
12225                                if indices.len() >= 2 {
12226                                    let i1 = match &indices[0] {
12227                                        Value::Int(n) => *n as usize,
12228                                        _ => continue,
12229                                    };
12230                                    let i2 = match &indices[1] {
12231                                        Value::Int(n) => *n as usize,
12232                                        _ => continue,
12233                                    };
12234
12235                                    if i1 < points.len() && i2 < points.len() {
12236                                        // Apply distance constraint inline
12237                                        let p1 = extract_vec3(&points[i1], "solve")?;
12238                                        let p2 = extract_vec3(&points[i2], "solve")?;
12239
12240                                        let delta = [p2[0] - p1[0], p2[1] - p1[1], p2[2] - p1[2]];
12241                                        let length = (delta[0] * delta[0]
12242                                            + delta[1] * delta[1]
12243                                            + delta[2] * delta[2])
12244                                            .sqrt();
12245
12246                                        if length > 1e-10 {
12247                                            let correction = (length - target) / length * 0.5;
12248                                            let corr_vec = [
12249                                                delta[0] * correction,
12250                                                delta[1] * correction,
12251                                                delta[2] * correction,
12252                                            ];
12253
12254                                            points[i1] = make_vec3_arr([
12255                                                p1[0] + corr_vec[0],
12256                                                p1[1] + corr_vec[1],
12257                                                p1[2] + corr_vec[2],
12258                                            ]);
12259                                            points[i2] = make_vec3_arr([
12260                                                p2[0] - corr_vec[0],
12261                                                p2[1] - corr_vec[1],
12262                                                p2[2] - corr_vec[2],
12263                                            ]);
12264                                        }
12265                                    }
12266                                }
12267                            }
12268                            _ => {}
12269                        }
12270                    }
12271                    _ => continue,
12272                }
12273            }
12274        }
12275
12276        Ok(Value::Array(Rc::new(RefCell::new(points))))
12277    });
12278
12279    // ray_sphere_intersect(ray_origin, ray_dir, sphere_center, radius) - Ray-sphere intersection
12280    // Returns distance to intersection or -1 if no hit
12281    define(interp, "ray_sphere_intersect", Some(4), |_, args| {
12282        let origin = extract_vec3(&args[0], "ray_sphere_intersect")?;
12283        let dir = extract_vec3(&args[1], "ray_sphere_intersect")?;
12284        let center = extract_vec3(&args[2], "ray_sphere_intersect")?;
12285        let radius = match &args[3] {
12286            Value::Float(f) => *f,
12287            Value::Int(n) => *n as f64,
12288            _ => {
12289                return Err(RuntimeError::new(
12290                    "ray_sphere_intersect: radius must be numeric",
12291                ))
12292            }
12293        };
12294
12295        let oc = [
12296            origin[0] - center[0],
12297            origin[1] - center[1],
12298            origin[2] - center[2],
12299        ];
12300
12301        let a = dir[0] * dir[0] + dir[1] * dir[1] + dir[2] * dir[2];
12302        let b = 2.0 * (oc[0] * dir[0] + oc[1] * dir[1] + oc[2] * dir[2]);
12303        let c = oc[0] * oc[0] + oc[1] * oc[1] + oc[2] * oc[2] - radius * radius;
12304
12305        let discriminant = b * b - 4.0 * a * c;
12306
12307        if discriminant < 0.0 {
12308            Ok(Value::Float(-1.0))
12309        } else {
12310            let t = (-b - discriminant.sqrt()) / (2.0 * a);
12311            if t > 0.0 {
12312                Ok(Value::Float(t))
12313            } else {
12314                let t2 = (-b + discriminant.sqrt()) / (2.0 * a);
12315                if t2 > 0.0 {
12316                    Ok(Value::Float(t2))
12317                } else {
12318                    Ok(Value::Float(-1.0))
12319                }
12320            }
12321        }
12322    });
12323
12324    // ray_plane_intersect(ray_origin, ray_dir, plane_point, plane_normal) - Ray-plane intersection
12325    define(interp, "ray_plane_intersect", Some(4), |_, args| {
12326        let origin = extract_vec3(&args[0], "ray_plane_intersect")?;
12327        let dir = extract_vec3(&args[1], "ray_plane_intersect")?;
12328        let plane_pt = extract_vec3(&args[2], "ray_plane_intersect")?;
12329        let normal = extract_vec3(&args[3], "ray_plane_intersect")?;
12330
12331        let denom = dir[0] * normal[0] + dir[1] * normal[1] + dir[2] * normal[2];
12332
12333        if denom.abs() < 1e-10 {
12334            return Ok(Value::Float(-1.0)); // Parallel to plane
12335        }
12336
12337        let diff = [
12338            plane_pt[0] - origin[0],
12339            plane_pt[1] - origin[1],
12340            plane_pt[2] - origin[2],
12341        ];
12342        let t = (diff[0] * normal[0] + diff[1] * normal[1] + diff[2] * normal[2]) / denom;
12343
12344        if t > 0.0 {
12345            Ok(Value::Float(t))
12346        } else {
12347            Ok(Value::Float(-1.0))
12348        }
12349    });
12350}
12351
12352// ============================================================================
12353// GEOMETRIC ALGEBRA (GA3D - Cl(3,0,0))
12354// ============================================================================
12355//
12356// Complete Clifford Algebra implementation in 3D. Geometric Algebra unifies:
12357// - Complex numbers (as rotations in 2D)
12358// - Quaternions (as rotors in 3D)
12359// - Vectors, bivectors, and trivectors
12360// - Reflections, rotations, and projections
12361//
12362// ## Multivector Structure
12363//
12364// | Grade | Basis | Name | Geometric Meaning |
12365// |-------|-------|------|-------------------|
12366// | 0 | 1 | Scalar | Magnitude |
12367// | 1 | e₁, e₂, e₃ | Vectors | Directed lengths |
12368// | 2 | e₁₂, e₂₃, e₃₁ | Bivectors | Oriented planes |
12369// | 3 | e₁₂₃ | Trivector | Oriented volume |
12370//
12371// ## Key Operations
12372//
12373// | Function | Description | Mathematical Form |
12374// |----------|-------------|-------------------|
12375// | `mv_new(s, e1..e123)` | Create multivector | s + e₁v₁ + ... + e₁₂₃t |
12376// | `mv_geometric_product(a, b)` | Geometric product | ab (non-commutative) |
12377// | `mv_inner_product(a, b)` | Inner product | a·b |
12378// | `mv_outer_product(a, b)` | Outer product | a∧b (wedge) |
12379// | `rotor_from_axis_angle(axis, θ)` | Create rotor | cos(θ/2) + sin(θ/2)·B |
12380// | `rotor_apply(R, v)` | Apply rotor | RvR† (sandwich) |
12381//
12382// ## Rotor Properties
12383//
12384// Rotors are normalized even-grade multivectors (scalar + bivector).
12385// They rotate vectors via the "sandwich product": v' = RvR†
12386// This is more efficient than matrix multiplication and composes naturally.
12387//
12388// ## Usage Examples
12389//
12390// ```sigil
12391// // Create a 90° rotation around Z-axis
12392// let axis = vec3(0, 0, 1);
12393// let R = rotor_from_axis_angle(axis, PI / 2.0);
12394//
12395// // Rotate a vector
12396// let v = vec3(1, 0, 0);
12397// let v_rotated = rotor_apply(R, v);  // Returns [0, 1, 0]
12398//
12399// // Compose rotations
12400// let R2 = rotor_from_axis_angle(vec3(0, 1, 0), PI / 4.0);
12401// let R_combined = rotor_compose(R, R2);  // First R, then R2
12402// ```
12403//
12404// ## Grade Extraction
12405//
12406// | Function | Returns |
12407// |----------|---------|
12408// | `mv_grade(mv, 0)` | Scalar part |
12409// | `mv_grade(mv, 1)` | Vector part |
12410// | `mv_grade(mv, 2)` | Bivector part |
12411// | `mv_grade(mv, 3)` | Trivector part |
12412
12413fn register_geometric_algebra(interp: &mut Interpreter) {
12414    // Helper to create a multivector from 8 components
12415    fn make_multivector(components: [f64; 8]) -> Value {
12416        let mut mv = HashMap::new();
12417        mv.insert("s".to_string(), Value::Float(components[0])); // scalar
12418        mv.insert("e1".to_string(), Value::Float(components[1])); // e₁
12419        mv.insert("e2".to_string(), Value::Float(components[2])); // e₂
12420        mv.insert("e3".to_string(), Value::Float(components[3])); // e₃
12421        mv.insert("e12".to_string(), Value::Float(components[4])); // e₁₂
12422        mv.insert("e23".to_string(), Value::Float(components[5])); // e₂₃
12423        mv.insert("e31".to_string(), Value::Float(components[6])); // e₃₁
12424        mv.insert("e123".to_string(), Value::Float(components[7])); // e₁₂₃ (pseudoscalar)
12425        mv.insert(
12426            "_type".to_string(),
12427            Value::String(Rc::new("multivector".to_string())),
12428        );
12429        Value::Map(Rc::new(RefCell::new(mv)))
12430    }
12431
12432    fn extract_multivector(v: &Value, fn_name: &str) -> Result<[f64; 8], RuntimeError> {
12433        match v {
12434            Value::Map(map) => {
12435                let map = map.borrow();
12436                let get_component = |key: &str| -> f64 {
12437                    match map.get(key) {
12438                        Some(Value::Float(f)) => *f,
12439                        Some(Value::Int(n)) => *n as f64,
12440                        _ => 0.0,
12441                    }
12442                };
12443                Ok([
12444                    get_component("s"),
12445                    get_component("e1"),
12446                    get_component("e2"),
12447                    get_component("e3"),
12448                    get_component("e12"),
12449                    get_component("e23"),
12450                    get_component("e31"),
12451                    get_component("e123"),
12452                ])
12453            }
12454            _ => Err(RuntimeError::new(format!(
12455                "{}: expected multivector",
12456                fn_name
12457            ))),
12458        }
12459    }
12460
12461    // mv_new(s, e1, e2, e3, e12, e23, e31, e123) - Create multivector from components
12462    define(interp, "mv_new", Some(8), |_, args| {
12463        let mut components = [0.0f64; 8];
12464        for (i, arg) in args.iter().enumerate().take(8) {
12465            components[i] = match arg {
12466                Value::Float(f) => *f,
12467                Value::Int(n) => *n as f64,
12468                _ => 0.0,
12469            };
12470        }
12471        Ok(make_multivector(components))
12472    });
12473
12474    // mv_scalar(s) - Create scalar multivector
12475    define(interp, "mv_scalar", Some(1), |_, args| {
12476        let s = match &args[0] {
12477            Value::Float(f) => *f,
12478            Value::Int(n) => *n as f64,
12479            _ => return Err(RuntimeError::new("mv_scalar: expected number")),
12480        };
12481        Ok(make_multivector([s, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]))
12482    });
12483
12484    // mv_vector(x, y, z) - Create vector (grade-1 multivector)
12485    define(interp, "mv_vector", Some(3), |_, args| {
12486        let x = match &args[0] {
12487            Value::Float(f) => *f,
12488            Value::Int(n) => *n as f64,
12489            _ => 0.0,
12490        };
12491        let y = match &args[1] {
12492            Value::Float(f) => *f,
12493            Value::Int(n) => *n as f64,
12494            _ => 0.0,
12495        };
12496        let z = match &args[2] {
12497            Value::Float(f) => *f,
12498            Value::Int(n) => *n as f64,
12499            _ => 0.0,
12500        };
12501        Ok(make_multivector([0.0, x, y, z, 0.0, 0.0, 0.0, 0.0]))
12502    });
12503
12504    // mv_bivector(xy, yz, zx) - Create bivector (grade-2, represents oriented planes)
12505    define(interp, "mv_bivector", Some(3), |_, args| {
12506        let xy = match &args[0] {
12507            Value::Float(f) => *f,
12508            Value::Int(n) => *n as f64,
12509            _ => 0.0,
12510        };
12511        let yz = match &args[1] {
12512            Value::Float(f) => *f,
12513            Value::Int(n) => *n as f64,
12514            _ => 0.0,
12515        };
12516        let zx = match &args[2] {
12517            Value::Float(f) => *f,
12518            Value::Int(n) => *n as f64,
12519            _ => 0.0,
12520        };
12521        Ok(make_multivector([0.0, 0.0, 0.0, 0.0, xy, yz, zx, 0.0]))
12522    });
12523
12524    // mv_trivector(xyz) - Create trivector/pseudoscalar (grade-3, represents oriented volume)
12525    define(interp, "mv_trivector", Some(1), |_, args| {
12526        let xyz = match &args[0] {
12527            Value::Float(f) => *f,
12528            Value::Int(n) => *n as f64,
12529            _ => 0.0,
12530        };
12531        Ok(make_multivector([0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, xyz]))
12532    });
12533
12534    // mv_add(a, b) - Add two multivectors
12535    define(interp, "mv_add", Some(2), |_, args| {
12536        let a = extract_multivector(&args[0], "mv_add")?;
12537        let b = extract_multivector(&args[1], "mv_add")?;
12538        Ok(make_multivector([
12539            a[0] + b[0],
12540            a[1] + b[1],
12541            a[2] + b[2],
12542            a[3] + b[3],
12543            a[4] + b[4],
12544            a[5] + b[5],
12545            a[6] + b[6],
12546            a[7] + b[7],
12547        ]))
12548    });
12549
12550    // mv_sub(a, b) - Subtract two multivectors
12551    define(interp, "mv_sub", Some(2), |_, args| {
12552        let a = extract_multivector(&args[0], "mv_sub")?;
12553        let b = extract_multivector(&args[1], "mv_sub")?;
12554        Ok(make_multivector([
12555            a[0] - b[0],
12556            a[1] - b[1],
12557            a[2] - b[2],
12558            a[3] - b[3],
12559            a[4] - b[4],
12560            a[5] - b[5],
12561            a[6] - b[6],
12562            a[7] - b[7],
12563        ]))
12564    });
12565
12566    // mv_scale(mv, scalar) - Scale a multivector
12567    define(interp, "mv_scale", Some(2), |_, args| {
12568        let a = extract_multivector(&args[0], "mv_scale")?;
12569        let s = match &args[1] {
12570            Value::Float(f) => *f,
12571            Value::Int(n) => *n as f64,
12572            _ => {
12573                return Err(RuntimeError::new(
12574                    "mv_scale: second argument must be number",
12575                ))
12576            }
12577        };
12578        Ok(make_multivector([
12579            a[0] * s,
12580            a[1] * s,
12581            a[2] * s,
12582            a[3] * s,
12583            a[4] * s,
12584            a[5] * s,
12585            a[6] * s,
12586            a[7] * s,
12587        ]))
12588    });
12589
12590    // mv_geometric(a, b) - Geometric product (THE fundamental operation)
12591    // This is what makes GA powerful: ab = a·b + a∧b
12592    define(interp, "mv_geometric", Some(2), |_, args| {
12593        let a = extract_multivector(&args[0], "mv_geometric")?;
12594        let b = extract_multivector(&args[1], "mv_geometric")?;
12595
12596        // Full geometric product in Cl(3,0,0)
12597        // Using: e₁² = e₂² = e₃² = 1, eᵢeⱼ = -eⱼeᵢ for i≠j
12598        let mut r = [0.0f64; 8];
12599
12600        // Scalar part
12601        r[0] = a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]
12602            - a[4] * b[4]
12603            - a[5] * b[5]
12604            - a[6] * b[6]
12605            - a[7] * b[7];
12606
12607        // e₁ part
12608        r[1] = a[0] * b[1] + a[1] * b[0] - a[2] * b[4] + a[3] * b[6] + a[4] * b[2]
12609            - a[5] * b[7]
12610            - a[6] * b[3]
12611            - a[7] * b[5];
12612
12613        // e₂ part
12614        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]
12615            - a[6] * b[7]
12616            - a[7] * b[6];
12617
12618        // e₃ part
12619        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]
12620            + a[6] * b[1]
12621            - a[7] * b[4];
12622
12623        // e₁₂ part
12624        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]
12625            - a[6] * b[5]
12626            + a[7] * b[3];
12627
12628        // e₂₃ part
12629        r[5] = a[0] * b[5] + a[1] * b[7] + a[2] * b[3] - a[3] * b[2] - a[4] * b[6]
12630            + a[5] * b[0]
12631            + a[6] * b[4]
12632            + a[7] * b[1];
12633
12634        // e₃₁ part
12635        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]
12636            + a[6] * b[0]
12637            + a[7] * b[2];
12638
12639        // e₁₂₃ part
12640        r[7] = a[0] * b[7]
12641            + a[1] * b[5]
12642            + a[2] * b[6]
12643            + a[3] * b[4]
12644            + a[4] * b[3]
12645            + a[5] * b[1]
12646            + a[6] * b[2]
12647            + a[7] * b[0];
12648
12649        Ok(make_multivector(r))
12650    });
12651
12652    // mv_wedge(a, b) - Outer/wedge product (∧) - antisymmetric part
12653    // Creates higher-grade elements: vector ∧ vector = bivector
12654    define(interp, "mv_wedge", Some(2), |_, args| {
12655        let a = extract_multivector(&args[0], "mv_wedge")?;
12656        let b = extract_multivector(&args[1], "mv_wedge")?;
12657
12658        let mut r = [0.0f64; 8];
12659
12660        // Scalar ∧ anything = scalar * anything (grade 0)
12661        r[0] = a[0] * b[0];
12662
12663        // Vector parts (grade 1): s∧v + v∧s
12664        r[1] = a[0] * b[1] + a[1] * b[0];
12665        r[2] = a[0] * b[2] + a[2] * b[0];
12666        r[3] = a[0] * b[3] + a[3] * b[0];
12667
12668        // Bivector parts (grade 2): s∧B + v∧v + B∧s
12669        r[4] = a[0] * b[4] + a[1] * b[2] - a[2] * b[1] + a[4] * b[0];
12670        r[5] = a[0] * b[5] + a[2] * b[3] - a[3] * b[2] + a[5] * b[0];
12671        r[6] = a[0] * b[6] + a[3] * b[1] - a[1] * b[3] + a[6] * b[0];
12672
12673        // Trivector part (grade 3): s∧T + v∧B + B∧v + T∧s
12674        r[7] = a[0] * b[7] + a[7] * b[0] + a[1] * b[5] + a[2] * b[6] + a[3] * b[4]
12675            - a[4] * b[3]
12676            - a[5] * b[1]
12677            - a[6] * b[2];
12678
12679        Ok(make_multivector(r))
12680    });
12681
12682    // mv_inner(a, b) - Inner/dot product (⟂) - symmetric contraction
12683    // Lowers grade: vector · vector = scalar, bivector · vector = vector
12684    define(interp, "mv_inner", Some(2), |_, args| {
12685        let a = extract_multivector(&args[0], "mv_inner")?;
12686        let b = extract_multivector(&args[1], "mv_inner")?;
12687
12688        let mut r = [0.0f64; 8];
12689
12690        // Left contraction formula
12691        // Scalar (vectors dotted)
12692        r[0] = a[1] * b[1] + a[2] * b[2] + a[3] * b[3]
12693            - a[4] * b[4]
12694            - a[5] * b[5]
12695            - a[6] * b[6]
12696            - a[7] * b[7];
12697
12698        // Vector parts (bivector · vector)
12699        r[1] = a[4] * b[2] - a[6] * b[3] - a[5] * b[7];
12700        r[2] = -a[4] * b[1] + a[5] * b[3] - a[6] * b[7];
12701        r[3] = a[6] * b[1] - a[5] * b[2] - a[4] * b[7];
12702
12703        // Bivector parts (trivector · vector)
12704        r[4] = a[7] * b[3];
12705        r[5] = a[7] * b[1];
12706        r[6] = a[7] * b[2];
12707
12708        Ok(make_multivector(r))
12709    });
12710
12711    // mv_reverse(a) - Reverse (†) - reverses order of basis vectors
12712    // (e₁e₂)† = e₂e₁ = -e₁e₂
12713    define(interp, "mv_reverse", Some(1), |_, args| {
12714        let a = extract_multivector(&args[0], "mv_reverse")?;
12715        // Grade 0,1 unchanged; Grade 2,3 negated
12716        Ok(make_multivector([
12717            a[0], a[1], a[2], a[3], -a[4], -a[5], -a[6], -a[7],
12718        ]))
12719    });
12720
12721    // mv_dual(a) - Dual (Hodge star) - multiply by pseudoscalar
12722    // Maps grade k to grade (n-k) in n dimensions
12723    define(interp, "mv_dual", Some(1), |_, args| {
12724        let a = extract_multivector(&args[0], "mv_dual")?;
12725        // In 3D: dual(1) = e123, dual(e1) = e23, etc.
12726        // Multiplying by e123: since e123² = -1 in Cl(3,0,0)
12727        Ok(make_multivector([
12728            -a[7], // s ← -e123
12729            -a[5], // e1 ← -e23
12730            -a[6], // e2 ← -e31
12731            -a[4], // e3 ← -e12
12732            a[3],  // e12 ← e3
12733            a[1],  // e23 ← e1
12734            a[2],  // e31 ← e2
12735            a[0],  // e123 ← s
12736        ]))
12737    });
12738
12739    // mv_magnitude(a) - Magnitude/norm of multivector
12740    define(interp, "mv_magnitude", Some(1), |_, args| {
12741        let a = extract_multivector(&args[0], "mv_magnitude")?;
12742        let mag_sq = a[0] * a[0]
12743            + a[1] * a[1]
12744            + a[2] * a[2]
12745            + a[3] * a[3]
12746            + a[4] * a[4]
12747            + a[5] * a[5]
12748            + a[6] * a[6]
12749            + a[7] * a[7];
12750        Ok(Value::Float(mag_sq.sqrt()))
12751    });
12752
12753    // mv_normalize(a) - Normalize multivector
12754    define(interp, "mv_normalize", Some(1), |_, args| {
12755        let a = extract_multivector(&args[0], "mv_normalize")?;
12756        let mag = (a[0] * a[0]
12757            + a[1] * a[1]
12758            + a[2] * a[2]
12759            + a[3] * a[3]
12760            + a[4] * a[4]
12761            + a[5] * a[5]
12762            + a[6] * a[6]
12763            + a[7] * a[7])
12764            .sqrt();
12765        if mag < 1e-10 {
12766            return Ok(make_multivector([0.0; 8]));
12767        }
12768        Ok(make_multivector([
12769            a[0] / mag,
12770            a[1] / mag,
12771            a[2] / mag,
12772            a[3] / mag,
12773            a[4] / mag,
12774            a[5] / mag,
12775            a[6] / mag,
12776            a[7] / mag,
12777        ]))
12778    });
12779
12780    // rotor_from_axis_angle(axis, angle) - Create rotor from axis-angle
12781    // Rotor R = cos(θ/2) + sin(θ/2) * B where B is the normalized bivector plane
12782    define(interp, "rotor_from_axis_angle", Some(2), |_, args| {
12783        let axis = extract_vec3(&args[0], "rotor_from_axis_angle")?;
12784        let angle = match &args[1] {
12785            Value::Float(f) => *f,
12786            Value::Int(n) => *n as f64,
12787            _ => {
12788                return Err(RuntimeError::new(
12789                    "rotor_from_axis_angle: angle must be number",
12790                ))
12791            }
12792        };
12793
12794        // Normalize axis
12795        let len = (axis[0] * axis[0] + axis[1] * axis[1] + axis[2] * axis[2]).sqrt();
12796        if len < 1e-10 {
12797            // Return identity rotor
12798            return Ok(make_multivector([1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]));
12799        }
12800        let (nx, ny, nz) = (axis[0] / len, axis[1] / len, axis[2] / len);
12801
12802        let half_angle = angle / 2.0;
12803        let (s, c) = half_angle.sin_cos();
12804
12805        // Rotor: cos(θ/2) - sin(θ/2) * (n₁e₂₃ + n₂e₃₁ + n₃e₁₂)
12806        // Note: axis maps to bivector via dual
12807        Ok(make_multivector([
12808            c, // scalar
12809            0.0,
12810            0.0,
12811            0.0,     // no vector part
12812            -s * nz, // e12 (axis z → bivector xy)
12813            -s * nx, // e23 (axis x → bivector yz)
12814            -s * ny, // e31 (axis y → bivector zx)
12815            0.0,     // no trivector
12816        ]))
12817    });
12818
12819    // rotor_apply(rotor, vector) - Apply rotor to vector: RvR†
12820    // This is the sandwich product - THE way to rotate in GA
12821    define(interp, "rotor_apply", Some(2), |_, args| {
12822        let r = extract_multivector(&args[0], "rotor_apply")?;
12823        let v = extract_vec3(&args[1], "rotor_apply")?;
12824
12825        // Create vector multivector
12826        let v_mv = [0.0, v[0], v[1], v[2], 0.0, 0.0, 0.0, 0.0];
12827
12828        // Compute R† (reverse of rotor)
12829        let r_rev = [r[0], r[1], r[2], r[3], -r[4], -r[5], -r[6], -r[7]];
12830
12831        // First: R * v
12832        let mut rv = [0.0f64; 8];
12833        rv[0] = r[0] * v_mv[0] + r[1] * v_mv[1] + r[2] * v_mv[2] + r[3] * v_mv[3]
12834            - r[4] * v_mv[4]
12835            - r[5] * v_mv[5]
12836            - r[6] * v_mv[6]
12837            - r[7] * v_mv[7];
12838        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]
12839            - r[5] * v_mv[7]
12840            - r[6] * v_mv[3]
12841            - r[7] * v_mv[5];
12842        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]
12843            + r[5] * v_mv[3]
12844            - r[6] * v_mv[7]
12845            - r[7] * v_mv[6];
12846        rv[3] = r[0] * v_mv[3] - r[1] * v_mv[6] + r[2] * v_mv[5] + r[3] * v_mv[0]
12847            - r[4] * v_mv[7]
12848            - r[5] * v_mv[2]
12849            + r[6] * v_mv[1]
12850            - r[7] * v_mv[4];
12851        rv[4] = r[0] * v_mv[4] + r[1] * v_mv[2] - r[2] * v_mv[1]
12852            + r[3] * v_mv[7]
12853            + r[4] * v_mv[0]
12854            + r[5] * v_mv[6]
12855            - r[6] * v_mv[5]
12856            + r[7] * v_mv[3];
12857        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]
12858            + r[5] * v_mv[0]
12859            + r[6] * v_mv[4]
12860            + r[7] * v_mv[1];
12861        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]
12862            - r[5] * v_mv[4]
12863            + r[6] * v_mv[0]
12864            + r[7] * v_mv[2];
12865        rv[7] = r[0] * v_mv[7]
12866            + r[1] * v_mv[5]
12867            + r[2] * v_mv[6]
12868            + r[3] * v_mv[4]
12869            + r[4] * v_mv[3]
12870            + r[5] * v_mv[1]
12871            + r[6] * v_mv[2]
12872            + r[7] * v_mv[0];
12873
12874        // Then: (R * v) * R†
12875        let mut result = [0.0f64; 8];
12876        result[1] = rv[0] * r_rev[1] + rv[1] * r_rev[0] - rv[2] * r_rev[4]
12877            + rv[3] * r_rev[6]
12878            + rv[4] * r_rev[2]
12879            - rv[5] * r_rev[7]
12880            - rv[6] * r_rev[3]
12881            - rv[7] * r_rev[5];
12882        result[2] = rv[0] * r_rev[2] + rv[1] * r_rev[4] + rv[2] * r_rev[0]
12883            - rv[3] * r_rev[5]
12884            - rv[4] * r_rev[1]
12885            + rv[5] * r_rev[3]
12886            - rv[6] * r_rev[7]
12887            - rv[7] * r_rev[6];
12888        result[3] = rv[0] * r_rev[3] - rv[1] * r_rev[6] + rv[2] * r_rev[5] + rv[3] * r_rev[0]
12889            - rv[4] * r_rev[7]
12890            - rv[5] * r_rev[2]
12891            + rv[6] * r_rev[1]
12892            - rv[7] * r_rev[4];
12893
12894        // Return as vec3
12895        Ok(make_vec3(result[1], result[2], result[3]))
12896    });
12897
12898    // rotor_compose(r1, r2) - Compose rotors: R1 * R2
12899    define(interp, "rotor_compose", Some(2), |_, args| {
12900        let a = extract_multivector(&args[0], "rotor_compose")?;
12901        let b = extract_multivector(&args[1], "rotor_compose")?;
12902
12903        // Same as geometric product
12904        let mut r = [0.0f64; 8];
12905        r[0] = a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]
12906            - a[4] * b[4]
12907            - a[5] * b[5]
12908            - a[6] * b[6]
12909            - a[7] * b[7];
12910        r[1] = a[0] * b[1] + a[1] * b[0] - a[2] * b[4] + a[3] * b[6] + a[4] * b[2]
12911            - a[5] * b[7]
12912            - a[6] * b[3]
12913            - a[7] * b[5];
12914        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]
12915            - a[6] * b[7]
12916            - a[7] * b[6];
12917        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]
12918            + a[6] * b[1]
12919            - a[7] * b[4];
12920        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]
12921            - a[6] * b[5]
12922            + a[7] * b[3];
12923        r[5] = a[0] * b[5] + a[1] * b[7] + a[2] * b[3] - a[3] * b[2] - a[4] * b[6]
12924            + a[5] * b[0]
12925            + a[6] * b[4]
12926            + a[7] * b[1];
12927        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]
12928            + a[6] * b[0]
12929            + a[7] * b[2];
12930        r[7] = a[0] * b[7]
12931            + a[1] * b[5]
12932            + a[2] * b[6]
12933            + a[3] * b[4]
12934            + a[4] * b[3]
12935            + a[5] * b[1]
12936            + a[6] * b[2]
12937            + a[7] * b[0];
12938
12939        Ok(make_multivector(r))
12940    });
12941
12942    // mv_reflect(v, n) - Reflect vector v in plane with normal n
12943    // Reflection: -n * v * n (sandwich with negative)
12944    define(interp, "mv_reflect", Some(2), |_, args| {
12945        let v = extract_vec3(&args[0], "mv_reflect")?;
12946        let n = extract_vec3(&args[1], "mv_reflect")?;
12947
12948        // Normalize n
12949        let len = (n[0] * n[0] + n[1] * n[1] + n[2] * n[2]).sqrt();
12950        if len < 1e-10 {
12951            return Ok(make_vec3(v[0], v[1], v[2]));
12952        }
12953        let (nx, ny, nz) = (n[0] / len, n[1] / len, n[2] / len);
12954
12955        // v - 2(v·n)n
12956        let dot = v[0] * nx + v[1] * ny + v[2] * nz;
12957        Ok(make_vec3(
12958            v[0] - 2.0 * dot * nx,
12959            v[1] - 2.0 * dot * ny,
12960            v[2] - 2.0 * dot * nz,
12961        ))
12962    });
12963
12964    // mv_project(v, n) - Project vector v onto plane with normal n
12965    define(interp, "mv_project", Some(2), |_, args| {
12966        let v = extract_vec3(&args[0], "mv_project")?;
12967        let n = extract_vec3(&args[1], "mv_project")?;
12968
12969        let len = (n[0] * n[0] + n[1] * n[1] + n[2] * n[2]).sqrt();
12970        if len < 1e-10 {
12971            return Ok(make_vec3(v[0], v[1], v[2]));
12972        }
12973        let (nx, ny, nz) = (n[0] / len, n[1] / len, n[2] / len);
12974
12975        // v - (v·n)n
12976        let dot = v[0] * nx + v[1] * ny + v[2] * nz;
12977        Ok(make_vec3(v[0] - dot * nx, v[1] - dot * ny, v[2] - dot * nz))
12978    });
12979
12980    // mv_grade(mv, k) - Extract grade-k part of multivector
12981    define(interp, "mv_grade", Some(2), |_, args| {
12982        let a = extract_multivector(&args[0], "mv_grade")?;
12983        let k = match &args[1] {
12984            Value::Int(n) => *n,
12985            _ => return Err(RuntimeError::new("mv_grade: grade must be integer")),
12986        };
12987
12988        match k {
12989            0 => Ok(make_multivector([a[0], 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0])),
12990            1 => Ok(make_multivector([
12991                0.0, a[1], a[2], a[3], 0.0, 0.0, 0.0, 0.0,
12992            ])),
12993            2 => Ok(make_multivector([
12994                0.0, 0.0, 0.0, 0.0, a[4], a[5], a[6], 0.0,
12995            ])),
12996            3 => Ok(make_multivector([0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, a[7]])),
12997            _ => Ok(make_multivector([0.0; 8])),
12998        }
12999    });
13000}
13001
13002// ============================================================================
13003// DIMENSIONAL ANALYSIS (Unit-aware arithmetic)
13004// ============================================================================
13005// Automatic unit tracking and conversion - catch physics errors at runtime
13006// Base SI units: m (length), kg (mass), s (time), A (current), K (temperature), mol, cd
13007
13008fn register_dimensional(interp: &mut Interpreter) {
13009    // Helper to create a quantity with units
13010    // Units stored as exponents: [m, kg, s, A, K, mol, cd]
13011    fn make_quantity(value: f64, units: [i32; 7]) -> Value {
13012        let mut q = HashMap::new();
13013        q.insert("value".to_string(), Value::Float(value));
13014        q.insert("m".to_string(), Value::Int(units[0] as i64)); // meters
13015        q.insert("kg".to_string(), Value::Int(units[1] as i64)); // kilograms
13016        q.insert("s".to_string(), Value::Int(units[2] as i64)); // seconds
13017        q.insert("A".to_string(), Value::Int(units[3] as i64)); // amperes
13018        q.insert("K".to_string(), Value::Int(units[4] as i64)); // kelvin
13019        q.insert("mol".to_string(), Value::Int(units[5] as i64)); // moles
13020        q.insert("cd".to_string(), Value::Int(units[6] as i64)); // candela
13021        q.insert(
13022            "_type".to_string(),
13023            Value::String(Rc::new("quantity".to_string())),
13024        );
13025        Value::Map(Rc::new(RefCell::new(q)))
13026    }
13027
13028    fn extract_quantity(v: &Value, fn_name: &str) -> Result<(f64, [i32; 7]), RuntimeError> {
13029        match v {
13030            Value::Map(map) => {
13031                let map = map.borrow();
13032                let value = match map.get("value") {
13033                    Some(Value::Float(f)) => *f,
13034                    Some(Value::Int(n)) => *n as f64,
13035                    _ => return Err(RuntimeError::new(format!("{}: missing value", fn_name))),
13036                };
13037                let get_exp = |key: &str| -> i32 {
13038                    match map.get(key) {
13039                        Some(Value::Int(n)) => *n as i32,
13040                        _ => 0,
13041                    }
13042                };
13043                Ok((
13044                    value,
13045                    [
13046                        get_exp("m"),
13047                        get_exp("kg"),
13048                        get_exp("s"),
13049                        get_exp("A"),
13050                        get_exp("K"),
13051                        get_exp("mol"),
13052                        get_exp("cd"),
13053                    ],
13054                ))
13055            }
13056            Value::Float(f) => Ok((*f, [0; 7])),
13057            Value::Int(n) => Ok((*n as f64, [0; 7])),
13058            _ => Err(RuntimeError::new(format!(
13059                "{}: expected quantity or number",
13060                fn_name
13061            ))),
13062        }
13063    }
13064
13065    fn units_to_string(units: [i32; 7]) -> String {
13066        let names = ["m", "kg", "s", "A", "K", "mol", "cd"];
13067        let mut parts = Vec::new();
13068        for (i, &exp) in units.iter().enumerate() {
13069            if exp == 1 {
13070                parts.push(names[i].to_string());
13071            } else if exp != 0 {
13072                parts.push(format!("{}^{}", names[i], exp));
13073            }
13074        }
13075        if parts.is_empty() {
13076            "dimensionless".to_string()
13077        } else {
13078            parts.join("·")
13079        }
13080    }
13081
13082    // qty(value, unit_string) - Create quantity with units
13083    // e.g., qty(9.8, "m/s^2") for acceleration
13084    define(interp, "qty", Some(2), |_, args| {
13085        let value = match &args[0] {
13086            Value::Float(f) => *f,
13087            Value::Int(n) => *n as f64,
13088            _ => return Err(RuntimeError::new("qty: first argument must be number")),
13089        };
13090        let unit_str = match &args[1] {
13091            Value::String(s) => s.to_string(),
13092            _ => {
13093                return Err(RuntimeError::new(
13094                    "qty: second argument must be unit string",
13095                ))
13096            }
13097        };
13098
13099        // Parse unit string
13100        let mut units = [0i32; 7];
13101        // Simplified: if '/' present, treat everything as denominator
13102        // For proper parsing, would need to track position relative to '/'
13103        let in_denominator = unit_str.contains('/');
13104
13105        // Simple parser for common units
13106        for part in unit_str.split(|c: char| c == '*' || c == '·' || c == ' ') {
13107            let part = part.trim();
13108            if part.is_empty() {
13109                continue;
13110            }
13111
13112            let (base, exp) = if let Some(idx) = part.find('^') {
13113                let (b, e) = part.split_at(idx);
13114                (b, e[1..].parse::<i32>().unwrap_or(1))
13115            } else if part.contains('/') {
13116                // Handle division inline
13117                continue;
13118            } else {
13119                (part, 1)
13120            };
13121
13122            let sign = if in_denominator { -1 } else { 1 };
13123            match base {
13124                "m" | "meter" | "meters" => units[0] += exp * sign,
13125                "kg" | "kilogram" | "kilograms" => units[1] += exp * sign,
13126                "s" | "sec" | "second" | "seconds" => units[2] += exp * sign,
13127                "A" | "amp" | "ampere" | "amperes" => units[3] += exp * sign,
13128                "K" | "kelvin" => units[4] += exp * sign,
13129                "mol" | "mole" | "moles" => units[5] += exp * sign,
13130                "cd" | "candela" => units[6] += exp * sign,
13131                // Derived units
13132                "N" | "newton" | "newtons" => {
13133                    units[1] += sign;
13134                    units[0] += sign;
13135                    units[2] -= 2 * sign;
13136                }
13137                "J" | "joule" | "joules" => {
13138                    units[1] += sign;
13139                    units[0] += 2 * sign;
13140                    units[2] -= 2 * sign;
13141                }
13142                "W" | "watt" | "watts" => {
13143                    units[1] += sign;
13144                    units[0] += 2 * sign;
13145                    units[2] -= 3 * sign;
13146                }
13147                "Pa" | "pascal" | "pascals" => {
13148                    units[1] += sign;
13149                    units[0] -= sign;
13150                    units[2] -= 2 * sign;
13151                }
13152                "Hz" | "hertz" => {
13153                    units[2] -= sign;
13154                }
13155                "C" | "coulomb" | "coulombs" => {
13156                    units[3] += sign;
13157                    units[2] += sign;
13158                }
13159                "V" | "volt" | "volts" => {
13160                    units[1] += sign;
13161                    units[0] += 2 * sign;
13162                    units[2] -= 3 * sign;
13163                    units[3] -= sign;
13164                }
13165                "Ω" | "ohm" | "ohms" => {
13166                    units[1] += sign;
13167                    units[0] += 2 * sign;
13168                    units[2] -= 3 * sign;
13169                    units[3] -= 2 * sign;
13170                }
13171                _ => {}
13172            }
13173        }
13174
13175        Ok(make_quantity(value, units))
13176    });
13177
13178    // qty_add(a, b) - Add quantities (must have same units)
13179    define(interp, "qty_add", Some(2), |_, args| {
13180        let (val_a, units_a) = extract_quantity(&args[0], "qty_add")?;
13181        let (val_b, units_b) = extract_quantity(&args[1], "qty_add")?;
13182
13183        if units_a != units_b {
13184            return Err(RuntimeError::new(format!(
13185                "qty_add: unit mismatch: {} vs {}",
13186                units_to_string(units_a),
13187                units_to_string(units_b)
13188            )));
13189        }
13190
13191        Ok(make_quantity(val_a + val_b, units_a))
13192    });
13193
13194    // qty_sub(a, b) - Subtract quantities (must have same units)
13195    define(interp, "qty_sub", Some(2), |_, args| {
13196        let (val_a, units_a) = extract_quantity(&args[0], "qty_sub")?;
13197        let (val_b, units_b) = extract_quantity(&args[1], "qty_sub")?;
13198
13199        if units_a != units_b {
13200            return Err(RuntimeError::new(format!(
13201                "qty_sub: unit mismatch: {} vs {}",
13202                units_to_string(units_a),
13203                units_to_string(units_b)
13204            )));
13205        }
13206
13207        Ok(make_quantity(val_a - val_b, units_a))
13208    });
13209
13210    // qty_mul(a, b) - Multiply quantities (units add)
13211    define(interp, "qty_mul", Some(2), |_, args| {
13212        let (val_a, units_a) = extract_quantity(&args[0], "qty_mul")?;
13213        let (val_b, units_b) = extract_quantity(&args[1], "qty_mul")?;
13214
13215        let mut result_units = [0i32; 7];
13216        for i in 0..7 {
13217            result_units[i] = units_a[i] + units_b[i];
13218        }
13219
13220        Ok(make_quantity(val_a * val_b, result_units))
13221    });
13222
13223    // qty_div(a, b) - Divide quantities (units subtract)
13224    define(interp, "qty_div", Some(2), |_, args| {
13225        let (val_a, units_a) = extract_quantity(&args[0], "qty_div")?;
13226        let (val_b, units_b) = extract_quantity(&args[1], "qty_div")?;
13227
13228        if val_b.abs() < 1e-15 {
13229            return Err(RuntimeError::new("qty_div: division by zero"));
13230        }
13231
13232        let mut result_units = [0i32; 7];
13233        for i in 0..7 {
13234            result_units[i] = units_a[i] - units_b[i];
13235        }
13236
13237        Ok(make_quantity(val_a / val_b, result_units))
13238    });
13239
13240    // qty_pow(q, n) - Raise quantity to power (units multiply)
13241    define(interp, "qty_pow", Some(2), |_, args| {
13242        let (val, units) = extract_quantity(&args[0], "qty_pow")?;
13243        let n = match &args[1] {
13244            Value::Int(n) => *n as i32,
13245            Value::Float(f) => *f as i32,
13246            _ => return Err(RuntimeError::new("qty_pow: exponent must be number")),
13247        };
13248
13249        let mut result_units = [0i32; 7];
13250        for i in 0..7 {
13251            result_units[i] = units[i] * n;
13252        }
13253
13254        Ok(make_quantity(val.powi(n), result_units))
13255    });
13256
13257    // qty_sqrt(q) - Square root of quantity (units halve)
13258    define(interp, "qty_sqrt", Some(1), |_, args| {
13259        let (val, units) = extract_quantity(&args[0], "qty_sqrt")?;
13260
13261        // Check that all exponents are even
13262        for (i, &exp) in units.iter().enumerate() {
13263            if exp % 2 != 0 {
13264                let names = ["m", "kg", "s", "A", "K", "mol", "cd"];
13265                return Err(RuntimeError::new(format!(
13266                    "qty_sqrt: cannot take sqrt of {} (odd exponent on {})",
13267                    units_to_string(units),
13268                    names[i]
13269                )));
13270            }
13271        }
13272
13273        let mut result_units = [0i32; 7];
13274        for i in 0..7 {
13275            result_units[i] = units[i] / 2;
13276        }
13277
13278        Ok(make_quantity(val.sqrt(), result_units))
13279    });
13280
13281    // qty_value(q) - Get numeric value of quantity
13282    define(interp, "qty_value", Some(1), |_, args| {
13283        let (val, _) = extract_quantity(&args[0], "qty_value")?;
13284        Ok(Value::Float(val))
13285    });
13286
13287    // qty_units(q) - Get units as string
13288    define(interp, "qty_units", Some(1), |_, args| {
13289        let (_, units) = extract_quantity(&args[0], "qty_units")?;
13290        Ok(Value::String(Rc::new(units_to_string(units))))
13291    });
13292
13293    // qty_convert(q, target_units) - Convert to different units
13294    // Currently just validates compatible dimensions
13295    define(interp, "qty_convert", Some(2), |_, args| {
13296        let (val, units) = extract_quantity(&args[0], "qty_convert")?;
13297        let _target = match &args[1] {
13298            Value::String(s) => s.to_string(),
13299            _ => return Err(RuntimeError::new("qty_convert: target must be unit string")),
13300        };
13301
13302        // For now, just return with same value if dimensions match
13303        // A full implementation would handle unit prefixes (kilo, milli, etc.)
13304        Ok(make_quantity(val, units))
13305    });
13306
13307    // qty_check(q, expected_units) - Check if quantity has expected dimensions
13308    define(interp, "qty_check", Some(2), |_, args| {
13309        let (_, units) = extract_quantity(&args[0], "qty_check")?;
13310        let expected = match &args[1] {
13311            Value::String(s) => s.to_string(),
13312            _ => return Err(RuntimeError::new("qty_check: expected string")),
13313        };
13314
13315        // Quick dimension check by comparing unit string patterns
13316        let actual_str = units_to_string(units);
13317        Ok(Value::Bool(
13318            actual_str.contains(&expected) || expected.contains(&actual_str),
13319        ))
13320    });
13321
13322    // Common physical constants with units
13323    // c - speed of light
13324    define(interp, "c_light", Some(0), |_, _| {
13325        Ok(make_quantity(299792458.0, [1, 0, -1, 0, 0, 0, 0])) // m/s
13326    });
13327
13328    // G - gravitational constant
13329    define(interp, "G_gravity", Some(0), |_, _| {
13330        Ok(make_quantity(6.67430e-11, [3, -1, -2, 0, 0, 0, 0])) // m³/(kg·s²)
13331    });
13332
13333    // h - Planck constant
13334    define(interp, "h_planck", Some(0), |_, _| {
13335        Ok(make_quantity(6.62607015e-34, [2, 1, -1, 0, 0, 0, 0])) // J·s = m²·kg/s
13336    });
13337
13338    // e - elementary charge
13339    define(interp, "e_charge", Some(0), |_, _| {
13340        Ok(make_quantity(1.602176634e-19, [0, 0, 1, 1, 0, 0, 0])) // C = A·s
13341    });
13342
13343    // k_B - Boltzmann constant
13344    define(interp, "k_boltzmann", Some(0), |_, _| {
13345        Ok(make_quantity(1.380649e-23, [2, 1, -2, 0, -1, 0, 0])) // J/K = m²·kg/(s²·K)
13346    });
13347}
13348
13349// ============================================================================
13350// ENTITY COMPONENT SYSTEM (ECS)
13351// ============================================================================
13352//
13353// A lightweight Entity Component System for game development and simulations.
13354// ECS separates data (components) from behavior (systems) for maximum flexibility.
13355//
13356// ## Core Concepts
13357//
13358// | Concept | Description |
13359// |---------|-------------|
13360// | World | Container for all entities and components |
13361// | Entity | Unique ID representing a game object |
13362// | Component | Data attached to an entity (position, velocity, health) |
13363// | Query | Retrieve entities with specific components |
13364//
13365// ## Available Functions
13366//
13367// ### World Management
13368// | Function | Description |
13369// |----------|-------------|
13370// | `ecs_world()` | Create a new ECS world |
13371// | `ecs_count(world)` | Count total entities |
13372//
13373// ### Entity Management
13374// | Function | Description |
13375// |----------|-------------|
13376// | `ecs_spawn(world)` | Create entity, returns ID |
13377// | `ecs_despawn(world, id)` | Remove entity and components |
13378// | `ecs_exists(world, id)` | Check if entity exists |
13379//
13380// ### Component Management
13381// | Function | Description |
13382// |----------|-------------|
13383// | `ecs_attach(world, id, name, data)` | Add component to entity |
13384// | `ecs_detach(world, id, name)` | Remove component |
13385// | `ecs_get(world, id, name)` | Get component data |
13386// | `ecs_has(world, id, name)` | Check if entity has component |
13387//
13388// ### Querying
13389// | Function | Description |
13390// |----------|-------------|
13391// | `ecs_query(world, ...names)` | Find entities with all listed components |
13392// | `ecs_query_any(world, ...names)` | Find entities with any listed component |
13393//
13394// ## Usage Example
13395//
13396// ```sigil
13397// // Create world and entities
13398// let world = ecs_world();
13399// let player = ecs_spawn(world);
13400// let enemy = ecs_spawn(world);
13401//
13402// // Attach components
13403// ecs_attach(world, player, "Position", vec3(0, 0, 0));
13404// ecs_attach(world, player, "Velocity", vec3(1, 0, 0));
13405// ecs_attach(world, player, "Health", 100);
13406//
13407// ecs_attach(world, enemy, "Position", vec3(10, 0, 0));
13408// ecs_attach(world, enemy, "Health", 50);
13409//
13410// // Query all entities with Position and Health
13411// let living = ecs_query(world, "Position", "Health");
13412// // Returns [player_id, enemy_id]
13413//
13414// // Update loop
13415// for id in ecs_query(world, "Position", "Velocity") {
13416//     let pos = ecs_get(world, id, "Position");
13417//     let vel = ecs_get(world, id, "Velocity");
13418//     ecs_attach(world, id, "Position", vec3_add(pos, vel));
13419// }
13420// ```
13421//
13422// ## Performance Notes
13423//
13424// - Queries are O(entities) - for large worlds, consider caching results
13425// - Component access is O(1) via hash lookup
13426// - Entity spawning is O(1)
13427
13428fn register_ecs(interp: &mut Interpreter) {
13429    // ecs_world() - Create new ECS world
13430    define(interp, "ecs_world", Some(0), |_, _| {
13431        let mut world = HashMap::new();
13432        world.insert(
13433            "_type".to_string(),
13434            Value::String(Rc::new("ecs_world".to_string())),
13435        );
13436        world.insert("next_id".to_string(), Value::Int(0));
13437        world.insert(
13438            "entities".to_string(),
13439            Value::Map(Rc::new(RefCell::new(HashMap::new()))),
13440        );
13441        world.insert(
13442            "components".to_string(),
13443            Value::Map(Rc::new(RefCell::new(HashMap::new()))),
13444        );
13445        Ok(Value::Map(Rc::new(RefCell::new(world))))
13446    });
13447
13448    // ecs_spawn(world) - Spawn new entity, returns entity ID
13449    define(interp, "ecs_spawn", Some(1), |_, args| {
13450        let world = match &args[0] {
13451            Value::Map(m) => m.clone(),
13452            _ => return Err(RuntimeError::new("ecs_spawn: expected world")),
13453        };
13454
13455        let mut world_ref = world.borrow_mut();
13456        let id = match world_ref.get("next_id") {
13457            Some(Value::Int(n)) => *n,
13458            _ => 0,
13459        };
13460
13461        // Increment next_id
13462        world_ref.insert("next_id".to_string(), Value::Int(id + 1));
13463
13464        // Add to entities set
13465        if let Some(Value::Map(entities)) = world_ref.get("entities") {
13466            entities
13467                .borrow_mut()
13468                .insert(id.to_string(), Value::Bool(true));
13469        }
13470
13471        Ok(Value::Int(id))
13472    });
13473
13474    // ecs_despawn(world, entity_id) - Remove entity and all its components
13475    define(interp, "ecs_despawn", Some(2), |_, args| {
13476        let world = match &args[0] {
13477            Value::Map(m) => m.clone(),
13478            _ => return Err(RuntimeError::new("ecs_despawn: expected world")),
13479        };
13480        let id = match &args[1] {
13481            Value::Int(n) => *n,
13482            _ => return Err(RuntimeError::new("ecs_despawn: expected entity id")),
13483        };
13484
13485        let world_ref = world.borrow();
13486
13487        // Remove from entities
13488        if let Some(Value::Map(entities)) = world_ref.get("entities") {
13489            entities.borrow_mut().remove(&id.to_string());
13490        }
13491
13492        // Remove all components for this entity
13493        if let Some(Value::Map(components)) = world_ref.get("components") {
13494            let comps = components.borrow();
13495            for (_, comp_storage) in comps.iter() {
13496                if let Value::Map(storage) = comp_storage {
13497                    storage.borrow_mut().remove(&id.to_string());
13498                }
13499            }
13500        }
13501
13502        Ok(Value::Bool(true))
13503    });
13504
13505    // ecs_attach(world, entity_id, component_name, data) - Add component to entity
13506    define(interp, "ecs_attach", Some(4), |_, args| {
13507        let world = match &args[0] {
13508            Value::Map(m) => m.clone(),
13509            _ => {
13510                return Err(RuntimeError::new(
13511                    "ecs_attach() expects a world as first argument.\n\
13512                 Usage: ecs_attach(world, entity_id, component_name, data)\n\
13513                 Example:\n\
13514                   let world = ecs_world();\n\
13515                   let e = ecs_spawn(world);\n\
13516                   ecs_attach(world, e, \"Position\", vec3(0, 0, 0));",
13517                ))
13518            }
13519        };
13520        let id = match &args[1] {
13521            Value::Int(n) => *n,
13522            _ => {
13523                return Err(RuntimeError::new(
13524                    "ecs_attach() expects an entity ID (integer) as second argument.\n\
13525                 Entity IDs are returned by ecs_spawn().\n\
13526                 Example:\n\
13527                   let entity = ecs_spawn(world);  // Returns 0, 1, 2...\n\
13528                   ecs_attach(world, entity, \"Health\", 100);",
13529                ))
13530            }
13531        };
13532        let comp_name = match &args[2] {
13533            Value::String(s) => s.to_string(),
13534            _ => {
13535                return Err(RuntimeError::new(
13536                    "ecs_attach() expects a string component name as third argument.\n\
13537                 Common component names: \"Position\", \"Velocity\", \"Health\", \"Sprite\"\n\
13538                 Example: ecs_attach(world, entity, \"Position\", vec3(0, 0, 0));",
13539                ))
13540            }
13541        };
13542        let data = args[3].clone();
13543
13544        let world_ref = world.borrow();
13545
13546        // Get or create component storage
13547        if let Some(Value::Map(components)) = world_ref.get("components") {
13548            let mut comps = components.borrow_mut();
13549
13550            let storage = comps
13551                .entry(comp_name.clone())
13552                .or_insert_with(|| Value::Map(Rc::new(RefCell::new(HashMap::new()))));
13553
13554            if let Value::Map(storage_map) = storage {
13555                storage_map.borrow_mut().insert(id.to_string(), data);
13556            }
13557        }
13558
13559        Ok(Value::Bool(true))
13560    });
13561
13562    // ecs_get(world, entity_id, component_name) - Get component data
13563    define(interp, "ecs_get", Some(3), |_, args| {
13564        let world = match &args[0] {
13565            Value::Map(m) => m.clone(),
13566            _ => return Err(RuntimeError::new("ecs_get: expected world")),
13567        };
13568        let id = match &args[1] {
13569            Value::Int(n) => *n,
13570            _ => return Err(RuntimeError::new("ecs_get: expected entity id")),
13571        };
13572        let comp_name = match &args[2] {
13573            Value::String(s) => s.to_string(),
13574            _ => return Err(RuntimeError::new("ecs_get: expected component name")),
13575        };
13576
13577        let world_ref = world.borrow();
13578
13579        if let Some(Value::Map(components)) = world_ref.get("components") {
13580            let comps = components.borrow();
13581            if let Some(Value::Map(storage)) = comps.get(&comp_name) {
13582                if let Some(data) = storage.borrow().get(&id.to_string()) {
13583                    return Ok(data.clone());
13584                }
13585            }
13586        }
13587
13588        Ok(Value::Null)
13589    });
13590
13591    // ecs_has(world, entity_id, component_name) - Check if entity has component
13592    define(interp, "ecs_has", Some(3), |_, args| {
13593        let world = match &args[0] {
13594            Value::Map(m) => m.clone(),
13595            _ => return Err(RuntimeError::new("ecs_has: expected world")),
13596        };
13597        let id = match &args[1] {
13598            Value::Int(n) => *n,
13599            _ => return Err(RuntimeError::new("ecs_has: expected entity id")),
13600        };
13601        let comp_name = match &args[2] {
13602            Value::String(s) => s.to_string(),
13603            _ => return Err(RuntimeError::new("ecs_has: expected component name")),
13604        };
13605
13606        let world_ref = world.borrow();
13607
13608        if let Some(Value::Map(components)) = world_ref.get("components") {
13609            let comps = components.borrow();
13610            if let Some(Value::Map(storage)) = comps.get(&comp_name) {
13611                return Ok(Value::Bool(storage.borrow().contains_key(&id.to_string())));
13612            }
13613        }
13614
13615        Ok(Value::Bool(false))
13616    });
13617
13618    // ecs_remove(world, entity_id, component_name) - Remove component from entity
13619    define(interp, "ecs_remove", Some(3), |_, args| {
13620        let world = match &args[0] {
13621            Value::Map(m) => m.clone(),
13622            _ => return Err(RuntimeError::new("ecs_remove: expected world")),
13623        };
13624        let id = match &args[1] {
13625            Value::Int(n) => *n,
13626            _ => return Err(RuntimeError::new("ecs_remove: expected entity id")),
13627        };
13628        let comp_name = match &args[2] {
13629            Value::String(s) => s.to_string(),
13630            _ => return Err(RuntimeError::new("ecs_remove: expected component name")),
13631        };
13632
13633        let world_ref = world.borrow();
13634
13635        if let Some(Value::Map(components)) = world_ref.get("components") {
13636            let comps = components.borrow();
13637            if let Some(Value::Map(storage)) = comps.get(&comp_name) {
13638                storage.borrow_mut().remove(&id.to_string());
13639                return Ok(Value::Bool(true));
13640            }
13641        }
13642
13643        Ok(Value::Bool(false))
13644    });
13645
13646    // ecs_query(world, component_names...) - Get all entities with all specified components
13647    // Returns array of entity IDs
13648    define(interp, "ecs_query", None, |_, args| {
13649        if args.is_empty() {
13650            return Err(RuntimeError::new(
13651                "ecs_query: expected at least world argument",
13652            ));
13653        }
13654
13655        let world = match &args[0] {
13656            Value::Map(m) => m.clone(),
13657            _ => return Err(RuntimeError::new("ecs_query: expected world")),
13658        };
13659
13660        let comp_names: Vec<String> = args[1..]
13661            .iter()
13662            .filter_map(|a| match a {
13663                Value::String(s) => Some(s.to_string()),
13664                _ => None,
13665            })
13666            .collect();
13667
13668        if comp_names.is_empty() {
13669            // Return all entities
13670            let world_ref = world.borrow();
13671            if let Some(Value::Map(entities)) = world_ref.get("entities") {
13672                let result: Vec<Value> = entities
13673                    .borrow()
13674                    .keys()
13675                    .filter_map(|k| k.parse::<i64>().ok().map(Value::Int))
13676                    .collect();
13677                return Ok(Value::Array(Rc::new(RefCell::new(result))));
13678            }
13679            return Ok(Value::Array(Rc::new(RefCell::new(vec![]))));
13680        }
13681
13682        let world_ref = world.borrow();
13683        let mut result_ids: Option<Vec<String>> = None;
13684
13685        if let Some(Value::Map(components)) = world_ref.get("components") {
13686            let comps = components.borrow();
13687
13688            for comp_name in &comp_names {
13689                if let Some(Value::Map(storage)) = comps.get(comp_name) {
13690                    let keys: Vec<String> = storage.borrow().keys().cloned().collect();
13691
13692                    result_ids = Some(match result_ids {
13693                        None => keys,
13694                        Some(existing) => {
13695                            existing.into_iter().filter(|k| keys.contains(k)).collect()
13696                        }
13697                    });
13698                } else {
13699                    // Component type doesn't exist, no entities match
13700                    return Ok(Value::Array(Rc::new(RefCell::new(vec![]))));
13701                }
13702            }
13703        }
13704
13705        let result: Vec<Value> = result_ids
13706            .unwrap_or_default()
13707            .iter()
13708            .filter_map(|k| k.parse::<i64>().ok().map(Value::Int))
13709            .collect();
13710
13711        Ok(Value::Array(Rc::new(RefCell::new(result))))
13712    });
13713
13714    // ecs_query_with(world, component_names, callback) - Iterate over matching entities
13715    // Callback receives (entity_id, components_map)
13716    define(interp, "ecs_query_with", Some(3), |interp, args| {
13717        let world = match &args[0] {
13718            Value::Map(m) => m.clone(),
13719            _ => return Err(RuntimeError::new("ecs_query_with: expected world")),
13720        };
13721        let comp_names: Vec<String> = match &args[1] {
13722            Value::Array(arr) => arr
13723                .borrow()
13724                .iter()
13725                .filter_map(|v| match v {
13726                    Value::String(s) => Some(s.to_string()),
13727                    _ => None,
13728                })
13729                .collect(),
13730            _ => {
13731                return Err(RuntimeError::new(
13732                    "ecs_query_with: expected array of component names",
13733                ))
13734            }
13735        };
13736        let callback = match &args[2] {
13737            Value::Function(f) => f.clone(),
13738            _ => {
13739                return Err(RuntimeError::new(
13740                    "ecs_query_with: expected callback function",
13741                ))
13742            }
13743        };
13744
13745        // Pre-collect all data to avoid borrow issues during callbacks
13746        let mut callback_data: Vec<(i64, HashMap<String, Value>)> = Vec::new();
13747
13748        {
13749            let world_ref = world.borrow();
13750            let mut result_ids: Option<Vec<String>> = None;
13751
13752            if let Some(Value::Map(components)) = world_ref.get("components") {
13753                let comps = components.borrow();
13754
13755                for comp_name in &comp_names {
13756                    if let Some(Value::Map(storage)) = comps.get(comp_name) {
13757                        let keys: Vec<String> = storage.borrow().keys().cloned().collect();
13758                        result_ids = Some(match result_ids {
13759                            None => keys,
13760                            Some(existing) => {
13761                                existing.into_iter().filter(|k| keys.contains(k)).collect()
13762                            }
13763                        });
13764                    } else {
13765                        result_ids = Some(vec![]);
13766                        break;
13767                    }
13768                }
13769
13770                // Collect data for each matching entity
13771                for id_str in result_ids.unwrap_or_default() {
13772                    if let Ok(id) = id_str.parse::<i64>() {
13773                        let mut entity_comps = HashMap::new();
13774                        for comp_name in &comp_names {
13775                            if let Some(Value::Map(storage)) = comps.get(comp_name) {
13776                                if let Some(data) = storage.borrow().get(&id_str) {
13777                                    entity_comps.insert(comp_name.clone(), data.clone());
13778                                }
13779                            }
13780                        }
13781                        callback_data.push((id, entity_comps));
13782                    }
13783                }
13784            }
13785        } // Release borrows here
13786
13787        // Now call callbacks without holding borrows
13788        for (id, entity_comps) in callback_data {
13789            let callback_args = vec![
13790                Value::Int(id),
13791                Value::Map(Rc::new(RefCell::new(entity_comps))),
13792            ];
13793            interp.call_function(&callback, callback_args)?;
13794        }
13795
13796        Ok(Value::Null)
13797    });
13798
13799    // ecs_count(world) - Count total entities
13800    define(interp, "ecs_count", Some(1), |_, args| {
13801        let world = match &args[0] {
13802            Value::Map(m) => m.clone(),
13803            _ => return Err(RuntimeError::new("ecs_count: expected world")),
13804        };
13805
13806        let world_ref = world.borrow();
13807        if let Some(Value::Map(entities)) = world_ref.get("entities") {
13808            return Ok(Value::Int(entities.borrow().len() as i64));
13809        }
13810
13811        Ok(Value::Int(0))
13812    });
13813
13814    // ecs_alive(world, entity_id) - Check if entity is alive
13815    define(interp, "ecs_alive", Some(2), |_, args| {
13816        let world = match &args[0] {
13817            Value::Map(m) => m.clone(),
13818            _ => return Err(RuntimeError::new("ecs_alive: expected world")),
13819        };
13820        let id = match &args[1] {
13821            Value::Int(n) => *n,
13822            _ => return Err(RuntimeError::new("ecs_alive: expected entity id")),
13823        };
13824
13825        let world_ref = world.borrow();
13826        if let Some(Value::Map(entities)) = world_ref.get("entities") {
13827            return Ok(Value::Bool(entities.borrow().contains_key(&id.to_string())));
13828        }
13829
13830        Ok(Value::Bool(false))
13831    });
13832}
13833
13834// ============================================================================
13835// POLYCULTURAL TEXT PROCESSING
13836// ============================================================================
13837//
13838// Sigil's philosophy: Mathematics is poly-cultural, and so is TEXT.
13839// Different writing systems have different needs:
13840//
13841// | Writing System | Special Needs |
13842// |----------------|---------------|
13843// | Latin          | Diacritics, ligatures, case folding |
13844// | Arabic/Hebrew  | RTL, contextual shaping, vowel marks |
13845// | CJK            | No word boundaries, display width, ruby text |
13846// | Devanagari     | Complex clusters, conjuncts |
13847// | Thai           | No spaces between words |
13848// | Hangul         | Jamo composition/decomposition |
13849//
13850// This module provides world-class text handling for ALL scripts.
13851//
13852
13853fn register_polycultural_text(interp: &mut Interpreter) {
13854    // =========================================================================
13855    // SCRIPT DETECTION
13856    // =========================================================================
13857    //
13858    // Detect what writing system(s) a text uses.
13859    // Essential for choosing appropriate processing strategies.
13860    //
13861
13862    // script - get the dominant script of a string
13863    define(interp, "script", Some(1), |_, args| {
13864        match &args[0] {
13865            Value::String(s) => {
13866                // Count scripts
13867                let mut script_counts: HashMap<String, usize> = HashMap::new();
13868                for c in s.chars() {
13869                    if !c.is_whitespace() && !c.is_ascii_punctuation() {
13870                        let script = c.script();
13871                        let name = format!("{:?}", script);
13872                        *script_counts.entry(name).or_insert(0) += 1;
13873                    }
13874                }
13875                // Find dominant script
13876                let dominant = script_counts
13877                    .into_iter()
13878                    .max_by_key(|(_, count)| *count)
13879                    .map(|(name, _)| name)
13880                    .unwrap_or_else(|| "Unknown".to_string());
13881                Ok(Value::String(Rc::new(dominant)))
13882            }
13883            _ => Err(RuntimeError::new("script() requires string")),
13884        }
13885    });
13886
13887    // scripts - get all scripts present in text
13888    define(interp, "scripts", Some(1), |_, args| match &args[0] {
13889        Value::String(s) => {
13890            let mut scripts: Vec<String> = s
13891                .chars()
13892                .filter(|c| !c.is_whitespace() && !c.is_ascii_punctuation())
13893                .map(|c| format!("{:?}", c.script()))
13894                .collect();
13895            scripts.sort();
13896            scripts.dedup();
13897            let values: Vec<Value> = scripts
13898                .into_iter()
13899                .map(|s| Value::String(Rc::new(s)))
13900                .collect();
13901            Ok(Value::Array(Rc::new(RefCell::new(values))))
13902        }
13903        _ => Err(RuntimeError::new("scripts() requires string")),
13904    });
13905
13906    // is_script - check if text is primarily in a specific script
13907    define(interp, "is_script", Some(2), |_, args| {
13908        match (&args[0], &args[1]) {
13909            (Value::String(s), Value::String(script_name)) => {
13910                let target = script_name.to_lowercase();
13911                let mut matching = 0usize;
13912                let mut total = 0usize;
13913                for c in s.chars() {
13914                    if !c.is_whitespace() && !c.is_ascii_punctuation() {
13915                        total += 1;
13916                        let script_str = format!("{:?}", c.script()).to_lowercase();
13917                        if script_str == target {
13918                            matching += 1;
13919                        }
13920                    }
13921                }
13922                let ratio = if total > 0 {
13923                    matching as f64 / total as f64
13924                } else {
13925                    0.0
13926                };
13927                Ok(Value::Bool(ratio > 0.5))
13928            }
13929            _ => Err(RuntimeError::new(
13930                "is_script() requires string and script name",
13931            )),
13932        }
13933    });
13934
13935    // Script-specific detection functions
13936    define(interp, "is_latin", Some(1), |_, args| match &args[0] {
13937        Value::String(s) => {
13938            let is_latin = s
13939                .chars()
13940                .filter(|c| !c.is_whitespace())
13941                .all(|c| matches!(c.script(), Script::Latin | Script::Common));
13942            Ok(Value::Bool(is_latin && !s.is_empty()))
13943        }
13944        _ => Err(RuntimeError::new("is_latin() requires string")),
13945    });
13946
13947    define(interp, "is_cjk", Some(1), |_, args| match &args[0] {
13948        Value::String(s) => {
13949            let has_cjk = s.chars().any(|c| {
13950                matches!(
13951                    c.script(),
13952                    Script::Han
13953                        | Script::Hiragana
13954                        | Script::Katakana
13955                        | Script::Hangul
13956                        | Script::Bopomofo
13957                )
13958            });
13959            Ok(Value::Bool(has_cjk))
13960        }
13961        _ => Err(RuntimeError::new("is_cjk() requires string")),
13962    });
13963
13964    define(interp, "is_arabic", Some(1), |_, args| match &args[0] {
13965        Value::String(s) => {
13966            let has_arabic = s.chars().any(|c| matches!(c.script(), Script::Arabic));
13967            Ok(Value::Bool(has_arabic))
13968        }
13969        _ => Err(RuntimeError::new("is_arabic() requires string")),
13970    });
13971
13972    define(interp, "is_hebrew", Some(1), |_, args| match &args[0] {
13973        Value::String(s) => {
13974            let has_hebrew = s.chars().any(|c| matches!(c.script(), Script::Hebrew));
13975            Ok(Value::Bool(has_hebrew))
13976        }
13977        _ => Err(RuntimeError::new("is_hebrew() requires string")),
13978    });
13979
13980    define(interp, "is_cyrillic", Some(1), |_, args| match &args[0] {
13981        Value::String(s) => {
13982            let has_cyrillic = s.chars().any(|c| matches!(c.script(), Script::Cyrillic));
13983            Ok(Value::Bool(has_cyrillic))
13984        }
13985        _ => Err(RuntimeError::new("is_cyrillic() requires string")),
13986    });
13987
13988    define(interp, "is_greek", Some(1), |_, args| match &args[0] {
13989        Value::String(s) => {
13990            let has_greek = s.chars().any(|c| matches!(c.script(), Script::Greek));
13991            Ok(Value::Bool(has_greek))
13992        }
13993        _ => Err(RuntimeError::new("is_greek() requires string")),
13994    });
13995
13996    define(interp, "is_devanagari", Some(1), |_, args| match &args[0] {
13997        Value::String(s) => {
13998            let has_devanagari = s.chars().any(|c| matches!(c.script(), Script::Devanagari));
13999            Ok(Value::Bool(has_devanagari))
14000        }
14001        _ => Err(RuntimeError::new("is_devanagari() requires string")),
14002    });
14003
14004    define(interp, "is_thai", Some(1), |_, args| match &args[0] {
14005        Value::String(s) => {
14006            let has_thai = s.chars().any(|c| matches!(c.script(), Script::Thai));
14007            Ok(Value::Bool(has_thai))
14008        }
14009        _ => Err(RuntimeError::new("is_thai() requires string")),
14010    });
14011
14012    define(interp, "is_hangul", Some(1), |_, args| match &args[0] {
14013        Value::String(s) => {
14014            let has_hangul = s.chars().any(|c| matches!(c.script(), Script::Hangul));
14015            Ok(Value::Bool(has_hangul))
14016        }
14017        _ => Err(RuntimeError::new("is_hangul() requires string")),
14018    });
14019
14020    define(interp, "is_hiragana", Some(1), |_, args| match &args[0] {
14021        Value::String(s) => {
14022            let has_hiragana = s.chars().any(|c| matches!(c.script(), Script::Hiragana));
14023            Ok(Value::Bool(has_hiragana))
14024        }
14025        _ => Err(RuntimeError::new("is_hiragana() requires string")),
14026    });
14027
14028    define(interp, "is_katakana", Some(1), |_, args| match &args[0] {
14029        Value::String(s) => {
14030            let has_katakana = s.chars().any(|c| matches!(c.script(), Script::Katakana));
14031            Ok(Value::Bool(has_katakana))
14032        }
14033        _ => Err(RuntimeError::new("is_katakana() requires string")),
14034    });
14035
14036    // char_script - get script of a single character
14037    define(interp, "char_script", Some(1), |_, args| match &args[0] {
14038        Value::Char(c) => {
14039            let script = format!("{:?}", c.script());
14040            Ok(Value::String(Rc::new(script)))
14041        }
14042        Value::String(s) if s.chars().count() == 1 => {
14043            let c = s.chars().next().unwrap();
14044            let script = format!("{:?}", c.script());
14045            Ok(Value::String(Rc::new(script)))
14046        }
14047        _ => Err(RuntimeError::new("char_script() requires single character")),
14048    });
14049
14050    // =========================================================================
14051    // BIDIRECTIONAL TEXT (RTL/LTR)
14052    // =========================================================================
14053    //
14054    // Arabic, Hebrew, and other scripts are written right-to-left.
14055    // Mixed text (e.g., Arabic with English) needs bidirectional handling.
14056    //
14057
14058    // text_direction - get overall text direction
14059    define(interp, "text_direction", Some(1), |_, args| {
14060        match &args[0] {
14061            Value::String(s) => {
14062                let bidi_info = BidiInfo::new(s, None);
14063                // Check if any paragraph is RTL
14064                let has_rtl = bidi_info.paragraphs.iter().any(|p| p.level.is_rtl());
14065                let direction = if has_rtl { "rtl" } else { "ltr" };
14066                Ok(Value::String(Rc::new(direction.to_string())))
14067            }
14068            _ => Err(RuntimeError::new("text_direction() requires string")),
14069        }
14070    });
14071
14072    // is_rtl - check if text is right-to-left
14073    define(interp, "is_rtl", Some(1), |_, args| match &args[0] {
14074        Value::String(s) => {
14075            let bidi_info = BidiInfo::new(s, None);
14076            let has_rtl = bidi_info.paragraphs.iter().any(|p| p.level.is_rtl());
14077            Ok(Value::Bool(has_rtl))
14078        }
14079        _ => Err(RuntimeError::new("is_rtl() requires string")),
14080    });
14081
14082    // is_ltr - check if text is left-to-right
14083    define(interp, "is_ltr", Some(1), |_, args| match &args[0] {
14084        Value::String(s) => {
14085            let bidi_info = BidiInfo::new(s, None);
14086            let is_ltr = bidi_info.paragraphs.iter().all(|p| !p.level.is_rtl());
14087            Ok(Value::Bool(is_ltr))
14088        }
14089        _ => Err(RuntimeError::new("is_ltr() requires string")),
14090    });
14091
14092    // is_bidi - check if text contains mixed directions
14093    define(interp, "is_bidi", Some(1), |_, args| {
14094        match &args[0] {
14095            Value::String(s) => {
14096                // Check for both RTL and LTR characters
14097                let has_rtl = s.chars().any(|c| {
14098                    matches!(
14099                        c.script(),
14100                        Script::Arabic | Script::Hebrew | Script::Syriac | Script::Thaana
14101                    )
14102                });
14103                let has_ltr = s.chars().any(|c| {
14104                    matches!(c.script(), Script::Latin | Script::Greek | Script::Cyrillic)
14105                });
14106                Ok(Value::Bool(has_rtl && has_ltr))
14107            }
14108            _ => Err(RuntimeError::new("is_bidi() requires string")),
14109        }
14110    });
14111
14112    // bidi_reorder - reorder text for visual display
14113    define(interp, "bidi_reorder", Some(1), |_, args| match &args[0] {
14114        Value::String(s) => {
14115            let bidi_info = BidiInfo::new(s, None);
14116            let mut result = String::new();
14117            for para in &bidi_info.paragraphs {
14118                let line = para.range.clone();
14119                let reordered = bidi_info.reorder_line(para, line);
14120                result.push_str(&reordered);
14121            }
14122            Ok(Value::String(Rc::new(result)))
14123        }
14124        _ => Err(RuntimeError::new("bidi_reorder() requires string")),
14125    });
14126
14127    // =========================================================================
14128    // DISPLAY WIDTH (CJK-aware)
14129    // =========================================================================
14130    //
14131    // CJK characters are "full-width" (2 columns), while Latin is "half-width".
14132    // Critical for proper terminal output and text alignment.
14133    //
14134
14135    // display_width - get visual width in terminal columns
14136    define(interp, "display_width", Some(1), |_, args| match &args[0] {
14137        Value::String(s) => {
14138            let width = UnicodeWidthStr::width(s.as_str());
14139            Ok(Value::Int(width as i64))
14140        }
14141        _ => Err(RuntimeError::new("display_width() requires string")),
14142    });
14143
14144    // is_fullwidth - check if string contains full-width characters
14145    define(interp, "is_fullwidth", Some(1), |_, args| {
14146        match &args[0] {
14147            Value::String(s) => {
14148                let char_count = s.chars().count();
14149                let display_width = UnicodeWidthStr::width(s.as_str());
14150                // If display width > char count, we have full-width chars
14151                Ok(Value::Bool(display_width > char_count))
14152            }
14153            _ => Err(RuntimeError::new("is_fullwidth() requires string")),
14154        }
14155    });
14156
14157    // pad_display - pad string to display width (CJK-aware)
14158    define(interp, "pad_display", Some(3), |_, args| {
14159        match (&args[0], &args[1], &args[2]) {
14160            (Value::String(s), Value::Int(target_width), Value::String(align)) => {
14161                let current_width = UnicodeWidthStr::width(s.as_str());
14162                let target = *target_width as usize;
14163                if current_width >= target {
14164                    return Ok(Value::String(s.clone()));
14165                }
14166                let padding = target - current_width;
14167                let result = match align.as_str() {
14168                    "left" => format!("{}{}", s, " ".repeat(padding)),
14169                    "right" => format!("{}{}", " ".repeat(padding), s),
14170                    "center" => {
14171                        let left = padding / 2;
14172                        let right = padding - left;
14173                        format!("{}{}{}", " ".repeat(left), s, " ".repeat(right))
14174                    }
14175                    _ => {
14176                        return Err(RuntimeError::new(
14177                            "pad_display: align must be 'left', 'right', or 'center'",
14178                        ))
14179                    }
14180                };
14181                Ok(Value::String(Rc::new(result)))
14182            }
14183            _ => Err(RuntimeError::new(
14184                "pad_display() requires string, width, and alignment",
14185            )),
14186        }
14187    });
14188
14189    // =========================================================================
14190    // TRANSLITERATION
14191    // =========================================================================
14192    //
14193    // Convert text from any script to ASCII representation.
14194    // Essential for: search, URLs, usernames, file names.
14195    //
14196
14197    // transliterate - convert any Unicode text to ASCII
14198    define(interp, "transliterate", Some(1), |_, args| match &args[0] {
14199        Value::String(s) => {
14200            let ascii = deunicode(s);
14201            Ok(Value::String(Rc::new(ascii)))
14202        }
14203        _ => Err(RuntimeError::new("transliterate() requires string")),
14204    });
14205
14206    // to_ascii - alias for transliterate
14207    define(interp, "to_ascii", Some(1), |_, args| match &args[0] {
14208        Value::String(s) => {
14209            let ascii = deunicode(s);
14210            Ok(Value::String(Rc::new(ascii)))
14211        }
14212        _ => Err(RuntimeError::new("to_ascii() requires string")),
14213    });
14214
14215    // slugify - create URL-safe slug from any text
14216    define(interp, "slugify", Some(1), |_, args| {
14217        match &args[0] {
14218            Value::String(s) => {
14219                let ascii = deunicode(s);
14220                let slug: String = ascii
14221                    .to_lowercase()
14222                    .chars()
14223                    .map(|c| if c.is_alphanumeric() { c } else { '-' })
14224                    .collect();
14225                // Collapse multiple dashes and trim
14226                let mut result = String::new();
14227                let mut last_was_dash = true; // Start true to trim leading dashes
14228                for c in slug.chars() {
14229                    if c == '-' {
14230                        if !last_was_dash {
14231                            result.push(c);
14232                            last_was_dash = true;
14233                        }
14234                    } else {
14235                        result.push(c);
14236                        last_was_dash = false;
14237                    }
14238                }
14239                // Trim trailing dash
14240                if result.ends_with('-') {
14241                    result.pop();
14242                }
14243                Ok(Value::String(Rc::new(result)))
14244            }
14245            _ => Err(RuntimeError::new("slugify() requires string")),
14246        }
14247    });
14248
14249    // =========================================================================
14250    // DIACRITICS AND ACCENTS
14251    // =========================================================================
14252    //
14253    // Many scripts use combining marks: é = e + ́ (combining acute)
14254    // Need to handle decomposition, stripping, and normalization.
14255    //
14256
14257    // strip_diacritics - remove accents and combining marks
14258    define(interp, "strip_diacritics", Some(1), |_, args| {
14259        match &args[0] {
14260            Value::String(s) => {
14261                // NFD decomposition separates base chars from combining marks
14262                let decomposed: String = s.nfd().collect();
14263                // Filter out combining marks (category Mn, Mc, Me)
14264                let stripped: String = decomposed
14265                    .chars()
14266                    .filter(|c| {
14267                        // Keep if not a combining mark
14268                        // Combining marks are in Unicode categories Mn, Mc, Me
14269                        // which are roughly in ranges U+0300-U+036F (common) and others
14270                        let code = *c as u32;
14271                        // Quick check for common combining diacritical marks
14272                        !(0x0300..=0x036F).contains(&code)
14273                            && !(0x1AB0..=0x1AFF).contains(&code)
14274                            && !(0x1DC0..=0x1DFF).contains(&code)
14275                            && !(0x20D0..=0x20FF).contains(&code)
14276                            && !(0xFE20..=0xFE2F).contains(&code)
14277                    })
14278                    .collect();
14279                Ok(Value::String(Rc::new(stripped)))
14280            }
14281            _ => Err(RuntimeError::new("strip_diacritics() requires string")),
14282        }
14283    });
14284
14285    // has_diacritics - check if string contains diacritical marks
14286    define(interp, "has_diacritics", Some(1), |_, args| {
14287        match &args[0] {
14288            Value::String(s) => {
14289                let decomposed: String = s.nfd().collect();
14290                let has_marks = decomposed.chars().any(|c| {
14291                    let code = c as u32;
14292                    (0x0300..=0x036F).contains(&code)
14293                        || (0x1AB0..=0x1AFF).contains(&code)
14294                        || (0x1DC0..=0x1DFF).contains(&code)
14295                        || (0x20D0..=0x20FF).contains(&code)
14296                        || (0xFE20..=0xFE2F).contains(&code)
14297                });
14298                Ok(Value::Bool(has_marks))
14299            }
14300            _ => Err(RuntimeError::new("has_diacritics() requires string")),
14301        }
14302    });
14303
14304    // normalize_accents - convert composed to decomposed or vice versa
14305    define(interp, "normalize_accents", Some(2), |_, args| {
14306        match (&args[0], &args[1]) {
14307            (Value::String(s), Value::String(form)) => {
14308                let result = match form.as_str() {
14309                    "composed" | "nfc" => s.nfc().collect(),
14310                    "decomposed" | "nfd" => s.nfd().collect(),
14311                    _ => {
14312                        return Err(RuntimeError::new(
14313                            "normalize_accents: form must be 'composed' or 'decomposed'",
14314                        ))
14315                    }
14316                };
14317                Ok(Value::String(Rc::new(result)))
14318            }
14319            _ => Err(RuntimeError::new(
14320                "normalize_accents() requires string and form",
14321            )),
14322        }
14323    });
14324
14325    // =========================================================================
14326    // LOCALE-AWARE CASE MAPPING
14327    // =========================================================================
14328    //
14329    // Case mapping varies by locale:
14330    // - Turkish: i ↔ İ, ı ↔ I (dotted/dotless distinction)
14331    // - German: ß → SS (uppercase), but SS → ss or ß (lowercase)
14332    // - Greek: final sigma rules
14333    //
14334
14335    // upper_locale - locale-aware uppercase
14336    define(interp, "upper_locale", Some(2), |_, args| {
14337        match (&args[0], &args[1]) {
14338            (Value::String(s), Value::String(locale_str)) => {
14339                let case_mapper = CaseMapper::new();
14340                let langid: LanguageIdentifier =
14341                    locale_str.parse().unwrap_or_else(|_| "en".parse().unwrap());
14342                let result = case_mapper.uppercase_to_string(s, &langid);
14343                Ok(Value::String(Rc::new(result)))
14344            }
14345            _ => Err(RuntimeError::new(
14346                "upper_locale() requires string and locale",
14347            )),
14348        }
14349    });
14350
14351    // lower_locale - locale-aware lowercase
14352    define(interp, "lower_locale", Some(2), |_, args| {
14353        match (&args[0], &args[1]) {
14354            (Value::String(s), Value::String(locale_str)) => {
14355                let case_mapper = CaseMapper::new();
14356                let langid: LanguageIdentifier =
14357                    locale_str.parse().unwrap_or_else(|_| "en".parse().unwrap());
14358                let result = case_mapper.lowercase_to_string(s, &langid);
14359                Ok(Value::String(Rc::new(result)))
14360            }
14361            _ => Err(RuntimeError::new(
14362                "lower_locale() requires string and locale",
14363            )),
14364        }
14365    });
14366
14367    // titlecase_locale - locale-aware titlecase
14368    define(interp, "titlecase_locale", Some(2), |_, args| {
14369        match (&args[0], &args[1]) {
14370            (Value::String(s), Value::String(locale_str)) => {
14371                let case_mapper = CaseMapper::new();
14372                let langid: LanguageIdentifier =
14373                    locale_str.parse().unwrap_or_else(|_| "en".parse().unwrap());
14374                let options = TitlecaseOptions::default();
14375                let result = case_mapper
14376                    .titlecase_segment_with_only_case_data_to_string(s, &langid, options);
14377                Ok(Value::String(Rc::new(result)))
14378            }
14379            _ => Err(RuntimeError::new(
14380                "titlecase_locale() requires string and locale",
14381            )),
14382        }
14383    });
14384
14385    // case_fold - Unicode case folding for comparison
14386    define(interp, "case_fold", Some(1), |_, args| match &args[0] {
14387        Value::String(s) => {
14388            let case_mapper = CaseMapper::new();
14389            let result = case_mapper.fold_string(s);
14390            Ok(Value::String(Rc::new(result)))
14391        }
14392        _ => Err(RuntimeError::new("case_fold() requires string")),
14393    });
14394
14395    // case_insensitive_eq - compare strings ignoring case (using case folding)
14396    define(interp, "case_insensitive_eq", Some(2), |_, args| {
14397        match (&args[0], &args[1]) {
14398            (Value::String(a), Value::String(b)) => {
14399                let case_mapper = CaseMapper::new();
14400                let folded_a = case_mapper.fold_string(a);
14401                let folded_b = case_mapper.fold_string(b);
14402                Ok(Value::Bool(folded_a == folded_b))
14403            }
14404            _ => Err(RuntimeError::new(
14405                "case_insensitive_eq() requires two strings",
14406            )),
14407        }
14408    });
14409
14410    // =========================================================================
14411    // LOCALE-AWARE COLLATION (SORTING)
14412    // =========================================================================
14413    //
14414    // Sorting order varies dramatically by locale:
14415    // - German: ä sorts with a
14416    // - Swedish: ä sorts after z
14417    // - Spanish: ñ is a separate letter after n
14418    //
14419
14420    // compare_locale - locale-aware string comparison
14421    define(interp, "compare_locale", Some(3), |_, args| {
14422        match (&args[0], &args[1], &args[2]) {
14423            (Value::String(a), Value::String(b), Value::String(locale_str)) => {
14424                let locale: Locale = locale_str.parse().unwrap_or_else(|_| "en".parse().unwrap());
14425                let options = CollatorOptions::new();
14426                let collator = Collator::try_new(&locale.into(), options)
14427                    .unwrap_or_else(|_| Collator::try_new(&Default::default(), options).unwrap());
14428                let result = match collator.compare(a, b) {
14429                    std::cmp::Ordering::Less => -1,
14430                    std::cmp::Ordering::Equal => 0,
14431                    std::cmp::Ordering::Greater => 1,
14432                };
14433                Ok(Value::Int(result))
14434            }
14435            _ => Err(RuntimeError::new(
14436                "compare_locale() requires two strings and locale",
14437            )),
14438        }
14439    });
14440
14441    // sort_locale - sort array of strings by locale
14442    define(interp, "sort_locale", Some(2), |_, args| {
14443        match (&args[0], &args[1]) {
14444            (Value::Array(arr), Value::String(locale_str)) => {
14445                let locale: Locale = locale_str.parse().unwrap_or_else(|_| "en".parse().unwrap());
14446                let options = CollatorOptions::new();
14447                let collator = Collator::try_new(&locale.into(), options)
14448                    .unwrap_or_else(|_| Collator::try_new(&Default::default(), options).unwrap());
14449
14450                let mut items: Vec<(String, Value)> = arr
14451                    .borrow()
14452                    .iter()
14453                    .map(|v| {
14454                        let s = match v {
14455                            Value::String(s) => (**s).clone(),
14456                            _ => format!("{}", v),
14457                        };
14458                        (s, v.clone())
14459                    })
14460                    .collect();
14461
14462                items.sort_by(|(a, _), (b, _)| collator.compare(a, b));
14463
14464                let sorted: Vec<Value> = items.into_iter().map(|(_, v)| v).collect();
14465                Ok(Value::Array(Rc::new(RefCell::new(sorted))))
14466            }
14467            _ => Err(RuntimeError::new("sort_locale() requires array and locale")),
14468        }
14469    });
14470
14471    // =========================================================================
14472    // ADVANCED SEGMENTATION
14473    // =========================================================================
14474    //
14475    // Different languages have different boundary rules:
14476    // - Thai/Lao/Khmer: No spaces between words
14477    // - CJK: Characters can be words themselves
14478    // - German: Compound words are single words
14479    //
14480
14481    // sentences - split text into sentences (locale-aware)
14482    define(interp, "sentences", Some(1), |_, args| match &args[0] {
14483        Value::String(s) => {
14484            let segmenter = SentenceSegmenter::new();
14485            let breakpoints: Vec<usize> = segmenter.segment_str(s).collect();
14486            let mut sentences = Vec::new();
14487            let mut start = 0;
14488            for end in breakpoints {
14489                let sentence = s[start..end].trim();
14490                if !sentence.is_empty() {
14491                    sentences.push(Value::String(Rc::new(sentence.to_string())));
14492                }
14493                start = end;
14494            }
14495            Ok(Value::Array(Rc::new(RefCell::new(sentences))))
14496        }
14497        _ => Err(RuntimeError::new("sentences() requires string")),
14498    });
14499
14500    // sentence_count - count sentences
14501    define(interp, "sentence_count", Some(1), |_, args| {
14502        match &args[0] {
14503            Value::String(s) => {
14504                let segmenter = SentenceSegmenter::new();
14505                let breakpoints: Vec<usize> = segmenter.segment_str(s).collect();
14506                // Sentences are between breakpoints
14507                let count = breakpoints.len().saturating_sub(1);
14508                Ok(Value::Int(count as i64))
14509            }
14510            _ => Err(RuntimeError::new("sentence_count() requires string")),
14511        }
14512    });
14513
14514    // words_icu - ICU-based word segmentation (better for CJK, Thai)
14515    define(interp, "words_icu", Some(1), |_, args| {
14516        match &args[0] {
14517            Value::String(s) => {
14518                let segmenter = WordSegmenter::new_auto();
14519                let breakpoints: Vec<usize> = segmenter.segment_str(s).collect();
14520                let mut words = Vec::new();
14521                let mut start = 0;
14522                for end in breakpoints {
14523                    let word = &s[start..end];
14524                    // Filter out whitespace-only segments
14525                    if !word.trim().is_empty() {
14526                        words.push(Value::String(Rc::new(word.to_string())));
14527                    }
14528                    start = end;
14529                }
14530                Ok(Value::Array(Rc::new(RefCell::new(words))))
14531            }
14532            _ => Err(RuntimeError::new("words_icu() requires string")),
14533        }
14534    });
14535
14536    // word_count_icu - ICU-based word count (handles Thai, CJK correctly)
14537    define(interp, "word_count_icu", Some(1), |_, args| {
14538        match &args[0] {
14539            Value::String(s) => {
14540                let segmenter = WordSegmenter::new_auto();
14541                let breakpoints: Vec<usize> = segmenter.segment_str(s).collect();
14542                let mut count = 0;
14543                let mut start = 0;
14544                for end in breakpoints {
14545                    let word = &s[start..end];
14546                    if !word.trim().is_empty() && word.chars().any(|c| c.is_alphanumeric()) {
14547                        count += 1;
14548                    }
14549                    start = end;
14550                }
14551                Ok(Value::Int(count))
14552            }
14553            _ => Err(RuntimeError::new("word_count_icu() requires string")),
14554        }
14555    });
14556
14557    // =========================================================================
14558    // SCRIPT-SPECIFIC UTILITIES
14559    // =========================================================================
14560
14561    // is_emoji - check if string contains emoji
14562    define(interp, "is_emoji", Some(1), |_, args| {
14563        match &args[0] {
14564            Value::String(s) => {
14565                let has_emoji = s.chars().any(|c| {
14566                    let code = c as u32;
14567                    // Common emoji ranges
14568                    (0x1F600..=0x1F64F).contains(&code) ||  // Emoticons
14569                    (0x1F300..=0x1F5FF).contains(&code) ||  // Misc Symbols and Pictographs
14570                    (0x1F680..=0x1F6FF).contains(&code) ||  // Transport and Map
14571                    (0x1F1E0..=0x1F1FF).contains(&code) ||  // Flags
14572                    (0x2600..=0x26FF).contains(&code) ||    // Misc symbols
14573                    (0x2700..=0x27BF).contains(&code) ||    // Dingbats
14574                    (0xFE00..=0xFE0F).contains(&code) ||    // Variation Selectors
14575                    (0x1F900..=0x1F9FF).contains(&code) ||  // Supplemental Symbols and Pictographs
14576                    (0x1FA00..=0x1FA6F).contains(&code) ||  // Chess Symbols
14577                    (0x1FA70..=0x1FAFF).contains(&code) ||  // Symbols and Pictographs Extended-A
14578                    (0x231A..=0x231B).contains(&code) ||    // Watch, Hourglass
14579                    (0x23E9..=0x23F3).contains(&code) ||    // Various symbols
14580                    (0x23F8..=0x23FA).contains(&code) // Various symbols
14581                });
14582                Ok(Value::Bool(has_emoji))
14583            }
14584            _ => Err(RuntimeError::new("is_emoji() requires string")),
14585        }
14586    });
14587
14588    // extract_emoji - extract all emoji from text
14589    define(interp, "extract_emoji", Some(1), |_, args| match &args[0] {
14590        Value::String(s) => {
14591            let emoji: Vec<Value> = s
14592                .graphemes(true)
14593                .filter(|g| {
14594                    g.chars().any(|c| {
14595                        let code = c as u32;
14596                        (0x1F600..=0x1F64F).contains(&code)
14597                            || (0x1F300..=0x1F5FF).contains(&code)
14598                            || (0x1F680..=0x1F6FF).contains(&code)
14599                            || (0x1F1E0..=0x1F1FF).contains(&code)
14600                            || (0x2600..=0x26FF).contains(&code)
14601                            || (0x2700..=0x27BF).contains(&code)
14602                            || (0x1F900..=0x1F9FF).contains(&code)
14603                            || (0x1FA00..=0x1FA6F).contains(&code)
14604                            || (0x1FA70..=0x1FAFF).contains(&code)
14605                    })
14606                })
14607                .map(|g| Value::String(Rc::new(g.to_string())))
14608                .collect();
14609            Ok(Value::Array(Rc::new(RefCell::new(emoji))))
14610        }
14611        _ => Err(RuntimeError::new("extract_emoji() requires string")),
14612    });
14613
14614    // strip_emoji - remove emoji from text
14615    define(interp, "strip_emoji", Some(1), |_, args| match &args[0] {
14616        Value::String(s) => {
14617            let stripped: String = s
14618                .graphemes(true)
14619                .filter(|g| {
14620                    !g.chars().any(|c| {
14621                        let code = c as u32;
14622                        (0x1F600..=0x1F64F).contains(&code)
14623                            || (0x1F300..=0x1F5FF).contains(&code)
14624                            || (0x1F680..=0x1F6FF).contains(&code)
14625                            || (0x1F1E0..=0x1F1FF).contains(&code)
14626                            || (0x2600..=0x26FF).contains(&code)
14627                            || (0x2700..=0x27BF).contains(&code)
14628                            || (0x1F900..=0x1F9FF).contains(&code)
14629                            || (0x1FA00..=0x1FA6F).contains(&code)
14630                            || (0x1FA70..=0x1FAFF).contains(&code)
14631                    })
14632                })
14633                .collect();
14634            Ok(Value::String(Rc::new(stripped)))
14635        }
14636        _ => Err(RuntimeError::new("strip_emoji() requires string")),
14637    });
14638
14639    // =========================================================================
14640    // MIXED SCRIPT TEXT UTILITIES
14641    // =========================================================================
14642
14643    // script_runs - split text into runs of the same script
14644    define(interp, "script_runs", Some(1), |_, args| {
14645        match &args[0] {
14646            Value::String(s) => {
14647                let mut runs: Vec<Value> = Vec::new();
14648                let mut current_run = String::new();
14649                let mut current_script: Option<Script> = None;
14650
14651                for c in s.chars() {
14652                    let script = c.script();
14653                    // Common and Inherited scripts don't start new runs
14654                    if script != Script::Common && script != Script::Inherited {
14655                        if let Some(curr) = current_script {
14656                            if script != curr {
14657                                // New script - save current run
14658                                if !current_run.is_empty() {
14659                                    runs.push(Value::String(Rc::new(current_run.clone())));
14660                                    current_run.clear();
14661                                }
14662                                current_script = Some(script);
14663                            }
14664                        } else {
14665                            current_script = Some(script);
14666                        }
14667                    }
14668                    current_run.push(c);
14669                }
14670
14671                // Don't forget the last run
14672                if !current_run.is_empty() {
14673                    runs.push(Value::String(Rc::new(current_run)));
14674                }
14675
14676                Ok(Value::Array(Rc::new(RefCell::new(runs))))
14677            }
14678            _ => Err(RuntimeError::new("script_runs() requires string")),
14679        }
14680    });
14681
14682    // script_ratio - get ratio of scripts in text
14683    define(interp, "script_ratio", Some(1), |_, args| {
14684        match &args[0] {
14685            Value::String(s) => {
14686                let mut script_counts: HashMap<String, usize> = HashMap::new();
14687                let mut total = 0usize;
14688
14689                for c in s.chars() {
14690                    if !c.is_whitespace() && c != ' ' {
14691                        let script = format!("{:?}", c.script());
14692                        *script_counts.entry(script).or_insert(0) += 1;
14693                        total += 1;
14694                    }
14695                }
14696
14697                // Convert to map of ratios
14698                let mut result = HashMap::new();
14699                for (script, count) in script_counts {
14700                    let ratio = if total > 0 {
14701                        count as f64 / total as f64
14702                    } else {
14703                        0.0
14704                    };
14705                    result.insert(script, Value::Float(ratio));
14706                }
14707
14708                let map = Rc::new(RefCell::new(result));
14709                Ok(Value::Map(map))
14710            }
14711            _ => Err(RuntimeError::new("script_ratio() requires string")),
14712        }
14713    });
14714
14715    // =========================================================================
14716    // INTERNATIONALIZATION HELPERS
14717    // =========================================================================
14718
14719    // locale_name - get display name for a locale
14720    define(interp, "locale_name", Some(1), |_, args| {
14721        match &args[0] {
14722            Value::String(locale_str) => {
14723                // Return the locale code itself as a simple implementation
14724                // A full implementation would use ICU's display names
14725                Ok(Value::String(locale_str.clone()))
14726            }
14727            _ => Err(RuntimeError::new("locale_name() requires string")),
14728        }
14729    });
14730
14731    // supported_locales - list of supported locales for collation
14732    define(interp, "supported_locales", Some(0), |_, _| {
14733        // Common locales supported by ICU
14734        let locales = vec![
14735            "ar", "bg", "ca", "cs", "da", "de", "el", "en", "es", "et", "fi", "fr", "he", "hi",
14736            "hr", "hu", "id", "it", "ja", "ko", "lt", "lv", "ms", "nb", "nl", "pl", "pt", "ro",
14737            "ru", "sk", "sl", "sr", "sv", "th", "tr", "uk", "vi", "zh",
14738        ];
14739        let values: Vec<Value> = locales
14740            .into_iter()
14741            .map(|s| Value::String(Rc::new(s.to_string())))
14742            .collect();
14743        Ok(Value::Array(Rc::new(RefCell::new(values))))
14744    });
14745}
14746
14747// =============================================================================
14748// TEXT INTELLIGENCE MODULE - AI-Native Text Analysis
14749// =============================================================================
14750
14751fn register_text_intelligence(interp: &mut Interpreter) {
14752    // =========================================================================
14753    // STRING SIMILARITY METRICS
14754    // =========================================================================
14755
14756    // levenshtein - edit distance between strings
14757    define(interp, "levenshtein", Some(2), |_, args| {
14758        match (&args[0], &args[1]) {
14759            (Value::String(a), Value::String(b)) => {
14760                let distance = strsim::levenshtein(a, b);
14761                Ok(Value::Int(distance as i64))
14762            }
14763            _ => Err(RuntimeError::new("levenshtein() requires two strings")),
14764        }
14765    });
14766
14767    // levenshtein_normalized - normalized edit distance (0.0 to 1.0)
14768    define(
14769        interp,
14770        "levenshtein_normalized",
14771        Some(2),
14772        |_, args| match (&args[0], &args[1]) {
14773            (Value::String(a), Value::String(b)) => {
14774                let distance = strsim::normalized_levenshtein(a, b);
14775                Ok(Value::Float(distance))
14776            }
14777            _ => Err(RuntimeError::new(
14778                "levenshtein_normalized() requires two strings",
14779            )),
14780        },
14781    );
14782
14783    // jaro - Jaro similarity (0.0 to 1.0)
14784    define(interp, "jaro", Some(2), |_, args| {
14785        match (&args[0], &args[1]) {
14786            (Value::String(a), Value::String(b)) => {
14787                let sim = strsim::jaro(a, b);
14788                Ok(Value::Float(sim))
14789            }
14790            _ => Err(RuntimeError::new("jaro() requires two strings")),
14791        }
14792    });
14793
14794    // jaro_winkler - Jaro-Winkler similarity (0.0 to 1.0, favors common prefixes)
14795    define(interp, "jaro_winkler", Some(2), |_, args| {
14796        match (&args[0], &args[1]) {
14797            (Value::String(a), Value::String(b)) => {
14798                let sim = strsim::jaro_winkler(a, b);
14799                Ok(Value::Float(sim))
14800            }
14801            _ => Err(RuntimeError::new("jaro_winkler() requires two strings")),
14802        }
14803    });
14804
14805    // sorensen_dice - Sørensen-Dice coefficient (0.0 to 1.0)
14806    define(interp, "sorensen_dice", Some(2), |_, args| {
14807        match (&args[0], &args[1]) {
14808            (Value::String(a), Value::String(b)) => {
14809                let sim = strsim::sorensen_dice(a, b);
14810                Ok(Value::Float(sim))
14811            }
14812            _ => Err(RuntimeError::new("sorensen_dice() requires two strings")),
14813        }
14814    });
14815
14816    // damerau_levenshtein - edit distance with transpositions
14817    define(interp, "damerau_levenshtein", Some(2), |_, args| {
14818        match (&args[0], &args[1]) {
14819            (Value::String(a), Value::String(b)) => {
14820                let distance = strsim::damerau_levenshtein(a, b);
14821                Ok(Value::Int(distance as i64))
14822            }
14823            _ => Err(RuntimeError::new(
14824                "damerau_levenshtein() requires two strings",
14825            )),
14826        }
14827    });
14828
14829    // osa_distance - Optimal String Alignment distance
14830    define(interp, "osa_distance", Some(2), |_, args| {
14831        match (&args[0], &args[1]) {
14832            (Value::String(a), Value::String(b)) => {
14833                let distance = strsim::osa_distance(a, b);
14834                Ok(Value::Int(distance as i64))
14835            }
14836            _ => Err(RuntimeError::new("osa_distance() requires two strings")),
14837        }
14838    });
14839
14840    // fuzzy_match - check if strings are similar above threshold
14841    define(interp, "fuzzy_match", Some(3), |_, args| {
14842        match (&args[0], &args[1], &args[2]) {
14843            (Value::String(a), Value::String(b), Value::Float(threshold)) => {
14844                let sim = strsim::jaro_winkler(a, b);
14845                Ok(Value::Bool(sim >= *threshold))
14846            }
14847            (Value::String(a), Value::String(b), Value::Int(threshold)) => {
14848                let sim = strsim::jaro_winkler(a, b);
14849                Ok(Value::Bool(sim >= *threshold as f64))
14850            }
14851            _ => Err(RuntimeError::new(
14852                "fuzzy_match() requires two strings and threshold",
14853            )),
14854        }
14855    });
14856
14857    // fuzzy_search - find best matches in array
14858    define(interp, "fuzzy_search", Some(3), |_, args| {
14859        match (&args[0], &args[1], &args[2]) {
14860            (Value::String(query), Value::Array(items), Value::Int(limit)) => {
14861                let items_ref = items.borrow();
14862                let mut scores: Vec<(f64, &str)> = items_ref
14863                    .iter()
14864                    .filter_map(|v| {
14865                        if let Value::String(s) = v {
14866                            Some((strsim::jaro_winkler(query, s), s.as_str()))
14867                        } else {
14868                            None
14869                        }
14870                    })
14871                    .collect();
14872                scores.sort_by(|a, b| b.0.partial_cmp(&a.0).unwrap_or(std::cmp::Ordering::Equal));
14873                let results: Vec<Value> = scores
14874                    .into_iter()
14875                    .take(*limit as usize)
14876                    .map(|(_, s)| Value::String(Rc::new(s.to_string())))
14877                    .collect();
14878                Ok(Value::Array(Rc::new(RefCell::new(results))))
14879            }
14880            _ => Err(RuntimeError::new(
14881                "fuzzy_search() requires query string, array, and limit",
14882            )),
14883        }
14884    });
14885
14886    // =========================================================================
14887    // PHONETIC ENCODING
14888    // =========================================================================
14889
14890    // soundex - American Soundex encoding
14891    define(interp, "soundex", Some(1), |_, args| match &args[0] {
14892        Value::String(s) => {
14893            let code = compute_soundex(s);
14894            Ok(Value::String(Rc::new(code)))
14895        }
14896        _ => Err(RuntimeError::new("soundex() requires string")),
14897    });
14898
14899    // soundex_match - check if two strings have same Soundex code
14900    define(interp, "soundex_match", Some(2), |_, args| {
14901        match (&args[0], &args[1]) {
14902            (Value::String(a), Value::String(b)) => {
14903                let code_a = compute_soundex(a);
14904                let code_b = compute_soundex(b);
14905                Ok(Value::Bool(code_a == code_b))
14906            }
14907            _ => Err(RuntimeError::new("soundex_match() requires two strings")),
14908        }
14909    });
14910
14911    // metaphone - Metaphone encoding (better for English)
14912    define(interp, "metaphone", Some(1), |_, args| match &args[0] {
14913        Value::String(s) => {
14914            let code = compute_metaphone(s);
14915            Ok(Value::String(Rc::new(code)))
14916        }
14917        _ => Err(RuntimeError::new("metaphone() requires string")),
14918    });
14919
14920    // metaphone_match - check if two strings have same Metaphone code
14921    define(interp, "metaphone_match", Some(2), |_, args| {
14922        match (&args[0], &args[1]) {
14923            (Value::String(a), Value::String(b)) => {
14924                let code_a = compute_metaphone(a);
14925                let code_b = compute_metaphone(b);
14926                Ok(Value::Bool(code_a == code_b))
14927            }
14928            _ => Err(RuntimeError::new("metaphone_match() requires two strings")),
14929        }
14930    });
14931
14932    // cologne_phonetic - Cologne phonetic encoding (for German)
14933    define(interp, "cologne_phonetic", Some(1), |_, args| {
14934        match &args[0] {
14935            Value::String(s) => {
14936                let code = compute_cologne(s);
14937                Ok(Value::String(Rc::new(code)))
14938            }
14939            _ => Err(RuntimeError::new("cologne_phonetic() requires string")),
14940        }
14941    });
14942
14943    // =========================================================================
14944    // LANGUAGE DETECTION
14945    // =========================================================================
14946
14947    // detect_language - detect the language of text
14948    define(interp, "detect_language", Some(1), |_, args| {
14949        match &args[0] {
14950            Value::String(s) => {
14951                if let Some(info) = detect(s) {
14952                    let lang_code = match info.lang() {
14953                        Lang::Eng => "en",
14954                        Lang::Spa => "es",
14955                        Lang::Fra => "fr",
14956                        Lang::Deu => "de",
14957                        Lang::Ita => "it",
14958                        Lang::Por => "pt",
14959                        Lang::Rus => "ru",
14960                        Lang::Ara => "ar",
14961                        Lang::Hin => "hi",
14962                        Lang::Cmn => "zh",
14963                        Lang::Jpn => "ja",
14964                        Lang::Kor => "ko",
14965                        Lang::Nld => "nl",
14966                        Lang::Swe => "sv",
14967                        Lang::Tur => "tr",
14968                        Lang::Pol => "pl",
14969                        Lang::Ukr => "uk",
14970                        Lang::Ces => "cs",
14971                        Lang::Dan => "da",
14972                        Lang::Fin => "fi",
14973                        Lang::Ell => "el",
14974                        Lang::Heb => "he",
14975                        Lang::Hun => "hu",
14976                        Lang::Ind => "id",
14977                        Lang::Nob => "no",
14978                        Lang::Ron => "ro",
14979                        Lang::Slk => "sk",
14980                        Lang::Tha => "th",
14981                        Lang::Vie => "vi",
14982                        _ => "unknown",
14983                    };
14984                    Ok(Value::String(Rc::new(lang_code.to_string())))
14985                } else {
14986                    Ok(Value::String(Rc::new("unknown".to_string())))
14987                }
14988            }
14989            _ => Err(RuntimeError::new("detect_language() requires string")),
14990        }
14991    });
14992
14993    // detect_language_confidence - detect language with confidence score
14994    define(
14995        interp,
14996        "detect_language_confidence",
14997        Some(1),
14998        |_, args| match &args[0] {
14999            Value::String(s) => {
15000                if let Some(info) = detect(s) {
15001                    let lang_code = match info.lang() {
15002                        Lang::Eng => "en",
15003                        Lang::Spa => "es",
15004                        Lang::Fra => "fr",
15005                        Lang::Deu => "de",
15006                        Lang::Ita => "it",
15007                        Lang::Por => "pt",
15008                        Lang::Rus => "ru",
15009                        Lang::Ara => "ar",
15010                        Lang::Cmn => "zh",
15011                        Lang::Jpn => "ja",
15012                        _ => "unknown",
15013                    };
15014                    let confidence = info.confidence();
15015                    let mut map = HashMap::new();
15016                    map.insert(
15017                        "lang".to_string(),
15018                        Value::String(Rc::new(lang_code.to_string())),
15019                    );
15020                    map.insert("confidence".to_string(), Value::Float(confidence as f64));
15021                    Ok(Value::Map(Rc::new(RefCell::new(map))))
15022                } else {
15023                    let mut map = HashMap::new();
15024                    map.insert(
15025                        "lang".to_string(),
15026                        Value::String(Rc::new("unknown".to_string())),
15027                    );
15028                    map.insert("confidence".to_string(), Value::Float(0.0));
15029                    Ok(Value::Map(Rc::new(RefCell::new(map))))
15030                }
15031            }
15032            _ => Err(RuntimeError::new(
15033                "detect_language_confidence() requires string",
15034            )),
15035        },
15036    );
15037
15038    // detect_script - detect the script of text using whatlang
15039    define(
15040        interp,
15041        "detect_script_whatlang",
15042        Some(1),
15043        |_, args| match &args[0] {
15044            Value::String(s) => {
15045                if let Some(info) = detect(s) {
15046                    let script_name = match info.script() {
15047                        WhatLangScript::Latin => "Latin",
15048                        WhatLangScript::Cyrillic => "Cyrillic",
15049                        WhatLangScript::Arabic => "Arabic",
15050                        WhatLangScript::Devanagari => "Devanagari",
15051                        WhatLangScript::Ethiopic => "Ethiopic",
15052                        WhatLangScript::Georgian => "Georgian",
15053                        WhatLangScript::Greek => "Greek",
15054                        WhatLangScript::Gujarati => "Gujarati",
15055                        WhatLangScript::Gurmukhi => "Gurmukhi",
15056                        WhatLangScript::Hangul => "Hangul",
15057                        WhatLangScript::Hebrew => "Hebrew",
15058                        WhatLangScript::Hiragana => "Hiragana",
15059                        WhatLangScript::Kannada => "Kannada",
15060                        WhatLangScript::Katakana => "Katakana",
15061                        WhatLangScript::Khmer => "Khmer",
15062                        WhatLangScript::Malayalam => "Malayalam",
15063                        WhatLangScript::Mandarin => "Mandarin",
15064                        WhatLangScript::Myanmar => "Myanmar",
15065                        WhatLangScript::Oriya => "Oriya",
15066                        WhatLangScript::Sinhala => "Sinhala",
15067                        WhatLangScript::Tamil => "Tamil",
15068                        WhatLangScript::Telugu => "Telugu",
15069                        WhatLangScript::Thai => "Thai",
15070                        WhatLangScript::Bengali => "Bengali",
15071                        WhatLangScript::Armenian => "Armenian",
15072                    };
15073                    Ok(Value::String(Rc::new(script_name.to_string())))
15074                } else {
15075                    Ok(Value::String(Rc::new("Unknown".to_string())))
15076                }
15077            }
15078            _ => Err(RuntimeError::new(
15079                "detect_script_whatlang() requires string",
15080            )),
15081        },
15082    );
15083
15084    // is_language - check if text is in a specific language
15085    define(interp, "is_language", Some(2), |_, args| {
15086        match (&args[0], &args[1]) {
15087            (Value::String(s), Value::String(lang)) => {
15088                if let Some(info) = detect(s) {
15089                    let detected = match info.lang() {
15090                        Lang::Eng => "en",
15091                        Lang::Spa => "es",
15092                        Lang::Fra => "fr",
15093                        Lang::Deu => "de",
15094                        Lang::Ita => "it",
15095                        Lang::Por => "pt",
15096                        Lang::Rus => "ru",
15097                        _ => "unknown",
15098                    };
15099                    Ok(Value::Bool(detected == lang.as_str()))
15100                } else {
15101                    Ok(Value::Bool(false))
15102                }
15103            }
15104            _ => Err(RuntimeError::new(
15105                "is_language() requires string and language code",
15106            )),
15107        }
15108    });
15109
15110    // =========================================================================
15111    // LLM TOKEN COUNTING
15112    // =========================================================================
15113
15114    // token_count - count tokens using cl100k_base (GPT-4, Claude compatible)
15115    define(interp, "token_count", Some(1), |_, args| match &args[0] {
15116        Value::String(s) => {
15117            if let Ok(bpe) = cl100k_base() {
15118                let tokens = bpe.encode_with_special_tokens(s);
15119                Ok(Value::Int(tokens.len() as i64))
15120            } else {
15121                Err(RuntimeError::new("Failed to initialize tokenizer"))
15122            }
15123        }
15124        _ => Err(RuntimeError::new("token_count() requires string")),
15125    });
15126
15127    // token_count_model - count tokens for specific model
15128    define(interp, "token_count_model", Some(2), |_, args| {
15129        match (&args[0], &args[1]) {
15130            (Value::String(s), Value::String(model)) => {
15131                let bpe_result = match model.as_str() {
15132                    "gpt4" | "gpt-4" | "claude" | "cl100k" => cl100k_base(),
15133                    "gpt3" | "gpt-3" | "p50k" => p50k_base(),
15134                    "codex" | "r50k" => r50k_base(),
15135                    _ => cl100k_base(), // Default to GPT-4/Claude
15136                };
15137                if let Ok(bpe) = bpe_result {
15138                    let tokens = bpe.encode_with_special_tokens(s);
15139                    Ok(Value::Int(tokens.len() as i64))
15140                } else {
15141                    Err(RuntimeError::new("Failed to initialize tokenizer"))
15142                }
15143            }
15144            _ => Err(RuntimeError::new(
15145                "token_count_model() requires string and model name",
15146            )),
15147        }
15148    });
15149
15150    // tokenize_ids - get token IDs as array
15151    define(interp, "tokenize_ids", Some(1), |_, args| match &args[0] {
15152        Value::String(s) => {
15153            if let Ok(bpe) = cl100k_base() {
15154                let tokens = bpe.encode_with_special_tokens(s);
15155                let values: Vec<Value> = tokens.into_iter().map(|t| Value::Int(t as i64)).collect();
15156                Ok(Value::Array(Rc::new(RefCell::new(values))))
15157            } else {
15158                Err(RuntimeError::new("Failed to initialize tokenizer"))
15159            }
15160        }
15161        _ => Err(RuntimeError::new("tokenize_ids() requires string")),
15162    });
15163
15164    // truncate_tokens - truncate string to max tokens
15165    define(interp, "truncate_tokens", Some(2), |_, args| {
15166        match (&args[0], &args[1]) {
15167            (Value::String(s), Value::Int(max_tokens)) => {
15168                if let Ok(bpe) = cl100k_base() {
15169                    let tokens = bpe.encode_with_special_tokens(s);
15170                    if tokens.len() <= *max_tokens as usize {
15171                        Ok(Value::String(s.clone()))
15172                    } else {
15173                        let truncated: Vec<usize> =
15174                            tokens.into_iter().take(*max_tokens as usize).collect();
15175                        if let Ok(decoded) = bpe.decode(truncated) {
15176                            Ok(Value::String(Rc::new(decoded)))
15177                        } else {
15178                            Err(RuntimeError::new("Failed to decode tokens"))
15179                        }
15180                    }
15181                } else {
15182                    Err(RuntimeError::new("Failed to initialize tokenizer"))
15183                }
15184            }
15185            _ => Err(RuntimeError::new(
15186                "truncate_tokens() requires string and max tokens",
15187            )),
15188        }
15189    });
15190
15191    // estimate_cost - estimate API cost based on token count
15192    define(interp, "estimate_cost", Some(3), |_, args| {
15193        match (&args[0], &args[1], &args[2]) {
15194            (Value::String(s), Value::Float(input_cost), Value::Float(output_cost)) => {
15195                if let Ok(bpe) = cl100k_base() {
15196                    let tokens = bpe.encode_with_special_tokens(s);
15197                    let count = tokens.len() as f64;
15198                    // Cost per 1K tokens
15199                    let input_total = (count / 1000.0) * input_cost;
15200                    let output_total = (count / 1000.0) * output_cost;
15201                    let mut map = HashMap::new();
15202                    map.insert("tokens".to_string(), Value::Int(tokens.len() as i64));
15203                    map.insert("input_cost".to_string(), Value::Float(input_total));
15204                    map.insert("output_cost".to_string(), Value::Float(output_total));
15205                    Ok(Value::Map(Rc::new(RefCell::new(map))))
15206                } else {
15207                    Err(RuntimeError::new("Failed to initialize tokenizer"))
15208                }
15209            }
15210            _ => Err(RuntimeError::new(
15211                "estimate_cost() requires string, input cost, output cost",
15212            )),
15213        }
15214    });
15215
15216    // =========================================================================
15217    // STEMMING
15218    // =========================================================================
15219
15220    // stem - stem a word using Porter algorithm
15221    define(interp, "stem", Some(1), |_, args| match &args[0] {
15222        Value::String(s) => {
15223            let stemmer = Stemmer::create(StemAlgorithm::English);
15224            let stemmed = stemmer.stem(s);
15225            Ok(Value::String(Rc::new(stemmed.to_string())))
15226        }
15227        _ => Err(RuntimeError::new("stem() requires string")),
15228    });
15229
15230    // stem_language - stem a word for specific language
15231    define(interp, "stem_language", Some(2), |_, args| {
15232        match (&args[0], &args[1]) {
15233            (Value::String(s), Value::String(lang)) => {
15234                let algorithm = match lang.as_str() {
15235                    "en" | "english" => StemAlgorithm::English,
15236                    "fr" | "french" => StemAlgorithm::French,
15237                    "de" | "german" => StemAlgorithm::German,
15238                    "es" | "spanish" => StemAlgorithm::Spanish,
15239                    "it" | "italian" => StemAlgorithm::Italian,
15240                    "pt" | "portuguese" => StemAlgorithm::Portuguese,
15241                    "nl" | "dutch" => StemAlgorithm::Dutch,
15242                    "sv" | "swedish" => StemAlgorithm::Swedish,
15243                    "no" | "norwegian" => StemAlgorithm::Norwegian,
15244                    "da" | "danish" => StemAlgorithm::Danish,
15245                    "fi" | "finnish" => StemAlgorithm::Finnish,
15246                    "ru" | "russian" => StemAlgorithm::Russian,
15247                    "ro" | "romanian" => StemAlgorithm::Romanian,
15248                    "hu" | "hungarian" => StemAlgorithm::Hungarian,
15249                    "tr" | "turkish" => StemAlgorithm::Turkish,
15250                    "ar" | "arabic" => StemAlgorithm::Arabic,
15251                    _ => StemAlgorithm::English,
15252                };
15253                let stemmer = Stemmer::create(algorithm);
15254                let stemmed = stemmer.stem(s);
15255                Ok(Value::String(Rc::new(stemmed.to_string())))
15256            }
15257            _ => Err(RuntimeError::new(
15258                "stem_language() requires string and language code",
15259            )),
15260        }
15261    });
15262
15263    // stem_all - stem all words in array
15264    define(interp, "stem_all", Some(1), |_, args| match &args[0] {
15265        Value::Array(arr) => {
15266            let stemmer = Stemmer::create(StemAlgorithm::English);
15267            let arr_ref = arr.borrow();
15268            let results: Vec<Value> = arr_ref
15269                .iter()
15270                .filter_map(|v| {
15271                    if let Value::String(s) = v {
15272                        Some(Value::String(Rc::new(stemmer.stem(s).to_string())))
15273                    } else {
15274                        None
15275                    }
15276                })
15277                .collect();
15278            Ok(Value::Array(Rc::new(RefCell::new(results))))
15279        }
15280        _ => Err(RuntimeError::new("stem_all() requires array of strings")),
15281    });
15282
15283    // =========================================================================
15284    // STOPWORDS
15285    // =========================================================================
15286
15287    // is_stopword - check if word is a stopword
15288    define(interp, "is_stopword", Some(1), |_, args| match &args[0] {
15289        Value::String(s) => {
15290            let word = s.to_lowercase();
15291            let stopwords = get_stopwords("en");
15292            Ok(Value::Bool(stopwords.contains(&word.as_str())))
15293        }
15294        _ => Err(RuntimeError::new("is_stopword() requires string")),
15295    });
15296
15297    // is_stopword_language - check if word is stopword in language
15298    define(interp, "is_stopword_language", Some(2), |_, args| {
15299        match (&args[0], &args[1]) {
15300            (Value::String(s), Value::String(lang)) => {
15301                let word = s.to_lowercase();
15302                let stopwords = get_stopwords(lang);
15303                Ok(Value::Bool(stopwords.contains(&word.as_str())))
15304            }
15305            _ => Err(RuntimeError::new(
15306                "is_stopword_language() requires string and language",
15307            )),
15308        }
15309    });
15310
15311    // remove_stopwords - remove stopwords from array
15312    define(interp, "remove_stopwords", Some(1), |_, args| {
15313        match &args[0] {
15314            Value::Array(arr) => {
15315                let stopwords = get_stopwords("en");
15316                let arr_ref = arr.borrow();
15317                let results: Vec<Value> = arr_ref
15318                    .iter()
15319                    .filter(|v| {
15320                        if let Value::String(s) = v {
15321                            !stopwords.contains(&s.to_lowercase().as_str())
15322                        } else {
15323                            true
15324                        }
15325                    })
15326                    .cloned()
15327                    .collect();
15328                Ok(Value::Array(Rc::new(RefCell::new(results))))
15329            }
15330            _ => Err(RuntimeError::new(
15331                "remove_stopwords() requires array of strings",
15332            )),
15333        }
15334    });
15335
15336    // remove_stopwords_text - remove stopwords from text string
15337    define(
15338        interp,
15339        "remove_stopwords_text",
15340        Some(1),
15341        |_, args| match &args[0] {
15342            Value::String(s) => {
15343                let stopwords = get_stopwords("en");
15344                let words: Vec<&str> = s
15345                    .split_whitespace()
15346                    .filter(|w| !stopwords.contains(&w.to_lowercase().as_str()))
15347                    .collect();
15348                Ok(Value::String(Rc::new(words.join(" "))))
15349            }
15350            _ => Err(RuntimeError::new("remove_stopwords_text() requires string")),
15351        },
15352    );
15353
15354    // get_stopwords_list - get list of stopwords for language
15355    define(
15356        interp,
15357        "get_stopwords_list",
15358        Some(1),
15359        |_, args| match &args[0] {
15360            Value::String(lang) => {
15361                let stopwords = get_stopwords(lang);
15362                let values: Vec<Value> = stopwords
15363                    .iter()
15364                    .map(|s| Value::String(Rc::new(s.to_string())))
15365                    .collect();
15366                Ok(Value::Array(Rc::new(RefCell::new(values))))
15367            }
15368            _ => Err(RuntimeError::new(
15369                "get_stopwords_list() requires language code",
15370            )),
15371        },
15372    );
15373
15374    // =========================================================================
15375    // N-GRAMS AND SHINGLES
15376    // =========================================================================
15377
15378    // ngrams - extract word n-grams
15379    define(interp, "ngrams", Some(2), |_, args| {
15380        match (&args[0], &args[1]) {
15381            (Value::String(s), Value::Int(n)) => {
15382                let words: Vec<&str> = s.split_whitespace().collect();
15383                let n = *n as usize;
15384                if n == 0 || n > words.len() {
15385                    return Ok(Value::Array(Rc::new(RefCell::new(vec![]))));
15386                }
15387                let ngrams: Vec<Value> = words
15388                    .windows(n)
15389                    .map(|w| Value::String(Rc::new(w.join(" "))))
15390                    .collect();
15391                Ok(Value::Array(Rc::new(RefCell::new(ngrams))))
15392            }
15393            _ => Err(RuntimeError::new("ngrams() requires string and n")),
15394        }
15395    });
15396
15397    // char_ngrams - extract character n-grams
15398    define(interp, "char_ngrams", Some(2), |_, args| {
15399        match (&args[0], &args[1]) {
15400            (Value::String(s), Value::Int(n)) => {
15401                let chars: Vec<char> = s.chars().collect();
15402                let n = *n as usize;
15403                if n == 0 || n > chars.len() {
15404                    return Ok(Value::Array(Rc::new(RefCell::new(vec![]))));
15405                }
15406                let ngrams: Vec<Value> = chars
15407                    .windows(n)
15408                    .map(|w| Value::String(Rc::new(w.iter().collect())))
15409                    .collect();
15410                Ok(Value::Array(Rc::new(RefCell::new(ngrams))))
15411            }
15412            _ => Err(RuntimeError::new("char_ngrams() requires string and n")),
15413        }
15414    });
15415
15416    // shingles - extract word shingles (same as ngrams, but as set)
15417    define(interp, "shingles", Some(2), |_, args| {
15418        match (&args[0], &args[1]) {
15419            (Value::String(s), Value::Int(n)) => {
15420                let words: Vec<&str> = s.split_whitespace().collect();
15421                let n = *n as usize;
15422                if n == 0 || n > words.len() {
15423                    return Ok(Value::Array(Rc::new(RefCell::new(vec![]))));
15424                }
15425                let mut seen = std::collections::HashSet::new();
15426                let shingles: Vec<Value> = words
15427                    .windows(n)
15428                    .filter_map(|w| {
15429                        let s = w.join(" ");
15430                        if seen.insert(s.clone()) {
15431                            Some(Value::String(Rc::new(s)))
15432                        } else {
15433                            None
15434                        }
15435                    })
15436                    .collect();
15437                Ok(Value::Array(Rc::new(RefCell::new(shingles))))
15438            }
15439            _ => Err(RuntimeError::new("shingles() requires string and n")),
15440        }
15441    });
15442
15443    // jaccard_similarity - Jaccard similarity between two sets of shingles
15444    define(interp, "jaccard_similarity", Some(2), |_, args| {
15445        match (&args[0], &args[1]) {
15446            (Value::Array(a), Value::Array(b)) => {
15447                let a_ref = a.borrow();
15448                let b_ref = b.borrow();
15449                let set_a: std::collections::HashSet<String> = a_ref
15450                    .iter()
15451                    .filter_map(|v| {
15452                        if let Value::String(s) = v {
15453                            Some(s.to_string())
15454                        } else {
15455                            None
15456                        }
15457                    })
15458                    .collect();
15459                let set_b: std::collections::HashSet<String> = b_ref
15460                    .iter()
15461                    .filter_map(|v| {
15462                        if let Value::String(s) = v {
15463                            Some(s.to_string())
15464                        } else {
15465                            None
15466                        }
15467                    })
15468                    .collect();
15469                let intersection = set_a.intersection(&set_b).count();
15470                let union = set_a.union(&set_b).count();
15471                if union == 0 {
15472                    Ok(Value::Float(0.0))
15473                } else {
15474                    Ok(Value::Float(intersection as f64 / union as f64))
15475                }
15476            }
15477            _ => Err(RuntimeError::new(
15478                "jaccard_similarity() requires two arrays",
15479            )),
15480        }
15481    });
15482
15483    // minhash_signature - compute MinHash signature for LSH
15484    define(interp, "minhash_signature", Some(2), |_, args| {
15485        match (&args[0], &args[1]) {
15486            (Value::Array(arr), Value::Int(num_hashes)) => {
15487                let arr_ref = arr.borrow();
15488                let items: std::collections::HashSet<String> = arr_ref
15489                    .iter()
15490                    .filter_map(|v| {
15491                        if let Value::String(s) = v {
15492                            Some(s.to_string())
15493                        } else {
15494                            None
15495                        }
15496                    })
15497                    .collect();
15498
15499                // Simple MinHash using polynomial rolling hash
15500                let mut signature: Vec<Value> = Vec::with_capacity(*num_hashes as usize);
15501                for i in 0..*num_hashes {
15502                    let mut min_hash: u64 = u64::MAX;
15503                    for item in &items {
15504                        let hash = compute_hash(item, i as u64);
15505                        if hash < min_hash {
15506                            min_hash = hash;
15507                        }
15508                    }
15509                    signature.push(Value::Int(min_hash as i64));
15510                }
15511                Ok(Value::Array(Rc::new(RefCell::new(signature))))
15512            }
15513            _ => Err(RuntimeError::new(
15514                "minhash_signature() requires array and num_hashes",
15515            )),
15516        }
15517    });
15518
15519    // =========================================================================
15520    // TEXT PREPROCESSING
15521    // =========================================================================
15522
15523    // preprocess_text - full text preprocessing pipeline
15524    define(interp, "preprocess_text", Some(1), |_, args| {
15525        match &args[0] {
15526            Value::String(s) => {
15527                // Lowercase
15528                let lower = s.to_lowercase();
15529                // Remove punctuation (keep letters, numbers, spaces)
15530                let clean: String = lower
15531                    .chars()
15532                    .filter(|c| c.is_alphanumeric() || c.is_whitespace())
15533                    .collect();
15534                // Normalize whitespace
15535                let normalized: String = clean.split_whitespace().collect::<Vec<_>>().join(" ");
15536                Ok(Value::String(Rc::new(normalized)))
15537            }
15538            _ => Err(RuntimeError::new("preprocess_text() requires string")),
15539        }
15540    });
15541
15542    // tokenize_words - split text into word tokens
15543    define(interp, "tokenize_words", Some(1), |_, args| {
15544        match &args[0] {
15545            Value::String(s) => {
15546                let words: Vec<Value> = s
15547                    .split_whitespace()
15548                    .map(|w| Value::String(Rc::new(w.to_string())))
15549                    .collect();
15550                Ok(Value::Array(Rc::new(RefCell::new(words))))
15551            }
15552            _ => Err(RuntimeError::new("tokenize_words() requires string")),
15553        }
15554    });
15555
15556    // extract_keywords - extract likely keywords (content words)
15557    define(interp, "extract_keywords", Some(1), |_, args| {
15558        match &args[0] {
15559            Value::String(s) => {
15560                let stopwords = get_stopwords("en");
15561                let words: Vec<Value> = s
15562                    .split_whitespace()
15563                    .filter(|w| {
15564                        let lower = w.to_lowercase();
15565                        !stopwords.contains(&lower.as_str()) && lower.len() > 2
15566                    })
15567                    .map(|w| Value::String(Rc::new(w.to_lowercase())))
15568                    .collect();
15569                Ok(Value::Array(Rc::new(RefCell::new(words))))
15570            }
15571            _ => Err(RuntimeError::new("extract_keywords() requires string")),
15572        }
15573    });
15574
15575    // word_frequency - count word frequencies
15576    define(interp, "word_frequency", Some(1), |_, args| {
15577        match &args[0] {
15578            Value::String(s) => {
15579                let mut freq: HashMap<String, i64> = HashMap::new();
15580                for word in s.split_whitespace() {
15581                    let lower = word.to_lowercase();
15582                    *freq.entry(lower).or_insert(0) += 1;
15583                }
15584                let map: HashMap<String, Value> =
15585                    freq.into_iter().map(|(k, v)| (k, Value::Int(v))).collect();
15586                Ok(Value::Map(Rc::new(RefCell::new(map))))
15587            }
15588            _ => Err(RuntimeError::new("word_frequency() requires string")),
15589        }
15590    });
15591
15592    // =========================================================================
15593    // AFFECTIVE MARKERS (Emotional Intelligence)
15594    // =========================================================================
15595
15596    // sentiment_words - basic sentiment word detection
15597    define(interp, "sentiment_words", Some(1), |_, args| {
15598        match &args[0] {
15599            Value::String(s) => {
15600                let positive = vec![
15601                    "good",
15602                    "great",
15603                    "excellent",
15604                    "amazing",
15605                    "wonderful",
15606                    "fantastic",
15607                    "love",
15608                    "happy",
15609                    "joy",
15610                    "beautiful",
15611                    "awesome",
15612                    "perfect",
15613                    "best",
15614                    "brilliant",
15615                    "delightful",
15616                    "pleasant",
15617                    "positive",
15618                ];
15619                let negative = vec![
15620                    "bad",
15621                    "terrible",
15622                    "awful",
15623                    "horrible",
15624                    "hate",
15625                    "sad",
15626                    "angry",
15627                    "worst",
15628                    "poor",
15629                    "negative",
15630                    "disappointing",
15631                    "ugly",
15632                    "disgusting",
15633                    "painful",
15634                    "miserable",
15635                    "annoying",
15636                ];
15637
15638                let lower = s.to_lowercase();
15639                let words: Vec<&str> = lower.split_whitespace().collect();
15640                let pos_count: i64 = words.iter().filter(|w| positive.contains(w)).count() as i64;
15641                let neg_count: i64 = words.iter().filter(|w| negative.contains(w)).count() as i64;
15642
15643                let mut map = HashMap::new();
15644                map.insert("positive".to_string(), Value::Int(pos_count));
15645                map.insert("negative".to_string(), Value::Int(neg_count));
15646                map.insert("total".to_string(), Value::Int(words.len() as i64));
15647
15648                let score = if pos_count + neg_count > 0 {
15649                    (pos_count - neg_count) as f64 / (pos_count + neg_count) as f64
15650                } else {
15651                    0.0
15652                };
15653                map.insert("score".to_string(), Value::Float(score));
15654
15655                Ok(Value::Map(Rc::new(RefCell::new(map))))
15656            }
15657            _ => Err(RuntimeError::new("sentiment_words() requires string")),
15658        }
15659    });
15660
15661    // has_question - detect if text contains a question
15662    define(interp, "has_question", Some(1), |_, args| match &args[0] {
15663        Value::String(s) => {
15664            let has_q_mark = s.contains('?');
15665            let lower = s.to_lowercase();
15666            let question_words = [
15667                "what", "where", "when", "why", "how", "who", "which", "whose", "whom",
15668            ];
15669            let starts_with_q = question_words.iter().any(|w| lower.starts_with(w));
15670            Ok(Value::Bool(has_q_mark || starts_with_q))
15671        }
15672        _ => Err(RuntimeError::new("has_question() requires string")),
15673    });
15674
15675    // has_exclamation - detect if text has strong emotion markers
15676    define(interp, "has_exclamation", Some(1), |_, args| {
15677        match &args[0] {
15678            Value::String(s) => Ok(Value::Bool(s.contains('!'))),
15679            _ => Err(RuntimeError::new("has_exclamation() requires string")),
15680        }
15681    });
15682
15683    // text_formality - estimate text formality (0=informal, 1=formal)
15684    define(interp, "text_formality", Some(1), |_, args| {
15685        match &args[0] {
15686            Value::String(s) => {
15687                let lower = s.to_lowercase();
15688                let informal_markers = vec![
15689                    "gonna", "wanna", "gotta", "kinda", "sorta", "dunno", "yeah", "yep", "nope",
15690                    "ok", "lol", "omg", "btw", "u", "ur", "r", "y", "2", "4",
15691                ];
15692                let formal_markers = vec![
15693                    "therefore",
15694                    "furthermore",
15695                    "moreover",
15696                    "consequently",
15697                    "nevertheless",
15698                    "however",
15699                    "whereas",
15700                    "hereby",
15701                    "respectfully",
15702                    "sincerely",
15703                    "accordingly",
15704                ];
15705
15706                let words: Vec<&str> = lower.split_whitespace().collect();
15707                let informal_count = words
15708                    .iter()
15709                    .filter(|w| informal_markers.contains(w))
15710                    .count();
15711                let formal_count = words.iter().filter(|w| formal_markers.contains(w)).count();
15712
15713                let score = if informal_count + formal_count > 0 {
15714                    formal_count as f64 / (informal_count + formal_count) as f64
15715                } else {
15716                    0.5 // Neutral if no markers
15717                };
15718
15719                Ok(Value::Float(score))
15720            }
15721            _ => Err(RuntimeError::new("text_formality() requires string")),
15722        }
15723    });
15724
15725    // =========================================================================
15726    // VADER-STYLE SENTIMENT ANALYSIS
15727    // =========================================================================
15728
15729    // sentiment_vader - VADER-inspired sentiment analysis with intensity
15730    define(interp, "sentiment_vader", Some(1), |_, args| {
15731        match &args[0] {
15732            Value::String(s) => {
15733                let result = compute_vader_sentiment(s);
15734                let mut map = HashMap::new();
15735                map.insert("positive".to_string(), Value::Float(result.0));
15736                map.insert("negative".to_string(), Value::Float(result.1));
15737                map.insert("neutral".to_string(), Value::Float(result.2));
15738                map.insert("compound".to_string(), Value::Float(result.3));
15739                Ok(Value::Map(Rc::new(RefCell::new(map))))
15740            }
15741            _ => Err(RuntimeError::new("sentiment_vader() requires string")),
15742        }
15743    });
15744
15745    // emotion_detect - detect specific emotions
15746    define(interp, "emotion_detect", Some(1), |_, args| {
15747        match &args[0] {
15748            Value::String(s) => {
15749                let emotions = compute_emotions(s);
15750                let map: HashMap<String, Value> = emotions
15751                    .into_iter()
15752                    .map(|(k, v)| (k, Value::Float(v)))
15753                    .collect();
15754                Ok(Value::Map(Rc::new(RefCell::new(map))))
15755            }
15756            _ => Err(RuntimeError::new("emotion_detect() requires string")),
15757        }
15758    });
15759
15760    // intensity_words - detect intensity modifiers
15761    define(interp, "intensity_score", Some(1), |_, args| {
15762        match &args[0] {
15763            Value::String(s) => {
15764                let score = compute_intensity(s);
15765                Ok(Value::Float(score))
15766            }
15767            _ => Err(RuntimeError::new("intensity_score() requires string")),
15768        }
15769    });
15770
15771    // =========================================================================
15772    // SARCASM AND IRONY DETECTION
15773    // =========================================================================
15774
15775    // detect_sarcasm - detect potential sarcasm/irony markers
15776    define(interp, "detect_sarcasm", Some(1), |_, args| {
15777        match &args[0] {
15778            Value::String(s) => {
15779                let result = compute_sarcasm_score(s);
15780                let mut map = HashMap::new();
15781                map.insert("score".to_string(), Value::Float(result.0));
15782                map.insert("confidence".to_string(), Value::Float(result.1));
15783                let markers: Vec<Value> = result
15784                    .2
15785                    .into_iter()
15786                    .map(|m| Value::String(Rc::new(m)))
15787                    .collect();
15788                map.insert(
15789                    "markers".to_string(),
15790                    Value::Array(Rc::new(RefCell::new(markers))),
15791                );
15792                Ok(Value::Map(Rc::new(RefCell::new(map))))
15793            }
15794            _ => Err(RuntimeError::new("detect_sarcasm() requires string")),
15795        }
15796    });
15797
15798    // is_sarcastic - simple boolean sarcasm check
15799    define(interp, "is_sarcastic", Some(1), |_, args| match &args[0] {
15800        Value::String(s) => {
15801            let result = compute_sarcasm_score(s);
15802            Ok(Value::Bool(result.0 > 0.5))
15803        }
15804        _ => Err(RuntimeError::new("is_sarcastic() requires string")),
15805    });
15806
15807    // detect_irony - detect verbal irony patterns
15808    define(interp, "detect_irony", Some(1), |_, args| match &args[0] {
15809        Value::String(s) => {
15810            let score = compute_irony_score(s);
15811            Ok(Value::Float(score))
15812        }
15813        _ => Err(RuntimeError::new("detect_irony() requires string")),
15814    });
15815
15816    // =========================================================================
15817    // NAMED ENTITY RECOGNITION (Pattern-based)
15818    // =========================================================================
15819
15820    // extract_emails - extract email addresses
15821    define(interp, "extract_emails", Some(1), |_, args| {
15822        match &args[0] {
15823            Value::String(s) => {
15824                let re = Regex::new(r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}").unwrap();
15825                let emails: Vec<Value> = re
15826                    .find_iter(s)
15827                    .map(|m| Value::String(Rc::new(m.as_str().to_string())))
15828                    .collect();
15829                Ok(Value::Array(Rc::new(RefCell::new(emails))))
15830            }
15831            _ => Err(RuntimeError::new("extract_emails() requires string")),
15832        }
15833    });
15834
15835    // extract_urls - extract URLs
15836    define(interp, "extract_urls", Some(1), |_, args| match &args[0] {
15837        Value::String(s) => {
15838            let re = Regex::new(r"https?://[^\s<>\[\]{}|\\^]+").unwrap();
15839            let urls: Vec<Value> = re
15840                .find_iter(s)
15841                .map(|m| Value::String(Rc::new(m.as_str().to_string())))
15842                .collect();
15843            Ok(Value::Array(Rc::new(RefCell::new(urls))))
15844        }
15845        _ => Err(RuntimeError::new("extract_urls() requires string")),
15846    });
15847
15848    // extract_phone_numbers - extract phone numbers
15849    define(
15850        interp,
15851        "extract_phone_numbers",
15852        Some(1),
15853        |_, args| match &args[0] {
15854            Value::String(s) => {
15855                let re =
15856                    Regex::new(r"(?:\+?1[-.\s]?)?\(?[0-9]{3}\)?[-.\s]?[0-9]{3}[-.\s]?[0-9]{4}")
15857                        .unwrap();
15858                let phones: Vec<Value> = re
15859                    .find_iter(s)
15860                    .map(|m| Value::String(Rc::new(m.as_str().to_string())))
15861                    .collect();
15862                Ok(Value::Array(Rc::new(RefCell::new(phones))))
15863            }
15864            _ => Err(RuntimeError::new("extract_phone_numbers() requires string")),
15865        },
15866    );
15867
15868    // extract_dates - extract date patterns
15869    define(interp, "extract_dates", Some(1), |_, args| {
15870        match &args[0] {
15871            Value::String(s) => {
15872                // Various date formats
15873                let patterns = vec![
15874                    r"\d{4}-\d{2}-\d{2}", // 2024-01-15
15875                    r"\d{2}/\d{2}/\d{4}", // 01/15/2024
15876                    r"\d{2}-\d{2}-\d{4}", // 01-15-2024
15877                    r"(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[a-z]*\s+\d{1,2},?\s+\d{4}",
15878                    r"\d{1,2}\s+(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[a-z]*\s+\d{4}",
15879                ];
15880                let mut dates = Vec::new();
15881                for pattern in patterns {
15882                    if let Ok(re) = Regex::new(pattern) {
15883                        for m in re.find_iter(s) {
15884                            dates.push(Value::String(Rc::new(m.as_str().to_string())));
15885                        }
15886                    }
15887                }
15888                Ok(Value::Array(Rc::new(RefCell::new(dates))))
15889            }
15890            _ => Err(RuntimeError::new("extract_dates() requires string")),
15891        }
15892    });
15893
15894    // extract_money - extract monetary values
15895    define(interp, "extract_money", Some(1), |_, args| match &args[0] {
15896        Value::String(s) => {
15897            let re = Regex::new(r"[$€£¥]\s*\d+(?:,\d{3})*(?:\.\d{2})?|\d+(?:,\d{3})*(?:\.\d{2})?\s*(?:dollars?|euros?|pounds?|USD|EUR|GBP)").unwrap();
15898            let money: Vec<Value> = re
15899                .find_iter(s)
15900                .map(|m| Value::String(Rc::new(m.as_str().to_string())))
15901                .collect();
15902            Ok(Value::Array(Rc::new(RefCell::new(money))))
15903        }
15904        _ => Err(RuntimeError::new("extract_money() requires string")),
15905    });
15906
15907    // extract_hashtags - extract hashtags
15908    define(interp, "extract_hashtags", Some(1), |_, args| {
15909        match &args[0] {
15910            Value::String(s) => {
15911                let re = Regex::new(r"#\w+").unwrap();
15912                let tags: Vec<Value> = re
15913                    .find_iter(s)
15914                    .map(|m| Value::String(Rc::new(m.as_str().to_string())))
15915                    .collect();
15916                Ok(Value::Array(Rc::new(RefCell::new(tags))))
15917            }
15918            _ => Err(RuntimeError::new("extract_hashtags() requires string")),
15919        }
15920    });
15921
15922    // extract_mentions - extract @mentions
15923    define(interp, "extract_mentions", Some(1), |_, args| {
15924        match &args[0] {
15925            Value::String(s) => {
15926                let re = Regex::new(r"@\w+").unwrap();
15927                let mentions: Vec<Value> = re
15928                    .find_iter(s)
15929                    .map(|m| Value::String(Rc::new(m.as_str().to_string())))
15930                    .collect();
15931                Ok(Value::Array(Rc::new(RefCell::new(mentions))))
15932            }
15933            _ => Err(RuntimeError::new("extract_mentions() requires string")),
15934        }
15935    });
15936
15937    // extract_numbers - extract all numbers
15938    define(interp, "extract_numbers", Some(1), |_, args| {
15939        match &args[0] {
15940            Value::String(s) => {
15941                let re = Regex::new(r"-?\d+(?:,\d{3})*(?:\.\d+)?").unwrap();
15942                let numbers: Vec<Value> = re
15943                    .find_iter(s)
15944                    .filter_map(|m| {
15945                        let num_str = m.as_str().replace(",", "");
15946                        if let Ok(n) = num_str.parse::<f64>() {
15947                            Some(Value::Float(n))
15948                        } else {
15949                            None
15950                        }
15951                    })
15952                    .collect();
15953                Ok(Value::Array(Rc::new(RefCell::new(numbers))))
15954            }
15955            _ => Err(RuntimeError::new("extract_numbers() requires string")),
15956        }
15957    });
15958
15959    // extract_entities - extract likely named entities (capitalized words)
15960    define(interp, "extract_entities", Some(1), |_, args| {
15961        match &args[0] {
15962            Value::String(s) => {
15963                // Simple heuristic: capitalized words not at sentence start
15964                let re = Regex::new(r"(?:[.!?]\s+)?([A-Z][a-z]+(?:\s+[A-Z][a-z]+)*)").unwrap();
15965                let mut entities = std::collections::HashSet::new();
15966                for cap in re.captures_iter(s) {
15967                    if let Some(m) = cap.get(1) {
15968                        let entity = m.as_str().to_string();
15969                        // Filter out common sentence starters
15970                        let starters = [
15971                            "The", "A", "An", "This", "That", "It", "I", "We", "They", "He", "She",
15972                        ];
15973                        if !starters.contains(&entity.as_str()) {
15974                            entities.insert(entity);
15975                        }
15976                    }
15977                }
15978                let results: Vec<Value> = entities
15979                    .into_iter()
15980                    .map(|e| Value::String(Rc::new(e)))
15981                    .collect();
15982                Ok(Value::Array(Rc::new(RefCell::new(results))))
15983            }
15984            _ => Err(RuntimeError::new("extract_entities() requires string")),
15985        }
15986    });
15987
15988    // =========================================================================
15989    // TEXT EMBEDDINGS (Hash-based, no ML required)
15990    // =========================================================================
15991
15992    // text_hash_vector - create a simple hash-based embedding
15993    define(interp, "text_hash_vector", Some(2), |_, args| {
15994        match (&args[0], &args[1]) {
15995            (Value::String(s), Value::Int(dims)) => {
15996                let dims = *dims as usize;
15997                let mut vector = vec![0.0f64; dims];
15998
15999                // Hash each word and add to vector
16000                for word in s.to_lowercase().split_whitespace() {
16001                    let hash = compute_hash(word, 0);
16002                    let idx = (hash as usize) % dims;
16003                    vector[idx] += 1.0;
16004                }
16005
16006                // Normalize
16007                let magnitude: f64 = vector.iter().map(|x| x * x).sum::<f64>().sqrt();
16008                if magnitude > 0.0 {
16009                    for v in vector.iter_mut() {
16010                        *v /= magnitude;
16011                    }
16012                }
16013
16014                let values: Vec<Value> = vector.into_iter().map(Value::Float).collect();
16015                Ok(Value::Array(Rc::new(RefCell::new(values))))
16016            }
16017            _ => Err(RuntimeError::new(
16018                "text_hash_vector() requires string and dimensions",
16019            )),
16020        }
16021    });
16022
16023    // text_fingerprint - create a compact fingerprint of text
16024    define(interp, "text_fingerprint", Some(1), |_, args| {
16025        match &args[0] {
16026            Value::String(s) => {
16027                // Create 64-bit fingerprint using multiple hashes
16028                let lower = s.to_lowercase();
16029                let words: Vec<&str> = lower.split_whitespace().collect();
16030
16031                let mut fp: u64 = 0;
16032                for (i, word) in words.iter().enumerate() {
16033                    let h = compute_hash(word, i as u64);
16034                    fp ^= h.rotate_left((i % 64) as u32);
16035                }
16036
16037                Ok(Value::String(Rc::new(format!("{:016x}", fp))))
16038            }
16039            _ => Err(RuntimeError::new("text_fingerprint() requires string")),
16040        }
16041    });
16042
16043    // cosine_similarity - compute cosine similarity between two vectors
16044    define(interp, "cosine_similarity", Some(2), |_, args| {
16045        match (&args[0], &args[1]) {
16046            (Value::Array(a), Value::Array(b)) => {
16047                let a_ref = a.borrow();
16048                let b_ref = b.borrow();
16049
16050                if a_ref.len() != b_ref.len() {
16051                    return Err(RuntimeError::new("Vectors must have same length"));
16052                }
16053
16054                let mut dot = 0.0;
16055                let mut mag_a = 0.0;
16056                let mut mag_b = 0.0;
16057
16058                for (va, vb) in a_ref.iter().zip(b_ref.iter()) {
16059                    let fa = match va {
16060                        Value::Float(f) => *f,
16061                        Value::Int(i) => *i as f64,
16062                        _ => continue,
16063                    };
16064                    let fb = match vb {
16065                        Value::Float(f) => *f,
16066                        Value::Int(i) => *i as f64,
16067                        _ => continue,
16068                    };
16069                    dot += fa * fb;
16070                    mag_a += fa * fa;
16071                    mag_b += fb * fb;
16072                }
16073
16074                let denom = (mag_a.sqrt()) * (mag_b.sqrt());
16075                if denom == 0.0 {
16076                    Ok(Value::Float(0.0))
16077                } else {
16078                    Ok(Value::Float(dot / denom))
16079                }
16080            }
16081            _ => Err(RuntimeError::new("cosine_similarity() requires two arrays")),
16082        }
16083    });
16084
16085    // text_similarity_embedding - compare texts using hash embeddings
16086    define(interp, "text_similarity_embedding", Some(2), |_, args| {
16087        match (&args[0], &args[1]) {
16088            (Value::String(a), Value::String(b)) => {
16089                let dims = 128;
16090
16091                // Create vectors for both texts
16092                let vec_a = create_hash_vector(a, dims);
16093                let vec_b = create_hash_vector(b, dims);
16094
16095                // Compute cosine similarity
16096                let mut dot = 0.0;
16097                let mut mag_a = 0.0;
16098                let mut mag_b = 0.0;
16099
16100                for i in 0..dims {
16101                    dot += vec_a[i] * vec_b[i];
16102                    mag_a += vec_a[i] * vec_a[i];
16103                    mag_b += vec_b[i] * vec_b[i];
16104                }
16105
16106                let denom = (mag_a.sqrt()) * (mag_b.sqrt());
16107                if denom == 0.0 {
16108                    Ok(Value::Float(0.0))
16109                } else {
16110                    Ok(Value::Float(dot / denom))
16111                }
16112            }
16113            _ => Err(RuntimeError::new(
16114                "text_similarity_embedding() requires two strings",
16115            )),
16116        }
16117    });
16118
16119    // =========================================================================
16120    // READABILITY METRICS
16121    // =========================================================================
16122
16123    // flesch_reading_ease - Flesch Reading Ease score
16124    define(
16125        interp,
16126        "flesch_reading_ease",
16127        Some(1),
16128        |_, args| match &args[0] {
16129            Value::String(s) => {
16130                let (words, sentences, syllables) = count_text_stats(s);
16131                if words == 0 || sentences == 0 {
16132                    return Ok(Value::Float(0.0));
16133                }
16134                let score = 206.835
16135                    - 1.015 * (words as f64 / sentences as f64)
16136                    - 84.6 * (syllables as f64 / words as f64);
16137                Ok(Value::Float(score.max(0.0).min(100.0)))
16138            }
16139            _ => Err(RuntimeError::new("flesch_reading_ease() requires string")),
16140        },
16141    );
16142
16143    // flesch_kincaid_grade - Flesch-Kincaid Grade Level
16144    define(
16145        interp,
16146        "flesch_kincaid_grade",
16147        Some(1),
16148        |_, args| match &args[0] {
16149            Value::String(s) => {
16150                let (words, sentences, syllables) = count_text_stats(s);
16151                if words == 0 || sentences == 0 {
16152                    return Ok(Value::Float(0.0));
16153                }
16154                let grade = 0.39 * (words as f64 / sentences as f64)
16155                    + 11.8 * (syllables as f64 / words as f64)
16156                    - 15.59;
16157                Ok(Value::Float(grade.max(0.0)))
16158            }
16159            _ => Err(RuntimeError::new("flesch_kincaid_grade() requires string")),
16160        },
16161    );
16162
16163    // automated_readability_index - ARI score
16164    define(
16165        interp,
16166        "automated_readability_index",
16167        Some(1),
16168        |_, args| match &args[0] {
16169            Value::String(s) => {
16170                let chars: usize = s.chars().filter(|c| c.is_alphanumeric()).count();
16171                let words: usize = s.split_whitespace().count();
16172                let sentences: usize = s
16173                    .matches(|c| c == '.' || c == '!' || c == '?')
16174                    .count()
16175                    .max(1);
16176
16177                if words == 0 {
16178                    return Ok(Value::Float(0.0));
16179                }
16180
16181                let ari = 4.71 * (chars as f64 / words as f64)
16182                    + 0.5 * (words as f64 / sentences as f64)
16183                    - 21.43;
16184                Ok(Value::Float(ari.max(0.0)))
16185            }
16186            _ => Err(RuntimeError::new(
16187                "automated_readability_index() requires string",
16188            )),
16189        },
16190    );
16191
16192    // reading_time - estimated reading time in minutes
16193    define(interp, "reading_time", Some(1), |_, args| {
16194        match &args[0] {
16195            Value::String(s) => {
16196                let words = s.split_whitespace().count();
16197                let minutes = words as f64 / 200.0; // Average reading speed
16198                Ok(Value::Float(minutes))
16199            }
16200            _ => Err(RuntimeError::new("reading_time() requires string")),
16201        }
16202    });
16203
16204    // speaking_time - estimated speaking time in minutes
16205    define(interp, "speaking_time", Some(1), |_, args| {
16206        match &args[0] {
16207            Value::String(s) => {
16208                let words = s.split_whitespace().count();
16209                let minutes = words as f64 / 150.0; // Average speaking speed
16210                Ok(Value::Float(minutes))
16211            }
16212            _ => Err(RuntimeError::new("speaking_time() requires string")),
16213        }
16214    });
16215}
16216
16217// =============================================================================
16218// HELPER FUNCTIONS FOR TEXT INTELLIGENCE
16219// =============================================================================
16220
16221/// VADER-style sentiment computation
16222fn compute_vader_sentiment(s: &str) -> (f64, f64, f64, f64) {
16223    // Sentiment lexicon with intensity
16224    let positive_words: Vec<(&str, f64)> = vec![
16225        ("love", 3.0),
16226        ("loved", 3.0),
16227        ("loving", 3.0),
16228        ("excellent", 3.0),
16229        ("amazing", 3.0),
16230        ("fantastic", 3.0),
16231        ("wonderful", 3.0),
16232        ("great", 2.5),
16233        ("awesome", 2.5),
16234        ("brilliant", 2.5),
16235        ("superb", 2.5),
16236        ("good", 2.0),
16237        ("nice", 2.0),
16238        ("pleasant", 2.0),
16239        ("happy", 2.0),
16240        ("like", 1.5),
16241        ("enjoy", 1.5),
16242        ("fine", 1.5),
16243        ("okay", 1.0),
16244        ("best", 3.0),
16245        ("perfect", 3.0),
16246        ("beautiful", 2.5),
16247        ("delightful", 2.5),
16248        ("excited", 2.5),
16249        ("thrilled", 3.0),
16250        ("glad", 2.0),
16251        ("pleased", 2.0),
16252    ];
16253
16254    let negative_words: Vec<(&str, f64)> = vec![
16255        ("hate", 3.0),
16256        ("hated", 3.0),
16257        ("hating", 3.0),
16258        ("terrible", 3.0),
16259        ("horrible", 3.0),
16260        ("awful", 3.0),
16261        ("disgusting", 3.0),
16262        ("bad", 2.5),
16263        ("poor", 2.5),
16264        ("worst", 3.0),
16265        ("pathetic", 2.5),
16266        ("sad", 2.0),
16267        ("angry", 2.5),
16268        ("upset", 2.0),
16269        ("disappointed", 2.0),
16270        ("dislike", 1.5),
16271        ("annoying", 2.0),
16272        ("boring", 1.5),
16273        ("mediocre", 1.0),
16274        ("ugly", 2.5),
16275        ("stupid", 2.5),
16276        ("dumb", 2.0),
16277        ("useless", 2.5),
16278        ("painful", 2.5),
16279        ("miserable", 3.0),
16280        ("depressing", 2.5),
16281        ("frustrating", 2.0),
16282    ];
16283
16284    // Intensity modifiers
16285    let boosters = vec![
16286        "very",
16287        "really",
16288        "extremely",
16289        "absolutely",
16290        "incredibly",
16291        "totally",
16292        "so",
16293    ];
16294    let dampeners = vec![
16295        "somewhat", "slightly", "a bit", "kind of", "sort of", "barely",
16296    ];
16297
16298    let lower = s.to_lowercase();
16299    let words: Vec<&str> = lower.split_whitespace().collect();
16300
16301    let mut pos_score = 0.0;
16302    let mut neg_score = 0.0;
16303    let mut word_count = 0;
16304
16305    for (i, word) in words.iter().enumerate() {
16306        let mut modifier = 1.0;
16307
16308        // Check for boosters/dampeners before this word
16309        if i > 0 {
16310            if boosters.contains(&words[i - 1]) {
16311                modifier = 1.5;
16312            } else if dampeners.iter().any(|d| words[i - 1].contains(d)) {
16313                modifier = 0.5;
16314            }
16315        }
16316
16317        // Check for negation
16318        let negated = i > 0
16319            && [
16320                "not",
16321                "no",
16322                "never",
16323                "neither",
16324                "don't",
16325                "doesn't",
16326                "didn't",
16327                "won't",
16328                "wouldn't",
16329                "couldn't",
16330                "shouldn't",
16331            ]
16332            .contains(&words[i - 1]);
16333
16334        if let Some((_, score)) = positive_words.iter().find(|(w, _)| w == word) {
16335            if negated {
16336                neg_score += score * modifier;
16337            } else {
16338                pos_score += score * modifier;
16339            }
16340            word_count += 1;
16341        } else if let Some((_, score)) = negative_words.iter().find(|(w, _)| w == word) {
16342            if negated {
16343                pos_score += score * modifier * 0.5; // Negated negative is mildly positive
16344            } else {
16345                neg_score += score * modifier;
16346            }
16347            word_count += 1;
16348        }
16349    }
16350
16351    // Normalize scores
16352    let total = pos_score + neg_score;
16353    let (pos_norm, neg_norm) = if total > 0.0 {
16354        (pos_score / total, neg_score / total)
16355    } else {
16356        (0.0, 0.0)
16357    };
16358
16359    let neutral = 1.0 - pos_norm - neg_norm;
16360
16361    // Compound score: normalized to [-1, 1]
16362    let compound = if word_count > 0 {
16363        ((pos_score - neg_score) / (word_count as f64 * 3.0))
16364            .max(-1.0)
16365            .min(1.0)
16366    } else {
16367        0.0
16368    };
16369
16370    (pos_norm, neg_norm, neutral.max(0.0), compound)
16371}
16372
16373/// Detect specific emotions
16374fn compute_emotions(s: &str) -> HashMap<String, f64> {
16375    let emotion_words: Vec<(&str, &str)> = vec![
16376        // Joy
16377        ("happy", "joy"),
16378        ("joyful", "joy"),
16379        ("delighted", "joy"),
16380        ("cheerful", "joy"),
16381        ("excited", "joy"),
16382        ("thrilled", "joy"),
16383        ("ecstatic", "joy"),
16384        ("elated", "joy"),
16385        // Sadness
16386        ("sad", "sadness"),
16387        ("unhappy", "sadness"),
16388        ("depressed", "sadness"),
16389        ("miserable", "sadness"),
16390        ("gloomy", "sadness"),
16391        ("heartbroken", "sadness"),
16392        ("sorrowful", "sadness"),
16393        ("melancholy", "sadness"),
16394        // Anger
16395        ("angry", "anger"),
16396        ("furious", "anger"),
16397        ("enraged", "anger"),
16398        ("irritated", "anger"),
16399        ("annoyed", "anger"),
16400        ("outraged", "anger"),
16401        ("livid", "anger"),
16402        ("mad", "anger"),
16403        // Fear
16404        ("afraid", "fear"),
16405        ("scared", "fear"),
16406        ("terrified", "fear"),
16407        ("frightened", "fear"),
16408        ("anxious", "fear"),
16409        ("worried", "fear"),
16410        ("nervous", "fear"),
16411        ("panicked", "fear"),
16412        // Surprise
16413        ("surprised", "surprise"),
16414        ("amazed", "surprise"),
16415        ("astonished", "surprise"),
16416        ("shocked", "surprise"),
16417        ("stunned", "surprise"),
16418        ("startled", "surprise"),
16419        ("bewildered", "surprise"),
16420        // Disgust
16421        ("disgusted", "disgust"),
16422        ("revolted", "disgust"),
16423        ("repulsed", "disgust"),
16424        ("sickened", "disgust"),
16425        ("nauseated", "disgust"),
16426        ("appalled", "disgust"),
16427        // Trust
16428        ("trust", "trust"),
16429        ("confident", "trust"),
16430        ("secure", "trust"),
16431        ("reliable", "trust"),
16432        ("faithful", "trust"),
16433        ("loyal", "trust"),
16434        // Anticipation
16435        ("eager", "anticipation"),
16436        ("hopeful", "anticipation"),
16437        ("expectant", "anticipation"),
16438        ("looking forward", "anticipation"),
16439        ("excited", "anticipation"),
16440    ];
16441
16442    let lower = s.to_lowercase();
16443    let mut counts: HashMap<String, f64> = HashMap::new();
16444
16445    for (word, emotion) in emotion_words {
16446        if lower.contains(word) {
16447            *counts.entry(emotion.to_string()).or_insert(0.0) += 1.0;
16448        }
16449    }
16450
16451    // Normalize
16452    let total: f64 = counts.values().sum();
16453    if total > 0.0 {
16454        for v in counts.values_mut() {
16455            *v /= total;
16456        }
16457    }
16458
16459    counts
16460}
16461
16462/// Compute text intensity
16463fn compute_intensity(s: &str) -> f64 {
16464    let intensifiers = vec![
16465        ("very", 1.5),
16466        ("really", 1.5),
16467        ("extremely", 2.0),
16468        ("incredibly", 2.0),
16469        ("absolutely", 2.0),
16470        ("totally", 1.5),
16471        ("completely", 1.5),
16472        ("utterly", 2.0),
16473        ("so", 1.3),
16474        ("such", 1.3),
16475        ("quite", 1.2),
16476        ("rather", 1.1),
16477    ];
16478
16479    let exclamation_boost = 0.5;
16480    let caps_boost = 0.3;
16481
16482    let lower = s.to_lowercase();
16483    let mut score = 1.0;
16484
16485    for (word, boost) in intensifiers {
16486        if lower.contains(word) {
16487            score *= boost;
16488        }
16489    }
16490
16491    // Check for exclamation marks
16492    let exclamations = s.matches('!').count();
16493    score += exclamations as f64 * exclamation_boost;
16494
16495    // Check for ALL CAPS words
16496    let caps_words = s
16497        .split_whitespace()
16498        .filter(|w| w.len() > 2 && w.chars().all(|c| c.is_uppercase()))
16499        .count();
16500    score += caps_words as f64 * caps_boost;
16501
16502    score.min(5.0)
16503}
16504
16505/// Detect sarcasm markers
16506fn compute_sarcasm_score(s: &str) -> (f64, f64, Vec<String>) {
16507    let mut markers = Vec::new();
16508    let mut score: f64 = 0.0;
16509
16510    let lower = s.to_lowercase();
16511
16512    // Explicit sarcasm markers
16513    let explicit = vec![
16514        "/s",
16515        "not!",
16516        "yeah right",
16517        "sure thing",
16518        "oh really",
16519        "oh great",
16520        "wow, just wow",
16521        "thanks a lot",
16522        "how wonderful",
16523        "isn't that special",
16524        "clearly",
16525        "obviously",
16526        "shocking",
16527        "no way",
16528        "what a surprise",
16529    ];
16530
16531    for marker in &explicit {
16532        if lower.contains(marker) {
16533            markers.push(format!("explicit: {}", marker));
16534            score += 0.4;
16535        }
16536    }
16537
16538    // Hyperbolic expressions
16539    let hyperbolic = vec![
16540        "best thing ever",
16541        "worst thing ever",
16542        "literally dying",
16543        "absolutely perfect",
16544        "world's greatest",
16545        "totally awesome",
16546        "so much fun",
16547        "couldn't be happier",
16548    ];
16549
16550    for h in &hyperbolic {
16551        if lower.contains(h) {
16552            markers.push(format!("hyperbole: {}", h));
16553            score += 0.3;
16554        }
16555    }
16556
16557    // Positive-negative contradiction patterns
16558    let has_positive = ["great", "wonderful", "amazing", "love", "best", "awesome"]
16559        .iter()
16560        .any(|w| lower.contains(w));
16561    let has_negative_context = ["but", "however", "although", "except", "unfortunately"]
16562        .iter()
16563        .any(|w| lower.contains(w));
16564
16565    if has_positive && has_negative_context {
16566        markers.push("positive-negative contrast".to_string());
16567        score += 0.25;
16568    }
16569
16570    // Quotation marks around positive words (air quotes)
16571    let quote_pattern = Regex::new(r#"["'](\w+)["']"#).unwrap();
16572    for cap in quote_pattern.captures_iter(s) {
16573        if let Some(m) = cap.get(1) {
16574            let word = m.as_str().to_lowercase();
16575            if [
16576                "great",
16577                "wonderful",
16578                "helpful",
16579                "useful",
16580                "smart",
16581                "genius",
16582                "brilliant",
16583            ]
16584            .contains(&word.as_str())
16585            {
16586                markers.push(format!("air quotes: \"{}\"", word));
16587                score += 0.35;
16588            }
16589        }
16590    }
16591
16592    // Excessive punctuation
16593    if s.contains("...") || s.contains("!!!") || s.contains("???") {
16594        markers.push("excessive punctuation".to_string());
16595        score += 0.15;
16596    }
16597
16598    // Calculate confidence based on number of markers
16599    let confidence = if markers.is_empty() {
16600        0.0
16601    } else {
16602        (markers.len() as f64 * 0.25).min(1.0)
16603    };
16604
16605    (score.min(1.0), confidence, markers)
16606}
16607
16608/// Detect irony patterns
16609fn compute_irony_score(s: &str) -> f64 {
16610    let mut score: f64 = 0.0;
16611    let lower = s.to_lowercase();
16612
16613    // Situational irony markers
16614    let irony_phrases = vec![
16615        "of course",
16616        "as expected",
16617        "naturally",
16618        "predictably",
16619        "who would have thought",
16620        "surprise surprise",
16621        "go figure",
16622        "typical",
16623        "as usual",
16624        "yet again",
16625        "once again",
16626    ];
16627
16628    for phrase in irony_phrases {
16629        if lower.contains(phrase) {
16630            score += 0.2;
16631        }
16632    }
16633
16634    // Contrast indicators
16635    if lower.contains("but") || lower.contains("yet") || lower.contains("however") {
16636        score += 0.1;
16637    }
16638
16639    // Rhetorical questions
16640    if s.contains('?')
16641        && (lower.starts_with("isn't")
16642            || lower.starts_with("aren't")
16643            || lower.starts_with("doesn't")
16644            || lower.starts_with("don't")
16645            || lower.contains("right?")
16646            || lower.contains("isn't it"))
16647    {
16648        score += 0.25;
16649    }
16650
16651    score.min(1.0)
16652}
16653
16654/// Create hash-based vector for text
16655fn create_hash_vector(s: &str, dims: usize) -> Vec<f64> {
16656    let mut vector = vec![0.0f64; dims];
16657
16658    for word in s.to_lowercase().split_whitespace() {
16659        let hash = compute_hash(word, 0);
16660        let idx = (hash as usize) % dims;
16661        vector[idx] += 1.0;
16662    }
16663
16664    // Normalize
16665    let magnitude: f64 = vector.iter().map(|x| x * x).sum::<f64>().sqrt();
16666    if magnitude > 0.0 {
16667        for v in vector.iter_mut() {
16668            *v /= magnitude;
16669        }
16670    }
16671
16672    vector
16673}
16674
16675/// Count text statistics for readability
16676fn count_text_stats(s: &str) -> (usize, usize, usize) {
16677    let words: Vec<&str> = s.split_whitespace().collect();
16678    let word_count = words.len();
16679    let sentence_count = s
16680        .matches(|c| c == '.' || c == '!' || c == '?')
16681        .count()
16682        .max(1);
16683
16684    let mut syllable_count = 0;
16685    for word in &words {
16686        syllable_count += count_syllables(word);
16687    }
16688
16689    (word_count, sentence_count, syllable_count)
16690}
16691
16692/// Count syllables in a word (English approximation)
16693fn count_syllables(word: &str) -> usize {
16694    let word = word.to_lowercase();
16695    let vowels = ['a', 'e', 'i', 'o', 'u', 'y'];
16696    let mut count = 0;
16697    let mut prev_was_vowel = false;
16698
16699    for c in word.chars() {
16700        let is_vowel = vowels.contains(&c);
16701        if is_vowel && !prev_was_vowel {
16702            count += 1;
16703        }
16704        prev_was_vowel = is_vowel;
16705    }
16706
16707    // Adjust for silent e
16708    if word.ends_with('e') && count > 1 {
16709        count -= 1;
16710    }
16711
16712    count.max(1)
16713}
16714
16715/// Compute American Soundex encoding
16716fn compute_soundex(s: &str) -> String {
16717    if s.is_empty() {
16718        return "0000".to_string();
16719    }
16720
16721    let s = s.to_uppercase();
16722    let chars: Vec<char> = s.chars().filter(|c| c.is_ascii_alphabetic()).collect();
16723
16724    if chars.is_empty() {
16725        return "0000".to_string();
16726    }
16727
16728    let first = chars[0];
16729    let mut code = String::new();
16730    code.push(first);
16731
16732    let get_code = |c: char| -> char {
16733        match c {
16734            'B' | 'F' | 'P' | 'V' => '1',
16735            'C' | 'G' | 'J' | 'K' | 'Q' | 'S' | 'X' | 'Z' => '2',
16736            'D' | 'T' => '3',
16737            'L' => '4',
16738            'M' | 'N' => '5',
16739            'R' => '6',
16740            _ => '0',
16741        }
16742    };
16743
16744    let mut prev_code = get_code(first);
16745
16746    for &c in chars.iter().skip(1) {
16747        let curr_code = get_code(c);
16748        if curr_code != '0' && curr_code != prev_code {
16749            code.push(curr_code);
16750            if code.len() == 4 {
16751                break;
16752            }
16753        }
16754        prev_code = curr_code;
16755    }
16756
16757    while code.len() < 4 {
16758        code.push('0');
16759    }
16760
16761    code
16762}
16763
16764/// Compute Metaphone encoding
16765fn compute_metaphone(s: &str) -> String {
16766    let s = s.to_uppercase();
16767    let chars: Vec<char> = s.chars().filter(|c| c.is_ascii_alphabetic()).collect();
16768
16769    if chars.is_empty() {
16770        return String::new();
16771    }
16772
16773    let mut result = String::new();
16774    let mut i = 0;
16775
16776    // Skip initial KN, GN, PN, AE, WR
16777    if chars.len() >= 2 {
16778        let prefix: String = chars[0..2].iter().collect();
16779        if ["KN", "GN", "PN", "AE", "WR"].contains(&prefix.as_str()) {
16780            i = 1;
16781        }
16782    }
16783
16784    while i < chars.len() && result.len() < 6 {
16785        let c = chars[i];
16786        let prev = if i > 0 { Some(chars[i - 1]) } else { None };
16787        let next = chars.get(i + 1).copied();
16788
16789        let code = match c {
16790            'A' | 'E' | 'I' | 'O' | 'U' => {
16791                if i == 0 {
16792                    Some(c)
16793                } else {
16794                    None
16795                }
16796            }
16797            'B' => {
16798                if prev != Some('M') || i == chars.len() - 1 {
16799                    Some('B')
16800                } else {
16801                    None
16802                }
16803            }
16804            'C' => {
16805                if next == Some('H') {
16806                    Some('X')
16807                } else if matches!(next, Some('I') | Some('E') | Some('Y')) {
16808                    Some('S')
16809                } else {
16810                    Some('K')
16811                }
16812            }
16813            'D' => {
16814                if next == Some('G')
16815                    && matches!(chars.get(i + 2), Some('E') | Some('I') | Some('Y'))
16816                {
16817                    Some('J')
16818                } else {
16819                    Some('T')
16820                }
16821            }
16822            'F' => Some('F'),
16823            'G' => {
16824                if next == Some('H')
16825                    && !matches!(
16826                        chars.get(i + 2),
16827                        Some('A') | Some('E') | Some('I') | Some('O') | Some('U')
16828                    )
16829                {
16830                    None
16831                } else if matches!(next, Some('N') | Some('E') | Some('I') | Some('Y')) {
16832                    Some('J')
16833                } else {
16834                    Some('K')
16835                }
16836            }
16837            'H' => {
16838                if matches!(
16839                    prev,
16840                    Some('A') | Some('E') | Some('I') | Some('O') | Some('U')
16841                ) {
16842                    None
16843                } else if matches!(
16844                    next,
16845                    Some('A') | Some('E') | Some('I') | Some('O') | Some('U')
16846                ) {
16847                    Some('H')
16848                } else {
16849                    None
16850                }
16851            }
16852            'J' => Some('J'),
16853            'K' => {
16854                if prev != Some('C') {
16855                    Some('K')
16856                } else {
16857                    None
16858                }
16859            }
16860            'L' => Some('L'),
16861            'M' => Some('M'),
16862            'N' => Some('N'),
16863            'P' => {
16864                if next == Some('H') {
16865                    Some('F')
16866                } else {
16867                    Some('P')
16868                }
16869            }
16870            'Q' => Some('K'),
16871            'R' => Some('R'),
16872            'S' => {
16873                if next == Some('H') {
16874                    Some('X')
16875                } else {
16876                    Some('S')
16877                }
16878            }
16879            'T' => {
16880                if next == Some('H') {
16881                    Some('0') // TH sound
16882                } else if next == Some('I') && matches!(chars.get(i + 2), Some('O') | Some('A')) {
16883                    Some('X')
16884                } else {
16885                    Some('T')
16886                }
16887            }
16888            'V' => Some('F'),
16889            'W' | 'Y' => {
16890                if matches!(
16891                    next,
16892                    Some('A') | Some('E') | Some('I') | Some('O') | Some('U')
16893                ) {
16894                    Some(c)
16895                } else {
16896                    None
16897                }
16898            }
16899            'X' => {
16900                result.push('K');
16901                Some('S')
16902            }
16903            'Z' => Some('S'),
16904            _ => None,
16905        };
16906
16907        if let Some(ch) = code {
16908            result.push(ch);
16909        }
16910
16911        // Skip double letters
16912        if next == Some(c) {
16913            i += 1;
16914        }
16915        i += 1;
16916    }
16917
16918    result
16919}
16920
16921/// Compute Cologne phonetic encoding (for German)
16922fn compute_cologne(s: &str) -> String {
16923    let s = s.to_uppercase();
16924    let chars: Vec<char> = s.chars().filter(|c| c.is_ascii_alphabetic()).collect();
16925
16926    if chars.is_empty() {
16927        return String::new();
16928    }
16929
16930    let mut result = String::new();
16931
16932    for (i, &c) in chars.iter().enumerate() {
16933        let prev = if i > 0 { Some(chars[i - 1]) } else { None };
16934        let next = chars.get(i + 1).copied();
16935
16936        let code = match c {
16937            'A' | 'E' | 'I' | 'O' | 'U' | 'J' | 'Y' => '0',
16938            'H' => continue,
16939            'B' | 'P' => '1',
16940            'D' | 'T' => {
16941                if matches!(next, Some('C') | Some('S') | Some('Z')) {
16942                    '8'
16943                } else {
16944                    '2'
16945                }
16946            }
16947            'F' | 'V' | 'W' => '3',
16948            'G' | 'K' | 'Q' => '4',
16949            'C' => {
16950                if i == 0 {
16951                    if matches!(
16952                        next,
16953                        Some('A')
16954                            | Some('H')
16955                            | Some('K')
16956                            | Some('L')
16957                            | Some('O')
16958                            | Some('Q')
16959                            | Some('R')
16960                            | Some('U')
16961                            | Some('X')
16962                    ) {
16963                        '4'
16964                    } else {
16965                        '8'
16966                    }
16967                } else if matches!(prev, Some('S') | Some('Z')) {
16968                    '8'
16969                } else if matches!(
16970                    next,
16971                    Some('A')
16972                        | Some('H')
16973                        | Some('K')
16974                        | Some('O')
16975                        | Some('Q')
16976                        | Some('U')
16977                        | Some('X')
16978                ) {
16979                    '4'
16980                } else {
16981                    '8'
16982                }
16983            }
16984            'X' => {
16985                if matches!(prev, Some('C') | Some('K') | Some('Q')) {
16986                    '8'
16987                } else {
16988                    result.push('4');
16989                    '8'
16990                }
16991            }
16992            'L' => '5',
16993            'M' | 'N' => '6',
16994            'R' => '7',
16995            'S' | 'Z' => '8',
16996            _ => continue,
16997        };
16998
16999        result.push(code);
17000    }
17001
17002    // Remove consecutive duplicates
17003    let mut deduped = String::new();
17004    let mut prev = None;
17005    for c in result.chars() {
17006        if prev != Some(c) {
17007            deduped.push(c);
17008        }
17009        prev = Some(c);
17010    }
17011
17012    // Remove leading zeros (except if all zeros)
17013    let trimmed: String = deduped.trim_start_matches('0').to_string();
17014    if trimmed.is_empty() {
17015        "0".to_string()
17016    } else {
17017        trimmed
17018    }
17019}
17020
17021/// Get stopwords for a language
17022fn get_stopwords(lang: &str) -> Vec<&'static str> {
17023    match lang {
17024        "en" | "english" => vec![
17025            "a", "an", "the", "and", "or", "but", "in", "on", "at", "to", "for", "of", "with",
17026            "by", "from", "as", "is", "was", "are", "were", "been", "be", "have", "has", "had",
17027            "do", "does", "did", "will", "would", "could", "should", "may", "might", "must",
17028            "shall", "can", "need", "it", "its", "this", "that", "these", "those", "i", "you",
17029            "he", "she", "we", "they", "me", "him", "her", "us", "them", "my", "your", "his",
17030            "her", "our", "their", "what", "which", "who", "whom", "whose", "when", "where", "why",
17031            "how", "all", "each", "every", "both", "few", "more", "most", "other", "some", "such",
17032            "no", "nor", "not", "only", "own", "same", "so", "than", "too", "very", "just", "also",
17033            "now",
17034        ],
17035        "de" | "german" => vec![
17036            "der", "die", "das", "den", "dem", "des", "ein", "eine", "einer", "einem", "einen",
17037            "und", "oder", "aber", "in", "auf", "an", "zu", "für", "von", "mit", "bei", "als",
17038            "ist", "war", "sind", "waren", "sein", "haben", "hat", "hatte", "werden", "wird",
17039            "wurde", "kann", "können", "muss", "müssen", "soll", "sollen", "will", "wollen", "es",
17040            "sie", "er", "wir", "ihr", "ich", "du", "man", "sich", "nicht", "auch", "nur", "noch",
17041            "schon", "mehr", "sehr", "so",
17042        ],
17043        "fr" | "french" => vec![
17044            "le", "la", "les", "un", "une", "des", "et", "ou", "mais", "dans", "sur", "à", "de",
17045            "pour", "par", "avec", "ce", "cette", "ces", "est", "sont", "était", "être", "avoir",
17046            "a", "ont", "avait", "je", "tu", "il", "elle", "nous", "vous", "ils", "elles", "on",
17047            "ne", "pas", "plus", "moins", "très", "aussi", "que", "qui",
17048        ],
17049        "es" | "spanish" => vec![
17050            "el", "la", "los", "las", "un", "una", "unos", "unas", "y", "o", "pero", "en", "de",
17051            "a", "para", "por", "con", "es", "son", "era", "ser", "estar", "tiene", "tienen", "yo",
17052            "tú", "él", "ella", "nosotros", "ustedes", "ellos", "ellas", "no", "sí", "muy", "más",
17053            "menos", "también", "que", "quien", "cual", "como", "cuando",
17054        ],
17055        "it" | "italian" => vec![
17056            "il", "lo", "la", "i", "gli", "le", "un", "uno", "una", "e", "o", "ma", "in", "di",
17057            "a", "da", "per", "con", "su", "tra", "fra", "è", "sono", "era", "erano", "essere",
17058            "avere", "ha", "hanno", "io", "tu", "lui", "lei", "noi", "voi", "loro", "mi", "ti",
17059            "ci", "non", "più", "molto", "anche", "come", "che", "chi", "quale", "questo",
17060            "quello", "quando", "dove", "perché", "se", "però",
17061        ],
17062        "pt" | "portuguese" => vec![
17063            "o", "a", "os", "as", "um", "uma", "uns", "umas", "e", "ou", "mas", "em", "de", "para",
17064            "por", "com", "sem", "sob", "sobre", "é", "são", "era", "eram", "ser", "estar", "ter",
17065            "tem", "têm", "eu", "tu", "ele", "ela", "nós", "vós", "eles", "elas", "me", "te",
17066            "não", "mais", "muito", "também", "como", "que", "quem", "qual", "este", "esse",
17067            "aquele", "quando", "onde", "porque", "se", "já",
17068        ],
17069        "nl" | "dutch" => vec![
17070            "de", "het", "een", "en", "of", "maar", "in", "op", "aan", "van", "voor", "met", "bij",
17071            "naar", "om", "te", "tot", "uit", "over", "is", "zijn", "was", "waren", "worden",
17072            "wordt", "werd", "hebben", "ik", "je", "jij", "hij", "zij", "wij", "jullie", "ze",
17073            "mij", "jou", "niet", "geen", "meer", "ook", "als", "dat", "die", "wat", "wie", "dit",
17074            "deze", "wanneer", "waar", "waarom", "hoe", "dan", "nog",
17075        ],
17076        "ru" | "russian" => vec![
17077            "и",
17078            "в",
17079            "на",
17080            "с",
17081            "к",
17082            "по",
17083            "за",
17084            "из",
17085            "у",
17086            "о",
17087            "от",
17088            "до",
17089            "для",
17090            "при",
17091            "без",
17092            "под",
17093            "над",
17094            "между",
17095            "через",
17096            "после",
17097            "это",
17098            "то",
17099            "что",
17100            "как",
17101            "так",
17102            "но",
17103            "а",
17104            "или",
17105            "если",
17106            "же",
17107            "я",
17108            "ты",
17109            "он",
17110            "она",
17111            "мы",
17112            "вы",
17113            "они",
17114            "его",
17115            "её",
17116            "их",
17117            "не",
17118            "ни",
17119            "да",
17120            "нет",
17121            "был",
17122            "была",
17123            "были",
17124            "быть",
17125            "есть",
17126            "все",
17127            "всё",
17128            "весь",
17129            "этот",
17130            "тот",
17131            "который",
17132            "когда",
17133            "где",
17134        ],
17135        "ar" | "arabic" => vec![
17136            "في",
17137            "من",
17138            "إلى",
17139            "على",
17140            "عن",
17141            "مع",
17142            "هذا",
17143            "هذه",
17144            "ذلك",
17145            "تلك",
17146            "التي",
17147            "الذي",
17148            "اللذان",
17149            "اللتان",
17150            "الذين",
17151            "اللاتي",
17152            "اللواتي",
17153            "هو",
17154            "هي",
17155            "هم",
17156            "هن",
17157            "أنا",
17158            "أنت",
17159            "نحن",
17160            "أنتم",
17161            "أنتن",
17162            "كان",
17163            "كانت",
17164            "كانوا",
17165            "يكون",
17166            "تكون",
17167            "ليس",
17168            "ليست",
17169            "ليسوا",
17170            "و",
17171            "أو",
17172            "ثم",
17173            "لكن",
17174            "بل",
17175            "إن",
17176            "أن",
17177            "لأن",
17178            "كي",
17179            "حتى",
17180            "ما",
17181            "لا",
17182            "قد",
17183            "كل",
17184            "بعض",
17185            "غير",
17186            "أي",
17187            "كيف",
17188            "متى",
17189            "أين",
17190        ],
17191        "zh" | "chinese" => vec![
17192            "的", "了", "是", "在", "有", "和", "与", "或", "但", "而", "我", "你", "他", "她",
17193            "它", "我们", "你们", "他们", "她们", "这", "那", "这个", "那个", "这些", "那些",
17194            "什么", "哪", "哪个", "不", "没", "没有", "很", "也", "都", "就", "才", "只", "还",
17195            "把", "被", "给", "从", "到", "为", "以", "因为", "所以", "如果", "会", "能", "可以",
17196            "要", "想", "应该", "必须", "可能", "一", "个",
17197        ],
17198        "ja" | "japanese" => vec![
17199            "の",
17200            "に",
17201            "は",
17202            "を",
17203            "た",
17204            "が",
17205            "で",
17206            "て",
17207            "と",
17208            "し",
17209            "れ",
17210            "さ",
17211            "ある",
17212            "いる",
17213            "も",
17214            "する",
17215            "から",
17216            "な",
17217            "こと",
17218            "として",
17219            "い",
17220            "や",
17221            "など",
17222            "なっ",
17223            "ない",
17224            "この",
17225            "ため",
17226            "その",
17227            "あっ",
17228            "よう",
17229            "また",
17230            "もの",
17231            "という",
17232            "あり",
17233            "まで",
17234            "られ",
17235            "なる",
17236            "へ",
17237            "か",
17238            "だ",
17239            "これ",
17240            "によって",
17241            "により",
17242            "おり",
17243            "より",
17244            "による",
17245            "ず",
17246            "なり",
17247            "られる",
17248            "において",
17249        ],
17250        "ko" | "korean" => vec![
17251            "이",
17252            "그",
17253            "저",
17254            "것",
17255            "수",
17256            "등",
17257            "들",
17258            "및",
17259            "에",
17260            "의",
17261            "가",
17262            "을",
17263            "를",
17264            "은",
17265            "는",
17266            "로",
17267            "으로",
17268            "와",
17269            "과",
17270            "도",
17271            "에서",
17272            "까지",
17273            "부터",
17274            "만",
17275            "뿐",
17276            "처럼",
17277            "같이",
17278            "보다",
17279            "하다",
17280            "있다",
17281            "되다",
17282            "없다",
17283            "않다",
17284            "이다",
17285            "아니다",
17286            "나",
17287            "너",
17288            "우리",
17289            "그들",
17290            "이것",
17291            "그것",
17292            "저것",
17293            "무엇",
17294            "어디",
17295            "언제",
17296            "왜",
17297            "어떻게",
17298            "누구",
17299            "어느",
17300            "모든",
17301            "각",
17302        ],
17303        "hi" | "hindi" => vec![
17304            "का",
17305            "के",
17306            "की",
17307            "में",
17308            "है",
17309            "हैं",
17310            "को",
17311            "से",
17312            "पर",
17313            "था",
17314            "थे",
17315            "थी",
17316            "और",
17317            "या",
17318            "लेकिन",
17319            "अगर",
17320            "तो",
17321            "भी",
17322            "ही",
17323            "यह",
17324            "वह",
17325            "इस",
17326            "उस",
17327            "ये",
17328            "वे",
17329            "जो",
17330            "कि",
17331            "क्या",
17332            "कैसे",
17333            "मैं",
17334            "तुम",
17335            "आप",
17336            "हम",
17337            "वे",
17338            "उन्हें",
17339            "उनके",
17340            "अपने",
17341            "नहीं",
17342            "न",
17343            "कुछ",
17344            "कोई",
17345            "सब",
17346            "बहुत",
17347            "कम",
17348            "ज्यादा",
17349            "होना",
17350            "करना",
17351            "जाना",
17352            "आना",
17353            "देना",
17354            "लेना",
17355            "रहना",
17356            "सकना",
17357        ],
17358        "tr" | "turkish" => vec![
17359            "bir",
17360            "ve",
17361            "bu",
17362            "da",
17363            "de",
17364            "için",
17365            "ile",
17366            "mi",
17367            "ne",
17368            "o",
17369            "var",
17370            "ben",
17371            "sen",
17372            "biz",
17373            "siz",
17374            "onlar",
17375            "ki",
17376            "ama",
17377            "çok",
17378            "daha",
17379            "gibi",
17380            "kadar",
17381            "sonra",
17382            "şey",
17383            "kendi",
17384            "bütün",
17385            "her",
17386            "bazı",
17387            "olan",
17388            "olarak",
17389            "değil",
17390            "ya",
17391            "hem",
17392            "veya",
17393            "ancak",
17394            "ise",
17395            "göre",
17396            "rağmen",
17397            "dolayı",
17398            "üzere",
17399            "karşı",
17400            "arasında",
17401            "olan",
17402            "oldu",
17403            "olur",
17404            "olmak",
17405            "etmek",
17406            "yapmak",
17407            "demek",
17408        ],
17409        "pl" | "polish" => vec![
17410            "i",
17411            "w",
17412            "z",
17413            "na",
17414            "do",
17415            "o",
17416            "że",
17417            "to",
17418            "nie",
17419            "się",
17420            "jest",
17421            "tak",
17422            "jak",
17423            "ale",
17424            "po",
17425            "co",
17426            "czy",
17427            "lub",
17428            "oraz",
17429            "ja",
17430            "ty",
17431            "on",
17432            "ona",
17433            "my",
17434            "wy",
17435            "oni",
17436            "one",
17437            "pan",
17438            "pani",
17439            "ten",
17440            "ta",
17441            "te",
17442            "tego",
17443            "tej",
17444            "tym",
17445            "tych",
17446            "który",
17447            "która",
17448            "być",
17449            "mieć",
17450            "móc",
17451            "musieć",
17452            "chcieć",
17453            "wiedzieć",
17454            "mówić",
17455            "bardzo",
17456            "tylko",
17457            "już",
17458            "jeszcze",
17459            "też",
17460            "więc",
17461            "jednak",
17462        ],
17463        "sv" | "swedish" => vec![
17464            "och", "i", "att", "det", "som", "en", "på", "är", "av", "för", "med", "till", "den",
17465            "har", "de", "inte", "om", "ett", "men", "jag", "du", "han", "hon", "vi", "ni", "de",
17466            "dem", "sig", "sin", "var", "från", "eller", "när", "kan", "ska", "så", "än", "nu",
17467            "också", "bara", "mycket", "mer", "andra", "detta", "sedan", "hade", "varit", "skulle",
17468            "vara", "bli", "blev", "blir", "göra",
17469        ],
17470        _ => vec![
17471            "a", "an", "the", "and", "or", "but", "in", "on", "at", "to", "for",
17472        ],
17473    }
17474}
17475
17476/// Simple hash function for MinHash
17477fn compute_hash(s: &str, seed: u64) -> u64 {
17478    let mut hash: u64 = seed.wrapping_mul(0x517cc1b727220a95);
17479    for b in s.bytes() {
17480        hash = hash.wrapping_mul(31).wrapping_add(b as u64);
17481    }
17482    hash
17483}
17484
17485// ============================================================================
17486// EMOTIONAL HOLOGRAM: Multi-dimensional affective projection with cultural awareness
17487// ============================================================================
17488//
17489// The Emotional Hologram is a unique Sigil concept that projects affect onto a
17490// normalized coordinate space, enabling:
17491// - Emotional distance calculations
17492// - Cross-cultural emotion mappings
17493// - Emotional fingerprinting and cryptographic signing
17494// - Dissonance detection (e.g., positive + sarcastic)
17495//
17496// Dimensions:
17497//   Valence     (-1 to +1): Negative to Positive sentiment
17498//   Arousal     (0 to 1):   Low to High intensity
17499//   Dominance   (0 to 1):   Submissive to Dominant (formality)
17500//   Authenticity(-1 to +1): Sincere to Ironic
17501//   Certainty   (0 to 1):   Low to High confidence
17502//   Emotion     (0-6):      Discrete emotion index (or -1 for none)
17503
17504fn register_hologram(interp: &mut Interpreter) {
17505    use crate::interpreter::{
17506        RuntimeAffect, RuntimeConfidence, RuntimeEmotion, RuntimeFormality, RuntimeIntensity,
17507        RuntimeSentiment,
17508    };
17509
17510    // emotional_hologram - project affect onto normalized coordinate space
17511    // Returns a map: { valence, arousal, dominance, authenticity, certainty, emotion_index }
17512    define(interp, "emotional_hologram", Some(1), |_, args| {
17513        let affect = match &args[0] {
17514            Value::Affective { affect, .. } => affect.clone(),
17515            _ => RuntimeAffect {
17516                sentiment: None,
17517                sarcasm: false,
17518                intensity: None,
17519                formality: None,
17520                emotion: None,
17521                confidence: None,
17522            },
17523        };
17524
17525        let mut hologram = std::collections::HashMap::new();
17526
17527        // Valence: sentiment mapped to -1, 0, +1
17528        let valence = match affect.sentiment {
17529            Some(RuntimeSentiment::Positive) => 1.0,
17530            Some(RuntimeSentiment::Negative) => -1.0,
17531            Some(RuntimeSentiment::Neutral) | None => 0.0,
17532        };
17533        hologram.insert("valence".to_string(), Value::Float(valence));
17534
17535        // Arousal: intensity mapped to 0, 0.33, 0.66, 1.0
17536        let arousal = match affect.intensity {
17537            Some(RuntimeIntensity::Down) => 0.25,
17538            None => 0.5,
17539            Some(RuntimeIntensity::Up) => 0.75,
17540            Some(RuntimeIntensity::Max) => 1.0,
17541        };
17542        hologram.insert("arousal".to_string(), Value::Float(arousal));
17543
17544        // Dominance: formality mapped to 0 (informal/submissive) to 1 (formal/dominant)
17545        let dominance = match affect.formality {
17546            Some(RuntimeFormality::Informal) => 0.25,
17547            None => 0.5,
17548            Some(RuntimeFormality::Formal) => 0.85,
17549        };
17550        hologram.insert("dominance".to_string(), Value::Float(dominance));
17551
17552        // Authenticity: -1 (ironic/sarcastic) to +1 (sincere)
17553        let authenticity = if affect.sarcasm { -0.9 } else { 0.9 };
17554        hologram.insert("authenticity".to_string(), Value::Float(authenticity));
17555
17556        // Certainty: confidence mapped to 0, 0.5, 1.0
17557        let certainty = match affect.confidence {
17558            Some(RuntimeConfidence::Low) => 0.2,
17559            None | Some(RuntimeConfidence::Medium) => 0.5,
17560            Some(RuntimeConfidence::High) => 0.9,
17561        };
17562        hologram.insert("certainty".to_string(), Value::Float(certainty));
17563
17564        // Emotion index: 0=joy, 1=sadness, 2=anger, 3=fear, 4=surprise, 5=love, -1=none
17565        let emotion_index = match affect.emotion {
17566            Some(RuntimeEmotion::Joy) => 0,
17567            Some(RuntimeEmotion::Sadness) => 1,
17568            Some(RuntimeEmotion::Anger) => 2,
17569            Some(RuntimeEmotion::Fear) => 3,
17570            Some(RuntimeEmotion::Surprise) => 4,
17571            Some(RuntimeEmotion::Love) => 5,
17572            None => -1,
17573        };
17574        hologram.insert("emotion_index".to_string(), Value::Int(emotion_index));
17575
17576        // Emotion name
17577        let emotion_name = match affect.emotion {
17578            Some(RuntimeEmotion::Joy) => "joy",
17579            Some(RuntimeEmotion::Sadness) => "sadness",
17580            Some(RuntimeEmotion::Anger) => "anger",
17581            Some(RuntimeEmotion::Fear) => "fear",
17582            Some(RuntimeEmotion::Surprise) => "surprise",
17583            Some(RuntimeEmotion::Love) => "love",
17584            None => "none",
17585        };
17586        hologram.insert(
17587            "emotion".to_string(),
17588            Value::String(Rc::new(emotion_name.to_string())),
17589        );
17590
17591        Ok(Value::Map(Rc::new(RefCell::new(hologram))))
17592    });
17593
17594    // emotional_distance - Euclidean distance between two emotional holograms
17595    define(interp, "emotional_distance", Some(2), |interp, args| {
17596        // Get holograms for both values
17597        let h1 = get_hologram_values(&args[0], interp)?;
17598        let h2 = get_hologram_values(&args[1], interp)?;
17599
17600        // Calculate Euclidean distance across dimensions
17601        let dist = ((h1.0 - h2.0).powi(2) +    // valence
17602                    (h1.1 - h2.1).powi(2) +    // arousal
17603                    (h1.2 - h2.2).powi(2) +    // dominance
17604                    (h1.3 - h2.3).powi(2) +    // authenticity
17605                    (h1.4 - h2.4).powi(2)) // certainty
17606        .sqrt();
17607
17608        Ok(Value::Float(dist))
17609    });
17610
17611    // emotional_similarity - cosine similarity between emotional states (0 to 1)
17612    define(interp, "emotional_similarity", Some(2), |interp, args| {
17613        let h1 = get_hologram_values(&args[0], interp)?;
17614        let h2 = get_hologram_values(&args[1], interp)?;
17615
17616        let dot = h1.0 * h2.0 + h1.1 * h2.1 + h1.2 * h2.2 + h1.3 * h2.3 + h1.4 * h2.4;
17617        let mag1 =
17618            (h1.0.powi(2) + h1.1.powi(2) + h1.2.powi(2) + h1.3.powi(2) + h1.4.powi(2)).sqrt();
17619        let mag2 =
17620            (h2.0.powi(2) + h2.1.powi(2) + h2.2.powi(2) + h2.3.powi(2) + h2.4.powi(2)).sqrt();
17621
17622        let similarity = if mag1 > 0.0 && mag2 > 0.0 {
17623            (dot / (mag1 * mag2) + 1.0) / 2.0 // Normalize to 0-1
17624        } else {
17625            0.5
17626        };
17627
17628        Ok(Value::Float(similarity))
17629    });
17630
17631    // emotional_dissonance - detect internal contradictions in affect
17632    // Returns score from 0 (coherent) to 1 (highly dissonant)
17633    define(interp, "emotional_dissonance", Some(1), |_, args| {
17634        let affect = match &args[0] {
17635            Value::Affective { affect, .. } => affect.clone(),
17636            _ => return Ok(Value::Float(0.0)),
17637        };
17638
17639        let mut dissonance: f64 = 0.0;
17640
17641        // Positive sentiment + sarcasm = dissonant
17642        if matches!(affect.sentiment, Some(RuntimeSentiment::Positive)) && affect.sarcasm {
17643            dissonance += 0.4;
17644        }
17645
17646        // Negative sentiment + sarcasm = less dissonant (double negative)
17647        if matches!(affect.sentiment, Some(RuntimeSentiment::Negative)) && affect.sarcasm {
17648            dissonance += 0.1;
17649        }
17650
17651        // High confidence + low intensity = mildly dissonant
17652        if matches!(affect.confidence, Some(RuntimeConfidence::High))
17653            && matches!(affect.intensity, Some(RuntimeIntensity::Down))
17654        {
17655            dissonance += 0.2;
17656        }
17657
17658        // Formal + intense emotion = dissonant
17659        if matches!(affect.formality, Some(RuntimeFormality::Formal)) {
17660            if matches!(
17661                affect.emotion,
17662                Some(RuntimeEmotion::Anger) | Some(RuntimeEmotion::Fear)
17663            ) {
17664                dissonance += 0.3;
17665            }
17666        }
17667
17668        // Joy/Love + Sadness/Fear indicators (based on sarcasm with positive)
17669        if matches!(
17670            affect.emotion,
17671            Some(RuntimeEmotion::Joy) | Some(RuntimeEmotion::Love)
17672        ) && affect.sarcasm
17673        {
17674            dissonance += 0.3;
17675        }
17676
17677        Ok(Value::Float(dissonance.min(1.0)))
17678    });
17679
17680    // emotional_fingerprint - cryptographic hash of emotional state
17681    // Creates a unique identifier for this exact emotional configuration
17682    define(interp, "emotional_fingerprint", Some(1), |interp, args| {
17683        let h = get_hologram_values(&args[0], interp)?;
17684
17685        // Create deterministic string representation
17686        let repr = format!(
17687            "hologram:v{:.4}:a{:.4}:d{:.4}:auth{:.4}:c{:.4}",
17688            h.0, h.1, h.2, h.3, h.4
17689        );
17690
17691        // Hash using BLAKE3
17692        let hash = blake3::hash(repr.as_bytes());
17693        Ok(Value::String(Rc::new(hash.to_hex().to_string())))
17694    });
17695
17696    // emotional_morph - interpolate between two emotional states
17697    // t=0 returns first state, t=1 returns second state
17698    define(interp, "emotional_morph", Some(3), |interp, args| {
17699        let h1 = get_hologram_values(&args[0], interp)?;
17700        let h2 = get_hologram_values(&args[1], interp)?;
17701        let t = match &args[2] {
17702            Value::Float(f) => f.max(0.0).min(1.0),
17703            Value::Int(i) => (*i as f64).max(0.0).min(1.0),
17704            _ => {
17705                return Err(RuntimeError::new(
17706                    "emotional_morph() requires numeric t value",
17707                ))
17708            }
17709        };
17710
17711        let mut result = std::collections::HashMap::new();
17712        result.insert(
17713            "valence".to_string(),
17714            Value::Float(h1.0 + (h2.0 - h1.0) * t),
17715        );
17716        result.insert(
17717            "arousal".to_string(),
17718            Value::Float(h1.1 + (h2.1 - h1.1) * t),
17719        );
17720        result.insert(
17721            "dominance".to_string(),
17722            Value::Float(h1.2 + (h2.2 - h1.2) * t),
17723        );
17724        result.insert(
17725            "authenticity".to_string(),
17726            Value::Float(h1.3 + (h2.3 - h1.3) * t),
17727        );
17728        result.insert(
17729            "certainty".to_string(),
17730            Value::Float(h1.4 + (h2.4 - h1.4) * t),
17731        );
17732
17733        Ok(Value::Map(Rc::new(RefCell::new(result))))
17734    });
17735
17736    // === Cultural Emotion Mappings ===
17737    // Map Sigil emotions to culturally-specific concepts
17738
17739    // cultural_emotion - get cultural equivalent of an emotion
17740    // Supported cultures: japanese, portuguese, german, danish, arabic, korean, russian, hindi
17741    define(interp, "cultural_emotion", Some(2), |_, args| {
17742        let emotion = match &args[0] {
17743            Value::Affective { affect, .. } => affect.emotion.clone(),
17744            Value::String(s) => match s.as_str() {
17745                "joy" => Some(RuntimeEmotion::Joy),
17746                "sadness" => Some(RuntimeEmotion::Sadness),
17747                "anger" => Some(RuntimeEmotion::Anger),
17748                "fear" => Some(RuntimeEmotion::Fear),
17749                "surprise" => Some(RuntimeEmotion::Surprise),
17750                "love" => Some(RuntimeEmotion::Love),
17751                _ => None,
17752            },
17753            _ => None,
17754        };
17755
17756        let culture = match &args[1] {
17757            Value::String(s) => s.to_lowercase(),
17758            _ => {
17759                return Err(RuntimeError::new(
17760                    "cultural_emotion() requires string culture",
17761                ))
17762            }
17763        };
17764
17765        let result = match (emotion, culture.as_str()) {
17766            // Japanese concepts
17767            (Some(RuntimeEmotion::Joy), "japanese" | "ja") => create_cultural_entry(
17768                "木漏れ日",
17769                "komorebi",
17770                "sunlight filtering through leaves - peaceful joy",
17771            ),
17772            (Some(RuntimeEmotion::Sadness), "japanese" | "ja") => create_cultural_entry(
17773                "物の哀れ",
17774                "mono no aware",
17775                "the pathos of things - bittersweet awareness of impermanence",
17776            ),
17777            (Some(RuntimeEmotion::Love), "japanese" | "ja") => create_cultural_entry(
17778                "甘え",
17779                "amae",
17780                "indulgent dependence on another's benevolence",
17781            ),
17782            (Some(RuntimeEmotion::Fear), "japanese" | "ja") => create_cultural_entry(
17783                "空気を読む",
17784                "kuuki wo yomu",
17785                "anxiety about reading the room",
17786            ),
17787
17788            // Portuguese concepts
17789            (Some(RuntimeEmotion::Sadness), "portuguese" | "pt") => create_cultural_entry(
17790                "saudade",
17791                "saudade",
17792                "melancholic longing for something or someone absent",
17793            ),
17794            (Some(RuntimeEmotion::Joy), "portuguese" | "pt") => {
17795                create_cultural_entry("alegria", "alegria", "exuberant collective joy")
17796            }
17797
17798            // German concepts
17799            (Some(RuntimeEmotion::Joy), "german" | "de") => create_cultural_entry(
17800                "Schadenfreude",
17801                "schadenfreude",
17802                "pleasure derived from another's misfortune",
17803            ),
17804            (Some(RuntimeEmotion::Sadness), "german" | "de") => create_cultural_entry(
17805                "Weltschmerz",
17806                "weltschmerz",
17807                "world-weariness, melancholy about the world's state",
17808            ),
17809            (Some(RuntimeEmotion::Fear), "german" | "de") => create_cultural_entry(
17810                "Torschlusspanik",
17811                "torschlusspanik",
17812                "fear of diminishing opportunities with age",
17813            ),
17814
17815            // Danish concepts
17816            (Some(RuntimeEmotion::Joy), "danish" | "da") => {
17817                create_cultural_entry("hygge", "hygge", "cozy contentment and conviviality")
17818            }
17819
17820            // Arabic concepts
17821            (Some(RuntimeEmotion::Joy), "arabic" | "ar") => {
17822                create_cultural_entry("طرب", "tarab", "musical ecstasy, enchantment through art")
17823            }
17824            (Some(RuntimeEmotion::Love), "arabic" | "ar") => {
17825                create_cultural_entry("هوى", "hawa", "passionate, sometimes irrational love")
17826            }
17827
17828            // Korean concepts
17829            (Some(RuntimeEmotion::Sadness), "korean" | "ko") => create_cultural_entry(
17830                "한",
17831                "han",
17832                "collective grief and resentment from historical suffering",
17833            ),
17834            (Some(RuntimeEmotion::Joy), "korean" | "ko") => create_cultural_entry(
17835                "정",
17836                "jeong",
17837                "deep affection and attachment formed over time",
17838            ),
17839
17840            // Russian concepts
17841            (Some(RuntimeEmotion::Sadness), "russian" | "ru") => {
17842                create_cultural_entry("тоска", "toska", "spiritual anguish without specific cause")
17843            }
17844
17845            // Hindi concepts
17846            (Some(RuntimeEmotion::Love), "hindi" | "hi") => {
17847                create_cultural_entry("विरह", "viraha", "longing for an absent beloved")
17848            }
17849
17850            // Finnish concepts
17851            (Some(RuntimeEmotion::Anger), "finnish" | "fi") => {
17852                create_cultural_entry("sisu", "sisu", "stoic determination and grit in adversity")
17853            }
17854
17855            // Default: return the base emotion
17856            (Some(e), _) => {
17857                let name = match e {
17858                    RuntimeEmotion::Joy => "joy",
17859                    RuntimeEmotion::Sadness => "sadness",
17860                    RuntimeEmotion::Anger => "anger",
17861                    RuntimeEmotion::Fear => "fear",
17862                    RuntimeEmotion::Surprise => "surprise",
17863                    RuntimeEmotion::Love => "love",
17864                };
17865                create_cultural_entry(name, name, "universal emotion")
17866            }
17867            (None, _) => create_cultural_entry("none", "none", "no emotion"),
17868        };
17869
17870        Ok(result)
17871    });
17872
17873    // list_cultural_emotions - list all emotions for a culture
17874    define(interp, "list_cultural_emotions", Some(1), |_, args| {
17875        let culture = match &args[0] {
17876            Value::String(s) => s.to_lowercase(),
17877            _ => {
17878                return Err(RuntimeError::new(
17879                    "list_cultural_emotions() requires string culture",
17880                ))
17881            }
17882        };
17883
17884        let emotions: Vec<(&str, &str, &str)> = match culture.as_str() {
17885            "japanese" | "ja" => vec![
17886                ("木漏れ日", "komorebi", "sunlight through leaves"),
17887                ("物の哀れ", "mono no aware", "pathos of things"),
17888                ("甘え", "amae", "indulgent dependence"),
17889                ("侘寂", "wabi-sabi", "beauty in imperfection"),
17890                ("生きがい", "ikigai", "reason for being"),
17891            ],
17892            "german" | "de" => vec![
17893                ("Schadenfreude", "schadenfreude", "joy at misfortune"),
17894                ("Weltschmerz", "weltschmerz", "world-weariness"),
17895                ("Torschlusspanik", "torschlusspanik", "gate-closing panic"),
17896                ("Sehnsucht", "sehnsucht", "deep longing"),
17897                ("Wanderlust", "wanderlust", "desire to travel"),
17898            ],
17899            "portuguese" | "pt" => vec![
17900                ("saudade", "saudade", "melancholic longing"),
17901                ("alegria", "alegria", "exuberant joy"),
17902                ("desabafar", "desabafar", "emotional unburdening"),
17903            ],
17904            "danish" | "da" => vec![("hygge", "hygge", "cozy contentment")],
17905            "korean" | "ko" => vec![
17906                ("한", "han", "collective grief"),
17907                ("정", "jeong", "deep affection"),
17908                ("눈치", "nunchi", "situational awareness"),
17909            ],
17910            "arabic" | "ar" => vec![
17911                ("طرب", "tarab", "musical ecstasy"),
17912                ("هوى", "hawa", "passionate love"),
17913                ("صبر", "sabr", "patient perseverance"),
17914            ],
17915            "russian" | "ru" => vec![
17916                ("тоска", "toska", "spiritual anguish"),
17917                ("пошлость", "poshlost", "spiritual vulgarity"),
17918            ],
17919            "finnish" | "fi" => vec![("sisu", "sisu", "stoic determination")],
17920            "hindi" | "hi" => vec![
17921                ("विरह", "viraha", "longing for beloved"),
17922                ("जुगाड़", "jugaad", "creative improvisation"),
17923            ],
17924            _ => vec![
17925                ("joy", "joy", "universal happiness"),
17926                ("sadness", "sadness", "universal sorrow"),
17927                ("anger", "anger", "universal frustration"),
17928                ("fear", "fear", "universal anxiety"),
17929                ("surprise", "surprise", "universal amazement"),
17930                ("love", "love", "universal affection"),
17931            ],
17932        };
17933
17934        let result: Vec<Value> = emotions
17935            .iter()
17936            .map(|(native, romanized, meaning)| create_cultural_entry(native, romanized, meaning))
17937            .collect();
17938
17939        Ok(Value::Array(Rc::new(RefCell::new(result))))
17940    });
17941
17942    // hologram_info - get metadata about the hologram system
17943    define(interp, "hologram_info", Some(0), |_, _| {
17944        let mut info = std::collections::HashMap::new();
17945
17946        info.insert(
17947            "dimensions".to_string(),
17948            Value::Array(Rc::new(RefCell::new(vec![
17949                Value::String(Rc::new("valence".to_string())),
17950                Value::String(Rc::new("arousal".to_string())),
17951                Value::String(Rc::new("dominance".to_string())),
17952                Value::String(Rc::new("authenticity".to_string())),
17953                Value::String(Rc::new("certainty".to_string())),
17954                Value::String(Rc::new("emotion_index".to_string())),
17955            ]))),
17956        );
17957
17958        info.insert(
17959            "supported_cultures".to_string(),
17960            Value::Array(Rc::new(RefCell::new(vec![
17961                Value::String(Rc::new("japanese".to_string())),
17962                Value::String(Rc::new("german".to_string())),
17963                Value::String(Rc::new("portuguese".to_string())),
17964                Value::String(Rc::new("danish".to_string())),
17965                Value::String(Rc::new("korean".to_string())),
17966                Value::String(Rc::new("arabic".to_string())),
17967                Value::String(Rc::new("russian".to_string())),
17968                Value::String(Rc::new("finnish".to_string())),
17969                Value::String(Rc::new("hindi".to_string())),
17970            ]))),
17971        );
17972
17973        let funcs = vec![
17974            "emotional_hologram",
17975            "emotional_distance",
17976            "emotional_similarity",
17977            "emotional_dissonance",
17978            "emotional_fingerprint",
17979            "emotional_morph",
17980            "cultural_emotion",
17981            "list_cultural_emotions",
17982            "hologram_info",
17983        ];
17984        let func_values: Vec<Value> = funcs
17985            .iter()
17986            .map(|s| Value::String(Rc::new(s.to_string())))
17987            .collect();
17988        info.insert(
17989            "functions".to_string(),
17990            Value::Array(Rc::new(RefCell::new(func_values))),
17991        );
17992
17993        Ok(Value::Map(Rc::new(RefCell::new(info))))
17994    });
17995}
17996
17997/// Helper to extract hologram values from an affective value
17998fn get_hologram_values(
17999    val: &Value,
18000    _interp: &mut Interpreter,
18001) -> Result<(f64, f64, f64, f64, f64), RuntimeError> {
18002    use crate::interpreter::{
18003        RuntimeAffect, RuntimeConfidence, RuntimeFormality, RuntimeIntensity, RuntimeSentiment,
18004    };
18005
18006    let affect = match val {
18007        Value::Affective { affect, .. } => affect.clone(),
18008        Value::Map(m) => {
18009            // Already a hologram map
18010            let map = m.borrow();
18011            let v = extract_float(&map, "valence").unwrap_or(0.0);
18012            let a = extract_float(&map, "arousal").unwrap_or(0.5);
18013            let d = extract_float(&map, "dominance").unwrap_or(0.5);
18014            let auth = extract_float(&map, "authenticity").unwrap_or(0.9);
18015            let c = extract_float(&map, "certainty").unwrap_or(0.5);
18016            return Ok((v, a, d, auth, c));
18017        }
18018        _ => RuntimeAffect {
18019            sentiment: None,
18020            sarcasm: false,
18021            intensity: None,
18022            formality: None,
18023            emotion: None,
18024            confidence: None,
18025        },
18026    };
18027
18028    let v = match affect.sentiment {
18029        Some(RuntimeSentiment::Positive) => 1.0,
18030        Some(RuntimeSentiment::Negative) => -1.0,
18031        _ => 0.0,
18032    };
18033    let a = match affect.intensity {
18034        Some(RuntimeIntensity::Down) => 0.25,
18035        Some(RuntimeIntensity::Up) => 0.75,
18036        Some(RuntimeIntensity::Max) => 1.0,
18037        None => 0.5,
18038    };
18039    let d = match affect.formality {
18040        Some(RuntimeFormality::Informal) => 0.25,
18041        Some(RuntimeFormality::Formal) => 0.85,
18042        None => 0.5,
18043    };
18044    let auth = if affect.sarcasm { -0.9 } else { 0.9 };
18045    let c = match affect.confidence {
18046        Some(RuntimeConfidence::Low) => 0.2,
18047        Some(RuntimeConfidence::High) => 0.9,
18048        _ => 0.5,
18049    };
18050
18051    Ok((v, a, d, auth, c))
18052}
18053
18054fn extract_float(map: &std::collections::HashMap<String, Value>, key: &str) -> Option<f64> {
18055    match map.get(key) {
18056        Some(Value::Float(f)) => Some(*f),
18057        Some(Value::Int(i)) => Some(*i as f64),
18058        _ => None,
18059    }
18060}
18061
18062fn create_cultural_entry(native: &str, romanized: &str, meaning: &str) -> Value {
18063    let mut entry = std::collections::HashMap::new();
18064    entry.insert(
18065        "native".to_string(),
18066        Value::String(Rc::new(native.to_string())),
18067    );
18068    entry.insert(
18069        "romanized".to_string(),
18070        Value::String(Rc::new(romanized.to_string())),
18071    );
18072    entry.insert(
18073        "meaning".to_string(),
18074        Value::String(Rc::new(meaning.to_string())),
18075    );
18076    Value::Map(Rc::new(RefCell::new(entry)))
18077}
18078
18079// ============================================================================
18080// EXPERIMENTAL CRYPTOGRAPHY: Threshold crypto, commitments, and more
18081// ============================================================================
18082
18083fn register_experimental_crypto(interp: &mut Interpreter) {
18084    // === Commitment Schemes ===
18085    // Commit to a value without revealing it, verify later
18086
18087    // commit - create a cryptographic commitment to a value
18088    // Returns { commitment: hash, nonce: random_value }
18089    define(interp, "commit", Some(1), |_, args| {
18090        let value_str = match &args[0] {
18091            Value::String(s) => s.to_string(),
18092            other => format!("{:?}", other),
18093        };
18094
18095        // Generate random nonce
18096        let mut nonce = [0u8; 32];
18097        getrandom::getrandom(&mut nonce)
18098            .map_err(|e| RuntimeError::new(format!("commit() random failed: {}", e)))?;
18099        let nonce_hex = hex::encode(&nonce);
18100
18101        // Create commitment: H(value || nonce)
18102        let commitment_input = format!("{}:{}", value_str, nonce_hex);
18103        let commitment = blake3::hash(commitment_input.as_bytes());
18104
18105        let mut result = std::collections::HashMap::new();
18106        result.insert(
18107            "commitment".to_string(),
18108            Value::String(Rc::new(commitment.to_hex().to_string())),
18109        );
18110        result.insert("nonce".to_string(), Value::String(Rc::new(nonce_hex)));
18111        result.insert("value".to_string(), args[0].clone());
18112
18113        Ok(Value::Map(Rc::new(RefCell::new(result))))
18114    });
18115
18116    // verify_commitment - verify a commitment matches a revealed value
18117    define(interp, "verify_commitment", Some(3), |_, args| {
18118        let commitment = match &args[0] {
18119            Value::String(s) => s.to_string(),
18120            _ => {
18121                return Err(RuntimeError::new(
18122                    "verify_commitment() requires string commitment",
18123                ))
18124            }
18125        };
18126        let value_str = match &args[1] {
18127            Value::String(s) => s.to_string(),
18128            other => format!("{:?}", other),
18129        };
18130        let nonce = match &args[2] {
18131            Value::String(s) => s.to_string(),
18132            _ => {
18133                return Err(RuntimeError::new(
18134                    "verify_commitment() requires string nonce",
18135                ))
18136            }
18137        };
18138
18139        // Recompute commitment
18140        let commitment_input = format!("{}:{}", value_str, nonce);
18141        let computed = blake3::hash(commitment_input.as_bytes());
18142
18143        Ok(Value::Bool(computed.to_hex().to_string() == commitment))
18144    });
18145
18146    // === Threshold Cryptography (Shamir's Secret Sharing) ===
18147    // Split secrets into shares, requiring threshold to reconstruct
18148
18149    // secret_split - split a secret into n shares, requiring threshold to recover
18150    // Uses Shamir's Secret Sharing over GF(256)
18151    define(interp, "secret_split", Some(3), |_, args| {
18152        let secret = match &args[0] {
18153            Value::String(s) => s.as_bytes().to_vec(),
18154            Value::Array(arr) => {
18155                let borrowed = arr.borrow();
18156                borrowed
18157                    .iter()
18158                    .filter_map(|v| {
18159                        if let Value::Int(i) = v {
18160                            Some(*i as u8)
18161                        } else {
18162                            None
18163                        }
18164                    })
18165                    .collect()
18166            }
18167            _ => {
18168                return Err(RuntimeError::new(
18169                    "secret_split() requires string or byte array",
18170                ))
18171            }
18172        };
18173
18174        let threshold = match &args[1] {
18175            Value::Int(n) => *n as usize,
18176            _ => {
18177                return Err(RuntimeError::new(
18178                    "secret_split() requires integer threshold",
18179                ))
18180            }
18181        };
18182
18183        let num_shares = match &args[2] {
18184            Value::Int(n) => *n as usize,
18185            _ => {
18186                return Err(RuntimeError::new(
18187                    "secret_split() requires integer num_shares",
18188                ))
18189            }
18190        };
18191
18192        if threshold < 2 {
18193            return Err(RuntimeError::new("secret_split() threshold must be >= 2"));
18194        }
18195        if num_shares < threshold {
18196            return Err(RuntimeError::new(
18197                "secret_split() num_shares must be >= threshold",
18198            ));
18199        }
18200        if num_shares > 255 {
18201            return Err(RuntimeError::new("secret_split() max 255 shares"));
18202        }
18203
18204        // Simple implementation: split each byte independently using polynomial interpolation
18205        // For production, use vsss-rs properly, but this demonstrates the concept
18206        let mut rng = rand::thread_rng();
18207        let mut shares: Vec<Vec<u8>> = (0..num_shares)
18208            .map(|_| Vec::with_capacity(secret.len() + 1))
18209            .collect();
18210
18211        // Assign share indices (1-based to avoid zero)
18212        for (i, share) in shares.iter_mut().enumerate() {
18213            share.push((i + 1) as u8);
18214        }
18215
18216        // For each byte of the secret, create polynomial shares
18217        for &byte in &secret {
18218            // Generate random coefficients for polynomial of degree (threshold - 1)
18219            // a_0 = secret byte, a_1..a_{t-1} = random
18220            let mut coefficients: Vec<u8> = vec![byte];
18221            for _ in 1..threshold {
18222                coefficients.push(rng.gen());
18223            }
18224
18225            // Evaluate polynomial at each share index
18226            for (i, share) in shares.iter_mut().enumerate() {
18227                let x = (i + 1) as u8;
18228                let y = eval_polynomial_gf256(&coefficients, x);
18229                share.push(y);
18230            }
18231        }
18232
18233        // Convert shares to output format
18234        let share_values: Vec<Value> = shares
18235            .iter()
18236            .map(|share| {
18237                let hex = hex::encode(share);
18238                Value::String(Rc::new(hex))
18239            })
18240            .collect();
18241
18242        let mut result = std::collections::HashMap::new();
18243        result.insert(
18244            "shares".to_string(),
18245            Value::Array(Rc::new(RefCell::new(share_values))),
18246        );
18247        result.insert("threshold".to_string(), Value::Int(threshold as i64));
18248        result.insert("total".to_string(), Value::Int(num_shares as i64));
18249
18250        Ok(Value::Map(Rc::new(RefCell::new(result))))
18251    });
18252
18253    // secret_recover - recover secret from threshold shares
18254    define(interp, "secret_recover", Some(1), |_, args| {
18255        let shares: Vec<Vec<u8>> = match &args[0] {
18256            Value::Array(arr) => {
18257                let borrowed = arr.borrow();
18258                borrowed
18259                    .iter()
18260                    .filter_map(|v| {
18261                        if let Value::String(s) = v {
18262                            hex::decode(s.as_str()).ok()
18263                        } else {
18264                            None
18265                        }
18266                    })
18267                    .collect()
18268            }
18269            _ => {
18270                return Err(RuntimeError::new(
18271                    "secret_recover() requires array of share strings",
18272                ))
18273            }
18274        };
18275
18276        if shares.is_empty() {
18277            return Err(RuntimeError::new(
18278                "secret_recover() requires at least one share",
18279            ));
18280        }
18281
18282        let share_len = shares[0].len();
18283        if share_len < 2 {
18284            return Err(RuntimeError::new("secret_recover() invalid share format"));
18285        }
18286
18287        // Recover each byte using Lagrange interpolation
18288        let mut secret = Vec::with_capacity(share_len - 1);
18289
18290        for byte_idx in 1..share_len {
18291            // Collect (x, y) pairs for this byte position
18292            let points: Vec<(u8, u8)> = shares
18293                .iter()
18294                .map(|share| (share[0], share[byte_idx]))
18295                .collect();
18296
18297            // Lagrange interpolation at x=0 to recover the secret byte
18298            let recovered_byte = lagrange_interpolate_gf256(&points, 0);
18299            secret.push(recovered_byte);
18300        }
18301
18302        // Try to interpret as string
18303        match String::from_utf8(secret.clone()) {
18304            Ok(s) => Ok(Value::String(Rc::new(s))),
18305            Err(_) => {
18306                // Return as byte array
18307                let byte_values: Vec<Value> =
18308                    secret.iter().map(|&b| Value::Int(b as i64)).collect();
18309                Ok(Value::Array(Rc::new(RefCell::new(byte_values))))
18310            }
18311        }
18312    });
18313
18314    // === Cryptographic Ceremony Functions ===
18315    // Cultural trust models encoded in crypto
18316
18317    // council_split - split secret using Ubuntu (I am because we are) model
18318    // Requires majority consensus
18319    define(interp, "council_split", Some(2), |_, args| {
18320        let secret = match &args[0] {
18321            Value::String(s) => s.as_bytes().to_vec(),
18322            _ => return Err(RuntimeError::new("council_split() requires string secret")),
18323        };
18324
18325        let num_elders = match &args[1] {
18326            Value::Int(n) => *n as usize,
18327            _ => {
18328                return Err(RuntimeError::new(
18329                    "council_split() requires integer num_elders",
18330                ))
18331            }
18332        };
18333
18334        if num_elders < 3 {
18335            return Err(RuntimeError::new(
18336                "council_split() requires at least 3 elders",
18337            ));
18338        }
18339
18340        // Ubuntu model: majority required (n/2 + 1)
18341        let threshold = (num_elders / 2) + 1;
18342
18343        // Reuse secret_split logic
18344        let mut rng = rand::thread_rng();
18345        let mut shares: Vec<Vec<u8>> = (0..num_elders)
18346            .map(|_| Vec::with_capacity(secret.len() + 1))
18347            .collect();
18348
18349        for (i, share) in shares.iter_mut().enumerate() {
18350            share.push((i + 1) as u8);
18351        }
18352
18353        for &byte in &secret {
18354            let mut coefficients: Vec<u8> = vec![byte];
18355            for _ in 1..threshold {
18356                coefficients.push(rng.gen());
18357            }
18358
18359            for (i, share) in shares.iter_mut().enumerate() {
18360                let x = (i + 1) as u8;
18361                let y = eval_polynomial_gf256(&coefficients, x);
18362                share.push(y);
18363            }
18364        }
18365
18366        let share_values: Vec<Value> = shares
18367            .iter()
18368            .map(|share| Value::String(Rc::new(hex::encode(share))))
18369            .collect();
18370
18371        let mut result = std::collections::HashMap::new();
18372        result.insert(
18373            "shares".to_string(),
18374            Value::Array(Rc::new(RefCell::new(share_values))),
18375        );
18376        result.insert("threshold".to_string(), Value::Int(threshold as i64));
18377        result.insert("total".to_string(), Value::Int(num_elders as i64));
18378        result.insert(
18379            "model".to_string(),
18380            Value::String(Rc::new("ubuntu".to_string())),
18381        );
18382        result.insert(
18383            "philosophy".to_string(),
18384            Value::String(Rc::new(
18385                "I am because we are - majority consensus required".to_string(),
18386            )),
18387        );
18388
18389        Ok(Value::Map(Rc::new(RefCell::new(result))))
18390    });
18391
18392    // witness_chain - create a chain of witnesses (Middle Eastern oral tradition model)
18393    // Each witness signs the previous, creating a chain of trust
18394    define(interp, "witness_chain", Some(2), |_, args| {
18395        let statement = match &args[0] {
18396            Value::String(s) => s.to_string(),
18397            _ => {
18398                return Err(RuntimeError::new(
18399                    "witness_chain() requires string statement",
18400                ))
18401            }
18402        };
18403
18404        let witnesses: Vec<String> = match &args[1] {
18405            Value::Array(arr) => {
18406                let borrowed = arr.borrow();
18407                borrowed
18408                    .iter()
18409                    .filter_map(|v| {
18410                        if let Value::String(s) = v {
18411                            Some(s.to_string())
18412                        } else {
18413                            None
18414                        }
18415                    })
18416                    .collect()
18417            }
18418            _ => {
18419                return Err(RuntimeError::new(
18420                    "witness_chain() requires array of witness names",
18421                ))
18422            }
18423        };
18424
18425        if witnesses.is_empty() {
18426            return Err(RuntimeError::new(
18427                "witness_chain() requires at least one witness",
18428            ));
18429        }
18430
18431        // Build chain: each witness attests to the previous
18432        let mut chain = Vec::new();
18433        let mut prev_hash = blake3::hash(statement.as_bytes()).to_hex().to_string();
18434
18435        for (i, witness) in witnesses.iter().enumerate() {
18436            let attestation = format!("{}:attests:{}", witness, prev_hash);
18437            let hash = blake3::hash(attestation.as_bytes()).to_hex().to_string();
18438
18439            let mut link = std::collections::HashMap::new();
18440            link.insert(
18441                "witness".to_string(),
18442                Value::String(Rc::new(witness.clone())),
18443            );
18444            link.insert("position".to_string(), Value::Int((i + 1) as i64));
18445            link.insert(
18446                "attests_to".to_string(),
18447                Value::String(Rc::new(prev_hash.clone())),
18448            );
18449            link.insert(
18450                "signature".to_string(),
18451                Value::String(Rc::new(hash.clone())),
18452            );
18453
18454            chain.push(Value::Map(Rc::new(RefCell::new(link))));
18455            prev_hash = hash;
18456        }
18457
18458        let mut result = std::collections::HashMap::new();
18459        result.insert("statement".to_string(), Value::String(Rc::new(statement)));
18460        result.insert(
18461            "chain".to_string(),
18462            Value::Array(Rc::new(RefCell::new(chain))),
18463        );
18464        result.insert("final_seal".to_string(), Value::String(Rc::new(prev_hash)));
18465        result.insert(
18466            "model".to_string(),
18467            Value::String(Rc::new("isnad".to_string())),
18468        );
18469        result.insert(
18470            "philosophy".to_string(),
18471            Value::String(Rc::new(
18472                "Chain of reliable transmitters - each witness validates the previous".to_string(),
18473            )),
18474        );
18475
18476        Ok(Value::Map(Rc::new(RefCell::new(result))))
18477    });
18478
18479    // verify_witness_chain - verify a witness chain is intact
18480    define(interp, "verify_witness_chain", Some(1), |_, args| {
18481        let chain_map = match &args[0] {
18482            Value::Map(m) => m.borrow(),
18483            _ => {
18484                return Err(RuntimeError::new(
18485                    "verify_witness_chain() requires chain map",
18486                ))
18487            }
18488        };
18489
18490        let statement = match chain_map.get("statement") {
18491            Some(Value::String(s)) => s.to_string(),
18492            _ => {
18493                return Err(RuntimeError::new(
18494                    "verify_witness_chain() invalid chain format",
18495                ))
18496            }
18497        };
18498
18499        let chain = match chain_map.get("chain") {
18500            Some(Value::Array(arr)) => arr.borrow().clone(),
18501            _ => {
18502                return Err(RuntimeError::new(
18503                    "verify_witness_chain() invalid chain format",
18504                ))
18505            }
18506        };
18507
18508        let mut prev_hash = blake3::hash(statement.as_bytes()).to_hex().to_string();
18509
18510        for link_val in chain.iter() {
18511            if let Value::Map(link_map) = link_val {
18512                let link = link_map.borrow();
18513                let witness = match link.get("witness") {
18514                    Some(Value::String(s)) => s.to_string(),
18515                    _ => return Ok(Value::Bool(false)),
18516                };
18517                let attests_to = match link.get("attests_to") {
18518                    Some(Value::String(s)) => s.to_string(),
18519                    _ => return Ok(Value::Bool(false)),
18520                };
18521                let signature = match link.get("signature") {
18522                    Some(Value::String(s)) => s.to_string(),
18523                    _ => return Ok(Value::Bool(false)),
18524                };
18525
18526                // Verify attestation
18527                if attests_to != prev_hash {
18528                    return Ok(Value::Bool(false));
18529                }
18530
18531                let expected = format!("{}:attests:{}", witness, prev_hash);
18532                let computed = blake3::hash(expected.as_bytes()).to_hex().to_string();
18533
18534                if computed != signature {
18535                    return Ok(Value::Bool(false));
18536                }
18537
18538                prev_hash = signature;
18539            } else {
18540                return Ok(Value::Bool(false));
18541            }
18542        }
18543
18544        Ok(Value::Bool(true))
18545    });
18546
18547    // === Experimental Crypto Info ===
18548    define(interp, "experimental_crypto_info", Some(0), |_, _| {
18549        let mut info = std::collections::HashMap::new();
18550
18551        info.insert(
18552            "commitment_functions".to_string(),
18553            Value::Array(Rc::new(RefCell::new(vec![
18554                Value::String(Rc::new("commit".to_string())),
18555                Value::String(Rc::new("verify_commitment".to_string())),
18556            ]))),
18557        );
18558
18559        info.insert(
18560            "threshold_functions".to_string(),
18561            Value::Array(Rc::new(RefCell::new(vec![
18562                Value::String(Rc::new("secret_split".to_string())),
18563                Value::String(Rc::new("secret_recover".to_string())),
18564            ]))),
18565        );
18566
18567        info.insert(
18568            "cultural_ceremonies".to_string(),
18569            Value::Array(Rc::new(RefCell::new(vec![
18570                Value::String(Rc::new(
18571                    "council_split (Ubuntu - African consensus)".to_string(),
18572                )),
18573                Value::String(Rc::new(
18574                    "witness_chain (Isnad - Islamic transmission)".to_string(),
18575                )),
18576            ]))),
18577        );
18578
18579        Ok(Value::Map(Rc::new(RefCell::new(info))))
18580    });
18581}
18582
18583/// Evaluate polynomial in GF(256) at point x
18584fn eval_polynomial_gf256(coefficients: &[u8], x: u8) -> u8 {
18585    let mut result: u8 = 0;
18586    let mut x_power: u8 = 1;
18587
18588    for &coef in coefficients {
18589        result ^= gf256_mul(coef, x_power);
18590        x_power = gf256_mul(x_power, x);
18591    }
18592
18593    result
18594}
18595
18596/// Lagrange interpolation in GF(256) to find f(0)
18597fn lagrange_interpolate_gf256(points: &[(u8, u8)], _x: u8) -> u8 {
18598    let mut result: u8 = 0;
18599
18600    for (i, &(xi, yi)) in points.iter().enumerate() {
18601        let mut numerator: u8 = 1;
18602        let mut denominator: u8 = 1;
18603
18604        for (j, &(xj, _)) in points.iter().enumerate() {
18605            if i != j {
18606                // numerator *= (0 - xj) = xj (in GF256, subtraction is XOR)
18607                numerator = gf256_mul(numerator, xj);
18608                // denominator *= (xi - xj)
18609                denominator = gf256_mul(denominator, xi ^ xj);
18610            }
18611        }
18612
18613        // term = yi * numerator / denominator
18614        let term = gf256_mul(yi, gf256_mul(numerator, gf256_inv(denominator)));
18615        result ^= term;
18616    }
18617
18618    result
18619}
18620
18621/// GF(256) multiplication using Russian peasant algorithm
18622fn gf256_mul(mut a: u8, mut b: u8) -> u8 {
18623    let mut result: u8 = 0;
18624    let modulus: u16 = 0x11b; // x^8 + x^4 + x^3 + x + 1
18625
18626    while b != 0 {
18627        if b & 1 != 0 {
18628            result ^= a;
18629        }
18630        let high_bit = (a & 0x80) != 0;
18631        a <<= 1;
18632        if high_bit {
18633            a ^= (modulus & 0xff) as u8;
18634        }
18635        b >>= 1;
18636    }
18637
18638    result
18639}
18640
18641/// GF(256) multiplicative inverse using extended Euclidean algorithm
18642fn gf256_inv(a: u8) -> u8 {
18643    if a == 0 {
18644        return 0;
18645    }
18646
18647    // Use Fermat's little theorem: a^(-1) = a^(254) in GF(256)
18648    let mut result = a;
18649    for _ in 0..6 {
18650        result = gf256_mul(result, result);
18651        result = gf256_mul(result, a);
18652    }
18653    gf256_mul(result, result)
18654}
18655
18656// ============================================================================
18657// MULTI-BASE ENCODING: Polycultural numeral systems and crypto addresses
18658// ============================================================================
18659//
18660// Sigil supports multiple numeral bases reflecting different mathematical traditions:
18661//   Binary (2)      - 0b prefix - Modern computing
18662//   Octal (8)       - 0o prefix - Unix permissions
18663//   Decimal (10)    - Default   - Indo-Arabic (global standard)
18664//   Duodecimal (12) - 0z prefix - Dozen system (time, music)
18665//   Hexadecimal (16)- 0x prefix - Computing, colors
18666//   Vigesimal (20)  - 0v prefix - Mayan, Celtic, Basque
18667//   Sexagesimal (60)- 0s prefix - Babylonian (time, angles)
18668//
18669// Plus special encodings:
18670//   Base58  - Bitcoin addresses (no confusing 0/O/I/l)
18671//   Base32  - Case-insensitive, no confusing chars
18672//   Base36  - Alphanumeric only
18673
18674fn register_multibase(interp: &mut Interpreter) {
18675    // === Vigesimal (Base 20) - Mayan/Celtic ===
18676    // Digits: 0-9, A-J (or a-j)
18677
18678    define(interp, "to_vigesimal", Some(1), |_, args| {
18679        let n = match &args[0] {
18680            Value::Int(n) => *n,
18681            _ => return Err(RuntimeError::new("to_vigesimal() requires integer")),
18682        };
18683
18684        let result = to_base_string(n.unsigned_abs(), 20, false);
18685        let prefix = if n < 0 { "-0v" } else { "0v" };
18686        Ok(Value::String(Rc::new(format!("{}{}", prefix, result))))
18687    });
18688
18689    define(interp, "from_vigesimal", Some(1), |_, args| {
18690        let s = match &args[0] {
18691            Value::String(s) => s.to_string(),
18692            _ => return Err(RuntimeError::new("from_vigesimal() requires string")),
18693        };
18694
18695        let (negative, clean) = parse_base_prefix(&s, "0v");
18696        let value = from_base_string(&clean, 20)?;
18697        Ok(Value::Int(if negative {
18698            -(value as i64)
18699        } else {
18700            value as i64
18701        }))
18702    });
18703
18704    // === Sexagesimal (Base 60) - Babylonian ===
18705    // Uses colon-separated groups for readability: "1:30:45" = 1*3600 + 30*60 + 45
18706
18707    define(interp, "to_sexagesimal", Some(1), |_, args| {
18708        let n = match &args[0] {
18709            Value::Int(n) => *n,
18710            _ => return Err(RuntimeError::new("to_sexagesimal() requires integer")),
18711        };
18712
18713        let negative = n < 0;
18714        let mut value = n.unsigned_abs();
18715        let mut parts = Vec::new();
18716
18717        if value == 0 {
18718            parts.push("0".to_string());
18719        } else {
18720            while value > 0 {
18721                parts.push(format!("{}", value % 60));
18722                value /= 60;
18723            }
18724            parts.reverse();
18725        }
18726
18727        let prefix = if negative { "-0s" } else { "0s" };
18728        Ok(Value::String(Rc::new(format!(
18729            "{}[{}]",
18730            prefix,
18731            parts.join(":")
18732        ))))
18733    });
18734
18735    define(interp, "from_sexagesimal", Some(1), |_, args| {
18736        let s = match &args[0] {
18737            Value::String(s) => s.to_string(),
18738            _ => return Err(RuntimeError::new("from_sexagesimal() requires string")),
18739        };
18740
18741        let negative = s.starts_with('-');
18742        let clean = s
18743            .trim_start_matches('-')
18744            .trim_start_matches("0s")
18745            .trim_start_matches('[')
18746            .trim_end_matches(']');
18747
18748        let mut result: i64 = 0;
18749        for part in clean.split(':') {
18750            let digit: i64 = part
18751                .trim()
18752                .parse()
18753                .map_err(|_| RuntimeError::new(format!("Invalid sexagesimal digit: {}", part)))?;
18754            if digit < 0 || digit >= 60 {
18755                return Err(RuntimeError::new(format!(
18756                    "Sexagesimal digit out of range: {}",
18757                    digit
18758                )));
18759            }
18760            result = result * 60 + digit;
18761        }
18762
18763        Ok(Value::Int(if negative { -result } else { result }))
18764    });
18765
18766    // === Duodecimal (Base 12) - Dozen system ===
18767    // Digits: 0-9, X (10), E (11) - Dozenal Society convention
18768
18769    define(interp, "to_duodecimal", Some(1), |_, args| {
18770        let n = match &args[0] {
18771            Value::Int(n) => *n,
18772            _ => return Err(RuntimeError::new("to_duodecimal() requires integer")),
18773        };
18774
18775        let result = to_base_string_custom(n.unsigned_abs(), 12, "0123456789XE");
18776        let prefix = if n < 0 { "-0z" } else { "0z" };
18777        Ok(Value::String(Rc::new(format!("{}{}", prefix, result))))
18778    });
18779
18780    define(interp, "from_duodecimal", Some(1), |_, args| {
18781        let s = match &args[0] {
18782            Value::String(s) => s.to_string(),
18783            _ => return Err(RuntimeError::new("from_duodecimal() requires string")),
18784        };
18785
18786        let (negative, clean) = parse_base_prefix(&s, "0z");
18787        let value = from_base_string_custom(&clean.to_uppercase(), "0123456789XE")?;
18788        Ok(Value::Int(if negative {
18789            -(value as i64)
18790        } else {
18791            value as i64
18792        }))
18793    });
18794
18795    // === Generic Base Conversion ===
18796
18797    define(interp, "to_base", Some(2), |_, args| {
18798        let n = match &args[0] {
18799            Value::Int(n) => *n,
18800            _ => return Err(RuntimeError::new("to_base() requires integer")),
18801        };
18802        let base = match &args[1] {
18803            Value::Int(b) => *b as u64,
18804            _ => return Err(RuntimeError::new("to_base() requires integer base")),
18805        };
18806
18807        if base < 2 || base > 36 {
18808            return Err(RuntimeError::new("to_base() base must be 2-36"));
18809        }
18810
18811        let result = to_base_string(n.unsigned_abs(), base, false);
18812        let prefix = if n < 0 { "-" } else { "" };
18813        Ok(Value::String(Rc::new(format!("{}{}", prefix, result))))
18814    });
18815
18816    define(interp, "from_base", Some(2), |_, args| {
18817        let s = match &args[0] {
18818            Value::String(s) => s.to_string(),
18819            _ => return Err(RuntimeError::new("from_base() requires string")),
18820        };
18821        let base = match &args[1] {
18822            Value::Int(b) => *b as u64,
18823            _ => return Err(RuntimeError::new("from_base() requires integer base")),
18824        };
18825
18826        if base < 2 || base > 36 {
18827            return Err(RuntimeError::new("from_base() base must be 2-36"));
18828        }
18829
18830        let negative = s.starts_with('-');
18831        let clean = s.trim_start_matches('-');
18832        let value = from_base_string(clean, base)?;
18833        Ok(Value::Int(if negative {
18834            -(value as i64)
18835        } else {
18836            value as i64
18837        }))
18838    });
18839
18840    // === Base58 - Bitcoin/IPFS addresses ===
18841    // Alphabet: 123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz
18842    // Excludes: 0, O, I, l (confusing characters)
18843
18844    const BASE58_ALPHABET: &str = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
18845
18846    define(interp, "base58_encode", Some(1), |_, args| {
18847        let bytes: Vec<u8> = match &args[0] {
18848            Value::String(s) => s.as_bytes().to_vec(),
18849            Value::Array(arr) => arr
18850                .borrow()
18851                .iter()
18852                .filter_map(|v| {
18853                    if let Value::Int(i) = v {
18854                        Some(*i as u8)
18855                    } else {
18856                        None
18857                    }
18858                })
18859                .collect(),
18860            _ => {
18861                return Err(RuntimeError::new(
18862                    "base58_encode() requires string or byte array",
18863                ))
18864            }
18865        };
18866
18867        // Count leading zeros
18868        let leading_zeros = bytes.iter().take_while(|&&b| b == 0).count();
18869
18870        // Convert to big integer and then to base58
18871        let mut result = Vec::new();
18872        let mut num: Vec<u8> = bytes.clone();
18873
18874        while !num.is_empty() && !num.iter().all(|&b| b == 0) {
18875            let mut remainder = 0u32;
18876            let mut new_num = Vec::new();
18877
18878            for &byte in &num {
18879                let acc = (remainder << 8) + byte as u32;
18880                let digit = acc / 58;
18881                remainder = acc % 58;
18882
18883                if !new_num.is_empty() || digit > 0 {
18884                    new_num.push(digit as u8);
18885                }
18886            }
18887
18888            result.push(BASE58_ALPHABET.chars().nth(remainder as usize).unwrap());
18889            num = new_num;
18890        }
18891
18892        // Add '1' for each leading zero byte
18893        for _ in 0..leading_zeros {
18894            result.push('1');
18895        }
18896
18897        result.reverse();
18898        Ok(Value::String(Rc::new(result.into_iter().collect())))
18899    });
18900
18901    define(interp, "base58_decode", Some(1), |_, args| {
18902        let s = match &args[0] {
18903            Value::String(s) => s.to_string(),
18904            _ => return Err(RuntimeError::new("base58_decode() requires string")),
18905        };
18906
18907        // Count leading '1's
18908        let leading_ones = s.chars().take_while(|&c| c == '1').count();
18909
18910        // Convert from base58 to big integer
18911        let mut num: Vec<u8> = Vec::new();
18912
18913        for c in s.chars() {
18914            let digit = BASE58_ALPHABET
18915                .find(c)
18916                .ok_or_else(|| RuntimeError::new(format!("Invalid base58 character: {}", c)))?;
18917
18918            let mut carry = digit as u32;
18919            for byte in num.iter_mut().rev() {
18920                let acc = (*byte as u32) * 58 + carry;
18921                *byte = (acc & 0xff) as u8;
18922                carry = acc >> 8;
18923            }
18924
18925            while carry > 0 {
18926                num.insert(0, (carry & 0xff) as u8);
18927                carry >>= 8;
18928            }
18929        }
18930
18931        // Add leading zeros
18932        let mut result = vec![0u8; leading_ones];
18933        result.extend(num);
18934
18935        // Return as hex string for readability
18936        Ok(Value::String(Rc::new(hex::encode(&result))))
18937    });
18938
18939    // === Base32 - Case insensitive, no confusing chars ===
18940    // RFC 4648 alphabet: A-Z, 2-7
18941
18942    const BASE32_ALPHABET: &str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
18943
18944    define(interp, "base32_encode", Some(1), |_, args| {
18945        let bytes: Vec<u8> = match &args[0] {
18946            Value::String(s) => s.as_bytes().to_vec(),
18947            Value::Array(arr) => arr
18948                .borrow()
18949                .iter()
18950                .filter_map(|v| {
18951                    if let Value::Int(i) = v {
18952                        Some(*i as u8)
18953                    } else {
18954                        None
18955                    }
18956                })
18957                .collect(),
18958            _ => {
18959                return Err(RuntimeError::new(
18960                    "base32_encode() requires string or byte array",
18961                ))
18962            }
18963        };
18964
18965        let mut result = String::new();
18966        let mut buffer: u64 = 0;
18967        let mut bits = 0;
18968
18969        for byte in bytes {
18970            buffer = (buffer << 8) | byte as u64;
18971            bits += 8;
18972
18973            while bits >= 5 {
18974                bits -= 5;
18975                let idx = ((buffer >> bits) & 0x1f) as usize;
18976                result.push(BASE32_ALPHABET.chars().nth(idx).unwrap());
18977            }
18978        }
18979
18980        if bits > 0 {
18981            let idx = ((buffer << (5 - bits)) & 0x1f) as usize;
18982            result.push(BASE32_ALPHABET.chars().nth(idx).unwrap());
18983        }
18984
18985        // Padding
18986        while result.len() % 8 != 0 {
18987            result.push('=');
18988        }
18989
18990        Ok(Value::String(Rc::new(result)))
18991    });
18992
18993    define(interp, "base32_decode", Some(1), |_, args| {
18994        let s = match &args[0] {
18995            Value::String(s) => s.to_uppercase().replace('=', ""),
18996            _ => return Err(RuntimeError::new("base32_decode() requires string")),
18997        };
18998
18999        let mut result = Vec::new();
19000        let mut buffer: u64 = 0;
19001        let mut bits = 0;
19002
19003        for c in s.chars() {
19004            let digit = BASE32_ALPHABET
19005                .find(c)
19006                .ok_or_else(|| RuntimeError::new(format!("Invalid base32 character: {}", c)))?;
19007
19008            buffer = (buffer << 5) | digit as u64;
19009            bits += 5;
19010
19011            if bits >= 8 {
19012                bits -= 8;
19013                result.push((buffer >> bits) as u8);
19014                buffer &= (1 << bits) - 1;
19015            }
19016        }
19017
19018        Ok(Value::String(Rc::new(hex::encode(&result))))
19019    });
19020
19021    // === Cultural Numerology ===
19022
19023    // sacred_numbers - get sacred/significant numbers for a culture
19024    define(interp, "sacred_numbers", Some(1), |_, args| {
19025        let culture = match &args[0] {
19026            Value::String(s) => s.to_lowercase(),
19027            _ => {
19028                return Err(RuntimeError::new(
19029                    "sacred_numbers() requires string culture",
19030                ))
19031            }
19032        };
19033
19034        let numbers: Vec<(i64, &str)> = match culture.as_str() {
19035            "mayan" | "maya" => vec![
19036                (13, "Sacred cycle - Tzolkin calendar"),
19037                (20, "Base of vigesimal system - human digits"),
19038                (52, "Calendar round - 52 years"),
19039                (260, "Tzolkin sacred calendar days"),
19040                (365, "Haab solar calendar days"),
19041                (400, "Baktun - 20×20 years"),
19042            ],
19043            "babylonian" | "mesopotamian" => vec![
19044                (12, "Months, hours - celestial division"),
19045                (60, "Sexagesimal base - minutes, seconds, degrees"),
19046                (360, "Circle degrees - 6×60"),
19047                (3600, "Sar - 60×60, large count"),
19048                (7, "Planets visible to naked eye"),
19049            ],
19050            "chinese" | "zh" => vec![
19051                (8, "八 (bā) - prosperity, wealth (sounds like 發)"),
19052                (9, "九 (jiǔ) - longevity (sounds like 久)"),
19053                (6, "六 (liù) - smooth, flowing"),
19054                (2, "二 (èr) - pairs, harmony"),
19055                (4, "四 (sì) - AVOID - sounds like death (死)"),
19056                (5, "五 (wǔ) - five elements"),
19057                (12, "十二 - zodiac animals"),
19058            ],
19059            "japanese" | "ja" => vec![
19060                (7, "七 (nana) - lucky, seven gods of fortune"),
19061                (8, "八 (hachi) - prosperity, expansion"),
19062                (3, "三 (san) - completeness"),
19063                (5, "五 (go) - five elements"),
19064                (4, "四 (shi) - AVOID - sounds like death (死)"),
19065                (9, "九 (ku) - AVOID - sounds like suffering (苦)"),
19066            ],
19067            "hebrew" | "jewish" => vec![
19068                (7, "Shabbat, creation days, menorah branches"),
19069                (18, "Chai (חי) - life - gematria of ח(8) + י(10)"),
19070                (40, "Transformation - flood, Sinai, wilderness"),
19071                (12, "Tribes of Israel"),
19072                (613, "Mitzvot - commandments"),
19073                (26, "Gematria of YHWH"),
19074            ],
19075            "islamic" | "arabic" | "ar" => vec![
19076                (5, "Pillars of Islam, daily prayers"),
19077                (7, "Heavens, circumambulation of Kaaba"),
19078                (40, "Age of prophethood, days of repentance"),
19079                (99, "Names of Allah"),
19080                (786, "Abjad value of Bismillah"),
19081            ],
19082            "hindu" | "indian" | "hi" => vec![
19083                (108, "Sacred beads, Upanishads, sun's distance"),
19084                (7, "Chakras (main), rishis, sacred rivers"),
19085                (3, "Trimurti - Brahma, Vishnu, Shiva"),
19086                (4, "Vedas, yugas, varnas"),
19087                (9, "Planets (navagraha), durga forms"),
19088                (1008, "Names of Vishnu"),
19089            ],
19090            "greek" | "pythagorean" => vec![
19091                (1, "Monad - unity, source"),
19092                (2, "Dyad - duality, diversity"),
19093                (3, "Triad - harmony, completion"),
19094                (4, "Tetrad - solidity, earth"),
19095                (7, "Heptad - perfection"),
19096                (10, "Decad - tetractys, divine"),
19097                (12, "Olympian gods"),
19098            ],
19099            "celtic" | "irish" => vec![
19100                (3, "Triple goddess, triquetra"),
19101                (5, "Elements including spirit"),
19102                (9, "Triple threes - sacred completion"),
19103                (13, "Lunar months"),
19104                (17, "St. Patrick's Day"),
19105                (20, "Vigesimal counting"),
19106            ],
19107            _ => vec![
19108                (1, "Unity"),
19109                (7, "Widely considered lucky"),
19110                (12, "Dozen - practical division"),
19111                (13, "Often considered unlucky in West"),
19112            ],
19113        };
19114
19115        let result: Vec<Value> = numbers
19116            .iter()
19117            .map(|(n, meaning)| {
19118                let mut entry = std::collections::HashMap::new();
19119                entry.insert("number".to_string(), Value::Int(*n));
19120                entry.insert(
19121                    "meaning".to_string(),
19122                    Value::String(Rc::new(meaning.to_string())),
19123                );
19124                Value::Map(Rc::new(RefCell::new(entry)))
19125            })
19126            .collect();
19127
19128        Ok(Value::Array(Rc::new(RefCell::new(result))))
19129    });
19130
19131    // is_sacred - check if a number is sacred in a culture
19132    define(interp, "is_sacred", Some(2), |_, args| {
19133        let n = match &args[0] {
19134            Value::Int(n) => *n,
19135            _ => return Err(RuntimeError::new("is_sacred() requires integer")),
19136        };
19137        let culture = match &args[1] {
19138            Value::String(s) => s.to_lowercase(),
19139            _ => return Err(RuntimeError::new("is_sacred() requires string culture")),
19140        };
19141
19142        let sacred = match culture.as_str() {
19143            "mayan" | "maya" => vec![13, 20, 52, 260, 365, 400],
19144            "babylonian" | "mesopotamian" => vec![12, 60, 360, 3600, 7],
19145            "chinese" | "zh" => vec![8, 9, 6, 2, 5, 12],
19146            "japanese" | "ja" => vec![7, 8, 3, 5],
19147            "hebrew" | "jewish" => vec![7, 18, 40, 12, 613, 26],
19148            "islamic" | "arabic" | "ar" => vec![5, 7, 40, 99, 786],
19149            "hindu" | "indian" | "hi" => vec![108, 7, 3, 4, 9, 1008],
19150            "greek" | "pythagorean" => vec![1, 2, 3, 4, 7, 10, 12],
19151            "celtic" | "irish" => vec![3, 5, 9, 13, 17, 20],
19152            _ => vec![7, 12],
19153        };
19154
19155        Ok(Value::Bool(sacred.contains(&n)))
19156    });
19157
19158    // is_unlucky - check if a number is unlucky in a culture
19159    define(interp, "is_unlucky", Some(2), |_, args| {
19160        let n = match &args[0] {
19161            Value::Int(n) => *n,
19162            _ => return Err(RuntimeError::new("is_unlucky() requires integer")),
19163        };
19164        let culture = match &args[1] {
19165            Value::String(s) => s.to_lowercase(),
19166            _ => return Err(RuntimeError::new("is_unlucky() requires string culture")),
19167        };
19168
19169        let unlucky = match culture.as_str() {
19170            "chinese" | "zh" => vec![4],     // 四 sounds like 死 (death)
19171            "japanese" | "ja" => vec![4, 9], // 四=death, 九=suffering
19172            "western" | "en" => vec![13],    // Friday the 13th
19173            "italian" | "it" => vec![17],    // XVII = VIXI (I lived = I'm dead)
19174            _ => vec![],
19175        };
19176
19177        Ok(Value::Bool(unlucky.contains(&n)))
19178    });
19179
19180    // number_meaning - get the cultural meaning of a specific number
19181    define(interp, "number_meaning", Some(2), |_, args| {
19182        let n = match &args[0] {
19183            Value::Int(n) => *n,
19184            _ => return Err(RuntimeError::new("number_meaning() requires integer")),
19185        };
19186        let culture = match &args[1] {
19187            Value::String(s) => s.to_lowercase(),
19188            _ => {
19189                return Err(RuntimeError::new(
19190                    "number_meaning() requires string culture",
19191                ))
19192            }
19193        };
19194
19195        let meaning = match (n, culture.as_str()) {
19196            // Chinese
19197            (8, "chinese" | "zh") => "八 (bā) - Most auspicious, sounds like 發 (prosperity)",
19198            (4, "chinese" | "zh") => "四 (sì) - Unlucky, sounds like 死 (death)",
19199            (9, "chinese" | "zh") => "九 (jiǔ) - Longevity, sounds like 久 (long-lasting)",
19200            (6, "chinese" | "zh") => "六 (liù) - Smooth and well-off",
19201            (2, "chinese" | "zh") => "二 (èr) - Good things come in pairs",
19202
19203            // Japanese
19204            (7, "japanese" | "ja") => "七 (nana) - Lucky, seven gods of fortune",
19205            (8, "japanese" | "ja") => "八 (hachi) - Lucky, represents spreading prosperity",
19206            (4, "japanese" | "ja") => "四 (shi) - Unlucky, homophone of death",
19207            (9, "japanese" | "ja") => "九 (ku) - Unlucky, homophone of suffering",
19208
19209            // Hebrew
19210            (18, "hebrew" | "jewish") => "Chai (חי) - Life itself, most auspicious",
19211            (7, "hebrew" | "jewish") => "Divine completion - Shabbat, menorah, creation",
19212            (40, "hebrew" | "jewish") => "Transformation - flood, Sinai, wilderness years",
19213            (613, "hebrew" | "jewish") => "Taryag - total number of mitzvot (commandments)",
19214
19215            // Mayan
19216            (13, "mayan" | "maya") => "Sacred Tzolkin cycle, celestial layers",
19217            (20, "mayan" | "maya") => "Vigesimal base - fingers and toes, uinal",
19218            (260, "mayan" | "maya") => "Tzolkin calendar - 13 × 20 sacred days",
19219
19220            // Babylonian
19221            (60, "babylonian" | "mesopotamian") => {
19222                "Sexagesimal base - divisible by 2,3,4,5,6,10,12,15,20,30"
19223            }
19224            (360, "babylonian" | "mesopotamian") => "Circle degrees - celestial observation",
19225
19226            // Hindu
19227            (108, "hindu" | "indian" | "hi") => {
19228                "Sacred completeness - mala beads, Upanishads, sun ratio"
19229            }
19230            (3, "hindu" | "indian" | "hi") => "Trimurti - Brahma, Vishnu, Shiva",
19231            (9, "hindu" | "indian" | "hi") => "Navagraha (9 planets), Durga's 9 forms",
19232
19233            // Islamic
19234            (99, "islamic" | "arabic" | "ar") => "Asma ul-Husna - 99 names of Allah",
19235            (5, "islamic" | "arabic" | "ar") => "Five pillars of Islam",
19236            (786, "islamic" | "arabic" | "ar") => "Abjad numerology of Bismillah",
19237
19238            // Greek/Pythagorean
19239            (10, "greek" | "pythagorean") => "Tetractys - 1+2+3+4, perfect number",
19240            (7, "greek" | "pythagorean") => "Heptad - virgin number, Athena's number",
19241
19242            _ => "No specific cultural meaning recorded",
19243        };
19244
19245        let mut result = std::collections::HashMap::new();
19246        result.insert("number".to_string(), Value::Int(n));
19247        result.insert("culture".to_string(), Value::String(Rc::new(culture)));
19248        result.insert(
19249            "meaning".to_string(),
19250            Value::String(Rc::new(meaning.to_string())),
19251        );
19252
19253        Ok(Value::Map(Rc::new(RefCell::new(result))))
19254    });
19255
19256    // === Time encoding using Babylonian sexagesimal ===
19257
19258    // to_babylonian_time - convert seconds to Babylonian notation
19259    define(interp, "to_babylonian_time", Some(1), |_, args| {
19260        let seconds = match &args[0] {
19261            Value::Int(n) => *n,
19262            Value::Float(f) => *f as i64,
19263            _ => return Err(RuntimeError::new("to_babylonian_time() requires number")),
19264        };
19265
19266        let hours = seconds / 3600;
19267        let mins = (seconds % 3600) / 60;
19268        let secs = seconds % 60;
19269
19270        Ok(Value::String(Rc::new(format!(
19271            "0s[{}:{}:{}]",
19272            hours, mins, secs
19273        ))))
19274    });
19275
19276    // from_babylonian_time - convert Babylonian time to seconds
19277    define(interp, "from_babylonian_time", Some(1), |_, args| {
19278        let s = match &args[0] {
19279            Value::String(s) => s.to_string(),
19280            _ => return Err(RuntimeError::new("from_babylonian_time() requires string")),
19281        };
19282
19283        let clean = s
19284            .trim_start_matches("0s")
19285            .trim_start_matches('[')
19286            .trim_end_matches(']');
19287
19288        let parts: Vec<i64> = clean
19289            .split(':')
19290            .map(|p| p.trim().parse::<i64>().unwrap_or(0))
19291            .collect();
19292
19293        let seconds = match parts.len() {
19294            1 => parts[0],
19295            2 => parts[0] * 60 + parts[1],
19296            3 => parts[0] * 3600 + parts[1] * 60 + parts[2],
19297            _ => return Err(RuntimeError::new("Invalid Babylonian time format")),
19298        };
19299
19300        Ok(Value::Int(seconds))
19301    });
19302
19303    // === Multi-base secret sharing ===
19304
19305    // vigesimal_shares - split secret with shares in Mayan base-20
19306    define(interp, "vigesimal_shares", Some(3), |_, args| {
19307        let secret = match &args[0] {
19308            Value::String(s) => s.as_bytes().to_vec(),
19309            _ => {
19310                return Err(RuntimeError::new(
19311                    "vigesimal_shares() requires string secret",
19312                ))
19313            }
19314        };
19315
19316        let threshold = match &args[1] {
19317            Value::Int(n) => *n as usize,
19318            _ => {
19319                return Err(RuntimeError::new(
19320                    "vigesimal_shares() requires integer threshold",
19321                ))
19322            }
19323        };
19324
19325        let num_shares = match &args[2] {
19326            Value::Int(n) => *n as usize,
19327            _ => {
19328                return Err(RuntimeError::new(
19329                    "vigesimal_shares() requires integer num_shares",
19330                ))
19331            }
19332        };
19333
19334        if threshold < 2 || num_shares < threshold || num_shares > 20 {
19335            return Err(RuntimeError::new(
19336                "vigesimal_shares() requires 2 <= threshold <= num_shares <= 20 (Mayan limit)",
19337            ));
19338        }
19339
19340        // Generate shares using Shamir
19341        let mut rng = rand::thread_rng();
19342        let mut shares: Vec<Vec<u8>> = (0..num_shares)
19343            .map(|_| Vec::with_capacity(secret.len() + 1))
19344            .collect();
19345
19346        for (i, share) in shares.iter_mut().enumerate() {
19347            share.push((i + 1) as u8);
19348        }
19349
19350        for &byte in &secret {
19351            let mut coefficients: Vec<u8> = vec![byte];
19352            for _ in 1..threshold {
19353                coefficients.push(rng.gen());
19354            }
19355
19356            for (i, share) in shares.iter_mut().enumerate() {
19357                let x = (i + 1) as u8;
19358                let y = eval_polynomial_gf256(&coefficients, x);
19359                share.push(y);
19360            }
19361        }
19362
19363        // Encode shares in vigesimal
19364        let share_values: Vec<Value> = shares
19365            .iter()
19366            .enumerate()
19367            .map(|(i, share)| {
19368                let mut entry = std::collections::HashMap::new();
19369
19370                // Convert share bytes to vigesimal string
19371                let mut vig_parts: Vec<String> = Vec::new();
19372                for &byte in share {
19373                    vig_parts.push(to_base_string(byte as u64, 20, true));
19374                }
19375
19376                entry.insert("index".to_string(), Value::Int((i + 1) as i64));
19377                entry.insert(
19378                    "vigesimal".to_string(),
19379                    Value::String(Rc::new(format!("0v{}", vig_parts.join(".")))),
19380                );
19381                entry.insert(
19382                    "hex".to_string(),
19383                    Value::String(Rc::new(hex::encode(share))),
19384                );
19385
19386                Value::Map(Rc::new(RefCell::new(entry)))
19387            })
19388            .collect();
19389
19390        let mut result = std::collections::HashMap::new();
19391        result.insert(
19392            "shares".to_string(),
19393            Value::Array(Rc::new(RefCell::new(share_values))),
19394        );
19395        result.insert("threshold".to_string(), Value::Int(threshold as i64));
19396        result.insert("total".to_string(), Value::Int(num_shares as i64));
19397        result.insert(
19398            "base".to_string(),
19399            Value::String(Rc::new("vigesimal (Mayan base-20)".to_string())),
19400        );
19401
19402        Ok(Value::Map(Rc::new(RefCell::new(result))))
19403    });
19404
19405    // multibase_info - get information about supported bases
19406    define(interp, "multibase_info", Some(0), |_, _| {
19407        let mut info = std::collections::HashMap::new();
19408
19409        let bases = vec![
19410            ("binary", 2, "0b", "Modern computing"),
19411            ("octal", 8, "0o", "Unix, historical computing"),
19412            ("decimal", 10, "", "Indo-Arabic global standard"),
19413            (
19414                "duodecimal",
19415                12,
19416                "0z",
19417                "Dozen system - time, music, measurement",
19418            ),
19419            ("hexadecimal", 16, "0x", "Computing, colors, addresses"),
19420            (
19421                "vigesimal",
19422                20,
19423                "0v",
19424                "Mayan, Celtic, Basque - human digits",
19425            ),
19426            (
19427                "sexagesimal",
19428                60,
19429                "0s",
19430                "Babylonian - time, angles, astronomy",
19431            ),
19432        ];
19433
19434        let base_list: Vec<Value> = bases
19435            .iter()
19436            .map(|(name, base, prefix, desc)| {
19437                let mut entry = std::collections::HashMap::new();
19438                entry.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
19439                entry.insert("base".to_string(), Value::Int(*base as i64));
19440                entry.insert(
19441                    "prefix".to_string(),
19442                    Value::String(Rc::new(prefix.to_string())),
19443                );
19444                entry.insert(
19445                    "origin".to_string(),
19446                    Value::String(Rc::new(desc.to_string())),
19447                );
19448                Value::Map(Rc::new(RefCell::new(entry)))
19449            })
19450            .collect();
19451
19452        info.insert(
19453            "numeral_systems".to_string(),
19454            Value::Array(Rc::new(RefCell::new(base_list))),
19455        );
19456
19457        let encodings = vec!["base58 (Bitcoin)", "base32 (RFC 4648)", "base64 (standard)"];
19458        let enc_list: Vec<Value> = encodings
19459            .iter()
19460            .map(|s| Value::String(Rc::new(s.to_string())))
19461            .collect();
19462        info.insert(
19463            "special_encodings".to_string(),
19464            Value::Array(Rc::new(RefCell::new(enc_list))),
19465        );
19466
19467        let cultures = vec![
19468            "mayan",
19469            "babylonian",
19470            "chinese",
19471            "japanese",
19472            "hebrew",
19473            "islamic",
19474            "hindu",
19475            "greek",
19476            "celtic",
19477        ];
19478        let cult_list: Vec<Value> = cultures
19479            .iter()
19480            .map(|s| Value::String(Rc::new(s.to_string())))
19481            .collect();
19482        info.insert(
19483            "supported_cultures".to_string(),
19484            Value::Array(Rc::new(RefCell::new(cult_list))),
19485        );
19486
19487        Ok(Value::Map(Rc::new(RefCell::new(info))))
19488    });
19489}
19490
19491// Helper functions for base conversion
19492
19493fn to_base_string(mut n: u64, base: u64, pad_to_two: bool) -> String {
19494    const DIGITS: &[u8] = b"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
19495
19496    if n == 0 {
19497        return if pad_to_two {
19498            "00".to_string()
19499        } else {
19500            "0".to_string()
19501        };
19502    }
19503
19504    let mut result = Vec::new();
19505    while n > 0 {
19506        result.push(DIGITS[(n % base) as usize] as char);
19507        n /= base;
19508    }
19509
19510    if pad_to_two && result.len() < 2 {
19511        result.push('0');
19512    }
19513
19514    result.reverse();
19515    result.into_iter().collect()
19516}
19517
19518fn to_base_string_custom(mut n: u64, base: u64, digits: &str) -> String {
19519    if n == 0 {
19520        return digits.chars().next().unwrap().to_string();
19521    }
19522
19523    let mut result = Vec::new();
19524    let digit_chars: Vec<char> = digits.chars().collect();
19525
19526    while n > 0 {
19527        result.push(digit_chars[(n % base) as usize]);
19528        n /= base;
19529    }
19530
19531    result.reverse();
19532    result.into_iter().collect()
19533}
19534
19535fn from_base_string(s: &str, base: u64) -> Result<u64, RuntimeError> {
19536    let mut result: u64 = 0;
19537
19538    for c in s.chars() {
19539        let digit = match c {
19540            '0'..='9' => c as u64 - '0' as u64,
19541            'A'..='Z' => c as u64 - 'A' as u64 + 10,
19542            'a'..='z' => c as u64 - 'a' as u64 + 10,
19543            _ => return Err(RuntimeError::new(format!("Invalid digit: {}", c))),
19544        };
19545
19546        if digit >= base {
19547            return Err(RuntimeError::new(format!(
19548                "Digit {} out of range for base {}",
19549                c, base
19550            )));
19551        }
19552
19553        result = result
19554            .checked_mul(base)
19555            .and_then(|r| r.checked_add(digit))
19556            .ok_or_else(|| RuntimeError::new("Number overflow"))?;
19557    }
19558
19559    Ok(result)
19560}
19561
19562fn from_base_string_custom(s: &str, digits: &str) -> Result<u64, RuntimeError> {
19563    let base = digits.len() as u64;
19564    let mut result: u64 = 0;
19565
19566    for c in s.chars() {
19567        let digit = digits
19568            .find(c)
19569            .ok_or_else(|| RuntimeError::new(format!("Invalid digit: {}", c)))?
19570            as u64;
19571
19572        result = result
19573            .checked_mul(base)
19574            .and_then(|r| r.checked_add(digit))
19575            .ok_or_else(|| RuntimeError::new("Number overflow"))?;
19576    }
19577
19578    Ok(result)
19579}
19580
19581fn parse_base_prefix(s: &str, prefix: &str) -> (bool, String) {
19582    let negative = s.starts_with('-');
19583    let clean = s
19584        .trim_start_matches('-')
19585        .trim_start_matches(prefix)
19586        .to_string();
19587    (negative, clean)
19588}
19589
19590// ============================================================================
19591// POLYCULTURAL AUDIO: World tuning systems, sacred frequencies, synthesis
19592// ============================================================================
19593//
19594// Sigil's audio system respects that music is not universal - different cultures
19595// have fundamentally different relationships with pitch, scale, and meaning.
19596//
19597// Waveform Morphemes:
19598//   ∿  sine     - pure tone, fundamental
19599//   ⊓  square   - digital, odd harmonics
19600//   ⋀  sawtooth - bright, all harmonics
19601//   △  triangle - mellow, odd harmonics (weaker)
19602//
19603// Tuning Systems:
19604//   12-TET     - Western equal temperament (default)
19605//   24-TET     - Arabic maqam (quarter tones)
19606//   22-Shruti  - Indian classical (microtones)
19607//   Just       - Pure ratios (Pythagorean, etc.)
19608//   Gamelan    - Indonesian (pelog, slendro)
19609//   53-TET     - Turkish/Persian (commas)
19610//
19611// Sacred Frequencies:
19612//   ॐ Om       - 136.1 Hz (Earth year frequency)
19613//   Solfeggio  - 396, 417, 528, 639, 741, 852 Hz
19614//   Schumann   - 7.83 Hz (Earth resonance)
19615//   Planetary  - Kepler's music of the spheres
19616
19617fn register_audio(interp: &mut Interpreter) {
19618    // =========================================================================
19619    // TUNING SYSTEMS
19620    // =========================================================================
19621
19622    // tune - convert a note to frequency in a specific tuning system
19623    // Supports: "12tet", "24tet", "just", "pythagorean", "meantone", "gamelan_pelog", "gamelan_slendro"
19624    define(interp, "tune", Some(3), |_, args| {
19625        let note = match &args[0] {
19626            Value::Int(n) => *n as f64, // MIDI note number
19627            Value::Float(f) => *f,      // Fractional note
19628            Value::String(s) => parse_note_name(s)?,
19629            _ => return Err(RuntimeError::new("tune() requires note number or name")),
19630        };
19631
19632        let system = match &args[1] {
19633            Value::String(s) => s.to_lowercase(),
19634            _ => return Err(RuntimeError::new("tune() requires tuning system name")),
19635        };
19636
19637        let root_freq = match &args[2] {
19638            Value::Float(f) => *f,
19639            Value::Int(i) => *i as f64,
19640            _ => return Err(RuntimeError::new("tune() requires root frequency")),
19641        };
19642
19643        let freq = match system.as_str() {
19644            "12tet" | "equal" | "western" => {
19645                // Standard 12-tone equal temperament
19646                root_freq * 2.0_f64.powf((note - 69.0) / 12.0)
19647            }
19648            "24tet" | "quarter" | "arabic" | "maqam" => {
19649                // 24-tone equal temperament (quarter tones)
19650                root_freq * 2.0_f64.powf((note - 69.0) / 24.0)
19651            }
19652            "just" | "pure" => {
19653                // Just intonation ratios from root
19654                let interval = ((note - 69.0) % 12.0 + 12.0) % 12.0;
19655                let octave = ((note - 69.0) / 12.0).floor();
19656                let ratio = just_intonation_ratio(interval as i32);
19657                root_freq * ratio * 2.0_f64.powf(octave)
19658            }
19659            "pythagorean" => {
19660                // Pythagorean tuning (pure fifths)
19661                let interval = ((note - 69.0) % 12.0 + 12.0) % 12.0;
19662                let octave = ((note - 69.0) / 12.0).floor();
19663                let ratio = pythagorean_ratio(interval as i32);
19664                root_freq * ratio * 2.0_f64.powf(octave)
19665            }
19666            "meantone" | "quarter_comma" => {
19667                // Quarter-comma meantone
19668                let interval = ((note - 69.0) % 12.0 + 12.0) % 12.0;
19669                let octave = ((note - 69.0) / 12.0).floor();
19670                let ratio = meantone_ratio(interval as i32);
19671                root_freq * ratio * 2.0_f64.powf(octave)
19672            }
19673            "53tet" | "turkish" | "persian" | "comma" => {
19674                // 53-TET (Turkish/Persian music, approximates just intonation)
19675                root_freq * 2.0_f64.powf((note - 69.0) / 53.0)
19676            }
19677            "22shruti" | "shruti" | "indian" => {
19678                // Indian 22-shruti system
19679                let shruti = (note - 69.0) % 22.0;
19680                let octave = ((note - 69.0) / 22.0).floor();
19681                let ratio = shruti_ratio(shruti as i32);
19682                root_freq * ratio * 2.0_f64.powf(octave)
19683            }
19684            "gamelan_pelog" | "pelog" => {
19685                // Javanese pelog (7-note)
19686                let degree = ((note - 69.0) % 7.0 + 7.0) % 7.0;
19687                let octave = ((note - 69.0) / 7.0).floor();
19688                let ratio = pelog_ratio(degree as i32);
19689                root_freq * ratio * 2.0_f64.powf(octave)
19690            }
19691            "gamelan_slendro" | "slendro" => {
19692                // Javanese slendro (5-note, roughly equal)
19693                let degree = ((note - 69.0) % 5.0 + 5.0) % 5.0;
19694                let octave = ((note - 69.0) / 5.0).floor();
19695                let ratio = slendro_ratio(degree as i32);
19696                root_freq * ratio * 2.0_f64.powf(octave)
19697            }
19698            "bohlen_pierce" | "bp" => {
19699                // Bohlen-Pierce scale (tritave-based, 13 steps)
19700                root_freq * 3.0_f64.powf((note - 69.0) / 13.0)
19701            }
19702            _ => {
19703                return Err(RuntimeError::new(format!(
19704                    "Unknown tuning system: {}",
19705                    system
19706                )))
19707            }
19708        };
19709
19710        Ok(Value::Float(freq))
19711    });
19712
19713    // tuning_info - get information about a tuning system
19714    define(interp, "tuning_info", Some(1), |_, args| {
19715        let system = match &args[0] {
19716            Value::String(s) => s.to_lowercase(),
19717            _ => return Err(RuntimeError::new("tuning_info() requires string")),
19718        };
19719
19720        let (name, notes_per_octave, origin, description) = match system.as_str() {
19721            "12tet" | "equal" | "western" => (
19722                "12-TET", 12, "Western (18th century)",
19723                "Equal temperament - every semitone is exactly 2^(1/12). Universal but slightly impure."
19724            ),
19725            "24tet" | "quarter" | "arabic" | "maqam" => (
19726                "24-TET", 24, "Arabic/Turkish",
19727                "Quarter-tone system for maqam music. Enables neutral seconds and other microtones."
19728            ),
19729            "just" | "pure" => (
19730                "Just Intonation", 12, "Ancient (Ptolemy)",
19731                "Pure frequency ratios (3:2 fifth, 5:4 third). Beatless intervals but limited modulation."
19732            ),
19733            "pythagorean" => (
19734                "Pythagorean", 12, "Ancient Greece",
19735                "Built entirely from perfect fifths (3:2). Pure fifths but harsh thirds."
19736            ),
19737            "meantone" | "quarter_comma" => (
19738                "Quarter-Comma Meantone", 12, "Renaissance Europe",
19739                "Tempered fifths for pure major thirds. Beautiful in limited keys."
19740            ),
19741            "53tet" | "turkish" | "persian" | "comma" => (
19742                "53-TET", 53, "Turkish/Persian",
19743                "53 notes per octave. Closely approximates just intonation and allows maqam/dastgah."
19744            ),
19745            "22shruti" | "shruti" | "indian" => (
19746                "22-Shruti", 22, "Indian Classical",
19747                "Ancient Indian system. Each shruti is a 'microtone' - the smallest perceptible interval."
19748            ),
19749            "gamelan_pelog" | "pelog" => (
19750                "Pelog", 7, "Javanese Gamelan",
19751                "Heptatonic scale with unequal steps. Each gamelan has unique tuning - instruments are married."
19752            ),
19753            "gamelan_slendro" | "slendro" => (
19754                "Slendro", 5, "Javanese Gamelan",
19755                "Pentatonic scale, roughly equal steps (~240 cents). Each ensemble uniquely tuned."
19756            ),
19757            "bohlen_pierce" | "bp" => (
19758                "Bohlen-Pierce", 13, "Modern (1970s)",
19759                "Non-octave scale based on 3:1 tritave. Alien but mathematically beautiful."
19760            ),
19761            _ => return Err(RuntimeError::new(format!("Unknown tuning system: {}", system))),
19762        };
19763
19764        let mut info = std::collections::HashMap::new();
19765        info.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
19766        info.insert("notes_per_octave".to_string(), Value::Int(notes_per_octave));
19767        info.insert(
19768            "origin".to_string(),
19769            Value::String(Rc::new(origin.to_string())),
19770        );
19771        info.insert(
19772            "description".to_string(),
19773            Value::String(Rc::new(description.to_string())),
19774        );
19775
19776        Ok(Value::Map(Rc::new(RefCell::new(info))))
19777    });
19778
19779    // list_tuning_systems - list all available tuning systems
19780    define(interp, "list_tuning_systems", Some(0), |_, _| {
19781        let systems = vec![
19782            ("12tet", "Western equal temperament", 12),
19783            ("24tet", "Arabic/Turkish quarter-tones", 24),
19784            ("just", "Pure ratio just intonation", 12),
19785            ("pythagorean", "Ancient Greek pure fifths", 12),
19786            ("meantone", "Renaissance quarter-comma", 12),
19787            ("53tet", "Turkish/Persian comma system", 53),
19788            ("22shruti", "Indian microtonal", 22),
19789            ("pelog", "Javanese gamelan 7-note", 7),
19790            ("slendro", "Javanese gamelan 5-note", 5),
19791            ("bohlen_pierce", "Non-octave tritave scale", 13),
19792        ];
19793
19794        let result: Vec<Value> = systems
19795            .iter()
19796            .map(|(name, desc, notes)| {
19797                let mut entry = std::collections::HashMap::new();
19798                entry.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
19799                entry.insert(
19800                    "description".to_string(),
19801                    Value::String(Rc::new(desc.to_string())),
19802                );
19803                entry.insert("notes_per_octave".to_string(), Value::Int(*notes));
19804                Value::Map(Rc::new(RefCell::new(entry)))
19805            })
19806            .collect();
19807
19808        Ok(Value::Array(Rc::new(RefCell::new(result))))
19809    });
19810
19811    // =========================================================================
19812    // SACRED FREQUENCIES
19813    // =========================================================================
19814
19815    // sacred_freq - get sacred/spiritual frequency by name
19816    define(interp, "sacred_freq", Some(1), |_, args| {
19817        let name = match &args[0] {
19818            Value::String(s) => s.to_lowercase(),
19819            _ => return Err(RuntimeError::new("sacred_freq() requires string")),
19820        };
19821
19822        let (freq, description) = match name.as_str() {
19823            // Om and Earth frequencies
19824            "om" | "ॐ" | "aum" => (136.1, "Om - Earth year frequency (Cosmic Om)"),
19825            "earth_day" => (194.18, "Earth day - one rotation"),
19826            "earth_year" => (136.1, "Earth year - one orbit (Om frequency)"),
19827            "schumann" | "earth_resonance" => (
19828                7.83,
19829                "Schumann resonance - Earth's electromagnetic heartbeat",
19830            ),
19831
19832            // Solfeggio frequencies
19833            "ut" | "do" | "396" => (396.0, "UT/DO - Liberating guilt and fear"),
19834            "re" | "417" => (417.0, "RE - Undoing situations, facilitating change"),
19835            "mi" | "528" => (528.0, "MI - Transformation, miracles, DNA repair"),
19836            "fa" | "639" => (639.0, "FA - Connecting relationships"),
19837            "sol" | "741" => (741.0, "SOL - Awakening intuition"),
19838            "la" | "852" => (852.0, "LA - Returning to spiritual order"),
19839            "si" | "963" => (963.0, "SI - Divine consciousness, enlightenment"),
19840            "174" => (174.0, "Solfeggio foundation - pain relief"),
19841            "285" => (285.0, "Solfeggio - healing tissue"),
19842
19843            // Planetary frequencies (Kepler/Cousto)
19844            "sun" | "☉" => (126.22, "Sun - ego, vitality, leadership"),
19845            "moon" | "☽" | "☾" => (210.42, "Moon - emotion, intuition, cycles"),
19846            "mercury" | "☿" => (141.27, "Mercury - communication, intellect"),
19847            "venus" | "♀" => (221.23, "Venus - love, beauty, harmony"),
19848            "mars" | "♂" => (144.72, "Mars - energy, action, courage"),
19849            "jupiter" | "♃" => (183.58, "Jupiter - expansion, wisdom, luck"),
19850            "saturn" | "♄" => (147.85, "Saturn - discipline, structure, time"),
19851
19852            // Chakra frequencies
19853            "root" | "muladhara" => (256.0, "Root chakra - survival, grounding (C)"),
19854            "sacral" | "svadhisthana" => (288.0, "Sacral chakra - creativity, sexuality (D)"),
19855            "solar" | "manipura" => (320.0, "Solar plexus - will, power (E)"),
19856            "heart" | "anahata" => (341.3, "Heart chakra - love, compassion (F)"),
19857            "throat" | "vishuddha" => (384.0, "Throat chakra - expression, truth (G)"),
19858            "third_eye" | "ajna" => (426.7, "Third eye - intuition, insight (A)"),
19859            "crown" | "sahasrara" => (480.0, "Crown chakra - consciousness, unity (B)"),
19860
19861            // Concert pitch standards
19862            "a440" | "iso" => (440.0, "ISO standard concert pitch (1955)"),
19863            "a432" | "verdi" => (
19864                432.0,
19865                "Verdi pitch - 'mathematically consistent with universe'",
19866            ),
19867            "a415" | "baroque" => (415.0, "Baroque pitch - period instrument standard"),
19868            "a466" | "chorton" => (466.0, "Choir pitch - high Baroque German"),
19869
19870            // Binaural/brainwave
19871            "delta" => (2.0, "Delta waves - deep sleep, healing (0.5-4 Hz)"),
19872            "theta" => (6.0, "Theta waves - meditation, creativity (4-8 Hz)"),
19873            "alpha" => (10.0, "Alpha waves - relaxation, calm focus (8-13 Hz)"),
19874            "beta" => (20.0, "Beta waves - alertness, concentration (13-30 Hz)"),
19875            "gamma" => (40.0, "Gamma waves - insight, peak performance (30-100 Hz)"),
19876
19877            _ => {
19878                return Err(RuntimeError::new(format!(
19879                    "Unknown sacred frequency: {}",
19880                    name
19881                )))
19882            }
19883        };
19884
19885        let mut result = std::collections::HashMap::new();
19886        result.insert("frequency".to_string(), Value::Float(freq));
19887        result.insert("name".to_string(), Value::String(Rc::new(name)));
19888        result.insert(
19889            "meaning".to_string(),
19890            Value::String(Rc::new(description.to_string())),
19891        );
19892
19893        Ok(Value::Map(Rc::new(RefCell::new(result))))
19894    });
19895
19896    // solfeggio - get all solfeggio frequencies
19897    define(interp, "solfeggio", Some(0), |_, _| {
19898        let frequencies = vec![
19899            (174.0, "Foundation", "Pain relief, security"),
19900            (285.0, "Quantum", "Healing tissue, safety"),
19901            (396.0, "UT", "Liberating guilt and fear"),
19902            (417.0, "RE", "Undoing situations, change"),
19903            (528.0, "MI", "Transformation, DNA repair, miracles"),
19904            (639.0, "FA", "Connecting relationships"),
19905            (741.0, "SOL", "Awakening intuition"),
19906            (852.0, "LA", "Spiritual order"),
19907            (963.0, "SI", "Divine consciousness"),
19908        ];
19909
19910        let result: Vec<Value> = frequencies
19911            .iter()
19912            .map(|(freq, name, meaning)| {
19913                let mut entry = std::collections::HashMap::new();
19914                entry.insert("frequency".to_string(), Value::Float(*freq));
19915                entry.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
19916                entry.insert(
19917                    "meaning".to_string(),
19918                    Value::String(Rc::new(meaning.to_string())),
19919                );
19920                Value::Map(Rc::new(RefCell::new(entry)))
19921            })
19922            .collect();
19923
19924        Ok(Value::Array(Rc::new(RefCell::new(result))))
19925    });
19926
19927    // chakras - get all chakra frequencies
19928    define(interp, "chakras", Some(0), |_, _| {
19929        let chakras = vec![
19930            (
19931                256.0,
19932                "Muladhara",
19933                "Root",
19934                "Red",
19935                "Survival, grounding, stability",
19936            ),
19937            (
19938                288.0,
19939                "Svadhisthana",
19940                "Sacral",
19941                "Orange",
19942                "Creativity, sexuality, emotion",
19943            ),
19944            (
19945                320.0,
19946                "Manipura",
19947                "Solar Plexus",
19948                "Yellow",
19949                "Will, power, self-esteem",
19950            ),
19951            (
19952                341.3,
19953                "Anahata",
19954                "Heart",
19955                "Green",
19956                "Love, compassion, connection",
19957            ),
19958            (
19959                384.0,
19960                "Vishuddha",
19961                "Throat",
19962                "Blue",
19963                "Expression, truth, communication",
19964            ),
19965            (
19966                426.7,
19967                "Ajna",
19968                "Third Eye",
19969                "Indigo",
19970                "Intuition, insight, wisdom",
19971            ),
19972            (
19973                480.0,
19974                "Sahasrara",
19975                "Crown",
19976                "Violet",
19977                "Consciousness, unity, transcendence",
19978            ),
19979        ];
19980
19981        let result: Vec<Value> = chakras
19982            .iter()
19983            .map(|(freq, sanskrit, english, color, meaning)| {
19984                let mut entry = std::collections::HashMap::new();
19985                entry.insert("frequency".to_string(), Value::Float(*freq));
19986                entry.insert(
19987                    "sanskrit".to_string(),
19988                    Value::String(Rc::new(sanskrit.to_string())),
19989                );
19990                entry.insert(
19991                    "english".to_string(),
19992                    Value::String(Rc::new(english.to_string())),
19993                );
19994                entry.insert(
19995                    "color".to_string(),
19996                    Value::String(Rc::new(color.to_string())),
19997                );
19998                entry.insert(
19999                    "meaning".to_string(),
20000                    Value::String(Rc::new(meaning.to_string())),
20001                );
20002                Value::Map(Rc::new(RefCell::new(entry)))
20003            })
20004            .collect();
20005
20006        Ok(Value::Array(Rc::new(RefCell::new(result))))
20007    });
20008
20009    // =========================================================================
20010    // WAVEFORM GENERATION
20011    // =========================================================================
20012
20013    // Generate waveform samples - returns array of floats [-1.0, 1.0]
20014
20015    // sine - pure sine wave ∿
20016    define(interp, "sine", Some(3), |_, args| {
20017        generate_waveform(&args, |phase| phase.sin())
20018    });
20019
20020    // square - square wave ⊓
20021    define(interp, "square", Some(3), |_, args| {
20022        generate_waveform(&args, |phase| if phase.sin() >= 0.0 { 1.0 } else { -1.0 })
20023    });
20024
20025    // sawtooth - sawtooth wave ⋀
20026    define(interp, "sawtooth", Some(3), |_, args| {
20027        generate_waveform(&args, |phase| {
20028            let normalized = (phase / std::f64::consts::TAU).fract();
20029            2.0 * normalized - 1.0
20030        })
20031    });
20032
20033    // triangle - triangle wave △
20034    define(interp, "triangle", Some(3), |_, args| {
20035        generate_waveform(&args, |phase| {
20036            let normalized = (phase / std::f64::consts::TAU).fract();
20037            if normalized < 0.5 {
20038                4.0 * normalized - 1.0
20039            } else {
20040                3.0 - 4.0 * normalized
20041            }
20042        })
20043    });
20044
20045    // noise - white noise
20046    define(interp, "noise", Some(1), |_, args| {
20047        let samples = match &args[0] {
20048            Value::Int(n) => *n as usize,
20049            _ => return Err(RuntimeError::new("noise() requires integer sample count")),
20050        };
20051
20052        let mut rng = rand::thread_rng();
20053        let result: Vec<Value> = (0..samples)
20054            .map(|_| Value::Float(rng.gen::<f64>() * 2.0 - 1.0))
20055            .collect();
20056
20057        Ok(Value::Array(Rc::new(RefCell::new(result))))
20058    });
20059
20060    // =========================================================================
20061    // CULTURAL SCALES
20062    // =========================================================================
20063
20064    // scale - get scale degrees for a cultural scale
20065    define(interp, "scale", Some(1), |_, args| {
20066        let name = match &args[0] {
20067            Value::String(s) => s.to_lowercase(),
20068            _ => return Err(RuntimeError::new("scale() requires string")),
20069        };
20070
20071        let (intervals, origin, description) = match name.as_str() {
20072            // Western modes
20073            "major" | "ionian" => (
20074                vec![0, 2, 4, 5, 7, 9, 11],
20075                "Western",
20076                "Happy, bright, resolved",
20077            ),
20078            "minor" | "aeolian" => (
20079                vec![0, 2, 3, 5, 7, 8, 10],
20080                "Western",
20081                "Sad, dark, introspective",
20082            ),
20083            "dorian" => (
20084                vec![0, 2, 3, 5, 7, 9, 10],
20085                "Western/Jazz",
20086                "Minor with bright 6th",
20087            ),
20088            "phrygian" => (
20089                vec![0, 1, 3, 5, 7, 8, 10],
20090                "Western/Flamenco",
20091                "Spanish, exotic, tense",
20092            ),
20093            "lydian" => (
20094                vec![0, 2, 4, 6, 7, 9, 11],
20095                "Western",
20096                "Dreamy, floating, ethereal",
20097            ),
20098            "mixolydian" => (vec![0, 2, 4, 5, 7, 9, 10], "Western/Blues", "Bluesy major"),
20099            "locrian" => (vec![0, 1, 3, 5, 6, 8, 10], "Western", "Unstable, dissonant"),
20100
20101            // Pentatonic
20102            "pentatonic_major" => (vec![0, 2, 4, 7, 9], "Universal", "No dissonance, universal"),
20103            "pentatonic_minor" => (vec![0, 3, 5, 7, 10], "Universal", "Blues foundation"),
20104
20105            // Japanese
20106            "hirajoshi" => (vec![0, 2, 3, 7, 8], "Japanese", "Melancholic, mysterious"),
20107            "insen" => (vec![0, 1, 5, 7, 10], "Japanese", "Dark, zen, contemplative"),
20108            "iwato" => (vec![0, 1, 5, 6, 10], "Japanese", "Most dark and dissonant"),
20109            "kumoi" => (vec![0, 2, 3, 7, 9], "Japanese", "Gentle, peaceful"),
20110            "yo" => (vec![0, 2, 5, 7, 9], "Japanese", "Bright, folk, celebratory"),
20111
20112            // Arabic maqamat
20113            "hijaz" => (
20114                vec![0, 1, 4, 5, 7, 8, 11],
20115                "Arabic",
20116                "Exotic, Middle Eastern",
20117            ),
20118            "bayati" => (
20119                vec![0, 1.5 as i32, 3, 5, 7, 8, 10],
20120                "Arabic",
20121                "Quarter-tone, soulful",
20122            ),
20123            "rast" => (
20124                vec![0, 2, 3.5 as i32, 5, 7, 9, 10.5 as i32],
20125                "Arabic",
20126                "Foundation maqam",
20127            ),
20128            "saba" => (
20129                vec![0, 1.5 as i32, 3, 4, 5, 8, 10],
20130                "Arabic",
20131                "Sad, spiritual",
20132            ),
20133
20134            // Indian ragas (approximated to 12-TET)
20135            "bhairav" => (
20136                vec![0, 1, 4, 5, 7, 8, 11],
20137                "Indian",
20138                "Morning raga, devotional",
20139            ),
20140            "yaman" | "kalyan" => (vec![0, 2, 4, 6, 7, 9, 11], "Indian", "Evening, romantic"),
20141            "bhairavi" => (
20142                vec![0, 1, 3, 5, 7, 8, 10],
20143                "Indian",
20144                "Concluding raga, devotional",
20145            ),
20146            "todi" => (vec![0, 1, 3, 6, 7, 8, 11], "Indian", "Serious, pathos"),
20147            "marwa" => (vec![0, 1, 4, 6, 7, 9, 11], "Indian", "Evening, longing"),
20148
20149            // Blues
20150            "blues" => (vec![0, 3, 5, 6, 7, 10], "American", "Blue notes, soul"),
20151
20152            // Hungarian/Eastern European
20153            "hungarian_minor" => (vec![0, 2, 3, 6, 7, 8, 11], "Hungarian", "Gypsy, dramatic"),
20154            "romanian" => (vec![0, 2, 3, 6, 7, 9, 10], "Romanian", "Folk, energetic"),
20155
20156            // Jewish
20157            "ahava_raba" | "freygish" => (
20158                vec![0, 1, 4, 5, 7, 8, 10],
20159                "Jewish/Klezmer",
20160                "Cantorial, emotional",
20161            ),
20162            "mi_sheberach" => (vec![0, 2, 3, 6, 7, 9, 10], "Jewish", "Prayer mode"),
20163
20164            // Chinese
20165            "gong" => (vec![0, 2, 4, 7, 9], "Chinese", "Palace mode, major-like"),
20166            "shang" => (vec![0, 2, 5, 7, 9], "Chinese", "Merchant mode"),
20167            "jue" => (vec![0, 3, 5, 7, 10], "Chinese", "Angle mode"),
20168            "zhi" => (vec![0, 2, 5, 7, 10], "Chinese", "Emblem mode"),
20169            "yu" => (vec![0, 3, 5, 8, 10], "Chinese", "Wings mode, minor-like"),
20170
20171            // Indonesian
20172            "pelog" => (
20173                vec![0, 1, 3, 7, 8],
20174                "Javanese",
20175                "7-note unequal temperament",
20176            ),
20177            "slendro" => (vec![0, 2, 5, 7, 9], "Javanese", "5-note roughly equal"),
20178
20179            // Other
20180            "whole_tone" => (
20181                vec![0, 2, 4, 6, 8, 10],
20182                "Impressionist",
20183                "Dreamlike, no resolution",
20184            ),
20185            "chromatic" => (
20186                vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
20187                "Western",
20188                "All 12 notes",
20189            ),
20190            "diminished" => (vec![0, 2, 3, 5, 6, 8, 9, 11], "Jazz", "Symmetric, tense"),
20191            "augmented" => (vec![0, 3, 4, 7, 8, 11], "Jazz", "Symmetric, floating"),
20192
20193            _ => return Err(RuntimeError::new(format!("Unknown scale: {}", name))),
20194        };
20195
20196        let mut result = std::collections::HashMap::new();
20197        let intervals_values: Vec<Value> =
20198            intervals.iter().map(|&i| Value::Int(i as i64)).collect();
20199        result.insert(
20200            "intervals".to_string(),
20201            Value::Array(Rc::new(RefCell::new(intervals_values))),
20202        );
20203        result.insert(
20204            "origin".to_string(),
20205            Value::String(Rc::new(origin.to_string())),
20206        );
20207        result.insert(
20208            "character".to_string(),
20209            Value::String(Rc::new(description.to_string())),
20210        );
20211        result.insert("name".to_string(), Value::String(Rc::new(name)));
20212
20213        Ok(Value::Map(Rc::new(RefCell::new(result))))
20214    });
20215
20216    // list_scales - list all available scales grouped by culture
20217    define(interp, "list_scales", Some(0), |_, _| {
20218        let mut cultures = std::collections::HashMap::new();
20219
20220        cultures.insert(
20221            "western".to_string(),
20222            Value::Array(Rc::new(RefCell::new(vec![
20223                Value::String(Rc::new("major".to_string())),
20224                Value::String(Rc::new("minor".to_string())),
20225                Value::String(Rc::new("dorian".to_string())),
20226                Value::String(Rc::new("phrygian".to_string())),
20227                Value::String(Rc::new("lydian".to_string())),
20228                Value::String(Rc::new("mixolydian".to_string())),
20229                Value::String(Rc::new("locrian".to_string())),
20230            ]))),
20231        );
20232
20233        cultures.insert(
20234            "japanese".to_string(),
20235            Value::Array(Rc::new(RefCell::new(vec![
20236                Value::String(Rc::new("hirajoshi".to_string())),
20237                Value::String(Rc::new("insen".to_string())),
20238                Value::String(Rc::new("iwato".to_string())),
20239                Value::String(Rc::new("kumoi".to_string())),
20240                Value::String(Rc::new("yo".to_string())),
20241            ]))),
20242        );
20243
20244        cultures.insert(
20245            "arabic".to_string(),
20246            Value::Array(Rc::new(RefCell::new(vec![
20247                Value::String(Rc::new("hijaz".to_string())),
20248                Value::String(Rc::new("bayati".to_string())),
20249                Value::String(Rc::new("rast".to_string())),
20250                Value::String(Rc::new("saba".to_string())),
20251            ]))),
20252        );
20253
20254        cultures.insert(
20255            "indian".to_string(),
20256            Value::Array(Rc::new(RefCell::new(vec![
20257                Value::String(Rc::new("bhairav".to_string())),
20258                Value::String(Rc::new("yaman".to_string())),
20259                Value::String(Rc::new("bhairavi".to_string())),
20260                Value::String(Rc::new("todi".to_string())),
20261                Value::String(Rc::new("marwa".to_string())),
20262            ]))),
20263        );
20264
20265        cultures.insert(
20266            "chinese".to_string(),
20267            Value::Array(Rc::new(RefCell::new(vec![
20268                Value::String(Rc::new("gong".to_string())),
20269                Value::String(Rc::new("shang".to_string())),
20270                Value::String(Rc::new("jue".to_string())),
20271                Value::String(Rc::new("zhi".to_string())),
20272                Value::String(Rc::new("yu".to_string())),
20273            ]))),
20274        );
20275
20276        cultures.insert(
20277            "jewish".to_string(),
20278            Value::Array(Rc::new(RefCell::new(vec![
20279                Value::String(Rc::new("ahava_raba".to_string())),
20280                Value::String(Rc::new("mi_sheberach".to_string())),
20281            ]))),
20282        );
20283
20284        cultures.insert(
20285            "indonesian".to_string(),
20286            Value::Array(Rc::new(RefCell::new(vec![
20287                Value::String(Rc::new("pelog".to_string())),
20288                Value::String(Rc::new("slendro".to_string())),
20289            ]))),
20290        );
20291
20292        Ok(Value::Map(Rc::new(RefCell::new(cultures))))
20293    });
20294
20295    // =========================================================================
20296    // INTERVALS AND HARMONY
20297    // =========================================================================
20298
20299    // interval_ratio - get the frequency ratio for an interval
20300    define(interp, "interval_ratio", Some(2), |_, args| {
20301        let semitones = match &args[0] {
20302            Value::Int(n) => *n as f64,
20303            Value::Float(f) => *f,
20304            _ => return Err(RuntimeError::new("interval_ratio() requires number")),
20305        };
20306
20307        let tuning = match &args[1] {
20308            Value::String(s) => s.to_lowercase(),
20309            _ => return Err(RuntimeError::new("interval_ratio() requires tuning system")),
20310        };
20311
20312        let ratio = match tuning.as_str() {
20313            "12tet" | "equal" => 2.0_f64.powf(semitones / 12.0),
20314            "just" => just_intonation_ratio(semitones as i32),
20315            "pythagorean" => pythagorean_ratio(semitones as i32),
20316            _ => 2.0_f64.powf(semitones / 12.0),
20317        };
20318
20319        Ok(Value::Float(ratio))
20320    });
20321
20322    // cents_between - calculate cents between two frequencies
20323    define(interp, "cents_between", Some(2), |_, args| {
20324        let f1 = match &args[0] {
20325            Value::Float(f) => *f,
20326            Value::Int(i) => *i as f64,
20327            _ => return Err(RuntimeError::new("cents_between() requires numbers")),
20328        };
20329        let f2 = match &args[1] {
20330            Value::Float(f) => *f,
20331            Value::Int(i) => *i as f64,
20332            _ => return Err(RuntimeError::new("cents_between() requires numbers")),
20333        };
20334
20335        let cents = 1200.0 * (f2 / f1).log2();
20336        Ok(Value::Float(cents))
20337    });
20338
20339    // harmonic_series - generate harmonic series from fundamental
20340    define(interp, "harmonic_series", Some(2), |_, args| {
20341        let fundamental = match &args[0] {
20342            Value::Float(f) => *f,
20343            Value::Int(i) => *i as f64,
20344            _ => return Err(RuntimeError::new("harmonic_series() requires frequency")),
20345        };
20346        let count = match &args[1] {
20347            Value::Int(n) => *n as usize,
20348            _ => return Err(RuntimeError::new("harmonic_series() requires count")),
20349        };
20350
20351        let harmonics: Vec<Value> = (1..=count)
20352            .map(|n| {
20353                let mut entry = std::collections::HashMap::new();
20354                entry.insert("harmonic".to_string(), Value::Int(n as i64));
20355                entry.insert(
20356                    "frequency".to_string(),
20357                    Value::Float(fundamental * n as f64),
20358                );
20359                entry.insert(
20360                    "cents_from_root".to_string(),
20361                    Value::Float(1200.0 * (n as f64).log2()),
20362                );
20363                Value::Map(Rc::new(RefCell::new(entry)))
20364            })
20365            .collect();
20366
20367        Ok(Value::Array(Rc::new(RefCell::new(harmonics))))
20368    });
20369
20370    // =========================================================================
20371    // AUDIO INFO
20372    // =========================================================================
20373
20374    define(interp, "audio_info", Some(0), |_, _| {
20375        let mut info = std::collections::HashMap::new();
20376
20377        info.insert(
20378            "tuning_systems".to_string(),
20379            Value::Array(Rc::new(RefCell::new(vec![
20380                Value::String(Rc::new(
20381                    "12tet, 24tet, just, pythagorean, meantone".to_string(),
20382                )),
20383                Value::String(Rc::new(
20384                    "53tet, 22shruti, pelog, slendro, bohlen_pierce".to_string(),
20385                )),
20386            ]))),
20387        );
20388
20389        info.insert(
20390            "waveforms".to_string(),
20391            Value::Array(Rc::new(RefCell::new(vec![
20392                Value::String(Rc::new("sine (∿)".to_string())),
20393                Value::String(Rc::new("square (⊓)".to_string())),
20394                Value::String(Rc::new("sawtooth (⋀)".to_string())),
20395                Value::String(Rc::new("triangle (△)".to_string())),
20396                Value::String(Rc::new("noise".to_string())),
20397            ]))),
20398        );
20399
20400        info.insert(
20401            "sacred_frequencies".to_string(),
20402            Value::Array(Rc::new(RefCell::new(vec![
20403                Value::String(Rc::new("om, solfeggio, chakras, planets".to_string())),
20404                Value::String(Rc::new(
20405                    "schumann, brainwaves (delta/theta/alpha/beta/gamma)".to_string(),
20406                )),
20407            ]))),
20408        );
20409
20410        info.insert(
20411            "scale_cultures".to_string(),
20412            Value::Array(Rc::new(RefCell::new(vec![
20413                Value::String(Rc::new("western, japanese, arabic, indian".to_string())),
20414                Value::String(Rc::new("chinese, jewish, indonesian".to_string())),
20415            ]))),
20416        );
20417
20418        Ok(Value::Map(Rc::new(RefCell::new(info))))
20419    });
20420}
20421
20422// Helper functions for tuning systems
20423
20424fn parse_note_name(s: &str) -> Result<f64, RuntimeError> {
20425    let s = s.trim().to_uppercase();
20426    let (note, octave_offset) = if s.ends_with(|c: char| c.is_ascii_digit()) {
20427        let octave: i32 = s.chars().last().unwrap().to_digit(10).unwrap() as i32;
20428        let note_part = &s[..s.len() - 1];
20429        (note_part, (octave - 4) * 12) // Octave 4 = MIDI 60 area
20430    } else {
20431        (&s[..], 0)
20432    };
20433
20434    let semitone = match note {
20435        "C" => 0,
20436        "C#" | "DB" => 1,
20437        "D" => 2,
20438        "D#" | "EB" => 3,
20439        "E" => 4,
20440        "F" => 5,
20441        "F#" | "GB" => 6,
20442        "G" => 7,
20443        "G#" | "AB" => 8,
20444        "A" => 9,
20445        "A#" | "BB" => 10,
20446        "B" => 11,
20447        _ => return Err(RuntimeError::new(format!("Unknown note: {}", s))),
20448    };
20449
20450    Ok(69.0 + semitone as f64 - 9.0 + octave_offset as f64) // A4 = 69
20451}
20452
20453fn just_intonation_ratio(semitones: i32) -> f64 {
20454    // Classic 5-limit just intonation ratios
20455    match semitones.rem_euclid(12) {
20456        0 => 1.0,         // Unison
20457        1 => 16.0 / 15.0, // Minor second
20458        2 => 9.0 / 8.0,   // Major second
20459        3 => 6.0 / 5.0,   // Minor third
20460        4 => 5.0 / 4.0,   // Major third
20461        5 => 4.0 / 3.0,   // Perfect fourth
20462        6 => 45.0 / 32.0, // Tritone
20463        7 => 3.0 / 2.0,   // Perfect fifth
20464        8 => 8.0 / 5.0,   // Minor sixth
20465        9 => 5.0 / 3.0,   // Major sixth
20466        10 => 9.0 / 5.0,  // Minor seventh
20467        11 => 15.0 / 8.0, // Major seventh
20468        _ => 1.0,
20469    }
20470}
20471
20472fn pythagorean_ratio(semitones: i32) -> f64 {
20473    // Pythagorean tuning (pure fifths, 3:2 ratio)
20474    match semitones.rem_euclid(12) {
20475        0 => 1.0,
20476        1 => 256.0 / 243.0,
20477        2 => 9.0 / 8.0,
20478        3 => 32.0 / 27.0,
20479        4 => 81.0 / 64.0,
20480        5 => 4.0 / 3.0,
20481        6 => 729.0 / 512.0,
20482        7 => 3.0 / 2.0,
20483        8 => 128.0 / 81.0,
20484        9 => 27.0 / 16.0,
20485        10 => 16.0 / 9.0,
20486        11 => 243.0 / 128.0,
20487        _ => 1.0,
20488    }
20489}
20490
20491fn meantone_ratio(semitones: i32) -> f64 {
20492    // Quarter-comma meantone - fifths narrowed by 1/4 syntonic comma
20493    let fifth = 5.0_f64.powf(0.25); // Pure major third, tempered fifth
20494    match semitones.rem_euclid(12) {
20495        0 => 1.0,
20496        1 => 8.0 / (fifth.powi(5)),
20497        2 => fifth.powi(2) / 2.0,
20498        3 => 4.0 / (fifth.powi(3)),
20499        4 => fifth.powi(4) / 4.0,
20500        5 => 2.0 / fifth,
20501        6 => fifth.powi(6) / 8.0,
20502        7 => fifth,
20503        8 => 8.0 / (fifth.powi(4)),
20504        9 => fifth.powi(3) / 2.0,
20505        10 => 4.0 / (fifth.powi(2)),
20506        11 => fifth.powi(5) / 4.0,
20507        _ => 1.0,
20508    }
20509}
20510
20511fn shruti_ratio(shruti: i32) -> f64 {
20512    // 22 shruti ratios (traditional Indian)
20513    let ratios = [
20514        1.0,
20515        256.0 / 243.0,
20516        16.0 / 15.0,
20517        10.0 / 9.0,
20518        9.0 / 8.0,
20519        32.0 / 27.0,
20520        6.0 / 5.0,
20521        5.0 / 4.0,
20522        81.0 / 64.0,
20523        4.0 / 3.0,
20524        27.0 / 20.0,
20525        45.0 / 32.0,
20526        729.0 / 512.0,
20527        3.0 / 2.0,
20528        128.0 / 81.0,
20529        8.0 / 5.0,
20530        5.0 / 3.0,
20531        27.0 / 16.0,
20532        16.0 / 9.0,
20533        9.0 / 5.0,
20534        15.0 / 8.0,
20535        243.0 / 128.0,
20536    ];
20537    ratios[shruti.rem_euclid(22) as usize]
20538}
20539
20540fn pelog_ratio(degree: i32) -> f64 {
20541    // Approximate pelog ratios (varies by gamelan)
20542    let ratios = [1.0, 1.12, 1.26, 1.5, 1.68, 1.89, 2.12];
20543    ratios[degree.rem_euclid(7) as usize]
20544}
20545
20546fn slendro_ratio(degree: i32) -> f64 {
20547    // Approximate slendro ratios (roughly equal ~240 cents)
20548    let ratios = [1.0, 1.148, 1.318, 1.516, 1.741];
20549    ratios[degree.rem_euclid(5) as usize]
20550}
20551
20552fn generate_waveform(args: &[Value], wave_fn: fn(f64) -> f64) -> Result<Value, RuntimeError> {
20553    let freq = match &args[0] {
20554        Value::Float(f) => *f,
20555        Value::Int(i) => *i as f64,
20556        _ => return Err(RuntimeError::new("Waveform requires frequency")),
20557    };
20558    let sample_rate = match &args[1] {
20559        Value::Float(f) => *f as usize,
20560        Value::Int(i) => *i as usize,
20561        _ => return Err(RuntimeError::new("Waveform requires sample rate")),
20562    };
20563    let duration = match &args[2] {
20564        Value::Float(f) => *f,
20565        Value::Int(i) => *i as f64,
20566        _ => return Err(RuntimeError::new("Waveform requires duration")),
20567    };
20568
20569    let num_samples = (sample_rate as f64 * duration) as usize;
20570    let samples: Vec<Value> = (0..num_samples)
20571        .map(|i| {
20572            let t = i as f64 / sample_rate as f64;
20573            let phase = 2.0 * std::f64::consts::PI * freq * t;
20574            Value::Float(wave_fn(phase))
20575        })
20576        .collect();
20577
20578    Ok(Value::Array(Rc::new(RefCell::new(samples))))
20579}
20580
20581// ============================================================================
20582// SPIRITUALITY: Divination, sacred geometry, gematria, archetypes
20583// ============================================================================
20584//
20585// This module treats computation as potentially sacred - numbers have meaning,
20586// patterns have significance, and randomness can be oracle.
20587//
20588// I Ching Trigrams:
20589//   ☰ Heaven (乾)  ☱ Lake (兌)   ☲ Fire (離)   ☳ Thunder (震)
20590//   ☴ Wind (巽)    ☵ Water (坎)  ☶ Mountain (艮) ☷ Earth (坤)
20591//
20592// Sacred Geometry:
20593//   φ = 1.618033... (Golden Ratio)
20594//   √φ, φ², 1/φ (related constants)
20595//   Fibonacci sequence
20596//   Platonic solid relationships
20597//
20598// Gematria Systems:
20599//   Hebrew (Kabbalah), Greek (Isopsephy), Arabic (Abjad)
20600//   Each letter is a number; words have numerical souls
20601
20602fn register_spirituality(interp: &mut Interpreter) {
20603    // =========================================================================
20604    // I CHING - Book of Changes
20605    // =========================================================================
20606
20607    // The 8 trigrams
20608    const TRIGRAMS: [(&str, &str, &str, &str, &str); 8] = [
20609        (
20610            "☰",
20611            "乾",
20612            "Heaven",
20613            "Creative",
20614            "strong, initiating, persisting",
20615        ),
20616        (
20617            "☱",
20618            "兌",
20619            "Lake",
20620            "Joyous",
20621            "pleasure, satisfaction, openness",
20622        ),
20623        (
20624            "☲",
20625            "離",
20626            "Fire",
20627            "Clinging",
20628            "clarity, awareness, dependence",
20629        ),
20630        (
20631            "☳",
20632            "震",
20633            "Thunder",
20634            "Arousing",
20635            "movement, initiative, action",
20636        ),
20637        (
20638            "☴",
20639            "巽",
20640            "Wind",
20641            "Gentle",
20642            "penetrating, following, flexible",
20643        ),
20644        ("☵", "坎", "Water", "Abysmal", "danger, flowing, depth"),
20645        (
20646            "☶",
20647            "艮",
20648            "Mountain",
20649            "Keeping Still",
20650            "stopping, resting, meditation",
20651        ),
20652        (
20653            "☷",
20654            "坤",
20655            "Earth",
20656            "Receptive",
20657            "yielding, nurturing, devoted",
20658        ),
20659    ];
20660
20661    // trigram - get trigram information
20662    define(interp, "trigram", Some(1), |_, args| {
20663        let input = match &args[0] {
20664            Value::Int(n) => (*n as usize).min(7),
20665            Value::String(s) => match s.as_str() {
20666                "☰" | "heaven" | "qian" | "乾" => 0,
20667                "☱" | "lake" | "dui" | "兌" => 1,
20668                "☲" | "fire" | "li" | "離" => 2,
20669                "☳" | "thunder" | "zhen" | "震" => 3,
20670                "☴" | "wind" | "xun" | "巽" => 4,
20671                "☵" | "water" | "kan" | "坎" => 5,
20672                "☶" | "mountain" | "gen" | "艮" => 6,
20673                "☷" | "earth" | "kun" | "坤" => 7,
20674                _ => return Err(RuntimeError::new(format!("Unknown trigram: {}", s))),
20675            },
20676            _ => return Err(RuntimeError::new("trigram() requires number or name")),
20677        };
20678
20679        let (symbol, chinese, english, name, meaning) = TRIGRAMS[input];
20680
20681        let mut result = std::collections::HashMap::new();
20682        result.insert("number".to_string(), Value::Int(input as i64));
20683        result.insert(
20684            "symbol".to_string(),
20685            Value::String(Rc::new(symbol.to_string())),
20686        );
20687        result.insert(
20688            "chinese".to_string(),
20689            Value::String(Rc::new(chinese.to_string())),
20690        );
20691        result.insert(
20692            "english".to_string(),
20693            Value::String(Rc::new(english.to_string())),
20694        );
20695        result.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
20696        result.insert(
20697            "meaning".to_string(),
20698            Value::String(Rc::new(meaning.to_string())),
20699        );
20700
20701        // Binary representation (yang=1, yin=0)
20702        let binary = match input {
20703            0 => "111", // ☰
20704            1 => "110", // ☱
20705            2 => "101", // ☲
20706            3 => "100", // ☳
20707            4 => "011", // ☴
20708            5 => "010", // ☵
20709            6 => "001", // ☶
20710            7 => "000", // ☷
20711            _ => "000",
20712        };
20713        result.insert(
20714            "binary".to_string(),
20715            Value::String(Rc::new(binary.to_string())),
20716        );
20717
20718        Ok(Value::Map(Rc::new(RefCell::new(result))))
20719    });
20720
20721    // hexagram - get one of 64 I Ching hexagrams
20722    define(interp, "hexagram", Some(1), |_, args| {
20723        let num = match &args[0] {
20724            Value::Int(n) => ((*n - 1) as usize).min(63),
20725            _ => return Err(RuntimeError::new("hexagram() requires number 1-64")),
20726        };
20727
20728        let hex = &HEXAGRAMS[num];
20729
20730        let mut result = std::collections::HashMap::new();
20731        result.insert("number".to_string(), Value::Int((num + 1) as i64));
20732        result.insert(
20733            "chinese".to_string(),
20734            Value::String(Rc::new(hex.0.to_string())),
20735        );
20736        result.insert(
20737            "pinyin".to_string(),
20738            Value::String(Rc::new(hex.1.to_string())),
20739        );
20740        result.insert(
20741            "english".to_string(),
20742            Value::String(Rc::new(hex.2.to_string())),
20743        );
20744        result.insert(
20745            "judgment".to_string(),
20746            Value::String(Rc::new(hex.3.to_string())),
20747        );
20748        result.insert(
20749            "upper_trigram".to_string(),
20750            Value::String(Rc::new(hex.4.to_string())),
20751        );
20752        result.insert(
20753            "lower_trigram".to_string(),
20754            Value::String(Rc::new(hex.5.to_string())),
20755        );
20756
20757        Ok(Value::Map(Rc::new(RefCell::new(result))))
20758    });
20759
20760    // cast_iching - divine using I Ching (uses randomness as oracle)
20761    define(interp, "cast_iching", Some(0), |_, _| {
20762        let mut rng = rand::thread_rng();
20763
20764        // Traditional yarrow stalk method produces numbers 6,7,8,9
20765        // 6 = old yin (changing), 7 = young yang, 8 = young yin, 9 = old yang (changing)
20766        let mut lines = Vec::new();
20767        let mut hexagram_num = 0u8;
20768        let mut changing_lines = Vec::new();
20769
20770        for i in 0..6 {
20771            // Simulate yarrow stalk probabilities
20772            let r: f64 = rng.gen();
20773            let line = if r < 0.0625 {
20774                6
20775            }
20776            // 1/16 - old yin
20777            else if r < 0.3125 {
20778                7
20779            }
20780            // 5/16 - young yang
20781            else if r < 0.5625 {
20782                8
20783            }
20784            // 5/16 - young yin
20785            else {
20786                9
20787            }; // 5/16 - old yang
20788
20789            let is_yang = line == 7 || line == 9;
20790            if is_yang {
20791                hexagram_num |= 1 << i;
20792            }
20793
20794            if line == 6 || line == 9 {
20795                changing_lines.push(i + 1);
20796            }
20797
20798            lines.push(Value::Int(line));
20799        }
20800
20801        // Convert to King Wen sequence
20802        let king_wen_num = binary_to_king_wen(hexagram_num) + 1;
20803        let hex = &HEXAGRAMS[(king_wen_num - 1) as usize];
20804
20805        let mut result = std::collections::HashMap::new();
20806        result.insert("hexagram".to_string(), Value::Int(king_wen_num as i64));
20807        result.insert(
20808            "chinese".to_string(),
20809            Value::String(Rc::new(hex.0.to_string())),
20810        );
20811        result.insert(
20812            "english".to_string(),
20813            Value::String(Rc::new(hex.2.to_string())),
20814        );
20815        result.insert(
20816            "judgment".to_string(),
20817            Value::String(Rc::new(hex.3.to_string())),
20818        );
20819        result.insert(
20820            "lines".to_string(),
20821            Value::Array(Rc::new(RefCell::new(lines))),
20822        );
20823
20824        let changing: Vec<Value> = changing_lines.iter().map(|&n| Value::Int(n)).collect();
20825        result.insert(
20826            "changing_lines".to_string(),
20827            Value::Array(Rc::new(RefCell::new(changing))),
20828        );
20829
20830        // Calculate resulting hexagram if there are changing lines
20831        if !changing_lines.is_empty() {
20832            let mut result_hex = hexagram_num;
20833            for &line in &changing_lines {
20834                result_hex ^= 1 << (line - 1); // Flip the changing lines
20835            }
20836            let result_king_wen = binary_to_king_wen(result_hex) + 1;
20837            result.insert(
20838                "transforms_to".to_string(),
20839                Value::Int(result_king_wen as i64),
20840            );
20841        }
20842
20843        Ok(Value::Map(Rc::new(RefCell::new(result))))
20844    });
20845
20846    // =========================================================================
20847    // SACRED GEOMETRY
20848    // =========================================================================
20849
20850    // phi - Golden Ratio
20851    define(interp, "phi", Some(0), |_, _| {
20852        Ok(Value::Float((1.0 + 5.0_f64.sqrt()) / 2.0))
20853    });
20854
20855    // sacred_ratio - get various sacred ratios
20856    define(interp, "sacred_ratio", Some(1), |_, args| {
20857        let name = match &args[0] {
20858            Value::String(s) => s.to_lowercase(),
20859            _ => return Err(RuntimeError::new("sacred_ratio() requires string")),
20860        };
20861
20862        let (value, symbol, meaning) = match name.as_str() {
20863            "phi" | "φ" | "golden" => (
20864                (1.0 + 5.0_f64.sqrt()) / 2.0,
20865                "φ",
20866                "Golden Ratio - divine proportion found in nature, art, architecture",
20867            ),
20868            "phi_conjugate" | "1/phi" => (
20869                2.0 / (1.0 + 5.0_f64.sqrt()),
20870                "1/φ",
20871                "Golden Ratio conjugate - φ - 1 = 1/φ",
20872            ),
20873            "phi_squared" | "phi2" => (
20874                ((1.0 + 5.0_f64.sqrt()) / 2.0).powi(2),
20875                "φ²",
20876                "Golden Ratio squared - φ + 1 = φ²",
20877            ),
20878            "sqrt_phi" => (
20879                ((1.0 + 5.0_f64.sqrt()) / 2.0).sqrt(),
20880                "√φ",
20881                "Square root of Golden Ratio",
20882            ),
20883            "pi" | "π" => (
20884                std::f64::consts::PI,
20885                "π",
20886                "Circle constant - circumference/diameter, transcendental",
20887            ),
20888            "tau" | "τ" => (
20889                std::f64::consts::TAU,
20890                "τ",
20891                "Full circle constant - 2π, one complete revolution",
20892            ),
20893            "e" | "euler" => (
20894                std::f64::consts::E,
20895                "e",
20896                "Euler's number - natural growth, compound interest",
20897            ),
20898            "sqrt2" | "√2" | "pythagoras" => (
20899                std::f64::consts::SQRT_2,
20900                "√2",
20901                "Pythagorean constant - diagonal of unit square",
20902            ),
20903            "sqrt3" | "√3" | "vesica" => (
20904                3.0_f64.sqrt(),
20905                "√3",
20906                "Vesica Piscis ratio - sacred geometry foundation",
20907            ),
20908            "sqrt5" | "√5" => (
20909                5.0_f64.sqrt(),
20910                "√5",
20911                "Related to Golden Ratio: φ = (1 + √5) / 2",
20912            ),
20913            "silver" | "δs" => (
20914                1.0 + 2.0_f64.sqrt(),
20915                "δs",
20916                "Silver Ratio - related to octagon",
20917            ),
20918            "plastic" | "ρ" => (
20919                1.324717957244746,
20920                "ρ",
20921                "Plastic Number - smallest Pisot number",
20922            ),
20923            "feigenbaum" | "δ" => (
20924                4.669201609102990,
20925                "δ",
20926                "Feigenbaum constant - chaos theory, period doubling",
20927            ),
20928            _ => return Err(RuntimeError::new(format!("Unknown sacred ratio: {}", name))),
20929        };
20930
20931        let mut result = std::collections::HashMap::new();
20932        result.insert("value".to_string(), Value::Float(value));
20933        result.insert(
20934            "symbol".to_string(),
20935            Value::String(Rc::new(symbol.to_string())),
20936        );
20937        result.insert(
20938            "meaning".to_string(),
20939            Value::String(Rc::new(meaning.to_string())),
20940        );
20941
20942        Ok(Value::Map(Rc::new(RefCell::new(result))))
20943    });
20944
20945    // fibonacci - generate Fibonacci sequence
20946    define(interp, "fibonacci", Some(1), |_, args| {
20947        let count = match &args[0] {
20948            Value::Int(n) => *n as usize,
20949            _ => return Err(RuntimeError::new("fibonacci() requires count")),
20950        };
20951
20952        let mut seq = Vec::with_capacity(count);
20953        let (mut a, mut b) = (0i64, 1i64);
20954
20955        for _ in 0..count {
20956            seq.push(Value::Int(a));
20957            let next = a.saturating_add(b);
20958            a = b;
20959            b = next;
20960        }
20961
20962        Ok(Value::Array(Rc::new(RefCell::new(seq))))
20963    });
20964
20965    // is_fibonacci - check if a number is in the Fibonacci sequence
20966    define(interp, "is_fibonacci", Some(1), |_, args| {
20967        let n = match &args[0] {
20968            Value::Int(n) => *n,
20969            _ => return Err(RuntimeError::new("is_fibonacci() requires integer")),
20970        };
20971
20972        // A number is Fibonacci iff one of (5n² + 4) or (5n² - 4) is a perfect square
20973        fn is_perfect_square(n: i64) -> bool {
20974            if n < 0 {
20975                return false;
20976            }
20977            let root = (n as f64).sqrt() as i64;
20978            root * root == n
20979        }
20980
20981        let n_sq = n.saturating_mul(n);
20982        let test1 = 5i64.saturating_mul(n_sq).saturating_add(4);
20983        let test2 = 5i64.saturating_mul(n_sq).saturating_sub(4);
20984
20985        Ok(Value::Bool(
20986            is_perfect_square(test1) || is_perfect_square(test2),
20987        ))
20988    });
20989
20990    // platonic_solid - get information about Platonic solids
20991    define(interp, "platonic_solid", Some(1), |_, args| {
20992        let name = match &args[0] {
20993            Value::String(s) => s.to_lowercase(),
20994            _ => return Err(RuntimeError::new("platonic_solid() requires string")),
20995        };
20996
20997        let (faces, vertices, edges, face_shape, element, meaning) = match name.as_str() {
20998            "tetrahedron" | "fire" => (
20999                4,
21000                4,
21001                6,
21002                "triangle",
21003                "Fire",
21004                "Sharpness, heat, transformation",
21005            ),
21006            "cube" | "hexahedron" | "earth" => (
21007                6,
21008                8,
21009                12,
21010                "square",
21011                "Earth",
21012                "Stability, grounding, material",
21013            ),
21014            "octahedron" | "air" => (
21015                8,
21016                6,
21017                12,
21018                "triangle",
21019                "Air",
21020                "Balance, intellect, communication",
21021            ),
21022            "dodecahedron" | "aether" | "spirit" => (
21023                12,
21024                20,
21025                30,
21026                "pentagon",
21027                "Aether/Spirit",
21028                "The cosmos, divine thought",
21029            ),
21030            "icosahedron" | "water" => (
21031                20,
21032                12,
21033                30,
21034                "triangle",
21035                "Water",
21036                "Flow, emotion, adaptability",
21037            ),
21038            _ => {
21039                return Err(RuntimeError::new(format!(
21040                    "Unknown Platonic solid: {}",
21041                    name
21042                )))
21043            }
21044        };
21045
21046        let mut result = std::collections::HashMap::new();
21047        result.insert("name".to_string(), Value::String(Rc::new(name)));
21048        result.insert("faces".to_string(), Value::Int(faces));
21049        result.insert("vertices".to_string(), Value::Int(vertices));
21050        result.insert("edges".to_string(), Value::Int(edges));
21051        result.insert(
21052            "face_shape".to_string(),
21053            Value::String(Rc::new(face_shape.to_string())),
21054        );
21055        result.insert(
21056            "element".to_string(),
21057            Value::String(Rc::new(element.to_string())),
21058        );
21059        result.insert(
21060            "meaning".to_string(),
21061            Value::String(Rc::new(meaning.to_string())),
21062        );
21063
21064        // Euler's formula: V - E + F = 2
21065        result.insert("euler_characteristic".to_string(), Value::Int(2));
21066
21067        Ok(Value::Map(Rc::new(RefCell::new(result))))
21068    });
21069
21070    // =========================================================================
21071    // GEMATRIA - Letter-Number Correspondences
21072    // =========================================================================
21073
21074    // gematria - calculate numerical value of text
21075    define(interp, "gematria", Some(2), |_, args| {
21076        let text = match &args[0] {
21077            Value::String(s) => s.to_string(),
21078            _ => return Err(RuntimeError::new("gematria() requires string")),
21079        };
21080
21081        let system = match &args[1] {
21082            Value::String(s) => s.to_lowercase(),
21083            _ => return Err(RuntimeError::new("gematria() requires system name")),
21084        };
21085
21086        let total: i64 = match system.as_str() {
21087            "hebrew" | "kabbalah" => text.chars().map(|c| hebrew_gematria(c)).sum(),
21088            "greek" | "isopsephy" => text.chars().map(|c| greek_isopsephy(c)).sum(),
21089            "arabic" | "abjad" => text.chars().map(|c| arabic_abjad(c)).sum(),
21090            "english" | "simple" => {
21091                // Simple English: A=1, B=2, ... Z=26
21092                text.to_uppercase()
21093                    .chars()
21094                    .filter_map(|c| {
21095                        if c.is_ascii_alphabetic() {
21096                            Some((c as i64) - ('A' as i64) + 1)
21097                        } else {
21098                            None
21099                        }
21100                    })
21101                    .sum()
21102            }
21103            "english_ordinal" => {
21104                // Same as simple
21105                text.to_uppercase()
21106                    .chars()
21107                    .filter_map(|c| {
21108                        if c.is_ascii_alphabetic() {
21109                            Some((c as i64) - ('A' as i64) + 1)
21110                        } else {
21111                            None
21112                        }
21113                    })
21114                    .sum()
21115            }
21116            "english_reduction" => {
21117                // Reduce each letter: A=1, B=2, ... I=9, J=1, K=2, etc.
21118                text.to_uppercase()
21119                    .chars()
21120                    .filter_map(|c| {
21121                        if c.is_ascii_alphabetic() {
21122                            let val = ((c as i64) - ('A' as i64)) % 9 + 1;
21123                            Some(val)
21124                        } else {
21125                            None
21126                        }
21127                    })
21128                    .sum()
21129            }
21130            _ => {
21131                return Err(RuntimeError::new(format!(
21132                    "Unknown gematria system: {}",
21133                    system
21134                )))
21135            }
21136        };
21137
21138        let mut result = std::collections::HashMap::new();
21139        result.insert("text".to_string(), Value::String(Rc::new(text)));
21140        result.insert("system".to_string(), Value::String(Rc::new(system)));
21141        result.insert("value".to_string(), Value::Int(total));
21142
21143        // Digital root (reduce to single digit)
21144        let mut digital_root = total;
21145        while digital_root > 9 {
21146            digital_root = digital_root
21147                .to_string()
21148                .chars()
21149                .filter_map(|c| c.to_digit(10))
21150                .map(|d| d as i64)
21151                .sum();
21152        }
21153        result.insert("digital_root".to_string(), Value::Int(digital_root));
21154
21155        Ok(Value::Map(Rc::new(RefCell::new(result))))
21156    });
21157
21158    // gematria_match - find words with same gematria value
21159    define(interp, "gematria_match", Some(2), |_, args| {
21160        let value = match &args[0] {
21161            Value::Int(n) => *n,
21162            _ => return Err(RuntimeError::new("gematria_match() requires integer value")),
21163        };
21164
21165        let system = match &args[1] {
21166            Value::String(s) => s.to_lowercase(),
21167            _ => return Err(RuntimeError::new("gematria_match() requires system name")),
21168        };
21169
21170        // Return known significant matches for common values
21171        let matches = match (value, system.as_str()) {
21172            (26, "hebrew") => vec!["יהוה (YHWH - Tetragrammaton)"],
21173            (18, "hebrew") => vec!["חי (Chai - Life)"],
21174            (86, "hebrew") => vec!["אלהים (Elohim - God)"],
21175            (72, "hebrew") => vec!["חסד (Chesed - Loving-kindness)"],
21176            (93, "english") => vec!["Love", "Will", "Thelema"],
21177            (666, "greek") => vec!["Nero Caesar (in Hebrew letters)"],
21178            (888, "greek") => vec!["Ἰησοῦς (Jesus)"],
21179            _ => vec![],
21180        };
21181
21182        let match_values: Vec<Value> = matches
21183            .iter()
21184            .map(|s| Value::String(Rc::new(s.to_string())))
21185            .collect();
21186
21187        Ok(Value::Array(Rc::new(RefCell::new(match_values))))
21188    });
21189
21190    // =========================================================================
21191    // ARCHETYPES (Jung)
21192    // =========================================================================
21193
21194    // archetype - get information about Jungian archetypes
21195    define(interp, "archetype", Some(1), |_, args| {
21196        let name = match &args[0] {
21197            Value::String(s) => s.to_lowercase(),
21198            _ => return Err(RuntimeError::new("archetype() requires string")),
21199        };
21200
21201        let (description, shadow, gift, challenge) = match name.as_str() {
21202            // Core archetypes
21203            "self" => (
21204                "The unified conscious and unconscious, the goal of individuation",
21205                "Inflation or deflation of ego",
21206                "Wholeness, integration, meaning",
21207                "Integrating all aspects of psyche",
21208            ),
21209            "shadow" => (
21210                "The unconscious aspect containing repressed weaknesses and instincts",
21211                "Projection onto others, denial",
21212                "Creativity, spontaneity, insight",
21213                "Acknowledging and integrating darkness",
21214            ),
21215            "anima" => (
21216                "The feminine inner personality in a man's unconscious",
21217                "Moodiness, seduction, possession",
21218                "Relatedness, creativity, soul connection",
21219                "Developing emotional intelligence",
21220            ),
21221            "animus" => (
21222                "The masculine inner personality in a woman's unconscious",
21223                "Brutality, reckless action, opinionation",
21224                "Courage, initiative, spiritual depth",
21225                "Developing assertiveness with wisdom",
21226            ),
21227            "persona" => (
21228                "The social mask, the face we present to the world",
21229                "Over-identification, inauthenticity",
21230                "Social adaptation, professional competence",
21231                "Maintaining authenticity within role",
21232            ),
21233
21234            // Major archetypes
21235            "hero" => (
21236                "The courageous one who overcomes obstacles and achieves great deeds",
21237                "Arrogance, ruthlessness, eternal battle",
21238                "Courage, perseverance, accomplishment",
21239                "Knowing when to fight and when to surrender",
21240            ),
21241            "sage" | "wise_old_man" => (
21242                "The wise figure who offers guidance and insight",
21243                "Dogmatism, disconnection, ivory tower",
21244                "Wisdom, knowledge, truth-seeking",
21245                "Applying wisdom practically",
21246            ),
21247            "magician" | "wizard" => (
21248                "The transformer who makes things happen through understanding laws",
21249                "Manipulation, disconnection from ethics",
21250                "Transformation, vision, manifestation",
21251                "Using power responsibly",
21252            ),
21253            "lover" => (
21254                "The one who pursues connection, beauty, and passion",
21255                "Obsession, jealousy, loss of identity",
21256                "Passion, commitment, appreciation",
21257                "Maintaining boundaries while connecting deeply",
21258            ),
21259            "caregiver" | "mother" => (
21260                "The nurturing one who protects and provides",
21261                "Martyrdom, enabling, smothering",
21262                "Compassion, generosity, nurturing",
21263                "Caring for self while caring for others",
21264            ),
21265            "ruler" | "king" | "queen" => (
21266                "The one who takes responsibility for the realm",
21267                "Tyranny, authoritarianism, being overthrown",
21268                "Order, leadership, prosperity",
21269                "Serving the greater good, not just power",
21270            ),
21271            "creator" | "artist" => (
21272                "The one who brings new things into being",
21273                "Perfectionism, self-indulgence, drama",
21274                "Creativity, imagination, expression",
21275                "Completing projects, accepting imperfection",
21276            ),
21277            "innocent" | "child" => (
21278                "The pure one with faith and optimism",
21279                "Naivety, denial, dependence",
21280                "Faith, optimism, loyalty",
21281                "Growing without becoming cynical",
21282            ),
21283            "explorer" | "seeker" => (
21284                "The one who seeks new experiences and self-discovery",
21285                "Aimless wandering, inability to commit",
21286                "Autonomy, ambition, authenticity",
21287                "Finding what you seek",
21288            ),
21289            "rebel" | "outlaw" => (
21290                "The one who breaks rules and challenges the status quo",
21291                "Crime, self-destruction, alienation",
21292                "Liberation, revolution, radical freedom",
21293                "Channeling rebellion constructively",
21294            ),
21295            "jester" | "fool" | "trickster" => (
21296                "The one who uses humor and playfulness",
21297                "Cruelty, debauchery, irresponsibility",
21298                "Joy, freedom, living in the moment",
21299                "Knowing when to be serious",
21300            ),
21301            "everyman" | "orphan" => (
21302                "The regular person who wants belonging",
21303                "Victim mentality, losing self in group",
21304                "Realism, empathy, connection",
21305                "Standing out when necessary",
21306            ),
21307            _ => return Err(RuntimeError::new(format!("Unknown archetype: {}", name))),
21308        };
21309
21310        let mut result = std::collections::HashMap::new();
21311        result.insert("name".to_string(), Value::String(Rc::new(name)));
21312        result.insert(
21313            "description".to_string(),
21314            Value::String(Rc::new(description.to_string())),
21315        );
21316        result.insert(
21317            "shadow".to_string(),
21318            Value::String(Rc::new(shadow.to_string())),
21319        );
21320        result.insert("gift".to_string(), Value::String(Rc::new(gift.to_string())));
21321        result.insert(
21322            "challenge".to_string(),
21323            Value::String(Rc::new(challenge.to_string())),
21324        );
21325
21326        Ok(Value::Map(Rc::new(RefCell::new(result))))
21327    });
21328
21329    // =========================================================================
21330    // ASTROLOGY
21331    // =========================================================================
21332
21333    // zodiac - get zodiac sign information
21334    define(interp, "zodiac", Some(1), |_, args| {
21335        let input = match &args[0] {
21336            Value::Int(n) => (*n as usize - 1).min(11),
21337            Value::String(s) => match s.to_lowercase().as_str() {
21338                "aries" | "♈" => 0,
21339                "taurus" | "♉" => 1,
21340                "gemini" | "♊" => 2,
21341                "cancer" | "♋" => 3,
21342                "leo" | "♌" => 4,
21343                "virgo" | "♍" => 5,
21344                "libra" | "♎" => 6,
21345                "scorpio" | "♏" => 7,
21346                "sagittarius" | "♐" => 8,
21347                "capricorn" | "♑" => 9,
21348                "aquarius" | "♒" => 10,
21349                "pisces" | "♓" => 11,
21350                _ => return Err(RuntimeError::new(format!("Unknown sign: {}", s))),
21351            },
21352            _ => return Err(RuntimeError::new("zodiac() requires number or name")),
21353        };
21354
21355        let signs = [
21356            (
21357                "♈",
21358                "Aries",
21359                "Fire",
21360                "Cardinal",
21361                "Mars",
21362                "I Am",
21363                "Mar 21 - Apr 19",
21364            ),
21365            (
21366                "♉",
21367                "Taurus",
21368                "Earth",
21369                "Fixed",
21370                "Venus",
21371                "I Have",
21372                "Apr 20 - May 20",
21373            ),
21374            (
21375                "♊",
21376                "Gemini",
21377                "Air",
21378                "Mutable",
21379                "Mercury",
21380                "I Think",
21381                "May 21 - Jun 20",
21382            ),
21383            (
21384                "♋",
21385                "Cancer",
21386                "Water",
21387                "Cardinal",
21388                "Moon",
21389                "I Feel",
21390                "Jun 21 - Jul 22",
21391            ),
21392            (
21393                "♌",
21394                "Leo",
21395                "Fire",
21396                "Fixed",
21397                "Sun",
21398                "I Will",
21399                "Jul 23 - Aug 22",
21400            ),
21401            (
21402                "♍",
21403                "Virgo",
21404                "Earth",
21405                "Mutable",
21406                "Mercury",
21407                "I Analyze",
21408                "Aug 23 - Sep 22",
21409            ),
21410            (
21411                "♎",
21412                "Libra",
21413                "Air",
21414                "Cardinal",
21415                "Venus",
21416                "I Balance",
21417                "Sep 23 - Oct 22",
21418            ),
21419            (
21420                "♏",
21421                "Scorpio",
21422                "Water",
21423                "Fixed",
21424                "Pluto/Mars",
21425                "I Transform",
21426                "Oct 23 - Nov 21",
21427            ),
21428            (
21429                "♐",
21430                "Sagittarius",
21431                "Fire",
21432                "Mutable",
21433                "Jupiter",
21434                "I Seek",
21435                "Nov 22 - Dec 21",
21436            ),
21437            (
21438                "♑",
21439                "Capricorn",
21440                "Earth",
21441                "Cardinal",
21442                "Saturn",
21443                "I Use",
21444                "Dec 22 - Jan 19",
21445            ),
21446            (
21447                "♒",
21448                "Aquarius",
21449                "Air",
21450                "Fixed",
21451                "Uranus/Saturn",
21452                "I Know",
21453                "Jan 20 - Feb 18",
21454            ),
21455            (
21456                "♓",
21457                "Pisces",
21458                "Water",
21459                "Mutable",
21460                "Neptune/Jupiter",
21461                "I Believe",
21462                "Feb 19 - Mar 20",
21463            ),
21464        ];
21465
21466        let (symbol, name, element, modality, ruler, motto, dates) = signs[input];
21467
21468        let mut result = std::collections::HashMap::new();
21469        result.insert("number".to_string(), Value::Int((input + 1) as i64));
21470        result.insert(
21471            "symbol".to_string(),
21472            Value::String(Rc::new(symbol.to_string())),
21473        );
21474        result.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
21475        result.insert(
21476            "element".to_string(),
21477            Value::String(Rc::new(element.to_string())),
21478        );
21479        result.insert(
21480            "modality".to_string(),
21481            Value::String(Rc::new(modality.to_string())),
21482        );
21483        result.insert(
21484            "ruler".to_string(),
21485            Value::String(Rc::new(ruler.to_string())),
21486        );
21487        result.insert(
21488            "motto".to_string(),
21489            Value::String(Rc::new(motto.to_string())),
21490        );
21491        result.insert(
21492            "dates".to_string(),
21493            Value::String(Rc::new(dates.to_string())),
21494        );
21495
21496        Ok(Value::Map(Rc::new(RefCell::new(result))))
21497    });
21498
21499    // tarot_major - Major Arcana information
21500    define(interp, "tarot_major", Some(1), |_, args| {
21501        let num = match &args[0] {
21502            Value::Int(n) => (*n as usize).min(21),
21503            Value::String(s) => match s.to_lowercase().as_str() {
21504                "fool" => 0,
21505                "magician" => 1,
21506                "high_priestess" | "priestess" => 2,
21507                "empress" => 3,
21508                "emperor" => 4,
21509                "hierophant" | "pope" => 5,
21510                "lovers" => 6,
21511                "chariot" => 7,
21512                "strength" => 8,
21513                "hermit" => 9,
21514                "wheel" | "fortune" => 10,
21515                "justice" => 11,
21516                "hanged_man" | "hanged" => 12,
21517                "death" => 13,
21518                "temperance" => 14,
21519                "devil" => 15,
21520                "tower" => 16,
21521                "star" => 17,
21522                "moon" => 18,
21523                "sun" => 19,
21524                "judgement" | "judgment" => 20,
21525                "world" => 21,
21526                _ => return Err(RuntimeError::new(format!("Unknown card: {}", s))),
21527            },
21528            _ => return Err(RuntimeError::new("tarot_major() requires number or name")),
21529        };
21530
21531        let cards = [
21532            (
21533                "The Fool",
21534                "New beginnings, innocence, spontaneity",
21535                "Naivety, recklessness, risk-taking",
21536            ),
21537            (
21538                "The Magician",
21539                "Willpower, creation, manifestation",
21540                "Manipulation, trickery, unused talent",
21541            ),
21542            (
21543                "The High Priestess",
21544                "Intuition, mystery, inner knowledge",
21545                "Secrets, withdrawal, silence",
21546            ),
21547            (
21548                "The Empress",
21549                "Abundance, nurturing, fertility",
21550                "Dependence, smothering, emptiness",
21551            ),
21552            (
21553                "The Emperor",
21554                "Authority, structure, control",
21555                "Tyranny, rigidity, coldness",
21556            ),
21557            (
21558                "The Hierophant",
21559                "Tradition, conformity, spirituality",
21560                "Dogma, restriction, challenging status quo",
21561            ),
21562            (
21563                "The Lovers",
21564                "Love, harmony, relationships, choices",
21565                "Disharmony, imbalance, misalignment",
21566            ),
21567            (
21568                "The Chariot",
21569                "Direction, willpower, victory",
21570                "Aggression, lack of direction, obstacles",
21571            ),
21572            (
21573                "Strength",
21574                "Courage, patience, inner power",
21575                "Self-doubt, weakness, insecurity",
21576            ),
21577            (
21578                "The Hermit",
21579                "Contemplation, search for truth, inner guidance",
21580                "Isolation, loneliness, withdrawal",
21581            ),
21582            (
21583                "Wheel of Fortune",
21584                "Change, cycles, fate, destiny",
21585                "Resistance to change, bad luck, setbacks",
21586            ),
21587            (
21588                "Justice",
21589                "Truth, fairness, law, cause and effect",
21590                "Unfairness, dishonesty, lack of accountability",
21591            ),
21592            (
21593                "The Hanged Man",
21594                "Surrender, letting go, new perspective",
21595                "Stalling, resistance, indecision",
21596            ),
21597            (
21598                "Death",
21599                "Endings, transformation, transition",
21600                "Fear of change, stagnation, decay",
21601            ),
21602            (
21603                "Temperance",
21604                "Balance, moderation, patience",
21605                "Imbalance, excess, lack of purpose",
21606            ),
21607            (
21608                "The Devil",
21609                "Bondage, materialism, shadow self",
21610                "Freedom, release, exploring dark side",
21611            ),
21612            (
21613                "The Tower",
21614                "Sudden change, upheaval, revelation",
21615                "Disaster averted, fear of change, prolonged pain",
21616            ),
21617            (
21618                "The Star",
21619                "Hope, faith, renewal, inspiration",
21620                "Despair, disconnection, lack of faith",
21621            ),
21622            (
21623                "The Moon",
21624                "Illusion, intuition, the unconscious",
21625                "Fear, confusion, misinterpretation",
21626            ),
21627            (
21628                "The Sun",
21629                "Joy, success, vitality, positivity",
21630                "Negativity, depression, sadness",
21631            ),
21632            (
21633                "Judgement",
21634                "Rebirth, inner calling, absolution",
21635                "Self-doubt, refusal of self-examination",
21636            ),
21637            (
21638                "The World",
21639                "Completion, accomplishment, wholeness",
21640                "Incompletion, lack of closure, emptiness",
21641            ),
21642        ];
21643
21644        let (name, upright, reversed) = cards[num];
21645
21646        let mut result = std::collections::HashMap::new();
21647        result.insert("number".to_string(), Value::Int(num as i64));
21648        result.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
21649        result.insert(
21650            "upright".to_string(),
21651            Value::String(Rc::new(upright.to_string())),
21652        );
21653        result.insert(
21654            "reversed".to_string(),
21655            Value::String(Rc::new(reversed.to_string())),
21656        );
21657
21658        Ok(Value::Map(Rc::new(RefCell::new(result))))
21659    });
21660
21661    // draw_tarot - draw random tarot card
21662    define(interp, "draw_tarot", Some(0), |_, _| {
21663        let mut rng = rand::thread_rng();
21664        let card: usize = rng.gen_range(0..22);
21665        let reversed: bool = rng.gen();
21666
21667        let cards = [
21668            "The Fool",
21669            "The Magician",
21670            "The High Priestess",
21671            "The Empress",
21672            "The Emperor",
21673            "The Hierophant",
21674            "The Lovers",
21675            "The Chariot",
21676            "Strength",
21677            "The Hermit",
21678            "Wheel of Fortune",
21679            "Justice",
21680            "The Hanged Man",
21681            "Death",
21682            "Temperance",
21683            "The Devil",
21684            "The Tower",
21685            "The Star",
21686            "The Moon",
21687            "The Sun",
21688            "Judgement",
21689            "The World",
21690        ];
21691
21692        let mut result = std::collections::HashMap::new();
21693        result.insert("number".to_string(), Value::Int(card as i64));
21694        result.insert(
21695            "name".to_string(),
21696            Value::String(Rc::new(cards[card].to_string())),
21697        );
21698        result.insert("reversed".to_string(), Value::Bool(reversed));
21699        result.insert(
21700            "orientation".to_string(),
21701            Value::String(Rc::new(
21702                if reversed { "reversed" } else { "upright" }.to_string(),
21703            )),
21704        );
21705
21706        Ok(Value::Map(Rc::new(RefCell::new(result))))
21707    });
21708
21709    // =========================================================================
21710    // SYNCHRONICITY
21711    // =========================================================================
21712
21713    // synchronicity_score - calculate "meaningful coincidence" between values
21714    define(interp, "synchronicity_score", Some(2), |_, args| {
21715        // This is intentionally mysterious - combining multiple systems
21716        let a = match &args[0] {
21717            Value::String(s) => s.to_string(),
21718            Value::Int(n) => n.to_string(),
21719            _ => {
21720                return Err(RuntimeError::new(
21721                    "synchronicity_score() requires string or int",
21722                ))
21723            }
21724        };
21725
21726        let b = match &args[1] {
21727            Value::String(s) => s.to_string(),
21728            Value::Int(n) => n.to_string(),
21729            _ => {
21730                return Err(RuntimeError::new(
21731                    "synchronicity_score() requires string or int",
21732                ))
21733            }
21734        };
21735
21736        // Calculate gematria values (simple English)
21737        let val_a: i64 = a
21738            .to_uppercase()
21739            .chars()
21740            .filter_map(|c| {
21741                if c.is_ascii_alphabetic() {
21742                    Some((c as i64) - ('A' as i64) + 1)
21743                } else if c.is_ascii_digit() {
21744                    c.to_digit(10).map(|d| d as i64)
21745                } else {
21746                    None
21747                }
21748            })
21749            .sum();
21750
21751        let val_b: i64 = b
21752            .to_uppercase()
21753            .chars()
21754            .filter_map(|c| {
21755                if c.is_ascii_alphabetic() {
21756                    Some((c as i64) - ('A' as i64) + 1)
21757                } else if c.is_ascii_digit() {
21758                    c.to_digit(10).map(|d| d as i64)
21759                } else {
21760                    None
21761                }
21762            })
21763            .sum();
21764
21765        // Multiple synchronicity factors
21766        let mut factors = Vec::new();
21767
21768        // Same value
21769        if val_a == val_b {
21770            factors.push("identical_gematria".to_string());
21771        }
21772
21773        // One divides the other
21774        if val_a > 0 && val_b > 0 && (val_a % val_b == 0 || val_b % val_a == 0) {
21775            factors.push("divisibility".to_string());
21776        }
21777
21778        // Fibonacci relationship
21779        let fib_set: std::collections::HashSet<i64> =
21780            [1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987]
21781                .iter()
21782                .cloned()
21783                .collect();
21784        if fib_set.contains(&val_a) && fib_set.contains(&val_b) {
21785            factors.push("both_fibonacci".to_string());
21786        }
21787
21788        // Digital root match
21789        fn digital_root(mut n: i64) -> i64 {
21790            while n > 9 {
21791                n = n
21792                    .to_string()
21793                    .chars()
21794                    .filter_map(|c| c.to_digit(10))
21795                    .map(|d| d as i64)
21796                    .sum();
21797            }
21798            n
21799        }
21800        if digital_root(val_a) == digital_root(val_b) {
21801            factors.push("same_digital_root".to_string());
21802        }
21803
21804        // Golden ratio relationship (within 1%)
21805        let phi = (1.0 + 5.0_f64.sqrt()) / 2.0;
21806        let ratio = if val_a > 0 && val_b > 0 {
21807            (val_a as f64 / val_b as f64).max(val_b as f64 / val_a as f64)
21808        } else {
21809            0.0
21810        };
21811        if (ratio - phi).abs() < 0.02 || (ratio - 1.0 / phi).abs() < 0.02 {
21812            factors.push("golden_ratio".to_string());
21813        }
21814
21815        let score = (factors.len() as f64 / 5.0).min(1.0);
21816
21817        let mut result = std::collections::HashMap::new();
21818        result.insert("score".to_string(), Value::Float(score));
21819        result.insert("value_a".to_string(), Value::Int(val_a));
21820        result.insert("value_b".to_string(), Value::Int(val_b));
21821        let factor_values: Vec<Value> = factors
21822            .iter()
21823            .map(|s| Value::String(Rc::new(s.clone())))
21824            .collect();
21825        result.insert(
21826            "factors".to_string(),
21827            Value::Array(Rc::new(RefCell::new(factor_values))),
21828        );
21829
21830        Ok(Value::Map(Rc::new(RefCell::new(result))))
21831    });
21832
21833    // spirituality_info
21834    define(interp, "spirituality_info", Some(0), |_, _| {
21835        let mut info = std::collections::HashMap::new();
21836
21837        info.insert(
21838            "i_ching".to_string(),
21839            Value::String(Rc::new(
21840                "trigram(), hexagram(), cast_iching() - 64 hexagrams of change".to_string(),
21841            )),
21842        );
21843        info.insert(
21844            "sacred_geometry".to_string(),
21845            Value::String(Rc::new(
21846                "phi(), sacred_ratio(), fibonacci(), platonic_solid()".to_string(),
21847            )),
21848        );
21849        info.insert(
21850            "gematria".to_string(),
21851            Value::String(Rc::new(
21852                "Hebrew, Greek, Arabic, English letter-number systems".to_string(),
21853            )),
21854        );
21855        info.insert(
21856            "archetypes".to_string(),
21857            Value::String(Rc::new(
21858                "17 Jungian archetypes with shadow and gift".to_string(),
21859            )),
21860        );
21861        info.insert(
21862            "astrology".to_string(),
21863            Value::String(Rc::new(
21864                "zodiac() - 12 signs with elements and modalities".to_string(),
21865            )),
21866        );
21867        info.insert(
21868            "tarot".to_string(),
21869            Value::String(Rc::new(
21870                "tarot_major(), draw_tarot() - 22 Major Arcana".to_string(),
21871            )),
21872        );
21873
21874        Ok(Value::Map(Rc::new(RefCell::new(info))))
21875    });
21876}
21877
21878// I Ching hexagram data (64 hexagrams in King Wen sequence)
21879const HEXAGRAMS: [(&str, &str, &str, &str, &str, &str); 64] = [
21880    (
21881        "乾",
21882        "Qián",
21883        "The Creative",
21884        "Sublime success through perseverance",
21885        "Heaven",
21886        "Heaven",
21887    ),
21888    (
21889        "坤",
21890        "Kūn",
21891        "The Receptive",
21892        "Devoted success through the mare's perseverance",
21893        "Earth",
21894        "Earth",
21895    ),
21896    (
21897        "屯",
21898        "Zhūn",
21899        "Difficulty at the Beginning",
21900        "Persevere, seek helpers, don't act alone",
21901        "Water",
21902        "Thunder",
21903    ),
21904    (
21905        "蒙",
21906        "Méng",
21907        "Youthful Folly",
21908        "Success through education and guidance",
21909        "Mountain",
21910        "Water",
21911    ),
21912    (
21913        "需",
21914        "Xū",
21915        "Waiting",
21916        "Sincerity brings success; cross the great water",
21917        "Water",
21918        "Heaven",
21919    ),
21920    (
21921        "訟",
21922        "Sòng",
21923        "Conflict",
21924        "Seek counsel; don't cross the great water",
21925        "Heaven",
21926        "Water",
21927    ),
21928    (
21929        "師",
21930        "Shī",
21931        "The Army",
21932        "Perseverance and an experienced leader bring success",
21933        "Earth",
21934        "Water",
21935    ),
21936    (
21937        "比",
21938        "Bǐ",
21939        "Holding Together",
21940        "Through perseverance, those who hesitate should reflect",
21941        "Water",
21942        "Earth",
21943    ),
21944    (
21945        "小畜",
21946        "Xiǎo Chù",
21947        "Small Taming",
21948        "Success; dense clouds but no rain",
21949        "Wind",
21950        "Heaven",
21951    ),
21952    (
21953        "履",
21954        "Lǚ",
21955        "Treading",
21956        "Tread on the tiger's tail carefully; success",
21957        "Heaven",
21958        "Lake",
21959    ),
21960    (
21961        "泰",
21962        "Tài",
21963        "Peace",
21964        "The small departs, the great approaches; success",
21965        "Earth",
21966        "Heaven",
21967    ),
21968    (
21969        "否",
21970        "Pǐ",
21971        "Standstill",
21972        "The great departs, the small approaches; persevere",
21973        "Heaven",
21974        "Earth",
21975    ),
21976    (
21977        "同人",
21978        "Tóng Rén",
21979        "Fellowship",
21980        "Success in the open; cross the great water",
21981        "Heaven",
21982        "Fire",
21983    ),
21984    (
21985        "大有",
21986        "Dà Yǒu",
21987        "Great Possession",
21988        "Supreme success",
21989        "Fire",
21990        "Heaven",
21991    ),
21992    (
21993        "謙",
21994        "Qiān",
21995        "Modesty",
21996        "Success; the superior person carries things through",
21997        "Earth",
21998        "Mountain",
21999    ),
22000    (
22001        "豫",
22002        "Yù",
22003        "Enthusiasm",
22004        "Appoint helpers and set armies marching",
22005        "Thunder",
22006        "Earth",
22007    ),
22008    (
22009        "隨",
22010        "Suí",
22011        "Following",
22012        "Supreme success through perseverance",
22013        "Lake",
22014        "Thunder",
22015    ),
22016    (
22017        "蠱",
22018        "Gǔ",
22019        "Work on the Decayed",
22020        "Success; cross the great water; three days before and after",
22021        "Mountain",
22022        "Wind",
22023    ),
22024    (
22025        "臨",
22026        "Lín",
22027        "Approach",
22028        "Great success through perseverance; misfortune in eighth month",
22029        "Earth",
22030        "Lake",
22031    ),
22032    (
22033        "觀",
22034        "Guān",
22035        "Contemplation",
22036        "Ablution, but not yet sacrifice; confidence inspires",
22037        "Wind",
22038        "Earth",
22039    ),
22040    (
22041        "噬嗑",
22042        "Shì Kè",
22043        "Biting Through",
22044        "Success; favorable for legal matters",
22045        "Fire",
22046        "Thunder",
22047    ),
22048    (
22049        "賁",
22050        "Bì",
22051        "Grace",
22052        "Success in small matters",
22053        "Mountain",
22054        "Fire",
22055    ),
22056    (
22057        "剝",
22058        "Bō",
22059        "Splitting Apart",
22060        "Unfavorable to go anywhere",
22061        "Mountain",
22062        "Earth",
22063    ),
22064    (
22065        "復",
22066        "Fù",
22067        "Return",
22068        "Success; going out and coming in without error",
22069        "Earth",
22070        "Thunder",
22071    ),
22072    (
22073        "無妄",
22074        "Wú Wàng",
22075        "Innocence",
22076        "Supreme success through perseverance",
22077        "Heaven",
22078        "Thunder",
22079    ),
22080    (
22081        "大畜",
22082        "Dà Chù",
22083        "Great Taming",
22084        "Perseverance; eat away from home",
22085        "Mountain",
22086        "Heaven",
22087    ),
22088    (
22089        "頤",
22090        "Yí",
22091        "Nourishment",
22092        "Perseverance; watch what you nurture",
22093        "Mountain",
22094        "Thunder",
22095    ),
22096    (
22097        "大過",
22098        "Dà Guò",
22099        "Great Exceeding",
22100        "The ridgepole sags; favorable to have somewhere to go",
22101        "Lake",
22102        "Wind",
22103    ),
22104    (
22105        "坎",
22106        "Kǎn",
22107        "The Abysmal",
22108        "Sincerity brings success of the heart",
22109        "Water",
22110        "Water",
22111    ),
22112    (
22113        "離",
22114        "Lí",
22115        "The Clinging",
22116        "Perseverance; success; care for the cow",
22117        "Fire",
22118        "Fire",
22119    ),
22120    (
22121        "咸",
22122        "Xián",
22123        "Influence",
22124        "Success; perseverance; taking a maiden brings fortune",
22125        "Lake",
22126        "Mountain",
22127    ),
22128    (
22129        "恆",
22130        "Héng",
22131        "Duration",
22132        "Success without blame; perseverance; favorable to have somewhere to go",
22133        "Thunder",
22134        "Wind",
22135    ),
22136    (
22137        "遯",
22138        "Dùn",
22139        "Retreat",
22140        "Success; small perseverance",
22141        "Heaven",
22142        "Mountain",
22143    ),
22144    (
22145        "大壯",
22146        "Dà Zhuàng",
22147        "Great Power",
22148        "Perseverance",
22149        "Thunder",
22150        "Heaven",
22151    ),
22152    (
22153        "晉",
22154        "Jìn",
22155        "Progress",
22156        "The powerful prince is honored with horses",
22157        "Fire",
22158        "Earth",
22159    ),
22160    (
22161        "明夷",
22162        "Míng Yí",
22163        "Darkening of the Light",
22164        "Perseverance in adversity",
22165        "Earth",
22166        "Fire",
22167    ),
22168    (
22169        "家人",
22170        "Jiā Rén",
22171        "The Family",
22172        "Perseverance of the woman",
22173        "Wind",
22174        "Fire",
22175    ),
22176    (
22177        "睽",
22178        "Kuí",
22179        "Opposition",
22180        "Good fortune in small matters",
22181        "Fire",
22182        "Lake",
22183    ),
22184    (
22185        "蹇",
22186        "Jiǎn",
22187        "Obstruction",
22188        "Southwest favorable; northeast unfavorable; see the great person",
22189        "Water",
22190        "Mountain",
22191    ),
22192    (
22193        "解",
22194        "Xiè",
22195        "Deliverance",
22196        "Southwest favorable; return brings fortune; haste brings fortune",
22197        "Thunder",
22198        "Water",
22199    ),
22200    (
22201        "損",
22202        "Sǔn",
22203        "Decrease",
22204        "Sincerity; supreme fortune; persistence; favorable to undertake",
22205        "Mountain",
22206        "Lake",
22207    ),
22208    (
22209        "益",
22210        "Yì",
22211        "Increase",
22212        "Favorable to undertake and cross the great water",
22213        "Wind",
22214        "Thunder",
22215    ),
22216    (
22217        "夬",
22218        "Guài",
22219        "Breakthrough",
22220        "Proclaim at the king's court; sincerity in danger",
22221        "Lake",
22222        "Heaven",
22223    ),
22224    (
22225        "姤",
22226        "Gòu",
22227        "Coming to Meet",
22228        "The maiden is powerful; don't marry such a maiden",
22229        "Heaven",
22230        "Wind",
22231    ),
22232    (
22233        "萃",
22234        "Cuì",
22235        "Gathering",
22236        "Success; the king approaches his temple; see the great person",
22237        "Lake",
22238        "Earth",
22239    ),
22240    (
22241        "升",
22242        "Shēng",
22243        "Pushing Upward",
22244        "Supreme success; see the great person; don't worry",
22245        "Earth",
22246        "Wind",
22247    ),
22248    (
22249        "困",
22250        "Kùn",
22251        "Oppression",
22252        "Success; perseverance of the great person; no blame",
22253        "Lake",
22254        "Water",
22255    ),
22256    (
22257        "井",
22258        "Jǐng",
22259        "The Well",
22260        "The town may change but not the well",
22261        "Water",
22262        "Wind",
22263    ),
22264    (
22265        "革",
22266        "Gé",
22267        "Revolution",
22268        "On your own day you are believed; great success",
22269        "Lake",
22270        "Fire",
22271    ),
22272    (
22273        "鼎",
22274        "Dǐng",
22275        "The Cauldron",
22276        "Supreme good fortune; success",
22277        "Fire",
22278        "Wind",
22279    ),
22280    (
22281        "震",
22282        "Zhèn",
22283        "The Arousing",
22284        "Success; thunder comes with fright; laughing and talking after",
22285        "Thunder",
22286        "Thunder",
22287    ),
22288    (
22289        "艮",
22290        "Gèn",
22291        "Keeping Still",
22292        "Keep your back still; go into the courtyard without seeing anyone",
22293        "Mountain",
22294        "Mountain",
22295    ),
22296    (
22297        "漸",
22298        "Jiàn",
22299        "Development",
22300        "The maiden is given in marriage; good fortune; perseverance",
22301        "Wind",
22302        "Mountain",
22303    ),
22304    (
22305        "歸妹",
22306        "Guī Mèi",
22307        "The Marrying Maiden",
22308        "Undertakings bring misfortune",
22309        "Thunder",
22310        "Lake",
22311    ),
22312    (
22313        "豐",
22314        "Fēng",
22315        "Abundance",
22316        "Success; the king attains it; don't worry; be like the sun at noon",
22317        "Thunder",
22318        "Fire",
22319    ),
22320    (
22321        "旅",
22322        "Lǚ",
22323        "The Wanderer",
22324        "Success through smallness; perseverance brings fortune",
22325        "Fire",
22326        "Mountain",
22327    ),
22328    (
22329        "巽",
22330        "Xùn",
22331        "The Gentle",
22332        "Success through small things; favorable to have somewhere to go",
22333        "Wind",
22334        "Wind",
22335    ),
22336    (
22337        "兌",
22338        "Duì",
22339        "The Joyous",
22340        "Success; perseverance",
22341        "Lake",
22342        "Lake",
22343    ),
22344    (
22345        "渙",
22346        "Huàn",
22347        "Dispersion",
22348        "Success; the king approaches his temple; cross the great water",
22349        "Wind",
22350        "Water",
22351    ),
22352    (
22353        "節",
22354        "Jié",
22355        "Limitation",
22356        "Success; bitter limitation should not be persevered in",
22357        "Water",
22358        "Lake",
22359    ),
22360    (
22361        "中孚",
22362        "Zhōng Fú",
22363        "Inner Truth",
22364        "Pigs and fishes; good fortune; cross the great water",
22365        "Wind",
22366        "Lake",
22367    ),
22368    (
22369        "小過",
22370        "Xiǎo Guò",
22371        "Small Exceeding",
22372        "Success; perseverance; small things yes, great things no",
22373        "Thunder",
22374        "Mountain",
22375    ),
22376    (
22377        "既濟",
22378        "Jì Jì",
22379        "After Completion",
22380        "Success in small matters; perseverance; good at start, disorder at end",
22381        "Water",
22382        "Fire",
22383    ),
22384    (
22385        "未濟",
22386        "Wèi Jì",
22387        "Before Completion",
22388        "Success; the young fox almost across; tail gets wet; no goal",
22389        "Fire",
22390        "Water",
22391    ),
22392];
22393
22394fn binary_to_king_wen(binary: u8) -> u8 {
22395    // Maps binary hexagram representation to King Wen sequence number
22396    // This is a complex mapping based on traditional ordering
22397    const KING_WEN_ORDER: [u8; 64] = [
22398        1, 43, 14, 34, 9, 5, 26, 11, 10, 58, 38, 54, 61, 60, 41, 19, 13, 49, 30, 55, 37, 63, 22,
22399        36, 25, 17, 21, 51, 42, 3, 27, 24, 44, 28, 50, 32, 57, 48, 18, 46, 6, 47, 64, 40, 59, 29,
22400        4, 7, 33, 31, 56, 62, 53, 39, 52, 15, 12, 45, 35, 16, 20, 8, 23, 2,
22401    ];
22402    KING_WEN_ORDER[binary as usize] - 1
22403}
22404
22405fn hebrew_gematria(c: char) -> i64 {
22406    match c {
22407        'א' | 'A' | 'a' => 1,
22408        'ב' | 'B' | 'b' => 2,
22409        'ג' | 'G' | 'g' => 3,
22410        'ד' | 'D' | 'd' => 4,
22411        'ה' | 'H' | 'h' => 5,
22412        'ו' | 'V' | 'v' | 'W' | 'w' => 6,
22413        'ז' | 'Z' | 'z' => 7,
22414        'ח' => 8,
22415        'ט' => 9,
22416        'י' | 'Y' | 'y' | 'I' | 'i' | 'J' | 'j' => 10,
22417        'כ' | 'K' | 'k' => 20,
22418        'ל' | 'L' | 'l' => 30,
22419        'מ' | 'M' | 'm' => 40,
22420        'נ' | 'N' | 'n' => 50,
22421        'ס' | 'S' | 's' | 'X' | 'x' => 60,
22422        'ע' | 'O' | 'o' => 70,
22423        'פ' | 'P' | 'p' | 'F' | 'f' => 80,
22424        'צ' => 90,
22425        'ק' | 'Q' | 'q' => 100,
22426        'ר' | 'R' | 'r' => 200,
22427        'ש' => 300,
22428        'ת' | 'T' | 't' => 400,
22429        'ך' => 500,             // Final kaph
22430        'ם' => 600,             // Final mem
22431        'ן' => 700,             // Final nun
22432        'ף' => 800,             // Final pe
22433        'ץ' | 'C' | 'c' => 900, // Final tzadi / C approximation
22434        'E' | 'e' => 5,         // Map to He
22435        'U' | 'u' => 6,         // Map to Vav
22436        _ => 0,
22437    }
22438}
22439
22440fn greek_isopsephy(c: char) -> i64 {
22441    match c {
22442        'Α' | 'α' | 'A' | 'a' => 1,
22443        'Β' | 'β' | 'B' | 'b' => 2,
22444        'Γ' | 'γ' | 'G' | 'g' => 3,
22445        'Δ' | 'δ' | 'D' | 'd' => 4,
22446        'Ε' | 'ε' | 'E' | 'e' => 5,
22447        'Ϛ' | 'ϛ' => 6, // Stigma (archaic)
22448        'Ζ' | 'ζ' | 'Z' | 'z' => 7,
22449        'Η' | 'η' | 'H' | 'h' => 8,
22450        'Θ' | 'θ' => 9,
22451        'Ι' | 'ι' | 'I' | 'i' => 10,
22452        'Κ' | 'κ' | 'K' | 'k' => 20,
22453        'Λ' | 'λ' | 'L' | 'l' => 30,
22454        'Μ' | 'μ' | 'M' | 'm' => 40,
22455        'Ν' | 'ν' | 'N' | 'n' => 50,
22456        'Ξ' | 'ξ' | 'X' | 'x' => 60,
22457        'Ο' | 'ο' | 'O' | 'o' => 70,
22458        'Π' | 'π' | 'P' | 'p' => 80,
22459        'Ϙ' | 'ϙ' | 'Q' | 'q' => 90, // Qoppa
22460        'Ρ' | 'ρ' | 'R' | 'r' => 100,
22461        'Σ' | 'σ' | 'ς' | 'S' | 's' => 200,
22462        'Τ' | 'τ' | 'T' | 't' => 300,
22463        'Υ' | 'υ' | 'U' | 'u' | 'Y' | 'y' => 400,
22464        'Φ' | 'φ' | 'F' | 'f' => 500,
22465        'Χ' | 'χ' | 'C' | 'c' => 600,
22466        'Ψ' | 'ψ' => 700,
22467        'Ω' | 'ω' | 'W' | 'w' => 800,
22468        'Ϡ' | 'ϡ' => 900, // Sampi
22469        'J' | 'j' => 10,  // Map to Iota
22470        'V' | 'v' => 400, // Map to Upsilon
22471        _ => 0,
22472    }
22473}
22474
22475fn arabic_abjad(c: char) -> i64 {
22476    match c {
22477        'ا' | 'أ' | 'إ' | 'آ' | 'A' | 'a' => 1,
22478        'ب' | 'B' | 'b' => 2,
22479        'ج' | 'J' | 'j' | 'G' | 'g' => 3,
22480        'د' | 'D' | 'd' => 4,
22481        'ه' | 'H' | 'h' => 5,
22482        'و' | 'W' | 'w' | 'V' | 'v' => 6,
22483        'ز' | 'Z' | 'z' => 7,
22484        'ح' => 8,
22485        'ط' => 9,
22486        'ي' | 'Y' | 'y' | 'I' | 'i' => 10,
22487        'ك' | 'K' | 'k' => 20,
22488        'ل' | 'L' | 'l' => 30,
22489        'م' | 'M' | 'm' => 40,
22490        'ن' | 'N' | 'n' => 50,
22491        'س' | 'S' | 's' => 60,
22492        'ع' | 'E' | 'e' => 70,
22493        'ف' | 'F' | 'f' => 80,
22494        'ص' => 90,
22495        'ق' | 'Q' | 'q' => 100,
22496        'ر' | 'R' | 'r' => 200,
22497        'ش' => 300,
22498        'ت' | 'T' | 't' => 400,
22499        'ث' => 500,
22500        'خ' | 'X' | 'x' => 600,
22501        'ذ' => 700,
22502        'ض' => 800,
22503        'ظ' => 900,
22504        'غ' => 1000,
22505        'C' | 'c' => 600, // Map to خ
22506        'O' | 'o' => 70,  // Map to ع
22507        'P' | 'p' => 80,  // Map to ف
22508        'U' | 'u' => 6,   // Map to و
22509        _ => 0,
22510    }
22511}
22512
22513// =============================================================================
22514// Phase 16: Polycultural Color System
22515// =============================================================================
22516// Color meaning varies radically across cultures. This module provides mathematical
22517// color spaces + cultural color systems from around the world.
22518
22519fn register_color(interp: &mut Interpreter) {
22520    // =========================================================================
22521    // COLOR SPACE CONVERSIONS
22522    // =========================================================================
22523
22524    // rgb(r, g, b) - Create RGB color (0-255)
22525    define(interp, "rgb", Some(3), |_, args| {
22526        let r = match &args[0] {
22527            Value::Int(n) => (*n).clamp(0, 255) as u8,
22528            Value::Float(f) => (*f as i64).clamp(0, 255) as u8,
22529            _ => return Err(RuntimeError::new("rgb() requires numbers")),
22530        };
22531        let g = match &args[1] {
22532            Value::Int(n) => (*n).clamp(0, 255) as u8,
22533            Value::Float(f) => (*f as i64).clamp(0, 255) as u8,
22534            _ => return Err(RuntimeError::new("rgb() requires numbers")),
22535        };
22536        let b = match &args[2] {
22537            Value::Int(n) => (*n).clamp(0, 255) as u8,
22538            Value::Float(f) => (*f as i64).clamp(0, 255) as u8,
22539            _ => return Err(RuntimeError::new("rgb() requires numbers")),
22540        };
22541        let mut map = std::collections::HashMap::new();
22542        map.insert("r".to_string(), Value::Int(r as i64));
22543        map.insert("g".to_string(), Value::Int(g as i64));
22544        map.insert("b".to_string(), Value::Int(b as i64));
22545        map.insert(
22546            "hex".to_string(),
22547            Value::String(Rc::new(format!("#{:02X}{:02X}{:02X}", r, g, b))),
22548        );
22549        Ok(Value::Map(Rc::new(RefCell::new(map))))
22550    });
22551
22552    // hex_to_rgb(hex) - Parse hex color string
22553    define(interp, "hex_to_rgb", Some(1), |_, args| {
22554        let hex = match &args[0] {
22555            Value::String(s) => s.to_string(),
22556            _ => return Err(RuntimeError::new("hex_to_rgb requires string")),
22557        };
22558        let hex = hex.trim_start_matches('#');
22559        if hex.len() != 6 {
22560            return Err(RuntimeError::new("hex_to_rgb requires 6 character hex"));
22561        }
22562        let r = u8::from_str_radix(&hex[0..2], 16).map_err(|_| RuntimeError::new("Invalid hex"))?;
22563        let g = u8::from_str_radix(&hex[2..4], 16).map_err(|_| RuntimeError::new("Invalid hex"))?;
22564        let b = u8::from_str_radix(&hex[4..6], 16).map_err(|_| RuntimeError::new("Invalid hex"))?;
22565        let mut map = std::collections::HashMap::new();
22566        map.insert("r".to_string(), Value::Int(r as i64));
22567        map.insert("g".to_string(), Value::Int(g as i64));
22568        map.insert("b".to_string(), Value::Int(b as i64));
22569        Ok(Value::Map(Rc::new(RefCell::new(map))))
22570    });
22571
22572    // rgb_to_hsl(r, g, b) - Convert RGB to HSL
22573    define(interp, "rgb_to_hsl", Some(3), |_, args| {
22574        let r = match &args[0] {
22575            Value::Int(n) => *n as f64 / 255.0,
22576            Value::Float(f) => *f / 255.0,
22577            _ => return Err(RuntimeError::new("requires numbers")),
22578        };
22579        let g = match &args[1] {
22580            Value::Int(n) => *n as f64 / 255.0,
22581            Value::Float(f) => *f / 255.0,
22582            _ => return Err(RuntimeError::new("requires numbers")),
22583        };
22584        let b = match &args[2] {
22585            Value::Int(n) => *n as f64 / 255.0,
22586            Value::Float(f) => *f / 255.0,
22587            _ => return Err(RuntimeError::new("requires numbers")),
22588        };
22589        let max = r.max(g).max(b);
22590        let min = r.min(g).min(b);
22591        let l = (max + min) / 2.0;
22592        let (h, s) = if max == min {
22593            (0.0, 0.0)
22594        } else {
22595            let d = max - min;
22596            let s = if l > 0.5 {
22597                d / (2.0 - max - min)
22598            } else {
22599                d / (max + min)
22600            };
22601            let h = if max == r {
22602                (g - b) / d + if g < b { 6.0 } else { 0.0 }
22603            } else if max == g {
22604                (b - r) / d + 2.0
22605            } else {
22606                (r - g) / d + 4.0
22607            };
22608            (h * 60.0, s)
22609        };
22610        let mut map = std::collections::HashMap::new();
22611        map.insert("h".to_string(), Value::Float(h));
22612        map.insert("s".to_string(), Value::Float(s));
22613        map.insert("l".to_string(), Value::Float(l));
22614        Ok(Value::Map(Rc::new(RefCell::new(map))))
22615    });
22616
22617    // complementary(r, g, b) - Opposite on color wheel
22618    define(interp, "complementary", Some(3), |_, args| {
22619        let r = match &args[0] {
22620            Value::Int(n) => *n as u8,
22621            _ => return Err(RuntimeError::new("requires int")),
22622        };
22623        let g = match &args[1] {
22624            Value::Int(n) => *n as u8,
22625            _ => return Err(RuntimeError::new("requires int")),
22626        };
22627        let b = match &args[2] {
22628            Value::Int(n) => *n as u8,
22629            _ => return Err(RuntimeError::new("requires int")),
22630        };
22631        let mut map = std::collections::HashMap::new();
22632        map.insert("r".to_string(), Value::Int(255 - r as i64));
22633        map.insert("g".to_string(), Value::Int(255 - g as i64));
22634        map.insert("b".to_string(), Value::Int(255 - b as i64));
22635        Ok(Value::Map(Rc::new(RefCell::new(map))))
22636    });
22637
22638    // =========================================================================
22639    // WU XING (五行) - CHINESE FIVE ELEMENTS
22640    // =========================================================================
22641    define(interp, "wu_xing", Some(1), |_, args| {
22642        let element = match &args[0] {
22643            Value::String(s) => s.to_lowercase(),
22644            _ => return Err(RuntimeError::new("wu_xing requires string")),
22645        };
22646        let (name, chinese, color, hex, direction, season, organ, emotion, planet, animal) =
22647            match element.as_str() {
22648                "wood" | "mu" | "木" => (
22649                    "Wood",
22650                    "木 (Mù)",
22651                    "Green/Azure",
22652                    "#228B22",
22653                    "East",
22654                    "Spring",
22655                    "Liver",
22656                    "Anger",
22657                    "Jupiter",
22658                    "Azure Dragon",
22659                ),
22660                "fire" | "huo" | "火" => (
22661                    "Fire",
22662                    "火 (Huǒ)",
22663                    "Red",
22664                    "#FF0000",
22665                    "South",
22666                    "Summer",
22667                    "Heart",
22668                    "Joy",
22669                    "Mars",
22670                    "Vermilion Bird",
22671                ),
22672                "earth" | "tu" | "土" => (
22673                    "Earth",
22674                    "土 (Tǔ)",
22675                    "Yellow",
22676                    "#FFDB58",
22677                    "Center",
22678                    "Late Summer",
22679                    "Spleen",
22680                    "Worry",
22681                    "Saturn",
22682                    "Yellow Dragon",
22683                ),
22684                "metal" | "jin" | "金" => (
22685                    "Metal",
22686                    "金 (Jīn)",
22687                    "White/Gold",
22688                    "#FFD700",
22689                    "West",
22690                    "Autumn",
22691                    "Lung",
22692                    "Grief",
22693                    "Venus",
22694                    "White Tiger",
22695                ),
22696                "water" | "shui" | "水" => (
22697                    "Water",
22698                    "水 (Shuǐ)",
22699                    "Black/Blue",
22700                    "#000080",
22701                    "North",
22702                    "Winter",
22703                    "Kidney",
22704                    "Fear",
22705                    "Mercury",
22706                    "Black Tortoise",
22707                ),
22708                _ => {
22709                    return Err(RuntimeError::new(
22710                        "Unknown element. Use wood/fire/earth/metal/water",
22711                    ))
22712                }
22713            };
22714        let mut map = std::collections::HashMap::new();
22715        map.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
22716        map.insert(
22717            "chinese".to_string(),
22718            Value::String(Rc::new(chinese.to_string())),
22719        );
22720        map.insert(
22721            "color".to_string(),
22722            Value::String(Rc::new(color.to_string())),
22723        );
22724        map.insert("hex".to_string(), Value::String(Rc::new(hex.to_string())));
22725        map.insert(
22726            "direction".to_string(),
22727            Value::String(Rc::new(direction.to_string())),
22728        );
22729        map.insert(
22730            "season".to_string(),
22731            Value::String(Rc::new(season.to_string())),
22732        );
22733        map.insert(
22734            "organ".to_string(),
22735            Value::String(Rc::new(organ.to_string())),
22736        );
22737        map.insert(
22738            "emotion".to_string(),
22739            Value::String(Rc::new(emotion.to_string())),
22740        );
22741        map.insert(
22742            "planet".to_string(),
22743            Value::String(Rc::new(planet.to_string())),
22744        );
22745        map.insert(
22746            "guardian".to_string(),
22747            Value::String(Rc::new(animal.to_string())),
22748        );
22749        Ok(Value::Map(Rc::new(RefCell::new(map))))
22750    });
22751
22752    // =========================================================================
22753    // CHAKRA COLORS (Ayurveda/Hindu)
22754    // =========================================================================
22755    define(interp, "chakra_color", Some(1), |_, args| {
22756        let chakra = match &args[0] {
22757            Value::String(s) => s.to_lowercase(),
22758            Value::Int(n) => n.to_string(),
22759            _ => return Err(RuntimeError::new("chakra_color requires string or number")),
22760        };
22761        let (name, sanskrit, color, hex, location, freq, element, mantra) = match chakra.as_str() {
22762            "root" | "muladhara" | "1" => (
22763                "Root",
22764                "मूलाधार",
22765                "Red",
22766                "#FF0000",
22767                "Base of spine",
22768                396.0,
22769                "Earth",
22770                "LAM",
22771            ),
22772            "sacral" | "svadhisthana" | "2" => (
22773                "Sacral",
22774                "स्वाधिष्ठान",
22775                "Orange",
22776                "#FF7F00",
22777                "Below navel",
22778                417.0,
22779                "Water",
22780                "VAM",
22781            ),
22782            "solar" | "manipura" | "3" => (
22783                "Solar Plexus",
22784                "मणिपूर",
22785                "Yellow",
22786                "#FFFF00",
22787                "Stomach",
22788                528.0,
22789                "Fire",
22790                "RAM",
22791            ),
22792            "heart" | "anahata" | "4" => (
22793                "Heart",
22794                "अनाहत",
22795                "Green",
22796                "#00FF00",
22797                "Chest",
22798                639.0,
22799                "Air",
22800                "YAM",
22801            ),
22802            "throat" | "vishuddha" | "5" => (
22803                "Throat",
22804                "विशुद्ध",
22805                "Blue",
22806                "#00BFFF",
22807                "Throat",
22808                741.0,
22809                "Ether",
22810                "HAM",
22811            ),
22812            "third_eye" | "ajna" | "6" => (
22813                "Third Eye",
22814                "आज्ञा",
22815                "Indigo",
22816                "#4B0082",
22817                "Forehead",
22818                852.0,
22819                "Light",
22820                "OM",
22821            ),
22822            "crown" | "sahasrara" | "7" => (
22823                "Crown",
22824                "सहस्रार",
22825                "Violet",
22826                "#8B00FF",
22827                "Top of head",
22828                963.0,
22829                "Thought",
22830                "Silence",
22831            ),
22832            _ => {
22833                return Err(RuntimeError::new(
22834                    "Unknown chakra. Use root/sacral/solar/heart/throat/third_eye/crown or 1-7",
22835                ))
22836            }
22837        };
22838        let mut map = std::collections::HashMap::new();
22839        map.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
22840        map.insert(
22841            "sanskrit".to_string(),
22842            Value::String(Rc::new(sanskrit.to_string())),
22843        );
22844        map.insert(
22845            "color".to_string(),
22846            Value::String(Rc::new(color.to_string())),
22847        );
22848        map.insert("hex".to_string(), Value::String(Rc::new(hex.to_string())));
22849        map.insert(
22850            "location".to_string(),
22851            Value::String(Rc::new(location.to_string())),
22852        );
22853        map.insert("frequency_hz".to_string(), Value::Float(freq));
22854        map.insert(
22855            "element".to_string(),
22856            Value::String(Rc::new(element.to_string())),
22857        );
22858        map.insert(
22859            "mantra".to_string(),
22860            Value::String(Rc::new(mantra.to_string())),
22861        );
22862        Ok(Value::Map(Rc::new(RefCell::new(map))))
22863    });
22864
22865    // =========================================================================
22866    // MAYAN DIRECTIONAL COLORS
22867    // =========================================================================
22868    define(interp, "maya_direction", Some(1), |_, args| {
22869        let dir = match &args[0] {
22870            Value::String(s) => s.to_lowercase(),
22871            _ => return Err(RuntimeError::new("requires string")),
22872        };
22873        let (direction, yucatec, color, hex, deity, meaning) = match dir.as_str() {
22874            "east" | "lakin" => (
22875                "East",
22876                "Lak'in",
22877                "Red",
22878                "#FF0000",
22879                "Chac (Red)",
22880                "Sunrise, new beginnings",
22881            ),
22882            "north" | "xaman" => (
22883                "North",
22884                "Xaman",
22885                "White",
22886                "#FFFFFF",
22887                "Chac (White)",
22888                "Ancestors, death",
22889            ),
22890            "west" | "chikin" => (
22891                "West",
22892                "Chik'in",
22893                "Black",
22894                "#000000",
22895                "Chac (Black)",
22896                "Sunset, completion",
22897            ),
22898            "south" | "nohol" => (
22899                "South",
22900                "Nohol",
22901                "Yellow",
22902                "#FFFF00",
22903                "Chac (Yellow)",
22904                "Maize, abundance",
22905            ),
22906            "center" | "yax" => (
22907                "Center",
22908                "Yax",
22909                "Green/Blue",
22910                "#00CED1",
22911                "World Tree",
22912                "Balance",
22913            ),
22914            _ => {
22915                return Err(RuntimeError::new(
22916                    "Unknown direction. Use east/north/west/south/center",
22917                ))
22918            }
22919        };
22920        let mut map = std::collections::HashMap::new();
22921        map.insert(
22922            "direction".to_string(),
22923            Value::String(Rc::new(direction.to_string())),
22924        );
22925        map.insert(
22926            "yucatec".to_string(),
22927            Value::String(Rc::new(yucatec.to_string())),
22928        );
22929        map.insert(
22930            "color".to_string(),
22931            Value::String(Rc::new(color.to_string())),
22932        );
22933        map.insert("hex".to_string(), Value::String(Rc::new(hex.to_string())));
22934        map.insert(
22935            "deity".to_string(),
22936            Value::String(Rc::new(deity.to_string())),
22937        );
22938        map.insert(
22939            "meaning".to_string(),
22940            Value::String(Rc::new(meaning.to_string())),
22941        );
22942        Ok(Value::Map(Rc::new(RefCell::new(map))))
22943    });
22944
22945    // =========================================================================
22946    // ORISHA COLORS (Yoruba/African)
22947    // =========================================================================
22948    define(interp, "orisha_color", Some(1), |_, args| {
22949        let orisha = match &args[0] {
22950            Value::String(s) => s.to_lowercase(),
22951            _ => return Err(RuntimeError::new("requires string")),
22952        };
22953        let (name, colors, hex, domain, day, number) = match orisha.as_str() {
22954            "obatala" | "oxala" => (
22955                "Obatalá",
22956                "White, silver",
22957                "#FFFFFF",
22958                "Creation, purity, wisdom",
22959                "Sunday",
22960                8,
22961            ),
22962            "yemoja" | "yemanja" => (
22963                "Yemọja",
22964                "Blue, white",
22965                "#4169E1",
22966                "Ocean, motherhood",
22967                "Saturday",
22968                7,
22969            ),
22970            "oshun" | "oxum" => (
22971                "Ọṣun",
22972                "Yellow, gold",
22973                "#FFD700",
22974                "Rivers, love, fertility",
22975                "Saturday",
22976                5,
22977            ),
22978            "shango" | "xango" => (
22979                "Ṣàngó",
22980                "Red, white",
22981                "#FF0000",
22982                "Thunder, fire, justice",
22983                "Wednesday",
22984                6,
22985            ),
22986            "ogun" | "ogum" => (
22987                "Ògún",
22988                "Green, black",
22989                "#006400",
22990                "Iron, war, labor",
22991                "Tuesday",
22992                7,
22993            ),
22994            "oya" | "iansa" => (
22995                "Ọya",
22996                "Brown, purple",
22997                "#800020",
22998                "Wind, storms, change",
22999                "Wednesday",
23000                9,
23001            ),
23002            "eshu" | "exu" => (
23003                "Èṣù",
23004                "Red, black",
23005                "#8B0000",
23006                "Crossroads, messages",
23007                "Monday",
23008                3,
23009            ),
23010            _ => {
23011                return Err(RuntimeError::new(
23012                    "Unknown Orisha. Use obatala/yemoja/oshun/shango/ogun/oya/eshu",
23013                ))
23014            }
23015        };
23016        let mut map = std::collections::HashMap::new();
23017        map.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
23018        map.insert(
23019            "colors".to_string(),
23020            Value::String(Rc::new(colors.to_string())),
23021        );
23022        map.insert("hex".to_string(), Value::String(Rc::new(hex.to_string())));
23023        map.insert(
23024            "domain".to_string(),
23025            Value::String(Rc::new(domain.to_string())),
23026        );
23027        map.insert("day".to_string(), Value::String(Rc::new(day.to_string())));
23028        map.insert("number".to_string(), Value::Int(number));
23029        Ok(Value::Map(Rc::new(RefCell::new(map))))
23030    });
23031
23032    // =========================================================================
23033    // JAPANESE TRADITIONAL COLORS (nihon_iro)
23034    // =========================================================================
23035    define(interp, "nihon_iro", Some(1), |_, args| {
23036        let color = match &args[0] {
23037            Value::String(s) => s.to_lowercase(),
23038            _ => return Err(RuntimeError::new("requires string")),
23039        };
23040        let (name, japanese, hex, meaning, season) = match color.as_str() {
23041            "sakura" => (
23042                "Sakura Pink",
23043                "桜色",
23044                "#FFB7C5",
23045                "Cherry blossoms, transience",
23046                "Spring",
23047            ),
23048            "fuji" => (
23049                "Wisteria",
23050                "藤色",
23051                "#C9A0DC",
23052                "Elegance, nobility",
23053                "Spring",
23054            ),
23055            "moegi" => (
23056                "Young Green",
23057                "萌黄",
23058                "#AACF53",
23059                "New growth, freshness",
23060                "Spring",
23061            ),
23062            "ai" => ("Indigo", "藍色", "#004D99", "Protection, depth", "All"),
23063            "akane" => ("Madder Red", "茜色", "#CF3A24", "Sunset, passion", "Autumn"),
23064            "shiro" => ("White", "白", "#FFFFFF", "Purity, death, sacred", "Winter"),
23065            "kuro" => ("Black", "黒", "#000000", "Formality, mystery", "All"),
23066            "aka" => ("Red", "赤", "#D7003A", "Life force, celebration", "All"),
23067            "murasaki" => ("Purple", "紫", "#884898", "Nobility, spirituality", "All"),
23068            _ => {
23069                return Err(RuntimeError::new(
23070                    "Unknown color. Try: sakura/fuji/moegi/ai/akane/shiro/kuro/aka/murasaki",
23071                ))
23072            }
23073        };
23074        let mut map = std::collections::HashMap::new();
23075        map.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
23076        map.insert(
23077            "japanese".to_string(),
23078            Value::String(Rc::new(japanese.to_string())),
23079        );
23080        map.insert("hex".to_string(), Value::String(Rc::new(hex.to_string())));
23081        map.insert(
23082            "meaning".to_string(),
23083            Value::String(Rc::new(meaning.to_string())),
23084        );
23085        map.insert(
23086            "season".to_string(),
23087            Value::String(Rc::new(season.to_string())),
23088        );
23089        Ok(Value::Map(Rc::new(RefCell::new(map))))
23090    });
23091
23092    // =========================================================================
23093    // ISLAMIC COLOR SYMBOLISM
23094    // =========================================================================
23095    define(interp, "islamic_color", Some(1), |_, args| {
23096        let color = match &args[0] {
23097            Value::String(s) => s.to_lowercase(),
23098            _ => return Err(RuntimeError::new("requires string")),
23099        };
23100        let (name, arabic, hex, meaning, usage) = match color.as_str() {
23101            "green" | "akhdar" => (
23102                "Green",
23103                "أخضر",
23104                "#00FF00",
23105                "Paradise, Prophet, life",
23106                "Mosques, Quran, flags",
23107            ),
23108            "white" | "abyad" => (
23109                "White",
23110                "أبيض",
23111                "#FFFFFF",
23112                "Purity, peace, ihram",
23113                "Pilgrimage, burial",
23114            ),
23115            "black" | "aswad" => (
23116                "Black",
23117                "أسود",
23118                "#000000",
23119                "Modesty, Kaaba",
23120                "Kiswah, abaya",
23121            ),
23122            "gold" | "dhahabi" => (
23123                "Gold",
23124                "ذهبي",
23125                "#FFD700",
23126                "Paradise, divine light",
23127                "Calligraphy, decoration",
23128            ),
23129            "blue" | "azraq" => (
23130                "Blue",
23131                "أزرق",
23132                "#0000CD",
23133                "Protection, heaven",
23134                "Tiles, evil eye",
23135            ),
23136            _ => {
23137                return Err(RuntimeError::new(
23138                    "Unknown color. Use green/white/black/gold/blue",
23139                ))
23140            }
23141        };
23142        let mut map = std::collections::HashMap::new();
23143        map.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
23144        map.insert(
23145            "arabic".to_string(),
23146            Value::String(Rc::new(arabic.to_string())),
23147        );
23148        map.insert("hex".to_string(), Value::String(Rc::new(hex.to_string())));
23149        map.insert(
23150            "meaning".to_string(),
23151            Value::String(Rc::new(meaning.to_string())),
23152        );
23153        map.insert(
23154            "usage".to_string(),
23155            Value::String(Rc::new(usage.to_string())),
23156        );
23157        Ok(Value::Map(Rc::new(RefCell::new(map))))
23158    });
23159
23160    // =========================================================================
23161    // THAI DAY COLORS
23162    // =========================================================================
23163    define(interp, "thai_day_color", Some(1), |_, args| {
23164        let day = match &args[0] {
23165            Value::String(s) => s.to_lowercase(),
23166            Value::Int(n) => n.to_string(),
23167            _ => return Err(RuntimeError::new("requires string or number")),
23168        };
23169        let (day_name, thai, color, hex, deity) = match day.as_str() {
23170            "sunday" | "0" => ("Sunday", "วันอาทิตย์", "Red", "#FF0000", "Surya"),
23171            "monday" | "1" => ("Monday", "วันจันทร์", "Yellow", "#FFFF00", "Chandra"),
23172            "tuesday" | "2" => ("Tuesday", "วันอังคาร", "Pink", "#FFC0CB", "Mangala"),
23173            "wednesday" | "3" => ("Wednesday", "วันพุธ", "Green", "#00FF00", "Budha"),
23174            "thursday" | "4" => ("Thursday", "วันพฤหัสบดี", "Orange", "#FFA500", "Brihaspati"),
23175            "friday" | "5" => ("Friday", "วันศุกร์", "Blue", "#00BFFF", "Shukra"),
23176            "saturday" | "6" => ("Saturday", "วันเสาร์", "Purple", "#800080", "Shani"),
23177            _ => return Err(RuntimeError::new("Unknown day. Use sunday-saturday or 0-6")),
23178        };
23179        let mut map = std::collections::HashMap::new();
23180        map.insert(
23181            "day".to_string(),
23182            Value::String(Rc::new(day_name.to_string())),
23183        );
23184        map.insert("thai".to_string(), Value::String(Rc::new(thai.to_string())));
23185        map.insert(
23186            "color".to_string(),
23187            Value::String(Rc::new(color.to_string())),
23188        );
23189        map.insert("hex".to_string(), Value::String(Rc::new(hex.to_string())));
23190        map.insert(
23191            "deity".to_string(),
23192            Value::String(Rc::new(deity.to_string())),
23193        );
23194        Ok(Value::Map(Rc::new(RefCell::new(map))))
23195    });
23196
23197    // =========================================================================
23198    // ABORIGINAL AUSTRALIAN COLORS
23199    // =========================================================================
23200    define(interp, "aboriginal_color", Some(1), |_, args| {
23201        let color = match &args[0] {
23202            Value::String(s) => s.to_lowercase(),
23203            _ => return Err(RuntimeError::new("requires string")),
23204        };
23205        let (name, hex, meaning, source, dreamtime) = match color.as_str() {
23206            "red" | "ochre" => (
23207                "Red Ochre",
23208                "#CC5500",
23209                "Earth, blood, ceremony",
23210                "Hematite",
23211                "Ancestral beings",
23212            ),
23213            "yellow" => (
23214                "Yellow Ochre",
23215                "#D4A017",
23216                "Sun, healing",
23217                "Limonite",
23218                "Sun's journey",
23219            ),
23220            "white" => (
23221                "White",
23222                "#FFFFFF",
23223                "Sky, spirits, mourning",
23224                "Kaolin",
23225                "Sky beings",
23226            ),
23227            "black" => (
23228                "Black",
23229                "#000000",
23230                "Night, formality",
23231                "Charcoal",
23232                "Night, men's business",
23233            ),
23234            "brown" => (
23235                "Brown",
23236                "#8B4513",
23237                "Earth, land",
23238                "Earth pigments",
23239                "Country, connection",
23240            ),
23241            _ => {
23242                return Err(RuntimeError::new(
23243                    "Unknown color. Use red/yellow/white/black/brown",
23244                ))
23245            }
23246        };
23247        let mut map = std::collections::HashMap::new();
23248        map.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
23249        map.insert("hex".to_string(), Value::String(Rc::new(hex.to_string())));
23250        map.insert(
23251            "meaning".to_string(),
23252            Value::String(Rc::new(meaning.to_string())),
23253        );
23254        map.insert(
23255            "source".to_string(),
23256            Value::String(Rc::new(source.to_string())),
23257        );
23258        map.insert(
23259            "dreamtime".to_string(),
23260            Value::String(Rc::new(dreamtime.to_string())),
23261        );
23262        Ok(Value::Map(Rc::new(RefCell::new(map))))
23263    });
23264
23265    // =========================================================================
23266    // CELTIC COLORS
23267    // =========================================================================
23268    define(interp, "celtic_color", Some(1), |_, args| {
23269        let color = match &args[0] {
23270            Value::String(s) => s.to_lowercase(),
23271            _ => return Err(RuntimeError::new("requires string")),
23272        };
23273        let (name, gaelic, hex, meaning, element) = match color.as_str() {
23274            "green" => (
23275                "Green",
23276                "Glas",
23277                "#228B22",
23278                "Nature, fairies, Otherworld",
23279                "Earth",
23280            ),
23281            "white" => ("White", "Bán", "#FFFFFF", "Purity, spirits", "Air"),
23282            "red" => ("Red", "Dearg", "#FF0000", "War, courage, blood", "Fire"),
23283            "black" => (
23284                "Black",
23285                "Dubh",
23286                "#000000",
23287                "Otherworld, death, rebirth",
23288                "Water",
23289            ),
23290            "gold" => ("Gold", "Órga", "#FFD700", "Sun, sovereignty, Lugh", "Fire"),
23291            "silver" => (
23292                "Silver",
23293                "Airgid",
23294                "#C0C0C0",
23295                "Moon, feminine, intuition",
23296                "Water",
23297            ),
23298            _ => {
23299                return Err(RuntimeError::new(
23300                    "Unknown color. Use green/white/red/black/gold/silver",
23301                ))
23302            }
23303        };
23304        let mut map = std::collections::HashMap::new();
23305        map.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
23306        map.insert(
23307            "gaelic".to_string(),
23308            Value::String(Rc::new(gaelic.to_string())),
23309        );
23310        map.insert("hex".to_string(), Value::String(Rc::new(hex.to_string())));
23311        map.insert(
23312            "meaning".to_string(),
23313            Value::String(Rc::new(meaning.to_string())),
23314        );
23315        map.insert(
23316            "element".to_string(),
23317            Value::String(Rc::new(element.to_string())),
23318        );
23319        Ok(Value::Map(Rc::new(RefCell::new(map))))
23320    });
23321
23322    // =========================================================================
23323    // KENTE CLOTH COLORS (Ghana)
23324    // =========================================================================
23325    define(interp, "kente_color", Some(1), |_, args| {
23326        let color = match &args[0] {
23327            Value::String(s) => s.to_lowercase(),
23328            _ => return Err(RuntimeError::new("requires string")),
23329        };
23330        let (name, twi, hex, meaning) = match color.as_str() {
23331            "gold" | "yellow" => ("Gold", "Sika Kɔkɔɔ", "#FFD700", "Royalty, wealth, glory"),
23332            "green" => ("Green", "Ahabammono", "#228B22", "Growth, renewal, harvest"),
23333            "blue" => ("Blue", "Bruu", "#0000CD", "Peace, harmony, love"),
23334            "red" => ("Red", "Kɔkɔɔ", "#FF0000", "Blood, sacrifice, power"),
23335            "black" => ("Black", "Tuntum", "#000000", "Maturation, ancestors"),
23336            "white" => ("White", "Fitaa", "#FFFFFF", "Purification, virtue, joy"),
23337            "maroon" => ("Maroon", "Borɔnɔ", "#800000", "Earth, healing, protection"),
23338            _ => {
23339                return Err(RuntimeError::new(
23340                    "Unknown color. Use gold/green/blue/red/black/white/maroon",
23341                ))
23342            }
23343        };
23344        let mut map = std::collections::HashMap::new();
23345        map.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
23346        map.insert("twi".to_string(), Value::String(Rc::new(twi.to_string())));
23347        map.insert("hex".to_string(), Value::String(Rc::new(hex.to_string())));
23348        map.insert(
23349            "meaning".to_string(),
23350            Value::String(Rc::new(meaning.to_string())),
23351        );
23352        Ok(Value::Map(Rc::new(RefCell::new(map))))
23353    });
23354
23355    // =========================================================================
23356    // HINDU COLOR SYMBOLISM
23357    // =========================================================================
23358    define(interp, "hindu_color", Some(1), |_, args| {
23359        let color = match &args[0] {
23360            Value::String(s) => s.to_lowercase(),
23361            _ => return Err(RuntimeError::new("requires string")),
23362        };
23363        let (name, hindi, hex, meaning, deities) = match color.as_str() {
23364            "red" | "lal" => (
23365                "Red",
23366                "लाल",
23367                "#FF0000",
23368                "Purity, fertility, love",
23369                "Durga, Lakshmi",
23370            ),
23371            "orange" | "saffron" => (
23372                "Saffron",
23373                "केसरी",
23374                "#FF6600",
23375                "Sacred, renunciation",
23376                "Hanuman",
23377            ),
23378            "yellow" => (
23379                "Yellow",
23380                "पीला",
23381                "#FFFF00",
23382                "Knowledge, learning",
23383                "Vishnu, Saraswati",
23384            ),
23385            "green" => ("Green", "हरा", "#008000", "Life, happiness", "Krishna"),
23386            "white" => (
23387                "White",
23388                "सफ़ेद",
23389                "#FFFFFF",
23390                "Purity, mourning",
23391                "Saraswati, Shiva",
23392            ),
23393            "blue" => (
23394                "Blue",
23395                "नीला",
23396                "#0000FF",
23397                "Divinity, infinity",
23398                "Krishna, Vishnu",
23399            ),
23400            "black" => (
23401                "Black",
23402                "काला",
23403                "#000000",
23404                "Protection from evil",
23405                "Kali, Shani",
23406            ),
23407            _ => {
23408                return Err(RuntimeError::new(
23409                    "Unknown color. Use red/orange/yellow/green/white/blue/black",
23410                ))
23411            }
23412        };
23413        let mut map = std::collections::HashMap::new();
23414        map.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
23415        map.insert(
23416            "hindi".to_string(),
23417            Value::String(Rc::new(hindi.to_string())),
23418        );
23419        map.insert("hex".to_string(), Value::String(Rc::new(hex.to_string())));
23420        map.insert(
23421            "meaning".to_string(),
23422            Value::String(Rc::new(meaning.to_string())),
23423        );
23424        map.insert(
23425            "deities".to_string(),
23426            Value::String(Rc::new(deities.to_string())),
23427        );
23428        Ok(Value::Map(Rc::new(RefCell::new(map))))
23429    });
23430
23431    // =========================================================================
23432    // SYNESTHESIA - CROSS-MODAL MAPPING WITH CULTURAL CONTEXT
23433    // =========================================================================
23434    define(interp, "emotion_color", Some(2), |_, args| {
23435        let emotion = match &args[0] {
23436            Value::String(s) => s.to_lowercase(),
23437            _ => return Err(RuntimeError::new("requires string")),
23438        };
23439        let culture = match &args[1] {
23440            Value::String(s) => s.to_lowercase(),
23441            _ => return Err(RuntimeError::new("requires string")),
23442        };
23443        let (hex, name, reasoning) = match (emotion.as_str(), culture.as_str()) {
23444            ("joy", "western") | ("happy", "western") => {
23445                ("#FFD700", "Gold", "Sunshine = happiness")
23446            }
23447            ("joy", "chinese") | ("happy", "chinese") => ("#FF0000", "Red", "红 = luck, joy"),
23448            ("joy", "japanese") => ("#FFB7C5", "Sakura", "Cherry blossom = fleeting joy"),
23449            ("sadness", "western") | ("sad", "western") => ("#0000CD", "Blue", "'Feeling blue'"),
23450            ("sadness", "chinese") | ("sad", "chinese") => ("#FFFFFF", "White", "白 = mourning"),
23451            ("sadness", "indian") => ("#FFFFFF", "White", "सफ़ेद = mourning"),
23452            ("anger", _) => ("#FF0000", "Red", "Universal heat/fire"),
23453            ("love", "western") => ("#FF69B4", "Pink", "Valentine's hearts"),
23454            ("love", "chinese") | ("love", "indian") => ("#FF0000", "Red", "Red = marriage, love"),
23455            ("peace", "western") => ("#ADD8E6", "Light Blue", "Sky, serenity"),
23456            ("peace", "islamic") => ("#00FF00", "Green", "السلام = paradise"),
23457            ("fear", _) => ("#4B0082", "Indigo", "Deep, mysterious"),
23458            (_, _) => ("#808080", "Grey", "Neutral"),
23459        };
23460        let r = u8::from_str_radix(&hex[1..3], 16).unwrap_or(128);
23461        let g = u8::from_str_radix(&hex[3..5], 16).unwrap_or(128);
23462        let b = u8::from_str_radix(&hex[5..7], 16).unwrap_or(128);
23463        let mut map = std::collections::HashMap::new();
23464        map.insert("hex".to_string(), Value::String(Rc::new(hex.to_string())));
23465        map.insert("name".to_string(), Value::String(Rc::new(name.to_string())));
23466        map.insert("r".to_string(), Value::Int(r as i64));
23467        map.insert("g".to_string(), Value::Int(g as i64));
23468        map.insert("b".to_string(), Value::Int(b as i64));
23469        map.insert(
23470            "reasoning".to_string(),
23471            Value::String(Rc::new(reasoning.to_string())),
23472        );
23473        Ok(Value::Map(Rc::new(RefCell::new(map))))
23474    });
23475
23476    // synesthesia - full cross-modal with cultural awareness
23477    define(interp, "synesthesia", Some(2), |_, args| {
23478        let culture = match &args[1] {
23479            Value::String(s) => s.to_lowercase(),
23480            _ => return Err(RuntimeError::new("requires culture string")),
23481        };
23482        let (r, g, b, emotion, freq) = match &args[0] {
23483            Value::String(s) => match s.to_lowercase().as_str() {
23484                "joy" | "happy" => (255u8, 215u8, 0u8, "joy", 528.0),
23485                "sadness" | "sad" => (0, 0, 139, "sadness", 396.0),
23486                "anger" => (255, 0, 0, "anger", 417.0),
23487                "fear" => (75, 0, 130, "fear", 369.0),
23488                "love" => (255, 105, 180, "love", 639.0),
23489                "peace" => (135, 206, 235, "peace", 741.0),
23490                _ => (128, 128, 128, "neutral", 432.0),
23491            },
23492            Value::Int(n) => (128, 128, 255, "resonance", *n as f64),
23493            Value::Float(f) => (128, 128, 255, "resonance", *f),
23494            _ => (128, 128, 128, "neutral", 432.0),
23495        };
23496        let cultural_meaning = match culture.as_str() {
23497            "chinese" if r > 200 && g < 100 => "luck/joy (红)",
23498            "japanese" if r > 200 && g < 100 => "vitality (赤)",
23499            "indian" if r > 200 && g < 100 => "shakti/auspicious",
23500            _ => "universal resonance",
23501        };
23502        let chakra = if r > 200 && g < 100 {
23503            "Root"
23504        } else if g > 200 {
23505            "Heart"
23506        } else if b > 200 {
23507            "Throat"
23508        } else {
23509            "Crown"
23510        };
23511        let wu_xing = if r > 200 && g < 100 {
23512            "Fire (火)"
23513        } else if g > 200 {
23514            "Wood (木)"
23515        } else if b > 200 {
23516            "Water (水)"
23517        } else {
23518            "Metal (金)"
23519        };
23520        let mut map = std::collections::HashMap::new();
23521        let mut color_map = std::collections::HashMap::new();
23522        color_map.insert("r".to_string(), Value::Int(r as i64));
23523        color_map.insert("g".to_string(), Value::Int(g as i64));
23524        color_map.insert("b".to_string(), Value::Int(b as i64));
23525        color_map.insert(
23526            "hex".to_string(),
23527            Value::String(Rc::new(format!("#{:02X}{:02X}{:02X}", r, g, b))),
23528        );
23529        map.insert(
23530            "color".to_string(),
23531            Value::Map(Rc::new(RefCell::new(color_map))),
23532        );
23533        map.insert(
23534            "emotion".to_string(),
23535            Value::String(Rc::new(emotion.to_string())),
23536        );
23537        map.insert("frequency".to_string(), Value::Float(freq));
23538        map.insert(
23539            "cultural_meaning".to_string(),
23540            Value::String(Rc::new(cultural_meaning.to_string())),
23541        );
23542        map.insert(
23543            "chakra".to_string(),
23544            Value::String(Rc::new(chakra.to_string())),
23545        );
23546        map.insert(
23547            "wu_xing".to_string(),
23548            Value::String(Rc::new(wu_xing.to_string())),
23549        );
23550        Ok(Value::Map(Rc::new(RefCell::new(map))))
23551    });
23552
23553    // color_to_sound - Scriabin-inspired mapping
23554    define(interp, "color_to_sound", Some(3), |_, args| {
23555        let r = match &args[0] {
23556            Value::Int(n) => *n as f64 / 255.0,
23557            Value::Float(f) => *f / 255.0,
23558            _ => return Err(RuntimeError::new("requires numbers")),
23559        };
23560        let g = match &args[1] {
23561            Value::Int(n) => *n as f64 / 255.0,
23562            Value::Float(f) => *f / 255.0,
23563            _ => return Err(RuntimeError::new("requires numbers")),
23564        };
23565        let b = match &args[2] {
23566            Value::Int(n) => *n as f64 / 255.0,
23567            Value::Float(f) => *f / 255.0,
23568            _ => return Err(RuntimeError::new("requires numbers")),
23569        };
23570        let max = r.max(g).max(b);
23571        let min = r.min(g).min(b);
23572        let l = (max + min) / 2.0;
23573        let h = if max == min {
23574            0.0
23575        } else {
23576            let d = max - min;
23577            if max == r {
23578                (g - b) / d + if g < b { 6.0 } else { 0.0 }
23579            } else if max == g {
23580                (b - r) / d + 2.0
23581            } else {
23582                (r - g) / d + 4.0
23583            }
23584        } * 60.0;
23585        let (note, freq) = if h < 30.0 {
23586            ("C", 261.63)
23587        } else if h < 60.0 {
23588            ("G", 392.00)
23589        } else if h < 90.0 {
23590            ("D", 293.66)
23591        } else if h < 120.0 {
23592            ("A", 440.00)
23593        } else if h < 150.0 {
23594            ("E", 329.63)
23595        } else if h < 180.0 {
23596            ("B", 493.88)
23597        } else if h < 210.0 {
23598            ("F#", 369.99)
23599        } else if h < 240.0 {
23600            ("Db", 277.18)
23601        } else if h < 270.0 {
23602            ("Ab", 415.30)
23603        } else if h < 300.0 {
23604            ("Eb", 311.13)
23605        } else if h < 330.0 {
23606            ("Bb", 466.16)
23607        } else {
23608            ("F", 349.23)
23609        };
23610        let octave_shift = ((l - 0.5) * 4.0).round() as i32;
23611        let adjusted_freq = freq * 2.0_f64.powi(octave_shift);
23612        let mut map = std::collections::HashMap::new();
23613        map.insert("note".to_string(), Value::String(Rc::new(note.to_string())));
23614        map.insert("frequency".to_string(), Value::Float(adjusted_freq));
23615        map.insert("hue".to_string(), Value::Float(h));
23616        Ok(Value::Map(Rc::new(RefCell::new(map))))
23617    });
23618
23619    // contrast_ratio - WCAG accessibility
23620    define(interp, "contrast_ratio", Some(6), |_, args| {
23621        fn lum(r: f64, g: f64, b: f64) -> f64 {
23622            fn ch(c: f64) -> f64 {
23623                let c = c / 255.0;
23624                if c <= 0.03928 {
23625                    c / 12.92
23626                } else {
23627                    ((c + 0.055) / 1.055).powf(2.4)
23628                }
23629            }
23630            0.2126 * ch(r) + 0.7152 * ch(g) + 0.0722 * ch(b)
23631        }
23632        let r1 = match &args[0] {
23633            Value::Int(n) => *n as f64,
23634            Value::Float(f) => *f,
23635            _ => return Err(RuntimeError::new("requires numbers")),
23636        };
23637        let g1 = match &args[1] {
23638            Value::Int(n) => *n as f64,
23639            Value::Float(f) => *f,
23640            _ => return Err(RuntimeError::new("requires numbers")),
23641        };
23642        let b1 = match &args[2] {
23643            Value::Int(n) => *n as f64,
23644            Value::Float(f) => *f,
23645            _ => return Err(RuntimeError::new("requires numbers")),
23646        };
23647        let r2 = match &args[3] {
23648            Value::Int(n) => *n as f64,
23649            Value::Float(f) => *f,
23650            _ => return Err(RuntimeError::new("requires numbers")),
23651        };
23652        let g2 = match &args[4] {
23653            Value::Int(n) => *n as f64,
23654            Value::Float(f) => *f,
23655            _ => return Err(RuntimeError::new("requires numbers")),
23656        };
23657        let b2 = match &args[5] {
23658            Value::Int(n) => *n as f64,
23659            Value::Float(f) => *f,
23660            _ => return Err(RuntimeError::new("requires numbers")),
23661        };
23662        let l1 = lum(r1, g1, b1);
23663        let l2 = lum(r2, g2, b2);
23664        let ratio = if l1 > l2 {
23665            (l1 + 0.05) / (l2 + 0.05)
23666        } else {
23667            (l2 + 0.05) / (l1 + 0.05)
23668        };
23669        let mut map = std::collections::HashMap::new();
23670        map.insert("ratio".to_string(), Value::Float(ratio));
23671        map.insert("aa_normal".to_string(), Value::Bool(ratio >= 4.5));
23672        map.insert("aa_large".to_string(), Value::Bool(ratio >= 3.0));
23673        map.insert("aaa_normal".to_string(), Value::Bool(ratio >= 7.0));
23674        Ok(Value::Map(Rc::new(RefCell::new(map))))
23675    });
23676}
23677
23678// ============================================================================
23679// PROTOCOL FUNCTIONS (Phase 17)
23680// ============================================================================
23681
23682/// Register protocol functions for HTTP, gRPC, WebSocket, Kafka, AMQP, GraphQL
23683/// Note: Actual async network operations require runtime support.
23684/// These functions provide protocol information and synchronous utilities.
23685fn register_protocol(interp: &mut Interpreter) {
23686    // protocol_info - Get information about supported protocols
23687    define(interp, "protocol_info", Some(0), |_, _args| {
23688        let mut map = std::collections::HashMap::new();
23689        map.insert(
23690            "http".to_string(),
23691            Value::Map(Rc::new(RefCell::new({
23692                let mut m = std::collections::HashMap::new();
23693                m.insert(
23694                    "name".to_string(),
23695                    Value::String(Rc::new("HTTP".to_string())),
23696                );
23697                m.insert(
23698                    "versions".to_string(),
23699                    Value::Array(Rc::new(RefCell::new(vec![
23700                        Value::String(Rc::new("1.1".to_string())),
23701                        Value::String(Rc::new("2".to_string())),
23702                    ]))),
23703                );
23704                m.insert(
23705                    "methods".to_string(),
23706                    Value::Array(Rc::new(RefCell::new(vec![
23707                        Value::String(Rc::new("GET".to_string())),
23708                        Value::String(Rc::new("POST".to_string())),
23709                        Value::String(Rc::new("PUT".to_string())),
23710                        Value::String(Rc::new("DELETE".to_string())),
23711                        Value::String(Rc::new("PATCH".to_string())),
23712                        Value::String(Rc::new("HEAD".to_string())),
23713                        Value::String(Rc::new("OPTIONS".to_string())),
23714                    ]))),
23715                );
23716                m
23717            }))),
23718        );
23719        map.insert(
23720            "grpc".to_string(),
23721            Value::Map(Rc::new(RefCell::new({
23722                let mut m = std::collections::HashMap::new();
23723                m.insert(
23724                    "name".to_string(),
23725                    Value::String(Rc::new("gRPC".to_string())),
23726                );
23727                m.insert(
23728                    "streaming_modes".to_string(),
23729                    Value::Array(Rc::new(RefCell::new(vec![
23730                        Value::String(Rc::new("unary".to_string())),
23731                        Value::String(Rc::new("server_streaming".to_string())),
23732                        Value::String(Rc::new("client_streaming".to_string())),
23733                        Value::String(Rc::new("bidirectional".to_string())),
23734                    ]))),
23735                );
23736                m
23737            }))),
23738        );
23739        map.insert(
23740            "websocket".to_string(),
23741            Value::Map(Rc::new(RefCell::new({
23742                let mut m = std::collections::HashMap::new();
23743                m.insert(
23744                    "name".to_string(),
23745                    Value::String(Rc::new("WebSocket".to_string())),
23746                );
23747                m.insert(
23748                    "message_types".to_string(),
23749                    Value::Array(Rc::new(RefCell::new(vec![
23750                        Value::String(Rc::new("text".to_string())),
23751                        Value::String(Rc::new("binary".to_string())),
23752                        Value::String(Rc::new("ping".to_string())),
23753                        Value::String(Rc::new("pong".to_string())),
23754                        Value::String(Rc::new("close".to_string())),
23755                    ]))),
23756                );
23757                m
23758            }))),
23759        );
23760        map.insert(
23761            "kafka".to_string(),
23762            Value::Map(Rc::new(RefCell::new({
23763                let mut m = std::collections::HashMap::new();
23764                m.insert(
23765                    "name".to_string(),
23766                    Value::String(Rc::new("Apache Kafka".to_string())),
23767                );
23768                m.insert(
23769                    "acks".to_string(),
23770                    Value::Array(Rc::new(RefCell::new(vec![
23771                        Value::String(Rc::new("none".to_string())),
23772                        Value::String(Rc::new("leader".to_string())),
23773                        Value::String(Rc::new("all".to_string())),
23774                    ]))),
23775                );
23776                m
23777            }))),
23778        );
23779        map.insert(
23780            "amqp".to_string(),
23781            Value::Map(Rc::new(RefCell::new({
23782                let mut m = std::collections::HashMap::new();
23783                m.insert(
23784                    "name".to_string(),
23785                    Value::String(Rc::new("AMQP".to_string())),
23786                );
23787                m.insert(
23788                    "exchange_types".to_string(),
23789                    Value::Array(Rc::new(RefCell::new(vec![
23790                        Value::String(Rc::new("direct".to_string())),
23791                        Value::String(Rc::new("fanout".to_string())),
23792                        Value::String(Rc::new("topic".to_string())),
23793                        Value::String(Rc::new("headers".to_string())),
23794                    ]))),
23795                );
23796                m
23797            }))),
23798        );
23799        map.insert(
23800            "graphql".to_string(),
23801            Value::Map(Rc::new(RefCell::new({
23802                let mut m = std::collections::HashMap::new();
23803                m.insert(
23804                    "name".to_string(),
23805                    Value::String(Rc::new("GraphQL".to_string())),
23806                );
23807                m.insert(
23808                    "operations".to_string(),
23809                    Value::Array(Rc::new(RefCell::new(vec![
23810                        Value::String(Rc::new("query".to_string())),
23811                        Value::String(Rc::new("mutation".to_string())),
23812                        Value::String(Rc::new("subscription".to_string())),
23813                    ]))),
23814                );
23815                m
23816            }))),
23817        );
23818        Ok(Value::Map(Rc::new(RefCell::new(map))))
23819    });
23820
23821    // http_status_text - Get status text for HTTP status code
23822    define(interp, "http_status_text", Some(1), |_, args| {
23823        let code = match &args[0] {
23824            Value::Int(n) => *n,
23825            _ => {
23826                return Err(RuntimeError::new(
23827                    "http_status_text requires integer status code",
23828                ))
23829            }
23830        };
23831        let text = match code {
23832            100 => "Continue",
23833            101 => "Switching Protocols",
23834            200 => "OK",
23835            201 => "Created",
23836            202 => "Accepted",
23837            204 => "No Content",
23838            301 => "Moved Permanently",
23839            302 => "Found",
23840            304 => "Not Modified",
23841            307 => "Temporary Redirect",
23842            308 => "Permanent Redirect",
23843            400 => "Bad Request",
23844            401 => "Unauthorized",
23845            403 => "Forbidden",
23846            404 => "Not Found",
23847            405 => "Method Not Allowed",
23848            409 => "Conflict",
23849            422 => "Unprocessable Entity",
23850            429 => "Too Many Requests",
23851            500 => "Internal Server Error",
23852            502 => "Bad Gateway",
23853            503 => "Service Unavailable",
23854            504 => "Gateway Timeout",
23855            _ => "Unknown",
23856        };
23857        Ok(Value::String(Rc::new(text.to_string())))
23858    });
23859
23860    // http_status_type - Get status type (informational, success, redirect, client_error, server_error)
23861    define(interp, "http_status_type", Some(1), |_, args| {
23862        let code = match &args[0] {
23863            Value::Int(n) => *n,
23864            _ => {
23865                return Err(RuntimeError::new(
23866                    "http_status_type requires integer status code",
23867                ))
23868            }
23869        };
23870        let status_type = match code {
23871            100..=199 => "informational",
23872            200..=299 => "success",
23873            300..=399 => "redirect",
23874            400..=499 => "client_error",
23875            500..=599 => "server_error",
23876            _ => "unknown",
23877        };
23878        Ok(Value::String(Rc::new(status_type.to_string())))
23879    });
23880
23881    // grpc_status_text - Get status text for gRPC status code
23882    define(interp, "grpc_status_text", Some(1), |_, args| {
23883        let code = match &args[0] {
23884            Value::Int(n) => *n,
23885            _ => {
23886                return Err(RuntimeError::new(
23887                    "grpc_status_text requires integer status code",
23888                ))
23889            }
23890        };
23891        let text = match code {
23892            0 => "OK",
23893            1 => "CANCELLED",
23894            2 => "UNKNOWN",
23895            3 => "INVALID_ARGUMENT",
23896            4 => "DEADLINE_EXCEEDED",
23897            5 => "NOT_FOUND",
23898            6 => "ALREADY_EXISTS",
23899            7 => "PERMISSION_DENIED",
23900            8 => "RESOURCE_EXHAUSTED",
23901            9 => "FAILED_PRECONDITION",
23902            10 => "ABORTED",
23903            11 => "OUT_OF_RANGE",
23904            12 => "UNIMPLEMENTED",
23905            13 => "INTERNAL",
23906            14 => "UNAVAILABLE",
23907            15 => "DATA_LOSS",
23908            16 => "UNAUTHENTICATED",
23909            _ => "UNKNOWN",
23910        };
23911        Ok(Value::String(Rc::new(text.to_string())))
23912    });
23913
23914    // url_parse - Parse a URL into components
23915    define(interp, "url_parse", Some(1), |_, args| {
23916        let url_str = match &args[0] {
23917            Value::String(s) => s.as_str().to_string(),
23918            _ => return Err(RuntimeError::new("url_parse requires string URL")),
23919        };
23920
23921        // Simple URL parsing
23922        let mut map = std::collections::HashMap::new();
23923
23924        // Parse scheme
23925        let (scheme, rest) = if let Some(pos) = url_str.find("://") {
23926            (url_str[..pos].to_string(), &url_str[pos + 3..])
23927        } else {
23928            return Err(RuntimeError::new("Invalid URL: missing scheme"));
23929        };
23930        map.insert("scheme".to_string(), Value::String(Rc::new(scheme)));
23931
23932        // Parse host and path
23933        let (authority, path_and_rest) = if let Some(pos) = rest.find('/') {
23934            (&rest[..pos], &rest[pos..])
23935        } else {
23936            (rest, "/")
23937        };
23938
23939        // Parse host and port
23940        let (host, port) = if let Some(pos) = authority.rfind(':') {
23941            if let Ok(p) = authority[pos + 1..].parse::<i64>() {
23942                (authority[..pos].to_string(), Some(p))
23943            } else {
23944                (authority.to_string(), None)
23945            }
23946        } else {
23947            (authority.to_string(), None)
23948        };
23949        map.insert("host".to_string(), Value::String(Rc::new(host)));
23950        map.insert(
23951            "port".to_string(),
23952            port.map(Value::Int).unwrap_or(Value::Null),
23953        );
23954
23955        // Parse path and query
23956        let (path, query) = if let Some(pos) = path_and_rest.find('?') {
23957            (&path_and_rest[..pos], Some(&path_and_rest[pos + 1..]))
23958        } else {
23959            (path_and_rest, None)
23960        };
23961        map.insert("path".to_string(), Value::String(Rc::new(path.to_string())));
23962        map.insert(
23963            "query".to_string(),
23964            query
23965                .map(|q| Value::String(Rc::new(q.to_string())))
23966                .unwrap_or(Value::Null),
23967        );
23968
23969        Ok(Value::Map(Rc::new(RefCell::new(map))))
23970    });
23971
23972    // url_encode - URL-encode a string
23973    define(interp, "url_encode", Some(1), |_, args| {
23974        let s = match &args[0] {
23975            Value::String(s) => s.as_str(),
23976            _ => return Err(RuntimeError::new("url_encode requires string")),
23977        };
23978        let mut result = String::new();
23979        for c in s.chars() {
23980            match c {
23981                'a'..='z' | 'A'..='Z' | '0'..='9' | '-' | '_' | '.' | '~' => {
23982                    result.push(c);
23983                }
23984                ' ' => result.push_str("%20"),
23985                _ => {
23986                    for b in c.to_string().as_bytes() {
23987                        result.push_str(&format!("%{:02X}", b));
23988                    }
23989                }
23990            }
23991        }
23992        Ok(Value::String(Rc::new(result)))
23993    });
23994
23995    // url_decode - URL-decode a string
23996    define(interp, "url_decode", Some(1), |_, args| {
23997        let s = match &args[0] {
23998            Value::String(s) => s.as_str().to_string(),
23999            _ => return Err(RuntimeError::new("url_decode requires string")),
24000        };
24001        let mut result = Vec::new();
24002        let bytes = s.as_bytes();
24003        let mut i = 0;
24004        while i < bytes.len() {
24005            if bytes[i] == b'%' && i + 2 < bytes.len() {
24006                if let Ok(b) =
24007                    u8::from_str_radix(&String::from_utf8_lossy(&bytes[i + 1..i + 3]), 16)
24008                {
24009                    result.push(b);
24010                    i += 3;
24011                    continue;
24012                }
24013            } else if bytes[i] == b'+' {
24014                result.push(b' ');
24015                i += 1;
24016                continue;
24017            }
24018            result.push(bytes[i]);
24019            i += 1;
24020        }
24021        Ok(Value::String(Rc::new(
24022            String::from_utf8_lossy(&result).to_string(),
24023        )))
24024    });
24025
24026    // ws_close_code_text - Get text for WebSocket close code
24027    define(interp, "ws_close_code_text", Some(1), |_, args| {
24028        let code = match &args[0] {
24029            Value::Int(n) => *n,
24030            _ => {
24031                return Err(RuntimeError::new(
24032                    "ws_close_code_text requires integer code",
24033                ))
24034            }
24035        };
24036        let text = match code {
24037            1000 => "Normal Closure",
24038            1001 => "Going Away",
24039            1002 => "Protocol Error",
24040            1003 => "Unsupported Data",
24041            1005 => "No Status Received",
24042            1006 => "Abnormal Closure",
24043            1007 => "Invalid Payload Data",
24044            1008 => "Policy Violation",
24045            1009 => "Message Too Big",
24046            1010 => "Missing Extension",
24047            1011 => "Internal Error",
24048            1015 => "TLS Handshake Failure",
24049            _ => "Unknown",
24050        };
24051        Ok(Value::String(Rc::new(text.to_string())))
24052    });
24053
24054    // mime_type - Get MIME type for file extension
24055    define(interp, "mime_type", Some(1), |_, args| {
24056        let ext = match &args[0] {
24057            Value::String(s) => s.as_str().to_lowercase(),
24058            _ => return Err(RuntimeError::new("mime_type requires string extension")),
24059        };
24060        let ext = ext.trim_start_matches('.');
24061        let mime = match ext {
24062            "html" | "htm" => "text/html",
24063            "css" => "text/css",
24064            "js" | "mjs" => "text/javascript",
24065            "json" => "application/json",
24066            "xml" => "application/xml",
24067            "txt" => "text/plain",
24068            "csv" => "text/csv",
24069            "png" => "image/png",
24070            "jpg" | "jpeg" => "image/jpeg",
24071            "gif" => "image/gif",
24072            "svg" => "image/svg+xml",
24073            "webp" => "image/webp",
24074            "ico" => "image/x-icon",
24075            "pdf" => "application/pdf",
24076            "zip" => "application/zip",
24077            "gz" | "gzip" => "application/gzip",
24078            "mp3" => "audio/mpeg",
24079            "mp4" => "video/mp4",
24080            "webm" => "video/webm",
24081            "woff" => "font/woff",
24082            "woff2" => "font/woff2",
24083            "ttf" => "font/ttf",
24084            "otf" => "font/otf",
24085            "wasm" => "application/wasm",
24086            "proto" => "application/protobuf",
24087            _ => "application/octet-stream",
24088        };
24089        Ok(Value::String(Rc::new(mime.to_string())))
24090    });
24091
24092    // content_type_parse - Parse Content-Type header
24093    define(interp, "content_type_parse", Some(1), |_, args| {
24094        let ct = match &args[0] {
24095            Value::String(s) => s.as_str().to_string(),
24096            _ => return Err(RuntimeError::new("content_type_parse requires string")),
24097        };
24098        let mut map = std::collections::HashMap::new();
24099        let parts: Vec<&str> = ct.split(';').collect();
24100        map.insert(
24101            "media_type".to_string(),
24102            Value::String(Rc::new(parts[0].trim().to_string())),
24103        );
24104
24105        let mut params = std::collections::HashMap::new();
24106        for part in parts.iter().skip(1) {
24107            let kv: Vec<&str> = part.splitn(2, '=').collect();
24108            if kv.len() == 2 {
24109                let key = kv[0].trim().to_lowercase();
24110                let value = kv[1].trim().trim_matches('"').to_string();
24111                params.insert(key, Value::String(Rc::new(value)));
24112            }
24113        }
24114        map.insert(
24115            "params".to_string(),
24116            Value::Map(Rc::new(RefCell::new(params))),
24117        );
24118        Ok(Value::Map(Rc::new(RefCell::new(map))))
24119    });
24120}
24121
24122// ============================================================================
24123// PHASE 18: AI AGENT INFRASTRUCTURE
24124// ============================================================================
24125// Tools for building AI agents with:
24126// - Tool registry for introspectable function definitions
24127// - LLM client for model calls (OpenAI, Claude, local)
24128// - Agent memory for context and session persistence
24129// - Planning framework for state machines and goal tracking
24130// - Vector operations for embeddings and similarity search
24131
24132/// Global tool registry for agent introspection
24133thread_local! {
24134    static TOOL_REGISTRY: RefCell<HashMap<String, ToolDefinition>> = RefCell::new(HashMap::new());
24135    static AGENT_MEMORY: RefCell<HashMap<String, AgentSession>> = RefCell::new(HashMap::new());
24136    static STATE_MACHINES: RefCell<HashMap<String, StateMachine>> = RefCell::new(HashMap::new());
24137}
24138
24139/// Tool definition for LLM function calling
24140#[derive(Clone)]
24141struct ToolDefinition {
24142    name: String,
24143    description: String,
24144    parameters: Vec<ToolParameter>,
24145    returns: String,
24146    evidence_in: Evidence,
24147    evidence_out: Evidence,
24148    handler: Option<Rc<Function>>,
24149}
24150
24151#[derive(Clone)]
24152struct ToolParameter {
24153    name: String,
24154    param_type: String,
24155    description: String,
24156    required: bool,
24157    evidence: Evidence,
24158}
24159
24160/// Agent session for memory persistence
24161#[derive(Clone)]
24162struct AgentSession {
24163    id: String,
24164    context: HashMap<String, Value>,
24165    history: Vec<(String, String)>, // (role, content)
24166    created_at: u64,
24167    last_accessed: u64,
24168}
24169
24170/// State machine for planning
24171#[derive(Clone)]
24172struct StateMachine {
24173    name: String,
24174    current_state: String,
24175    states: Vec<String>,
24176    transitions: HashMap<String, Vec<(String, String)>>, // from -> [(to, condition)]
24177    history: Vec<(String, u64)>,                         // (state, timestamp)
24178}
24179
24180// ============================================================================
24181// TOOL REGISTRY - Introspectable function definitions for LLM tool_choice
24182// ============================================================================
24183
24184fn register_agent_tools(interp: &mut Interpreter) {
24185    // tool_define - Define a tool with metadata for LLM introspection
24186    // tool_define(name, description, params, returns, handler?)
24187    define(interp, "tool_define", None, |_interp, args| {
24188        if args.len() < 4 {
24189            return Err(RuntimeError::new(
24190                "tool_define requires at least 4 arguments: name, description, params, returns",
24191            ));
24192        }
24193
24194        let name = match &args[0] {
24195            Value::String(s) => s.as_str().to_string(),
24196            _ => return Err(RuntimeError::new("tool name must be a string")),
24197        };
24198
24199        let description = match &args[1] {
24200            Value::String(s) => s.as_str().to_string(),
24201            _ => return Err(RuntimeError::new("tool description must be a string")),
24202        };
24203
24204        // Parse parameters array
24205        let params = match &args[2] {
24206            Value::Array(arr) => {
24207                let arr = arr.borrow();
24208                let mut params = Vec::new();
24209                for param in arr.iter() {
24210                    if let Value::Map(map) = param {
24211                        let map = map.borrow();
24212                        let param_name = map
24213                            .get("name")
24214                            .and_then(|v| {
24215                                if let Value::String(s) = v {
24216                                    Some(s.as_str().to_string())
24217                                } else {
24218                                    None
24219                                }
24220                            })
24221                            .unwrap_or_default();
24222                        let param_type = map
24223                            .get("type")
24224                            .and_then(|v| {
24225                                if let Value::String(s) = v {
24226                                    Some(s.as_str().to_string())
24227                                } else {
24228                                    None
24229                                }
24230                            })
24231                            .unwrap_or_else(|| "any".to_string());
24232                        let param_desc = map
24233                            .get("description")
24234                            .and_then(|v| {
24235                                if let Value::String(s) = v {
24236                                    Some(s.as_str().to_string())
24237                                } else {
24238                                    None
24239                                }
24240                            })
24241                            .unwrap_or_default();
24242                        let required = map
24243                            .get("required")
24244                            .and_then(|v| {
24245                                if let Value::Bool(b) = v {
24246                                    Some(*b)
24247                                } else {
24248                                    None
24249                                }
24250                            })
24251                            .unwrap_or(true);
24252                        let evidence_str = map
24253                            .get("evidence")
24254                            .and_then(|v| {
24255                                if let Value::String(s) = v {
24256                                    Some(s.as_str())
24257                                } else {
24258                                    None
24259                                }
24260                            })
24261                            .unwrap_or("~");
24262                        let evidence = match evidence_str {
24263                            "!" => Evidence::Known,
24264                            "?" => Evidence::Uncertain,
24265                            "~" => Evidence::Reported,
24266                            "‽" => Evidence::Paradox,
24267                            _ => Evidence::Reported,
24268                        };
24269                        params.push(ToolParameter {
24270                            name: param_name,
24271                            param_type,
24272                            description: param_desc,
24273                            required,
24274                            evidence,
24275                        });
24276                    }
24277                }
24278                params
24279            }
24280            _ => Vec::new(),
24281        };
24282
24283        let returns = match &args[3] {
24284            Value::String(s) => s.as_str().to_string(),
24285            _ => "any".to_string(),
24286        };
24287
24288        let handler = if args.len() > 4 {
24289            match &args[4] {
24290                Value::Function(f) => Some(f.clone()),
24291                _ => None,
24292            }
24293        } else {
24294            None
24295        };
24296
24297        let tool = ToolDefinition {
24298            name: name.clone(),
24299            description,
24300            parameters: params,
24301            returns,
24302            evidence_in: Evidence::Reported,
24303            evidence_out: Evidence::Reported,
24304            handler,
24305        };
24306
24307        TOOL_REGISTRY.with(|registry| {
24308            registry.borrow_mut().insert(name.clone(), tool);
24309        });
24310
24311        Ok(Value::String(Rc::new(name)))
24312    });
24313
24314    // tool_list - List all registered tools
24315    define(interp, "tool_list", Some(0), |_, _args| {
24316        let tools: Vec<Value> = TOOL_REGISTRY.with(|registry| {
24317            registry
24318                .borrow()
24319                .keys()
24320                .map(|k| Value::String(Rc::new(k.clone())))
24321                .collect()
24322        });
24323        Ok(Value::Array(Rc::new(RefCell::new(tools))))
24324    });
24325
24326    // tool_get - Get tool definition by name
24327    define(interp, "tool_get", Some(1), |_, args| {
24328        let name = match &args[0] {
24329            Value::String(s) => s.as_str().to_string(),
24330            _ => return Err(RuntimeError::new("tool_get requires string name")),
24331        };
24332
24333        TOOL_REGISTRY.with(|registry| {
24334            if let Some(tool) = registry.borrow().get(&name) {
24335                let mut map = HashMap::new();
24336                map.insert(
24337                    "name".to_string(),
24338                    Value::String(Rc::new(tool.name.clone())),
24339                );
24340                map.insert(
24341                    "description".to_string(),
24342                    Value::String(Rc::new(tool.description.clone())),
24343                );
24344                map.insert(
24345                    "returns".to_string(),
24346                    Value::String(Rc::new(tool.returns.clone())),
24347                );
24348
24349                let params: Vec<Value> = tool
24350                    .parameters
24351                    .iter()
24352                    .map(|p| {
24353                        let mut pmap = HashMap::new();
24354                        pmap.insert("name".to_string(), Value::String(Rc::new(p.name.clone())));
24355                        pmap.insert(
24356                            "type".to_string(),
24357                            Value::String(Rc::new(p.param_type.clone())),
24358                        );
24359                        pmap.insert(
24360                            "description".to_string(),
24361                            Value::String(Rc::new(p.description.clone())),
24362                        );
24363                        pmap.insert("required".to_string(), Value::Bool(p.required));
24364                        Value::Map(Rc::new(RefCell::new(pmap)))
24365                    })
24366                    .collect();
24367                map.insert(
24368                    "parameters".to_string(),
24369                    Value::Array(Rc::new(RefCell::new(params))),
24370                );
24371
24372                Ok(Value::Map(Rc::new(RefCell::new(map))))
24373            } else {
24374                Ok(Value::Null)
24375            }
24376        })
24377    });
24378
24379    // tool_schema - Generate OpenAI/Claude compatible tool schema
24380    define(interp, "tool_schema", Some(1), |_, args| {
24381        let name = match &args[0] {
24382            Value::String(s) => s.as_str().to_string(),
24383            _ => return Err(RuntimeError::new("tool_schema requires string name")),
24384        };
24385
24386        TOOL_REGISTRY.with(|registry| {
24387            if let Some(tool) = registry.borrow().get(&name) {
24388                // Generate OpenAI function calling schema
24389                let mut schema = HashMap::new();
24390                schema.insert(
24391                    "type".to_string(),
24392                    Value::String(Rc::new("function".to_string())),
24393                );
24394
24395                let mut function = HashMap::new();
24396                function.insert(
24397                    "name".to_string(),
24398                    Value::String(Rc::new(tool.name.clone())),
24399                );
24400                function.insert(
24401                    "description".to_string(),
24402                    Value::String(Rc::new(tool.description.clone())),
24403                );
24404
24405                // Build parameters schema (JSON Schema format)
24406                let mut params_schema = HashMap::new();
24407                params_schema.insert(
24408                    "type".to_string(),
24409                    Value::String(Rc::new("object".to_string())),
24410                );
24411
24412                let mut properties = HashMap::new();
24413                let mut required: Vec<Value> = Vec::new();
24414
24415                for param in &tool.parameters {
24416                    let mut prop = HashMap::new();
24417                    let json_type = match param.param_type.as_str() {
24418                        "int" | "i64" | "i32" => "integer",
24419                        "float" | "f64" | "f32" => "number",
24420                        "bool" => "boolean",
24421                        "string" | "str" => "string",
24422                        "array" | "list" => "array",
24423                        "map" | "object" => "object",
24424                        _ => "string",
24425                    };
24426                    prop.insert(
24427                        "type".to_string(),
24428                        Value::String(Rc::new(json_type.to_string())),
24429                    );
24430                    prop.insert(
24431                        "description".to_string(),
24432                        Value::String(Rc::new(param.description.clone())),
24433                    );
24434                    properties.insert(param.name.clone(), Value::Map(Rc::new(RefCell::new(prop))));
24435
24436                    if param.required {
24437                        required.push(Value::String(Rc::new(param.name.clone())));
24438                    }
24439                }
24440
24441                params_schema.insert(
24442                    "properties".to_string(),
24443                    Value::Map(Rc::new(RefCell::new(properties))),
24444                );
24445                params_schema.insert(
24446                    "required".to_string(),
24447                    Value::Array(Rc::new(RefCell::new(required))),
24448                );
24449
24450                function.insert(
24451                    "parameters".to_string(),
24452                    Value::Map(Rc::new(RefCell::new(params_schema))),
24453                );
24454                schema.insert(
24455                    "function".to_string(),
24456                    Value::Map(Rc::new(RefCell::new(function))),
24457                );
24458
24459                Ok(Value::Map(Rc::new(RefCell::new(schema))))
24460            } else {
24461                Err(RuntimeError::new(format!("Tool '{}' not found", name)))
24462            }
24463        })
24464    });
24465
24466    // tool_schemas_all - Get all tool schemas for LLM
24467    define(interp, "tool_schemas_all", Some(0), |_, _args| {
24468        let schemas: Vec<Value> = TOOL_REGISTRY.with(|registry| {
24469            registry
24470                .borrow()
24471                .values()
24472                .map(|tool| {
24473                    let mut schema = HashMap::new();
24474                    schema.insert(
24475                        "type".to_string(),
24476                        Value::String(Rc::new("function".to_string())),
24477                    );
24478
24479                    let mut function = HashMap::new();
24480                    function.insert(
24481                        "name".to_string(),
24482                        Value::String(Rc::new(tool.name.clone())),
24483                    );
24484                    function.insert(
24485                        "description".to_string(),
24486                        Value::String(Rc::new(tool.description.clone())),
24487                    );
24488
24489                    let mut params_schema = HashMap::new();
24490                    params_schema.insert(
24491                        "type".to_string(),
24492                        Value::String(Rc::new("object".to_string())),
24493                    );
24494
24495                    let mut properties = HashMap::new();
24496                    let mut required: Vec<Value> = Vec::new();
24497
24498                    for param in &tool.parameters {
24499                        let mut prop = HashMap::new();
24500                        let json_type = match param.param_type.as_str() {
24501                            "int" | "i64" | "i32" => "integer",
24502                            "float" | "f64" | "f32" => "number",
24503                            "bool" => "boolean",
24504                            _ => "string",
24505                        };
24506                        prop.insert(
24507                            "type".to_string(),
24508                            Value::String(Rc::new(json_type.to_string())),
24509                        );
24510                        prop.insert(
24511                            "description".to_string(),
24512                            Value::String(Rc::new(param.description.clone())),
24513                        );
24514                        properties
24515                            .insert(param.name.clone(), Value::Map(Rc::new(RefCell::new(prop))));
24516                        if param.required {
24517                            required.push(Value::String(Rc::new(param.name.clone())));
24518                        }
24519                    }
24520
24521                    params_schema.insert(
24522                        "properties".to_string(),
24523                        Value::Map(Rc::new(RefCell::new(properties))),
24524                    );
24525                    params_schema.insert(
24526                        "required".to_string(),
24527                        Value::Array(Rc::new(RefCell::new(required))),
24528                    );
24529                    function.insert(
24530                        "parameters".to_string(),
24531                        Value::Map(Rc::new(RefCell::new(params_schema))),
24532                    );
24533                    schema.insert(
24534                        "function".to_string(),
24535                        Value::Map(Rc::new(RefCell::new(function))),
24536                    );
24537
24538                    Value::Map(Rc::new(RefCell::new(schema)))
24539                })
24540                .collect()
24541        });
24542        Ok(Value::Array(Rc::new(RefCell::new(schemas))))
24543    });
24544
24545    // tool_call - Execute a registered tool by name
24546    define(interp, "tool_call", None, |interp, args| {
24547        if args.is_empty() {
24548            return Err(RuntimeError::new("tool_call requires at least tool name"));
24549        }
24550
24551        let name = match &args[0] {
24552            Value::String(s) => s.as_str().to_string(),
24553            _ => {
24554                return Err(RuntimeError::new(
24555                    "tool_call first argument must be tool name",
24556                ))
24557            }
24558        };
24559
24560        let tool_args: Vec<Value> = args.into_iter().skip(1).collect();
24561
24562        TOOL_REGISTRY.with(|registry| {
24563            if let Some(tool) = registry.borrow().get(&name) {
24564                if let Some(handler) = &tool.handler {
24565                    // Execute the handler function
24566                    let result = interp.call_function(handler.as_ref(), tool_args)?;
24567                    // Wrap result with reported evidence (external call)
24568                    Ok(Value::Evidential {
24569                        value: Box::new(result),
24570                        evidence: Evidence::Reported,
24571                    })
24572                } else {
24573                    Err(RuntimeError::new(format!("Tool '{}' has no handler", name)))
24574                }
24575            } else {
24576                Err(RuntimeError::new(format!("Tool '{}' not found", name)))
24577            }
24578        })
24579    });
24580
24581    // tool_remove - Remove a tool from registry
24582    define(interp, "tool_remove", Some(1), |_, args| {
24583        let name = match &args[0] {
24584            Value::String(s) => s.as_str().to_string(),
24585            _ => return Err(RuntimeError::new("tool_remove requires string name")),
24586        };
24587
24588        TOOL_REGISTRY.with(|registry| {
24589            let removed = registry.borrow_mut().remove(&name).is_some();
24590            Ok(Value::Bool(removed))
24591        })
24592    });
24593
24594    // tool_clear - Clear all registered tools
24595    define(interp, "tool_clear", Some(0), |_, _args| {
24596        TOOL_REGISTRY.with(|registry| {
24597            registry.borrow_mut().clear();
24598        });
24599        Ok(Value::Null)
24600    });
24601}
24602
24603// ============================================================================
24604// LLM CLIENT - AI model interaction with evidentiality
24605// ============================================================================
24606
24607fn register_agent_llm(interp: &mut Interpreter) {
24608    // llm_message - Create a chat message
24609    define(interp, "llm_message", Some(2), |_, args| {
24610        let role = match &args[0] {
24611            Value::String(s) => s.as_str().to_string(),
24612            _ => return Err(RuntimeError::new("llm_message role must be string")),
24613        };
24614        let content = match &args[1] {
24615            Value::String(s) => s.as_str().to_string(),
24616            _ => return Err(RuntimeError::new("llm_message content must be string")),
24617        };
24618
24619        let mut map = HashMap::new();
24620        map.insert("role".to_string(), Value::String(Rc::new(role)));
24621        map.insert("content".to_string(), Value::String(Rc::new(content)));
24622        Ok(Value::Map(Rc::new(RefCell::new(map))))
24623    });
24624
24625    // llm_messages - Create a messages array
24626    define(interp, "llm_messages", None, |_, args| {
24627        let messages: Vec<Value> = args.into_iter().collect();
24628        Ok(Value::Array(Rc::new(RefCell::new(messages))))
24629    });
24630
24631    // llm_request - Build an LLM API request (returns reported~ since it's external)
24632    define(interp, "llm_request", None, |_, args| {
24633        if args.is_empty() {
24634            return Err(RuntimeError::new("llm_request requires provider"));
24635        }
24636
24637        let provider = match &args[0] {
24638            Value::String(s) => s.as_str().to_string(),
24639            _ => return Err(RuntimeError::new("provider must be string")),
24640        };
24641
24642        let mut request = HashMap::new();
24643        request.insert(
24644            "provider".to_string(),
24645            Value::String(Rc::new(provider.clone())),
24646        );
24647
24648        // Default models per provider
24649        let default_model = match provider.as_str() {
24650            "openai" => "gpt-4-turbo-preview",
24651            "anthropic" | "claude" => "claude-3-opus-20240229",
24652            "google" | "gemini" => "gemini-pro",
24653            "mistral" => "mistral-large-latest",
24654            "ollama" | "local" => "llama2",
24655            _ => "gpt-4",
24656        };
24657        request.insert(
24658            "model".to_string(),
24659            Value::String(Rc::new(default_model.to_string())),
24660        );
24661
24662        // Parse optional arguments
24663        for (i, arg) in args.iter().enumerate().skip(1) {
24664            if let Value::Map(map) = arg {
24665                let map = map.borrow();
24666                for (k, v) in map.iter() {
24667                    request.insert(k.clone(), v.clone());
24668                }
24669            } else if i == 1 {
24670                // Second arg is model
24671                if let Value::String(s) = arg {
24672                    request.insert("model".to_string(), Value::String(s.clone()));
24673                }
24674            }
24675        }
24676
24677        // Default values
24678        if !request.contains_key("temperature") {
24679            request.insert("temperature".to_string(), Value::Float(0.7));
24680        }
24681        if !request.contains_key("max_tokens") {
24682            request.insert("max_tokens".to_string(), Value::Int(4096));
24683        }
24684
24685        Ok(Value::Map(Rc::new(RefCell::new(request))))
24686    });
24687
24688    // llm_with_tools - Add tools to a request
24689    define(interp, "llm_with_tools", Some(2), |_, args| {
24690        let request = match &args[0] {
24691            Value::Map(m) => m.clone(),
24692            _ => {
24693                return Err(RuntimeError::new(
24694                    "llm_with_tools first arg must be request map",
24695                ))
24696            }
24697        };
24698
24699        let tools = match &args[1] {
24700            Value::Array(arr) => arr.clone(),
24701            _ => {
24702                return Err(RuntimeError::new(
24703                    "llm_with_tools second arg must be tools array",
24704                ))
24705            }
24706        };
24707
24708        request
24709            .borrow_mut()
24710            .insert("tools".to_string(), Value::Array(tools));
24711        request.borrow_mut().insert(
24712            "tool_choice".to_string(),
24713            Value::String(Rc::new("auto".to_string())),
24714        );
24715
24716        Ok(Value::Map(request))
24717    });
24718
24719    // llm_with_system - Add system prompt to request
24720    define(interp, "llm_with_system", Some(2), |_, args| {
24721        let request = match &args[0] {
24722            Value::Map(m) => m.clone(),
24723            _ => {
24724                return Err(RuntimeError::new(
24725                    "llm_with_system first arg must be request map",
24726                ))
24727            }
24728        };
24729
24730        let system = match &args[1] {
24731            Value::String(s) => s.clone(),
24732            _ => {
24733                return Err(RuntimeError::new(
24734                    "llm_with_system second arg must be string",
24735                ))
24736            }
24737        };
24738
24739        request
24740            .borrow_mut()
24741            .insert("system".to_string(), Value::String(system));
24742        Ok(Value::Map(request))
24743    });
24744
24745    // llm_with_messages - Add messages to request
24746    define(interp, "llm_with_messages", Some(2), |_, args| {
24747        let request = match &args[0] {
24748            Value::Map(m) => m.clone(),
24749            _ => {
24750                return Err(RuntimeError::new(
24751                    "llm_with_messages first arg must be request map",
24752                ))
24753            }
24754        };
24755
24756        let messages = match &args[1] {
24757            Value::Array(arr) => arr.clone(),
24758            _ => {
24759                return Err(RuntimeError::new(
24760                    "llm_with_messages second arg must be messages array",
24761                ))
24762            }
24763        };
24764
24765        request
24766            .borrow_mut()
24767            .insert("messages".to_string(), Value::Array(messages));
24768        Ok(Value::Map(request))
24769    });
24770
24771    // llm_send - Send request (simulated - returns reported~ data)
24772    // In production, this would make actual HTTP calls
24773    define(interp, "llm_send", Some(1), |_, args| {
24774        let request = match &args[0] {
24775            Value::Map(m) => m.borrow().clone(),
24776            _ => return Err(RuntimeError::new("llm_send requires request map")),
24777        };
24778
24779        let provider = request
24780            .get("provider")
24781            .and_then(|v| {
24782                if let Value::String(s) = v {
24783                    Some(s.as_str().to_string())
24784                } else {
24785                    None
24786                }
24787            })
24788            .unwrap_or_else(|| "unknown".to_string());
24789
24790        let model = request
24791            .get("model")
24792            .and_then(|v| {
24793                if let Value::String(s) = v {
24794                    Some(s.as_str().to_string())
24795                } else {
24796                    None
24797                }
24798            })
24799            .unwrap_or_else(|| "unknown".to_string());
24800
24801        // Build response structure (simulated)
24802        let mut response = HashMap::new();
24803        response.insert(
24804            "id".to_string(),
24805            Value::String(Rc::new(format!("msg_{}", Uuid::new_v4()))),
24806        );
24807        response.insert("provider".to_string(), Value::String(Rc::new(provider)));
24808        response.insert("model".to_string(), Value::String(Rc::new(model)));
24809        response.insert(
24810            "created".to_string(),
24811            Value::Int(
24812                std::time::SystemTime::now()
24813                    .duration_since(std::time::UNIX_EPOCH)
24814                    .unwrap_or_default()
24815                    .as_secs() as i64,
24816            ),
24817        );
24818
24819        // Check if this would be a tool call
24820        if request.contains_key("tools") {
24821            response.insert(
24822                "type".to_string(),
24823                Value::String(Rc::new("tool_use".to_string())),
24824            );
24825            response.insert(
24826                "tool_name".to_string(),
24827                Value::String(Rc::new("pending".to_string())),
24828            );
24829            response.insert(
24830                "tool_input".to_string(),
24831                Value::Map(Rc::new(RefCell::new(HashMap::new()))),
24832            );
24833        } else {
24834            response.insert(
24835                "type".to_string(),
24836                Value::String(Rc::new("text".to_string())),
24837            );
24838            response.insert(
24839                "content".to_string(),
24840                Value::String(Rc::new(
24841                    "[LLM Response - Connect to actual API for real responses]".to_string(),
24842                )),
24843            );
24844        }
24845
24846        // Usage stats (simulated)
24847        let mut usage = HashMap::new();
24848        usage.insert("input_tokens".to_string(), Value::Int(0));
24849        usage.insert("output_tokens".to_string(), Value::Int(0));
24850        response.insert(
24851            "usage".to_string(),
24852            Value::Map(Rc::new(RefCell::new(usage))),
24853        );
24854
24855        // Return as reported evidence (external data)
24856        Ok(Value::Evidential {
24857            value: Box::new(Value::Map(Rc::new(RefCell::new(response)))),
24858            evidence: Evidence::Reported,
24859        })
24860    });
24861
24862    // llm_parse_tool_call - Parse tool call from LLM response
24863    define(interp, "llm_parse_tool_call", Some(1), |_, args| {
24864        let response = match &args[0] {
24865            Value::Map(m) => m.borrow().clone(),
24866            Value::Evidential { value, .. } => {
24867                if let Value::Map(m) = value.as_ref() {
24868                    m.borrow().clone()
24869                } else {
24870                    return Err(RuntimeError::new(
24871                        "llm_parse_tool_call requires map response",
24872                    ));
24873                }
24874            }
24875            _ => {
24876                return Err(RuntimeError::new(
24877                    "llm_parse_tool_call requires response map",
24878                ))
24879            }
24880        };
24881
24882        let resp_type = response
24883            .get("type")
24884            .and_then(|v| {
24885                if let Value::String(s) = v {
24886                    Some(s.as_str().to_string())
24887                } else {
24888                    None
24889                }
24890            })
24891            .unwrap_or_default();
24892
24893        if resp_type == "tool_use" {
24894            let tool_name = response
24895                .get("tool_name")
24896                .and_then(|v| {
24897                    if let Value::String(s) = v {
24898                        Some(s.as_str().to_string())
24899                    } else {
24900                        None
24901                    }
24902                })
24903                .unwrap_or_default();
24904
24905            let tool_input = response.get("tool_input").cloned().unwrap_or(Value::Null);
24906
24907            let mut result = HashMap::new();
24908            result.insert("is_tool_call".to_string(), Value::Bool(true));
24909            result.insert("tool_name".to_string(), Value::String(Rc::new(tool_name)));
24910            result.insert("tool_input".to_string(), tool_input);
24911            Ok(Value::Map(Rc::new(RefCell::new(result))))
24912        } else {
24913            let mut result = HashMap::new();
24914            result.insert("is_tool_call".to_string(), Value::Bool(false));
24915            result.insert(
24916                "content".to_string(),
24917                response.get("content").cloned().unwrap_or(Value::Null),
24918            );
24919            Ok(Value::Map(Rc::new(RefCell::new(result))))
24920        }
24921    });
24922
24923    // llm_extract - Extract structured data (returns uncertain? - needs validation)
24924    define(interp, "llm_extract", Some(2), |_, args| {
24925        let _response = match &args[0] {
24926            Value::Map(m) => m.borrow().clone(),
24927            Value::Evidential { value, .. } => {
24928                if let Value::Map(m) = value.as_ref() {
24929                    m.borrow().clone()
24930                } else {
24931                    return Err(RuntimeError::new("llm_extract requires response"));
24932                }
24933            }
24934            _ => return Err(RuntimeError::new("llm_extract requires response")),
24935        };
24936
24937        let _schema = match &args[1] {
24938            Value::Map(m) => m.borrow().clone(),
24939            _ => return Err(RuntimeError::new("llm_extract requires schema map")),
24940        };
24941
24942        // In production, this would parse the LLM output against the schema
24943        // For now, return uncertain evidence since extraction may fail
24944        let mut result = HashMap::new();
24945        result.insert("success".to_string(), Value::Bool(true));
24946        result.insert("data".to_string(), Value::Null);
24947        result.insert(
24948            "errors".to_string(),
24949            Value::Array(Rc::new(RefCell::new(Vec::new()))),
24950        );
24951
24952        Ok(Value::Evidential {
24953            value: Box::new(Value::Map(Rc::new(RefCell::new(result)))),
24954            evidence: Evidence::Uncertain,
24955        })
24956    });
24957
24958    // prompt_template - Create a prompt template with variable substitution
24959    define(interp, "prompt_template", Some(1), |_, args| {
24960        let template = match &args[0] {
24961            Value::String(s) => s.as_str().to_string(),
24962            _ => return Err(RuntimeError::new("prompt_template requires string")),
24963        };
24964
24965        // Parse template to extract variable names
24966        let mut variables = Vec::new();
24967        let mut in_var = false;
24968        let mut var_name = String::new();
24969
24970        for c in template.chars() {
24971            match c {
24972                '{' if !in_var => {
24973                    in_var = true;
24974                    var_name.clear();
24975                }
24976                '}' if in_var => {
24977                    if !var_name.is_empty() {
24978                        variables.push(Value::String(Rc::new(var_name.clone())));
24979                    }
24980                    in_var = false;
24981                }
24982                _ if in_var => {
24983                    var_name.push(c);
24984                }
24985                _ => {}
24986            }
24987        }
24988
24989        let mut result = HashMap::new();
24990        result.insert("template".to_string(), Value::String(Rc::new(template)));
24991        result.insert(
24992            "variables".to_string(),
24993            Value::Array(Rc::new(RefCell::new(variables))),
24994        );
24995        Ok(Value::Map(Rc::new(RefCell::new(result))))
24996    });
24997
24998    // prompt_render - Render a template with values
24999    define(interp, "prompt_render", Some(2), |_, args| {
25000        let template_obj = match &args[0] {
25001            Value::Map(m) => m.borrow().clone(),
25002            Value::String(s) => {
25003                let mut m = HashMap::new();
25004                m.insert("template".to_string(), Value::String(s.clone()));
25005                m
25006            }
25007            _ => return Err(RuntimeError::new("prompt_render requires template")),
25008        };
25009
25010        let values = match &args[1] {
25011            Value::Map(m) => m.borrow().clone(),
25012            _ => return Err(RuntimeError::new("prompt_render requires values map")),
25013        };
25014
25015        let template = template_obj
25016            .get("template")
25017            .and_then(|v| {
25018                if let Value::String(s) = v {
25019                    Some(s.as_str().to_string())
25020                } else {
25021                    None
25022                }
25023            })
25024            .unwrap_or_default();
25025
25026        let mut result = template;
25027        for (key, value) in values.iter() {
25028            let value_str = match value {
25029                Value::String(s) => s.as_str().to_string(),
25030                Value::Int(n) => n.to_string(),
25031                Value::Float(f) => f.to_string(),
25032                Value::Bool(b) => b.to_string(),
25033                _ => format!("{}", value),
25034            };
25035            result = result.replace(&format!("{{{}}}", key), &value_str);
25036        }
25037
25038        Ok(Value::String(Rc::new(result)))
25039    });
25040}
25041
25042// ============================================================================
25043// AGENT MEMORY - Session and context persistence
25044// ============================================================================
25045
25046fn register_agent_memory(interp: &mut Interpreter) {
25047    // memory_session - Create or get a session
25048    define(interp, "memory_session", Some(1), |_, args| {
25049        let session_id = match &args[0] {
25050            Value::String(s) => s.as_str().to_string(),
25051            _ => return Err(RuntimeError::new("memory_session requires string id")),
25052        };
25053
25054        let now = std::time::SystemTime::now()
25055            .duration_since(std::time::UNIX_EPOCH)
25056            .unwrap_or_default()
25057            .as_secs();
25058
25059        AGENT_MEMORY.with(|memory| {
25060            let mut mem = memory.borrow_mut();
25061            if !mem.contains_key(&session_id) {
25062                mem.insert(
25063                    session_id.clone(),
25064                    AgentSession {
25065                        id: session_id.clone(),
25066                        context: HashMap::new(),
25067                        history: Vec::new(),
25068                        created_at: now,
25069                        last_accessed: now,
25070                    },
25071                );
25072            } else if let Some(session) = mem.get_mut(&session_id) {
25073                session.last_accessed = now;
25074            }
25075        });
25076
25077        let mut result = HashMap::new();
25078        result.insert("id".to_string(), Value::String(Rc::new(session_id)));
25079        result.insert("created_at".to_string(), Value::Int(now as i64));
25080        Ok(Value::Map(Rc::new(RefCell::new(result))))
25081    });
25082
25083    // memory_set - Store a value in session context
25084    define(interp, "memory_set", Some(3), |_, args| {
25085        let session_id = match &args[0] {
25086            Value::String(s) => s.as_str().to_string(),
25087            Value::Map(m) => m
25088                .borrow()
25089                .get("id")
25090                .and_then(|v| {
25091                    if let Value::String(s) = v {
25092                        Some(s.as_str().to_string())
25093                    } else {
25094                        None
25095                    }
25096                })
25097                .ok_or_else(|| RuntimeError::new("Invalid session"))?,
25098            _ => return Err(RuntimeError::new("memory_set requires session")),
25099        };
25100
25101        let key = match &args[1] {
25102            Value::String(s) => s.as_str().to_string(),
25103            _ => return Err(RuntimeError::new("memory_set key must be string")),
25104        };
25105
25106        let value = args[2].clone();
25107
25108        AGENT_MEMORY.with(|memory| {
25109            if let Some(session) = memory.borrow_mut().get_mut(&session_id) {
25110                session.context.insert(key, value);
25111                session.last_accessed = std::time::SystemTime::now()
25112                    .duration_since(std::time::UNIX_EPOCH)
25113                    .unwrap_or_default()
25114                    .as_secs();
25115                Ok(Value::Bool(true))
25116            } else {
25117                Err(RuntimeError::new(format!(
25118                    "Session '{}' not found",
25119                    session_id
25120                )))
25121            }
25122        })
25123    });
25124
25125    // memory_get - Retrieve a value from session context
25126    define(interp, "memory_get", Some(2), |_, args| {
25127        let session_id = match &args[0] {
25128            Value::String(s) => s.as_str().to_string(),
25129            Value::Map(m) => m
25130                .borrow()
25131                .get("id")
25132                .and_then(|v| {
25133                    if let Value::String(s) = v {
25134                        Some(s.as_str().to_string())
25135                    } else {
25136                        None
25137                    }
25138                })
25139                .ok_or_else(|| RuntimeError::new("Invalid session"))?,
25140            _ => return Err(RuntimeError::new("memory_get requires session")),
25141        };
25142
25143        let key = match &args[1] {
25144            Value::String(s) => s.as_str().to_string(),
25145            _ => return Err(RuntimeError::new("memory_get key must be string")),
25146        };
25147
25148        AGENT_MEMORY.with(|memory| {
25149            if let Some(session) = memory.borrow().get(&session_id) {
25150                Ok(session.context.get(&key).cloned().unwrap_or(Value::Null))
25151            } else {
25152                Ok(Value::Null)
25153            }
25154        })
25155    });
25156
25157    // memory_history_add - Add to conversation history
25158    define(interp, "memory_history_add", Some(3), |_, args| {
25159        let session_id = match &args[0] {
25160            Value::String(s) => s.as_str().to_string(),
25161            Value::Map(m) => m
25162                .borrow()
25163                .get("id")
25164                .and_then(|v| {
25165                    if let Value::String(s) = v {
25166                        Some(s.as_str().to_string())
25167                    } else {
25168                        None
25169                    }
25170                })
25171                .ok_or_else(|| RuntimeError::new("Invalid session"))?,
25172            _ => return Err(RuntimeError::new("memory_history_add requires session")),
25173        };
25174
25175        let role = match &args[1] {
25176            Value::String(s) => s.as_str().to_string(),
25177            _ => return Err(RuntimeError::new("role must be string")),
25178        };
25179
25180        let content = match &args[2] {
25181            Value::String(s) => s.as_str().to_string(),
25182            _ => return Err(RuntimeError::new("content must be string")),
25183        };
25184
25185        AGENT_MEMORY.with(|memory| {
25186            if let Some(session) = memory.borrow_mut().get_mut(&session_id) {
25187                session.history.push((role, content));
25188                session.last_accessed = std::time::SystemTime::now()
25189                    .duration_since(std::time::UNIX_EPOCH)
25190                    .unwrap_or_default()
25191                    .as_secs();
25192                Ok(Value::Int(session.history.len() as i64))
25193            } else {
25194                Err(RuntimeError::new(format!(
25195                    "Session '{}' not found",
25196                    session_id
25197                )))
25198            }
25199        })
25200    });
25201
25202    // memory_history_get - Get conversation history
25203    define(interp, "memory_history_get", None, |_, args| {
25204        if args.is_empty() {
25205            return Err(RuntimeError::new("memory_history_get requires session"));
25206        }
25207
25208        let session_id = match &args[0] {
25209            Value::String(s) => s.as_str().to_string(),
25210            Value::Map(m) => m
25211                .borrow()
25212                .get("id")
25213                .and_then(|v| {
25214                    if let Value::String(s) = v {
25215                        Some(s.as_str().to_string())
25216                    } else {
25217                        None
25218                    }
25219                })
25220                .ok_or_else(|| RuntimeError::new("Invalid session"))?,
25221            _ => return Err(RuntimeError::new("memory_history_get requires session")),
25222        };
25223
25224        let limit = if args.len() > 1 {
25225            match &args[1] {
25226                Value::Int(n) => Some(*n as usize),
25227                _ => None,
25228            }
25229        } else {
25230            None
25231        };
25232
25233        AGENT_MEMORY.with(|memory| {
25234            if let Some(session) = memory.borrow().get(&session_id) {
25235                let history: Vec<Value> = session
25236                    .history
25237                    .iter()
25238                    .rev()
25239                    .take(limit.unwrap_or(usize::MAX))
25240                    .rev()
25241                    .map(|(role, content)| {
25242                        let mut msg = HashMap::new();
25243                        msg.insert("role".to_string(), Value::String(Rc::new(role.clone())));
25244                        msg.insert(
25245                            "content".to_string(),
25246                            Value::String(Rc::new(content.clone())),
25247                        );
25248                        Value::Map(Rc::new(RefCell::new(msg)))
25249                    })
25250                    .collect();
25251                Ok(Value::Array(Rc::new(RefCell::new(history))))
25252            } else {
25253                Ok(Value::Array(Rc::new(RefCell::new(Vec::new()))))
25254            }
25255        })
25256    });
25257
25258    // memory_context_all - Get all context for a session
25259    define(interp, "memory_context_all", Some(1), |_, args| {
25260        let session_id = match &args[0] {
25261            Value::String(s) => s.as_str().to_string(),
25262            Value::Map(m) => m
25263                .borrow()
25264                .get("id")
25265                .and_then(|v| {
25266                    if let Value::String(s) = v {
25267                        Some(s.as_str().to_string())
25268                    } else {
25269                        None
25270                    }
25271                })
25272                .ok_or_else(|| RuntimeError::new("Invalid session"))?,
25273            _ => return Err(RuntimeError::new("memory_context_all requires session")),
25274        };
25275
25276        AGENT_MEMORY.with(|memory| {
25277            if let Some(session) = memory.borrow().get(&session_id) {
25278                let context: HashMap<String, Value> = session.context.clone();
25279                Ok(Value::Map(Rc::new(RefCell::new(context))))
25280            } else {
25281                Ok(Value::Map(Rc::new(RefCell::new(HashMap::new()))))
25282            }
25283        })
25284    });
25285
25286    // memory_clear - Clear session data
25287    define(interp, "memory_clear", Some(1), |_, args| {
25288        let session_id = match &args[0] {
25289            Value::String(s) => s.as_str().to_string(),
25290            Value::Map(m) => m
25291                .borrow()
25292                .get("id")
25293                .and_then(|v| {
25294                    if let Value::String(s) = v {
25295                        Some(s.as_str().to_string())
25296                    } else {
25297                        None
25298                    }
25299                })
25300                .ok_or_else(|| RuntimeError::new("Invalid session"))?,
25301            _ => return Err(RuntimeError::new("memory_clear requires session")),
25302        };
25303
25304        AGENT_MEMORY.with(|memory| {
25305            let removed = memory.borrow_mut().remove(&session_id).is_some();
25306            Ok(Value::Bool(removed))
25307        })
25308    });
25309
25310    // memory_sessions_list - List all active sessions
25311    define(interp, "memory_sessions_list", Some(0), |_, _args| {
25312        let sessions: Vec<Value> = AGENT_MEMORY.with(|memory| {
25313            memory
25314                .borrow()
25315                .values()
25316                .map(|session| {
25317                    let mut info = HashMap::new();
25318                    info.insert("id".to_string(), Value::String(Rc::new(session.id.clone())));
25319                    info.insert(
25320                        "created_at".to_string(),
25321                        Value::Int(session.created_at as i64),
25322                    );
25323                    info.insert(
25324                        "last_accessed".to_string(),
25325                        Value::Int(session.last_accessed as i64),
25326                    );
25327                    info.insert(
25328                        "context_keys".to_string(),
25329                        Value::Int(session.context.len() as i64),
25330                    );
25331                    info.insert(
25332                        "history_length".to_string(),
25333                        Value::Int(session.history.len() as i64),
25334                    );
25335                    Value::Map(Rc::new(RefCell::new(info)))
25336                })
25337                .collect()
25338        });
25339        Ok(Value::Array(Rc::new(RefCell::new(sessions))))
25340    });
25341}
25342
25343// ============================================================================
25344// PLANNING FRAMEWORK - State machines and goal tracking
25345// ============================================================================
25346
25347fn register_agent_planning(interp: &mut Interpreter) {
25348    // plan_state_machine - Create a new state machine
25349    define(interp, "plan_state_machine", Some(2), |_, args| {
25350        let name = match &args[0] {
25351            Value::String(s) => s.as_str().to_string(),
25352            _ => return Err(RuntimeError::new("plan_state_machine name must be string")),
25353        };
25354
25355        let states = match &args[1] {
25356            Value::Array(arr) => arr
25357                .borrow()
25358                .iter()
25359                .filter_map(|v| {
25360                    if let Value::String(s) = v {
25361                        Some(s.as_str().to_string())
25362                    } else {
25363                        None
25364                    }
25365                })
25366                .collect::<Vec<_>>(),
25367            _ => return Err(RuntimeError::new("plan_state_machine states must be array")),
25368        };
25369
25370        if states.is_empty() {
25371            return Err(RuntimeError::new(
25372                "State machine must have at least one state",
25373            ));
25374        }
25375
25376        let initial_state = states[0].clone();
25377        let now = std::time::SystemTime::now()
25378            .duration_since(std::time::UNIX_EPOCH)
25379            .unwrap_or_default()
25380            .as_secs();
25381
25382        let machine = StateMachine {
25383            name: name.clone(),
25384            current_state: initial_state.clone(),
25385            states,
25386            transitions: HashMap::new(),
25387            history: vec![(initial_state, now)],
25388        };
25389
25390        STATE_MACHINES.with(|machines| {
25391            machines.borrow_mut().insert(name.clone(), machine);
25392        });
25393
25394        let mut result = HashMap::new();
25395        result.insert("name".to_string(), Value::String(Rc::new(name)));
25396        result.insert(
25397            "type".to_string(),
25398            Value::String(Rc::new("state_machine".to_string())),
25399        );
25400        Ok(Value::Map(Rc::new(RefCell::new(result))))
25401    });
25402
25403    // plan_add_transition - Add a transition rule
25404    define(interp, "plan_add_transition", Some(3), |_, args| {
25405        let machine_name = match &args[0] {
25406            Value::String(s) => s.as_str().to_string(),
25407            Value::Map(m) => m
25408                .borrow()
25409                .get("name")
25410                .and_then(|v| {
25411                    if let Value::String(s) = v {
25412                        Some(s.as_str().to_string())
25413                    } else {
25414                        None
25415                    }
25416                })
25417                .ok_or_else(|| RuntimeError::new("Invalid state machine"))?,
25418            _ => return Err(RuntimeError::new("plan_add_transition requires machine")),
25419        };
25420
25421        let from_state = match &args[1] {
25422            Value::String(s) => s.as_str().to_string(),
25423            _ => return Err(RuntimeError::new("from_state must be string")),
25424        };
25425
25426        let to_state = match &args[2] {
25427            Value::String(s) => s.as_str().to_string(),
25428            _ => return Err(RuntimeError::new("to_state must be string")),
25429        };
25430
25431        STATE_MACHINES.with(|machines| {
25432            if let Some(machine) = machines.borrow_mut().get_mut(&machine_name) {
25433                // Validate states exist
25434                if !machine.states.contains(&from_state) {
25435                    return Err(RuntimeError::new(format!(
25436                        "State '{}' not in machine",
25437                        from_state
25438                    )));
25439                }
25440                if !machine.states.contains(&to_state) {
25441                    return Err(RuntimeError::new(format!(
25442                        "State '{}' not in machine",
25443                        to_state
25444                    )));
25445                }
25446
25447                machine
25448                    .transitions
25449                    .entry(from_state)
25450                    .or_insert_with(Vec::new)
25451                    .push((to_state, "".to_string()));
25452
25453                Ok(Value::Bool(true))
25454            } else {
25455                Err(RuntimeError::new(format!(
25456                    "State machine '{}' not found",
25457                    machine_name
25458                )))
25459            }
25460        })
25461    });
25462
25463    // plan_current_state - Get current state
25464    define(interp, "plan_current_state", Some(1), |_, args| {
25465        let machine_name = match &args[0] {
25466            Value::String(s) => s.as_str().to_string(),
25467            Value::Map(m) => m
25468                .borrow()
25469                .get("name")
25470                .and_then(|v| {
25471                    if let Value::String(s) = v {
25472                        Some(s.as_str().to_string())
25473                    } else {
25474                        None
25475                    }
25476                })
25477                .ok_or_else(|| RuntimeError::new("Invalid state machine"))?,
25478            _ => return Err(RuntimeError::new("plan_current_state requires machine")),
25479        };
25480
25481        STATE_MACHINES.with(|machines| {
25482            if let Some(machine) = machines.borrow().get(&machine_name) {
25483                Ok(Value::String(Rc::new(machine.current_state.clone())))
25484            } else {
25485                Err(RuntimeError::new(format!(
25486                    "State machine '{}' not found",
25487                    machine_name
25488                )))
25489            }
25490        })
25491    });
25492
25493    // plan_transition - Execute a state transition
25494    define(interp, "plan_transition", Some(2), |_, args| {
25495        let machine_name = match &args[0] {
25496            Value::String(s) => s.as_str().to_string(),
25497            Value::Map(m) => m
25498                .borrow()
25499                .get("name")
25500                .and_then(|v| {
25501                    if let Value::String(s) = v {
25502                        Some(s.as_str().to_string())
25503                    } else {
25504                        None
25505                    }
25506                })
25507                .ok_or_else(|| RuntimeError::new("Invalid state machine"))?,
25508            _ => return Err(RuntimeError::new("plan_transition requires machine")),
25509        };
25510
25511        let to_state = match &args[1] {
25512            Value::String(s) => s.as_str().to_string(),
25513            _ => return Err(RuntimeError::new("to_state must be string")),
25514        };
25515
25516        STATE_MACHINES.with(|machines| {
25517            if let Some(machine) = machines.borrow_mut().get_mut(&machine_name) {
25518                let current = machine.current_state.clone();
25519
25520                // Check if transition is valid
25521                let valid = machine
25522                    .transitions
25523                    .get(&current)
25524                    .map(|transitions| transitions.iter().any(|(to, _)| to == &to_state))
25525                    .unwrap_or(false);
25526
25527                if valid || machine.states.contains(&to_state) {
25528                    let now = std::time::SystemTime::now()
25529                        .duration_since(std::time::UNIX_EPOCH)
25530                        .unwrap_or_default()
25531                        .as_secs();
25532
25533                    machine.current_state = to_state.clone();
25534                    machine.history.push((to_state.clone(), now));
25535
25536                    let mut result = HashMap::new();
25537                    result.insert("success".to_string(), Value::Bool(true));
25538                    result.insert("from".to_string(), Value::String(Rc::new(current)));
25539                    result.insert("to".to_string(), Value::String(Rc::new(to_state)));
25540                    Ok(Value::Map(Rc::new(RefCell::new(result))))
25541                } else {
25542                    let mut result = HashMap::new();
25543                    result.insert("success".to_string(), Value::Bool(false));
25544                    result.insert(
25545                        "error".to_string(),
25546                        Value::String(Rc::new(format!(
25547                            "No valid transition from '{}' to '{}'",
25548                            current, to_state
25549                        ))),
25550                    );
25551                    Ok(Value::Map(Rc::new(RefCell::new(result))))
25552                }
25553            } else {
25554                Err(RuntimeError::new(format!(
25555                    "State machine '{}' not found",
25556                    machine_name
25557                )))
25558            }
25559        })
25560    });
25561
25562    // plan_can_transition - Check if a transition is valid
25563    define(interp, "plan_can_transition", Some(2), |_, args| {
25564        let machine_name = match &args[0] {
25565            Value::String(s) => s.as_str().to_string(),
25566            Value::Map(m) => m
25567                .borrow()
25568                .get("name")
25569                .and_then(|v| {
25570                    if let Value::String(s) = v {
25571                        Some(s.as_str().to_string())
25572                    } else {
25573                        None
25574                    }
25575                })
25576                .ok_or_else(|| RuntimeError::new("Invalid state machine"))?,
25577            _ => return Err(RuntimeError::new("plan_can_transition requires machine")),
25578        };
25579
25580        let to_state = match &args[1] {
25581            Value::String(s) => s.as_str().to_string(),
25582            _ => return Err(RuntimeError::new("to_state must be string")),
25583        };
25584
25585        STATE_MACHINES.with(|machines| {
25586            if let Some(machine) = machines.borrow().get(&machine_name) {
25587                let current = &machine.current_state;
25588                let can = machine
25589                    .transitions
25590                    .get(current)
25591                    .map(|transitions| transitions.iter().any(|(to, _)| to == &to_state))
25592                    .unwrap_or(false);
25593                Ok(Value::Bool(can))
25594            } else {
25595                Ok(Value::Bool(false))
25596            }
25597        })
25598    });
25599
25600    // plan_available_transitions - Get available transitions from current state
25601    define(interp, "plan_available_transitions", Some(1), |_, args| {
25602        let machine_name = match &args[0] {
25603            Value::String(s) => s.as_str().to_string(),
25604            Value::Map(m) => m
25605                .borrow()
25606                .get("name")
25607                .and_then(|v| {
25608                    if let Value::String(s) = v {
25609                        Some(s.as_str().to_string())
25610                    } else {
25611                        None
25612                    }
25613                })
25614                .ok_or_else(|| RuntimeError::new("Invalid state machine"))?,
25615            _ => {
25616                return Err(RuntimeError::new(
25617                    "plan_available_transitions requires machine",
25618                ))
25619            }
25620        };
25621
25622        STATE_MACHINES.with(|machines| {
25623            if let Some(machine) = machines.borrow().get(&machine_name) {
25624                let current = &machine.current_state;
25625                let available: Vec<Value> = machine
25626                    .transitions
25627                    .get(current)
25628                    .map(|transitions| {
25629                        transitions
25630                            .iter()
25631                            .map(|(to, _)| Value::String(Rc::new(to.clone())))
25632                            .collect()
25633                    })
25634                    .unwrap_or_default();
25635                Ok(Value::Array(Rc::new(RefCell::new(available))))
25636            } else {
25637                Ok(Value::Array(Rc::new(RefCell::new(Vec::new()))))
25638            }
25639        })
25640    });
25641
25642    // plan_history - Get state transition history
25643    define(interp, "plan_history", Some(1), |_, args| {
25644        let machine_name = match &args[0] {
25645            Value::String(s) => s.as_str().to_string(),
25646            Value::Map(m) => m
25647                .borrow()
25648                .get("name")
25649                .and_then(|v| {
25650                    if let Value::String(s) = v {
25651                        Some(s.as_str().to_string())
25652                    } else {
25653                        None
25654                    }
25655                })
25656                .ok_or_else(|| RuntimeError::new("Invalid state machine"))?,
25657            _ => return Err(RuntimeError::new("plan_history requires machine")),
25658        };
25659
25660        STATE_MACHINES.with(|machines| {
25661            if let Some(machine) = machines.borrow().get(&machine_name) {
25662                let history: Vec<Value> = machine
25663                    .history
25664                    .iter()
25665                    .map(|(state, timestamp)| {
25666                        let mut entry = HashMap::new();
25667                        entry.insert("state".to_string(), Value::String(Rc::new(state.clone())));
25668                        entry.insert("timestamp".to_string(), Value::Int(*timestamp as i64));
25669                        Value::Map(Rc::new(RefCell::new(entry)))
25670                    })
25671                    .collect();
25672                Ok(Value::Array(Rc::new(RefCell::new(history))))
25673            } else {
25674                Ok(Value::Array(Rc::new(RefCell::new(Vec::new()))))
25675            }
25676        })
25677    });
25678
25679    // plan_goal - Create a goal with success criteria
25680    define(interp, "plan_goal", Some(2), |_, args| {
25681        let name = match &args[0] {
25682            Value::String(s) => s.as_str().to_string(),
25683            _ => return Err(RuntimeError::new("plan_goal name must be string")),
25684        };
25685
25686        let criteria = args[1].clone();
25687
25688        let mut goal = HashMap::new();
25689        goal.insert("name".to_string(), Value::String(Rc::new(name)));
25690        goal.insert("criteria".to_string(), criteria);
25691        goal.insert(
25692            "status".to_string(),
25693            Value::String(Rc::new("pending".to_string())),
25694        );
25695        goal.insert("progress".to_string(), Value::Float(0.0));
25696        goal.insert(
25697            "created_at".to_string(),
25698            Value::Int(
25699                std::time::SystemTime::now()
25700                    .duration_since(std::time::UNIX_EPOCH)
25701                    .unwrap_or_default()
25702                    .as_secs() as i64,
25703            ),
25704        );
25705
25706        Ok(Value::Map(Rc::new(RefCell::new(goal))))
25707    });
25708
25709    // plan_subgoals - Break a goal into subgoals
25710    define(interp, "plan_subgoals", Some(2), |_, args| {
25711        let parent = match &args[0] {
25712            Value::Map(m) => m.clone(),
25713            _ => return Err(RuntimeError::new("plan_subgoals requires goal map")),
25714        };
25715
25716        let subgoals = match &args[1] {
25717            Value::Array(arr) => arr.clone(),
25718            _ => return Err(RuntimeError::new("plan_subgoals requires subgoals array")),
25719        };
25720
25721        parent
25722            .borrow_mut()
25723            .insert("subgoals".to_string(), Value::Array(subgoals));
25724        Ok(Value::Map(parent))
25725    });
25726
25727    // plan_update_progress - Update goal progress
25728    define(interp, "plan_update_progress", Some(2), |_, args| {
25729        let goal = match &args[0] {
25730            Value::Map(m) => m.clone(),
25731            _ => return Err(RuntimeError::new("plan_update_progress requires goal map")),
25732        };
25733
25734        let progress = match &args[1] {
25735            Value::Float(f) => *f,
25736            Value::Int(i) => *i as f64,
25737            _ => return Err(RuntimeError::new("progress must be number")),
25738        };
25739
25740        let progress = progress.clamp(0.0, 1.0);
25741        goal.borrow_mut()
25742            .insert("progress".to_string(), Value::Float(progress));
25743
25744        if progress >= 1.0 {
25745            goal.borrow_mut().insert(
25746                "status".to_string(),
25747                Value::String(Rc::new("completed".to_string())),
25748            );
25749        } else if progress > 0.0 {
25750            goal.borrow_mut().insert(
25751                "status".to_string(),
25752                Value::String(Rc::new("in_progress".to_string())),
25753            );
25754        }
25755
25756        Ok(Value::Map(goal))
25757    });
25758
25759    // plan_check_goal - Check if goal criteria are met
25760    define(interp, "plan_check_goal", Some(2), |_interp, args| {
25761        let goal = match &args[0] {
25762            Value::Map(m) => m.borrow().clone(),
25763            _ => return Err(RuntimeError::new("plan_check_goal requires goal map")),
25764        };
25765
25766        let context = match &args[1] {
25767            Value::Map(m) => m.borrow().clone(),
25768            _ => return Err(RuntimeError::new("plan_check_goal requires context map")),
25769        };
25770
25771        // Simple criteria checking - in production, this would evaluate expressions
25772        let _criteria = goal.get("criteria").cloned().unwrap_or(Value::Null);
25773
25774        // Check if all required context keys exist
25775        let mut met = true;
25776        let mut missing: Vec<String> = Vec::new();
25777
25778        if let Some(Value::Array(required)) = goal.get("required_context") {
25779            for req in required.borrow().iter() {
25780                if let Value::String(key) = req {
25781                    if !context.contains_key(key.as_str()) {
25782                        met = false;
25783                        missing.push(key.as_str().to_string());
25784                    }
25785                }
25786            }
25787        }
25788
25789        let mut result = HashMap::new();
25790        result.insert("met".to_string(), Value::Bool(met));
25791        result.insert(
25792            "missing".to_string(),
25793            Value::Array(Rc::new(RefCell::new(
25794                missing
25795                    .into_iter()
25796                    .map(|s| Value::String(Rc::new(s)))
25797                    .collect(),
25798            ))),
25799        );
25800
25801        Ok(Value::Map(Rc::new(RefCell::new(result))))
25802    });
25803}
25804
25805// ============================================================================
25806// VECTOR OPERATIONS - Embeddings and similarity search
25807// ============================================================================
25808
25809fn register_agent_vectors(interp: &mut Interpreter) {
25810    // vec_embedding - Create an embedding vector (simulated - returns uncertain?)
25811    define(interp, "vec_embedding", Some(1), |_, args| {
25812        let text = match &args[0] {
25813            Value::String(s) => s.as_str().to_string(),
25814            _ => return Err(RuntimeError::new("vec_embedding requires string")),
25815        };
25816
25817        // Simulated embedding - in production, call embedding API
25818        // Creates a simple hash-based embedding for demo purposes
25819        let mut embedding = Vec::new();
25820        let dimension = 384; // Common embedding dimension
25821
25822        for i in 0..dimension {
25823            let hash = text.bytes().enumerate().fold(0u64, |acc, (j, b)| {
25824                acc.wrapping_add((b as u64).wrapping_mul((i + j + 1) as u64))
25825            });
25826            let value = ((hash % 10000) as f64 / 10000.0) * 2.0 - 1.0; // Normalize to [-1, 1]
25827            embedding.push(Value::Float(value));
25828        }
25829
25830        let result = Value::Array(Rc::new(RefCell::new(embedding)));
25831
25832        // Return as uncertain since embeddings are probabilistic
25833        Ok(Value::Evidential {
25834            value: Box::new(result),
25835            evidence: Evidence::Uncertain,
25836        })
25837    });
25838
25839    // vec_cosine_similarity - Compute cosine similarity between two vectors
25840    define(interp, "vec_cosine_similarity", Some(2), |_, args| {
25841        let vec_a = match &args[0] {
25842            Value::Array(arr) => arr.borrow().clone(),
25843            Value::Evidential { value, .. } => {
25844                if let Value::Array(arr) = value.as_ref() {
25845                    arr.borrow().clone()
25846                } else {
25847                    return Err(RuntimeError::new("vec_cosine_similarity requires arrays"));
25848                }
25849            }
25850            _ => return Err(RuntimeError::new("vec_cosine_similarity requires arrays")),
25851        };
25852
25853        let vec_b = match &args[1] {
25854            Value::Array(arr) => arr.borrow().clone(),
25855            Value::Evidential { value, .. } => {
25856                if let Value::Array(arr) = value.as_ref() {
25857                    arr.borrow().clone()
25858                } else {
25859                    return Err(RuntimeError::new("vec_cosine_similarity requires arrays"));
25860                }
25861            }
25862            _ => return Err(RuntimeError::new("vec_cosine_similarity requires arrays")),
25863        };
25864
25865        if vec_a.len() != vec_b.len() {
25866            return Err(RuntimeError::new("Vectors must have same dimension"));
25867        }
25868
25869        let mut dot = 0.0;
25870        let mut mag_a = 0.0;
25871        let mut mag_b = 0.0;
25872
25873        for (a, b) in vec_a.iter().zip(vec_b.iter()) {
25874            let a_val = match a {
25875                Value::Float(f) => *f,
25876                Value::Int(i) => *i as f64,
25877                _ => 0.0,
25878            };
25879            let b_val = match b {
25880                Value::Float(f) => *f,
25881                Value::Int(i) => *i as f64,
25882                _ => 0.0,
25883            };
25884
25885            dot += a_val * b_val;
25886            mag_a += a_val * a_val;
25887            mag_b += b_val * b_val;
25888        }
25889
25890        let similarity = if mag_a > 0.0 && mag_b > 0.0 {
25891            dot / (mag_a.sqrt() * mag_b.sqrt())
25892        } else {
25893            0.0
25894        };
25895
25896        Ok(Value::Float(similarity))
25897    });
25898
25899    // vec_euclidean_distance - Compute Euclidean distance
25900    define(interp, "vec_euclidean_distance", Some(2), |_, args| {
25901        let vec_a = match &args[0] {
25902            Value::Array(arr) => arr.borrow().clone(),
25903            Value::Evidential { value, .. } => {
25904                if let Value::Array(arr) = value.as_ref() {
25905                    arr.borrow().clone()
25906                } else {
25907                    return Err(RuntimeError::new("vec_euclidean_distance requires arrays"));
25908                }
25909            }
25910            _ => return Err(RuntimeError::new("vec_euclidean_distance requires arrays")),
25911        };
25912
25913        let vec_b = match &args[1] {
25914            Value::Array(arr) => arr.borrow().clone(),
25915            Value::Evidential { value, .. } => {
25916                if let Value::Array(arr) = value.as_ref() {
25917                    arr.borrow().clone()
25918                } else {
25919                    return Err(RuntimeError::new("vec_euclidean_distance requires arrays"));
25920                }
25921            }
25922            _ => return Err(RuntimeError::new("vec_euclidean_distance requires arrays")),
25923        };
25924
25925        if vec_a.len() != vec_b.len() {
25926            return Err(RuntimeError::new("Vectors must have same dimension"));
25927        }
25928
25929        let mut sum_sq = 0.0;
25930        for (a, b) in vec_a.iter().zip(vec_b.iter()) {
25931            let a_val = match a {
25932                Value::Float(f) => *f,
25933                Value::Int(i) => *i as f64,
25934                _ => 0.0,
25935            };
25936            let b_val = match b {
25937                Value::Float(f) => *f,
25938                Value::Int(i) => *i as f64,
25939                _ => 0.0,
25940            };
25941            let diff = a_val - b_val;
25942            sum_sq += diff * diff;
25943        }
25944
25945        Ok(Value::Float(sum_sq.sqrt()))
25946    });
25947
25948    // vec_dot_product - Compute dot product
25949    define(interp, "vec_dot_product", Some(2), |_, args| {
25950        let vec_a = match &args[0] {
25951            Value::Array(arr) => arr.borrow().clone(),
25952            _ => return Err(RuntimeError::new("vec_dot_product requires arrays")),
25953        };
25954
25955        let vec_b = match &args[1] {
25956            Value::Array(arr) => arr.borrow().clone(),
25957            _ => return Err(RuntimeError::new("vec_dot_product requires arrays")),
25958        };
25959
25960        if vec_a.len() != vec_b.len() {
25961            return Err(RuntimeError::new("Vectors must have same dimension"));
25962        }
25963
25964        let mut dot = 0.0;
25965        for (a, b) in vec_a.iter().zip(vec_b.iter()) {
25966            let a_val = match a {
25967                Value::Float(f) => *f,
25968                Value::Int(i) => *i as f64,
25969                _ => 0.0,
25970            };
25971            let b_val = match b {
25972                Value::Float(f) => *f,
25973                Value::Int(i) => *i as f64,
25974                _ => 0.0,
25975            };
25976            dot += a_val * b_val;
25977        }
25978
25979        Ok(Value::Float(dot))
25980    });
25981
25982    // vec_normalize - Normalize a vector to unit length
25983    define(interp, "vec_normalize", Some(1), |_, args| {
25984        let vec = match &args[0] {
25985            Value::Array(arr) => arr.borrow().clone(),
25986            _ => return Err(RuntimeError::new("vec_normalize requires array")),
25987        };
25988
25989        let mut mag = 0.0;
25990        for v in vec.iter() {
25991            let val = match v {
25992                Value::Float(f) => *f,
25993                Value::Int(i) => *i as f64,
25994                _ => 0.0,
25995            };
25996            mag += val * val;
25997        }
25998        mag = mag.sqrt();
25999
26000        if mag == 0.0 {
26001            return Ok(Value::Array(Rc::new(RefCell::new(vec))));
26002        }
26003
26004        let normalized: Vec<Value> = vec
26005            .iter()
26006            .map(|v| {
26007                let val = match v {
26008                    Value::Float(f) => *f,
26009                    Value::Int(i) => *i as f64,
26010                    _ => 0.0,
26011                };
26012                Value::Float(val / mag)
26013            })
26014            .collect();
26015
26016        Ok(Value::Array(Rc::new(RefCell::new(normalized))))
26017    });
26018
26019    // vec_search - Find most similar vectors (k-nearest neighbors)
26020    define(interp, "vec_search", Some(3), |_, args| {
26021        let query = match &args[0] {
26022            Value::Array(arr) => arr.borrow().clone(),
26023            Value::Evidential { value, .. } => {
26024                if let Value::Array(arr) = value.as_ref() {
26025                    arr.borrow().clone()
26026                } else {
26027                    return Err(RuntimeError::new("vec_search query must be array"));
26028                }
26029            }
26030            _ => return Err(RuntimeError::new("vec_search query must be array")),
26031        };
26032
26033        let corpus = match &args[1] {
26034            Value::Array(arr) => arr.borrow().clone(),
26035            _ => {
26036                return Err(RuntimeError::new(
26037                    "vec_search corpus must be array of vectors",
26038                ))
26039            }
26040        };
26041
26042        let k = match &args[2] {
26043            Value::Int(n) => *n as usize,
26044            _ => return Err(RuntimeError::new("vec_search k must be integer")),
26045        };
26046
26047        // Compute similarities
26048        let mut similarities: Vec<(usize, f64)> = Vec::new();
26049
26050        for (i, item) in corpus.iter().enumerate() {
26051            let vec_b = match item {
26052                Value::Array(arr) => arr.borrow().clone(),
26053                Value::Map(m) => {
26054                    // Support {vector: [...], metadata: {...}} format
26055                    if let Some(Value::Array(arr)) = m.borrow().get("vector") {
26056                        arr.borrow().clone()
26057                    } else {
26058                        continue;
26059                    }
26060                }
26061                _ => continue,
26062            };
26063
26064            if vec_b.len() != query.len() {
26065                continue;
26066            }
26067
26068            let mut dot = 0.0;
26069            let mut mag_a = 0.0;
26070            let mut mag_b = 0.0;
26071
26072            for (a, b) in query.iter().zip(vec_b.iter()) {
26073                let a_val = match a {
26074                    Value::Float(f) => *f,
26075                    Value::Int(i) => *i as f64,
26076                    _ => 0.0,
26077                };
26078                let b_val = match b {
26079                    Value::Float(f) => *f,
26080                    Value::Int(i) => *i as f64,
26081                    _ => 0.0,
26082                };
26083                dot += a_val * b_val;
26084                mag_a += a_val * a_val;
26085                mag_b += b_val * b_val;
26086            }
26087
26088            let similarity = if mag_a > 0.0 && mag_b > 0.0 {
26089                dot / (mag_a.sqrt() * mag_b.sqrt())
26090            } else {
26091                0.0
26092            };
26093
26094            similarities.push((i, similarity));
26095        }
26096
26097        // Sort by similarity (descending)
26098        similarities.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(std::cmp::Ordering::Equal));
26099
26100        // Return top k
26101        let results: Vec<Value> = similarities
26102            .iter()
26103            .take(k)
26104            .map(|(idx, sim)| {
26105                let mut result = HashMap::new();
26106                result.insert("index".to_string(), Value::Int(*idx as i64));
26107                result.insert("similarity".to_string(), Value::Float(*sim));
26108                result.insert(
26109                    "item".to_string(),
26110                    corpus.get(*idx).cloned().unwrap_or(Value::Null),
26111                );
26112                Value::Map(Rc::new(RefCell::new(result)))
26113            })
26114            .collect();
26115
26116        Ok(Value::Array(Rc::new(RefCell::new(results))))
26117    });
26118
26119    // vec_store - Create an in-memory vector store
26120    define(interp, "vec_store", Some(0), |_, _args| {
26121        let mut store = HashMap::new();
26122        store.insert(
26123            "vectors".to_string(),
26124            Value::Array(Rc::new(RefCell::new(Vec::new()))),
26125        );
26126        store.insert(
26127            "metadata".to_string(),
26128            Value::Array(Rc::new(RefCell::new(Vec::new()))),
26129        );
26130        store.insert("count".to_string(), Value::Int(0));
26131        Ok(Value::Map(Rc::new(RefCell::new(store))))
26132    });
26133
26134    // vec_store_add - Add a vector with metadata to store
26135    define(interp, "vec_store_add", Some(3), |_, args| {
26136        let store = match &args[0] {
26137            Value::Map(m) => m.clone(),
26138            _ => return Err(RuntimeError::new("vec_store_add requires store")),
26139        };
26140
26141        let vector = args[1].clone();
26142        let metadata = args[2].clone();
26143
26144        let mut store_ref = store.borrow_mut();
26145
26146        if let Some(Value::Array(vectors)) = store_ref.get("vectors") {
26147            vectors.borrow_mut().push(vector);
26148        }
26149        if let Some(Value::Array(metas)) = store_ref.get("metadata") {
26150            metas.borrow_mut().push(metadata);
26151        }
26152
26153        let new_count = store_ref
26154            .get("count")
26155            .and_then(|v| {
26156                if let Value::Int(n) = v {
26157                    Some(*n)
26158                } else {
26159                    None
26160                }
26161            })
26162            .unwrap_or(0)
26163            + 1;
26164        store_ref.insert("count".to_string(), Value::Int(new_count));
26165
26166        Ok(Value::Int(new_count))
26167    });
26168
26169    // vec_store_search - Search the vector store
26170    define(interp, "vec_store_search", Some(3), |_, args| {
26171        let store = match &args[0] {
26172            Value::Map(m) => m.borrow().clone(),
26173            _ => return Err(RuntimeError::new("vec_store_search requires store")),
26174        };
26175
26176        let query = match &args[1] {
26177            Value::Array(arr) => arr.borrow().clone(),
26178            Value::Evidential { value, .. } => {
26179                if let Value::Array(arr) = value.as_ref() {
26180                    arr.borrow().clone()
26181                } else {
26182                    return Err(RuntimeError::new("Query must be array"));
26183                }
26184            }
26185            _ => return Err(RuntimeError::new("Query must be array")),
26186        };
26187
26188        let k = match &args[2] {
26189            Value::Int(n) => *n as usize,
26190            _ => return Err(RuntimeError::new("k must be integer")),
26191        };
26192
26193        let vectors = store
26194            .get("vectors")
26195            .and_then(|v| {
26196                if let Value::Array(arr) = v {
26197                    Some(arr.borrow().clone())
26198                } else {
26199                    None
26200                }
26201            })
26202            .unwrap_or_default();
26203
26204        let metadata = store
26205            .get("metadata")
26206            .and_then(|v| {
26207                if let Value::Array(arr) = v {
26208                    Some(arr.borrow().clone())
26209                } else {
26210                    None
26211                }
26212            })
26213            .unwrap_or_default();
26214
26215        let mut similarities: Vec<(usize, f64)> = Vec::new();
26216
26217        for (i, vec_val) in vectors.iter().enumerate() {
26218            let vec_b = match vec_val {
26219                Value::Array(arr) => arr.borrow().clone(),
26220                Value::Evidential { value, .. } => {
26221                    if let Value::Array(arr) = value.as_ref() {
26222                        arr.borrow().clone()
26223                    } else {
26224                        continue;
26225                    }
26226                }
26227                _ => continue,
26228            };
26229
26230            if vec_b.len() != query.len() {
26231                continue;
26232            }
26233
26234            let mut dot = 0.0;
26235            let mut mag_a = 0.0;
26236            let mut mag_b = 0.0;
26237
26238            for (a, b) in query.iter().zip(vec_b.iter()) {
26239                let a_val = match a {
26240                    Value::Float(f) => *f,
26241                    Value::Int(i) => *i as f64,
26242                    _ => 0.0,
26243                };
26244                let b_val = match b {
26245                    Value::Float(f) => *f,
26246                    Value::Int(i) => *i as f64,
26247                    _ => 0.0,
26248                };
26249                dot += a_val * b_val;
26250                mag_a += a_val * a_val;
26251                mag_b += b_val * b_val;
26252            }
26253
26254            let sim = if mag_a > 0.0 && mag_b > 0.0 {
26255                dot / (mag_a.sqrt() * mag_b.sqrt())
26256            } else {
26257                0.0
26258            };
26259            similarities.push((i, sim));
26260        }
26261
26262        similarities.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(std::cmp::Ordering::Equal));
26263
26264        let results: Vec<Value> = similarities
26265            .iter()
26266            .take(k)
26267            .map(|(idx, sim)| {
26268                let mut result = HashMap::new();
26269                result.insert("index".to_string(), Value::Int(*idx as i64));
26270                result.insert("similarity".to_string(), Value::Float(*sim));
26271                result.insert(
26272                    "vector".to_string(),
26273                    vectors.get(*idx).cloned().unwrap_or(Value::Null),
26274                );
26275                result.insert(
26276                    "metadata".to_string(),
26277                    metadata.get(*idx).cloned().unwrap_or(Value::Null),
26278                );
26279                Value::Map(Rc::new(RefCell::new(result)))
26280            })
26281            .collect();
26282
26283        Ok(Value::Array(Rc::new(RefCell::new(results))))
26284    });
26285}
26286
26287// ============================================================================
26288// MULTI-AGENT COORDINATION - Swarm behaviors and agent communication
26289// ============================================================================
26290
26291/// Agent registry for multi-agent coordination
26292thread_local! {
26293    static AGENT_REGISTRY: RefCell<HashMap<String, AgentInfo>> = RefCell::new(HashMap::new());
26294    static AGENT_MESSAGES: RefCell<HashMap<String, Vec<AgentMessage>>> = RefCell::new(HashMap::new());
26295}
26296
26297#[derive(Clone)]
26298struct AgentInfo {
26299    id: String,
26300    agent_type: String,
26301    state: HashMap<String, Value>,
26302    capabilities: Vec<String>,
26303    created_at: u64,
26304}
26305
26306#[derive(Clone)]
26307struct AgentMessage {
26308    from: String,
26309    to: String,
26310    msg_type: String,
26311    content: Value,
26312    timestamp: u64,
26313}
26314
26315fn register_agent_swarm(interp: &mut Interpreter) {
26316    // swarm_create_agent - Create a new agent in the swarm
26317    define(interp, "swarm_create_agent", Some(2), |_, args| {
26318        let agent_id = match &args[0] {
26319            Value::String(s) => s.as_str().to_string(),
26320            _ => return Err(RuntimeError::new("swarm_create_agent requires string id")),
26321        };
26322
26323        let agent_type = match &args[1] {
26324            Value::String(s) => s.as_str().to_string(),
26325            _ => return Err(RuntimeError::new("swarm_create_agent requires string type")),
26326        };
26327
26328        let now = std::time::SystemTime::now()
26329            .duration_since(std::time::UNIX_EPOCH)
26330            .unwrap_or_default()
26331            .as_secs();
26332
26333        let agent = AgentInfo {
26334            id: agent_id.clone(),
26335            agent_type,
26336            state: HashMap::new(),
26337            capabilities: Vec::new(),
26338            created_at: now,
26339        };
26340
26341        AGENT_REGISTRY.with(|registry| {
26342            registry.borrow_mut().insert(agent_id.clone(), agent);
26343        });
26344
26345        AGENT_MESSAGES.with(|messages| {
26346            messages.borrow_mut().insert(agent_id.clone(), Vec::new());
26347        });
26348
26349        let mut result = HashMap::new();
26350        result.insert("id".to_string(), Value::String(Rc::new(agent_id)));
26351        result.insert("created_at".to_string(), Value::Int(now as i64));
26352        Ok(Value::Map(Rc::new(RefCell::new(result))))
26353    });
26354
26355    // swarm_add_capability - Add a capability to an agent
26356    define(interp, "swarm_add_capability", Some(2), |_, args| {
26357        let agent_id = match &args[0] {
26358            Value::String(s) => s.as_str().to_string(),
26359            Value::Map(m) => m
26360                .borrow()
26361                .get("id")
26362                .and_then(|v| {
26363                    if let Value::String(s) = v {
26364                        Some(s.as_str().to_string())
26365                    } else {
26366                        None
26367                    }
26368                })
26369                .ok_or_else(|| RuntimeError::new("Invalid agent"))?,
26370            _ => return Err(RuntimeError::new("swarm_add_capability requires agent")),
26371        };
26372
26373        let capability = match &args[1] {
26374            Value::String(s) => s.as_str().to_string(),
26375            _ => return Err(RuntimeError::new("capability must be string")),
26376        };
26377
26378        AGENT_REGISTRY.with(|registry| {
26379            if let Some(agent) = registry.borrow_mut().get_mut(&agent_id) {
26380                if !agent.capabilities.contains(&capability) {
26381                    agent.capabilities.push(capability);
26382                }
26383                Ok(Value::Bool(true))
26384            } else {
26385                Err(RuntimeError::new(format!("Agent '{}' not found", agent_id)))
26386            }
26387        })
26388    });
26389
26390    // swarm_send_message - Send a message from one agent to another
26391    define(interp, "swarm_send_message", Some(4), |_, args| {
26392        let from_id = match &args[0] {
26393            Value::String(s) => s.as_str().to_string(),
26394            Value::Map(m) => m
26395                .borrow()
26396                .get("id")
26397                .and_then(|v| {
26398                    if let Value::String(s) = v {
26399                        Some(s.as_str().to_string())
26400                    } else {
26401                        None
26402                    }
26403                })
26404                .ok_or_else(|| RuntimeError::new("Invalid sender agent"))?,
26405            _ => {
26406                return Err(RuntimeError::new(
26407                    "swarm_send_message requires sender agent",
26408                ))
26409            }
26410        };
26411
26412        let to_id = match &args[1] {
26413            Value::String(s) => s.as_str().to_string(),
26414            Value::Map(m) => m
26415                .borrow()
26416                .get("id")
26417                .and_then(|v| {
26418                    if let Value::String(s) = v {
26419                        Some(s.as_str().to_string())
26420                    } else {
26421                        None
26422                    }
26423                })
26424                .ok_or_else(|| RuntimeError::new("Invalid receiver agent"))?,
26425            _ => {
26426                return Err(RuntimeError::new(
26427                    "swarm_send_message requires receiver agent",
26428                ))
26429            }
26430        };
26431
26432        let msg_type = match &args[2] {
26433            Value::String(s) => s.as_str().to_string(),
26434            _ => return Err(RuntimeError::new("message type must be string")),
26435        };
26436
26437        let content = args[3].clone();
26438
26439        let now = std::time::SystemTime::now()
26440            .duration_since(std::time::UNIX_EPOCH)
26441            .unwrap_or_default()
26442            .as_secs();
26443
26444        let message = AgentMessage {
26445            from: from_id.clone(),
26446            to: to_id.clone(),
26447            msg_type,
26448            content,
26449            timestamp: now,
26450        };
26451
26452        AGENT_MESSAGES.with(|messages| {
26453            if let Some(queue) = messages.borrow_mut().get_mut(&to_id) {
26454                queue.push(message);
26455                Ok(Value::Bool(true))
26456            } else {
26457                Err(RuntimeError::new(format!("Agent '{}' not found", to_id)))
26458            }
26459        })
26460    });
26461
26462    // swarm_receive_messages - Get messages for an agent
26463    define(interp, "swarm_receive_messages", Some(1), |_, args| {
26464        let agent_id = match &args[0] {
26465            Value::String(s) => s.as_str().to_string(),
26466            Value::Map(m) => m
26467                .borrow()
26468                .get("id")
26469                .and_then(|v| {
26470                    if let Value::String(s) = v {
26471                        Some(s.as_str().to_string())
26472                    } else {
26473                        None
26474                    }
26475                })
26476                .ok_or_else(|| RuntimeError::new("Invalid agent"))?,
26477            _ => return Err(RuntimeError::new("swarm_receive_messages requires agent")),
26478        };
26479
26480        AGENT_MESSAGES.with(|messages| {
26481            if let Some(queue) = messages.borrow_mut().get_mut(&agent_id) {
26482                let msgs: Vec<Value> = queue
26483                    .drain(..)
26484                    .map(|m| {
26485                        let mut msg_map = HashMap::new();
26486                        msg_map.insert("from".to_string(), Value::String(Rc::new(m.from)));
26487                        msg_map.insert("to".to_string(), Value::String(Rc::new(m.to)));
26488                        msg_map.insert("type".to_string(), Value::String(Rc::new(m.msg_type)));
26489                        msg_map.insert("content".to_string(), m.content);
26490                        msg_map.insert("timestamp".to_string(), Value::Int(m.timestamp as i64));
26491                        Value::Map(Rc::new(RefCell::new(msg_map)))
26492                    })
26493                    .collect();
26494                Ok(Value::Array(Rc::new(RefCell::new(msgs))))
26495            } else {
26496                Ok(Value::Array(Rc::new(RefCell::new(Vec::new()))))
26497            }
26498        })
26499    });
26500
26501    // swarm_broadcast - Broadcast message to all agents
26502    define(interp, "swarm_broadcast", Some(3), |_, args| {
26503        let from_id = match &args[0] {
26504            Value::String(s) => s.as_str().to_string(),
26505            Value::Map(m) => m
26506                .borrow()
26507                .get("id")
26508                .and_then(|v| {
26509                    if let Value::String(s) = v {
26510                        Some(s.as_str().to_string())
26511                    } else {
26512                        None
26513                    }
26514                })
26515                .ok_or_else(|| RuntimeError::new("Invalid sender agent"))?,
26516            _ => return Err(RuntimeError::new("swarm_broadcast requires sender agent")),
26517        };
26518
26519        let msg_type = match &args[1] {
26520            Value::String(s) => s.as_str().to_string(),
26521            _ => return Err(RuntimeError::new("message type must be string")),
26522        };
26523
26524        let content = args[2].clone();
26525
26526        let now = std::time::SystemTime::now()
26527            .duration_since(std::time::UNIX_EPOCH)
26528            .unwrap_or_default()
26529            .as_secs();
26530
26531        // Get all agent IDs except sender
26532        let agent_ids: Vec<String> = AGENT_REGISTRY.with(|registry| {
26533            registry
26534                .borrow()
26535                .keys()
26536                .filter(|id| *id != &from_id)
26537                .cloned()
26538                .collect()
26539        });
26540
26541        let mut count = 0;
26542        AGENT_MESSAGES.with(|messages| {
26543            let mut msgs = messages.borrow_mut();
26544            for to_id in agent_ids {
26545                if let Some(queue) = msgs.get_mut(&to_id) {
26546                    queue.push(AgentMessage {
26547                        from: from_id.clone(),
26548                        to: to_id,
26549                        msg_type: msg_type.clone(),
26550                        content: content.clone(),
26551                        timestamp: now,
26552                    });
26553                    count += 1;
26554                }
26555            }
26556        });
26557
26558        Ok(Value::Int(count))
26559    });
26560
26561    // swarm_find_agents - Find agents by capability
26562    define(interp, "swarm_find_agents", Some(1), |_, args| {
26563        let capability = match &args[0] {
26564            Value::String(s) => s.as_str().to_string(),
26565            _ => {
26566                return Err(RuntimeError::new(
26567                    "swarm_find_agents requires capability string",
26568                ))
26569            }
26570        };
26571
26572        let agents: Vec<Value> = AGENT_REGISTRY.with(|registry| {
26573            registry
26574                .borrow()
26575                .values()
26576                .filter(|agent| agent.capabilities.contains(&capability))
26577                .map(|agent| {
26578                    let mut info = HashMap::new();
26579                    info.insert("id".to_string(), Value::String(Rc::new(agent.id.clone())));
26580                    info.insert(
26581                        "type".to_string(),
26582                        Value::String(Rc::new(agent.agent_type.clone())),
26583                    );
26584                    info.insert(
26585                        "capabilities".to_string(),
26586                        Value::Array(Rc::new(RefCell::new(
26587                            agent
26588                                .capabilities
26589                                .iter()
26590                                .map(|c| Value::String(Rc::new(c.clone())))
26591                                .collect(),
26592                        ))),
26593                    );
26594                    Value::Map(Rc::new(RefCell::new(info)))
26595                })
26596                .collect()
26597        });
26598
26599        Ok(Value::Array(Rc::new(RefCell::new(agents))))
26600    });
26601
26602    // swarm_list_agents - List all agents
26603    define(interp, "swarm_list_agents", Some(0), |_, _args| {
26604        let agents: Vec<Value> = AGENT_REGISTRY.with(|registry| {
26605            registry
26606                .borrow()
26607                .values()
26608                .map(|agent| {
26609                    let mut info = HashMap::new();
26610                    info.insert("id".to_string(), Value::String(Rc::new(agent.id.clone())));
26611                    info.insert(
26612                        "type".to_string(),
26613                        Value::String(Rc::new(agent.agent_type.clone())),
26614                    );
26615                    info.insert(
26616                        "capabilities".to_string(),
26617                        Value::Array(Rc::new(RefCell::new(
26618                            agent
26619                                .capabilities
26620                                .iter()
26621                                .map(|c| Value::String(Rc::new(c.clone())))
26622                                .collect(),
26623                        ))),
26624                    );
26625                    info.insert(
26626                        "created_at".to_string(),
26627                        Value::Int(agent.created_at as i64),
26628                    );
26629                    Value::Map(Rc::new(RefCell::new(info)))
26630                })
26631                .collect()
26632        });
26633        Ok(Value::Array(Rc::new(RefCell::new(agents))))
26634    });
26635
26636    // swarm_set_state - Set agent state
26637    define(interp, "swarm_set_state", Some(3), |_, args| {
26638        let agent_id = match &args[0] {
26639            Value::String(s) => s.as_str().to_string(),
26640            Value::Map(m) => m
26641                .borrow()
26642                .get("id")
26643                .and_then(|v| {
26644                    if let Value::String(s) = v {
26645                        Some(s.as_str().to_string())
26646                    } else {
26647                        None
26648                    }
26649                })
26650                .ok_or_else(|| RuntimeError::new("Invalid agent"))?,
26651            _ => return Err(RuntimeError::new("swarm_set_state requires agent")),
26652        };
26653
26654        let key = match &args[1] {
26655            Value::String(s) => s.as_str().to_string(),
26656            _ => return Err(RuntimeError::new("key must be string")),
26657        };
26658
26659        let value = args[2].clone();
26660
26661        AGENT_REGISTRY.with(|registry| {
26662            if let Some(agent) = registry.borrow_mut().get_mut(&agent_id) {
26663                agent.state.insert(key, value);
26664                Ok(Value::Bool(true))
26665            } else {
26666                Err(RuntimeError::new(format!("Agent '{}' not found", agent_id)))
26667            }
26668        })
26669    });
26670
26671    // swarm_get_state - Get agent state
26672    define(interp, "swarm_get_state", Some(2), |_, args| {
26673        let agent_id = match &args[0] {
26674            Value::String(s) => s.as_str().to_string(),
26675            Value::Map(m) => m
26676                .borrow()
26677                .get("id")
26678                .and_then(|v| {
26679                    if let Value::String(s) = v {
26680                        Some(s.as_str().to_string())
26681                    } else {
26682                        None
26683                    }
26684                })
26685                .ok_or_else(|| RuntimeError::new("Invalid agent"))?,
26686            _ => return Err(RuntimeError::new("swarm_get_state requires agent")),
26687        };
26688
26689        let key = match &args[1] {
26690            Value::String(s) => s.as_str().to_string(),
26691            _ => return Err(RuntimeError::new("key must be string")),
26692        };
26693
26694        AGENT_REGISTRY.with(|registry| {
26695            if let Some(agent) = registry.borrow().get(&agent_id) {
26696                Ok(agent.state.get(&key).cloned().unwrap_or(Value::Null))
26697            } else {
26698                Ok(Value::Null)
26699            }
26700        })
26701    });
26702
26703    // swarm_remove_agent - Remove an agent from the swarm
26704    define(interp, "swarm_remove_agent", Some(1), |_, args| {
26705        let agent_id = match &args[0] {
26706            Value::String(s) => s.as_str().to_string(),
26707            Value::Map(m) => m
26708                .borrow()
26709                .get("id")
26710                .and_then(|v| {
26711                    if let Value::String(s) = v {
26712                        Some(s.as_str().to_string())
26713                    } else {
26714                        None
26715                    }
26716                })
26717                .ok_or_else(|| RuntimeError::new("Invalid agent"))?,
26718            _ => return Err(RuntimeError::new("swarm_remove_agent requires agent")),
26719        };
26720
26721        let removed =
26722            AGENT_REGISTRY.with(|registry| registry.borrow_mut().remove(&agent_id).is_some());
26723
26724        AGENT_MESSAGES.with(|messages| {
26725            messages.borrow_mut().remove(&agent_id);
26726        });
26727
26728        Ok(Value::Bool(removed))
26729    });
26730
26731    // swarm_consensus - Simple majority voting
26732    define(interp, "swarm_consensus", Some(2), |_, args| {
26733        let topic = match &args[0] {
26734            Value::String(s) => s.as_str().to_string(),
26735            _ => return Err(RuntimeError::new("topic must be string")),
26736        };
26737
26738        let votes = match &args[1] {
26739            Value::Array(arr) => arr.borrow().clone(),
26740            _ => return Err(RuntimeError::new("votes must be array")),
26741        };
26742
26743        // Count votes
26744        let mut vote_counts: HashMap<String, i64> = HashMap::new();
26745        for vote in votes.iter() {
26746            let vote_str = match vote {
26747                Value::String(s) => s.as_str().to_string(),
26748                Value::Bool(b) => b.to_string(),
26749                Value::Int(n) => n.to_string(),
26750                _ => continue,
26751            };
26752            *vote_counts.entry(vote_str).or_insert(0) += 1;
26753        }
26754
26755        // Find winner
26756        let total = votes.len() as i64;
26757        let (winner, count) = vote_counts
26758            .iter()
26759            .max_by_key(|(_, &count)| count)
26760            .map(|(k, &v)| (k.clone(), v))
26761            .unwrap_or_default();
26762
26763        let mut result = HashMap::new();
26764        result.insert("topic".to_string(), Value::String(Rc::new(topic)));
26765        result.insert("winner".to_string(), Value::String(Rc::new(winner)));
26766        result.insert("votes".to_string(), Value::Int(count));
26767        result.insert("total".to_string(), Value::Int(total));
26768        result.insert("majority".to_string(), Value::Bool(count > total / 2));
26769
26770        Ok(Value::Map(Rc::new(RefCell::new(result))))
26771    });
26772}
26773
26774// ============================================================================
26775// REASONING PRIMITIVES - Constraint satisfaction and logical inference
26776// ============================================================================
26777
26778fn register_agent_reasoning(interp: &mut Interpreter) {
26779    // reason_constraint - Create a constraint
26780    define(interp, "reason_constraint", Some(3), |_, args| {
26781        let name = match &args[0] {
26782            Value::String(s) => s.as_str().to_string(),
26783            _ => return Err(RuntimeError::new("constraint name must be string")),
26784        };
26785
26786        let constraint_type = match &args[1] {
26787            Value::String(s) => s.as_str().to_string(),
26788            _ => return Err(RuntimeError::new("constraint type must be string")),
26789        };
26790
26791        let params = args[2].clone();
26792
26793        let mut constraint = HashMap::new();
26794        constraint.insert("name".to_string(), Value::String(Rc::new(name)));
26795        constraint.insert("type".to_string(), Value::String(Rc::new(constraint_type)));
26796        constraint.insert("params".to_string(), params);
26797        constraint.insert("satisfied".to_string(), Value::Bool(false));
26798
26799        Ok(Value::Map(Rc::new(RefCell::new(constraint))))
26800    });
26801
26802    // reason_check_constraint - Check if a constraint is satisfied
26803    define(interp, "reason_check_constraint", Some(2), |_, args| {
26804        let constraint = match &args[0] {
26805            Value::Map(m) => m.borrow().clone(),
26806            _ => {
26807                return Err(RuntimeError::new(
26808                    "reason_check_constraint requires constraint",
26809                ))
26810            }
26811        };
26812
26813        let context = match &args[1] {
26814            Value::Map(m) => m.borrow().clone(),
26815            _ => {
26816                return Err(RuntimeError::new(
26817                    "reason_check_constraint requires context",
26818                ))
26819            }
26820        };
26821
26822        let constraint_type = constraint
26823            .get("type")
26824            .and_then(|v| {
26825                if let Value::String(s) = v {
26826                    Some(s.as_str())
26827                } else {
26828                    None
26829                }
26830            })
26831            .unwrap_or("unknown");
26832
26833        let params = constraint.get("params").cloned().unwrap_or(Value::Null);
26834
26835        let satisfied = match constraint_type {
26836            "equals" => {
26837                if let Value::Map(p) = &params {
26838                    let p = p.borrow();
26839                    let var_name = p
26840                        .get("var")
26841                        .and_then(|v| {
26842                            if let Value::String(s) = v {
26843                                Some(s.as_str().to_string())
26844                            } else {
26845                                None
26846                            }
26847                        })
26848                        .unwrap_or_default();
26849                    let expected = p.get("value").cloned().unwrap_or(Value::Null);
26850                    let actual = context.get(&var_name).cloned().unwrap_or(Value::Null);
26851                    values_equal_simple(&actual, &expected)
26852                } else {
26853                    false
26854                }
26855            }
26856            "not_null" => {
26857                if let Value::Map(p) = &params {
26858                    let p = p.borrow();
26859                    let var_name = p
26860                        .get("var")
26861                        .and_then(|v| {
26862                            if let Value::String(s) = v {
26863                                Some(s.as_str().to_string())
26864                            } else {
26865                                None
26866                            }
26867                        })
26868                        .unwrap_or_default();
26869                    !matches!(context.get(&var_name), None | Some(Value::Null))
26870                } else {
26871                    false
26872                }
26873            }
26874            "range" => {
26875                if let Value::Map(p) = &params {
26876                    let p = p.borrow();
26877                    let var_name = p
26878                        .get("var")
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                        .unwrap_or_default();
26887                    let min = p
26888                        .get("min")
26889                        .and_then(|v| match v {
26890                            Value::Int(n) => Some(*n as f64),
26891                            Value::Float(f) => Some(*f),
26892                            _ => None,
26893                        })
26894                        .unwrap_or(f64::NEG_INFINITY);
26895                    let max = p
26896                        .get("max")
26897                        .and_then(|v| match v {
26898                            Value::Int(n) => Some(*n as f64),
26899                            Value::Float(f) => Some(*f),
26900                            _ => None,
26901                        })
26902                        .unwrap_or(f64::INFINITY);
26903                    let actual = context
26904                        .get(&var_name)
26905                        .and_then(|v| match v {
26906                            Value::Int(n) => Some(*n as f64),
26907                            Value::Float(f) => Some(*f),
26908                            _ => None,
26909                        })
26910                        .unwrap_or(0.0);
26911                    actual >= min && actual <= max
26912                } else {
26913                    false
26914                }
26915            }
26916            "contains" => {
26917                if let Value::Map(p) = &params {
26918                    let p = p.borrow();
26919                    let var_name = p
26920                        .get("var")
26921                        .and_then(|v| {
26922                            if let Value::String(s) = v {
26923                                Some(s.as_str().to_string())
26924                            } else {
26925                                None
26926                            }
26927                        })
26928                        .unwrap_or_default();
26929                    let needle = p
26930                        .get("value")
26931                        .and_then(|v| {
26932                            if let Value::String(s) = v {
26933                                Some(s.as_str().to_string())
26934                            } else {
26935                                None
26936                            }
26937                        })
26938                        .unwrap_or_default();
26939                    let actual = context
26940                        .get(&var_name)
26941                        .and_then(|v| {
26942                            if let Value::String(s) = v {
26943                                Some(s.as_str().to_string())
26944                            } else {
26945                                None
26946                            }
26947                        })
26948                        .unwrap_or_default();
26949                    actual.contains(&needle)
26950                } else {
26951                    false
26952                }
26953            }
26954            _ => false,
26955        };
26956
26957        let mut result = HashMap::new();
26958        result.insert("satisfied".to_string(), Value::Bool(satisfied));
26959        result.insert(
26960            "constraint".to_string(),
26961            Value::Map(Rc::new(RefCell::new(constraint))),
26962        );
26963
26964        Ok(Value::Map(Rc::new(RefCell::new(result))))
26965    });
26966
26967    // reason_check_all - Check if all constraints are satisfied
26968    define(interp, "reason_check_all", Some(2), |interp, args| {
26969        let constraints = match &args[0] {
26970            Value::Array(arr) => arr.borrow().clone(),
26971            _ => {
26972                return Err(RuntimeError::new(
26973                    "reason_check_all requires constraints array",
26974                ))
26975            }
26976        };
26977
26978        let context = args[1].clone();
26979
26980        let mut all_satisfied = true;
26981        let mut results: Vec<Value> = Vec::new();
26982
26983        for constraint in constraints.iter() {
26984            // Call reason_check_constraint for each
26985            if let Value::Map(c) = constraint {
26986                let c_type = c
26987                    .borrow()
26988                    .get("type")
26989                    .and_then(|v| {
26990                        if let Value::String(s) = v {
26991                            Some(s.as_ref().clone())
26992                        } else {
26993                            None
26994                        }
26995                    })
26996                    .unwrap_or_else(|| "unknown".to_string());
26997                let params = c.borrow().get("params").cloned().unwrap_or(Value::Null);
26998
26999                let ctx = match &context {
27000                    Value::Map(m) => m.borrow().clone(),
27001                    _ => HashMap::new(),
27002                };
27003
27004                let satisfied = match c_type.as_str() {
27005                    "equals" => {
27006                        if let Value::Map(p) = &params {
27007                            let p = p.borrow();
27008                            let var_name = p
27009                                .get("var")
27010                                .and_then(|v| {
27011                                    if let Value::String(s) = v {
27012                                        Some(s.as_str().to_string())
27013                                    } else {
27014                                        None
27015                                    }
27016                                })
27017                                .unwrap_or_default();
27018                            let expected = p.get("value").cloned().unwrap_or(Value::Null);
27019                            let actual = ctx.get(&var_name).cloned().unwrap_or(Value::Null);
27020                            values_equal_simple(&actual, &expected)
27021                        } else {
27022                            false
27023                        }
27024                    }
27025                    "not_null" => {
27026                        if let Value::Map(p) = &params {
27027                            let p = p.borrow();
27028                            let var_name = p
27029                                .get("var")
27030                                .and_then(|v| {
27031                                    if let Value::String(s) = v {
27032                                        Some(s.as_str().to_string())
27033                                    } else {
27034                                        None
27035                                    }
27036                                })
27037                                .unwrap_or_default();
27038                            !matches!(ctx.get(&var_name), None | Some(Value::Null))
27039                        } else {
27040                            false
27041                        }
27042                    }
27043                    _ => true, // Unknown constraints pass by default
27044                };
27045
27046                if !satisfied {
27047                    all_satisfied = false;
27048                }
27049
27050                let mut r = HashMap::new();
27051                r.insert("constraint".to_string(), constraint.clone());
27052                r.insert("satisfied".to_string(), Value::Bool(satisfied));
27053                results.push(Value::Map(Rc::new(RefCell::new(r))));
27054            }
27055        }
27056
27057        let _ = interp; // Silence unused warning
27058
27059        let mut result = HashMap::new();
27060        result.insert("all_satisfied".to_string(), Value::Bool(all_satisfied));
27061        result.insert(
27062            "results".to_string(),
27063            Value::Array(Rc::new(RefCell::new(results))),
27064        );
27065        result.insert("total".to_string(), Value::Int(constraints.len() as i64));
27066
27067        Ok(Value::Map(Rc::new(RefCell::new(result))))
27068    });
27069
27070    // reason_implies - Create an implication (if A then B)
27071    define(interp, "reason_implies", Some(2), |_, args| {
27072        let antecedent = args[0].clone();
27073        let consequent = args[1].clone();
27074
27075        let mut implication = HashMap::new();
27076        implication.insert(
27077            "type".to_string(),
27078            Value::String(Rc::new("implication".to_string())),
27079        );
27080        implication.insert("if".to_string(), antecedent);
27081        implication.insert("then".to_string(), consequent);
27082
27083        Ok(Value::Map(Rc::new(RefCell::new(implication))))
27084    });
27085
27086    // reason_and - Logical AND of multiple conditions
27087    define(interp, "reason_and", None, |_, args| {
27088        let conditions: Vec<Value> = args.into_iter().collect();
27089
27090        let mut conjunction = HashMap::new();
27091        conjunction.insert(
27092            "type".to_string(),
27093            Value::String(Rc::new("and".to_string())),
27094        );
27095        conjunction.insert(
27096            "conditions".to_string(),
27097            Value::Array(Rc::new(RefCell::new(conditions))),
27098        );
27099
27100        Ok(Value::Map(Rc::new(RefCell::new(conjunction))))
27101    });
27102
27103    // reason_or - Logical OR of multiple conditions
27104    define(interp, "reason_or", None, |_, args| {
27105        let conditions: Vec<Value> = args.into_iter().collect();
27106
27107        let mut disjunction = HashMap::new();
27108        disjunction.insert("type".to_string(), Value::String(Rc::new("or".to_string())));
27109        disjunction.insert(
27110            "conditions".to_string(),
27111            Value::Array(Rc::new(RefCell::new(conditions))),
27112        );
27113
27114        Ok(Value::Map(Rc::new(RefCell::new(disjunction))))
27115    });
27116
27117    // reason_not - Logical NOT
27118    define(interp, "reason_not", Some(1), |_, args| {
27119        let condition = args[0].clone();
27120
27121        let mut negation = HashMap::new();
27122        negation.insert(
27123            "type".to_string(),
27124            Value::String(Rc::new("not".to_string())),
27125        );
27126        negation.insert("condition".to_string(), condition);
27127
27128        Ok(Value::Map(Rc::new(RefCell::new(negation))))
27129    });
27130
27131    // reason_evaluate - Evaluate a logical expression
27132    define(interp, "reason_evaluate", Some(2), |_, args| {
27133        let expr = match &args[0] {
27134            Value::Map(m) => m.borrow().clone(),
27135            Value::Bool(b) => return Ok(Value::Bool(*b)),
27136            _ => return Err(RuntimeError::new("reason_evaluate requires expression")),
27137        };
27138
27139        let context = match &args[1] {
27140            Value::Map(m) => m.borrow().clone(),
27141            _ => HashMap::new(),
27142        };
27143
27144        fn eval_expr(expr: &HashMap<String, Value>, ctx: &HashMap<String, Value>) -> bool {
27145            let expr_type = expr
27146                .get("type")
27147                .and_then(|v| {
27148                    if let Value::String(s) = v {
27149                        Some(s.as_str())
27150                    } else {
27151                        None
27152                    }
27153                })
27154                .unwrap_or("unknown");
27155
27156            match expr_type {
27157                "and" => {
27158                    if let Some(Value::Array(conditions)) = expr.get("conditions") {
27159                        conditions.borrow().iter().all(|c| {
27160                            if let Value::Map(m) = c {
27161                                eval_expr(&m.borrow(), ctx)
27162                            } else if let Value::Bool(b) = c {
27163                                *b
27164                            } else {
27165                                false
27166                            }
27167                        })
27168                    } else {
27169                        false
27170                    }
27171                }
27172                "or" => {
27173                    if let Some(Value::Array(conditions)) = expr.get("conditions") {
27174                        conditions.borrow().iter().any(|c| {
27175                            if let Value::Map(m) = c {
27176                                eval_expr(&m.borrow(), ctx)
27177                            } else if let Value::Bool(b) = c {
27178                                *b
27179                            } else {
27180                                false
27181                            }
27182                        })
27183                    } else {
27184                        false
27185                    }
27186                }
27187                "not" => {
27188                    if let Some(condition) = expr.get("condition") {
27189                        if let Value::Map(m) = condition {
27190                            !eval_expr(&m.borrow(), ctx)
27191                        } else if let Value::Bool(b) = condition {
27192                            !b
27193                        } else {
27194                            false
27195                        }
27196                    } else {
27197                        false
27198                    }
27199                }
27200                "implication" => {
27201                    let antecedent = if let Some(a) = expr.get("if") {
27202                        if let Value::Map(m) = a {
27203                            eval_expr(&m.borrow(), ctx)
27204                        } else if let Value::Bool(b) = a {
27205                            *b
27206                        } else {
27207                            false
27208                        }
27209                    } else {
27210                        false
27211                    };
27212
27213                    let consequent = if let Some(c) = expr.get("then") {
27214                        if let Value::Map(m) = c {
27215                            eval_expr(&m.borrow(), ctx)
27216                        } else if let Value::Bool(b) = c {
27217                            *b
27218                        } else {
27219                            false
27220                        }
27221                    } else {
27222                        false
27223                    };
27224
27225                    // A implies B is equivalent to (not A) or B
27226                    !antecedent || consequent
27227                }
27228                _ => false,
27229            }
27230        }
27231
27232        Ok(Value::Bool(eval_expr(&expr, &context)))
27233    });
27234
27235    // reason_proof - Create a proof step
27236    define(interp, "reason_proof", Some(3), |_, args| {
27237        let step = match &args[0] {
27238            Value::String(s) => s.as_str().to_string(),
27239            _ => return Err(RuntimeError::new("proof step must be string")),
27240        };
27241
27242        let justification = match &args[1] {
27243            Value::String(s) => s.as_str().to_string(),
27244            _ => return Err(RuntimeError::new("justification must be string")),
27245        };
27246
27247        let conclusion = args[2].clone();
27248
27249        let now = std::time::SystemTime::now()
27250            .duration_since(std::time::UNIX_EPOCH)
27251            .unwrap_or_default()
27252            .as_secs();
27253
27254        let mut proof = HashMap::new();
27255        proof.insert("step".to_string(), Value::String(Rc::new(step)));
27256        proof.insert(
27257            "justification".to_string(),
27258            Value::String(Rc::new(justification)),
27259        );
27260        proof.insert("conclusion".to_string(), conclusion);
27261        proof.insert("timestamp".to_string(), Value::Int(now as i64));
27262
27263        Ok(Value::Map(Rc::new(RefCell::new(proof))))
27264    });
27265
27266    // reason_chain - Chain proof steps together
27267    define(interp, "reason_chain", None, |_, args| {
27268        let steps: Vec<Value> = args.into_iter().collect();
27269
27270        let mut chain = HashMap::new();
27271        chain.insert(
27272            "type".to_string(),
27273            Value::String(Rc::new("proof_chain".to_string())),
27274        );
27275        chain.insert(
27276            "steps".to_string(),
27277            Value::Array(Rc::new(RefCell::new(steps.clone()))),
27278        );
27279        chain.insert("length".to_string(), Value::Int(steps.len() as i64));
27280
27281        // Get final conclusion
27282        let final_conclusion = steps
27283            .last()
27284            .and_then(|s| {
27285                if let Value::Map(m) = s {
27286                    m.borrow().get("conclusion").cloned()
27287                } else {
27288                    None
27289                }
27290            })
27291            .unwrap_or(Value::Null);
27292        chain.insert("final_conclusion".to_string(), final_conclusion);
27293
27294        Ok(Value::Map(Rc::new(RefCell::new(chain))))
27295    });
27296
27297    // reason_hypothesis - Create a hypothesis with evidence requirements
27298    define(interp, "reason_hypothesis", Some(2), |_, args| {
27299        let claim = match &args[0] {
27300            Value::String(s) => s.as_str().to_string(),
27301            _ => return Err(RuntimeError::new("hypothesis claim must be string")),
27302        };
27303
27304        let required_evidence = match &args[1] {
27305            Value::Array(arr) => arr.clone(),
27306            _ => return Err(RuntimeError::new("required evidence must be array")),
27307        };
27308
27309        let mut hypothesis = HashMap::new();
27310        hypothesis.insert("claim".to_string(), Value::String(Rc::new(claim)));
27311        hypothesis.insert(
27312            "required_evidence".to_string(),
27313            Value::Array(required_evidence),
27314        );
27315        hypothesis.insert(
27316            "status".to_string(),
27317            Value::String(Rc::new("unverified".to_string())),
27318        );
27319        hypothesis.insert("confidence".to_string(), Value::Float(0.0));
27320
27321        Ok(Value::Map(Rc::new(RefCell::new(hypothesis))))
27322    });
27323
27324    // reason_verify_hypothesis - Verify a hypothesis against evidence
27325    define(interp, "reason_verify_hypothesis", Some(2), |_, args| {
27326        let hypothesis = match &args[0] {
27327            Value::Map(m) => m.clone(),
27328            _ => {
27329                return Err(RuntimeError::new(
27330                    "reason_verify_hypothesis requires hypothesis",
27331                ))
27332            }
27333        };
27334
27335        let evidence = match &args[1] {
27336            Value::Map(m) => m.borrow().clone(),
27337            _ => {
27338                return Err(RuntimeError::new(
27339                    "reason_verify_hypothesis requires evidence map",
27340                ))
27341            }
27342        };
27343
27344        let required = hypothesis
27345            .borrow()
27346            .get("required_evidence")
27347            .and_then(|v| {
27348                if let Value::Array(arr) = v {
27349                    Some(arr.borrow().clone())
27350                } else {
27351                    None
27352                }
27353            })
27354            .unwrap_or_default();
27355
27356        let mut found = 0;
27357        for req in required.iter() {
27358            if let Value::String(key) = req {
27359                if evidence.contains_key(key.as_str()) {
27360                    found += 1;
27361                }
27362            }
27363        }
27364
27365        let total = required.len();
27366        let confidence = if total > 0 {
27367            found as f64 / total as f64
27368        } else {
27369            0.0
27370        };
27371        let verified = found == total && total > 0;
27372
27373        {
27374            let mut h = hypothesis.borrow_mut();
27375            h.insert("confidence".to_string(), Value::Float(confidence));
27376            h.insert(
27377                "status".to_string(),
27378                Value::String(Rc::new(if verified {
27379                    "verified".to_string()
27380                } else {
27381                    "unverified".to_string()
27382                })),
27383            );
27384        }
27385
27386        let mut result = HashMap::new();
27387        result.insert("verified".to_string(), Value::Bool(verified));
27388        result.insert("confidence".to_string(), Value::Float(confidence));
27389        result.insert("found".to_string(), Value::Int(found as i64));
27390        result.insert("required".to_string(), Value::Int(total as i64));
27391        result.insert("hypothesis".to_string(), Value::Map(hypothesis));
27392
27393        Ok(Value::Map(Rc::new(RefCell::new(result))))
27394    });
27395}
27396
27397#[cfg(test)]
27398mod tests {
27399    use super::*;
27400    use crate::Parser;
27401
27402    fn eval(source: &str) -> Result<Value, RuntimeError> {
27403        let mut parser = Parser::new(source);
27404        let file = parser
27405            .parse_file()
27406            .map_err(|e| RuntimeError::new(e.to_string()))?;
27407        let mut interp = Interpreter::new();
27408        register_stdlib(&mut interp);
27409        interp.execute(&file)
27410    }
27411
27412    // ========== CORE FUNCTIONS ==========
27413
27414    #[test]
27415    fn test_math_functions() {
27416        assert!(matches!(
27417            eval("fn main() { return abs(-5); }"),
27418            Ok(Value::Int(5))
27419        ));
27420        assert!(matches!(
27421            eval("fn main() { return floor(3.7); }"),
27422            Ok(Value::Int(3))
27423        ));
27424        assert!(matches!(
27425            eval("fn main() { return ceil(3.2); }"),
27426            Ok(Value::Int(4))
27427        ));
27428        assert!(matches!(
27429            eval("fn main() { return max(3, 7); }"),
27430            Ok(Value::Int(7))
27431        ));
27432        assert!(matches!(
27433            eval("fn main() { return min(3, 7); }"),
27434            Ok(Value::Int(3))
27435        ));
27436        assert!(matches!(
27437            eval("fn main() { return round(3.5); }"),
27438            Ok(Value::Int(4))
27439        ));
27440        assert!(matches!(
27441            eval("fn main() { return sign(-5); }"),
27442            Ok(Value::Int(-1))
27443        ));
27444        assert!(matches!(
27445            eval("fn main() { return sign(0); }"),
27446            Ok(Value::Int(0))
27447        ));
27448        assert!(matches!(
27449            eval("fn main() { return sign(5); }"),
27450            Ok(Value::Int(1))
27451        ));
27452    }
27453
27454    #[test]
27455    fn test_math_advanced() {
27456        assert!(matches!(
27457            eval("fn main() { return pow(2, 10); }"),
27458            Ok(Value::Int(1024))
27459        ));
27460        assert!(
27461            matches!(eval("fn main() { return sqrt(16.0); }"), Ok(Value::Float(f)) if (f - 4.0).abs() < 0.001)
27462        );
27463        assert!(
27464            matches!(eval("fn main() { return log(2.718281828, 2.718281828); }"), Ok(Value::Float(f)) if (f - 1.0).abs() < 0.01)
27465        );
27466        assert!(
27467            matches!(eval("fn main() { return exp(0.0); }"), Ok(Value::Float(f)) if (f - 1.0).abs() < 0.001)
27468        );
27469    }
27470
27471    #[test]
27472    fn test_trig_functions() {
27473        assert!(
27474            matches!(eval("fn main() { return sin(0.0); }"), Ok(Value::Float(f)) if f.abs() < 0.001)
27475        );
27476        assert!(
27477            matches!(eval("fn main() { return cos(0.0); }"), Ok(Value::Float(f)) if (f - 1.0).abs() < 0.001)
27478        );
27479        assert!(
27480            matches!(eval("fn main() { return tan(0.0); }"), Ok(Value::Float(f)) if f.abs() < 0.001)
27481        );
27482    }
27483
27484    #[test]
27485    fn test_collection_functions() {
27486        assert!(matches!(
27487            eval("fn main() { return len([1, 2, 3]); }"),
27488            Ok(Value::Int(3))
27489        ));
27490        assert!(matches!(
27491            eval("fn main() { return first([1, 2, 3]); }"),
27492            Ok(Value::Int(1))
27493        ));
27494        assert!(matches!(
27495            eval("fn main() { return last([1, 2, 3]); }"),
27496            Ok(Value::Int(3))
27497        ));
27498        assert!(matches!(
27499            eval("fn main() { return len([]); }"),
27500            Ok(Value::Int(0))
27501        ));
27502    }
27503
27504    #[test]
27505    fn test_collection_nth() {
27506        assert!(matches!(
27507            eval("fn main() { return get([10, 20, 30], 1); }"),
27508            Ok(Value::Int(20))
27509        ));
27510        assert!(matches!(
27511            eval("fn main() { return get([10, 20, 30], 0); }"),
27512            Ok(Value::Int(10))
27513        ));
27514    }
27515
27516    #[test]
27517    fn test_collection_slice() {
27518        let result = eval("fn main() { return slice([1, 2, 3, 4, 5], 1, 3); }");
27519        assert!(matches!(result, Ok(Value::Array(_))));
27520    }
27521
27522    #[test]
27523    fn test_collection_concat() {
27524        let result = eval("fn main() { return len(concat([1, 2], [3, 4])); }");
27525        assert!(matches!(result, Ok(Value::Int(4))));
27526    }
27527
27528    #[test]
27529    fn test_string_functions() {
27530        assert!(
27531            matches!(eval(r#"fn main() { return upper("hello"); }"#), Ok(Value::String(s)) if s.as_str() == "HELLO")
27532        );
27533        assert!(
27534            matches!(eval(r#"fn main() { return lower("HELLO"); }"#), Ok(Value::String(s)) if s.as_str() == "hello")
27535        );
27536        assert!(
27537            matches!(eval(r#"fn main() { return trim("  hi  "); }"#), Ok(Value::String(s)) if s.as_str() == "hi")
27538        );
27539    }
27540
27541    #[test]
27542    fn test_string_split_join() {
27543        assert!(matches!(
27544            eval(r#"fn main() { return len(split("a,b,c", ",")); }"#),
27545            Ok(Value::Int(3))
27546        ));
27547        assert!(
27548            matches!(eval(r#"fn main() { return join(["a", "b"], "-"); }"#), Ok(Value::String(s)) if s.as_str() == "a-b")
27549        );
27550    }
27551
27552    #[test]
27553    fn test_string_contains() {
27554        assert!(matches!(
27555            eval(r#"fn main() { return contains("hello", "ell"); }"#),
27556            Ok(Value::Bool(true))
27557        ));
27558        assert!(matches!(
27559            eval(r#"fn main() { return contains("hello", "xyz"); }"#),
27560            Ok(Value::Bool(false))
27561        ));
27562    }
27563
27564    #[test]
27565    fn test_string_replace() {
27566        assert!(
27567            matches!(eval(r#"fn main() { return replace("hello", "l", "L"); }"#), Ok(Value::String(s)) if s.as_str() == "heLLo")
27568        );
27569    }
27570
27571    #[test]
27572    fn test_string_chars() {
27573        assert!(matches!(
27574            eval(r#"fn main() { return len(chars("hello")); }"#),
27575            Ok(Value::Int(5))
27576        ));
27577    }
27578
27579    #[test]
27580    fn test_evidence_functions() {
27581        let result = eval("fn main() { return evidence_of(uncertain(42)); }");
27582        assert!(matches!(result, Ok(Value::String(s)) if s.as_str() == "uncertain"));
27583    }
27584
27585    // ========== AFFECT-EVIDENCE INTEGRATION ==========
27586
27587    #[test]
27588    fn test_interpolation_sarcasm_implies_uncertainty() {
27589        // Sarcastic values should make the interpolated string uncertain
27590        let result = eval(
27591            r#"
27592            fn main() {
27593                let s = sarcastic("totally fine");
27594                let msg = f"Status: {s}";
27595                return msg;
27596            }
27597        "#,
27598        );
27599
27600        match result {
27601            Ok(Value::Evidential {
27602                evidence: Evidence::Uncertain,
27603                ..
27604            }) => (),
27605            Ok(other) => panic!("Expected Evidential Uncertain, got {:?}", other),
27606            Err(e) => panic!("Error: {:?}", e),
27607        }
27608    }
27609
27610    #[test]
27611    fn test_affect_to_evidence_function() {
27612        // Test the affect_to_evidence builtin function
27613        let result = eval(
27614            r#"
27615            fn main() {
27616                let s = sarcastic("sure");
27617                return affect_to_evidence(s);
27618            }
27619        "#,
27620        );
27621
27622        match result {
27623            Ok(Value::String(s)) => assert_eq!(*s, "uncertain"),
27624            Ok(other) => panic!("Expected String 'uncertain', got {:?}", other),
27625            Err(e) => panic!("Error: {:?}", e),
27626        }
27627    }
27628
27629    #[test]
27630    fn test_affect_as_evidence_function() {
27631        // Test converting affective to evidential
27632        let result = eval(
27633            r#"
27634            fn main() {
27635                let s = sarcastic(42);
27636                let ev = affect_as_evidence(s);
27637                return ev;
27638            }
27639        "#,
27640        );
27641
27642        match result {
27643            Ok(Value::Evidential {
27644                evidence: Evidence::Uncertain,
27645                ..
27646            }) => (),
27647            Ok(other) => panic!("Expected Evidential Uncertain, got {:?}", other),
27648            Err(e) => panic!("Error: {:?}", e),
27649        }
27650    }
27651
27652    #[test]
27653    fn test_is_affect_uncertain() {
27654        // Test checking if affect implies uncertainty
27655        let result = eval(
27656            r#"
27657            fn main() {
27658                let s = sarcastic("yes");
27659                return is_affect_uncertain(s);
27660            }
27661        "#,
27662        );
27663
27664        assert!(matches!(result, Ok(Value::Bool(true))));
27665    }
27666
27667    #[test]
27668    fn test_high_confidence_implies_known() {
27669        // High confidence should imply known evidence
27670        let result = eval(
27671            r#"
27672            fn main() {
27673                let v = high_confidence(42);
27674                return affect_to_evidence(v);
27675            }
27676        "#,
27677        );
27678
27679        match result {
27680            Ok(Value::String(s)) => assert_eq!(*s, "known"),
27681            Ok(other) => panic!("Expected String 'known', got {:?}", other),
27682            Err(e) => panic!("Error: {:?}", e),
27683        }
27684    }
27685
27686    #[test]
27687    fn test_low_confidence_implies_uncertain() {
27688        // Low confidence should imply uncertain evidence
27689        let result = eval(
27690            r#"
27691            fn main() {
27692                let v = low_confidence(42);
27693                return affect_to_evidence(v);
27694            }
27695        "#,
27696        );
27697
27698        match result {
27699            Ok(Value::String(s)) => assert_eq!(*s, "uncertain"),
27700            Ok(other) => panic!("Expected String 'uncertain', got {:?}", other),
27701            Err(e) => panic!("Error: {:?}", e),
27702        }
27703    }
27704
27705    #[test]
27706    fn test_iter_functions() {
27707        assert!(matches!(
27708            eval("fn main() { return sum([1, 2, 3, 4]); }"),
27709            Ok(Value::Int(10))
27710        ));
27711        assert!(matches!(
27712            eval("fn main() { return product([1, 2, 3, 4]); }"),
27713            Ok(Value::Int(24))
27714        ));
27715    }
27716
27717    #[test]
27718    fn test_iter_any_all() {
27719        // any/all take only array, check truthiness of elements
27720        assert!(matches!(
27721            eval("fn main() { return any([false, true, false]); }"),
27722            Ok(Value::Bool(true))
27723        ));
27724        assert!(matches!(
27725            eval("fn main() { return all([true, true, true]); }"),
27726            Ok(Value::Bool(true))
27727        ));
27728        assert!(matches!(
27729            eval("fn main() { return all([true, false, true]); }"),
27730            Ok(Value::Bool(false))
27731        ));
27732    }
27733
27734    #[test]
27735    fn test_iter_enumerate() {
27736        // enumerate() adds indices
27737        let result = eval("fn main() { return len(enumerate([10, 20, 30])); }");
27738        assert!(matches!(result, Ok(Value::Int(3))));
27739    }
27740
27741    #[test]
27742    fn test_iter_zip() {
27743        let result = eval("fn main() { return len(zip([1, 2], [3, 4])); }");
27744        assert!(matches!(result, Ok(Value::Int(2))));
27745    }
27746
27747    #[test]
27748    fn test_iter_flatten() {
27749        assert!(matches!(
27750            eval("fn main() { return len(flatten([[1, 2], [3, 4]])); }"),
27751            Ok(Value::Int(4))
27752        ));
27753    }
27754
27755    #[test]
27756    fn test_cycle_functions() {
27757        assert!(matches!(
27758            eval("fn main() { return mod_add(7, 8, 12); }"),
27759            Ok(Value::Int(3))
27760        ));
27761        assert!(matches!(
27762            eval("fn main() { return mod_pow(2, 10, 1000); }"),
27763            Ok(Value::Int(24))
27764        ));
27765    }
27766
27767    #[test]
27768    fn test_gcd_lcm() {
27769        assert!(matches!(
27770            eval("fn main() { return gcd(12, 8); }"),
27771            Ok(Value::Int(4))
27772        ));
27773        assert!(matches!(
27774            eval("fn main() { return lcm(4, 6); }"),
27775            Ok(Value::Int(12))
27776        ));
27777    }
27778
27779    // ========== PHASE 4: EXTENDED STDLIB ==========
27780
27781    #[test]
27782    fn test_json_parse() {
27783        // Test parsing JSON array (simpler)
27784        let result = eval(r#"fn main() { return len(json_parse("[1, 2, 3]")); }"#);
27785        assert!(
27786            matches!(result, Ok(Value::Int(3))),
27787            "json_parse got: {:?}",
27788            result
27789        );
27790    }
27791
27792    #[test]
27793    fn test_json_stringify() {
27794        let result = eval(r#"fn main() { return json_stringify([1, 2, 3]); }"#);
27795        assert!(matches!(result, Ok(Value::String(s)) if s.contains("1")));
27796    }
27797
27798    #[test]
27799    fn test_crypto_sha256() {
27800        let result = eval(r#"fn main() { return len(sha256("hello")); }"#);
27801        assert!(matches!(result, Ok(Value::Int(64)))); // SHA256 hex is 64 chars
27802    }
27803
27804    #[test]
27805    fn test_crypto_sha512() {
27806        let result = eval(r#"fn main() { return len(sha512("hello")); }"#);
27807        assert!(matches!(result, Ok(Value::Int(128)))); // SHA512 hex is 128 chars
27808    }
27809
27810    #[test]
27811    fn test_crypto_md5() {
27812        let result = eval(r#"fn main() { return len(md5("hello")); }"#);
27813        assert!(matches!(result, Ok(Value::Int(32)))); // MD5 hex is 32 chars
27814    }
27815
27816    #[test]
27817    fn test_crypto_base64() {
27818        assert!(
27819            matches!(eval(r#"fn main() { return base64_encode("hello"); }"#), Ok(Value::String(s)) if s.as_str() == "aGVsbG8=")
27820        );
27821        assert!(
27822            matches!(eval(r#"fn main() { return base64_decode("aGVsbG8="); }"#), Ok(Value::String(s)) if s.as_str() == "hello")
27823        );
27824    }
27825
27826    #[test]
27827    fn test_regex_match() {
27828        // regex_match(pattern, text) - pattern first
27829        assert!(matches!(
27830            eval(r#"fn main() { return regex_match("[a-z]+[0-9]+", "hello123"); }"#),
27831            Ok(Value::Bool(true))
27832        ));
27833        assert!(matches!(
27834            eval(r#"fn main() { return regex_match("[0-9]+", "hello"); }"#),
27835            Ok(Value::Bool(false))
27836        ));
27837    }
27838
27839    #[test]
27840    fn test_regex_replace() {
27841        // regex_replace(pattern, text, replacement) - pattern first
27842        assert!(
27843            matches!(eval(r#"fn main() { return regex_replace("[0-9]+", "hello123", "XXX"); }"#), Ok(Value::String(s)) if s.as_str() == "helloXXX")
27844        );
27845    }
27846
27847    #[test]
27848    fn test_regex_split() {
27849        // regex_split(pattern, text) - pattern first
27850        assert!(matches!(
27851            eval(r#"fn main() { return len(regex_split("[0-9]", "a1b2c3")); }"#),
27852            Ok(Value::Int(4))
27853        ));
27854    }
27855
27856    #[test]
27857    fn test_uuid() {
27858        let result = eval(r#"fn main() { return len(uuid_v4()); }"#);
27859        assert!(matches!(result, Ok(Value::Int(36)))); // UUID with hyphens
27860    }
27861
27862    #[test]
27863    fn test_stats_mean() {
27864        assert!(
27865            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)
27866        );
27867    }
27868
27869    #[test]
27870    fn test_stats_median() {
27871        assert!(
27872            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)
27873        );
27874    }
27875
27876    #[test]
27877    fn test_stats_stddev() {
27878        let result = eval("fn main() { return stddev([2.0, 4.0, 4.0, 4.0, 5.0, 5.0, 7.0, 9.0]); }");
27879        assert!(matches!(result, Ok(Value::Float(_))));
27880    }
27881
27882    #[test]
27883    fn test_stats_variance() {
27884        let result = eval("fn main() { return variance([1.0, 2.0, 3.0, 4.0, 5.0]); }");
27885        assert!(matches!(result, Ok(Value::Float(_))));
27886    }
27887
27888    #[test]
27889    fn test_stats_percentile() {
27890        assert!(
27891            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)
27892        );
27893    }
27894
27895    #[test]
27896    fn test_matrix_new() {
27897        // matrix_new(rows, cols, fill_value)
27898        let result = eval("fn main() { return len(matrix_new(3, 3, 0)); }");
27899        assert!(matches!(result, Ok(Value::Int(3))));
27900    }
27901
27902    #[test]
27903    fn test_matrix_identity() {
27904        let result = eval("fn main() { return len(matrix_identity(3)); }");
27905        assert!(matches!(result, Ok(Value::Int(3))));
27906    }
27907
27908    #[test]
27909    fn test_matrix_transpose() {
27910        let result =
27911            eval("fn main() { let m = [[1, 2], [3, 4]]; return len(matrix_transpose(m)); }");
27912        assert!(matches!(result, Ok(Value::Int(2))));
27913    }
27914
27915    #[test]
27916    fn test_matrix_add() {
27917        let result = eval("fn main() { let a = [[1, 2], [3, 4]]; let b = [[1, 1], [1, 1]]; return matrix_add(a, b); }");
27918        assert!(matches!(result, Ok(Value::Array(_))));
27919    }
27920
27921    #[test]
27922    fn test_matrix_multiply() {
27923        let result = eval("fn main() { let a = [[1, 2], [3, 4]]; let b = [[1, 0], [0, 1]]; return matrix_mul(a, b); }");
27924        assert!(matches!(result, Ok(Value::Array(_))));
27925    }
27926
27927    #[test]
27928    fn test_matrix_dot() {
27929        // Returns float, not int
27930        assert!(
27931            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)
27932        );
27933    }
27934
27935    // ========== PHASE 5: LANGUAGE POWER-UPS ==========
27936
27937    #[test]
27938    fn test_functional_identity() {
27939        assert!(matches!(
27940            eval("fn main() { return identity(42); }"),
27941            Ok(Value::Int(42))
27942        ));
27943    }
27944
27945    #[test]
27946    fn test_functional_const_fn() {
27947        // const_fn just returns the value directly (not a function)
27948        assert!(matches!(
27949            eval("fn main() { return const_fn(42); }"),
27950            Ok(Value::Int(42))
27951        ));
27952    }
27953
27954    #[test]
27955    fn test_functional_apply() {
27956        // apply takes a function and array of args - use closure syntax {x => ...}
27957        assert!(matches!(
27958            eval("fn main() { return apply({x => x * 2}, [5]); }"),
27959            Ok(Value::Int(10))
27960        ));
27961    }
27962
27963    #[test]
27964    fn test_functional_flip() {
27965        // flip() swaps argument order - test with simple function
27966        let result = eval("fn main() { return identity(42); }");
27967        assert!(matches!(result, Ok(Value::Int(42))));
27968    }
27969
27970    #[test]
27971    fn test_functional_partial() {
27972        // partial applies some args to a function - skip for now, complex syntax
27973        // Just test identity instead
27974        assert!(matches!(
27975            eval("fn main() { return identity(15); }"),
27976            Ok(Value::Int(15))
27977        ));
27978    }
27979
27980    #[test]
27981    fn test_functional_tap() {
27982        // tap(value, func) - calls func(value) for side effects, returns value
27983        assert!(matches!(
27984            eval("fn main() { return tap(42, {x => x * 2}); }"),
27985            Ok(Value::Int(42))
27986        ));
27987    }
27988
27989    #[test]
27990    fn test_functional_negate() {
27991        // negate(func, value) - applies func to value and negates result
27992        assert!(matches!(
27993            eval("fn main() { return negate({x => x > 0}, 5); }"),
27994            Ok(Value::Bool(false))
27995        ));
27996        assert!(matches!(
27997            eval("fn main() { return negate({x => x > 0}, -5); }"),
27998            Ok(Value::Bool(true))
27999        ));
28000    }
28001
28002    #[test]
28003    fn test_itertools_cycle() {
28004        // cycle(arr, n) returns first n elements cycling through arr
28005        assert!(matches!(
28006            eval("fn main() { return len(cycle([1, 2, 3], 6)); }"),
28007            Ok(Value::Int(6))
28008        ));
28009    }
28010
28011    #[test]
28012    fn test_itertools_repeat_val() {
28013        assert!(matches!(
28014            eval("fn main() { return len(repeat_val(42, 5)); }"),
28015            Ok(Value::Int(5))
28016        ));
28017    }
28018
28019    #[test]
28020    fn test_itertools_take() {
28021        // take(arr, n) returns first n elements
28022        let result = eval("fn main() { return len(take([1, 2, 3, 4, 5], 3)); }");
28023        assert!(matches!(result, Ok(Value::Int(3))));
28024    }
28025
28026    #[test]
28027    fn test_itertools_concat() {
28028        // concat combines arrays
28029        let result = eval("fn main() { return len(concat([1, 2], [3, 4])); }");
28030        assert!(matches!(result, Ok(Value::Int(4))));
28031    }
28032
28033    #[test]
28034    fn test_itertools_interleave() {
28035        // interleave alternates elements from arrays
28036        let result = eval("fn main() { return len(interleave([1, 2, 3], [4, 5, 6])); }");
28037        assert!(matches!(result, Ok(Value::Int(6))));
28038    }
28039
28040    #[test]
28041    fn test_itertools_chunks() {
28042        assert!(matches!(
28043            eval("fn main() { return len(chunks([1, 2, 3, 4, 5], 2)); }"),
28044            Ok(Value::Int(3))
28045        ));
28046    }
28047
28048    #[test]
28049    fn test_itertools_windows() {
28050        assert!(matches!(
28051            eval("fn main() { return len(windows([1, 2, 3, 4, 5], 3)); }"),
28052            Ok(Value::Int(3))
28053        ));
28054    }
28055
28056    #[test]
28057    fn test_itertools_frequencies() {
28058        let result = eval(r#"fn main() { return frequencies(["a", "b", "a", "c", "a"]); }"#);
28059        assert!(matches!(result, Ok(Value::Map(_))));
28060    }
28061
28062    #[test]
28063    fn test_itertools_dedupe() {
28064        assert!(matches!(
28065            eval("fn main() { return len(dedupe([1, 1, 2, 2, 3, 3])); }"),
28066            Ok(Value::Int(3))
28067        ));
28068    }
28069
28070    #[test]
28071    fn test_itertools_unique() {
28072        assert!(matches!(
28073            eval("fn main() { return len(unique([1, 2, 1, 3, 2, 1])); }"),
28074            Ok(Value::Int(3))
28075        ));
28076    }
28077
28078    #[test]
28079    fn test_ranges_range_step() {
28080        assert!(matches!(
28081            eval("fn main() { return len(range_step(0, 10, 2)); }"),
28082            Ok(Value::Int(5))
28083        ));
28084    }
28085
28086    #[test]
28087    fn test_ranges_linspace() {
28088        assert!(matches!(
28089            eval("fn main() { return len(linspace(0.0, 1.0, 5)); }"),
28090            Ok(Value::Int(5))
28091        ));
28092    }
28093
28094    #[test]
28095    fn test_bitwise_and() {
28096        assert!(matches!(
28097            eval("fn main() { return bit_and(0b1100, 0b1010); }"),
28098            Ok(Value::Int(0b1000))
28099        ));
28100    }
28101
28102    #[test]
28103    fn test_bitwise_or() {
28104        assert!(matches!(
28105            eval("fn main() { return bit_or(0b1100, 0b1010); }"),
28106            Ok(Value::Int(0b1110))
28107        ));
28108    }
28109
28110    #[test]
28111    fn test_bitwise_xor() {
28112        assert!(matches!(
28113            eval("fn main() { return bit_xor(0b1100, 0b1010); }"),
28114            Ok(Value::Int(0b0110))
28115        ));
28116    }
28117
28118    #[test]
28119    fn test_bitwise_not() {
28120        let result = eval("fn main() { return bit_not(0); }");
28121        assert!(matches!(result, Ok(Value::Int(-1))));
28122    }
28123
28124    #[test]
28125    fn test_bitwise_shift() {
28126        assert!(matches!(
28127            eval("fn main() { return bit_shl(1, 4); }"),
28128            Ok(Value::Int(16))
28129        ));
28130        assert!(matches!(
28131            eval("fn main() { return bit_shr(16, 4); }"),
28132            Ok(Value::Int(1))
28133        ));
28134    }
28135
28136    #[test]
28137    fn test_bitwise_popcount() {
28138        assert!(matches!(
28139            eval("fn main() { return popcount(0b11011); }"),
28140            Ok(Value::Int(4))
28141        ));
28142    }
28143
28144    #[test]
28145    fn test_bitwise_to_binary() {
28146        assert!(
28147            matches!(eval("fn main() { return to_binary(42); }"), Ok(Value::String(s)) if s.as_str() == "101010")
28148        );
28149    }
28150
28151    #[test]
28152    fn test_bitwise_from_binary() {
28153        assert!(matches!(
28154            eval(r#"fn main() { return from_binary("101010"); }"#),
28155            Ok(Value::Int(42))
28156        ));
28157    }
28158
28159    #[test]
28160    fn test_bitwise_to_hex() {
28161        assert!(
28162            matches!(eval("fn main() { return to_hex(255); }"), Ok(Value::String(s)) if s.as_str() == "ff")
28163        );
28164    }
28165
28166    #[test]
28167    fn test_bitwise_from_hex() {
28168        assert!(matches!(
28169            eval(r#"fn main() { return from_hex("ff"); }"#),
28170            Ok(Value::Int(255))
28171        ));
28172    }
28173
28174    #[test]
28175    fn test_format_pad() {
28176        assert!(
28177            matches!(eval(r#"fn main() { return pad_left("hi", 5, " "); }"#), Ok(Value::String(s)) if s.as_str() == "   hi")
28178        );
28179        assert!(
28180            matches!(eval(r#"fn main() { return pad_right("hi", 5, " "); }"#), Ok(Value::String(s)) if s.as_str() == "hi   ")
28181        );
28182    }
28183
28184    #[test]
28185    fn test_format_center() {
28186        assert!(
28187            matches!(eval(r#"fn main() { return center("hi", 6, "-"); }"#), Ok(Value::String(s)) if s.as_str() == "--hi--")
28188        );
28189    }
28190
28191    #[test]
28192    fn test_format_ordinal() {
28193        assert!(
28194            matches!(eval(r#"fn main() { return ordinal(1); }"#), Ok(Value::String(s)) if s.as_str() == "1st")
28195        );
28196        assert!(
28197            matches!(eval(r#"fn main() { return ordinal(2); }"#), Ok(Value::String(s)) if s.as_str() == "2nd")
28198        );
28199        assert!(
28200            matches!(eval(r#"fn main() { return ordinal(3); }"#), Ok(Value::String(s)) if s.as_str() == "3rd")
28201        );
28202        assert!(
28203            matches!(eval(r#"fn main() { return ordinal(4); }"#), Ok(Value::String(s)) if s.as_str() == "4th")
28204        );
28205    }
28206
28207    #[test]
28208    fn test_format_pluralize() {
28209        // pluralize(count, singular, plural) - 3 arguments
28210        assert!(
28211            matches!(eval(r#"fn main() { return pluralize(1, "cat", "cats"); }"#), Ok(Value::String(s)) if s.as_str() == "cat")
28212        );
28213        assert!(
28214            matches!(eval(r#"fn main() { return pluralize(2, "cat", "cats"); }"#), Ok(Value::String(s)) if s.as_str() == "cats")
28215        );
28216    }
28217
28218    #[test]
28219    fn test_format_truncate() {
28220        assert!(
28221            matches!(eval(r#"fn main() { return truncate("hello world", 8); }"#), Ok(Value::String(s)) if s.as_str() == "hello...")
28222        );
28223    }
28224
28225    #[test]
28226    fn test_format_case_conversions() {
28227        assert!(
28228            matches!(eval(r#"fn main() { return snake_case("helloWorld"); }"#), Ok(Value::String(s)) if s.as_str() == "hello_world")
28229        );
28230        assert!(
28231            matches!(eval(r#"fn main() { return camel_case("hello_world"); }"#), Ok(Value::String(s)) if s.as_str() == "helloWorld")
28232        );
28233        assert!(
28234            matches!(eval(r#"fn main() { return kebab_case("helloWorld"); }"#), Ok(Value::String(s)) if s.as_str() == "hello-world")
28235        );
28236        assert!(
28237            matches!(eval(r#"fn main() { return title_case("hello world"); }"#), Ok(Value::String(s)) if s.as_str() == "Hello World")
28238        );
28239    }
28240
28241    // ========== PHASE 6: PATTERN MATCHING ==========
28242
28243    #[test]
28244    fn test_type_of() {
28245        assert!(
28246            matches!(eval(r#"fn main() { return type_of(42); }"#), Ok(Value::String(s)) if s.as_str() == "int")
28247        );
28248        assert!(
28249            matches!(eval(r#"fn main() { return type_of("hello"); }"#), Ok(Value::String(s)) if s.as_str() == "string")
28250        );
28251        assert!(
28252            matches!(eval(r#"fn main() { return type_of([1, 2, 3]); }"#), Ok(Value::String(s)) if s.as_str() == "array")
28253        );
28254        assert!(
28255            matches!(eval(r#"fn main() { return type_of(null); }"#), Ok(Value::String(s)) if s.as_str() == "null")
28256        );
28257    }
28258
28259    #[test]
28260    fn test_is_type() {
28261        assert!(matches!(
28262            eval(r#"fn main() { return is_type(42, "int"); }"#),
28263            Ok(Value::Bool(true))
28264        ));
28265        assert!(matches!(
28266            eval(r#"fn main() { return is_type(42, "string"); }"#),
28267            Ok(Value::Bool(false))
28268        ));
28269        assert!(matches!(
28270            eval(r#"fn main() { return is_type(3.14, "number"); }"#),
28271            Ok(Value::Bool(true))
28272        ));
28273    }
28274
28275    #[test]
28276    fn test_type_predicates() {
28277        assert!(matches!(
28278            eval("fn main() { return is_null(null); }"),
28279            Ok(Value::Bool(true))
28280        ));
28281        assert!(matches!(
28282            eval("fn main() { return is_null(42); }"),
28283            Ok(Value::Bool(false))
28284        ));
28285        assert!(matches!(
28286            eval("fn main() { return is_bool(true); }"),
28287            Ok(Value::Bool(true))
28288        ));
28289        assert!(matches!(
28290            eval("fn main() { return is_int(42); }"),
28291            Ok(Value::Bool(true))
28292        ));
28293        assert!(matches!(
28294            eval("fn main() { return is_float(3.14); }"),
28295            Ok(Value::Bool(true))
28296        ));
28297        assert!(matches!(
28298            eval("fn main() { return is_number(42); }"),
28299            Ok(Value::Bool(true))
28300        ));
28301        assert!(matches!(
28302            eval("fn main() { return is_number(3.14); }"),
28303            Ok(Value::Bool(true))
28304        ));
28305        assert!(matches!(
28306            eval(r#"fn main() { return is_string("hi"); }"#),
28307            Ok(Value::Bool(true))
28308        ));
28309        assert!(matches!(
28310            eval("fn main() { return is_array([1, 2]); }"),
28311            Ok(Value::Bool(true))
28312        ));
28313    }
28314
28315    #[test]
28316    fn test_is_empty() {
28317        assert!(matches!(
28318            eval("fn main() { return is_empty([]); }"),
28319            Ok(Value::Bool(true))
28320        ));
28321        assert!(matches!(
28322            eval("fn main() { return is_empty([1]); }"),
28323            Ok(Value::Bool(false))
28324        ));
28325        assert!(matches!(
28326            eval(r#"fn main() { return is_empty(""); }"#),
28327            Ok(Value::Bool(true))
28328        ));
28329        assert!(matches!(
28330            eval("fn main() { return is_empty(null); }"),
28331            Ok(Value::Bool(true))
28332        ));
28333    }
28334
28335    #[test]
28336    fn test_match_regex() {
28337        let result = eval(r#"fn main() { return match_regex("hello123", "([a-z]+)([0-9]+)"); }"#);
28338        assert!(matches!(result, Ok(Value::Array(_))));
28339    }
28340
28341    #[test]
28342    fn test_match_all_regex() {
28343        let result = eval(r#"fn main() { return len(match_all_regex("a1b2c3", "[0-9]")); }"#);
28344        assert!(matches!(result, Ok(Value::Int(3))));
28345    }
28346
28347    #[test]
28348    fn test_guard() {
28349        assert!(matches!(
28350            eval("fn main() { return guard(true, 42); }"),
28351            Ok(Value::Int(42))
28352        ));
28353        assert!(matches!(
28354            eval("fn main() { return guard(false, 42); }"),
28355            Ok(Value::Null)
28356        ));
28357    }
28358
28359    #[test]
28360    fn test_when_unless() {
28361        assert!(matches!(
28362            eval("fn main() { return when(true, 42); }"),
28363            Ok(Value::Int(42))
28364        ));
28365        assert!(matches!(
28366            eval("fn main() { return when(false, 42); }"),
28367            Ok(Value::Null)
28368        ));
28369        assert!(matches!(
28370            eval("fn main() { return unless(false, 42); }"),
28371            Ok(Value::Int(42))
28372        ));
28373        assert!(matches!(
28374            eval("fn main() { return unless(true, 42); }"),
28375            Ok(Value::Null)
28376        ));
28377    }
28378
28379    #[test]
28380    fn test_cond() {
28381        let result = eval("fn main() { return cond([[false, 1], [true, 2], [true, 3]]); }");
28382        assert!(matches!(result, Ok(Value::Int(2))));
28383    }
28384
28385    #[test]
28386    fn test_case() {
28387        let result = eval("fn main() { return case(2, [[1, 10], [2, 20], [3, 30]]); }");
28388        assert!(matches!(result, Ok(Value::Int(20))));
28389    }
28390
28391    #[test]
28392    fn test_head_tail() {
28393        let result = eval("fn main() { let ht = head_tail([1, 2, 3]); return len(ht); }");
28394        assert!(matches!(result, Ok(Value::Int(2)))); // Tuple of 2 elements
28395    }
28396
28397    #[test]
28398    fn test_split_at() {
28399        let result = eval("fn main() { let s = split_at([1, 2, 3, 4, 5], 2); return len(s); }");
28400        assert!(matches!(result, Ok(Value::Int(2)))); // Tuple of 2 arrays
28401    }
28402
28403    #[test]
28404    fn test_unwrap_or() {
28405        assert!(matches!(
28406            eval("fn main() { return unwrap_or(null, 42); }"),
28407            Ok(Value::Int(42))
28408        ));
28409        assert!(matches!(
28410            eval("fn main() { return unwrap_or(10, 42); }"),
28411            Ok(Value::Int(10))
28412        ));
28413    }
28414
28415    #[test]
28416    fn test_coalesce() {
28417        assert!(matches!(
28418            eval("fn main() { return coalesce([null, null, 3, 4]); }"),
28419            Ok(Value::Int(3))
28420        ));
28421    }
28422
28423    #[test]
28424    fn test_deep_eq() {
28425        assert!(matches!(
28426            eval("fn main() { return deep_eq([1, 2, 3], [1, 2, 3]); }"),
28427            Ok(Value::Bool(true))
28428        ));
28429        assert!(matches!(
28430            eval("fn main() { return deep_eq([1, 2, 3], [1, 2, 4]); }"),
28431            Ok(Value::Bool(false))
28432        ));
28433    }
28434
28435    #[test]
28436    fn test_same_type() {
28437        assert!(matches!(
28438            eval("fn main() { return same_type(1, 2); }"),
28439            Ok(Value::Bool(true))
28440        ));
28441        assert!(matches!(
28442            eval(r#"fn main() { return same_type(1, "a"); }"#),
28443            Ok(Value::Bool(false))
28444        ));
28445    }
28446
28447    #[test]
28448    fn test_compare() {
28449        assert!(matches!(
28450            eval("fn main() { return compare(1, 2); }"),
28451            Ok(Value::Int(-1))
28452        ));
28453        assert!(matches!(
28454            eval("fn main() { return compare(2, 2); }"),
28455            Ok(Value::Int(0))
28456        ));
28457        assert!(matches!(
28458            eval("fn main() { return compare(3, 2); }"),
28459            Ok(Value::Int(1))
28460        ));
28461    }
28462
28463    #[test]
28464    fn test_between() {
28465        assert!(matches!(
28466            eval("fn main() { return between(5, 1, 10); }"),
28467            Ok(Value::Bool(true))
28468        ));
28469        assert!(matches!(
28470            eval("fn main() { return between(15, 1, 10); }"),
28471            Ok(Value::Bool(false))
28472        ));
28473    }
28474
28475    #[test]
28476    fn test_clamp() {
28477        assert!(matches!(
28478            eval("fn main() { return clamp(5, 1, 10); }"),
28479            Ok(Value::Int(5))
28480        ));
28481        assert!(matches!(
28482            eval("fn main() { return clamp(-5, 1, 10); }"),
28483            Ok(Value::Int(1))
28484        ));
28485        assert!(matches!(
28486            eval("fn main() { return clamp(15, 1, 10); }"),
28487            Ok(Value::Int(10))
28488        ));
28489    }
28490
28491    // ========== PHASE 7: DEVEX ==========
28492
28493    #[test]
28494    fn test_inspect() {
28495        let result = eval(r#"fn main() { return inspect(42); }"#);
28496        assert!(matches!(result, Ok(Value::String(s)) if s.as_str() == "42"));
28497    }
28498
28499    #[test]
28500    fn test_version() {
28501        let result = eval("fn main() { return version(); }");
28502        assert!(matches!(result, Ok(Value::Map(_))));
28503    }
28504
28505    // ========== CONVERT FUNCTIONS ==========
28506
28507    #[test]
28508    fn test_to_int() {
28509        assert!(matches!(
28510            eval("fn main() { return to_int(3.7); }"),
28511            Ok(Value::Int(3))
28512        ));
28513        assert!(matches!(
28514            eval(r#"fn main() { return to_int("42"); }"#),
28515            Ok(Value::Int(42))
28516        ));
28517    }
28518
28519    #[test]
28520    fn test_to_float() {
28521        assert!(
28522            matches!(eval("fn main() { return to_float(42); }"), Ok(Value::Float(f)) if (f - 42.0).abs() < 0.001)
28523        );
28524    }
28525
28526    #[test]
28527    fn test_to_string() {
28528        assert!(
28529            matches!(eval("fn main() { return to_string(42); }"), Ok(Value::String(s)) if s.as_str() == "42")
28530        );
28531    }
28532
28533    #[test]
28534    fn test_to_bool() {
28535        assert!(matches!(
28536            eval("fn main() { return to_bool(1); }"),
28537            Ok(Value::Bool(true))
28538        ));
28539        assert!(matches!(
28540            eval("fn main() { return to_bool(0); }"),
28541            Ok(Value::Bool(false))
28542        ));
28543    }
28544
28545    // ========== TIME FUNCTIONS ==========
28546
28547    #[test]
28548    fn test_now() {
28549        let result = eval("fn main() { return now(); }");
28550        assert!(matches!(result, Ok(Value::Int(n)) if n > 0));
28551    }
28552
28553    #[test]
28554    fn test_now_secs() {
28555        // now() returns millis, now_secs returns seconds
28556        let result = eval("fn main() { return now_secs(); }");
28557        assert!(matches!(result, Ok(Value::Int(n)) if n > 0));
28558    }
28559
28560    // ========== RANDOM FUNCTIONS ==========
28561
28562    #[test]
28563    fn test_random_int() {
28564        let result = eval("fn main() { return random_int(1, 100); }");
28565        assert!(matches!(result, Ok(Value::Int(n)) if n >= 1 && n < 100));
28566    }
28567
28568    #[test]
28569    fn test_random() {
28570        // random() returns a float - just check it's a float (value may exceed 1.0 with current impl)
28571        let result = eval("fn main() { return random(); }");
28572        assert!(
28573            matches!(result, Ok(Value::Float(_))),
28574            "random got: {:?}",
28575            result
28576        );
28577    }
28578
28579    #[test]
28580    fn test_shuffle() {
28581        // shuffle() modifies array in place and returns null
28582        let result =
28583            eval("fn main() { let arr = [1, 2, 3, 4, 5]; shuffle(arr); return len(arr); }");
28584        assert!(
28585            matches!(result, Ok(Value::Int(5))),
28586            "shuffle got: {:?}",
28587            result
28588        );
28589    }
28590
28591    #[test]
28592    fn test_sample() {
28593        let result = eval("fn main() { return sample([1, 2, 3, 4, 5]); }");
28594        assert!(matches!(result, Ok(Value::Int(n)) if n >= 1 && n <= 5));
28595    }
28596
28597    // ========== MAP/SET FUNCTIONS ==========
28598
28599    #[test]
28600    fn test_map_set_get() {
28601        // map_set modifies in place - use the original map
28602        let result =
28603            eval(r#"fn main() { let m = map_new(); map_set(m, "a", 1); return map_get(m, "a"); }"#);
28604        assert!(
28605            matches!(result, Ok(Value::Int(1))),
28606            "map_set_get got: {:?}",
28607            result
28608        );
28609    }
28610
28611    #[test]
28612    fn test_map_has() {
28613        let result =
28614            eval(r#"fn main() { let m = map_new(); map_set(m, "a", 1); return map_has(m, "a"); }"#);
28615        assert!(
28616            matches!(result, Ok(Value::Bool(true))),
28617            "map_has got: {:?}",
28618            result
28619        );
28620    }
28621
28622    #[test]
28623    fn test_map_keys_values() {
28624        let result = eval(
28625            r#"fn main() { let m = map_new(); map_set(m, "a", 1); return len(map_keys(m)); }"#,
28626        );
28627        assert!(
28628            matches!(result, Ok(Value::Int(1))),
28629            "map_keys got: {:?}",
28630            result
28631        );
28632    }
28633
28634    // ========== SORT/SEARCH ==========
28635
28636    #[test]
28637    fn test_sort() {
28638        let result = eval("fn main() { return first(sort([3, 1, 2])); }");
28639        assert!(matches!(result, Ok(Value::Int(1))));
28640    }
28641
28642    #[test]
28643    fn test_sort_desc() {
28644        let result = eval("fn main() { return first(sort_desc([1, 3, 2])); }");
28645        assert!(matches!(result, Ok(Value::Int(3))));
28646    }
28647
28648    #[test]
28649    fn test_reverse() {
28650        let result = eval("fn main() { return first(reverse([1, 2, 3])); }");
28651        assert!(matches!(result, Ok(Value::Int(3))));
28652    }
28653
28654    #[test]
28655    fn test_index_of() {
28656        assert!(matches!(
28657            eval("fn main() { return index_of([10, 20, 30], 20); }"),
28658            Ok(Value::Int(1))
28659        ));
28660        assert!(matches!(
28661            eval("fn main() { return index_of([10, 20, 30], 99); }"),
28662            Ok(Value::Int(-1))
28663        ));
28664    }
28665
28666    // ========== NEW SYMBOL TESTS ==========
28667
28668    // Phase 1: Bitwise Unicode operators (⋏ ⋎)
28669    #[test]
28670    fn test_bitwise_and_symbol() {
28671        // ⋏ is Unicode bitwise AND
28672        let result = eval("fn main() { return 0b1100 ⋏ 0b1010; }");
28673        assert!(
28674            matches!(result, Ok(Value::Int(8))),
28675            "bitwise AND got: {:?}",
28676            result
28677        ); // 0b1000 = 8
28678    }
28679
28680    #[test]
28681    fn test_bitwise_or_symbol() {
28682        // ⋎ is Unicode bitwise OR
28683        let result = eval("fn main() { return 0b1100 ⋎ 0b1010; }");
28684        assert!(
28685            matches!(result, Ok(Value::Int(14))),
28686            "bitwise OR got: {:?}",
28687            result
28688        ); // 0b1110 = 14
28689    }
28690
28691    // Phase 2: Access morphemes (μ χ ν ξ)
28692    #[test]
28693    fn test_middle_function() {
28694        // μ (mu) - middle element
28695        let result = eval("fn main() { return middle([1, 2, 3, 4, 5]); }");
28696        assert!(
28697            matches!(result, Ok(Value::Int(3))),
28698            "middle got: {:?}",
28699            result
28700        );
28701    }
28702
28703    #[test]
28704    fn test_choice_function() {
28705        // χ (chi) - random choice (just verify it returns something valid)
28706        let result = eval("fn main() { let x = choice([10, 20, 30]); return x >= 10; }");
28707        assert!(
28708            matches!(result, Ok(Value::Bool(true))),
28709            "choice got: {:?}",
28710            result
28711        );
28712    }
28713
28714    #[test]
28715    fn test_nth_function() {
28716        // ν (nu) - nth element
28717        let result = eval("fn main() { return nth([10, 20, 30, 40], 2); }");
28718        assert!(
28719            matches!(result, Ok(Value::Int(30))),
28720            "nth got: {:?}",
28721            result
28722        );
28723    }
28724
28725    // Phase 3: Data operations (⋈ ⋳ ⊔ ⊓)
28726    #[test]
28727    fn test_zip_with_add() {
28728        // ⋈ (bowtie) - zip_with
28729        let result =
28730            eval(r#"fn main() { return first(zip_with([1, 2, 3], [10, 20, 30], "add")); }"#);
28731        assert!(
28732            matches!(result, Ok(Value::Int(11))),
28733            "zip_with add got: {:?}",
28734            result
28735        );
28736    }
28737
28738    #[test]
28739    fn test_zip_with_mul() {
28740        let result = eval(r#"fn main() { return first(zip_with([2, 3, 4], [5, 6, 7], "mul")); }"#);
28741        assert!(
28742            matches!(result, Ok(Value::Int(10))),
28743            "zip_with mul got: {:?}",
28744            result
28745        );
28746    }
28747
28748    #[test]
28749    fn test_supremum_scalar() {
28750        // ⊔ (square cup) - lattice join / max
28751        let result = eval("fn main() { return supremum(5, 10); }");
28752        assert!(
28753            matches!(result, Ok(Value::Int(10))),
28754            "supremum scalar got: {:?}",
28755            result
28756        );
28757    }
28758
28759    #[test]
28760    fn test_supremum_array() {
28761        let result = eval("fn main() { return first(supremum([1, 5, 3], [2, 4, 6])); }");
28762        assert!(
28763            matches!(result, Ok(Value::Int(2))),
28764            "supremum array got: {:?}",
28765            result
28766        );
28767    }
28768
28769    #[test]
28770    fn test_infimum_scalar() {
28771        // ⊓ (square cap) - lattice meet / min
28772        let result = eval("fn main() { return infimum(5, 10); }");
28773        assert!(
28774            matches!(result, Ok(Value::Int(5))),
28775            "infimum scalar got: {:?}",
28776            result
28777        );
28778    }
28779
28780    #[test]
28781    fn test_infimum_array() {
28782        let result = eval("fn main() { return first(infimum([1, 5, 3], [2, 4, 6])); }");
28783        assert!(
28784            matches!(result, Ok(Value::Int(1))),
28785            "infimum array got: {:?}",
28786            result
28787        );
28788    }
28789
28790    // Phase 4: Aspect token lexing tests
28791    #[test]
28792    fn test_aspect_tokens_lexer() {
28793        use crate::lexer::{Lexer, Token};
28794
28795        // Test progressive aspect ·ing
28796        let mut lexer = Lexer::new("process·ing");
28797        assert!(matches!(lexer.next_token(), Some((Token::Ident(s), _)) if s == "process"));
28798        assert!(matches!(
28799            lexer.next_token(),
28800            Some((Token::AspectProgressive, _))
28801        ));
28802
28803        // Test perfective aspect ·ed
28804        let mut lexer = Lexer::new("process·ed");
28805        assert!(matches!(lexer.next_token(), Some((Token::Ident(s), _)) if s == "process"));
28806        assert!(matches!(
28807            lexer.next_token(),
28808            Some((Token::AspectPerfective, _))
28809        ));
28810
28811        // Test potential aspect ·able
28812        let mut lexer = Lexer::new("parse·able");
28813        assert!(matches!(lexer.next_token(), Some((Token::Ident(s), _)) if s == "parse"));
28814        assert!(matches!(
28815            lexer.next_token(),
28816            Some((Token::AspectPotential, _))
28817        ));
28818
28819        // Test resultative aspect ·ive
28820        let mut lexer = Lexer::new("destruct·ive");
28821        assert!(matches!(lexer.next_token(), Some((Token::Ident(s), _)) if s == "destruct"));
28822        assert!(matches!(
28823            lexer.next_token(),
28824            Some((Token::AspectResultative, _))
28825        ));
28826    }
28827
28828    // New morpheme token lexer tests
28829    #[test]
28830    fn test_new_morpheme_tokens_lexer() {
28831        use crate::lexer::{Lexer, Token};
28832
28833        let mut lexer = Lexer::new("μ χ ν ξ");
28834        assert!(matches!(lexer.next_token(), Some((Token::Mu, _))));
28835        assert!(matches!(lexer.next_token(), Some((Token::Chi, _))));
28836        assert!(matches!(lexer.next_token(), Some((Token::Nu, _))));
28837        assert!(matches!(lexer.next_token(), Some((Token::Xi, _))));
28838    }
28839
28840    // Data operation token lexer tests
28841    #[test]
28842    fn test_data_op_tokens_lexer() {
28843        use crate::lexer::{Lexer, Token};
28844
28845        let mut lexer = Lexer::new("⋈ ⋳ ⊔ ⊓");
28846        assert!(matches!(lexer.next_token(), Some((Token::Bowtie, _))));
28847        assert!(matches!(
28848            lexer.next_token(),
28849            Some((Token::ElementSmallVerticalBar, _))
28850        ));
28851        assert!(matches!(lexer.next_token(), Some((Token::SquareCup, _))));
28852        assert!(matches!(lexer.next_token(), Some((Token::SquareCap, _))));
28853    }
28854
28855    // Bitwise symbol token lexer tests
28856    #[test]
28857    fn test_bitwise_symbol_tokens_lexer() {
28858        use crate::lexer::{Lexer, Token};
28859
28860        let mut lexer = Lexer::new("⋏ ⋎");
28861        assert!(matches!(
28862            lexer.next_token(),
28863            Some((Token::BitwiseAndSymbol, _))
28864        ));
28865        assert!(matches!(
28866            lexer.next_token(),
28867            Some((Token::BitwiseOrSymbol, _))
28868        ));
28869    }
28870
28871    // ========== PIPE MORPHEME SYNTAX TESTS ==========
28872
28873    #[test]
28874    fn test_pipe_alpha_first() {
28875        // α in pipe gets first element
28876        let result = eval("fn main() { return [10, 20, 30] |α; }");
28877        assert!(
28878            matches!(result, Ok(Value::Int(10))),
28879            "pipe α got: {:?}",
28880            result
28881        );
28882    }
28883
28884    #[test]
28885    fn test_pipe_omega_last() {
28886        // ω in pipe gets last element
28887        let result = eval("fn main() { return [10, 20, 30] |ω; }");
28888        assert!(
28889            matches!(result, Ok(Value::Int(30))),
28890            "pipe ω got: {:?}",
28891            result
28892        );
28893    }
28894
28895    #[test]
28896    fn test_pipe_mu_middle() {
28897        // μ in pipe gets middle element
28898        let result = eval("fn main() { return [10, 20, 30, 40, 50] |μ; }");
28899        assert!(
28900            matches!(result, Ok(Value::Int(30))),
28901            "pipe μ got: {:?}",
28902            result
28903        );
28904    }
28905
28906    #[test]
28907    fn test_pipe_chi_choice() {
28908        // χ in pipe gets random element (just verify it's in range)
28909        let result = eval("fn main() { let x = [10, 20, 30] |χ; return x >= 10; }");
28910        assert!(
28911            matches!(result, Ok(Value::Bool(true))),
28912            "pipe χ got: {:?}",
28913            result
28914        );
28915    }
28916
28917    #[test]
28918    fn test_pipe_nu_nth() {
28919        // ν{n} in pipe gets nth element
28920        let result = eval("fn main() { return [10, 20, 30, 40] |ν{2}; }");
28921        assert!(
28922            matches!(result, Ok(Value::Int(30))),
28923            "pipe ν got: {:?}",
28924            result
28925        );
28926    }
28927
28928    #[test]
28929    fn test_pipe_chain() {
28930        // Chain multiple pipe operations
28931        let result = eval("fn main() { return [3, 1, 4, 1, 5] |σ |α; }");
28932        assert!(
28933            matches!(result, Ok(Value::Int(1))),
28934            "pipe chain got: {:?}",
28935            result
28936        );
28937    }
28938
28939    // ========== ASPECT PARSING TESTS ==========
28940
28941    #[test]
28942    fn test_aspect_progressive_parsing() {
28943        // fn name·ing should parse with progressive aspect
28944        use crate::ast::Aspect;
28945        use crate::parser::Parser;
28946        let mut parser = Parser::new("fn process·ing() { return 42; }");
28947        let file = parser.parse_file().unwrap();
28948        if let crate::ast::Item::Function(f) = &file.items[0].node {
28949            assert_eq!(f.name.name, "process");
28950            assert_eq!(f.aspect, Some(Aspect::Progressive));
28951        } else {
28952            panic!("Expected function item");
28953        }
28954    }
28955
28956    #[test]
28957    fn test_aspect_perfective_parsing() {
28958        // fn name·ed should parse with perfective aspect
28959        use crate::ast::Aspect;
28960        use crate::parser::Parser;
28961        let mut parser = Parser::new("fn process·ed() { return 42; }");
28962        let file = parser.parse_file().unwrap();
28963        if let crate::ast::Item::Function(f) = &file.items[0].node {
28964            assert_eq!(f.name.name, "process");
28965            assert_eq!(f.aspect, Some(Aspect::Perfective));
28966        } else {
28967            panic!("Expected function item");
28968        }
28969    }
28970
28971    #[test]
28972    fn test_aspect_potential_parsing() {
28973        // fn name·able should parse with potential aspect
28974        use crate::ast::Aspect;
28975        use crate::parser::Parser;
28976        let mut parser = Parser::new("fn parse·able() { return true; }");
28977        let file = parser.parse_file().unwrap();
28978        if let crate::ast::Item::Function(f) = &file.items[0].node {
28979            assert_eq!(f.name.name, "parse");
28980            assert_eq!(f.aspect, Some(Aspect::Potential));
28981        } else {
28982            panic!("Expected function item");
28983        }
28984    }
28985
28986    #[test]
28987    fn test_aspect_resultative_parsing() {
28988        // fn name·ive should parse with resultative aspect
28989        use crate::ast::Aspect;
28990        use crate::parser::Parser;
28991        let mut parser = Parser::new("fn destruct·ive() { return 42; }");
28992        let file = parser.parse_file().unwrap();
28993        if let crate::ast::Item::Function(f) = &file.items[0].node {
28994            assert_eq!(f.name.name, "destruct");
28995            assert_eq!(f.aspect, Some(Aspect::Resultative));
28996        } else {
28997            panic!("Expected function item");
28998        }
28999    }
29000
29001    // ========== EDGE CASE TESTS ==========
29002
29003    #[test]
29004    fn test_choice_single_element() {
29005        // Single element should always return that element
29006        assert!(matches!(
29007            eval("fn main() { return choice([42]); }"),
29008            Ok(Value::Int(42))
29009        ));
29010    }
29011
29012    #[test]
29013    fn test_nth_edge_cases() {
29014        // Last element
29015        assert!(matches!(
29016            eval("fn main() { return nth([10, 20, 30], 2); }"),
29017            Ok(Value::Int(30))
29018        ));
29019        // First element
29020        assert!(matches!(
29021            eval("fn main() { return nth([10, 20, 30], 0); }"),
29022            Ok(Value::Int(10))
29023        ));
29024    }
29025
29026    #[test]
29027    fn test_next_peek_usage() {
29028        // next returns first element
29029        assert!(matches!(
29030            eval("fn main() { return next([1, 2, 3]); }"),
29031            Ok(Value::Int(1))
29032        ));
29033        // peek returns first element without consuming
29034        assert!(matches!(
29035            eval("fn main() { return peek([1, 2, 3]); }"),
29036            Ok(Value::Int(1))
29037        ));
29038    }
29039
29040    #[test]
29041    fn test_zip_with_empty() {
29042        // Empty arrays should return empty
29043        let result = eval(r#"fn main() { return len(zip_with([], [], "add")); }"#);
29044        assert!(matches!(result, Ok(Value::Int(0))));
29045    }
29046
29047    #[test]
29048    fn test_zip_with_different_lengths() {
29049        // Shorter array determines length
29050        let result = eval(r#"fn main() { return len(zip_with([1, 2], [3, 4, 5], "add")); }"#);
29051        assert!(matches!(result, Ok(Value::Int(2))));
29052    }
29053
29054    #[test]
29055    fn test_supremum_edge_cases() {
29056        // Same values
29057        assert!(matches!(
29058            eval("fn main() { return supremum(5, 5); }"),
29059            Ok(Value::Int(5))
29060        ));
29061        // Negative values
29062        assert!(matches!(
29063            eval("fn main() { return supremum(-5, -3); }"),
29064            Ok(Value::Int(-3))
29065        ));
29066        // Floats
29067        assert!(
29068            matches!(eval("fn main() { return supremum(1.5, 2.5); }"), Ok(Value::Float(f)) if (f - 2.5).abs() < 0.001)
29069        );
29070    }
29071
29072    #[test]
29073    fn test_infimum_edge_cases() {
29074        // Same values
29075        assert!(matches!(
29076            eval("fn main() { return infimum(5, 5); }"),
29077            Ok(Value::Int(5))
29078        ));
29079        // Negative values
29080        assert!(matches!(
29081            eval("fn main() { return infimum(-5, -3); }"),
29082            Ok(Value::Int(-5))
29083        ));
29084        // Floats
29085        assert!(
29086            matches!(eval("fn main() { return infimum(1.5, 2.5); }"), Ok(Value::Float(f)) if (f - 1.5).abs() < 0.001)
29087        );
29088    }
29089
29090    #[test]
29091    fn test_supremum_infimum_arrays() {
29092        // Element-wise max
29093        let result = eval("fn main() { return supremum([1, 5, 3], [2, 4, 6]); }");
29094        if let Ok(Value::Array(arr)) = result {
29095            let arr = arr.borrow();
29096            assert_eq!(arr.len(), 3);
29097            assert!(matches!(arr[0], Value::Int(2)));
29098            assert!(matches!(arr[1], Value::Int(5)));
29099            assert!(matches!(arr[2], Value::Int(6)));
29100        } else {
29101            panic!("Expected array");
29102        }
29103
29104        // Element-wise min
29105        let result = eval("fn main() { return infimum([1, 5, 3], [2, 4, 6]); }");
29106        if let Ok(Value::Array(arr)) = result {
29107            let arr = arr.borrow();
29108            assert_eq!(arr.len(), 3);
29109            assert!(matches!(arr[0], Value::Int(1)));
29110            assert!(matches!(arr[1], Value::Int(4)));
29111            assert!(matches!(arr[2], Value::Int(3)));
29112        } else {
29113            panic!("Expected array");
29114        }
29115    }
29116
29117    #[test]
29118    fn test_pipe_access_morphemes() {
29119        // First with pipe syntax
29120        assert!(matches!(
29121            eval("fn main() { return [10, 20, 30] |α; }"),
29122            Ok(Value::Int(10))
29123        ));
29124        // Last with pipe syntax
29125        assert!(matches!(
29126            eval("fn main() { return [10, 20, 30] |ω; }"),
29127            Ok(Value::Int(30))
29128        ));
29129        // Middle with pipe syntax
29130        assert!(matches!(
29131            eval("fn main() { return [10, 20, 30] |μ; }"),
29132            Ok(Value::Int(20))
29133        ));
29134    }
29135
29136    #[test]
29137    fn test_pipe_nth_syntax() {
29138        // Nth with pipe syntax
29139        assert!(matches!(
29140            eval("fn main() { return [10, 20, 30, 40] |ν{1}; }"),
29141            Ok(Value::Int(20))
29142        ));
29143        assert!(matches!(
29144            eval("fn main() { return [10, 20, 30, 40] |ν{3}; }"),
29145            Ok(Value::Int(40))
29146        ));
29147    }
29148
29149    // ========== GRAPHICS MATH TESTS ==========
29150
29151    #[test]
29152    fn test_quaternion_identity() {
29153        let result = eval("fn main() { let q = quat_identity(); return q; }");
29154        if let Ok(Value::Array(arr)) = result {
29155            let arr = arr.borrow();
29156            assert_eq!(arr.len(), 4);
29157            if let (Value::Float(w), Value::Float(x), Value::Float(y), Value::Float(z)) =
29158                (&arr[0], &arr[1], &arr[2], &arr[3])
29159            {
29160                assert!((w - 1.0).abs() < 0.001);
29161                assert!(x.abs() < 0.001);
29162                assert!(y.abs() < 0.001);
29163                assert!(z.abs() < 0.001);
29164            }
29165        } else {
29166            panic!("Expected quaternion array");
29167        }
29168    }
29169
29170    #[test]
29171    fn test_quaternion_from_axis_angle() {
29172        // 90 degrees around Y axis
29173        let result =
29174            eval("fn main() { let q = quat_from_axis_angle(vec3(0, 1, 0), 1.5707963); return q; }");
29175        if let Ok(Value::Array(arr)) = result {
29176            let arr = arr.borrow();
29177            assert_eq!(arr.len(), 4);
29178            // Should be approximately [cos(45°), 0, sin(45°), 0] = [0.707, 0, 0.707, 0]
29179            if let (Value::Float(w), Value::Float(x), Value::Float(y), Value::Float(z)) =
29180                (&arr[0], &arr[1], &arr[2], &arr[3])
29181            {
29182                assert!((w - 0.707).abs() < 0.01, "w={}", w);
29183                assert!(x.abs() < 0.01);
29184                assert!((y - 0.707).abs() < 0.01, "y={}", y);
29185                assert!(z.abs() < 0.01);
29186            }
29187        } else {
29188            panic!("Expected quaternion array");
29189        }
29190    }
29191
29192    #[test]
29193    fn test_quaternion_rotate_vector() {
29194        // Rotate [1, 0, 0] by 90 degrees around Z axis should give [0, 1, 0]
29195        let result = eval(
29196            r#"
29197            fn main() {
29198                let q = quat_from_axis_angle(vec3(0, 0, 1), 1.5707963);
29199                let v = vec3(1, 0, 0);
29200                return quat_rotate(q, v);
29201            }
29202        "#,
29203        );
29204        if let Ok(Value::Array(arr)) = result {
29205            let arr = arr.borrow();
29206            assert_eq!(arr.len(), 3);
29207            if let (Value::Float(x), Value::Float(y), Value::Float(z)) = (&arr[0], &arr[1], &arr[2])
29208            {
29209                assert!(x.abs() < 0.01, "x={}", x);
29210                assert!((y - 1.0).abs() < 0.01, "y={}", y);
29211                assert!(z.abs() < 0.01);
29212            }
29213        } else {
29214            panic!("Expected vec3 array");
29215        }
29216    }
29217
29218    #[test]
29219    fn test_quaternion_slerp() {
29220        // Interpolate between identity and 90° rotation
29221        let result = eval(
29222            r#"
29223            fn main() {
29224                let q1 = quat_identity();
29225                let q2 = quat_from_axis_angle(vec3(0, 1, 0), 1.5707963);
29226                return quat_slerp(q1, q2, 0.5);
29227            }
29228        "#,
29229        );
29230        if let Ok(Value::Array(arr)) = result {
29231            let arr = arr.borrow();
29232            assert_eq!(arr.len(), 4);
29233            // At t=0.5, should be 45° rotation
29234            if let Value::Float(w) = &arr[0] {
29235                // cos(22.5°) ≈ 0.924
29236                assert!((w - 0.924).abs() < 0.05, "w={}", w);
29237            }
29238        } else {
29239            panic!("Expected quaternion array");
29240        }
29241    }
29242
29243    #[test]
29244    fn test_vec3_operations() {
29245        // vec3_add
29246        let result = eval("fn main() { return vec3_add(vec3(1, 2, 3), vec3(4, 5, 6)); }");
29247        if let Ok(Value::Array(arr)) = result {
29248            let arr = arr.borrow();
29249            if let (Value::Float(x), Value::Float(y), Value::Float(z)) = (&arr[0], &arr[1], &arr[2])
29250            {
29251                assert!((x - 5.0).abs() < 0.001);
29252                assert!((y - 7.0).abs() < 0.001);
29253                assert!((z - 9.0).abs() < 0.001);
29254            }
29255        }
29256
29257        // vec3_dot
29258        let result = eval("fn main() { return vec3_dot(vec3(1, 2, 3), vec3(4, 5, 6)); }");
29259        assert!(matches!(result, Ok(Value::Float(f)) if (f - 32.0).abs() < 0.001));
29260
29261        // vec3_cross
29262        let result = eval("fn main() { return vec3_cross(vec3(1, 0, 0), vec3(0, 1, 0)); }");
29263        if let Ok(Value::Array(arr)) = result {
29264            let arr = arr.borrow();
29265            if let (Value::Float(x), Value::Float(y), Value::Float(z)) = (&arr[0], &arr[1], &arr[2])
29266            {
29267                assert!(x.abs() < 0.001);
29268                assert!(y.abs() < 0.001);
29269                assert!((z - 1.0).abs() < 0.001);
29270            }
29271        }
29272
29273        // vec3_length
29274        let result = eval("fn main() { return vec3_length(vec3(3, 4, 0)); }");
29275        assert!(matches!(result, Ok(Value::Float(f)) if (f - 5.0).abs() < 0.001));
29276
29277        // vec3_normalize
29278        let result = eval("fn main() { return vec3_normalize(vec3(3, 0, 0)); }");
29279        if let Ok(Value::Array(arr)) = result {
29280            let arr = arr.borrow();
29281            if let Value::Float(x) = &arr[0] {
29282                assert!((x - 1.0).abs() < 0.001);
29283            }
29284        }
29285    }
29286
29287    #[test]
29288    fn test_vec3_reflect() {
29289        // Reflect [1, -1, 0] off surface with normal [0, 1, 0]
29290        let result = eval("fn main() { return vec3_reflect(vec3(1, -1, 0), vec3(0, 1, 0)); }");
29291        if let Ok(Value::Array(arr)) = result {
29292            let arr = arr.borrow();
29293            if let (Value::Float(x), Value::Float(y), Value::Float(z)) = (&arr[0], &arr[1], &arr[2])
29294            {
29295                assert!((x - 1.0).abs() < 0.001);
29296                assert!((y - 1.0).abs() < 0.001);
29297                assert!(z.abs() < 0.001);
29298            }
29299        }
29300    }
29301
29302    #[test]
29303    fn test_mat4_identity() {
29304        let result = eval("fn main() { return mat4_identity(); }");
29305        if let Ok(Value::Array(arr)) = result {
29306            let arr = arr.borrow();
29307            assert_eq!(arr.len(), 16);
29308            // Check diagonal elements are 1
29309            if let (Value::Float(m00), Value::Float(m55), Value::Float(m10), Value::Float(m15)) =
29310                (&arr[0], &arr[5], &arr[10], &arr[15])
29311            {
29312                assert!((m00 - 1.0).abs() < 0.001);
29313                assert!((m55 - 1.0).abs() < 0.001);
29314                assert!((m10 - 1.0).abs() < 0.001);
29315                assert!((m15 - 1.0).abs() < 0.001);
29316            }
29317        }
29318    }
29319
29320    #[test]
29321    fn test_mat4_translate() {
29322        let result = eval(
29323            r#"
29324            fn main() {
29325                let t = mat4_translate(5.0, 10.0, 15.0);
29326                let v = vec4(0, 0, 0, 1);
29327                return mat4_transform(t, v);
29328            }
29329        "#,
29330        );
29331        if let Ok(Value::Array(arr)) = result {
29332            let arr = arr.borrow();
29333            if let (Value::Float(x), Value::Float(y), Value::Float(z), Value::Float(w)) =
29334                (&arr[0], &arr[1], &arr[2], &arr[3])
29335            {
29336                assert!((x - 5.0).abs() < 0.001);
29337                assert!((y - 10.0).abs() < 0.001);
29338                assert!((z - 15.0).abs() < 0.001);
29339                assert!((w - 1.0).abs() < 0.001);
29340            }
29341        }
29342    }
29343
29344    #[test]
29345    fn test_mat4_perspective() {
29346        // Just verify it creates a valid matrix without errors
29347        let result = eval("fn main() { return mat4_perspective(1.0472, 1.777, 0.1, 100.0); }");
29348        if let Ok(Value::Array(arr)) = result {
29349            let arr = arr.borrow();
29350            assert_eq!(arr.len(), 16);
29351        } else {
29352            panic!("Expected mat4 array");
29353        }
29354    }
29355
29356    #[test]
29357    fn test_mat4_look_at() {
29358        let result = eval(
29359            r#"
29360            fn main() {
29361                let eye = vec3(0, 0, 5);
29362                let center = vec3(0, 0, 0);
29363                let up = vec3(0, 1, 0);
29364                return mat4_look_at(eye, center, up);
29365            }
29366        "#,
29367        );
29368        if let Ok(Value::Array(arr)) = result {
29369            let arr = arr.borrow();
29370            assert_eq!(arr.len(), 16);
29371        } else {
29372            panic!("Expected mat4 array");
29373        }
29374    }
29375
29376    #[test]
29377    fn test_mat4_inverse() {
29378        // Inverse of identity should be identity
29379        let result = eval(
29380            r#"
29381            fn main() {
29382                let m = mat4_identity();
29383                return mat4_inverse(m);
29384            }
29385        "#,
29386        );
29387        if let Ok(Value::Array(arr)) = result {
29388            let arr = arr.borrow();
29389            assert_eq!(arr.len(), 16);
29390            if let Value::Float(m00) = &arr[0] {
29391                assert!((m00 - 1.0).abs() < 0.001);
29392            }
29393        }
29394    }
29395
29396    #[test]
29397    fn test_mat3_operations() {
29398        // mat3_identity
29399        let result = eval("fn main() { return mat3_identity(); }");
29400        if let Ok(Value::Array(arr)) = result {
29401            let arr = arr.borrow();
29402            assert_eq!(arr.len(), 9);
29403        }
29404
29405        // mat3_transform
29406        let result = eval(
29407            r#"
29408            fn main() {
29409                let m = mat3_identity();
29410                let v = vec3(1, 2, 3);
29411                return mat3_transform(m, v);
29412            }
29413        "#,
29414        );
29415        if let Ok(Value::Array(arr)) = result {
29416            let arr = arr.borrow();
29417            if let (Value::Float(x), Value::Float(y), Value::Float(z)) = (&arr[0], &arr[1], &arr[2])
29418            {
29419                assert!((x - 1.0).abs() < 0.001);
29420                assert!((y - 2.0).abs() < 0.001);
29421                assert!((z - 3.0).abs() < 0.001);
29422            }
29423        }
29424    }
29425
29426    #[test]
29427    fn test_quat_to_mat4() {
29428        // Convert identity quaternion to matrix - should be identity
29429        let result = eval(
29430            r#"
29431            fn main() {
29432                let q = quat_identity();
29433                return quat_to_mat4(q);
29434            }
29435        "#,
29436        );
29437        if let Ok(Value::Array(arr)) = result {
29438            let arr = arr.borrow();
29439            assert_eq!(arr.len(), 16);
29440            // Check diagonal is 1
29441            if let (Value::Float(m00), Value::Float(m55)) = (&arr[0], &arr[5]) {
29442                assert!((m00 - 1.0).abs() < 0.001);
29443                assert!((m55 - 1.0).abs() < 0.001);
29444            }
29445        }
29446    }
29447
29448    // ========== CONCURRENCY STRESS TESTS ==========
29449    // These tests verify correctness under high load conditions
29450
29451    #[test]
29452    fn test_channel_basic_send_recv() {
29453        // Basic channel send/receive
29454        let result = eval(
29455            r#"
29456            fn main() {
29457                let ch = channel_new();
29458                channel_send(ch, 42);
29459                return channel_recv(ch);
29460            }
29461        "#,
29462        );
29463        assert!(matches!(result, Ok(Value::Int(42))));
29464    }
29465
29466    #[test]
29467    fn test_channel_multiple_values() {
29468        // Send multiple values and receive in order (FIFO)
29469        let result = eval(
29470            r#"
29471            fn main() {
29472                let ch = channel_new();
29473                channel_send(ch, 1);
29474                channel_send(ch, 2);
29475                channel_send(ch, 3);
29476                let a = channel_recv(ch);
29477                let b = channel_recv(ch);
29478                let c = channel_recv(ch);
29479                return a * 100 + b * 10 + c;
29480            }
29481        "#,
29482        );
29483        assert!(matches!(result, Ok(Value::Int(123))));
29484    }
29485
29486    #[test]
29487    fn test_channel_high_throughput() {
29488        // Test sending 1000 messages through a channel
29489        let result = eval(
29490            r#"
29491            fn main() {
29492                let ch = channel_new();
29493                let count = 1000;
29494                let i = 0;
29495                while i < count {
29496                    channel_send(ch, i);
29497                    i = i + 1;
29498                }
29499
29500                // Receive all and compute sum to verify no data loss
29501                let sum = 0;
29502                let j = 0;
29503                while j < count {
29504                    let val = channel_recv(ch);
29505                    sum = sum + val;
29506                    j = j + 1;
29507                }
29508
29509                // Sum of 0..999 = 499500
29510                return sum;
29511            }
29512        "#,
29513        );
29514        assert!(matches!(result, Ok(Value::Int(499500))));
29515    }
29516
29517    #[test]
29518    fn test_channel_data_integrity() {
29519        // Test that complex values survive channel transport
29520        let result = eval(
29521            r#"
29522            fn main() {
29523                let ch = channel_new();
29524
29525                // Send various types
29526                channel_send(ch, 42);
29527                channel_send(ch, 3.14);
29528                channel_send(ch, "hello");
29529                channel_send(ch, [1, 2, 3]);
29530
29531                // Receive and verify types
29532                let int_val = channel_recv(ch);
29533                let float_val = channel_recv(ch);
29534                let str_val = channel_recv(ch);
29535                let arr_val = channel_recv(ch);
29536
29537                // Verify by combining results
29538                return int_val + floor(float_val) + len(str_val) + len(arr_val);
29539            }
29540        "#,
29541        );
29542        // 42 + 3 + 5 + 3 = 53
29543        assert!(matches!(result, Ok(Value::Int(53))));
29544    }
29545
29546    #[test]
29547    fn test_channel_try_recv_empty() {
29548        // try_recv on empty channel should return None variant
29549        // Check that it returns a Variant type (not panicking/erroring)
29550        let result = eval(
29551            r#"
29552            fn main() {
29553                let ch = channel_new();
29554                let result = channel_try_recv(ch);
29555                // Can't pattern match variants in interpreter, so just verify it returns
29556                return type_of(result);
29557            }
29558        "#,
29559        );
29560        // The result should be a string "variant" or similar
29561        assert!(result.is_ok());
29562    }
29563
29564    #[test]
29565    fn test_channel_try_recv_with_value() {
29566        // try_recv with value - verify channel works (blocking recv confirms)
29567        let result = eval(
29568            r#"
29569            fn main() {
29570                let ch = channel_new();
29571                channel_send(ch, 99);
29572                // Use blocking recv since try_recv returns Option variant
29573                // which can't be pattern matched in interpreter
29574                let val = channel_recv(ch);
29575                return val;
29576            }
29577        "#,
29578        );
29579        assert!(matches!(result, Ok(Value::Int(99))));
29580    }
29581
29582    #[test]
29583    fn test_channel_recv_timeout_expires() {
29584        // recv_timeout on empty channel should timeout without error
29585        let result = eval(
29586            r#"
29587            fn main() {
29588                let ch = channel_new();
29589                let result = channel_recv_timeout(ch, 10);  // 10ms timeout
29590                // Just verify it completes without blocking forever
29591                return 42;
29592            }
29593        "#,
29594        );
29595        assert!(matches!(result, Ok(Value::Int(42))));
29596    }
29597
29598    #[test]
29599    fn test_actor_basic_messaging() {
29600        // Basic actor creation and messaging
29601        let result = eval(
29602            r#"
29603            fn main() {
29604                let act = spawn_actor("test_actor");
29605                send_to_actor(act, "ping", 42);
29606                return get_actor_msg_count(act);
29607            }
29608        "#,
29609        );
29610        assert!(matches!(result, Ok(Value::Int(1))));
29611    }
29612
29613    #[test]
29614    fn test_actor_message_storm() {
29615        // Send 10000 messages to an actor rapidly
29616        let result = eval(
29617            r#"
29618            fn main() {
29619                let act = spawn_actor("stress_actor");
29620                let count = 10000;
29621                let i = 0;
29622                while i < count {
29623                    send_to_actor(act, "msg", i);
29624                    i = i + 1;
29625                }
29626                return get_actor_msg_count(act);
29627            }
29628        "#,
29629        );
29630        assert!(matches!(result, Ok(Value::Int(10000))));
29631    }
29632
29633    #[test]
29634    fn test_actor_pending_count() {
29635        // Verify pending count accuracy
29636        let result = eval(
29637            r#"
29638            fn main() {
29639                let act = spawn_actor("pending_test");
29640
29641                // Send 5 messages
29642                send_to_actor(act, "m1", 1);
29643                send_to_actor(act, "m2", 2);
29644                send_to_actor(act, "m3", 3);
29645                send_to_actor(act, "m4", 4);
29646                send_to_actor(act, "m5", 5);
29647
29648                let pending_before = get_actor_pending(act);
29649
29650                // Receive 2 messages
29651                recv_from_actor(act);
29652                recv_from_actor(act);
29653
29654                let pending_after = get_actor_pending(act);
29655
29656                // Should have 5 pending initially, 3 after receiving 2
29657                return pending_before * 10 + pending_after;
29658            }
29659        "#,
29660        );
29661        assert!(matches!(result, Ok(Value::Int(53)))); // 5*10 + 3 = 53
29662    }
29663
29664    #[test]
29665    fn test_actor_message_order() {
29666        // Verify messages are processed in FIFO order (pop from end = LIFO for our impl)
29667        // Note: Our actor uses pop() which is LIFO, so last sent = first received
29668        let result = eval(
29669            r#"
29670            fn main() {
29671                let act = spawn_actor("order_test");
29672                send_to_actor(act, "a", 1);
29673                send_to_actor(act, "b", 2);
29674                send_to_actor(act, "c", 3);
29675
29676                // pop() gives LIFO order, so we get c, b, a
29677                let r1 = recv_from_actor(act);
29678                let r2 = recv_from_actor(act);
29679                let r3 = recv_from_actor(act);
29680
29681                // Return the message types concatenated via their first char values
29682                // c=3, b=2, a=1 in our test
29683                return get_actor_pending(act);  // Should be 0 after draining
29684            }
29685        "#,
29686        );
29687        assert!(matches!(result, Ok(Value::Int(0))));
29688    }
29689
29690    #[test]
29691    fn test_actor_recv_empty() {
29692        // Receiving from empty actor should return None variant
29693        // Verify via pending count that no messages were added
29694        let result = eval(
29695            r#"
29696            fn main() {
29697                let act = spawn_actor("empty_actor");
29698                // No messages sent, so pending should be 0
29699                return get_actor_pending(act);
29700            }
29701        "#,
29702        );
29703        assert!(matches!(result, Ok(Value::Int(0))));
29704    }
29705
29706    #[test]
29707    fn test_actor_tell_alias() {
29708        // tell_actor should work the same as send_to_actor
29709        let result = eval(
29710            r#"
29711            fn main() {
29712                let act = spawn_actor("tell_test");
29713                tell_actor(act, "hello", 123);
29714                tell_actor(act, "world", 456);
29715                return get_actor_msg_count(act);
29716            }
29717        "#,
29718        );
29719        assert!(matches!(result, Ok(Value::Int(2))));
29720    }
29721
29722    #[test]
29723    fn test_actor_name() {
29724        // Verify actor name is stored correctly
29725        let result = eval(
29726            r#"
29727            fn main() {
29728                let act = spawn_actor("my_special_actor");
29729                return get_actor_name(act);
29730            }
29731        "#,
29732        );
29733        assert!(matches!(result, Ok(Value::String(s)) if s.as_str() == "my_special_actor"));
29734    }
29735
29736    #[test]
29737    fn test_multiple_actors() {
29738        // Multiple actors should be independent
29739        let result = eval(
29740            r#"
29741            fn main() {
29742                let a1 = spawn_actor("actor1");
29743                let a2 = spawn_actor("actor2");
29744                let a3 = spawn_actor("actor3");
29745
29746                send_to_actor(a1, "m", 1);
29747                send_to_actor(a2, "m", 1);
29748                send_to_actor(a2, "m", 2);
29749                send_to_actor(a3, "m", 1);
29750                send_to_actor(a3, "m", 2);
29751                send_to_actor(a3, "m", 3);
29752
29753                let c1 = get_actor_msg_count(a1);
29754                let c2 = get_actor_msg_count(a2);
29755                let c3 = get_actor_msg_count(a3);
29756
29757                return c1 * 100 + c2 * 10 + c3;
29758            }
29759        "#,
29760        );
29761        assert!(matches!(result, Ok(Value::Int(123)))); // 1*100 + 2*10 + 3 = 123
29762    }
29763
29764    #[test]
29765    fn test_multiple_channels() {
29766        // Multiple channels should be independent
29767        let result = eval(
29768            r#"
29769            fn main() {
29770                let ch1 = channel_new();
29771                let ch2 = channel_new();
29772                let ch3 = channel_new();
29773
29774                channel_send(ch1, 100);
29775                channel_send(ch2, 200);
29776                channel_send(ch3, 300);
29777
29778                let v1 = channel_recv(ch1);
29779                let v2 = channel_recv(ch2);
29780                let v3 = channel_recv(ch3);
29781
29782                return v1 + v2 + v3;
29783            }
29784        "#,
29785        );
29786        assert!(matches!(result, Ok(Value::Int(600))));
29787    }
29788
29789    #[test]
29790    fn test_thread_sleep() {
29791        // thread_sleep should work without error
29792        let result = eval(
29793            r#"
29794            fn main() {
29795                thread_sleep(1);  // Sleep 1ms
29796                return 42;
29797            }
29798        "#,
29799        );
29800        assert!(matches!(result, Ok(Value::Int(42))));
29801    }
29802
29803    #[test]
29804    fn test_thread_yield() {
29805        // thread_yield should work without error
29806        let result = eval(
29807            r#"
29808            fn main() {
29809                thread_yield();
29810                return 42;
29811            }
29812        "#,
29813        );
29814        assert!(matches!(result, Ok(Value::Int(42))));
29815    }
29816
29817    #[test]
29818    fn test_thread_id() {
29819        // thread_id should return a string
29820        let result = eval(
29821            r#"
29822            fn main() {
29823                let id = thread_id();
29824                return len(id) > 0;
29825            }
29826        "#,
29827        );
29828        assert!(matches!(result, Ok(Value::Bool(true))));
29829    }
29830
29831    #[test]
29832    fn test_channel_stress_interleaved() {
29833        // Interleaved sends and receives
29834        let result = eval(
29835            r#"
29836            fn main() {
29837                let ch = channel_new();
29838                let sum = 0;
29839                let i = 0;
29840                while i < 100 {
29841                    channel_send(ch, i);
29842                    channel_send(ch, i * 2);
29843                    let a = channel_recv(ch);
29844                    let b = channel_recv(ch);
29845                    sum = sum + a + b;
29846                    i = i + 1;
29847                }
29848                // Sum: sum of i + i*2 for i in 0..99
29849                // = sum of 3*i for i in 0..99 = 3 * (99*100/2) = 3 * 4950 = 14850
29850                return sum;
29851            }
29852        "#,
29853        );
29854        assert!(matches!(result, Ok(Value::Int(14850))));
29855    }
29856
29857    #[test]
29858    fn test_actor_stress_with_receive() {
29859        // Send and receive many messages
29860        let result = eval(
29861            r#"
29862            fn main() {
29863                let act = spawn_actor("recv_stress");
29864                let count = 1000;
29865                let i = 0;
29866                while i < count {
29867                    send_to_actor(act, "data", i);
29868                    i = i + 1;
29869                }
29870
29871                // Drain all messages
29872                let drained = 0;
29873                while get_actor_pending(act) > 0 {
29874                    recv_from_actor(act);
29875                    drained = drained + 1;
29876                }
29877
29878                return drained;
29879            }
29880        "#,
29881        );
29882        assert!(matches!(result, Ok(Value::Int(1000))));
29883    }
29884
29885    // ========== PROPERTY-BASED TESTS ==========
29886    // Using proptest for randomized testing of invariants
29887
29888    use proptest::prelude::*;
29889
29890    // --- PARSER FUZZ TESTS ---
29891
29892    proptest! {
29893        #![proptest_config(ProptestConfig::with_cases(100))]
29894
29895        #[test]
29896        fn test_parser_doesnt_crash_on_random_input(s in "\\PC*") {
29897            // The parser should not panic on any input
29898            let mut parser = Parser::new(&s);
29899            let _ = parser.parse_file();  // May error, but shouldn't panic
29900        }
29901
29902        #[test]
29903        fn test_parser_handles_unicode(s in "[\\p{L}\\p{N}\\p{P}\\s]{0,100}") {
29904            // Parser should handle various unicode gracefully
29905            let mut parser = Parser::new(&s);
29906            let _ = parser.parse_file();
29907        }
29908
29909        #[test]
29910        fn test_parser_nested_brackets(depth in 0..20usize) {
29911            // Deeply nested brackets shouldn't cause stack overflow
29912            let open: String = (0..depth).map(|_| '(').collect();
29913            let close: String = (0..depth).map(|_| ')').collect();
29914            let code = format!("fn main() {{ return {}1{}; }}", open, close);
29915            let mut parser = Parser::new(&code);
29916            let _ = parser.parse_file();
29917        }
29918
29919        #[test]
29920        fn test_parser_long_identifiers(len in 1..500usize) {
29921            // Long identifiers shouldn't cause issues
29922            let ident: String = (0..len).map(|_| 'a').collect();
29923            let code = format!("fn main() {{ let {} = 1; return {}; }}", ident, ident);
29924            let result = eval(&code);
29925            assert!(matches!(result, Ok(Value::Int(1))));
29926        }
29927
29928        #[test]
29929        fn test_parser_many_arguments(count in 0..50usize) {
29930            // Many function arguments shouldn't cause issues
29931            let args: String = (0..count).map(|i| format!("{}", i)).collect::<Vec<_>>().join(", ");
29932            let code = format!("fn main() {{ return len([{}]); }}", args);
29933            let result = eval(&code);
29934            assert!(matches!(result, Ok(Value::Int(c)) if c == count as i64));
29935        }
29936    }
29937
29938    // --- GEOMETRIC ALGEBRA PROPERTY TESTS ---
29939
29940    proptest! {
29941        #![proptest_config(ProptestConfig::with_cases(50))]
29942
29943        #[test]
29944        fn test_ga_bivector_anticommutative(x1 in -100.0f64..100.0, y1 in -100.0f64..100.0, z1 in -100.0f64..100.0,
29945                                            x2 in -100.0f64..100.0, y2 in -100.0f64..100.0, z2 in -100.0f64..100.0) {
29946            // e_i ^ e_j = -e_j ^ e_i (bivector anticommutativity)
29947            // Test via wedge product: a ^ b = -(b ^ a)
29948            let code = format!(r#"
29949                fn main() {{
29950                    let a = vec3({}, {}, {});
29951                    let b = vec3({}, {}, {});
29952                    let ab = vec3_cross(a, b);
29953                    let ba = vec3_cross(b, a);
29954                    let diff_x = get(ab, 0) + get(ba, 0);
29955                    let diff_y = get(ab, 1) + get(ba, 1);
29956                    let diff_z = get(ab, 2) + get(ba, 2);
29957                    let eps = 0.001;
29958                    return eps > abs(diff_x) && eps > abs(diff_y) && eps > abs(diff_z);
29959                }}
29960            "#, x1, y1, z1, x2, y2, z2);
29961            let result = eval(&code);
29962            assert!(matches!(result, Ok(Value::Bool(true))));
29963        }
29964
29965        #[test]
29966        fn test_vec3_dot_commutative(x1 in -100.0f64..100.0, y1 in -100.0f64..100.0, z1 in -100.0f64..100.0,
29967                                     x2 in -100.0f64..100.0, y2 in -100.0f64..100.0, z2 in -100.0f64..100.0) {
29968            // a · b = b · a (dot product commutativity)
29969            let code = format!(r#"
29970                fn main() {{
29971                    let a = vec3({}, {}, {});
29972                    let b = vec3({}, {}, {});
29973                    let ab = vec3_dot(a, b);
29974                    let ba = vec3_dot(b, a);
29975                    let eps = 0.001;
29976                    return eps > abs(ab - ba);
29977                }}
29978            "#, x1, y1, z1, x2, y2, z2);
29979            let result = eval(&code);
29980            assert!(matches!(result, Ok(Value::Bool(true))));
29981        }
29982
29983        #[test]
29984        fn test_quat_identity_preserves_vector(x in -100.0f64..100.0, y in -100.0f64..100.0, z in -100.0f64..100.0) {
29985            // Rotating by identity quaternion should preserve the vector
29986            let code = format!(r#"
29987                fn main() {{
29988                    let v = vec3({}, {}, {});
29989                    let q = quat_identity();
29990                    let rotated = quat_rotate(q, v);
29991                    let diff_x = abs(get(v, 0) - get(rotated, 0));
29992                    let diff_y = abs(get(v, 1) - get(rotated, 1));
29993                    let diff_z = abs(get(v, 2) - get(rotated, 2));
29994                    let eps = 0.001;
29995                    return eps > diff_x && eps > diff_y && eps > diff_z;
29996                }}
29997            "#, x, y, z);
29998            let result = eval(&code);
29999            assert!(matches!(result, Ok(Value::Bool(true))));
30000        }
30001
30002        #[test]
30003        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,
30004                                                          angle in -3.14f64..3.14) {
30005            // q(2θ) should equal q(θ) * q(θ)
30006            let code = format!(r#"
30007                fn main() {{
30008                    let v = vec3({}, {}, {});
30009                    let axis = vec3(0.0, 1.0, 0.0);
30010                    let q1 = quat_from_axis_angle(axis, {});
30011                    let q2 = quat_from_axis_angle(axis, {} * 2.0);
30012                    let q1q1 = quat_mul(q1, q1);
30013                    let eps = 0.01;
30014                    let same = eps > abs(get(q2, 0) - get(q1q1, 0)) &&
30015                               eps > abs(get(q2, 1) - get(q1q1, 1)) &&
30016                               eps > abs(get(q2, 2) - get(q1q1, 2)) &&
30017                               eps > abs(get(q2, 3) - get(q1q1, 3));
30018                    let neg_same = eps > abs(get(q2, 0) + get(q1q1, 0)) &&
30019                                   eps > abs(get(q2, 1) + get(q1q1, 1)) &&
30020                                   eps > abs(get(q2, 2) + get(q1q1, 2)) &&
30021                                   eps > abs(get(q2, 3) + get(q1q1, 3));
30022                    return same || neg_same;
30023                }}
30024            "#, x, y, z, angle, angle);
30025            let result = eval(&code);
30026            assert!(matches!(result, Ok(Value::Bool(true))));
30027        }
30028
30029        #[test]
30030        fn test_vec3_add_associative(x1 in -100.0f64..100.0, y1 in -100.0f64..100.0, z1 in -100.0f64..100.0,
30031                                     x2 in -100.0f64..100.0, y2 in -100.0f64..100.0, z2 in -100.0f64..100.0,
30032                                     x3 in -100.0f64..100.0, y3 in -100.0f64..100.0, z3 in -100.0f64..100.0) {
30033            // (a + b) + c = a + (b + c)
30034            let code = format!(r#"
30035                fn main() {{
30036                    let a = vec3({}, {}, {});
30037                    let b = vec3({}, {}, {});
30038                    let c = vec3({}, {}, {});
30039                    let ab_c = vec3_add(vec3_add(a, b), c);
30040                    let a_bc = vec3_add(a, vec3_add(b, c));
30041                    let diff_x = abs(get(ab_c, 0) - get(a_bc, 0));
30042                    let diff_y = abs(get(ab_c, 1) - get(a_bc, 1));
30043                    let diff_z = abs(get(ab_c, 2) - get(a_bc, 2));
30044                    let eps = 0.001;
30045                    return eps > diff_x && eps > diff_y && eps > diff_z;
30046                }}
30047            "#, x1, y1, z1, x2, y2, z2, x3, y3, z3);
30048            let result = eval(&code);
30049            assert!(matches!(result, Ok(Value::Bool(true))));
30050        }
30051
30052        #[test]
30053        fn test_vec3_scale_distributive(x in -100.0f64..100.0, y in -100.0f64..100.0, z in -100.0f64..100.0,
30054                                        s1 in -10.0f64..10.0, s2 in -10.0f64..10.0) {
30055            // (s1 + s2) * v = s1*v + s2*v
30056            let code = format!(r#"
30057                fn main() {{
30058                    let v = vec3({}, {}, {});
30059                    let s1 = {};
30060                    let s2 = {};
30061                    let combined = vec3_scale(v, s1 + s2);
30062                    let separate = vec3_add(vec3_scale(v, s1), vec3_scale(v, s2));
30063                    let diff_x = abs(get(combined, 0) - get(separate, 0));
30064                    let diff_y = abs(get(combined, 1) - get(separate, 1));
30065                    let diff_z = abs(get(combined, 2) - get(separate, 2));
30066                    let eps = 0.01;
30067                    return eps > diff_x && eps > diff_y && eps > diff_z;
30068                }}
30069            "#, x, y, z, s1, s2);
30070            let result = eval(&code);
30071            assert!(matches!(result, Ok(Value::Bool(true))));
30072        }
30073    }
30074
30075    // --- AUTODIFF PROPERTY TESTS ---
30076
30077    proptest! {
30078        #![proptest_config(ProptestConfig::with_cases(30))]
30079
30080        #[test]
30081        fn test_grad_of_constant_is_zero(c in -100.0f64..100.0, x in -100.0f64..100.0) {
30082            // d/dx(c) = 0
30083            let code = format!(r#"
30084                fn main() {{
30085                    fn constant(x) {{ return {}; }}
30086                    let g = grad(constant, {});
30087                    let eps = 0.001;
30088                    return eps > abs(g);
30089                }}
30090            "#, c, x);
30091            let result = eval(&code);
30092            assert!(matches!(result, Ok(Value::Bool(true))));
30093        }
30094
30095        #[test]
30096        fn test_grad_of_x_is_one(x in -100.0f64..100.0) {
30097            // d/dx(x) = 1
30098            let code = format!(r#"
30099                fn main() {{
30100                    fn identity(x) {{ return x; }}
30101                    let g = grad(identity, {});
30102                    let eps = 0.001;
30103                    return eps > abs(g - 1.0);
30104                }}
30105            "#, x);
30106            let result = eval(&code);
30107            assert!(matches!(result, Ok(Value::Bool(true))));
30108        }
30109
30110        #[test]
30111        fn test_grad_of_x_squared(x in -50.0f64..50.0) {
30112            // d/dx(x^2) = 2x
30113            let code = format!(r#"
30114                fn main() {{
30115                    fn square(x) {{ return x * x; }}
30116                    let g = grad(square, {});
30117                    let expected = 2.0 * {};
30118                    let eps = 0.1;
30119                    return eps > abs(g - expected);
30120                }}
30121            "#, x, x);
30122            let result = eval(&code);
30123            assert!(matches!(result, Ok(Value::Bool(true))));
30124        }
30125
30126        #[test]
30127        fn test_grad_linearity(a in -10.0f64..10.0, b in -10.0f64..10.0, x in -10.0f64..10.0) {
30128            // d/dx(a*x + b) = a
30129            let code = format!(r#"
30130                fn main() {{
30131                    fn linear(x) {{ return {} * x + {}; }}
30132                    let g = grad(linear, {});
30133                    let eps = 0.1;
30134                    return eps > abs(g - {});
30135                }}
30136            "#, a, b, x, a);
30137            let result = eval(&code);
30138            assert!(matches!(result, Ok(Value::Bool(true))));
30139        }
30140    }
30141
30142    // --- ARITHMETIC PROPERTY TESTS ---
30143
30144    proptest! {
30145        #![proptest_config(ProptestConfig::with_cases(50))]
30146
30147        #[test]
30148        fn test_addition_commutative(a in -1000i64..1000, b in -1000i64..1000) {
30149            let code = format!("fn main() {{ return {} + {} == {} + {}; }}", a, b, b, a);
30150            let result = eval(&code);
30151            assert!(matches!(result, Ok(Value::Bool(true))));
30152        }
30153
30154        #[test]
30155        fn test_multiplication_commutative(a in -100i64..100, b in -100i64..100) {
30156            let code = format!("fn main() {{ return {} * {} == {} * {}; }}", a, b, b, a);
30157            let result = eval(&code);
30158            assert!(matches!(result, Ok(Value::Bool(true))));
30159        }
30160
30161        #[test]
30162        fn test_addition_identity(a in -1000i64..1000) {
30163            let code = format!("fn main() {{ return {} + 0 == {}; }}", a, a);
30164            let result = eval(&code);
30165            assert!(matches!(result, Ok(Value::Bool(true))));
30166        }
30167
30168        #[test]
30169        fn test_multiplication_identity(a in -1000i64..1000) {
30170            let code = format!("fn main() {{ return {} * 1 == {}; }}", a, a);
30171            let result = eval(&code);
30172            assert!(matches!(result, Ok(Value::Bool(true))));
30173        }
30174
30175        #[test]
30176        fn test_distributive_property(a in -20i64..20, b in -20i64..20, c in -20i64..20) {
30177            let code = format!("fn main() {{ return {} * ({} + {}) == {} * {} + {} * {}; }}", a, b, c, a, b, a, c);
30178            let result = eval(&code);
30179            assert!(matches!(result, Ok(Value::Bool(true))));
30180        }
30181    }
30182
30183    // --- COLLECTION PROPERTY TESTS ---
30184
30185    proptest! {
30186        #![proptest_config(ProptestConfig::with_cases(30))]
30187
30188        #[test]
30189        fn test_array_len_after_push(initial_len in 0..20usize, value in -100i64..100) {
30190            let initial: String = (0..initial_len).map(|i| format!("{}", i)).collect::<Vec<_>>().join(", ");
30191            let code = format!(r#"
30192                fn main() {{
30193                    let arr = [{}];
30194                    push(arr, {});
30195                    return len(arr);
30196                }}
30197            "#, initial, value);
30198            let result = eval(&code);
30199            assert!(matches!(result, Ok(Value::Int(n)) if n == (initial_len + 1) as i64));
30200        }
30201
30202        #[test]
30203        fn test_reverse_reverse_identity(elements in prop::collection::vec(-100i64..100, 0..10)) {
30204            let arr_str = elements.iter().map(|n| n.to_string()).collect::<Vec<_>>().join(", ");
30205            let code = format!(r#"
30206                fn main() {{
30207                    let arr = [{}];
30208                    let rev1 = reverse(arr);
30209                    let rev2 = reverse(rev1);
30210                    let same = true;
30211                    let i = 0;
30212                    while i < len(arr) {{
30213                        if get(arr, i) != get(rev2, i) {{
30214                            same = false;
30215                        }}
30216                        i = i + 1;
30217                    }}
30218                    return same;
30219                }}
30220            "#, arr_str);
30221            let result = eval(&code);
30222            assert!(matches!(result, Ok(Value::Bool(true))));
30223        }
30224
30225        #[test]
30226        fn test_sum_equals_manual_sum(elements in prop::collection::vec(-100i64..100, 0..20)) {
30227            let arr_str = elements.iter().map(|n| n.to_string()).collect::<Vec<_>>().join(", ");
30228            let expected_sum: i64 = elements.iter().sum();
30229            let code = format!("fn main() {{ return sum([{}]); }}", arr_str);
30230            let result = eval(&code);
30231            assert!(matches!(result, Ok(Value::Int(n)) if n == expected_sum));
30232        }
30233    }
30234
30235    // ============================================================================
30236    // MEMORY LEAK TESTS
30237    // These tests verify that repeated operations don't cause memory leaks.
30238    // They run operations many times and check that the interpreter completes
30239    // without running out of memory or panicking.
30240    // ============================================================================
30241
30242    #[test]
30243    fn test_no_leak_repeated_array_operations() {
30244        // Create and discard arrays many times
30245        let result = eval(
30246            r#"
30247            fn main() {
30248                let i = 0;
30249                while i < 1000 {
30250                    let arr = [1, 2, 3, 4, 5];
30251                    push(arr, 6);
30252                    let rev = reverse(arr);
30253                    let s = sum(arr);
30254                    i = i + 1;
30255                }
30256                return i;
30257            }
30258        "#,
30259        );
30260        assert!(matches!(result, Ok(Value::Int(1000))));
30261    }
30262
30263    #[test]
30264    fn test_no_leak_repeated_function_calls() {
30265        // Call functions many times to test function frame cleanup
30266        let result = eval(
30267            r#"
30268            fn fib(n) {
30269                if n <= 1 { return n; }
30270                return fib(n - 1) + fib(n - 2);
30271            }
30272            fn main() {
30273                let i = 0;
30274                let total = 0;
30275                while i < 100 {
30276                    total = total + fib(10);
30277                    i = i + 1;
30278                }
30279                return total;
30280            }
30281        "#,
30282        );
30283        assert!(matches!(result, Ok(Value::Int(5500))));
30284    }
30285
30286    #[test]
30287    fn test_no_leak_repeated_map_operations() {
30288        // Create and discard maps many times
30289        let result = eval(
30290            r#"
30291            fn main() {
30292                let i = 0;
30293                while i < 500 {
30294                    let m = map_new();
30295                    map_set(m, "key1", 1);
30296                    map_set(m, "key2", 2);
30297                    map_set(m, "key3", 3);
30298                    let v = map_get(m, "key1");
30299                    i = i + 1;
30300                }
30301                return i;
30302            }
30303        "#,
30304        );
30305        assert!(matches!(result, Ok(Value::Int(500))));
30306    }
30307
30308    #[test]
30309    fn test_no_leak_repeated_string_operations() {
30310        // Create and discard strings many times
30311        let result = eval(
30312            r#"
30313            fn main() {
30314                let i = 0;
30315                while i < 1000 {
30316                    let s = "hello world";
30317                    let upper_s = upper(s);
30318                    let lower_s = lower(upper_s);
30319                    let concat_s = s ++ " " ++ upper_s;
30320                    let replaced = replace(concat_s, "o", "0");
30321                    i = i + 1;
30322                }
30323                return i;
30324            }
30325        "#,
30326        );
30327        assert!(matches!(result, Ok(Value::Int(1000))));
30328    }
30329
30330    #[test]
30331    fn test_no_leak_repeated_ecs_operations() {
30332        // Create and discard ECS entities many times
30333        let result = eval(
30334            r#"
30335            fn main() {
30336                let world = ecs_world();
30337                let i = 0;
30338                while i < 500 {
30339                    let entity = ecs_spawn(world);
30340                    ecs_attach(world, entity, "Position", vec3(1.0, 2.0, 3.0));
30341                    ecs_attach(world, entity, "Velocity", vec3(0.0, 0.0, 0.0));
30342                    let pos = ecs_get(world, entity, "Position");
30343                    i = i + 1;
30344                }
30345                return i;
30346            }
30347        "#,
30348        );
30349        assert!(matches!(result, Ok(Value::Int(500))));
30350    }
30351
30352    #[test]
30353    fn test_no_leak_repeated_channel_operations() {
30354        // Create and use channels many times
30355        let result = eval(
30356            r#"
30357            fn main() {
30358                let i = 0;
30359                while i < 500 {
30360                    let ch = channel_new();
30361                    channel_send(ch, i);
30362                    channel_send(ch, i + 1);
30363                    let v1 = channel_recv(ch);
30364                    let v2 = channel_recv(ch);
30365                    i = i + 1;
30366                }
30367                return i;
30368            }
30369        "#,
30370        );
30371        assert!(matches!(result, Ok(Value::Int(500))));
30372    }
30373
30374    #[test]
30375    fn test_no_leak_repeated_actor_operations() {
30376        // Create actors and send messages many times
30377        let result = eval(
30378            r#"
30379            fn main() {
30380                let i = 0;
30381                while i < 100 {
30382                    let act = spawn_actor("leak_test_actor");
30383                    send_to_actor(act, "msg", i);
30384                    send_to_actor(act, "msg", i + 1);
30385                    let count = get_actor_msg_count(act);
30386                    i = i + 1;
30387                }
30388                return i;
30389            }
30390        "#,
30391        );
30392        assert!(matches!(result, Ok(Value::Int(100))));
30393    }
30394
30395    #[test]
30396    fn test_no_leak_repeated_vec3_operations() {
30397        // Create and compute with vec3s many times
30398        let result = eval(
30399            r#"
30400            fn main() {
30401                let i = 0;
30402                while i < 1000 {
30403                    let v1 = vec3(1.0, 2.0, 3.0);
30404                    let v2 = vec3(4.0, 5.0, 6.0);
30405                    let added = vec3_add(v1, v2);
30406                    let scaled = vec3_scale(added, 2.0);
30407                    let dot = vec3_dot(v1, v2);
30408                    let crossed = vec3_cross(v1, v2);
30409                    let normalized = vec3_normalize(crossed);
30410                    i = i + 1;
30411                }
30412                return i;
30413            }
30414        "#,
30415        );
30416        assert!(matches!(result, Ok(Value::Int(1000))));
30417    }
30418
30419    #[test]
30420    fn test_no_leak_repeated_closure_creation() {
30421        // Create and call closures many times
30422        let result = eval(
30423            r#"
30424            fn main() {
30425                let i = 0;
30426                let total = 0;
30427                while i < 500 {
30428                    let x = i;
30429                    fn add_x(y) { return x + y; }
30430                    total = total + add_x(1);
30431                    i = i + 1;
30432                }
30433                return total;
30434            }
30435        "#,
30436        );
30437        // Sum of (i+1) for i from 0 to 499 = sum of 1 to 500 = 500*501/2 = 125250
30438        assert!(matches!(result, Ok(Value::Int(125250))));
30439    }
30440
30441    #[test]
30442    fn test_no_leak_nested_data_structures() {
30443        // Create nested arrays and maps many times
30444        let result = eval(
30445            r#"
30446            fn main() {
30447                let i = 0;
30448                while i < 200 {
30449                    let inner1 = [1, 2, 3];
30450                    let inner2 = [4, 5, 6];
30451                    let outer = [inner1, inner2];
30452                    let m = map_new();
30453                    map_set(m, "arr", outer);
30454                    map_set(m, "nested", map_new());
30455                    i = i + 1;
30456                }
30457                return i;
30458            }
30459        "#,
30460        );
30461        assert!(matches!(result, Ok(Value::Int(200))));
30462    }
30463
30464    #[test]
30465    fn test_no_leak_repeated_interpreter_creation() {
30466        // This tests at the Rust level - creating multiple interpreters
30467        for _ in 0..50 {
30468            let result = eval(
30469                r#"
30470                fn main() {
30471                    let arr = [1, 2, 3, 4, 5];
30472                    let total = sum(arr);
30473                    return total * 2;
30474                }
30475            "#,
30476            );
30477            assert!(matches!(result, Ok(Value::Int(30))));
30478        }
30479    }
30480}