Skip to content

Commit

Permalink
Add type checking tests
Browse files Browse the repository at this point in the history
  • Loading branch information
ethanuppal committed Apr 13, 2024
1 parent f7e34f5 commit fb76350
Show file tree
Hide file tree
Showing 15 changed files with 88 additions and 30 deletions.
24 changes: 22 additions & 2 deletions lib/analysis.ml
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,31 @@ let () =
| _ -> None)

(** After [infer_expr ctx hint expr], [expr] will be assigned a type based on
[hint] and [ctx].
[ctx] and [hint].
@raise TypeInferenceError on failure. *)
let rec infer_expr ctx hint expr =
match expr with
| Var var -> var.ty <- Context.get ctx var.name
| Var var ->
var.ty <- Context.get ctx var.name;
if var.ty = None then
raise
(TypeInferenceError
{
domain = "resolution";
symbol = Some var.name;
ast = Left expr;
unify = None;
})
else if hint <> None && var.ty <> hint then
raise
(TypeInferenceError
{
domain = "unification";
symbol = Some var.name;
ast = Left expr;
unify = Some (Option.get hint, Option.get var.ty);
})
| ConstInt _ -> (
match hint with
| None | Some (Type.Primitive Int63) | Some Any -> ()
Expand Down Expand Up @@ -111,6 +130,7 @@ let infer_stmt ctx stmt =
unify = Some (t1, t2);
}));
Context.insert ctx name (type_of_expr expr |> Option.get)
| Print expr -> infer_expr ctx None expr
| _ -> ()

let infer prog =
Expand Down
3 changes: 3 additions & 0 deletions lib/ast.ml
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,15 @@ let rec pp_expr fmt = function
| Infix { lhs; op; rhs; _ } ->
Format.pp_print_string fmt "(";
pp_expr fmt lhs;
Format.pp_print_string fmt " ";
pp_op fmt op;
Format.pp_print_string fmt " ";
pp_expr fmt rhs;
Format.pp_print_string fmt ")"
| Prefix { op; rhs; _ } ->
Format.pp_print_string fmt "(";
pp_op fmt op;
Format.pp_print_string fmt " ";
pp_expr fmt rhs;
Format.pp_print_string fmt ")"
| FunctionExpr _ -> Format.pp_print_string fmt "<func>"
Expand Down
8 changes: 3 additions & 5 deletions test/snapshot.ml
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,9 @@ open Cs3110_compiler

type transform = string -> string -> string

(** Used to categorize snapshots by validity in version. *)
let version_string = Meta.Version.to_string Meta.get.version

let make_test_suite (root : string) (transform : transform) : unit test =
let make_test_suite ?(version = Meta.get.version) root transform =
let open Util in
let version_string = Meta.Version.to_string version in
let snapshot_folder =
Util.merge_paths [ Project_root.path; root; version_string ]
in
Expand All @@ -25,7 +23,7 @@ let make_test_suite (root : string) (transform : transform) : unit test =
let input = read_file input_path in
let expected = read_file output_path in
try
let actual = transform input_path input in
let actual = transform (snapshot ^ ".in") input in
(check string)
"Using the given input transformer should yield matching output to the \
expected."
Expand Down
14 changes: 9 additions & 5 deletions test/snapshot.mli
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
open Alcotest

(** Let [f] be of type [transform]. Then, [f path contents] is the result of
transforming the string [contents] (from the file at path [path]). *)
transforming the string [contents] (from the file at path [path] relative to
the version root, e.g., for version v1.0.4, relative to
[test/snapshots/v1.0.4]). *)
type transform = string -> string -> string

(** [make_test_suite name f] is a snapshot test suite named [name] for version
[Meta.get.version] using snapshot transformation [f] (see the documentation
for [transform]). *)
val make_test_suite : string -> transform -> unit test
for [transform]). Optionally, the version can be manually specified. *)
val make_test_suite :
?version:Cs3110_compiler.Meta.Version.t ->
string ->
transform ->
unit Alcotest.test
1 change: 1 addition & 0 deletions test/snapshots/v0.1.0/type0.in
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
print true
1 change: 1 addition & 0 deletions test/snapshots/v0.1.0/type0.out
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
print true
3 changes: 3 additions & 0 deletions test/snapshots/v0.1.0/type1.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
let x = 1
let y = 2
let z = x + y
3 changes: 3 additions & 0 deletions test/snapshots/v0.1.0/type1.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
let x: Int = 1
let y: Int = 2
let z: Int = (x + y)
2 changes: 2 additions & 0 deletions test/snapshots/v0.1.0/type2.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
let x = 4
let y = *4
1 change: 1 addition & 0 deletions test/snapshots/v0.1.0/type2.out
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Type unification error: attempt to unify ?* and Int
3 changes: 3 additions & 0 deletions test/snapshots/v0.1.0/type3.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
let x = 1
let y = true
print x + y
1 change: 1 addition & 0 deletions test/snapshots/v0.1.0/type3.out
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Type unification error (symbol='y'): attempt to unify Int and Bool
1 change: 1 addition & 0 deletions test/snapshots/v0.1.0/type4.in
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
print x
1 change: 1 addition & 0 deletions test/snapshots/v0.1.0/type4.out
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Type resolution error (symbol='x')
52 changes: 34 additions & 18 deletions test/test_cs3110_compiler.ml
Original file line number Diff line number Diff line change
@@ -1,20 +1,3 @@
let interpreter_transform path input =
ignore path;
let open Cs3110_compiler in
let interpreter = Interpreter.create () in
let stdout = ref "" in
let statements = Parse_lex.lex_and_parse input in
interpreter.set_mode (Text stdout);
List.iter interpreter.step statements;
stdout

let () = ignore interpreter_transform

let ir_transform path input =
ignore path;
ignore input;
""

let id_module_test_suite =
let open Alcotest in
let id_gens_isolated_test n () =
Expand Down Expand Up @@ -139,11 +122,44 @@ let cfg_module_test_suite =
in
("lib/control_flow_graph.mli", [ test_1 ])

let snapshot_test_suite =
let interpreter_transform path input =
ignore path;
let open Cs3110_compiler in
let interpreter = Interpreter.create () in
let stdout = ref "" in
let statements = Parse_lex.lex_and_parse input in
interpreter.set_mode (Text stdout);
List.iter interpreter.step statements;
stdout
in
let () = ignore interpreter_transform in
let transform path input =
let open Cs3110_compiler in
let open Util in
let stmt_to_string stmt =
Ast.pp_stmt Format.str_formatter stmt;
Format.flush_str_formatter ()
in
if String.starts_with ~prefix:"type" path then
try
let statements = Parse_lex.lex_and_parse input in
Analysis.infer statements;
List.map (stmt_to_string >> fun s -> s ^ "\n") statements
|> String.concat ""
with
| Analysis.TypeInferenceError err ->
Printexc.to_string (Analysis.TypeInferenceError err) ^ "\n"
| e -> raise e
else ""
in
Snapshot.make_test_suite "test/snapshots" transform

let () =
[
util_module_test_suite;
id_module_test_suite;
cfg_module_test_suite;
Snapshot.make_test_suite "test/snapshots" ir_transform;
snapshot_test_suite;
]
|> Alcotest.run "x86ISTMB"

0 comments on commit fb76350

Please sign in to comment.