open Aufbau
let failed = ref 0
let case name cond =
if cond then Printf.printf "ok %s\n" name
else (incr failed; Printf.printf "FAIL %s\n" name)
let ml_grammar () =
let rec up dir =
let candidate = Filename.concat dir "examples/ml.auf" in
if Sys.file_exists candidate then candidate
else
let parent = Filename.dirname dir in
if parent = dir then failwith "examples/ml.auf not found" else up parent
in
let path = up (Sys.getcwd ()) in
let ic = open_in_bin path in
let src = really_input_string ic (in_channel_length ic) in
close_in ic;
match Grammar.load src with Ok g -> g | Error e -> failwith e
let valid =
[ "fun (x : int) -> x";
"fun (x : int) -> fun (y : bool) -> x";
"(fun (x : int) -> x)(5)";
"let a : int = 5 in a";
"let a : int = 5 in a + 1";
"1 < 2";
"if true then 1 else 2";
"if 1 < 2 then 1 else 0";
"(1, true)";
"fst (1, true)";
"snd (1, true)";
"1 :: []";
"1 :: 2 :: 3 :: []";
"(1, true) :: []";
"let xs : int list = 1 :: [] in xs";
"let rec f : int -> int = fun (n : int) -> f(n) in f(0)";
"assert false";
"let a : int = assert false in a";
"if true then 1 else assert false";
"let f : int -> bool = assert false in f(0)";
"match [] with [] -> 0 | h :: t -> h + 1";
"let rec length : int list -> int = fun (xs : int list) -> match xs with [] -> 0 | h :: t -> 1 + length(t) in length(1 :: 2 :: 3 :: [])";
"let rec sum : int list -> int = fun (xs : int list) -> match xs with [] -> 0 | h :: t -> h + sum(t) in sum(1 :: 2 :: [])";
"let rec member : int list -> bool = fun (xs : int list) -> match xs with [] -> false | h :: t -> if h = 0 then true else member(t) in member(0 :: 1 :: [])";
"let rec copy : int list -> int list = fun (xs : int list) -> match xs with [] -> [] | h :: t -> h :: copy(t) in copy(1 :: 2 :: [])" ]
let invalid =
[ "fun (x : int) -> y";
"1 + true";
"if 1 then 2 else 3";
"if true then 1 else false";
"fst 5";
"let a : bool = 5 in a";
"true < 2";
"1 :: true :: []";
"1 :: 2";
"let xs : bool list = 1 :: [] in xs";
"match 1 :: [] with [] -> 0 | h :: t -> true";
"match 5 with [] -> 0 | h :: t -> 1";
"let rec f : int list -> int = fun (xs : int list) -> match xs with [] -> 0 | h :: t -> f(h) in f(1 :: [])" ]
let beyond =
[ "match [] with [] -> 0 | h :: t -> if h then 1 else h + 1" ]
let () =
let g = ml_grammar () in
case "complete (inhabited via assert false)" (Grammar.complete g);
List.iter
(fun p ->
let aufbau = Check.accepts g p in
let oracle = Oracle.typechecks p in
case ("agree+ " ^ p) (aufbau && oracle))
valid;
List.iter
(fun p ->
let aufbau = Check.accepts g p in
let oracle = Oracle.typechecks p in
case ("agree- " ^ p) ((not aufbau) && not oracle))
invalid;
List.iter
(fun p ->
let aufbau = Check.accepts g p in
let oracle = Oracle.typechecks p in
case ("bound " ^ p) ((not aufbau) && oracle))
beyond;
if !failed > 0 then (Printf.printf "\n%d disagreement(s)\n" !failed; exit 1)
else print_endline "\naufbau ≡ OCaml typechecker on the monomorphic ML corpus"