1#[cfg(test)]
2mod tests {
3 use std::rc::Rc;
4 use crate::compiler_test::{run_compiler_test, CompilerTestCase};
5 use crate::op_code::Opcode::*;
6 use crate::op_code::{concat_instructions, make_instructions};
7 use object::Object;
8
9 #[test]
10 fn test_functions() {
11 let tests = vec![
12 CompilerTestCase {
13 input: "fn() { return 5 + 10; }",
14 expected_constants: vec![
15 Object::Integer(5),
16 Object::Integer(10),
17 Object::CompiledFunction(Rc::from(object::CompiledFunction {
18 instructions: concat_instructions(&vec![
19 make_instructions(OpConst, &vec![0]),
20 make_instructions(OpConst, &vec![1]),
21 make_instructions(OpAdd, &vec![0]),
22 make_instructions(OpReturnValue, &vec![0]),
23 ])
24 .data,
25 num_locals: 0,
26 num_parameters: 0,
27 })),
28 ],
29 expected_instructions: vec![
30 make_instructions(OpClosure, &vec![2, 0]),
31 make_instructions(OpPop, &vec![0]),
32 ],
33 },
34 CompilerTestCase {
35 input: "fn() { 5 + 10; }",
36 expected_constants: vec![
37 Object::Integer(5),
38 Object::Integer(10),
39 Object::CompiledFunction(Rc::from(object::CompiledFunction {
40 instructions: concat_instructions(&vec![
41 make_instructions(OpConst, &vec![0]),
42 make_instructions(OpConst, &vec![1]),
43 make_instructions(OpAdd, &vec![0]),
44 make_instructions(OpReturnValue, &vec![0]),
45 ])
46 .data,
47 num_locals: 0,
48 num_parameters: 0,
49 })),
50 ],
51 expected_instructions: vec![
52 make_instructions(OpClosure, &vec![2, 0]),
53 make_instructions(OpPop, &vec![0]),
54 ],
55 },
56 CompilerTestCase {
57 input: "fn() { 1; 2}",
58 expected_constants: vec![
59 Object::Integer(1),
60 Object::Integer(2),
61 Object::CompiledFunction(Rc::from(object::CompiledFunction {
62 instructions: concat_instructions(&vec![
63 make_instructions(OpConst, &vec![0]),
64 make_instructions(OpPop, &vec![0]),
65 make_instructions(OpConst, &vec![1]),
66 make_instructions(OpReturnValue, &vec![0]),
67 ])
68 .data,
69 num_locals: 0,
70 num_parameters: 0,
71 })),
72 ],
73 expected_instructions: vec![
74 make_instructions(OpClosure, &vec![2, 0]),
75 make_instructions(OpPop, &vec![0]),
76 ],
77 },
78 ];
79 run_compiler_test(tests);
80 }
81
82 #[test]
83 fn test_function_without_return_value() {
84 let tests = vec![CompilerTestCase {
85 input: "fn() { }",
86 expected_constants: vec![Object::CompiledFunction(Rc::from(object::CompiledFunction {
87 instructions: concat_instructions(&vec![make_instructions(OpReturn, &vec![0])])
88 .data,
89 num_locals: 0,
90 num_parameters: 0,
91 }))],
92 expected_instructions: vec![
93 make_instructions(OpClosure, &vec![0, 0]),
94 make_instructions(OpPop, &vec![0]),
95 ],
96 }];
97 run_compiler_test(tests);
98 }
99
100 #[test]
101 fn test_function_calls() {
102 let tests = vec![
103 CompilerTestCase {
104 input: "fn() { 24 }();",
105 expected_constants: vec![
106 Object::Integer(24),
107 Object::CompiledFunction(Rc::from(object::CompiledFunction {
108 instructions: concat_instructions(&vec![
109 make_instructions(OpConst, &vec![0]),
110 make_instructions(OpReturnValue, &vec![0]),
111 ])
112 .data,
113 num_locals: 0,
114 num_parameters: 0,
115 })),
116 ],
117 expected_instructions: vec![
118 make_instructions(OpClosure, &vec![1, 0]),
119 make_instructions(OpCall, &vec![0]),
120 make_instructions(OpPop, &vec![0]),
121 ],
122 },
123 CompilerTestCase {
124 input: "let noArg = fn() { 24; }; noArg();",
125 expected_constants: vec![
126 Object::Integer(24),
127 Object::CompiledFunction(Rc::from(object::CompiledFunction {
128 instructions: concat_instructions(&vec![
129 make_instructions(OpConst, &vec![0]),
130 make_instructions(OpReturnValue, &vec![0]),
131 ])
132 .data,
133 num_locals: 0,
134 num_parameters: 0,
135 })),
136 ],
137 expected_instructions: vec![
138 make_instructions(OpClosure, &vec![1, 0]),
139 make_instructions(OpSetGlobal, &vec![0]),
140 make_instructions(OpGetGlobal, &vec![0]),
141 make_instructions(OpCall, &vec![0]),
142 make_instructions(OpPop, &vec![0]),
143 ],
144 },
145 CompilerTestCase {
146 input: "let oneArg = fn(a) { a; }; oneArg(24);",
147 expected_constants: vec![
148 Object::CompiledFunction(Rc::from(object::CompiledFunction {
149 instructions: concat_instructions(&vec![
150 make_instructions(OpGetLocal, &vec![0]),
151 make_instructions(OpReturnValue, &vec![0]),
152 ])
153 .data,
154 num_locals: 1,
155 num_parameters: 1,
156 })),
157 Object::Integer(24),
158 ],
159 expected_instructions: vec![
160 make_instructions(OpClosure, &vec![0, 0]),
161 make_instructions(OpSetGlobal, &vec![0]),
162 make_instructions(OpGetGlobal, &vec![0]),
163 make_instructions(OpConst, &vec![1]),
164 make_instructions(OpCall, &vec![1]),
165 make_instructions(OpPop, &vec![0]),
166 ],
167 },
168 CompilerTestCase {
169 input: "let manyArg = fn(a, b, c) { a; b; c; }; manyArg(24, 25, 26);",
170 expected_constants: vec![
171 Object::CompiledFunction(Rc::from(object::CompiledFunction {
172 instructions: concat_instructions(&vec![
173 make_instructions(OpGetLocal, &vec![0]),
174 make_instructions(OpPop, &vec![0]),
175 make_instructions(OpGetLocal, &vec![1]),
176 make_instructions(OpPop, &vec![0]),
177 make_instructions(OpGetLocal, &vec![2]),
178 make_instructions(OpReturnValue, &vec![0]),
179 ])
180 .data,
181 num_locals: 3,
182 num_parameters: 3,
183 })),
184 Object::Integer(24),
185 Object::Integer(25),
186 Object::Integer(26),
187 ],
188 expected_instructions: vec![
189 make_instructions(OpClosure, &vec![0, 0]),
190 make_instructions(OpSetGlobal, &vec![0]),
191 make_instructions(OpGetGlobal, &vec![0]),
192 make_instructions(OpConst, &vec![1]),
193 make_instructions(OpConst, &vec![2]),
194 make_instructions(OpConst, &vec![3]),
195 make_instructions(OpCall, &vec![3]),
196 make_instructions(OpPop, &vec![0]),
197 ],
198 },
199 ];
200
201 run_compiler_test(tests);
202 }
203
204 #[test]
205 fn test_let_statement_scope() {
206 let tests = vec![
207 CompilerTestCase {
208 input: "let num = 55; fn() { num; }",
209 expected_constants: vec![
210 Object::Integer(55),
211 Object::CompiledFunction(Rc::from(object::CompiledFunction {
212 instructions: concat_instructions(&vec![
213 make_instructions(OpGetGlobal, &vec![0]),
214 make_instructions(OpReturnValue, &vec![0]),
215 ])
216 .data,
217 num_locals: 0,
218 num_parameters: 0,
219 })),
220 ],
221 expected_instructions: vec![
222 make_instructions(OpConst, &vec![0]),
223 make_instructions(OpSetGlobal, &vec![0]),
224 make_instructions(OpClosure, &vec![1, 0]),
225 make_instructions(OpPop, &vec![0]),
226 ],
227 },
228 CompilerTestCase {
229 input: "fn() { let num = 55; num; }",
230 expected_constants: vec![
231 Object::Integer(55),
232 Object::CompiledFunction(Rc::from(object::CompiledFunction {
233 instructions: concat_instructions(&vec![
234 make_instructions(OpConst, &vec![0]),
235 make_instructions(OpSetLocal, &vec![0]),
236 make_instructions(OpGetLocal, &vec![0]),
237 make_instructions(OpReturnValue, &vec![0]),
238 ])
239 .data,
240 num_locals: 1,
241 num_parameters: 0,
242 })),
243 ],
244 expected_instructions: vec![
245 make_instructions(OpClosure, &vec![1, 0]),
246 make_instructions(OpPop, &vec![0]),
247 ],
248 },
249 CompilerTestCase {
250 input: "fn() { let a = 55; let b = 77; a + b; }",
251 expected_constants: vec![
252 Object::Integer(55),
253 Object::Integer(77),
254 Object::CompiledFunction(Rc::from(object::CompiledFunction {
255 instructions: concat_instructions(&vec![
256 make_instructions(OpConst, &vec![0]),
257 make_instructions(OpSetLocal, &vec![0]),
258 make_instructions(OpConst, &vec![1]),
259 make_instructions(OpSetLocal, &vec![1]),
260 make_instructions(OpGetLocal, &vec![0]),
261 make_instructions(OpGetLocal, &vec![1]),
262 make_instructions(OpAdd, &vec![0]),
263 make_instructions(OpReturnValue, &vec![0]),
264 ])
265 .data,
266 num_locals: 2,
267 num_parameters: 0,
268 })),
269 ],
270 expected_instructions: vec![
271 make_instructions(OpClosure, &vec![2, 0]),
272 make_instructions(OpPop, &vec![0]),
273 ],
274 },
275 ];
276 run_compiler_test(tests);
277 }
278
279 #[test]
280 fn test_builtins() {
281 let tests = vec![
282 CompilerTestCase {
283 input: "len([]); push([], 1);",
284 expected_constants: vec![Object::Integer(1)],
285 expected_instructions: vec![
286 make_instructions(OpGetBuiltin, &vec![0]),
287 make_instructions(OpArray, &vec![0]),
288 make_instructions(OpCall, &vec![1]),
289 make_instructions(OpPop, &vec![0]),
290 make_instructions(OpGetBuiltin, &vec![5]),
291 make_instructions(OpArray, &vec![0]),
292 make_instructions(OpConst, &vec![0]),
293 make_instructions(OpCall, &vec![2]),
294 make_instructions(OpPop, &vec![0]),
295 ],
296 },
297 CompilerTestCase {
298 input: "fn() { len([]) }",
299 expected_constants: vec![Object::CompiledFunction(Rc::from(object::CompiledFunction {
300 instructions: concat_instructions(&vec![
301 make_instructions(OpGetBuiltin, &vec![0]),
302 make_instructions(OpArray, &vec![0]),
303 make_instructions(OpCall, &vec![1]),
304 make_instructions(OpReturnValue, &vec![0]),
305 ])
306 .data,
307 num_locals: 0,
308 num_parameters: 0,
309 }))],
310 expected_instructions: vec![
311 make_instructions(OpClosure, &vec![0, 0]),
312 make_instructions(OpPop, &vec![0]),
313 ],
314 },
315 ];
316 run_compiler_test(tests);
317 }
318}