-
Notifications
You must be signed in to change notification settings - Fork 31
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[tools] Checkdecls tool for Coq blueprints
Co-authored-by: Andrej Bauer <Andrej.Bauer@andrej.com>
- Loading branch information
1 parent
46679d4
commit a4a4ebc
Showing
8 changed files
with
223 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
(************************************************************************) | ||
(* Flèche => checkdecls support for Proof blueprint *) | ||
(* Copyright 2019 MINES ParisTech -- Dual License LGPL 2.1 / GPL3+ *) | ||
(* Copyright 2019-2024 Inria -- Dual License LGPL 2.1 / GPL3+ *) | ||
(* Written by: Andrej Bauaer, Emilio J. Gallego Arias *) | ||
(************************************************************************) | ||
|
||
let err_fmt = Format.err_formatter | ||
let pf fmt = Format.kfprintf (fun fmt -> Format.pp_print_flush fmt ()) fmt | ||
|
||
let coq_init ~debug = | ||
let load_module = Dynlink.loadfile in | ||
let load_plugin = Coq.Loader.plugin_handler None in | ||
Coq.Init.( | ||
coq_init { debug; load_module; load_plugin; vm = true; warnings = None }) | ||
|
||
let workspace_init ~token ~debug ~cmdline ~roots = | ||
let roots = if List.length roots < 1 then [ Sys.getcwd () ] else roots in | ||
let default = Coq.Workspace.default ~debug ~cmdline in | ||
( default | ||
, List.map | ||
(fun dir -> (dir, Coq.Workspace.guess ~token ~cmdline ~debug ~dir)) | ||
roots ) | ||
|
||
(* Stdlib.Int.max requires OCaml 4.13 *) | ||
let int_max x y = if x >= y then x else y | ||
let max = List.fold_left int_max 0 | ||
|
||
(* We capture all the exns, bad people *) | ||
let locate_decl decl = | ||
try | ||
let qid = Libnames.qualid_of_string decl in | ||
Ok (Nametab.locate_constant qid) | ||
with | ||
| Not_found -> Error (Format.asprintf "%s not found in name table" decl) | ||
| exn -> | ||
let iexn = Exninfo.capture exn in | ||
let exn_msg = CErrors.iprint iexn |> Pp.string_of_ppcmds in | ||
Error (Format.asprintf "internal Coq error: %s" exn_msg) | ||
|
||
let pp_lp = function | ||
| Loadpath.Error.LibNotFound -> "LibNotFound" | ||
| Loadpath.Error.LibUnmappedDir -> "LibUnmappedDir" | ||
|
||
(* EJGA: also check if the location info is available *) | ||
let location_enabled = false | ||
|
||
let do_decl decl = | ||
let open Coq.Compat.Result.O in | ||
let* cr = locate_decl decl in | ||
if location_enabled then | ||
let dp = Names.Constant.modpath cr |> Names.ModPath.dp in | ||
let* m = Coq.Module.make dp |> Result.map_error pp_lp in | ||
let id = Names.Constant.label cr |> Names.Label.to_string in | ||
let* _loc_info = Coq.Module.find m id in | ||
Ok () | ||
else Ok () | ||
|
||
let do_decl decl = | ||
(* pf err "decl for: %s" decl; *) | ||
match do_decl decl with | ||
| Ok () -> | ||
(* pf err "decl found! %s" decl; *) | ||
0 | ||
| Error err -> | ||
pf err_fmt "Error when processing input %s [%s]@\n" decl err; | ||
1 | ||
|
||
let do_decls file = | ||
Coq.Compat.Ocaml_414.In_channel.(with_open_text file input_all) | ||
|> String.split_on_char '\n' | ||
|> List.filter (fun s -> not (CString.is_empty s)) | ||
|> List.map do_decl |> max | ||
|
||
let do_decls ws files = | ||
let intern = Vernacinterp.fs_intern in | ||
let uri = | ||
Lang.LUri.(of_string "file:///fake.v" |> File.of_uri) |> Result.get_ok | ||
in | ||
let () = Coq.Workspace.apply ~intern ~uri ws in | ||
List.map do_decls files | ||
|
||
let do_decls ~token st ws files = | ||
let f files = do_decls ws files in | ||
Coq.State.in_state ~token ~st ~f files | ||
|
||
let go ~cmdline ~roots ~debug ~files = | ||
Coq.Limits.select_best None; | ||
Coq.Limits.start (); | ||
let token = Coq.Limits.Token.create () in | ||
let root_state = coq_init ~debug in | ||
let default, _ws = workspace_init ~token ~debug ~cmdline ~roots in | ||
match do_decls ~token root_state default files with | ||
| { r = Interrupted; feedback = _ } -> 2 | ||
| { r = Completed (Ok outs); feedback = _ } -> max outs | ||
| { r = Completed (Error _); feedback = _ } -> | ||
pf err_fmt "critical error!"; | ||
222 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
val go : | ||
cmdline:Coq.Workspace.CmdLine.t | ||
-> roots:string list | ||
-> debug:bool | ||
-> files:string list | ||
-> int |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
(executable | ||
(name main) | ||
(public_name checkdecls) | ||
(libraries coq cmdliner)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
(* Flèche Coq compiler / checkdecls for Coq-blueprints *) | ||
|
||
let cd_main roots debug files coqlib coqcorelib findlib_config ocamlpath | ||
rload_path load_path require_libraries = | ||
let vo_load_path = rload_path @ load_path in | ||
let ml_include_path = [] in | ||
let args = [] in | ||
let cmdline = | ||
{ Coq.Workspace.CmdLine.coqlib | ||
; coqcorelib | ||
; findlib_config | ||
; ocamlpath | ||
; vo_load_path | ||
; ml_include_path | ||
; args | ||
; require_libraries | ||
} | ||
in | ||
Driver.go ~cmdline ~roots ~debug ~files | ||
|
||
open Cmdliner | ||
|
||
(****************************************************************************) | ||
let files : string list Term.t = | ||
let doc = "Files with list of identifiers to check" in | ||
Arg.(non_empty & pos_all non_dir_file [] & info [] ~docv:"FILES" ~doc) | ||
|
||
module Exit_codes = struct | ||
let missing_id : Cmd.Exit.info = | ||
let doc = "An input identifier was not found" in | ||
Cmd.Exit.info ~doc 1 | ||
|
||
let stopped : Cmd.Exit.info = | ||
let doc = | ||
"The document was not fully checked: this is often due to a timeout, \ | ||
interrupt, or resource limit." | ||
in | ||
Cmd.Exit.info ~doc 2 | ||
|
||
let uri_failed : Cmd.Exit.info = | ||
let doc = | ||
"[INTERNAL] There was an internal error setting up the Coq workspace" | ||
in | ||
Cmd.Exit.info ~doc 222 | ||
end | ||
|
||
let cd_cmd : int Cmd.t = | ||
let doc = "CheckDecls for Coq" in | ||
let man = | ||
[ `S "DESCRIPTION" | ||
; `P "checkdecls checker" | ||
; `S "USAGE" | ||
; `P "See the documentation of blueprints" | ||
] | ||
in | ||
(* let version = Fleche.Version.server in *) | ||
let version = "0.1" in | ||
let fcc_term = | ||
let open Coq.Args in | ||
Term.( | ||
const cd_main $ roots $ debug $ files $ coqlib $ coqcorelib | ||
$ findlib_config $ ocamlpath $ rload_paths $ qload_paths $ ri_from) | ||
in | ||
let exits = Exit_codes.[ missing_id; stopped; uri_failed ] in | ||
Cmd.(v (Cmd.info "checkdecls" ~exits ~version ~doc ~man) fcc_term) | ||
|
||
let main () = | ||
let ecode = Cmd.eval' cd_cmd in | ||
exit ecode | ||
|
||
let () = main () |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
(* empty interface *) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
(cram | ||
(deps | ||
; For the coq-lsp plugins to be built, in case we need it | ||
(package coq-lsp) | ||
%{bin:checkdecls})) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
General tests for checkdecls | ||
|
||
Error when not input: | ||
|
||
$ checkdecls | ||
checkdecls: required argument FILES is missing | ||
Usage: checkdecls [OPTION]… FILES… | ||
Try 'checkdecls --help' for more information. | ||
[124] | ||
|
||
Error when file doesn't exists: | ||
|
||
$ checkdecls where_i_am.txt | ||
checkdecls: FILES… arguments: no 'where_i_am.txt' file | ||
Usage: checkdecls [OPTION]… FILES… | ||
Try 'checkdecls --help' for more information. | ||
[124] | ||
|
||
Simple test with one file, succeed | ||
|
||
$ echo Coq.Init.Nat.add > clist | ||
$ echo Coq.Init.Peano.plus_n_O >> clist | ||
$ checkdecls clist | ||
$ echo $? | ||
0 | ||
|
||
Simple test with one file, fail | ||
|
||
$ echo Coq.Init.Peano.not_a_constant >> clist | ||
$ echo Coq.Init.Nat.not_a_theorem >> clist | ||
$ checkdecls clist | ||
Error when processing input Coq.Init.Peano.not_a_constant [Coq.Init.Peano.not_a_constant not found in name table] | ||
Error when processing input Coq.Init.Nat.not_a_theorem [Coq.Init.Nat.not_a_theorem not found in name table] | ||
[1] | ||
$ echo $? | ||
0 |