1
// Tests for lambda list keywords (&rest, &optional, etc.)
2
// These tests verify that the lambda list keyword infrastructure works correctly
3

            
4
use nomiscript::{
5
    Reader, eval_program,
6
    runtime::{SymbolTable, Value},
7
};
8
use num_rational::Ratio;
9

            
10
12
fn eval_expr(code: &str) -> Result<Value, nomiscript::Error> {
11
12
    let program = Reader::parse(code)?;
12
12
    let mut symbols = SymbolTable::with_builtins();
13
12
    eval_program(&mut symbols, &program)
14
12
}
15

            
16
fn num(n: i64) -> Value {
17
    Value::Number(Ratio::from_integer(n))
18
}
19

            
20
#[cfg(test)]
21
mod rest_parameter_tests {
22
    use super::*;
23

            
24
    #[test]
25
1
    fn test_lambda_with_rest_basic() {
26
1
        let result = eval_expr("((lambda (x &rest y) y) 1 2 3 4)");
27
1
        match &result {
28
            Err(e) => println!("Error: {e:?}"),
29
1
            Ok(v) => println!("Result: {v:?}"),
30
        }
31
1
        assert!(result.is_ok(), "Lambda with &rest should work");
32
1
    }
33

            
34
    #[test]
35
1
    fn test_lambda_with_rest_no_extra_args() {
36
1
        let result = eval_expr("((lambda (x &rest y) x) 42)");
37
1
        assert!(
38
1
            result.is_ok(),
39
            "Lambda with &rest and no extra args should work"
40
        );
41
1
    }
42

            
43
    #[test]
44
1
    fn test_defun_with_rest() {
45
1
        let code = r"
46
1
        (defun sum-all (first &rest others)
47
1
          first)
48
1
        (sum-all 10 20 30)
49
1
        ";
50
1
        let result = eval_expr(code);
51
1
        assert!(result.is_ok(), "DEFUN with &rest should work");
52
1
    }
53
}
54

            
55
#[cfg(test)]
56
mod optional_parameter_tests {
57
    use super::*;
58

            
59
    #[test]
60
1
    fn test_lambda_with_optional_no_default() {
61
1
        let result = eval_expr("((lambda (x &optional y) x) 42)");
62
1
        assert!(result.is_ok(), "Lambda with &optional should work");
63
1
    }
64

            
65
    #[test]
66
1
    fn test_lambda_with_optional_with_default() {
67
1
        let result = eval_expr("((lambda (x &optional (y 100)) x) 42)");
68
1
        assert!(
69
1
            result.is_ok(),
70
            "Lambda with &optional and default should work"
71
        );
72
1
    }
73

            
74
    #[test]
75
1
    fn test_defun_with_optional() {
76
1
        let code = r#"
77
1
        (defun greet (&optional (name "World"))
78
1
          name)
79
1
        (greet "Alice")
80
1
        "#;
81
1
        let result = eval_expr(code);
82
1
        assert!(result.is_ok(), "DEFUN with &optional should work");
83
1
    }
84
}
85

            
86
#[cfg(test)]
87
mod aux_parameter_tests {
88
    use super::*;
89

            
90
    #[test]
91
1
    fn test_lambda_with_aux() {
92
1
        let result = eval_expr("((lambda (x &aux (temp 42)) x) 10)");
93
1
        assert!(result.is_ok(), "Lambda with &aux should work");
94
1
    }
95

            
96
    #[test]
97
1
    fn test_defun_with_aux() {
98
1
        let code = r"
99
1
        (defun process (data &aux (result nil))
100
1
          data)
101
1
        (process 123)
102
1
        ";
103
1
        let result = eval_expr(code);
104
1
        assert!(result.is_ok(), "DEFUN with &aux should work");
105
1
    }
106
}
107

            
108
#[cfg(test)]
109
mod key_parameter_tests {
110
    use super::*;
111

            
112
    #[test]
113
1
    fn test_lambda_with_key_basic() {
114
1
        let result = eval_expr("((lambda (x &key name) x) 42 :name \"test\")");
115
1
        assert!(result.is_ok(), "Lambda with &key should work");
116
1
    }
117

            
118
    #[test]
119
1
    fn test_lambda_with_key_no_keyword_args() {
120
1
        let result = eval_expr("((lambda (x &key name) x) 42)");
121
1
        assert!(
122
1
            result.is_ok(),
123
            "Lambda with &key and no keyword args should work"
124
        );
125
1
    }
126

            
127
    #[test]
128
1
    fn test_defun_with_key() {
129
1
        let code = r#"
130
1
        (defun greet (person &key (greeting "Hello"))
131
1
          person)
132
1
        (greet "Alice" :greeting "Hi")
133
1
        "#;
134
1
        let result = eval_expr(code);
135
1
        assert!(result.is_ok(), "DEFUN with &key should work");
136
1
    }
137

            
138
    #[test]
139
1
    fn test_defmacro_with_key() {
140
1
        let code = r#"
141
1
        (defmacro test-macro (name &key (type "default"))
142
1
          (quote (+ 1 2)))
143
1
        (test-macro foo :type "custom")
144
1
        "#;
145
1
        let result = eval_expr(code);
146
1
        assert!(result.is_ok(), "DEFMACRO with &key should work");
147
1
    }
148
}