smtv2.ml 11.7 KB
Newer Older
Andrei Paskevich's avatar
Andrei Paskevich committed
1
2
3
(********************************************************************)
(*                                                                  *)
(*  The Why3 Verification Platform   /   The Why3 Development Team  *)
Jean-Christophe Filliâtre's avatar
Jean-Christophe Filliâtre committed
4
(*  Copyright 2010-2014   --   INRIA - CNRS - Paris-Sud University  *)
Andrei Paskevich's avatar
Andrei Paskevich committed
5
6
7
8
9
10
(*                                                                  *)
(*  This software is distributed under the terms of the GNU Lesser  *)
(*  General Public License version 2.1, with the special exception  *)
(*  on linking described in file LICENSE.                           *)
(*                                                                  *)
(********************************************************************)
11
12
13
14
15
16
17
18
19
20
21

(** SMT v1 printer with some extensions *)

open Format
open Pp
open Ident
open Ty
open Term
open Decl
open Printer

22
(** SMTLIB tokens taken from CVC4: src/parser/smt2/Smt2.g *)
23
24
25
26
27
28
29
30
31
let ident_printer =
  let bls = (*["and";" benchmark";" distinct";"exists";"false";"flet";"forall";
     "if then else";"iff";"implies";"ite";"let";"logic";"not";"or";
     "sat";"theory";"true";"unknown";"unsat";"xor";
     "assumption";"axioms";"defintion";"extensions";"formula";
     "funs";"extrafuns";"extrasorts";"extrapreds";"language";
     "notes";"preds";"sorts";"status";"theory";"Int";"Real";"Bool";
     "Array";"U";"select";"store"]*)
    (** smtlib2 V2 p71 *)
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
    [(** Base SMT-LIB tokens *)
      "assert"; "check-sat"; "declare-fun"; "declare-sort"; "define-fun";
      "define-sort"; "get-value"; "get-assignment"; "get-assertions";
      "get-proof"; "get-unsat-core"; "exit"; "ite"; "let"; "!"; "_";
      "set-logic"; "set-info"; "get-info"; "set-option"; "get-option";
      "push"; "pop"; "as";

      (** extended commands *)
      "declare-datatypes"; "get-model"; "echo"; "assert-rewrite";
      "assert-reduction"; "assert-propagation"; "declare-sorts";
      "declare-funs"; "declare-preds"; "define"; "declare-const";
      "simplify";

      (** attributes *)

      (** operators, including theory symbols *)
      "and"; "distinct"; "exists"; "forall"; "is_int"; "not"; "or"; "select";
      "store"; "to_int"; "to_real"; "xor";

      "div"; "mod";

      "concat"; "bvnot"; "bvand"; "bvor"; "bvneg"; "bvadd"; "bvmul"; "bvudiv";
      "bvurem"; "bvshl"; "bvlshr"; "bvult"; "bvnand"; "bvnor"; "bvxor";
      "bvcomp"; "bvsub"; "bvsdiv"; "bvsrem"; "bvsmod"; "bvashr"; "bvule";
56
      "bvugt"; "bvuge"; "bvslt"; "bvsle"; "bvsgt"; "bvsge"; "rotate_left"; "rotate_right";
57

58
59
      "cos"; "sin"; "tan"; "atan"; "pi";

60
61
      (** Other stuff that Why3 seems to need *)
      "DECIMAL"; "NUMERAL"; "par"; "STRING";
62
      "unsat";"sat";
63
64
65
66
      "Bool"; "true"; "false";
      "Array";"const";
      "abs";
      "BitVec"; "extract"; "bv2nat"; "nat2bv"
Andrei Paskevich's avatar
Andrei Paskevich committed
67
      ]
68
69
70
71
72
73
74
75
  in
  let san = sanitizer char_to_alpha char_to_alnumus in
  create_ident_printer bls ~sanitizer:san

let print_ident fmt id =
  fprintf fmt "%s" (id_unique ident_printer id)

type info = {
76
  info_syn : syntax_map;
77
78
}

79
(** type *)
80
81
let rec print_type info fmt ty = match ty.ty_node with
  | Tyvar _ -> unsupported "smt : you must encode the polymorphism"
82
  | Tyapp (ts, l) ->
83
84
85
86
87
     begin match query_syntax info.info_syn ts.ts_name, l with
      | Some s, _ -> syntax_arguments s (print_type info) fmt l
      | None, [] -> fprintf fmt "%a" print_ident ts.ts_name
      | None, _ -> fprintf fmt "(%a %a)" print_ident ts.ts_name
          (print_list space (print_type info)) l
88
89
     end

90
91
let print_type info fmt ty = try print_type info fmt ty
  with Unsupported s -> raise (UnsupportedType (ty,s))
92
93
94
95
96
97
98
99
100
101
102
103
104

let print_type_value info fmt = function
  | None -> fprintf fmt "Bool"
  | Some ty -> print_type info fmt ty

(** var *)
let forget_var v = forget_id ident_printer v.vs_name

let print_var fmt {vs_name = id} =
  let n = id_unique ident_printer id in
  fprintf fmt "%s" n

let print_typed_var info fmt vs =
105
106
  fprintf fmt "(%a %a)" print_var vs
    (print_type info) vs.vs_ty
107
108
109
110
111
112

let print_var_list info fmt vsl =
  print_list space (print_typed_var info) fmt vsl

(** expr *)
let rec print_term info fmt t = match t.t_node with
113
114
  | Tconst c ->
      let number_format = {
115
          Number.long_int_support = true;
116
          Number.extra_leading_zeros_support = false;
117
118
119
120
121
122
123
124
125
126
          Number.dec_int_support = Number.Number_default;
          Number.hex_int_support = Number.Number_unsupported;
          Number.oct_int_support = Number.Number_unsupported;
          Number.bin_int_support = Number.Number_unsupported;
          Number.def_int_support = Number.Number_unsupported;
          Number.dec_real_support = Number.Number_unsupported;
          Number.hex_real_support = Number.Number_unsupported;
          Number.frac_real_support = Number.Number_custom
            (Number.PrintFracReal ("%s.0", "(* %s.0 %s.0)", "(/ %s.0 %s.0)"));
          Number.def_real_support = Number.Number_unsupported;
127
        } in
128
      Number.print number_format fmt c
129
130
  | Tvar v -> print_var fmt v
  | Tapp (ls, tl) -> begin match query_syntax info.info_syn ls.ls_name with
131
      | Some s -> syntax_arguments_typed s (print_term info)
132
        (print_type info) t fmt tl
133
134
135
      | None -> begin match tl with (* for cvc3 wich doesn't accept (toto ) *)
          | [] -> fprintf fmt "@[%a@]" print_ident ls.ls_name
          | _ -> fprintf fmt "@[(%a@ %a)@]"
136
              print_ident ls.ls_name (print_list space (print_term info)) tl
137
138
139
        end end
  | Tlet (t1, tb) ->
      let v, t2 = t_open_bound tb in
140
      fprintf fmt "@[(let ((%a %a))@ %a)@]" print_var v
141
142
143
144
145
146
147
148
149
        (print_term info) t1 (print_term info) t2;
      forget_var v
  | Tif (f1,t1,t2) ->
      fprintf fmt "@[(ite %a@ %a@ %a)@]"
        (print_fmla info) f1 (print_term info) t1 (print_term info) t2
  | Tcase _ -> unsupportedTerm t
      "smtv2 : you must eliminate match"
  | Teps _ -> unsupportedTerm t
      "smtv2 : you must eliminate epsilon"
150
  | Tquant _ | Tbinop _ | Tnot _ | Ttrue | Tfalse -> raise (TermExpected t)
151

152
153
and print_fmla info fmt f = match f.t_node with
  | Tapp ({ ls_name = id }, []) ->
154
      print_ident fmt id
155
  | Tapp (ls, tl) -> begin match query_syntax info.info_syn ls.ls_name with
156
      | Some s -> syntax_arguments_typed s (print_term info)
157
        (print_type info) f fmt tl
158
159
160
      | None -> begin match tl with (* for cvc3 wich doesn't accept (toto ) *)
          | [] -> fprintf fmt "%a" print_ident ls.ls_name
          | _ -> fprintf fmt "(%a@ %a)"
161
              print_ident ls.ls_name (print_list space (print_term info)) tl
162
        end end
163
164
165
  | Tquant (q, fq) ->
      let q = match q with Tforall -> "forall" | Texists -> "exists" in
      let vl, tl, f = t_open_quant fq in
166
167
168
      (* TODO trigger dépend des capacités du prover : 2 printers?
      smtwithtriggers/smtstrict *)
      if tl = [] then
169
        fprintf fmt "@[(%s@ (%a)@ %a)@]"
170
171
172
173
          q
          (print_var_list info) vl
          (print_fmla info) f
      else
174
        fprintf fmt "@[(%s@ (%a)@ (! %a %a))@]"
175
176
177
178
179
          q
          (print_var_list info) vl
          (print_fmla info) f
          (print_triggers info) tl;
      List.iter forget_var vl
180
  | Tbinop (Tand, f1, f2) ->
181
      fprintf fmt "@[(and@ %a@ %a)@]" (print_fmla info) f1 (print_fmla info) f2
182
  | Tbinop (Tor, f1, f2) ->
183
      fprintf fmt "@[(or@ %a@ %a)@]" (print_fmla info) f1 (print_fmla info) f2
184
  | Tbinop (Timplies, f1, f2) ->
Andrei Paskevich's avatar
Andrei Paskevich committed
185
      fprintf fmt "@[(=>@ %a@ %a)@]"
186
        (print_fmla info) f1 (print_fmla info) f2
187
  | Tbinop (Tiff, f1, f2) ->
Andrei Paskevich's avatar
Andrei Paskevich committed
188
      fprintf fmt "@[(=@ %a@ %a)@]" (print_fmla info) f1 (print_fmla info) f2
189
  | Tnot f ->
190
      fprintf fmt "@[(not@ %a)@]" (print_fmla info) f
191
  | Ttrue ->
192
      fprintf fmt "true"
193
  | Tfalse ->
194
      fprintf fmt "false"
195
  | Tif (f1, f2, f3) ->
Andrei Paskevich's avatar
Andrei Paskevich committed
196
      fprintf fmt "@[(ite %a@ %a@ %a)@]"
197
        (print_fmla info) f1 (print_fmla info) f2 (print_fmla info) f3
198
  | Tlet (t1, tb) ->
199
      let v, f2 = t_open_bound tb in
200
201
202
      fprintf fmt "@[(let ((%a %a))@ %a)@]" print_var v
        (print_term info) t1 (print_fmla info) f2;
      forget_var v
203
  | Tcase _ -> unsupportedTerm f
204
      "smtv2 : you must eliminate match"
205
  | Tvar _ | Tconst _ | Teps _ -> raise (FmlaExpected f)
206

207
208
and print_expr info fmt =
  TermTF.t_select (print_term info fmt) (print_fmla info fmt)
209

Andrei Paskevich's avatar
Andrei Paskevich committed
210
and print_trigger info fmt e = fprintf fmt "%a" (print_expr info) e
211
212
213
214
215
216
217

and print_triggers info fmt = function
  | [] -> ()
  | a::l -> fprintf fmt ":pattern (%a) %a"
    (print_list space (print_trigger info)) a
    (print_triggers info) l

218
219
let print_type_decl info fmt ts =
  if ts.ts_def <> None then () else
220
  if Mid.mem ts.ts_name info.info_syn then () else
221
222
  fprintf fmt "(declare-sort %a %i)@\n@\n"
    print_ident ts.ts_name (List.length ts.ts_args)
223

224
225
226
227
228
229
let print_param_decl info fmt ls =
  if Mid.mem ls.ls_name info.info_syn then () else
  fprintf fmt "@[<hov 2>(declare-fun %a (%a) %a)@]@\n@\n"
    print_ident ls.ls_name
    (print_list space (print_type info)) ls.ls_args
    (print_type_value info) ls.ls_value
230

231
let print_logic_decl info fmt (ls,def) =
232
  if Mid.mem ls.ls_name info.info_syn then () else
233
  let vsl,expr = Decl.open_ls_defn def in
234
  fprintf fmt "@[<hov 2>(define-fun %a (%a) %a %a)@]@\n@\n"
235
236
237
238
239
    print_ident ls.ls_name
    (print_var_list info) vsl
    (print_type_value info) ls.ls_value
    (print_expr info) expr;
  List.iter forget_var vsl
240
241
242
243
244
245
246

let print_prop_decl info fmt k pr f = match k with
  | Paxiom ->
      fprintf fmt "@[<hov 2>;; %s@\n(assert@ %a)@]@\n@\n"
        pr.pr_name.id_string (* FIXME? collisions *)
        (print_fmla info) f
  | Pgoal ->
247
248
      fprintf fmt "@[(assert@\n";
      fprintf fmt "@[;; %a@]@\n" print_ident pr.pr_name;
249
      (match pr.pr_name.id_loc with
250
251
252
        | None -> ()
        | Some loc -> fprintf fmt " @[;; %a@]@\n"
            Loc.gen_report_position loc);
253
254
255
256
      fprintf fmt "  @[(not@ %a))@]@\n" (print_fmla info) f;
      fprintf fmt "@[(check-sat)@]@\n"
  | Plemma| Pskip -> assert false

257
258
let print_constructor_decl info fmt (ls,args) =
  match args with
259
  | [] -> fprintf fmt "(%a)" print_ident ls.ls_name
260
  | _ ->
261
262
263
264
265
266
267
268
269
270
271
272
     fprintf fmt "@[(%a@ " print_ident ls.ls_name;
     let _ = 
       List.fold_left2
         (fun i ty pr ->
          begin match pr with
                | Some pr -> fprintf fmt "(%a" print_ident pr.ls_name
                | None -> fprintf fmt "(%a_proj_%d" print_ident ls.ls_name i
          end;
          fprintf fmt " %a)" (print_type info) ty;
          succ i) 1 ls.ls_args args
     in
     fprintf fmt ")@]"
273
274
275
276
277
278

let print_data_decl info fmt (ts,cl) =
  fprintf fmt "@[(%a@ %a)@]"
    print_ident ts.ts_name
    (print_list space (print_constructor_decl info)) cl

279
let print_decl info fmt d = match d.d_node with
280
281
  | Dtype ts ->
      print_type_decl info fmt ts
282
283
284
285
286
  | Ddata dl ->
    (*unsupportedDecl d
      "smtv2 : algebraic type are not supported" *)
    fprintf fmt "@[(declare-datatypes ()@ (%a))@]@\n"
      (print_list space (print_data_decl info)) dl
287
288
  | Dparam ls ->
      print_param_decl info fmt ls
289
290
291
  | Dlogic dl ->
      print_list nothing (print_logic_decl info) fmt dl
  | Dind _ -> unsupportedDecl d
292
      "smtv2 : inductive definition are not supported"
293
294
295
  | Dprop (k,pr,f) ->
      if Mid.mem pr.pr_name info.info_syn then () else
      print_prop_decl info fmt k pr f
296

297
let print_decls =
298
  let print_decl sm fmt d =
299
    try print_decl {info_syn = sm} fmt d; sm, []
300
301
302
303
    with Unsupported s -> raise (UnsupportedDecl (d,s)) in
  let print_decl = Printer.sprint_decl print_decl in
  let print_decl task acc = print_decl task.Task.task_decl acc in
  Discriminate.on_syntax_map (fun sm -> Trans.fold print_decl (sm,[]))
304

305
let print_task args ?old:_ fmt task =
306
  (* In trans-based p-printing [forget_all] is a no-no *)
307
  (* forget_all ident_printer; *)
308
309
  print_prelude fmt args.prelude;
  print_th_prelude task fmt args.th_prelude;
310
311
312
313
314
315
316
317
  let rec print = function
    | x :: r -> print r; Pp.string fmt x
    | [] -> () in
  print (snd (Trans.apply print_decls task));
  pp_print_flush fmt ()

let () = register_printer "smtv2" print_task
  ~desc:"Printer@ for@ the@ SMTlib@ version@ 2@ format."