summaryrefslogtreecommitdiff
path: root/plugins/dp/dp_zenon.mll
blob: 949e91e344ff71293dd9476a1734e0d0a631cbda (plain)
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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189

{

  open Lexing
  open Pp
  open Util
  open Names
  open Tacmach
  open Dp_why
  open Tactics
  open Tacticals

  let debug = ref false
  let set_debug b = debug := b

  let buf = Buffer.create 1024

  let string_of_global env ref =
    Libnames.string_of_qualid (Nametab.shortest_qualid_of_global env ref)

  let axioms = ref []

  (* we cannot interpret the terms as we read them (since some lemmas
     may need other lemmas to be already interpreted) *)
  type lemma = { l_id : string; l_type : string; l_proof : string }
  type zenon_proof = lemma list * string

}

let ident = ['a'-'z' 'A'-'Z' '_' '0'-'9' '\'']+
let space = [' ' '\t' '\r']

rule start = parse
| "(* BEGIN-PROOF *)" "\n" { scan lexbuf }
| _ { start lexbuf }
| eof { anomaly "malformed Zenon proof term" }

(* here we read the lemmas and the main proof term;
   meanwhile we maintain the set of axioms that were used *)

and scan = parse
| "Let" space (ident as id) space* ":"
  { let t = read_coq_term lexbuf in
    let p = read_lemma_proof lexbuf in
    let l,pr = scan lexbuf in
    { l_id = id; l_type = t; l_proof = p } :: l, pr }
| "Definition theorem:"
  { let t = read_main_proof lexbuf in [], t }
| _ | eof
  { anomaly "malformed Zenon proof term" }

and read_coq_term = parse
| "." "\n"
  { let s = Buffer.contents buf in Buffer.clear buf; s }
| "coq__" (ident as id) (* a Why keyword renamed *)
  { Buffer.add_string buf id; read_coq_term lexbuf }
| ("dp_axiom__" ['0'-'9']+) as id
  { axioms := id :: !axioms; Buffer.add_string buf id; read_coq_term lexbuf }
| _ as c
  { Buffer.add_char buf c; read_coq_term lexbuf }
| eof
  { anomaly "malformed Zenon proof term" }

and read_lemma_proof = parse
| "Proof" space
  { read_coq_term lexbuf }
| _ | eof
  { anomaly "malformed Zenon proof term" }

(* skip the main proof statement and then read its term *)
and read_main_proof = parse
| ":=" "\n"
  { read_coq_term lexbuf }
| _
  { read_main_proof lexbuf }
| eof
  { anomaly "malformed Zenon proof term" }


{

  let read_zenon_proof f =
    Buffer.clear buf;
    let c = open_in f in
    let lb = from_channel c in
    let p = start lb in
    close_in c;
    if not !debug then begin try Sys.remove f with _ -> () end;
    p

  let constr_of_string gl s =
    let parse_constr = Pcoq.parse_string Pcoq.Constr.constr in
    Constrintern.interp_constr (project gl) (pf_env gl) (parse_constr s)

  (* we are lazy here: we build strings containing Coq terms using a *)
  (* pretty-printer Fol -> Coq *)
  module Coq = struct
    open Format
    open Fol

    let rec print_list sep print fmt = function
      | [] -> ()
      | [x] -> print fmt x
      | x :: r -> print fmt x; sep fmt (); print_list sep print fmt r

    let space fmt () = fprintf fmt "@ "
    let comma fmt () = fprintf fmt ",@ "

    let rec print_typ fmt = function
      | Tvar x -> fprintf fmt "%s" x
      | Tid ("int", []) -> fprintf fmt "Z"
      | Tid (x, []) -> fprintf fmt "%s" x
      | Tid (x, [t]) -> fprintf fmt "(%s %a)" x print_typ t
      | Tid (x,tl) ->
	  fprintf fmt "(%s %a)" x (print_list comma print_typ) tl

    let rec print_term fmt = function
      | Cst n ->
	  fprintf fmt "%s" (Big_int.string_of_big_int n)
      | RCst s ->
          fprintf fmt "%s" (Big_int.string_of_big_int s)
      | Power2 n ->
          fprintf fmt "@[(powerRZ 2 %s)@]" (Big_int.string_of_big_int n)

          (* TODO: bug, it might be operations on reals *)
      | Plus (a, b) ->
	  fprintf fmt "@[(Zplus %a %a)@]" print_term a print_term b
      | Moins (a, b) ->
	  fprintf fmt "@[(Zminus %a %a)@]" print_term a print_term b
      | Mult (a, b) ->
	  fprintf fmt "@[(Zmult %a %a)@]" print_term a print_term b
      | Div (a, b) ->
	  fprintf fmt "@[(Zdiv %a %a)@]" print_term a print_term b
      | Opp (a) ->
	  fprintf fmt "@[(Zopp %a)@]" print_term a
      | App (id, []) ->
	  fprintf fmt "%s" id
      | App (id, tl) ->
	  fprintf fmt "@[(%s %a)@]" id print_terms tl

    and print_terms fmt tl =
      print_list space print_term fmt tl

    (* builds the text for "forall vars, f vars = t" *)
    let fun_def_axiom f vars t =
      let binder fmt (x,t) = fprintf fmt "(%s: %a)" x print_typ t in
      fprintf str_formatter
	"@[(forall %a, %s %a = %a)@]@."
	(print_list space binder) vars f
	(print_list space (fun fmt (x,_) -> pp_print_string fmt x)) vars
	print_term t;
      flush_str_formatter ()

  end

  let prove_axiom id = match Dp_why.find_proof id with
    | Immediate t ->
	exact_check t
    | Fun_def (f, vars, ty, t) ->
	tclTHENS
	  (fun gl ->
	     let s = Coq.fun_def_axiom f vars t in
	     if !debug then Format.eprintf "axiom fun def = %s@." s;
	     let c = constr_of_string gl s in
	     assert_tac (Name (id_of_string id)) c gl)
	  [tclTHEN intros reflexivity; tclIDTAC]

  let exact_string s gl =
    let c = constr_of_string gl s in
    exact_check c gl

  let interp_zenon_proof (ll,p) =
    let interp_lemma l gl =
      let ty = constr_of_string gl l.l_type in
      tclTHENS
	(assert_tac (Name (id_of_string l.l_id)) ty)
	[exact_string l.l_proof; tclIDTAC]
	gl
    in
    tclTHEN (tclMAP interp_lemma ll) (exact_string p)

  let proof_from_file f =
    axioms := [];
    msgnl (str "proof_from_file " ++ str f);
    let zp = read_zenon_proof f in
    msgnl (str "proof term is " ++ str (snd zp));
    tclTHEN (tclMAP prove_axiom !axioms) (interp_zenon_proof zp)

}