-
Notifications
You must be signed in to change notification settings - Fork 0
/
test_general.ml
108 lines (98 loc) · 3.54 KB
/
test_general.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
open Llvm
open OUnit2
let main_function exp =
Ast.Function (
"main",
[| |],
exp
)
(** Codegen an expression into a new module, and return the module. *)
let compile exp =
let context = global_context () in
let the_module = create_module context "my singleton module" in
let builder = builder context in
ignore (Codegen.codegen_expr context the_module builder (Infer.infer_types exp));
the_module
(** Run the no-args function called "main" from the given module. Return its
int result. *)
let run_main the_module =
ignore (Llvm_executionengine.initialize ()); (* I don't think we care if this fails (returns false), because I suppose it then falls back to the interpreter, which is enough for test purposes. *)
let engine = Llvm_executionengine.create the_module in
(* This has the side effect of generating the machine code, after which no
more changes to the module will ever be taken into account: *)
let func = Llvm_executionengine.get_function_address "main" (Foreign.funptr (Ctypes.(@->) Ctypes.void (Ctypes.returning Ctypes.int))) engine in
let result : int = func () in
Llvm_executionengine.dispose engine;
result
let tests = "General tests" >::: [
(** Repro a bug wherein assignment didn't return a value, leading LLVM function
validation to fail. *)
"Assignments must return their value." >:: (fun _ -> (
let main = main_function (Ast.Assignment ("x", Int(1))) in
ignore (compile main)
));
"When the branches of an `if` read an undefined var, raise an error." >:: (fun _ -> (
let func = Ast.Function (
"foo",
[| |],
Ast.Block (
[
Ast.Assignment ("x", Ast.Bool true);
Ast.If (
Ast.Var "x",
Ast.Assignment("a", Int 1),
Ast.Assignment("q", Int 2)
);
Ast.Var "a"
]
)
) in
let tfunc = Infer.infer_types func in
let tbody = match tfunc with
| TFunction (_, _, body, _) -> body
| _ -> assert_failure "Something went terribly wrong."
in
assert_raises (Exc.Undefined_var "a") (fun () -> Ast.assert_no_unwritten_reads_in_scope tbody)
));
"Inner functions are disallowed for now." >:: (fun _ -> (
let main = main_function (
Ast.Function (
"sub",
[| |],
Ast.Int(3)
)
) in
assert_raises (Codegen.Error "Inner functions are not allowed yet.")
(fun () -> compile main)
));
"JITting test harness works" >:: (fun _ -> (
let result = run_main (compile (main_function (Ast.Int 33))) in
assert_equal result 33
));
(*
"Global functions are first-class." >:: (fun _ -> (
let context = global_context () in
let the_module = create_module context "my singleton module" in
let builder = builder context in
let other_func = Ast.Function (
"other", [| |],
Ast.Int 44
) in
assert_equal !Codegen.is_generating_function false;
ignore (Codegen.codegen_expr context the_module builder (Infer.infer_types other_func));
assert_equal !Codegen.is_generating_function false;
let main_func = Ast.Function (
"main", [| |],
Ast.Block [
Ast.Assignment ("first_class_other_func",
Ast.Var "other");
Ast.Call (Ast.Var "first_class_other_func",
[])
]
) in
ignore (Codegen.codegen_expr context the_module builder (Infer.infer_types main_func));
let result = run_main the_module in
assert_equal result 44
));
*)
]