oxur_repl/eval/
lisp_mode.rs

1//! Lisp Mode Evaluation
2//!
3//! Integrates with oxur-lang to parse and evaluate Lisp syntax.
4//! Provides Tier 1 (Calculator) fast-path evaluation for simple arithmetic.
5//!
6//! Based on ODD-0026: Oxur REPL Evaluation Strategy
7
8use crate::eval::{EvalError, Result};
9use oxur_lang::{CoreForm, Expander, Parser};
10use std::collections::HashMap;
11
12/// Typed value for REPL variable storage
13///
14/// Stores a value along with its Rust type annotation.
15/// Used exclusively for calculator-mode (Tier 1) REPL variables.
16///
17/// # Examples
18///
19/// ```
20/// use oxur_repl::eval::TypedValue;
21///
22/// let x = TypedValue::new(42, "i32");
23/// assert_eq!(x.value(), 42);
24/// assert_eq!(x.type_name(), "i32");
25/// ```
26#[derive(Debug, Clone, PartialEq, Eq)]
27pub struct TypedValue {
28    value: i64,
29    type_name: String,
30}
31
32impl TypedValue {
33    /// Create a new typed value
34    pub fn new(value: i64, type_name: impl Into<String>) -> Self {
35        Self { value, type_name: type_name.into() }
36    }
37
38    /// Get the value
39    pub fn value(&self) -> i64 {
40        self.value
41    }
42
43    /// Get the type name
44    pub fn type_name(&self) -> &str {
45        &self.type_name
46    }
47}
48
49/// Lisp mode evaluator
50///
51/// Integrates with oxur-lang for parsing and evaluation.
52/// Provides fast-path calculator mode for simple arithmetic.
53#[derive(Debug, Clone)]
54pub struct LispEvaluator {
55    /// REPL variables (calculator mode only)
56    variables: HashMap<String, TypedValue>,
57}
58
59impl LispEvaluator {
60    /// Create a new Lisp evaluator
61    pub fn new() -> Self {
62        Self { variables: HashMap::new() }
63    }
64
65    /// Try to evaluate code in calculator mode (Tier 1)
66    ///
67    /// Handles:
68    /// - Simple arithmetic: `(+ 1 2)` → `"3"`
69    /// - Variables: `x` → `"42"` (if defined)
70    /// - Variable definitions: `(def x:i32 42)` → `"42"`
71    ///
72    /// Returns `Some(result)` if successful, `None` if not calculator-eligible.
73    ///
74    /// Note: For `def` forms, errors are surfaced via `try_eval_with_errors()` instead.
75    pub fn try_eval_calculator(&mut self, code: impl AsRef<str>) -> Option<String> {
76        self.try_eval_with_errors(code).ok().flatten()
77    }
78
79    /// Try to evaluate code in calculator mode, distinguishing between errors and ineligibility
80    ///
81    /// Returns:
82    /// - `Ok(Some(result))` if evaluation succeeded
83    /// - `Ok(None)` if not calculator-eligible (should fall through to compilation)
84    /// - `Err(error)` if there was an actual error (e.g., def syntax error)
85    pub fn try_eval_with_errors(&mut self, code: impl AsRef<str>) -> Result<Option<String>> {
86        // Parse the code
87        let expr = match self.parse_simple(code.as_ref()) {
88            Ok(expr) => expr,
89            Err(_) => return Ok(None), // Parse failure means not calculator-eligible
90        };
91
92        // Check if it's a def form - errors should be surfaced
93        if let Expr::List(ref elements) = expr {
94            if let Some(Expr::Symbol(op)) = elements.first() {
95                if op == "def" {
96                    return self.eval_def(&elements[1..]).map(Some);
97                }
98            }
99        }
100
101        // Evaluate as calculator expression
102        match self.eval_calculator_expr(&expr) {
103            Ok(result) => Ok(Some(result)),
104            Err(_) => Ok(None), // Errors in non-def expressions mean not calculator-eligible
105        }
106    }
107
108    /// Get all defined variables for hybrid compilation
109    ///
110    /// Returns a list of (variable_name, type_name) pairs.
111    /// Used when compiling code that references calculator-mode variables.
112    ///
113    /// # Examples
114    ///
115    /// ```
116    /// use oxur_repl::eval::LispEvaluator;
117    ///
118    /// let mut eval = LispEvaluator::new();
119    /// eval.try_eval_calculator("(def x:i32 42)");
120    /// eval.try_eval_calculator("(def y:i64 100)");
121    ///
122    /// let vars = eval.get_variables();
123    /// assert_eq!(vars.len(), 2);
124    /// ```
125    pub fn get_variables(&self) -> Vec<(String, String)> {
126        self.variables
127            .iter()
128            .map(|(name, typed_value)| (name.clone(), typed_value.type_name().to_string()))
129            .collect()
130    }
131
132    /// Get a specific variable's value
133    ///
134    /// Returns the value as a string if the variable exists.
135    pub fn get_variable_value(&self, name: &str) -> Option<String> {
136        self.variables.get(name).map(|v| v.value().to_string())
137    }
138
139    /// Parse simple Lisp expression
140    ///
141    /// Handles basic s-expression syntax:
142    /// - Numbers: `42`, `-5`, `123`
143    /// - Symbols: `+`, `-`, `*`, `/`, `foo`, `bar`
144    /// - Lists: `(+ 1 2)`, `(foo bar baz)`
145    fn parse_simple(&mut self, code: &str) -> Result<Expr> {
146        let trimmed = code.trim();
147        if trimmed.is_empty() {
148            return Err(EvalError::SyntaxError {
149                msg: "Empty expression".to_string(),
150                pos: oxur_smap::SourcePos::repl(1, 1, 1),
151            });
152        }
153
154        // Try to parse as number first
155        if let Ok(num) = trimmed.parse::<i64>() {
156            return Ok(Expr::Number(num));
157        }
158
159        // Check if it's a list
160        if trimmed.starts_with('(') && trimmed.ends_with(')') {
161            return self.parse_list(trimmed);
162        }
163
164        // Otherwise, it's a symbol
165        Ok(Expr::Symbol(trimmed.to_string()))
166    }
167
168    /// Parse a list expression: `(op arg1 arg2 ...)`
169    fn parse_list(&mut self, code: &str) -> Result<Expr> {
170        // Remove outer parentheses
171        let inner = &code[1..code.len() - 1].trim();
172
173        if inner.is_empty() {
174            return Ok(Expr::List(vec![]));
175        }
176
177        // Tokenize the inner content (returns owned strings)
178        let tokens = self.tokenize(inner)?;
179
180        // Parse each token
181        let mut elements = Vec::new();
182        for token in tokens {
183            elements.push(self.parse_simple(&token)?);
184        }
185
186        Ok(Expr::List(elements))
187    }
188
189    /// Tokenize a string into s-expression tokens
190    ///
191    /// Handles nested parentheses correctly:
192    /// `(+ (* 2 3) 4)` → `["+", "(* 2 3)", "4"]`
193    fn tokenize(&self, input: &str) -> Result<Vec<String>> {
194        let mut tokens = Vec::new();
195        let mut current_start = 0;
196        let mut depth = 0;
197        let bytes = input.as_bytes();
198
199        for (i, &byte) in bytes.iter().enumerate() {
200            match byte {
201                b'(' => {
202                    if depth == 0 && i > current_start {
203                        let token = input[current_start..i].trim();
204                        if !token.is_empty() {
205                            tokens.push(token.to_string());
206                        }
207                        current_start = i;
208                    }
209                    depth += 1;
210                }
211                b')' => {
212                    depth -= 1;
213                    if depth == 0 {
214                        let token = input[current_start..=i].trim();
215                        if !token.is_empty() {
216                            tokens.push(token.to_string());
217                        }
218                        current_start = i + 1;
219                    }
220                }
221                b' ' | b'\t' | b'\n' => {
222                    if depth == 0 && i > current_start {
223                        let token = input[current_start..i].trim();
224                        if !token.is_empty() {
225                            tokens.push(token.to_string());
226                        }
227                        current_start = i + 1;
228                    }
229                }
230                _ => {}
231            }
232        }
233
234        // Handle final token
235        if current_start < input.len() {
236            let token = input[current_start..].trim();
237            if !token.is_empty() {
238                tokens.push(token.to_string());
239            }
240        }
241
242        if depth != 0 {
243            return Err(EvalError::SyntaxError {
244                msg: "Mismatched parentheses".to_string(),
245                pos: oxur_smap::SourcePos::repl(1, 1, 1),
246            });
247        }
248
249        Ok(tokens)
250    }
251
252    /// Evaluate a calculator expression
253    fn eval_calculator_expr(&self, expr: &Expr) -> Result<String> {
254        match expr {
255            Expr::Number(n) => Ok(n.to_string()),
256
257            Expr::Symbol(s) => {
258                // Try to look up variable
259                if let Some(typed_value) = self.variables.get(s) {
260                    Ok(typed_value.value().to_string())
261                } else {
262                    Err(EvalError::RuntimeError {
263                        msg: format!("Undefined variable: {}", s),
264                        pos: oxur_smap::SourcePos::repl(1, 1, 1),
265                    })
266                }
267            }
268
269            Expr::List(elements) => {
270                if elements.is_empty() {
271                    return Err(EvalError::SyntaxError {
272                        msg: "Empty list".to_string(),
273                        pos: oxur_smap::SourcePos::repl(1, 1, 1),
274                    });
275                }
276
277                // First element should be an operator
278                let op = match &elements[0] {
279                    Expr::Symbol(s) => s.as_str(),
280                    _ => {
281                        return Err(EvalError::SyntaxError {
282                            msg: "First element must be an operator".to_string(),
283                            pos: oxur_smap::SourcePos::repl(1, 1, 1),
284                        })
285                    }
286                };
287
288                // Evaluate arguments
289                let args: Result<Vec<i64>> = elements[1..]
290                    .iter()
291                    .map(|e| {
292                        let result = self.eval_calculator_expr(e)?;
293                        result.parse::<i64>().map_err(|_| EvalError::RuntimeError {
294                            msg: format!("Not a number: {}", result),
295                            pos: oxur_smap::SourcePos::repl(1, 1, 1),
296                        })
297                    })
298                    .collect();
299
300                let args = args?;
301
302                // Apply operator
303                self.apply_operator(op, &args)
304            }
305        }
306    }
307
308    /// Apply an arithmetic operator to arguments
309    fn apply_operator(&self, op: &str, args: &[i64]) -> Result<String> {
310        if args.is_empty() {
311            return Err(EvalError::SyntaxError {
312                msg: format!("Operator '{}' requires at least one argument", op),
313                pos: oxur_smap::SourcePos::repl(1, 1, 1),
314            });
315        }
316
317        match op {
318            "+" => {
319                let sum: i64 = args.iter().sum();
320                Ok(sum.to_string())
321            }
322            "-" => {
323                if args.len() == 1 {
324                    Ok((-args[0]).to_string())
325                } else {
326                    let result = args.iter().skip(1).fold(args[0], |acc, &x| acc - x);
327                    Ok(result.to_string())
328                }
329            }
330            "*" => {
331                let product: i64 = args.iter().product();
332                Ok(product.to_string())
333            }
334            "/" => {
335                if args.len() == 1 {
336                    return Err(EvalError::RuntimeError {
337                        msg: "Division requires at least two arguments".to_string(),
338                        pos: oxur_smap::SourcePos::repl(1, 1, 1),
339                    });
340                }
341
342                let result = args.iter().skip(1).try_fold(args[0], |acc, &x| {
343                    if x == 0 {
344                        Err(EvalError::RuntimeError {
345                            msg: "Division by zero".to_string(),
346                            pos: oxur_smap::SourcePos::repl(1, 1, 1),
347                        })
348                    } else {
349                        Ok(acc / x)
350                    }
351                })?;
352
353                Ok(result.to_string())
354            }
355            _ => Err(EvalError::UnsupportedOperation {
356                msg: format!("Unknown operator in calculator mode: {}", op),
357                pos: oxur_smap::SourcePos::repl(1, 1, 1),
358            }),
359        }
360    }
361
362    /// Evaluate a def form: `(def varname:type value)`
363    ///
364    /// Defines a typed variable in calculator mode.
365    /// The value expression is evaluated and stored with its type annotation.
366    ///
367    /// # Arguments
368    ///
369    /// * `args` - Arguments after the `def` symbol: `[varname:type, value]`
370    ///
371    /// # Returns
372    ///
373    /// The value as a string if successful
374    ///
375    /// # Errors
376    ///
377    /// Returns error if:
378    /// - Wrong number of arguments
379    /// - Invalid type annotation syntax
380    /// - Type name is not a valid integer type
381    /// - Value expression fails to evaluate
382    fn eval_def(&mut self, args: &[Expr]) -> Result<String> {
383        // Expect exactly 2 arguments: varname:type and value
384        if args.len() != 2 {
385            return Err(EvalError::SyntaxError {
386                msg: format!("def requires 2 arguments, got {}", args.len()),
387                pos: oxur_smap::SourcePos::repl(1, 1, 1),
388            });
389        }
390
391        // Parse the typed identifier (varname:type)
392        let (var_name, type_name) = self.parse_typed_identifier(&args[0])?;
393
394        // Validate type name (for now, only i32 and i64)
395        if type_name != "i32" && type_name != "i64" {
396            return Err(EvalError::TypeError {
397                msg: format!(
398                    "Only i32 and i64 types are supported in calculator mode, got: {}",
399                    type_name
400                ),
401                pos: oxur_smap::SourcePos::repl(1, 1, 1),
402            });
403        }
404
405        // Evaluate the value expression
406        let value_str = self.eval_calculator_expr(&args[1])?;
407        let value = value_str.parse::<i64>().map_err(|_| EvalError::RuntimeError {
408            msg: format!("Value must be an integer, got: {}", value_str),
409            pos: oxur_smap::SourcePos::repl(1, 1, 1),
410        })?;
411
412        // Store the variable
413        self.variables.insert(var_name.clone(), TypedValue::new(value, type_name));
414
415        // Return the value
416        Ok(value.to_string())
417    }
418
419    /// Parse a typed identifier: `varname:type`
420    ///
421    /// # Arguments
422    ///
423    /// * `expr` - Expression that should be a symbol containing `:`
424    ///
425    /// # Returns
426    ///
427    /// Tuple of (variable_name, type_name)
428    ///
429    /// # Errors
430    ///
431    /// Returns error if the syntax is invalid
432    fn parse_typed_identifier(&self, expr: &Expr) -> Result<(String, String)> {
433        match expr {
434            Expr::Symbol(s) => {
435                // Parse "varname:type" syntax
436                if let Some(colon_pos) = s.find(':') {
437                    let var_name = s[..colon_pos].to_string();
438                    let type_name = s[colon_pos + 1..].to_string();
439
440                    if var_name.is_empty() {
441                        return Err(EvalError::SyntaxError {
442                            msg: "Variable name cannot be empty".to_string(),
443                            pos: oxur_smap::SourcePos::repl(1, 1, 1),
444                        });
445                    }
446
447                    if type_name.is_empty() {
448                        return Err(EvalError::SyntaxError {
449                            msg: "Type name cannot be empty".to_string(),
450                            pos: oxur_smap::SourcePos::repl(1, 1, 1),
451                        });
452                    }
453
454                    Ok((var_name, type_name))
455                } else {
456                    Err(EvalError::SyntaxError {
457                        msg: format!("Expected type annotation 'varname:type', got: {}", s),
458                        pos: oxur_smap::SourcePos::repl(1, 1, 1),
459                    })
460                }
461            }
462            _ => Err(EvalError::SyntaxError {
463                msg: "Expected symbol with type annotation".to_string(),
464                pos: oxur_smap::SourcePos::repl(1, 1, 1),
465            }),
466        }
467    }
468
469    /// Parse code using the full oxur-lang compilation pipeline
470    ///
471    /// This integrates with oxur-lang's Parser (Stage 1) and Expander (Stage 2)
472    /// to convert Oxur source code into Core Forms (IR).
473    pub fn parse(&mut self, code: impl AsRef<str>) -> Result<Vec<CoreForm>> {
474        // Stage 1: Parse source → SurfaceForm
475        let mut parser = Parser::new(code.as_ref().to_string());
476        let surface_forms = parser.parse().map_err(|e| EvalError::SyntaxError {
477            msg: format!("Parse error: {}", e),
478            pos: oxur_smap::SourcePos::repl(1, 1, 1),
479        })?;
480
481        // Stage 2: Expand SurfaceForm → CoreForm (macro expansion, deffn, etc.)
482        let mut expander = Expander::new();
483        expander.expand(surface_forms).map_err(|e| EvalError::SyntaxError {
484            msg: format!("Expansion error: {}", e),
485            pos: oxur_smap::SourcePos::repl(1, 1, 1),
486        })
487    }
488}
489
490impl Default for LispEvaluator {
491    fn default() -> Self {
492        Self::new()
493    }
494}
495
496/// Simple expression type for calculator mode
497#[derive(Debug, Clone, PartialEq)]
498enum Expr {
499    Number(i64),
500    Symbol(String),
501    List(Vec<Expr>),
502}
503
504#[cfg(test)]
505mod tests {
506    use super::*;
507
508    #[test]
509    fn test_calculator_simple_addition() {
510        let mut eval = LispEvaluator::new();
511        assert_eq!(eval.try_eval_calculator("(+ 1 2)"), Some("3".to_string()));
512    }
513
514    #[test]
515    fn test_calculator_simple_subtraction() {
516        let mut eval = LispEvaluator::new();
517        assert_eq!(eval.try_eval_calculator("(- 10 5)"), Some("5".to_string()));
518    }
519
520    #[test]
521    fn test_calculator_simple_multiplication() {
522        let mut eval = LispEvaluator::new();
523        assert_eq!(eval.try_eval_calculator("(* 3 4)"), Some("12".to_string()));
524    }
525
526    #[test]
527    fn test_calculator_simple_division() {
528        let mut eval = LispEvaluator::new();
529        assert_eq!(eval.try_eval_calculator("(/ 10 2)"), Some("5".to_string()));
530    }
531
532    #[test]
533    fn test_calculator_multiple_args() {
534        let mut eval = LispEvaluator::new();
535        assert_eq!(eval.try_eval_calculator("(+ 1 2 3 4)"), Some("10".to_string()));
536        assert_eq!(eval.try_eval_calculator("(* 2 3 4)"), Some("24".to_string()));
537    }
538
539    #[test]
540    fn test_calculator_nested_expressions() {
541        let mut eval = LispEvaluator::new();
542        assert_eq!(eval.try_eval_calculator("(+ (* 2 3) 4)"), Some("10".to_string()));
543        assert_eq!(eval.try_eval_calculator("(* (+ 1 2) (- 10 5))"), Some("15".to_string()));
544    }
545
546    #[test]
547    fn test_calculator_unary_minus() {
548        let mut eval = LispEvaluator::new();
549        assert_eq!(eval.try_eval_calculator("(- 5)"), Some("-5".to_string()));
550    }
551
552    #[test]
553    fn test_calculator_division_by_zero() {
554        let mut eval = LispEvaluator::new();
555        assert_eq!(eval.try_eval_calculator("(/ 10 0)"), None);
556    }
557
558    #[test]
559    fn test_calculator_invalid_operator() {
560        let mut eval = LispEvaluator::new();
561        assert_eq!(eval.try_eval_calculator("(foo 1 2)"), None);
562    }
563
564    #[test]
565    fn test_calculator_variables_not_supported() {
566        let mut eval = LispEvaluator::new();
567        assert_eq!(eval.try_eval_calculator("(+ x 2)"), None);
568    }
569
570    #[test]
571    fn test_calculator_empty_list() {
572        let mut eval = LispEvaluator::new();
573        assert_eq!(eval.try_eval_calculator("()"), None);
574    }
575
576    #[test]
577    fn test_parse_simple_number() {
578        let mut eval = LispEvaluator::new();
579        let expr = eval.parse_simple("42").unwrap();
580        assert_eq!(expr, Expr::Number(42));
581    }
582
583    #[test]
584    fn test_parse_simple_symbol() {
585        let mut eval = LispEvaluator::new();
586        let expr = eval.parse_simple("+").unwrap();
587        assert_eq!(expr, Expr::Symbol("+".to_string()));
588    }
589
590    #[test]
591    fn test_parse_simple_list() {
592        let mut eval = LispEvaluator::new();
593        let expr = eval.parse_simple("(+ 1 2)").unwrap();
594        assert_eq!(
595            expr,
596            Expr::List(vec![Expr::Symbol("+".to_string()), Expr::Number(1), Expr::Number(2),])
597        );
598    }
599
600    #[test]
601    fn test_parse_nested_list() {
602        let mut eval = LispEvaluator::new();
603        let expr = eval.parse_simple("(+ (* 2 3) 4)").unwrap();
604        assert_eq!(
605            expr,
606            Expr::List(vec![
607                Expr::Symbol("+".to_string()),
608                Expr::List(vec![Expr::Symbol("*".to_string()), Expr::Number(2), Expr::Number(3),]),
609                Expr::Number(4),
610            ])
611        );
612    }
613
614    #[test]
615    fn test_tokenize_simple() {
616        let eval = LispEvaluator::new();
617        let tokens = eval.tokenize("+ 1 2").unwrap();
618        assert_eq!(tokens, vec!["+".to_string(), "1".to_string(), "2".to_string()]);
619    }
620
621    #[test]
622    fn test_tokenize_nested() {
623        let eval = LispEvaluator::new();
624        let tokens = eval.tokenize("+ (* 2 3) 4").unwrap();
625        assert_eq!(tokens, vec!["+".to_string(), "(* 2 3)".to_string(), "4".to_string()]);
626    }
627
628    #[test]
629    fn test_tokenize_mismatched_parens() {
630        let eval = LispEvaluator::new();
631        let result = eval.tokenize("(+ 1 2");
632        assert!(result.is_err());
633    }
634
635    #[test]
636    fn test_apply_operator_addition() {
637        let eval = LispEvaluator::new();
638        assert_eq!(eval.apply_operator("+", &[1, 2, 3]).unwrap(), "6");
639    }
640
641    #[test]
642    fn test_apply_operator_subtraction() {
643        let eval = LispEvaluator::new();
644        assert_eq!(eval.apply_operator("-", &[10, 3, 2]).unwrap(), "5");
645    }
646
647    #[test]
648    fn test_apply_operator_multiplication() {
649        let eval = LispEvaluator::new();
650        assert_eq!(eval.apply_operator("*", &[2, 3, 4]).unwrap(), "24");
651    }
652
653    #[test]
654    fn test_apply_operator_division() {
655        let eval = LispEvaluator::new();
656        assert_eq!(eval.apply_operator("/", &[20, 2, 2]).unwrap(), "5");
657    }
658
659    #[test]
660    fn test_apply_operator_unknown() {
661        let eval = LispEvaluator::new();
662        assert!(eval.apply_operator("foo", &[1, 2]).is_err());
663    }
664
665    #[test]
666    fn test_parse_simple_expression() {
667        let mut eval = LispEvaluator::new();
668        let forms = eval.parse("42").unwrap();
669
670        assert_eq!(forms.len(), 1);
671        match &forms[0] {
672            CoreForm::Number { value, .. } => assert_eq!(value, &42),
673            _ => panic!("Expected Number"),
674        }
675    }
676
677    #[test]
678    fn test_parse_symbol() {
679        let mut eval = LispEvaluator::new();
680        let forms = eval.parse("test-symbol").unwrap();
681
682        assert_eq!(forms.len(), 1);
683        match &forms[0] {
684            CoreForm::Symbol { name, .. } => assert_eq!(name, "test-symbol"),
685            _ => panic!("Expected Symbol"),
686        }
687    }
688
689    #[test]
690    fn test_parse_string() {
691        let mut eval = LispEvaluator::new();
692        let forms = eval.parse(r#""hello world""#).unwrap();
693
694        assert_eq!(forms.len(), 1);
695        match &forms[0] {
696            CoreForm::String { value, .. } => assert_eq!(value, "hello world"),
697            _ => panic!("Expected String"),
698        }
699    }
700
701    #[test]
702    fn test_parse_list() {
703        let mut eval = LispEvaluator::new();
704        let forms = eval.parse("(+ 1 2)").unwrap();
705
706        assert_eq!(forms.len(), 1);
707        match &forms[0] {
708            CoreForm::List { elements, .. } => assert_eq!(elements.len(), 3),
709            _ => panic!("Expected List"),
710        }
711    }
712
713    #[test]
714    fn test_parse_deffn_expands_to_define_func() {
715        let mut eval = LispEvaluator::new();
716        let forms = eval.parse(r#"(deffn main () (println! "Hello"))"#).unwrap();
717
718        assert_eq!(forms.len(), 1);
719
720        // deffn should expand to DefineFunc, not remain as List
721        match &forms[0] {
722            CoreForm::DefineFunc { name, params, body, .. } => {
723                assert_eq!(name, "main");
724                assert!(params.is_empty());
725
726                // Body should be the (println! "Hello") list
727                match &**body {
728                    CoreForm::List { elements, .. } => {
729                        assert_eq!(elements.len(), 2);
730                        match &elements[0] {
731                            CoreForm::Symbol { name, .. } => assert_eq!(name, "println!"),
732                            _ => panic!("Expected println! symbol"),
733                        }
734                    }
735                    _ => panic!("Expected List as body"),
736                }
737            }
738            other => panic!("Expected DefineFunc, got {:?}", other),
739        }
740    }
741
742    #[test]
743    fn test_parse_deffn_with_params() {
744        let mut eval = LispEvaluator::new();
745        let forms = eval.parse("(deffn add (a b) (+ a b))").unwrap();
746
747        assert_eq!(forms.len(), 1);
748
749        match &forms[0] {
750            CoreForm::DefineFunc { name, params, .. } => {
751                assert_eq!(name, "add");
752                assert_eq!(params.len(), 2);
753                assert_eq!(params[0], "a");
754                assert_eq!(params[1], "b");
755            }
756            other => panic!("Expected DefineFunc, got {:?}", other),
757        }
758    }
759
760    // ===== Tests for def feature =====
761
762    #[test]
763    fn test_def_simple_literal() {
764        let mut eval = LispEvaluator::new();
765        let result = eval.try_eval_calculator("(def x:i32 42)");
766        assert_eq!(result, Some("42".to_string()));
767    }
768
769    #[test]
770    fn test_def_with_i64() {
771        let mut eval = LispEvaluator::new();
772        let result = eval.try_eval_calculator("(def y:i64 1000)");
773        assert_eq!(result, Some("1000".to_string()));
774    }
775
776    #[test]
777    fn test_def_with_expression() {
778        let mut eval = LispEvaluator::new();
779        let result = eval.try_eval_calculator("(def z:i32 (+ 1 2))");
780        assert_eq!(result, Some("3".to_string()));
781    }
782
783    #[test]
784    fn test_def_with_nested_expression() {
785        let mut eval = LispEvaluator::new();
786        let result = eval.try_eval_calculator("(def result:i32 (* (+ 2 3) 4))");
787        assert_eq!(result, Some("20".to_string()));
788    }
789
790    #[test]
791    fn test_variable_lookup_after_def() {
792        let mut eval = LispEvaluator::new();
793
794        // Define variable
795        eval.try_eval_calculator("(def x:i32 42)");
796
797        // Look it up
798        let result = eval.try_eval_calculator("x");
799        assert_eq!(result, Some("42".to_string()));
800    }
801
802    #[test]
803    fn test_use_variable_in_expression() {
804        let mut eval = LispEvaluator::new();
805
806        // Define variable
807        eval.try_eval_calculator("(def x:i32 10)");
808
809        // Use in expression
810        let result = eval.try_eval_calculator("(+ x 5)");
811        assert_eq!(result, Some("15".to_string()));
812    }
813
814    #[test]
815    fn test_multiple_variables() {
816        let mut eval = LispEvaluator::new();
817
818        eval.try_eval_calculator("(def x:i32 10)");
819        eval.try_eval_calculator("(def y:i32 20)");
820        eval.try_eval_calculator("(def z:i32 5)");
821
822        let result = eval.try_eval_calculator("(+ x y z)");
823        assert_eq!(result, Some("35".to_string()));
824    }
825
826    #[test]
827    fn test_def_using_existing_variable() {
828        let mut eval = LispEvaluator::new();
829
830        eval.try_eval_calculator("(def x:i32 10)");
831        eval.try_eval_calculator("(def y:i32 (+ x 5))");
832
833        let result = eval.try_eval_calculator("y");
834        assert_eq!(result, Some("15".to_string()));
835    }
836
837    #[test]
838    fn test_variable_shadowing() {
839        let mut eval = LispEvaluator::new();
840
841        eval.try_eval_calculator("(def x:i32 10)");
842        assert_eq!(eval.try_eval_calculator("x"), Some("10".to_string()));
843
844        // Redefine x
845        eval.try_eval_calculator("(def x:i32 20)");
846        assert_eq!(eval.try_eval_calculator("x"), Some("20".to_string()));
847    }
848
849    #[test]
850    fn test_def_with_negative_value() {
851        let mut eval = LispEvaluator::new();
852        let result = eval.try_eval_calculator("(def neg:i32 (- 5))");
853        assert_eq!(result, Some("-5".to_string()));
854    }
855
856    #[test]
857    fn test_complex_expression_with_variables() {
858        let mut eval = LispEvaluator::new();
859
860        eval.try_eval_calculator("(def a:i32 10)");
861        eval.try_eval_calculator("(def b:i32 20)");
862        eval.try_eval_calculator("(def c:i32 (+ (* a 2) b))");
863
864        // a * 2 + b = 10 * 2 + 20 = 40
865        assert_eq!(eval.try_eval_calculator("c"), Some("40".to_string()));
866    }
867
868    // ===== Error case tests =====
869
870    #[test]
871    fn test_def_wrong_number_of_args_too_few() {
872        let mut eval = LispEvaluator::new();
873        let result = eval.try_eval_calculator("(def x:i32)");
874        assert_eq!(result, None); // Should fail
875    }
876
877    #[test]
878    fn test_def_wrong_number_of_args_too_many() {
879        let mut eval = LispEvaluator::new();
880        let result = eval.try_eval_calculator("(def x:i32 42 extra)");
881        assert_eq!(result, None); // Should fail
882    }
883
884    #[test]
885    fn test_def_missing_type_annotation() {
886        let mut eval = LispEvaluator::new();
887        let result = eval.try_eval_calculator("(def x 42)");
888        assert_eq!(result, None); // Should fail - no type annotation
889    }
890
891    #[test]
892    fn test_def_invalid_type() {
893        let mut eval = LispEvaluator::new();
894        let result = eval.try_eval_calculator("(def x:String 42)");
895        assert_eq!(result, None); // Should fail - String not supported
896    }
897
898    #[test]
899    fn test_def_invalid_type_f64() {
900        let mut eval = LispEvaluator::new();
901        let result = eval.try_eval_calculator("(def x:f64 42)");
902        assert_eq!(result, None); // Should fail - only i32/i64 supported
903    }
904
905    #[test]
906    fn test_undefined_variable_lookup() {
907        let mut eval = LispEvaluator::new();
908        let result = eval.try_eval_calculator("undefined_var");
909        assert_eq!(result, None); // Should fail - variable not defined
910    }
911
912    #[test]
913    fn test_undefined_variable_in_expression() {
914        let mut eval = LispEvaluator::new();
915        let result = eval.try_eval_calculator("(+ undefined_var 5)");
916        assert_eq!(result, None); // Should fail
917    }
918
919    #[test]
920    fn test_def_empty_variable_name() {
921        let mut eval = LispEvaluator::new();
922        let result = eval.try_eval_calculator("(def :i32 42)");
923        assert_eq!(result, None); // Should fail - empty variable name
924    }
925
926    #[test]
927    fn test_def_empty_type_name() {
928        let mut eval = LispEvaluator::new();
929        let result = eval.try_eval_calculator("(def x: 42)");
930        assert_eq!(result, None); // Should fail - empty type name
931    }
932
933    #[test]
934    fn test_def_no_colon_in_identifier() {
935        let mut eval = LispEvaluator::new();
936        let result = eval.try_eval_calculator("(def xi32 42)");
937        assert_eq!(result, None); // Should fail - no colon separator
938    }
939
940    #[test]
941    fn test_typed_value_creation() {
942        let val = TypedValue::new(42, "i32");
943        assert_eq!(val.value(), 42);
944        assert_eq!(val.type_name(), "i32");
945    }
946
947    #[test]
948    fn test_typed_value_equality() {
949        let val1 = TypedValue::new(42, "i32");
950        let val2 = TypedValue::new(42, "i32");
951        let val3 = TypedValue::new(43, "i32");
952        let val4 = TypedValue::new(42, "i64");
953
954        assert_eq!(val1, val2);
955        assert_ne!(val1, val3);
956        assert_ne!(val1, val4);
957    }
958
959    #[test]
960    fn test_typed_value_clone() {
961        let val1 = TypedValue::new(42, "i32");
962        let val2 = val1.clone();
963        assert_eq!(val1, val2);
964    }
965}