dazzle_core/scheme/
evaluator.rs

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