1
//! Extra LET / LET* / DEFVAR / DEFPARAMETER paths beyond the
2
//! basic runtime-binding tests.
3

            
4
use super::common::{compile_and_validate, compile_expect_error, wrap_with_runtime_ratio};
5

            
6
#[test]
7
1
fn let_with_constant_bindings() {
8
1
    compile_and_validate("(let ((x 1) (y 2)) (+ x y))");
9
1
}
10

            
11
#[test]
12
1
fn let_with_multiple_runtime_bindings_in_parallel() {
13
1
    compile_and_validate(&wrap_with_runtime_ratio(
14
1
        "(let ((a (+ X 1)) (b (+ X 2))) (+ a b))",
15
1
    ));
16
1
}
17

            
18
#[test]
19
1
fn let_star_sequential_bindings() {
20
1
    compile_and_validate(&wrap_with_runtime_ratio("(let* ((a X) (b (+ a 1))) b)"));
21
1
}
22

            
23
#[test]
24
1
fn let_missing_body_errors() {
25
1
    let err = compile_expect_error("(let ((x 1)))");
26
1
    assert!(err.contains("LET"), "got: {err}");
27
1
}
28

            
29
#[test]
30
1
fn let_star_missing_body_errors() {
31
1
    let err = compile_expect_error("(let* ((x 1)))");
32
1
    assert!(err.contains("LET*"), "got: {err}");
33
1
}
34

            
35
#[test]
36
1
fn defvar_constant_init() {
37
1
    compile_and_validate("(defvar my-var 42) my-var");
38
1
}
39

            
40
#[test]
41
1
fn defvar_with_doc_string() {
42
1
    compile_and_validate("(defvar pi 314/100 \"approximation\") pi");
43
1
}
44

            
45
#[test]
46
1
fn defparameter_constant_init() {
47
1
    compile_and_validate("(defparameter the-param 99) the-param");
48
1
}
49

            
50
#[test]
51
1
fn defvar_without_init_compiles() {
52
1
    compile_and_validate("(defvar my-var)");
53
1
}
54

            
55
#[test]
56
1
fn defparameter_missing_init_errors() {
57
1
    let err = compile_expect_error("(defparameter the-param)");
58
1
    assert!(err.contains("DEFPARAMETER"), "got: {err}");
59
1
}
60

            
61
#[test]
62
1
fn defun_with_optional_param() {
63
1
    compile_and_validate(
64
1
        "(defun greet (name &optional (suffix \"!\")) (upcase-string name)) (greet \"hi\")",
65
    );
66
1
}
67

            
68
#[test]
69
1
fn defun_with_rest_param() {
70
1
    compile_and_validate("(defun sum (&rest nums) 0) (sum 1 2 3)");
71
1
}
72

            
73
#[test]
74
1
fn defun_with_keyword_param() {
75
1
    compile_and_validate("(defun config (&key (level 0)) level) (config :level 5)");
76
1
}
77

            
78
#[test]
79
1
fn defun_with_doc_string() {
80
1
    compile_and_validate("(defun square (x) \"compute x squared\" (* x x)) (square 3)");
81
1
}
82

            
83
#[test]
84
1
fn nested_let_star() {
85
1
    compile_and_validate(&wrap_with_runtime_ratio(
86
1
        "(let* ((a X)) (let* ((b (+ a 1))) (let* ((c (* b 2))) c)))",
87
1
    ));
88
1
}
89

            
90
/// Regression (AFL): the setf-accumulator runtime-type walk (`binding::infer`)
91
/// sliced a binder body via `&elems[2..]` / `&elems[3..]` and panicked when a
92
/// nested binder form was too short to have a body — a malformed `(do)` /
93
/// `(dolist)` / `(let)` inside an accumulator body. The walk is best-effort, so
94
/// such a form must surface a structured compile error, never a slice panic.
95
#[test]
96
1
fn short_nested_binder_in_accumulator_body_does_not_panic() {
97
4
    for src in [
98
1
        "(let ((acc 0)) (setf acc (cons 1 acc)) (do))",
99
1
        "(let ((acc 0)) (setf acc (cons 1 acc)) (dolist))",
100
1
        "(let ((acc 0)) (setf acc (cons 1 acc)) (let))",
101
1
        "(let ((r nil)) (setf r (cons 1 r)) (do ((i 0)) ))",
102
4
    ] {
103
4
        // Must return an Err (caught by `compile_expect_error`) rather than
104
4
        // panicking — the assertion is simply that the call returns.
105
4
        let _ = compile_expect_error(src);
106
4
    }
107
1
}