1
use nms::interpreter::Interpreter;
2
use scripting::nomiscript::{Fraction, Value};
3

            
4
#[test]
5
1
fn test_defmacro_when() {
6
1
    let mut interp = Interpreter::new(false).unwrap();
7
1
    let results = interp
8
1
        .eval("(defmacro when (test body) (list 'if test body))\n(when (> 3 2) \"yes\")")
9
1
        .unwrap();
10
1
    assert_eq!(results, vec![Value::String("yes".to_string())]);
11
1
}
12

            
13
#[test]
14
1
fn test_defmacro_when_false() {
15
1
    let mut interp = Interpreter::new(false).unwrap();
16
1
    let results = interp
17
1
        .eval("(defmacro when (test body) (list 'if test body))\n(when (> 2 3) \"yes\")")
18
1
        .unwrap();
19
1
    assert_eq!(results, vec![Value::Nil]);
20
1
}
21

            
22
#[test]
23
1
fn test_defmacro_unless() {
24
1
    let mut interp = Interpreter::new(false).unwrap();
25
1
    let results = interp
26
1
        .eval("(defmacro unless (test body) (list 'if test nil body))\n(unless #f \"yes\")")
27
1
        .unwrap();
28
1
    assert_eq!(results, vec![Value::String("yes".to_string())]);
29
1
}
30

            
31
#[test]
32
1
fn test_defmacro_constant() {
33
1
    let mut interp = Interpreter::new(false).unwrap();
34
1
    let results = interp
35
1
        .eval("(defmacro always-42 () 42)\n(always-42)")
36
1
        .unwrap();
37
1
    assert_eq!(results, vec![Value::Number(Fraction::from_integer(42))]);
38
1
}
39

            
40
#[test]
41
1
fn test_defmacro_returns_name() {
42
1
    let mut interp = Interpreter::new(false).unwrap();
43
1
    let results = interp.eval("(defmacro my-m (x) x)").unwrap();
44
1
    assert_eq!(results, vec![Value::Symbol("MY-M".to_string())]);
45
1
}
46

            
47
#[test]
48
1
fn test_defmacro_arity_error() {
49
1
    let mut interp = Interpreter::new(false).unwrap();
50
1
    let result = interp.eval("(defmacro when (test body) (list 'if test body))\n(when (> 3 2))");
51
1
    assert!(result.is_err());
52
1
}
53

            
54
#[test]
55
1
fn test_defmacro_persistence() {
56
1
    let mut interp = Interpreter::new(false).unwrap();
57
1
    interp
58
1
        .eval("(defmacro when (test body) (list 'if test body))")
59
1
        .unwrap();
60
1
    let results = interp.eval("(when #t 42)").unwrap();
61
1
    assert_eq!(results, vec![Value::Number(Fraction::from_integer(42))]);
62
1
}
63

            
64
#[test]
65
1
fn test_defmacro_swap_args() {
66
1
    let mut interp = Interpreter::new(false).unwrap();
67
1
    let results = interp
68
1
        .eval("(defmacro swap-sub (a b) (list '- b a))\n(swap-sub 1 10)")
69
1
        .unwrap();
70
1
    assert_eq!(results, vec![Value::Number(Fraction::from_integer(9))]);
71
1
}
72

            
73
#[test]
74
1
fn test_defmacro_nested_expansion() {
75
1
    let mut interp = Interpreter::new(false).unwrap();
76
1
    let results = interp
77
1
        .eval("(defmacro when (test body) (list 'if test body))\n(when (when #t #t) 42)")
78
1
        .unwrap();
79
1
    assert_eq!(results, vec![Value::Number(Fraction::from_integer(42))]);
80
1
}
81

            
82
#[test]
83
1
fn test_defmacro_chained() {
84
1
    let mut interp = Interpreter::new(false).unwrap();
85
1
    let results = interp
86
1
        .eval("(defmacro when (test body) (list 'if test body))\n(defmacro my-when (test body) (list 'when test body))\n(my-when (> 3 2) \"yes\")")
87
1
        .unwrap();
88
1
    assert_eq!(results, vec![Value::String("yes".to_string())]);
89
1
}
90

            
91
#[test]
92
1
fn test_defmacro_bare_value_error() {
93
1
    let mut interp = Interpreter::new(false).unwrap();
94
1
    interp
95
1
        .eval("(defmacro when (test body) (list 'if test body))")
96
1
        .unwrap();
97
1
    let err = interp.eval("when").unwrap_err();
98
1
    assert!(
99
1
        err.to_string().contains("macro"),
100
        "expected macro error, got: {err}"
101
    );
102
1
}
103

            
104
// MACROEXPAND-1
105

            
106
#[test]
107
1
fn test_macroexpand_1_macro() {
108
1
    let mut interp = Interpreter::new(false).unwrap();
109
1
    let results = interp
110
1
        .eval("(defmacro when (test body) (list 'if test body))\n(macroexpand-1 '(when #t 42))")
111
1
        .unwrap();
112
1
    assert_eq!(results, vec![Value::String("('IF #T 42)".to_string())]);
113
1
}
114

            
115
#[test]
116
1
fn test_macroexpand_1_non_macro() {
117
1
    let mut interp = Interpreter::new(false).unwrap();
118
1
    let results = interp.eval("(macroexpand-1 '(+ 1 2))").unwrap();
119
1
    assert_eq!(results, vec![Value::String("(+ 1 2)".to_string())]);
120
1
}
121

            
122
// MACROEXPAND
123

            
124
#[test]
125
1
fn test_macroexpand_repeated() {
126
1
    let mut interp = Interpreter::new(false).unwrap();
127
1
    let results = interp
128
1
        .eval("(defmacro when (test body) (list 'if test body))\n(defmacro my-when (test body) (list 'when test body))\n(macroexpand '(my-when #t 42))")
129
1
        .unwrap();
130
1
    assert_eq!(results, vec![Value::String("('IF #T 42)".to_string())]);
131
1
}
132

            
133
// QUASIQUOTE
134

            
135
#[test]
136
1
fn test_quasiquote_when() {
137
1
    let mut interp = Interpreter::new(false).unwrap();
138
1
    let results = interp
139
1
        .eval("(defmacro when (test body) `(if ,test ,body))\n(when (> 3 2) \"yes\")")
140
1
        .unwrap();
141
1
    assert_eq!(results, vec![Value::String("yes".to_string())]);
142
1
}
143

            
144
#[test]
145
1
fn test_quasiquote_unless() {
146
1
    let mut interp = Interpreter::new(false).unwrap();
147
1
    let results = interp
148
1
        .eval("(defmacro unless (test body) `(if ,test nil ,body))\n(unless #f \"yes\")")
149
1
        .unwrap();
150
1
    assert_eq!(results, vec![Value::String("yes".to_string())]);
151
1
}
152

            
153
#[test]
154
1
fn test_quasiquote_unquote_splicing() {
155
1
    let mut interp = Interpreter::new(false).unwrap();
156
1
    let results = interp
157
1
        .eval("(defmacro listify (&rest xs) `(list ,@xs))\n(listify 1 2 3)")
158
1
        .unwrap();
159
1
    assert_eq!(results, vec![Value::String("(1 2 3)".to_string())]);
160
1
}
161

            
162
#[test]
163
1
fn test_quasiquote_literal() {
164
1
    let mut interp = Interpreter::new(false).unwrap();
165
1
    let results = interp.eval("`42").unwrap();
166
1
    assert_eq!(results, vec![Value::Number(Fraction::from_integer(42))]);
167
1
}
168

            
169
#[test]
170
1
fn test_quasiquote_symbol() {
171
1
    let mut interp = Interpreter::new(false).unwrap();
172
1
    let results = interp.eval("`foo").unwrap();
173
1
    assert_eq!(results, vec![Value::Symbol("FOO".to_string())]);
174
1
}
175

            
176
#[test]
177
1
fn test_unquote_outside_error() {
178
1
    let mut interp = Interpreter::new(false).unwrap();
179
1
    assert!(interp.eval("(defvar *x* 1) ,*x*").is_err());
180
1
}
181

            
182
// DESCRIBE with macros
183

            
184
#[test]
185
1
fn test_describe_macro() {
186
1
    let mut interp = Interpreter::new(false).unwrap();
187
1
    let results = interp
188
1
        .eval("(defmacro when (test body) (list 'if test body))\n(describe when)")
189
1
        .unwrap();
190
1
    match &results[0] {
191
1
        Value::String(s) => {
192
1
            assert!(s.contains("WHEN is a macro"), "got: {s}");
193
        }
194
        _ => panic!("expected string, got {:?}", results[0]),
195
    }
196
1
}