dazzle_core/scheme/
evaluator.rs

1//! Scheme evaluator (eval loop)
2//!
3//! Ported from OpenJade's `Interpreter.cxx` (~2,000 lines).
4//!
5//! ## Core Responsibilities
6//!
7//! 1. **Evaluate expressions** - Transform Values into results
8//! 2. **Special forms** - Handle if, let, define, lambda, quote, etc.
9//! 3. **Function application** - Call procedures with arguments
10//! 4. **Tail call optimization** - Prevent stack overflow in recursive functions
11//!
12//! ## OpenJade Correspondence
13//!
14//! | Dazzle          | OpenJade                  | Purpose                    |
15//! |-----------------|---------------------------|----------------------------|
16//! | `Evaluator`     | `Interpreter`             | Main evaluator state       |
17//! | `eval()`        | `Interpreter::eval()`     | Core eval loop             |
18//! | `apply()`       | `Interpreter::apply()`    | Function application       |
19//! | `eval_special()`| `Interpreter::evalXXX()`  | Special form handlers      |
20//!
21//! ## Evaluation Rules (R4RS)
22//!
23//! - **Self-evaluating**: Numbers, strings, booleans, characters → return as-is
24//! - **Symbols**: Look up in environment
25//! - **Lists**: First element determines behavior:
26//!   - Special form keyword → handle specially
27//!   - Otherwise → evaluate all elements, apply first to rest
28
29use crate::scheme::environment::Environment;
30use crate::scheme::parser::Position;
31use crate::scheme::value::{Procedure, Value};
32use crate::grove::{Grove, Node};
33use crate::fot::FotBuilder;
34use gc::Gc;
35use std::rc::Rc;
36use std::cell::RefCell;
37
38// Thread-local evaluator context for primitives
39//
40// Similar to OpenJade's approach, we use thread-local storage to give
41// primitives access to the evaluator state (current node, grove, etc.)
42// without changing all primitive signatures.
43//
44// This is safe because:
45// 1. Scheme evaluation is single-threaded in our implementation
46// 2. The context is set/cleared around each eval call
47// 3. Primitives only run during evaluation
48thread_local! {
49    static EVALUATOR_CONTEXT: RefCell<Option<EvaluatorContext>> = RefCell::new(None);
50}
51
52/// Context available to primitives during evaluation
53#[derive(Clone)]
54pub struct EvaluatorContext {
55    pub grove: Option<Rc<dyn Grove>>,
56    pub current_node: Option<Rc<Box<dyn Node>>>,
57    pub backend: Option<Rc<RefCell<dyn FotBuilder>>>,
58}
59
60/// Get the current evaluator context (for use in primitives)
61pub fn get_evaluator_context() -> Option<EvaluatorContext> {
62    EVALUATOR_CONTEXT.with(|ctx| ctx.borrow().clone())
63}
64
65/// Check if evaluator context is currently set
66fn has_evaluator_context() -> bool {
67    EVALUATOR_CONTEXT.with(|ctx| ctx.borrow().is_some())
68}
69
70/// Set the evaluator context (called by evaluator before eval)
71fn set_evaluator_context(ctx: EvaluatorContext) {
72    EVALUATOR_CONTEXT.with(|c| *c.borrow_mut() = Some(ctx));
73}
74
75/// Clear the evaluator context (called by evaluator after eval)
76fn clear_evaluator_context() {
77    EVALUATOR_CONTEXT.with(|c| *c.borrow_mut() = None);
78}
79
80// =============================================================================
81// Call Stack (for error reporting)
82// =============================================================================
83
84use crate::scheme::value::SourceInfo;
85
86/// A call stack frame
87///
88/// Tracks function calls for error reporting with source locations.
89#[derive(Debug, Clone)]
90pub struct CallFrame {
91    /// Function name (or "<lambda>" for anonymous functions)
92    pub function_name: String,
93    /// Source location (file:line:column)
94    pub source: Option<SourceInfo>,
95}
96
97impl CallFrame {
98    pub fn new(function_name: String, source: Option<SourceInfo>) -> Self {
99        CallFrame {
100            function_name,
101            source,
102        }
103    }
104}
105
106// =============================================================================
107// Evaluation Error
108// =============================================================================
109
110/// Evaluation error with call stack
111#[derive(Debug, Clone)]
112pub struct EvalError {
113    pub message: String,
114    pub call_stack: Vec<CallFrame>,
115}
116
117impl EvalError {
118    pub fn new(message: String) -> Self {
119        EvalError {
120            message,
121            call_stack: Vec::new(),
122        }
123    }
124
125    /// Create error with call stack
126    pub fn with_stack(message: String, call_stack: Vec<CallFrame>) -> Self {
127        EvalError {
128            message,
129            call_stack,
130        }
131    }
132}
133
134impl std::fmt::Display for EvalError {
135    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
136        // OpenJade-style format: file:line:col:E: message
137        write!(f, "{}", self.message)?;
138
139        // Show call stack in reverse order (innermost to outermost, matching OpenJade)
140        for (i, frame) in self.call_stack.iter().rev().enumerate() {
141            if let Some(ref source) = frame.source {
142                // First frame gets a newline before it, rest don't
143                if i == 0 {
144                    writeln!(f, "\n{}:{}:{}:I: called from here",
145                             source.file, source.pos.line, source.pos.column)?;
146                } else {
147                    writeln!(f, "{}:{}:{}:I: called from here",
148                             source.file, source.pos.line, source.pos.column)?;
149                }
150            } else {
151                if i == 0 {
152                    writeln!(f, "\n{}:I: called from here", frame.function_name)?;
153                } else {
154                    writeln!(f, "{}:I: called from here", frame.function_name)?;
155                }
156            }
157        }
158
159        Ok(())
160    }
161}
162
163impl std::error::Error for EvalError {}
164
165pub type EvalResult = Result<Value, EvalError>;
166
167// =============================================================================
168// DSSSL Processing Mode (OpenJade ProcessingMode.h/ProcessingMode.cxx)
169// =============================================================================
170
171/// Construction rule for DSSSL processing
172///
173/// Corresponds to OpenJade's `ElementRule` + `Rule` + `Action`.
174/// Stores the pattern (element name) and action (expression to evaluate).
175#[derive(Clone)]
176pub struct ConstructionRule {
177    /// Element name pattern (GI)
178    pub element_name: String,
179
180    /// Construction expression (returns sosofo when evaluated)
181    pub expr: Value,
182
183    /// Source position where this rule was defined (for error reporting)
184    pub source_file: Option<String>,
185    pub source_pos: Option<Position>,
186}
187
188/// Processing mode containing construction rules
189///
190/// Corresponds to OpenJade's `ProcessingMode` class.
191/// Stores all element construction rules defined in the template.
192pub struct ProcessingMode {
193    /// Construction rules indexed by element name
194    /// In OpenJade, rules are stored in intrusive linked lists and indexed lazily.
195    /// We use a simple Vec for now - can optimize later with HashMap if needed.
196    pub rules: Vec<ConstructionRule>,
197
198    /// Default construction rule (fallback when no specific rule matches)
199    pub default_rule: Option<Value>,
200}
201
202impl ProcessingMode {
203    /// Create a new empty processing mode
204    pub fn new() -> Self {
205        ProcessingMode {
206            rules: Vec::new(),
207            default_rule: None,
208        }
209    }
210
211    /// Add a construction rule
212    pub fn add_rule(&mut self, element_name: String, expr: Value, source_file: Option<String>, source_pos: Option<Position>) {
213        self.rules.push(ConstructionRule {
214            element_name,
215            expr,
216            source_file,
217            source_pos
218        });
219    }
220
221    /// Add a default construction rule
222    pub fn add_default_rule(&mut self, expr: Value) {
223        self.default_rule = Some(expr);
224    }
225
226    /// Find matching rule for an element
227    ///
228    /// Corresponds to OpenJade's `ProcessingMode::findMatch()`.
229    /// Returns the first rule matching the given element name.
230    pub fn find_match(&self, gi: &str) -> Option<&ConstructionRule> {
231        self.rules.iter().find(|rule| rule.element_name == gi)
232    }
233}
234
235// =============================================================================
236// Evaluator
237// =============================================================================
238
239/// Scheme evaluator
240///
241/// Corresponds to OpenJade's `Interpreter` class.
242///
243/// ## Usage
244///
245/// ```ignore
246/// let mut evaluator = Evaluator::new();
247/// let result = evaluator.eval(expr, env)?;
248/// ```
249pub struct Evaluator {
250    /// The document grove (for element-with-id, etc.)
251    grove: Option<Rc<dyn Grove>>,
252
253    /// Current node context (for current-node primitive)
254    ///
255    /// This changes dynamically as we process the document tree.
256    /// When evaluating a template, this starts as the root node.
257    /// When processing children, it changes to each child node.
258    current_node: Option<Rc<Box<dyn Node>>>,
259
260    /// Processing mode containing construction rules
261    ///
262    /// Corresponds to OpenJade's `Interpreter::initialProcessingMode_`.
263    /// Rules are stored here during template loading, then used during processing.
264    processing_mode: ProcessingMode,
265
266    /// Backend for output generation (FotBuilder)
267    ///
268    /// This is used by the `make` special form to write flow objects to output.
269    /// Wrapped in Rc<RefCell<>> to allow shared mutable access.
270    backend: Option<Rc<RefCell<dyn FotBuilder>>>,
271
272    /// Call stack for error reporting
273    ///
274    /// Tracks function calls with their source locations.
275    /// Used to generate helpful error messages with clickable file paths.
276    call_stack: Vec<CallFrame>,
277
278    /// Current source file being evaluated (for error reporting)
279    ///
280    /// Set when loading templates, used to provide context in errors.
281    current_source_file: Option<String>,
282
283    /// Current position in source (for error reporting)
284    ///
285    /// Tracks line and column for the expression being evaluated.
286    current_position: Option<Position>,
287
288    /// Line mappings for translating output lines to source files
289    ///
290    /// When templates are loaded from XML wrappers that concatenate multiple files,
291    /// this maps output line numbers to (source_file, source_line) pairs.
292    /// Used to provide accurate file names and line numbers in error messages.
293    line_mappings: Vec<LineMapping>,
294}
295
296/// Line mapping entry - maps a line number in concatenated code to its source file and line
297#[derive(Debug, Clone)]
298pub struct LineMapping {
299    /// Line number in the concatenated output (1-indexed)
300    pub output_line: usize,
301    /// Source file path
302    pub source_file: String,
303    /// Line number in the source file (1-indexed)
304    pub source_line: usize,
305}
306
307impl Evaluator {
308    /// Create a new evaluator without a grove
309    pub fn new() -> Self {
310        Evaluator {
311            grove: None,
312            current_node: None,
313            processing_mode: ProcessingMode::new(),
314            backend: None,
315            call_stack: Vec::new(),
316            current_source_file: None,
317            current_position: None,
318            line_mappings: Vec::new(),
319        }
320    }
321
322    /// Create a new evaluator with a grove
323    pub fn with_grove(grove: Rc<dyn Grove>) -> Self {
324        Evaluator {
325            grove: Some(grove),
326            current_node: None,
327            processing_mode: ProcessingMode::new(),
328            backend: None,
329            call_stack: Vec::new(),
330            current_source_file: None,
331            current_position: None,
332            line_mappings: Vec::new(),
333        }
334    }
335
336    /// Set line mappings for error reporting
337    pub fn set_line_mappings(&mut self, mappings: Vec<LineMapping>) {
338        self.line_mappings = mappings;
339    }
340
341    /// Set the current source file (for error reporting)
342    pub fn set_source_file(&mut self, file: String) {
343        self.current_source_file = Some(file);
344    }
345
346    /// Get the current source file
347    pub fn source_file(&self) -> Option<&str> {
348        self.current_source_file.as_deref()
349    }
350
351    /// Set the current position (for error reporting)
352    pub fn set_position(&mut self, position: Position) {
353        self.current_position = Some(position);
354    }
355
356    /// Push a call frame onto the stack
357    fn push_call_frame(&mut self, function_name: String, source: Option<SourceInfo>) {
358        self.call_stack.push(CallFrame::new(function_name, source));
359    }
360
361    /// Pop a call frame from the stack
362    fn pop_call_frame(&mut self) {
363        self.call_stack.pop();
364    }
365
366    /// Create an error with the current call stack and position
367    fn error_with_stack(&self, message: String) -> EvalError {
368        // Include current position in the error message (OpenJade format)
369        let full_message = match (&self.current_source_file, &self.current_position) {
370            (Some(file), Some(pos)) => {
371                format!("{}:{}:{}:E: {}", file, pos.line, pos.column, message)
372            }
373            (Some(file), None) => {
374                format!("{}:E: {}", file, message)
375            }
376            _ => message,
377        };
378        EvalError::with_stack(full_message, self.call_stack.clone())
379    }
380
381    /// Set the backend
382    pub fn set_backend(&mut self, backend: Rc<RefCell<dyn FotBuilder>>) {
383        self.backend = Some(backend);
384    }
385
386    /// Set the grove
387    pub fn set_grove(&mut self, grove: Rc<dyn Grove>) {
388        self.grove = Some(grove);
389    }
390
391    /// Get the grove
392    pub fn grove(&self) -> Option<&Rc<dyn Grove>> {
393        self.grove.as_ref()
394    }
395
396    /// Set the current node
397    pub fn set_current_node(&mut self, node: Box<dyn Node>) {
398        self.current_node = Some(Rc::new(node));
399    }
400
401    /// Get the current node
402    pub fn current_node(&self) -> Option<Rc<Box<dyn Node>>> {
403        self.current_node.clone()
404    }
405
406    /// Clear the current node
407    pub fn clear_current_node(&mut self) {
408        self.current_node = None;
409    }
410
411    // =========================================================================
412    // DSSSL Processing (OpenJade ProcessContext.cxx)
413    // =========================================================================
414
415    /// Start DSSSL processing from the root node
416    ///
417    /// Corresponds to OpenJade's `ProcessContext::process()`.
418    /// After template loading, this triggers automatic tree processing.
419    pub fn process_root(&mut self, env: Gc<Environment>) -> EvalResult {
420        // Get the root node from the grove
421        let root_node = match &self.grove {
422            Some(grove) => grove.root(),
423            None => return Err(EvalError::new("No grove set".to_string())),
424        };
425
426        // Set as current node and start processing
427        self.current_node = Some(Rc::new(root_node));
428        self.process_node(env)
429    }
430
431    /// Process the current node
432    ///
433    /// Corresponds to OpenJade's `ProcessContext::processNode()`.
434    ///
435    /// ## Algorithm (from OpenJade):
436    /// 1. If character data node, output directly
437    /// 2. If element node:
438    ///    a. Find matching construction rule by GI
439    ///    b. If rule found, evaluate it (returns sosofo)
440    ///    c. If no rule, default behavior: process-children
441    pub fn process_node(&mut self, env: Gc<Environment>) -> EvalResult {
442        let node = match &self.current_node {
443            Some(n) => n.clone(),
444            None => return Err(EvalError::new("No current node".to_string())),
445        };
446
447        // Get element name (GI)
448        let gi = match node.gi() {
449            Some(gi) => gi,
450            None => {
451                // Not an element (e.g., text node, comment, etc.)
452                // For code generation, we typically ignore non-elements
453                return Ok(Value::Unspecified);
454            }
455        };
456
457        // Find matching construction rule
458        let rule = self.processing_mode.find_match(&gi);
459
460        if let Some(rule) = rule {
461            // Rule found - evaluate the construction expression
462            // Save current source context
463            let saved_file = self.current_source_file.clone();
464            let saved_pos = self.current_position.clone();
465
466            // Restore source context to where the rule was defined
467            // This ensures error messages show the rule definition location, not the rule body location
468            if let Some(ref rule_file) = rule.source_file {
469                self.current_source_file = Some(rule_file.clone());
470            }
471            if let Some(ref rule_pos) = rule.source_pos {
472                self.current_position = Some(rule_pos.clone());
473            }
474
475            // Evaluate the construction expression
476            let result = self.eval(rule.expr.clone(), env);
477
478            // Restore previous source context
479            self.current_source_file = saved_file;
480            self.current_position = saved_pos;
481
482            result
483        } else if let Some(ref default_expr) = self.processing_mode.default_rule {
484            // No specific rule found - use default rule
485            self.eval(default_expr.clone(), env)
486        } else {
487            // No rule found (and no default) - OpenJade's implicit default behavior:
488            // Process children automatically (DSSSL §10.1.5)
489            self.eval_process_children(env)
490        }
491    }
492
493    /// Evaluate an expression in an environment
494    ///
495    /// Corresponds to OpenJade's `Interpreter::eval()`.
496    ///
497    /// ## Evaluation Rules
498    ///
499    /// 1. **Self-evaluating**: Numbers, strings, bools, chars → return as-is
500    /// 2. **Symbols**: Variable lookup in environment
501    /// 3. **Lists**: Check first element for special forms, otherwise apply
502    pub fn eval(&mut self, expr: Value, env: Gc<Environment>) -> EvalResult {
503        // Save previous context state
504        let context_was_set = has_evaluator_context();
505        let previous_context = get_evaluator_context();
506
507        // ALWAYS update context to reflect current evaluator state
508        // This ensures current_node is correct for nested eval() calls
509        set_evaluator_context(EvaluatorContext {
510            grove: self.grove.clone(),
511            current_node: self.current_node.clone(),
512            backend: self.backend.clone(),
513        });
514
515        // Evaluate
516        let result = self.eval_inner(expr, env);
517
518        // Restore previous context state
519        if context_was_set {
520            if let Some(prev_ctx) = previous_context {
521                set_evaluator_context(prev_ctx);
522            }
523        } else {
524            clear_evaluator_context();
525        }
526
527        result
528    }
529
530    /// Inner eval implementation (separated to ensure context cleanup)
531    fn eval_inner(&mut self, expr: Value, env: Gc<Environment>) -> EvalResult {
532        match expr {
533            // Self-evaluating literals
534            Value::Nil => Ok(Value::Nil),
535            Value::Bool(_) => Ok(expr),
536            Value::Integer(_) => Ok(expr),
537            Value::Real(_) => Ok(expr),
538            Value::Char(_) => Ok(expr),
539            Value::String(_) => Ok(expr),
540            Value::Procedure(_) => Ok(expr),
541            Value::Vector(_) => Ok(expr), // Vectors are self-evaluating in R4RS
542            Value::Unspecified => Ok(expr),
543            Value::Error => Ok(expr),
544
545            // DSSSL types (self-evaluating for now)
546            Value::Node(_) => Ok(expr),
547            Value::NodeList(_) => Ok(expr),
548            Value::Sosofo => Ok(expr),
549
550            // Symbols: variable lookup
551            Value::Symbol(ref name) => env
552                .lookup(name)
553                .ok_or_else(|| self.error_with_stack(format!("Undefined variable: {}", name))),
554
555            // Keywords are self-evaluating
556            Value::Keyword(_) => Ok(expr),
557
558            // Lists: special forms or function application
559            Value::Pair(_) => self.eval_list(expr, env),
560        }
561    }
562
563    /// Evaluate a list (special form or function call)
564    fn eval_list(&mut self, expr: Value, env: Gc<Environment>) -> EvalResult {
565        // Extract position from the pair if available and update current position
566        if let Value::Pair(ref p) = expr {
567            let pair_data = p.borrow();
568            if let Some(ref pos) = pair_data.pos {
569                // If we have line mappings, translate the position to source file coordinates
570                if !self.line_mappings.is_empty() {
571                    if let Some(mapping) = self.line_mappings.iter().find(|m| m.output_line == pos.line) {
572                        self.current_source_file = Some(mapping.source_file.clone());
573                        self.current_position = Some(Position {
574                            line: mapping.source_line,
575                            column: pos.column,
576                        });
577                    } else {
578                        // No mapping found, use original position
579                        self.current_position = Some(pos.clone());
580                    }
581                } else {
582                    // No line mappings, use original position
583                    self.current_position = Some(pos.clone());
584                }
585            }
586        }
587
588        // Extract the operator (first element)
589        let (operator, args) = self.list_car_cdr(&expr)?;
590
591        // Check if operator is a symbol (special form keyword)
592        if let Value::Symbol(ref sym) = operator {
593            match &**sym {
594                "quote" => self.eval_quote(args),
595                "if" => self.eval_if(args, env),
596                "define" => self.eval_define(args, env),
597                "set!" => self.eval_set(args, env),
598                "lambda" => self.eval_lambda(args, env),
599                "let" => self.eval_let(args, env),
600                "let*" => self.eval_let_star(args, env),
601                "letrec" => self.eval_letrec(args, env),
602                "begin" => self.eval_begin(args, env),
603                "cond" => self.eval_cond(args, env),
604                "case" => self.eval_case(args, env),
605                "and" => self.eval_and(args, env),
606                "or" => self.eval_or(args, env),
607                "apply" => self.eval_apply(args, env),
608                "map" => self.eval_map(args, env),
609                "for-each" => self.eval_for_each(args, env),
610                "node-list-filter" => self.eval_node_list_filter(args, env),
611                "node-list-map" => self.eval_node_list_map(args, env),
612                "node-list-some?" => self.eval_node_list_some(args, env),
613                "load" => self.eval_load(args, env),
614
615                // DSSSL special forms
616                "define-language" => self.eval_define_language(args, env),
617                "declare-flow-object-class" => self.eval_declare_flow_object_class(args, env),
618                "declare-characteristic" => self.eval_declare_characteristic(args, env),
619                "element" => self.eval_element(args, env),
620                "default" => self.eval_default(args, env),
621                "process-children" => self.eval_process_children(env),
622                "make" => self.eval_make(args, env),
623
624                // Not a special form - evaluate as function call
625                _ => self.eval_application(operator, args, env),
626            }
627        } else {
628            // Operator is not a symbol - evaluate and apply
629            self.eval_application(operator, args, env)
630        }
631    }
632
633    /// Extract car and cdr from a list
634    fn list_car_cdr(&self, list: &Value) -> Result<(Value, Value), EvalError> {
635        if let Value::Pair(ref p) = list {
636            let pair = p.borrow();
637            Ok((pair.car.clone(), pair.cdr.clone()))
638        } else {
639            Err(EvalError::new("Expected list".to_string()))
640        }
641    }
642
643    /// Convert a Vec to a list
644    fn vec_to_list(&self, vec: Vec<Value>) -> Value {
645        let mut result = Value::Nil;
646        for val in vec.iter().rev() {
647            result = Value::cons(val.clone(), result);
648        }
649        result
650    }
651
652    /// Convert a list to a Vec of elements
653    fn list_to_vec(&self, list: Value) -> Result<Vec<Value>, EvalError> {
654        let mut result = Vec::new();
655        let mut current = list;
656
657        loop {
658            match current {
659                Value::Nil => break,
660                Value::Pair(ref p) => {
661                    let pair = p.borrow();
662                    result.push(pair.car.clone());
663                    let cdr = pair.cdr.clone();
664                    drop(pair); // Explicitly drop borrow before reassigning
665                    current = cdr;
666                }
667                _ => return Err(EvalError::new("Improper list".to_string())),
668            }
669        }
670
671        Ok(result)
672    }
673
674    // =========================================================================
675    // Special Forms
676    // =========================================================================
677
678    /// (quote expr) → expr
679    fn eval_quote(&mut self, args: Value) -> EvalResult {
680        let args_vec = self.list_to_vec(args)?;
681        if args_vec.len() != 1 {
682            return Err(EvalError::new("quote requires exactly 1 argument".to_string()));
683        }
684        Ok(args_vec[0].clone())
685    }
686
687    /// (if test consequent [alternate])
688    fn eval_if(&mut self, args: Value, env: Gc<Environment>) -> EvalResult {
689        let args_vec = self.list_to_vec(args)?;
690        if args_vec.len() < 2 || args_vec.len() > 3 {
691            return Err(EvalError::new(
692                "if requires 2 or 3 arguments".to_string(),
693            ));
694        }
695
696        let test = self.eval_inner(args_vec[0].clone(), env.clone())?;
697
698        if test.is_true() {
699            self.eval_inner(args_vec[1].clone(), env)
700        } else if args_vec.len() == 3 {
701            self.eval_inner(args_vec[2].clone(), env)
702        } else {
703            Ok(Value::Unspecified)
704        }
705    }
706
707    /// (define name value) or (define (name params...) body...)
708    fn eval_define(&mut self, args: Value, env: Gc<Environment>) -> EvalResult {
709        let args_vec = self.list_to_vec(args)?;
710        if args_vec.len() < 2 {
711            return Err(EvalError::new(
712                "define requires at least 2 arguments".to_string(),
713            ));
714        }
715
716        // Check if first arg is a symbol or a list
717        match &args_vec[0] {
718            Value::Symbol(ref name) => {
719                // Simple variable definition: (define x value)
720                if args_vec.len() != 2 {
721                    return Err(EvalError::new(
722                        "define with symbol requires exactly 2 arguments".to_string(),
723                    ));
724                }
725                let value = self.eval_inner(args_vec[1].clone(), env.clone())?;
726                env.define(name, value);
727                Ok(Value::Unspecified)
728            }
729
730            Value::Pair(_) => {
731                // Function definition: (define (name params...) body...)
732                // This is syntactic sugar for: (define name (lambda (params...) body...))
733                let (name_val, params) = self.list_car_cdr(&args_vec[0])?;
734
735                if let Value::Symbol(ref name) = name_val {
736                    // Extract parameter names
737                    let params_vec = if params.is_nil() {
738                        Vec::new()
739                    } else {
740                        self.list_to_vec(params)?
741                    };
742
743                    let mut param_names = Vec::new();
744                    for param in params_vec {
745                        if let Value::Symbol(ref pname) = param {
746                            param_names.push(pname.to_string());
747                        } else {
748                            return Err(EvalError::new(format!(
749                                "Parameter must be a symbol, got: {:?}",
750                                param
751                            )));
752                        }
753                    }
754
755                    // Build body
756                    let body = if args_vec.len() == 2 {
757                        args_vec[1].clone()
758                    } else {
759                        let mut body_list = Value::Nil;
760                        for expr in args_vec[1..].iter().rev() {
761                            body_list = Value::cons(expr.clone(), body_list);
762                        }
763                        Value::cons(Value::symbol("begin"), body_list)
764                    };
765
766                    // Create lambda with function name and source info
767                    let source_info = self.current_source_file.as_ref().map(|file| {
768                        use crate::scheme::parser::Position;
769                        SourceInfo::new(file.clone(), Position::new())
770                    });
771                    let lambda_value = Value::lambda_with_source(
772                        param_names,
773                        body,
774                        env.clone(),
775                        source_info,
776                        Some(name.to_string()),
777                    );
778
779                    env.define(name, lambda_value);
780                    Ok(Value::Unspecified)
781                } else {
782                    Err(EvalError::new(
783                        "First element of define must be a symbol".to_string(),
784                    ))
785                }
786            }
787
788            _ => Err(EvalError::new(
789                "First argument to define must be symbol or list".to_string(),
790            )),
791        }
792    }
793
794    /// Evaluate (define-language name props...)
795    /// DSSSL language definition - defines the language name as a symbol
796    fn eval_define_language(&mut self, args: Value, env: Gc<Environment>) -> EvalResult {
797        let args_vec = self.list_to_vec(args)?;
798
799        if args_vec.is_empty() {
800            return Err(EvalError::new(
801                "define-language requires at least 1 argument".to_string(),
802            ));
803        }
804
805        // First argument must be a symbol (language name)
806        if let Value::Symbol(ref name) = args_vec[0] {
807            // Define the language name as a symbol bound to itself
808            // This allows it to be used in (declare-default-language name)
809            env.define(name, args_vec[0].clone());
810            Ok(Value::Unspecified)
811        } else {
812            Err(EvalError::new(
813                "First argument to define-language must be a symbol".to_string(),
814            ))
815        }
816    }
817
818    /// Evaluate (declare-flow-object-class name public-id)
819    /// DSSSL flow object class declaration - defines the class name as a symbol
820    fn eval_declare_flow_object_class(&mut self, args: Value, env: Gc<Environment>) -> EvalResult {
821        let args_vec = self.list_to_vec(args)?;
822
823        if args_vec.is_empty() {
824            return Err(EvalError::new(
825                "declare-flow-object-class requires at least 1 argument".to_string(),
826            ));
827        }
828
829        // First argument must be a symbol (flow object class name)
830        if let Value::Symbol(ref name) = args_vec[0] {
831            // Define the class name as a symbol bound to itself
832            // This allows it to be used in (make name ...) constructs
833            env.define(name, args_vec[0].clone());
834            Ok(Value::Unspecified)
835        } else {
836            Err(EvalError::new(
837                "First argument to declare-flow-object-class must be a symbol".to_string(),
838            ))
839        }
840    }
841
842    /// Evaluate (declare-characteristic name public-id default-value)
843    /// DSSSL characteristic declaration - defines the characteristic with its default value
844    fn eval_declare_characteristic(&mut self, args: Value, env: Gc<Environment>) -> EvalResult {
845        let args_vec = self.list_to_vec(args)?;
846
847        if args_vec.len() < 3 {
848            return Err(EvalError::new(
849                "declare-characteristic requires at least 3 arguments (name, public-id, default-value)".to_string(),
850            ));
851        }
852
853        // First argument must be a symbol (characteristic name)
854        if let Value::Symbol(ref name) = args_vec[0] {
855            // Third argument is the default value - evaluate it
856            let default_value = self.eval(args_vec[2].clone(), env.clone())?;
857
858            // Define the characteristic name as a variable with its default value
859            env.define(name, default_value);
860            Ok(Value::Unspecified)
861        } else {
862            Err(EvalError::new(
863                "First argument to declare-characteristic must be a symbol".to_string(),
864            ))
865        }
866    }
867
868    /// DSSSL element construction rule (OpenJade SchemeParser::doElement)
869    /// Syntax: (element element-name construction-expression)
870    ///
871    /// Stores the rule in processing mode WITHOUT evaluating the body.
872    /// The body will be evaluated later during tree processing when a matching element is found.
873    fn eval_element(&mut self, args: Value, _env: Gc<Environment>) -> EvalResult {
874        let args_vec = self.list_to_vec(args)?;
875
876        if args_vec.len() < 2 {
877            return Err(self.error_with_stack(
878                "element requires at least 2 arguments (element-name and construction-expression)".to_string(),
879            ));
880        }
881
882        if args_vec.len() > 2 {
883            return Err(self.error_with_stack(
884                "element construction rule can only contain one sosofo expression\nTo combine multiple sosofos, use (sosofo-append ...)".to_string(),
885            ));
886        }
887
888        // First argument is the element name (symbol)
889        let element_name = if let Value::Symbol(ref name) = args_vec[0] {
890            name.clone()
891        } else {
892            return Err(self.error_with_stack(
893                "First argument to element must be a symbol".to_string(),
894            ));
895        };
896
897        // Second argument is the construction expression (NOT evaluated yet!)
898        // Store it for later evaluation during processing
899        // Capture the current source position (where the 'element' form is)
900        self.processing_mode.add_rule(
901            element_name.to_string(),
902            args_vec[1].clone(),
903            self.current_source_file.clone(),
904            self.current_position.clone()
905        );
906
907        Ok(Value::Unspecified)
908    }
909
910    /// DSSSL default construction rule
911    /// Syntax: (default construction-expression)
912    ///
913    /// Defines a default rule that applies to all elements that don't have a specific rule.
914    /// This is the catch-all rule.
915    fn eval_default(&mut self, args: Value, _env: Gc<Environment>) -> EvalResult {
916        let args_vec = self.list_to_vec(args)?;
917
918        if args_vec.is_empty() {
919            return Err(self.error_with_stack(
920                "default requires at least 1 argument (construction-expression)".to_string(),
921            ));
922        }
923
924        if args_vec.len() > 1 {
925            return Err(self.error_with_stack(
926                "default construction rule can only contain one sosofo expression\nTo combine multiple sosofos, use (sosofo-append ...)".to_string(),
927            ));
928        }
929
930        // Store the default rule (use empty string as the key for default)
931        self.processing_mode.add_default_rule(args_vec[0].clone());
932
933        Ok(Value::Unspecified)
934    }
935
936    /// DSSSL process-children (OpenJade ProcessContext::processChildren)
937    /// Syntax: (process-children)
938    ///
939    /// Processes all children of the current node.
940    /// For each child, matches construction rules and evaluates them.
941    fn eval_process_children(&mut self, env: Gc<Environment>) -> EvalResult {
942        // Get current node
943        let current_node = match &self.current_node {
944            Some(node) => node.clone(),
945            None => return Err(EvalError::new("No current node".to_string())),
946        };
947
948        // Get children
949        let mut children = current_node.children();
950
951        // Process each child (using DSSSL node-list iteration pattern)
952        let mut result = Value::Unspecified;
953        while !children.is_empty() {
954            // Get first child
955            if let Some(child_node) = children.first() {
956                // Save current node
957                let saved_node = self.current_node.clone();
958
959                // Set child as current node
960                self.current_node = Some(Rc::new(child_node));
961
962                // Process the child node
963                result = self.process_node(env.clone())?;
964
965                // Restore current node
966                self.current_node = saved_node;
967            }
968
969            // Move to rest of children
970            children = children.rest();
971        }
972
973        Ok(result)
974    }
975
976    /// DSSSL make flow object (OpenJade FotBuilder)
977    /// Syntax: (make flow-object-type keyword: value ... body-sosofo)
978    ///
979    /// Creates flow objects and writes them to the backend.
980    /// Supports: entity, formatting-instruction
981    fn eval_make(&mut self, args: Value, env: Gc<Environment>) -> EvalResult {
982        let args_vec = self.list_to_vec(args)?;
983
984        if args_vec.is_empty() {
985            return Err(EvalError::new(
986                "make requires at least a flow object type".to_string(),
987            ));
988        }
989
990        // First argument is the flow object type (symbol)
991        let fo_type = match &args_vec[0] {
992            Value::Symbol(s) => s.as_ref(),
993            _ => return Err(EvalError::new(
994                "make: first argument must be a flow object type symbol".to_string(),
995            )),
996        };
997
998        // Parse keyword arguments and collect body expressions
999        let mut i = 1;
1000        let mut system_id = None;
1001        let mut data = None;
1002        let mut path = None;
1003        let mut body_exprs = Vec::new();
1004
1005        while i < args_vec.len() {
1006            match &args_vec[i] {
1007                Value::Keyword(kw) => {
1008                    // Next argument is the keyword value
1009                    if i + 1 >= args_vec.len() {
1010                        return Err(EvalError::new(
1011                            format!("make: keyword {} requires a value", kw),
1012                        ));
1013                    }
1014                    let value = self.eval(args_vec[i + 1].clone(), env.clone())?;
1015
1016                    match kw.as_ref() {
1017                        "system-id" => {
1018                            if let Value::String(s) = value {
1019                                system_id = Some(s);
1020                            } else {
1021                                return Err(EvalError::new(
1022                                    "make: system-id must be a string".to_string(),
1023                                ));
1024                            }
1025                        }
1026                        "data" => {
1027                            if let Value::String(s) = value {
1028                                data = Some(s);
1029                            } else {
1030                                return Err(EvalError::new(
1031                                    "make: data must be a string".to_string(),
1032                                ));
1033                            }
1034                        }
1035                        "path" => {
1036                            if let Value::String(s) = value {
1037                                path = Some(s);
1038                            } else {
1039                                return Err(EvalError::new(
1040                                    "make: path must be a string".to_string(),
1041                                ));
1042                            }
1043                        }
1044                        _ => {
1045                            // Ignore unknown keywords for now
1046                        }
1047                    }
1048                    i += 2;
1049                }
1050                _ => {
1051                    // Non-keyword argument - collect as body expression
1052                    body_exprs.push(args_vec[i].clone());
1053                    i += 1;
1054                }
1055            }
1056        }
1057
1058        // Call backend method based on flow object type
1059        let backend = self.backend.clone();
1060        match backend {
1061            Some(ref backend) => {
1062                match fo_type {
1063                    "entity" => {
1064                        if let Some(sid) = system_id {
1065                            // Evaluate body expressions (they append to buffer)
1066                            for expr in body_exprs {
1067                                self.eval(expr, env.clone())?;
1068                            }
1069
1070                            // Get current buffer content and write to file
1071                            let content = backend.borrow().current_output().to_string();
1072                            backend.borrow_mut().entity(&sid, &content)
1073                                .map_err(|e| EvalError::new(format!("Backend error: {}", e)))?;
1074                            // Clear buffer after writing file
1075                            backend.borrow_mut().clear_buffer();
1076                        } else {
1077                            return Err(EvalError::new(
1078                                "make entity requires system-id: keyword".to_string(),
1079                            ));
1080                        }
1081                    }
1082                    "formatting-instruction" => {
1083                        if let Some(d) = data {
1084                            // Append to current buffer
1085                            backend.borrow_mut().formatting_instruction(&d)
1086                                .map_err(|e| EvalError::new(format!("Backend error: {}", e)))?;
1087                        } else {
1088                            return Err(EvalError::new(
1089                                "make formatting-instruction requires data: keyword".to_string(),
1090                            ));
1091                        }
1092                    }
1093                    "literal" => {
1094                        // literal is typically called as (literal "text") not (make literal ...)
1095                        // but we support both forms for completeness
1096                        if let Some(d) = data {
1097                            backend.borrow_mut().formatting_instruction(&d)
1098                                .map_err(|e| EvalError::new(format!("Backend error: {}", e)))?;
1099                        } else {
1100                            return Err(EvalError::new(
1101                                "make literal requires data: keyword or a string body".to_string(),
1102                            ));
1103                        }
1104                    }
1105                    "directory" => {
1106                        if let Some(p) = path {
1107                            // Save current directory context
1108                            let prev_dir = backend.borrow().current_directory().map(|s| s.to_string());
1109
1110                            // Create directory and set as current context
1111                            backend.borrow_mut().directory(&p)
1112                                .map_err(|e| EvalError::new(format!("Backend error: {}", e)))?;
1113
1114                            // Evaluate body expressions in the new directory context
1115                            // (nested entities/directories will be created relative to this directory)
1116                            for expr in body_exprs {
1117                                self.eval(expr, env.clone())?;
1118                            }
1119
1120                            // Restore previous directory context
1121                            backend.borrow_mut().set_current_directory(prev_dir);
1122                        } else {
1123                            return Err(EvalError::new(
1124                                "make directory requires path: keyword".to_string(),
1125                            ));
1126                        }
1127                    }
1128                    _ => {
1129                        // Unknown flow object type - just return unspecified for now
1130                        return Ok(Value::Unspecified);
1131                    }
1132                }
1133            }
1134            None => {
1135                return Err(EvalError::new(
1136                    "make: no backend available".to_string(),
1137                ));
1138            }
1139        }
1140
1141        Ok(Value::Unspecified)
1142    }
1143
1144    /// (set! name value)
1145    fn eval_set(&mut self, args: Value, env: Gc<Environment>) -> EvalResult {
1146        let args_vec = self.list_to_vec(args)?;
1147        if args_vec.len() != 2 {
1148            return Err(EvalError::new(
1149                "set! requires exactly 2 arguments".to_string(),
1150            ));
1151        }
1152
1153        if let Value::Symbol(ref name) = args_vec[0] {
1154            let value = self.eval(args_vec[1].clone(), env.clone())?;
1155            env.set(name, value)
1156                .map_err(|e| EvalError::new(e))?;
1157            Ok(Value::Unspecified)
1158        } else {
1159            Err(EvalError::new(
1160                "First argument to set! must be a symbol".to_string(),
1161            ))
1162        }
1163    }
1164
1165    /// (lambda (params...) body...)
1166    fn eval_lambda(&mut self, args: Value, env: Gc<Environment>) -> EvalResult {
1167        let args_vec = self.list_to_vec(args)?;
1168        if args_vec.len() < 2 {
1169            return Err(EvalError::new(
1170                "lambda requires at least 2 arguments (params and body)".to_string(),
1171            ));
1172        }
1173
1174        // Extract parameter list
1175        let params_list = &args_vec[0];
1176        let params_vec = if params_list.is_nil() {
1177            // No parameters: (lambda () body)
1178            Vec::new()
1179        } else {
1180            self.list_to_vec(params_list.clone())?
1181        };
1182
1183        // Convert parameter values to strings
1184        let mut param_names = Vec::new();
1185        for param in params_vec {
1186            if let Value::Symbol(ref name) = param {
1187                param_names.push(name.to_string());
1188            } else {
1189                return Err(EvalError::new(format!(
1190                    "Lambda parameter must be a symbol, got: {:?}",
1191                    param
1192                )));
1193            }
1194        }
1195
1196        // Extract body (one or more expressions)
1197        let body = if args_vec.len() == 2 {
1198            // Single body expression
1199            args_vec[1].clone()
1200        } else {
1201            // Multiple body expressions - wrap in (begin ...)
1202            let mut body_list = Value::Nil;
1203            for expr in args_vec[1..].iter().rev() {
1204                body_list = Value::cons(expr.clone(), body_list);
1205            }
1206            Value::cons(Value::symbol("begin"), body_list)
1207        };
1208
1209        // Create lambda closure capturing current environment and source location
1210        // current_position has been set by eval_list to the position of the (lambda ...) expression
1211        let source_info = match (&self.current_source_file, &self.current_position) {
1212            (Some(file), Some(pos)) => {
1213                // Clone the position since we'll be mutating current_position later
1214                Some(SourceInfo::new(file.clone(), pos.clone()))
1215            }
1216            (Some(file), None) => {
1217                use crate::scheme::parser::Position;
1218                Some(SourceInfo::new(file.clone(), Position::new()))
1219            }
1220            _ => None,
1221        };
1222        Ok(Value::lambda_with_source(param_names, body, env, source_info, None))
1223    }
1224
1225    /// (let ((var val)...) body...)
1226    fn eval_let(&mut self, args: Value, env: Gc<Environment>) -> EvalResult {
1227        let args_vec = self.list_to_vec(args)?;
1228        if args_vec.len() < 2 {
1229            return Err(EvalError::new(
1230                "let requires at least 2 arguments".to_string(),
1231            ));
1232        }
1233
1234        // Check if this is named let: (let name ((var val)...) body...)
1235        if let Value::Symbol(ref loop_name) = args_vec[0] {
1236            if args_vec.len() < 3 {
1237                return Err(EvalError::new(
1238                    "named let requires at least 3 arguments".to_string(),
1239                ));
1240            }
1241
1242            // Named let: transform to (letrec ((name (lambda (vars...) body...))) (name vals...))
1243            let bindings_list = &args_vec[1];
1244            let bindings = self.list_to_vec(bindings_list.clone())?;
1245            let body = &args_vec[2..];
1246
1247            // Extract variable names and initial values
1248            let mut var_names = Vec::new();
1249            let mut init_values = Vec::new();
1250            for binding in &bindings {
1251                let binding_vec = self.list_to_vec(binding.clone())?;
1252                if binding_vec.len() != 2 {
1253                    return Err(EvalError::new(
1254                        "named let binding must have exactly 2 elements".to_string(),
1255                    ));
1256                }
1257                var_names.push(binding_vec[0].clone());
1258                init_values.push(binding_vec[1].clone());
1259            }
1260
1261            // Create lambda: (lambda (vars...) body...)
1262            let lambda_params = self.vec_to_list(var_names);
1263            let mut lambda_body = vec![Value::symbol("lambda"), lambda_params];
1264            lambda_body.extend_from_slice(body);
1265            let lambda_expr = self.vec_to_list(lambda_body);
1266
1267            // Create letrec binding: ((name (lambda ...)))
1268            let letrec_binding = Value::cons(
1269                Value::symbol(loop_name),
1270                Value::cons(lambda_expr, Value::Nil),
1271            );
1272            let letrec_bindings = Value::cons(letrec_binding, Value::Nil);
1273
1274            // Create function call: (name vals...)
1275            let mut call_expr = vec![Value::symbol(loop_name)];
1276            call_expr.extend_from_slice(&init_values);
1277            let call = self.vec_to_list(call_expr);
1278
1279            // Evaluate: (letrec ((name (lambda ...))) (name vals...))
1280            return self.eval_letrec(self.vec_to_list(vec![letrec_bindings, call]), env);
1281        }
1282
1283        // Standard let: (let ((var val)...) body...)
1284        let bindings_list = &args_vec[0];
1285        let bindings = self.list_to_vec(bindings_list.clone())?;
1286
1287        // Create new environment extending current
1288        let new_env = Environment::extend(env.clone());
1289
1290        // Evaluate bindings in OLD environment, define in NEW environment
1291        for binding in bindings {
1292            let binding_vec = self.list_to_vec(binding)?;
1293            if binding_vec.len() != 2 {
1294                return Err(EvalError::new(
1295                    "let binding must have exactly 2 elements".to_string(),
1296                ));
1297            }
1298
1299            if let Value::Symbol(ref name) = binding_vec[0] {
1300                let value = self.eval_inner(binding_vec[1].clone(), env.clone())?;
1301                new_env.define(name, value);
1302            } else {
1303                return Err(EvalError::new(
1304                    "Binding variable must be a symbol".to_string(),
1305                ));
1306            }
1307        }
1308
1309        // Evaluate body in new environment
1310        let body = &args_vec[1..];
1311        self.eval_sequence(body, new_env)
1312    }
1313
1314    /// (let* ((var val)...) body...)
1315    fn eval_let_star(&mut self, args: Value, env: Gc<Environment>) -> EvalResult {
1316        let args_vec = self.list_to_vec(args)?;
1317        if args_vec.len() < 2 {
1318            return Err(EvalError::new(
1319                "let* requires at least 2 arguments".to_string(),
1320            ));
1321        }
1322
1323        // Parse bindings
1324        let bindings_list = &args_vec[0];
1325        let bindings = self.list_to_vec(bindings_list.clone())?;
1326
1327        // Create new environment
1328        let current_env = Environment::extend(env);
1329
1330        // Evaluate bindings sequentially in CURRENT environment
1331        for binding in bindings {
1332            let binding_vec = self.list_to_vec(binding)?;
1333            if binding_vec.len() != 2 {
1334                return Err(EvalError::new(
1335                    "let* binding must have exactly 2 elements".to_string(),
1336                ));
1337            }
1338
1339            if let Value::Symbol(ref name) = binding_vec[0] {
1340                let value = self.eval_inner(binding_vec[1].clone(), current_env.clone())?;
1341                current_env.define(name, value);
1342            } else {
1343                return Err(EvalError::new(
1344                    "Binding variable must be a symbol".to_string(),
1345                ));
1346            }
1347        }
1348
1349        // Evaluate body
1350        let body = &args_vec[1..];
1351        self.eval_sequence(body, current_env)
1352    }
1353
1354    /// (letrec ((var val)...) body...)
1355    ///
1356    /// letrec allows recursive definitions - all bindings can refer to each other.
1357    /// Implementation:
1358    /// 1. Create new environment
1359    /// 2. Bind all variables to Unspecified first
1360    /// 3. Evaluate all values in the new environment
1361    /// 4. Update bindings with evaluated values
1362    /// 5. Evaluate body in the new environment
1363    fn eval_letrec(&mut self, args: Value, env: Gc<Environment>) -> EvalResult {
1364        let args_vec = self.list_to_vec(args)?;
1365        if args_vec.len() < 2 {
1366            return Err(EvalError::new(
1367                "letrec requires at least 2 arguments".to_string(),
1368            ));
1369        }
1370
1371        // Parse bindings
1372        let bindings_list = &args_vec[0];
1373        let bindings = self.list_to_vec(bindings_list.clone())?;
1374
1375        // Create new environment extending current
1376        let new_env = Environment::extend(env);
1377
1378        // First pass: bind all variables to Unspecified
1379        let mut var_names = Vec::new();
1380        for binding in &bindings {
1381            let binding_vec = self.list_to_vec(binding.clone())?;
1382            if binding_vec.len() != 2 {
1383                return Err(EvalError::new(
1384                    "letrec binding must have exactly 2 elements".to_string(),
1385                ));
1386            }
1387
1388            if let Value::Symbol(ref name) = binding_vec[0] {
1389                var_names.push(name.to_string());
1390                new_env.define(name, Value::Unspecified);
1391            } else {
1392                return Err(EvalError::new(
1393                    "Binding variable must be a symbol".to_string(),
1394                ));
1395            }
1396        }
1397
1398        // Second pass: evaluate all values in the new environment and update bindings
1399        for (i, binding) in bindings.iter().enumerate() {
1400            let binding_vec = self.list_to_vec(binding.clone())?;
1401            let value = self.eval_inner(binding_vec[1].clone(), new_env.clone())?;
1402
1403            // Update the binding (set! will work since we already defined it)
1404            new_env.set(&var_names[i], value)
1405                .map_err(|e| EvalError::new(e))?;
1406        }
1407
1408        // Evaluate body in new environment
1409        let body = &args_vec[1..];
1410        self.eval_sequence(body, new_env)
1411    }
1412
1413    /// (begin expr...)
1414    fn eval_begin(&mut self, args: Value, env: Gc<Environment>) -> EvalResult {
1415        let args_vec = self.list_to_vec(args)?;
1416        self.eval_sequence(&args_vec, env)
1417    }
1418
1419    /// (cond (test expr...)...)
1420    fn eval_cond(&mut self, args: Value, env: Gc<Environment>) -> EvalResult {
1421        let clauses = self.list_to_vec(args)?;
1422
1423        for clause in clauses {
1424            let clause_vec = self.list_to_vec(clause)?;
1425            if clause_vec.is_empty() {
1426                return Err(EvalError::new("Empty cond clause".to_string()));
1427            }
1428
1429            // Check for else clause
1430            if let Value::Symbol(ref sym) = clause_vec[0] {
1431                if &**sym == "else" {
1432                    return self.eval_sequence(&clause_vec[1..], env);
1433                }
1434            }
1435
1436            // Evaluate test
1437            let test = self.eval_inner(clause_vec[0].clone(), env.clone())?;
1438            if test.is_true() {
1439                if clause_vec.len() == 1 {
1440                    return Ok(test);
1441                } else {
1442                    return self.eval_sequence(&clause_vec[1..], env);
1443                }
1444            }
1445        }
1446
1447        Ok(Value::Unspecified)
1448    }
1449
1450    /// (case key ((datum...) expr...)...)
1451    ///
1452    /// R4RS case statement:
1453    /// ```scheme
1454    /// (case expr
1455    ///   ((datum1 datum2 ...) result1 result2 ...)
1456    ///   ((datum3 datum4 ...) result3 result4 ...)
1457    ///   ...
1458    ///   [else resultN ...])
1459    /// ```
1460    ///
1461    /// The key expression is evaluated and compared with each datum using eqv?.
1462    /// The datums are NOT evaluated (they are literal constants).
1463    fn eval_case(&mut self, args: Value, env: Gc<Environment>) -> EvalResult {
1464        // Save position at the start of eval_case for accurate error reporting
1465        // (the case expression's position, not sub-expressions)
1466        let case_position = self.current_position.clone();
1467        let case_file = self.current_source_file.clone();
1468
1469        let args_vec = self.list_to_vec(args)?;
1470        if args_vec.is_empty() {
1471            return Err(EvalError::new("case requires at least 1 argument".to_string()));
1472        }
1473
1474        // Evaluate the key expression
1475        let key = self.eval_inner(args_vec[0].clone(), env.clone())?;
1476
1477        // Iterate through clauses
1478        for clause in &args_vec[1..] {
1479            let clause_vec = self.list_to_vec(clause.clone())?;
1480            if clause_vec.is_empty() {
1481                return Err(EvalError::new("Empty case clause".to_string()));
1482            }
1483
1484            // Check for else clause
1485            if let Value::Symbol(ref sym) = clause_vec[0] {
1486                if &**sym == "else" {
1487                    return self.eval_sequence(&clause_vec[1..], env);
1488                }
1489            }
1490
1491            // First element should be a list of datums
1492            let datums = self.list_to_vec(clause_vec[0].clone())?;
1493
1494            // Check if key matches any datum using equal? (not eqv?)
1495            // NOTE: R4RS specifies eqv?, but that doesn't work for strings.
1496            // OpenJade uses equal? for case matching to handle string comparisons.
1497            for datum in datums {
1498                if key.equal(&datum) {
1499                    // Match found - evaluate body expressions
1500                    if clause_vec.len() == 1 {
1501                        // No expressions in clause - return unspecified
1502                        return Ok(Value::Unspecified);
1503                    } else {
1504                        return self.eval_sequence(&clause_vec[1..], env);
1505                    }
1506                }
1507            }
1508        }
1509
1510        // No match found - restore the case expression's position for the error
1511        self.current_position = case_position.clone();
1512        self.current_source_file = case_file;
1513        Err(self.error_with_stack(format!(
1514            "no clause in case expression matched {:?}",
1515            key
1516        )))
1517    }
1518
1519    /// (and expr...)
1520    fn eval_and(&mut self, args: Value, env: Gc<Environment>) -> EvalResult {
1521        let args_vec = self.list_to_vec(args)?;
1522
1523        if args_vec.is_empty() {
1524            return Ok(Value::bool(true));
1525        }
1526
1527        let mut result = Value::bool(true);
1528        for expr in args_vec {
1529            result = self.eval_inner(expr, env.clone())?;
1530            if !result.is_true() {
1531                return Ok(Value::bool(false));
1532            }
1533        }
1534
1535        Ok(result)
1536    }
1537
1538    /// (or expr...)
1539    fn eval_or(&mut self, args: Value, env: Gc<Environment>) -> EvalResult {
1540        let args_vec = self.list_to_vec(args)?;
1541
1542        for expr in args_vec {
1543            let result = self.eval_inner(expr, env.clone())?;
1544            if result.is_true() {
1545                return Ok(result);
1546            }
1547        }
1548
1549        Ok(Value::bool(false))
1550    }
1551
1552    /// Evaluate a sequence of expressions, return last result
1553    fn eval_sequence(&mut self, exprs: &[Value], env: Gc<Environment>) -> EvalResult {
1554        if exprs.is_empty() {
1555            return Ok(Value::Unspecified);
1556        }
1557
1558        let mut result = Value::Unspecified;
1559        for expr in exprs {
1560            result = self.eval_inner(expr.clone(), env.clone())?;
1561        }
1562
1563        Ok(result)
1564    }
1565
1566    /// (apply proc args)
1567    ///
1568    /// Apply a procedure to a list of arguments.
1569    /// Example: (apply + '(1 2 3)) → 6
1570    fn eval_apply(&mut self, args: Value, env: Gc<Environment>) -> EvalResult {
1571        let args_vec = self.list_to_vec(args)?;
1572        if args_vec.len() != 2 {
1573            return Err(EvalError::new(
1574                "apply requires exactly 2 arguments".to_string(),
1575            ));
1576        }
1577
1578        // Evaluate the procedure
1579        let proc = self.eval_inner(args_vec[0].clone(), env.clone())?;
1580
1581        // Evaluate the argument list
1582        let arg_list = self.eval_inner(args_vec[1].clone(), env)?;
1583
1584        // Convert argument list to vector
1585        let arg_values = self.list_to_vec(arg_list)?;
1586
1587        // Apply the procedure
1588        self.apply(proc, arg_values)
1589    }
1590
1591    /// (map proc list)
1592    ///
1593    /// Apply procedure to each element of list, return list of results.
1594    /// Example: (map (lambda (x) (* x 2)) '(1 2 3)) → '(2 4 6)
1595    /// (map proc list1 list2 ...)
1596    ///
1597    /// R4RS: Apply procedure to corresponding elements of lists.
1598    /// All lists must have the same length.
1599    /// Returns a list of results.
1600    ///
1601    /// Examples:
1602    /// - (map + '(1 2 3) '(4 5 6)) => (5 7 9)
1603    /// - (map list '(1 2) '(a b) '(x y)) => ((1 a x) (2 b y))
1604    fn eval_map(&mut self, args: Value, env: Gc<Environment>) -> EvalResult {
1605        let args_vec = self.list_to_vec(args)?;
1606        if args_vec.len() < 2 {
1607            return Err(EvalError::new("map requires at least 2 arguments".to_string()));
1608        }
1609
1610        // Evaluate the procedure
1611        let proc = self.eval_inner(args_vec[0].clone(), env.clone())?;
1612
1613        // Evaluate all lists
1614        let mut lists = Vec::new();
1615        for i in 1..args_vec.len() {
1616            let list = self.eval_inner(args_vec[i].clone(), env.clone())?;
1617            let list_vec = self.list_to_vec(list)?;
1618            lists.push(list_vec);
1619        }
1620
1621        // Check all lists have the same length
1622        if lists.is_empty() {
1623            return Ok(Value::Nil);
1624        }
1625
1626        let length = lists[0].len();
1627        for list in &lists[1..] {
1628            if list.len() != length {
1629                return Err(EvalError::new(
1630                    "map: all lists must have the same length".to_string(),
1631                ));
1632            }
1633        }
1634
1635        // Apply procedure to corresponding elements
1636        let mut result_vec = Vec::new();
1637        for i in 0..length {
1638            // Gather i-th element from each list
1639            let mut proc_args = Vec::new();
1640            for list in &lists {
1641                proc_args.push(list[i].clone());
1642            }
1643
1644            // Apply procedure
1645            let result = self.apply(proc.clone(), proc_args)?;
1646            result_vec.push(result);
1647        }
1648
1649        // Convert result vector back to list
1650        let mut result_list = Value::Nil;
1651        for elem in result_vec.into_iter().rev() {
1652            result_list = Value::cons(elem, result_list);
1653        }
1654
1655        Ok(result_list)
1656    }
1657
1658    /// (for-each proc list1 list2 ...)
1659    ///
1660    /// R4RS: Apply procedure to corresponding elements of lists for side effects.
1661    /// All lists must have the same length.
1662    /// Returns unspecified.
1663    ///
1664    /// Example: (for-each display '("a" "b" "c"))
1665    fn eval_for_each(&mut self, args: Value, env: Gc<Environment>) -> EvalResult {
1666        let args_vec = self.list_to_vec(args)?;
1667        if args_vec.len() < 2 {
1668            return Err(EvalError::new(
1669                "for-each requires at least 2 arguments".to_string(),
1670            ));
1671        }
1672
1673        // Evaluate the procedure
1674        let proc = self.eval_inner(args_vec[0].clone(), env.clone())?;
1675
1676        // Evaluate all lists
1677        let mut lists = Vec::new();
1678        for i in 1..args_vec.len() {
1679            let list = self.eval_inner(args_vec[i].clone(), env.clone())?;
1680            let list_vec = self.list_to_vec(list)?;
1681            lists.push(list_vec);
1682        }
1683
1684        // Check all lists have the same length
1685        if lists.is_empty() {
1686            return Ok(Value::Unspecified);
1687        }
1688
1689        let length = lists[0].len();
1690        for list in &lists[1..] {
1691            if list.len() != length {
1692                return Err(EvalError::new(
1693                    "for-each: all lists must have the same length".to_string(),
1694                ));
1695            }
1696        }
1697
1698        // Apply procedure to corresponding elements (for side effects)
1699        for i in 0..length {
1700            // Gather i-th element from each list
1701            let mut proc_args = Vec::new();
1702            for list in &lists {
1703                proc_args.push(list[i].clone());
1704            }
1705
1706            // Apply procedure for side effects
1707            self.apply(proc.clone(), proc_args)?;
1708        }
1709
1710        Ok(Value::Unspecified)
1711    }
1712
1713    /// (node-list-filter predicate node-list)
1714    ///
1715    /// (node-list-filter pred node-list) → node-list
1716    ///
1717    /// Returns a node-list containing only nodes for which predicate returns #t.
1718    /// DSSSL: Filter a node-list based on a predicate function.
1719    fn eval_node_list_filter(&mut self, args: Value, env: Gc<Environment>) -> EvalResult {
1720        let args_vec = self.list_to_vec(args)?;
1721        if args_vec.len() != 2 {
1722            return Err(EvalError::new("node-list-filter requires exactly 2 arguments".to_string()));
1723        }
1724
1725        // Evaluate the predicate
1726        let pred = self.eval_inner(args_vec[0].clone(), env.clone())?;
1727
1728        // Evaluate the node-list
1729        let node_list_val = self.eval_inner(args_vec[1].clone(), env.clone())?;
1730
1731        match node_list_val {
1732            Value::NodeList(ref nl) => {
1733                let mut filtered_nodes = Vec::new();
1734
1735                // Iterate through the node-list
1736                let mut index = 0;
1737                loop {
1738                    if let Some(node) = nl.get(index) {
1739                        // Apply predicate to this node
1740                        let node_val = Value::node(node);
1741                        let result = self.apply(pred.clone(), vec![node_val.clone()])?;
1742
1743                        // If predicate returns a truthy value (anything except #f), include this node
1744                        if !matches!(result, Value::Bool(false)) {
1745                            // Need to get the node again since we consumed it
1746                            if let Value::Node(n) = node_val {
1747                                filtered_nodes.push(n.as_ref().clone_node());
1748                            }
1749                        }
1750
1751                        index += 1;
1752                    } else {
1753                        break;
1754                    }
1755                }
1756
1757                Ok(Value::node_list(Box::new(crate::grove::VecNodeList::new(filtered_nodes))))
1758            }
1759            _ => Err(EvalError::new(format!("node-list-filter: second argument not a node-list: {:?}", node_list_val))),
1760        }
1761    }
1762
1763    /// (node-list-map proc node-list) → node-list
1764    ///
1765    /// Applies proc to each node in node-list and returns a flattened node-list.
1766    /// Each result must be a node-list or a single node (which is treated as a singleton node-list).
1767    /// Results are concatenated (flattened) into a single node-list.
1768    /// If proc returns #f or any non-node value, processing stops (OpenJade compatibility).
1769    ///
1770    /// DSSSL: Maps a procedure over a node-list, flattening results into a single node-list.
1771    /// OpenJade: MapNodeListObj - stops processing when proc returns a non-node-list value.
1772    fn eval_node_list_map(&mut self, args: Value, env: Gc<Environment>) -> EvalResult {
1773        let args_vec = self.list_to_vec(args)?;
1774        if args_vec.len() != 2 {
1775            return Err(EvalError::new("node-list-map requires exactly 2 arguments".to_string()));
1776        }
1777
1778        // Evaluate the procedure
1779        let proc = self.eval_inner(args_vec[0].clone(), env.clone())?;
1780
1781        // Evaluate the node-list
1782        let node_list_val = self.eval_inner(args_vec[1].clone(), env.clone())?;
1783
1784        // Collect all nodes from mapping results (flattened)
1785        let mut result_nodes: Vec<Box<dyn crate::grove::Node>> = Vec::new();
1786
1787        match node_list_val {
1788            Value::Node(ref n) => {
1789                // Single node - apply proc and collect result
1790                let node_val = Value::node(n.as_ref().clone_node());
1791                let result = self.apply(proc, vec![node_val])?;
1792
1793                // OpenJade: Result must be node or node-list. If not, stop processing.
1794                // Single nodes are auto-converted to singleton node-lists (DSSSL spec)
1795                match result {
1796                    Value::Node(n) => {
1797                        // Single node - treat as singleton node-list
1798                        result_nodes.push(n.as_ref().clone_node());
1799                    }
1800                    Value::NodeList(nl) => {
1801                        // Node-list - flatten all nodes
1802                        let mut index = 0;
1803                        while let Some(node) = nl.get(index) {
1804                            result_nodes.push(node);
1805                            index += 1;
1806                        }
1807                    }
1808                    _ => {
1809                        // Non-node result (e.g., #f) - stop processing (OpenJade compat)
1810                        // Return empty node-list
1811                    }
1812                }
1813            }
1814            Value::NodeList(ref nl) => {
1815                // Iterate through the node-list
1816                let mut index = 0;
1817                loop {
1818                    if let Some(node) = nl.get(index) {
1819                        // Apply procedure to this node
1820                        let node_val = Value::node(node);
1821                        let result = self.apply(proc.clone(), vec![node_val])?;
1822
1823                        // OpenJade: Result must be node or node-list. If not, stop processing.
1824                        match result {
1825                            Value::Node(n) => {
1826                                // Single node - treat as singleton node-list
1827                                result_nodes.push(n.as_ref().clone_node());
1828                                index += 1;
1829                            }
1830                            Value::NodeList(nl_result) => {
1831                                // Node-list - flatten all nodes
1832                                let mut nl_index = 0;
1833                                while let Some(node) = nl_result.get(nl_index) {
1834                                    result_nodes.push(node);
1835                                    nl_index += 1;
1836                                }
1837                                index += 1;
1838                            }
1839                            _ => {
1840                                // Non-node result (e.g., #f) - stop processing (OpenJade compat)
1841                                break;
1842                            }
1843                        }
1844                    } else {
1845                        break;
1846                    }
1847                }
1848            }
1849            _ => return Err(EvalError::new(format!("node-list-map: second argument must be a node or node-list: {:?}", node_list_val))),
1850        }
1851
1852        // Return flattened node-list
1853        Ok(Value::node_list(Box::new(crate::grove::VecNodeList::new(result_nodes))))
1854    }
1855
1856    /// (node-list-some? predicate node-list) → boolean
1857    ///
1858    /// Returns #t if the predicate returns true for at least one node in the node-list.
1859    /// Returns #f if the node-list is empty or the predicate returns false for all nodes.
1860    /// DSSSL: Test if any node in the node-list satisfies the predicate.
1861    fn eval_node_list_some(&mut self, args: Value, env: Gc<Environment>) -> EvalResult {
1862        let args_vec = self.list_to_vec(args)?;
1863        if args_vec.len() != 2 {
1864            return Err(EvalError::new("node-list-some? requires exactly 2 arguments".to_string()));
1865        }
1866
1867        // Evaluate the predicate
1868        let pred = self.eval_inner(args_vec[0].clone(), env.clone())?;
1869
1870        // Evaluate the node-list
1871        let node_list_val = self.eval_inner(args_vec[1].clone(), env.clone())?;
1872
1873        match node_list_val {
1874            Value::NodeList(ref nl) => {
1875                // Iterate through the node-list
1876                let mut index = 0;
1877                loop {
1878                    if let Some(node) = nl.get(index) {
1879                        // Apply predicate to this node
1880                        let node_val = Value::node(node);
1881                        let result = self.apply(pred.clone(), vec![node_val])?;
1882
1883                        // If predicate returns a truthy value (anything except #f), return #t immediately
1884                        if !matches!(result, Value::Bool(false)) {
1885                            return Ok(Value::bool(true));
1886                        }
1887
1888                        index += 1;
1889                    } else {
1890                        break;
1891                    }
1892                }
1893
1894                // If we get here, no node satisfied the predicate
1895                Ok(Value::bool(false))
1896            }
1897            _ => Err(EvalError::new(format!("node-list-some?: second argument not a node-list: {:?}", node_list_val))),
1898        }
1899    }
1900
1901    /// (load filename)
1902    ///
1903    /// Load and evaluate Scheme code from a file.
1904    /// Returns the result of the last expression in the file.
1905    fn eval_load(&mut self, args: Value, env: Gc<Environment>) -> EvalResult {
1906        let args_vec = self.list_to_vec(args)?;
1907        if args_vec.len() != 1 {
1908            return Err(EvalError::new(
1909                "load requires exactly 1 argument".to_string(),
1910            ));
1911        }
1912
1913        // Evaluate the filename argument
1914        let filename_val = self.eval_inner(args_vec[0].clone(), env.clone())?;
1915
1916        let filename = match filename_val {
1917            Value::String(s) => s.to_string(),
1918            _ => return Err(EvalError::new(
1919                format!("load: filename must be a string, got {:?}", filename_val)
1920            )),
1921        };
1922
1923        // Read the file
1924        let contents = std::fs::read_to_string(&filename)
1925            .map_err(|e| EvalError::new(format!("load: cannot read file '{}': {}", filename, e)))?;
1926
1927        // Parse the file contents with filename for error reporting
1928        let mut parser = crate::scheme::parser::Parser::new_with_filename(&contents, filename.clone());
1929        let mut result = Value::Unspecified;
1930
1931        // Save current source file and position, set to the loaded file for error reporting
1932        let prev_source_file = self.current_source_file.clone();
1933        let prev_position = self.current_position.clone();
1934        self.current_source_file = Some(filename.clone());
1935
1936        // Evaluate each expression in sequence
1937        let eval_result = loop {
1938            // Get position before parsing
1939            let pos = parser.current_position();
1940
1941            match parser.parse() {
1942                Ok(expr) => {
1943                    // Set position for this expression
1944                    self.current_position = Some(pos);
1945
1946                    match self.eval_inner(expr, env.clone()) {
1947                        Ok(val) => result = val,
1948                        Err(e) => break Err(e),
1949                    }
1950                }
1951                Err(e) => {
1952                    // Check if we've reached end of input (not an error)
1953                    let error_msg = e.to_string();
1954                    if error_msg.contains("Unexpected end of input")
1955                        || error_msg.contains("Expected")
1956                        || error_msg.contains("EOF") {
1957                        break Ok(result);
1958                    }
1959                    break Err(EvalError::new(
1960                        format!("load: parse error in '{}': {}", filename, e)
1961                    ));
1962                }
1963            }
1964        };
1965
1966        // Restore previous source file and position
1967        self.current_source_file = prev_source_file;
1968        self.current_position = prev_position;
1969
1970        eval_result
1971    }
1972
1973    // =========================================================================
1974    // Function Application
1975    // =========================================================================
1976
1977    /// Apply a function to arguments
1978    fn eval_application(
1979        &mut self,
1980        operator: Value,
1981        args: Value,
1982        env: Gc<Environment>,
1983    ) -> EvalResult {
1984        // Save the position of this application expression (the call site)
1985        let application_pos = self.current_position.clone();
1986        let application_file = self.current_source_file.clone();
1987
1988        // Evaluate operator
1989        let proc = self.eval_inner(operator, env.clone())?;
1990
1991        // Evaluate arguments - extract position from the pair containing each argument
1992        let mut evaled_args = Vec::new();
1993        let mut current_args = args;
1994        loop {
1995            match current_args {
1996                Value::Nil => break,
1997                Value::Pair(ref p) => {
1998                    let pair_borrow = p.borrow();
1999
2000                    // Extract position from this pair (which contains the argument)
2001                    // This gives us the position where the argument appears in the source
2002                    if let Some(ref pos) = pair_borrow.pos {
2003                        // Translate output position to source position using line mappings
2004                        if !self.line_mappings.is_empty() {
2005                            if let Some(mapping) = self.line_mappings.iter().find(|m| m.output_line == pos.line) {
2006                                self.current_source_file = Some(mapping.source_file.clone());
2007                                self.current_position = Some(Position {
2008                                    line: mapping.source_line,
2009                                    column: pos.column,
2010                                });
2011                            } else {
2012                                self.current_position = Some(pos.clone());
2013                            }
2014                        } else {
2015                            self.current_position = Some(pos.clone());
2016                        }
2017                    }
2018
2019                    let arg = pair_borrow.car.clone();
2020                    let cdr = pair_borrow.cdr.clone();
2021                    drop(pair_borrow); // Release borrow before evaluating
2022
2023                    evaled_args.push(self.eval_inner(arg, env.clone())?);
2024                    current_args = cdr;
2025                }
2026                _ => return Err(EvalError::new("Improper argument list".to_string())),
2027            }
2028        }
2029
2030        // Restore the application position before calling apply
2031        // This ensures that when we push a call frame, we capture the CALL SITE, not the last argument's position
2032        self.current_position = application_pos;
2033        self.current_source_file = application_file;
2034
2035        // Apply procedure
2036        self.apply(proc, evaled_args)
2037    }
2038
2039    /// Apply a procedure to evaluated arguments
2040    fn apply(&mut self, proc: Value, args: Vec<Value>) -> EvalResult {
2041        if let Value::Procedure(ref p) = proc {
2042            match &**p {
2043                Procedure::Primitive { name: _, func } => {
2044                    // Don't push call frames for primitives - only for user lambdas
2045                    // This matches OpenJade's behavior
2046                    func(&args).map_err(|e| self.error_with_stack(e))
2047                }
2048                Procedure::Lambda { params, body, env, source, name } => {
2049                    // Check argument count
2050                    if args.len() != params.len() {
2051                        return Err(self.error_with_stack(format!(
2052                            "Lambda expects {} arguments, got {}",
2053                            params.len(),
2054                            args.len()
2055                        )));
2056                    }
2057
2058                    // Save current position (call site) before switching to lambda's definition location
2059                    let saved_file = self.current_source_file.clone();
2060                    let saved_pos = self.current_position.clone();
2061
2062                    // Only push call frame for NAMED functions (not anonymous lambdas)
2063                    // This matches OpenJade's behavior - it only tracks named function calls
2064                    let pushed_frame = if let Some(func_name) = name.clone() {
2065                        let call_site = match (&saved_file, &saved_pos) {
2066                            (Some(file), Some(pos)) => Some(SourceInfo {
2067                                file: file.clone(),
2068                                pos: pos.clone(),
2069                            }),
2070                            _ => None,
2071                        };
2072                        self.push_call_frame(func_name, call_site);
2073                        true
2074                    } else {
2075                        false
2076                    };
2077
2078                    // Switch to lambda's definition location for evaluating the body
2079                    if let Some(ref src) = source {
2080                        self.current_source_file = Some(src.file.clone());
2081                        self.current_position = Some(src.pos.clone());
2082                    }
2083
2084                    // Create new environment extending the closure environment
2085                    let lambda_env = Environment::extend(env.clone());
2086
2087                    // Bind parameters to arguments
2088                    for (param_name, arg_value) in params.iter().zip(args.iter()) {
2089                        lambda_env.define(param_name, arg_value.clone());
2090                    }
2091
2092                    // Evaluate body in the new environment
2093                    let result = self.eval_inner((**body).clone(), lambda_env);
2094
2095                    // Restore previous position
2096                    self.current_source_file = saved_file;
2097                    self.current_position = saved_pos;
2098
2099                    // Pop call frame if we pushed one
2100                    if pushed_frame {
2101                        self.pop_call_frame();
2102                    }
2103
2104                    result
2105                }
2106            }
2107        } else {
2108            Err(self.error_with_stack(format!(
2109                "Not a procedure: {:?}",
2110                proc
2111            )))
2112        }
2113    }
2114}
2115
2116impl Default for Evaluator {
2117    fn default() -> Self {
2118        Self::new()
2119    }
2120}
2121
2122// =============================================================================
2123// Tests
2124// =============================================================================
2125
2126#[cfg(test)]
2127mod tests {
2128    use super::*;
2129
2130    fn make_env() -> Gc<Environment> {
2131        Environment::new_global()
2132    }
2133
2134    #[test]
2135    fn test_eval_self_evaluating() {
2136        let mut eval = Evaluator::new();
2137        let env = make_env();
2138
2139        assert!(eval.eval(Value::integer(42), env.clone()).unwrap().is_integer());
2140        assert!(eval.eval(Value::bool(true), env.clone()).unwrap().is_bool());
2141        assert!(eval.eval(Value::string("hello".to_string()), env).unwrap().is_string());
2142    }
2143
2144    #[test]
2145    fn test_eval_quote() {
2146        let mut eval = Evaluator::new();
2147        let env = make_env();
2148
2149        // (quote (1 2 3))
2150        let expr = Value::cons(
2151            Value::symbol("quote"),
2152            Value::cons(
2153                Value::cons(
2154                    Value::integer(1),
2155                    Value::cons(Value::integer(2), Value::cons(Value::integer(3), Value::Nil)),
2156                ),
2157                Value::Nil,
2158            ),
2159        );
2160
2161        let result = eval.eval(expr, env).unwrap();
2162        assert!(result.is_list());
2163    }
2164
2165    #[test]
2166    fn test_eval_if_true() {
2167        let mut eval = Evaluator::new();
2168        let env = make_env();
2169
2170        // (if #t 1 2)
2171        let expr = Value::cons(
2172            Value::symbol("if"),
2173            Value::cons(
2174                Value::bool(true),
2175                Value::cons(Value::integer(1), Value::cons(Value::integer(2), Value::Nil)),
2176            ),
2177        );
2178
2179        let result = eval.eval(expr, env).unwrap();
2180        if let Value::Integer(n) = result {
2181            assert_eq!(n, 1);
2182        } else {
2183            panic!("Expected integer 1");
2184        }
2185    }
2186
2187    #[test]
2188    fn test_eval_if_false() {
2189        let mut eval = Evaluator::new();
2190        let env = make_env();
2191
2192        // (if #f 1 2)
2193        let expr = Value::cons(
2194            Value::symbol("if"),
2195            Value::cons(
2196                Value::bool(false),
2197                Value::cons(Value::integer(1), Value::cons(Value::integer(2), Value::Nil)),
2198            ),
2199        );
2200
2201        let result = eval.eval(expr, env).unwrap();
2202        if let Value::Integer(n) = result {
2203            assert_eq!(n, 2);
2204        } else {
2205            panic!("Expected integer 2");
2206        }
2207    }
2208
2209    #[test]
2210    fn test_eval_define() {
2211        let mut eval = Evaluator::new();
2212        let env = make_env();
2213
2214        // (define x 42)
2215        let expr = Value::cons(
2216            Value::symbol("define"),
2217            Value::cons(Value::symbol("x"), Value::cons(Value::integer(42), Value::Nil)),
2218        );
2219
2220        eval.eval(expr, env.clone()).unwrap();
2221
2222        // Check that x is defined
2223        assert!(env.is_defined("x"));
2224        if let Value::Integer(n) = env.lookup("x").unwrap() {
2225            assert_eq!(n, 42);
2226        }
2227    }
2228
2229    #[test]
2230    fn test_eval_symbol_lookup() {
2231        let mut eval = Evaluator::new();
2232        let env = make_env();
2233
2234        env.define("x", Value::integer(99));
2235
2236        let result = eval.eval(Value::symbol("x"), env).unwrap();
2237        if let Value::Integer(n) = result {
2238            assert_eq!(n, 99);
2239        } else {
2240            panic!("Expected integer 99");
2241        }
2242    }
2243
2244    #[test]
2245    fn test_eval_and() {
2246        let mut eval = Evaluator::new();
2247        let env = make_env();
2248
2249        // (and #t #t)
2250        let expr = Value::cons(
2251            Value::symbol("and"),
2252            Value::cons(Value::bool(true), Value::cons(Value::bool(true), Value::Nil)),
2253        );
2254
2255        let result = eval.eval(expr, env.clone()).unwrap();
2256        assert!(result.is_true());
2257
2258        // (and #t #f)
2259        let expr = Value::cons(
2260            Value::symbol("and"),
2261            Value::cons(Value::bool(true), Value::cons(Value::bool(false), Value::Nil)),
2262        );
2263
2264        let result = eval.eval(expr, env).unwrap();
2265        assert!(!result.is_true());
2266    }
2267
2268    #[test]
2269    fn test_eval_or() {
2270        let mut eval = Evaluator::new();
2271        let env = make_env();
2272
2273        // (or #f #t)
2274        let expr = Value::cons(
2275            Value::symbol("or"),
2276            Value::cons(Value::bool(false), Value::cons(Value::bool(true), Value::Nil)),
2277        );
2278
2279        let result = eval.eval(expr, env.clone()).unwrap();
2280        assert!(result.is_true());
2281
2282        // (or #f #f)
2283        let expr = Value::cons(
2284            Value::symbol("or"),
2285            Value::cons(Value::bool(false), Value::cons(Value::bool(false), Value::Nil)),
2286        );
2287
2288        let result = eval.eval(expr, env).unwrap();
2289        assert!(!result.is_true());
2290    }
2291
2292    #[test]
2293    fn test_eval_lambda_creation() {
2294        let mut eval = Evaluator::new();
2295        let env = make_env();
2296
2297        // (lambda (x) x)
2298        let expr = Value::cons(
2299            Value::symbol("lambda"),
2300            Value::cons(
2301                Value::cons(Value::symbol("x"), Value::Nil),
2302                Value::cons(Value::symbol("x"), Value::Nil),
2303            ),
2304        );
2305
2306        let result = eval.eval(expr, env).unwrap();
2307        assert!(result.is_procedure());
2308    }
2309
2310    #[test]
2311    fn test_eval_lambda_application() {
2312        let mut eval = Evaluator::new();
2313        let env = make_env();
2314
2315        // ((lambda (x) x) 42)
2316        let lambda_expr = Value::cons(
2317            Value::symbol("lambda"),
2318            Value::cons(
2319                Value::cons(Value::symbol("x"), Value::Nil),
2320                Value::cons(Value::symbol("x"), Value::Nil),
2321            ),
2322        );
2323
2324        let app_expr = Value::cons(lambda_expr, Value::cons(Value::integer(42), Value::Nil));
2325
2326        let result = eval.eval(app_expr, env).unwrap();
2327        if let Value::Integer(n) = result {
2328            assert_eq!(n, 42);
2329        } else {
2330            panic!("Expected integer 42");
2331        }
2332    }
2333
2334    #[test]
2335    fn test_eval_lambda_multiple_params() {
2336        let mut eval = Evaluator::new();
2337        let env = make_env();
2338
2339        // ((lambda (x y) x) 1 2) - Just return first param
2340        let params = Value::cons(Value::symbol("x"), Value::cons(Value::symbol("y"), Value::Nil));
2341        let body = Value::symbol("x");
2342
2343        let lambda_expr = Value::cons(Value::symbol("lambda"), Value::cons(params, Value::cons(body, Value::Nil)));
2344
2345        let app_expr = Value::cons(
2346            lambda_expr,
2347            Value::cons(Value::integer(1), Value::cons(Value::integer(2), Value::Nil)),
2348        );
2349
2350        let result = eval.eval(app_expr, env).unwrap();
2351        if let Value::Integer(n) = result {
2352            assert_eq!(n, 1);
2353        } else {
2354            panic!("Expected integer 1");
2355        }
2356    }
2357
2358    #[test]
2359    fn test_eval_lambda_wrong_arg_count() {
2360        let mut eval = Evaluator::new();
2361        let env = make_env();
2362
2363        // ((lambda (x) x) 1 2) - wrong argument count
2364        let lambda_expr = Value::cons(
2365            Value::symbol("lambda"),
2366            Value::cons(
2367                Value::cons(Value::symbol("x"), Value::Nil),
2368                Value::cons(Value::symbol("x"), Value::Nil),
2369            ),
2370        );
2371
2372        let app_expr = Value::cons(
2373            lambda_expr,
2374            Value::cons(Value::integer(1), Value::cons(Value::integer(2), Value::Nil)),
2375        );
2376
2377        let result = eval.eval(app_expr, env);
2378        assert!(result.is_err());
2379    }
2380
2381    #[test]
2382    fn test_eval_lambda_closure() {
2383        let mut eval = Evaluator::new();
2384        let env = make_env();
2385
2386        // (define x 10)
2387        env.define("x", Value::integer(10));
2388
2389        // ((lambda (y) x) 20)
2390        // Should capture x from outer environment and ignore y
2391        let lambda_expr = Value::cons(
2392            Value::symbol("lambda"),
2393            Value::cons(
2394                Value::cons(Value::symbol("y"), Value::Nil),
2395                Value::cons(Value::symbol("x"), Value::Nil),
2396            ),
2397        );
2398
2399        let app_expr = Value::cons(lambda_expr, Value::cons(Value::integer(20), Value::Nil));
2400
2401        let result = eval.eval(app_expr, env).unwrap();
2402        if let Value::Integer(n) = result {
2403            assert_eq!(n, 10); // Should get x from outer environment
2404        } else {
2405            panic!("Expected integer 10 from closure");
2406        }
2407    }
2408
2409    #[test]
2410    fn test_eval_lambda_no_params() {
2411        let mut eval = Evaluator::new();
2412        let env = make_env();
2413
2414        // ((lambda () 42))
2415        let lambda_expr = Value::cons(
2416            Value::symbol("lambda"),
2417            Value::cons(Value::Nil, Value::cons(Value::integer(42), Value::Nil)),
2418        );
2419
2420        let app_expr = Value::cons(lambda_expr, Value::Nil);
2421
2422        let result = eval.eval(app_expr, env).unwrap();
2423        if let Value::Integer(n) = result {
2424            assert_eq!(n, 42);
2425        } else {
2426            panic!("Expected integer 42");
2427        }
2428    }
2429
2430    #[test]
2431    fn test_eval_lambda_multiple_body_expressions() {
2432        let mut eval = Evaluator::new();
2433        let env = make_env();
2434
2435        // ((lambda (x) 1 2 x) 99)
2436        // Should return x (last expression)
2437        let params = Value::cons(Value::symbol("x"), Value::Nil);
2438        let body1 = Value::integer(1);
2439        let body2 = Value::integer(2);
2440        let body3 = Value::symbol("x");
2441
2442        let lambda_expr = Value::cons(
2443            Value::symbol("lambda"),
2444            Value::cons(
2445                params,
2446                Value::cons(body1, Value::cons(body2, Value::cons(body3, Value::Nil))),
2447            ),
2448        );
2449
2450        let app_expr = Value::cons(lambda_expr, Value::cons(Value::integer(99), Value::Nil));
2451
2452        let result = eval.eval(app_expr, env).unwrap();
2453        if let Value::Integer(n) = result {
2454            assert_eq!(n, 99);
2455        } else {
2456            panic!("Expected integer 99");
2457        }
2458    }
2459
2460    #[test]
2461    fn test_element_rule_multiple_sosofos_error() {
2462        let mut eval = Evaluator::new();
2463        let env = make_env();
2464
2465        // (element foo expr1 expr2) - should error
2466        let expr = Value::cons(
2467            Value::symbol("element"),
2468            Value::cons(
2469                Value::symbol("foo"),
2470                Value::cons(
2471                    Value::symbol("expr1"),
2472                    Value::cons(Value::symbol("expr2"), Value::Nil),
2473                ),
2474            ),
2475        );
2476
2477        let result = eval.eval(expr, env);
2478        assert!(result.is_err());
2479        let err_msg = result.unwrap_err().to_string();
2480        assert!(err_msg.contains("can only contain one sosofo expression"));
2481        assert!(err_msg.contains("sosofo-append"));
2482    }
2483
2484    #[test]
2485    fn test_element_rule_single_sosofo_ok() {
2486        let mut eval = Evaluator::new();
2487        let env = make_env();
2488
2489        // (element foo expr) - should succeed
2490        let expr = Value::cons(
2491            Value::symbol("element"),
2492            Value::cons(
2493                Value::symbol("foo"),
2494                Value::cons(Value::symbol("expr"), Value::Nil),
2495            ),
2496        );
2497
2498        let result = eval.eval(expr, env);
2499        assert!(result.is_ok());
2500    }
2501
2502    #[test]
2503    fn test_default_rule_multiple_sosofos_error() {
2504        let mut eval = Evaluator::new();
2505        let env = make_env();
2506
2507        // (default expr1 expr2) - should error
2508        let expr = Value::cons(
2509            Value::symbol("default"),
2510            Value::cons(
2511                Value::symbol("expr1"),
2512                Value::cons(Value::symbol("expr2"), Value::Nil),
2513            ),
2514        );
2515
2516        let result = eval.eval(expr, env);
2517        assert!(result.is_err());
2518        let err_msg = result.unwrap_err().to_string();
2519        assert!(err_msg.contains("can only contain one sosofo expression"));
2520        assert!(err_msg.contains("sosofo-append"));
2521    }
2522
2523    #[test]
2524    fn test_default_rule_single_sosofo_ok() {
2525        let mut eval = Evaluator::new();
2526        let env = make_env();
2527
2528        // (default expr) - should succeed
2529        let expr = Value::cons(
2530            Value::symbol("default"),
2531            Value::cons(Value::symbol("expr"), Value::Nil),
2532        );
2533
2534        let result = eval.eval(expr, env);
2535        assert!(result.is_ok());
2536    }
2537}