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