compiler/
compiler_function_test.rs

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}