smtv2.ml 10.9 KB
Newer Older
Andrei Paskevich's avatar
Andrei Paskevich committed
1
2
3
(********************************************************************)
(*                                                                  *)
(*  The Why3 Verification Platform   /   The Why3 Development Team  *)
4
(*  Copyright 2010-2013   --   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
22

(** SMT v1 printer with some extensions *)

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

23
(** SMTLIB tokens taken from CVC4: src/parser/smt2/Smt2.g *)
24
25
26
27
28
29
30
31
32
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 *)
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
    [(** 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";
      "bvugt"; "bvuge"; "bvslt"; "bvsle"; "bvsgt"; "bvsge";

      (** Other stuff that Why3 seems to need *)
      "DECIMAL"; "NUMERAL"; "par"; "STRING";
61
      "unsat";"sat";
62
63
64
65
      "Bool"; "true"; "false";
      "Array";"const";
      "abs";
      "BitVec"; "extract"; "bv2nat"; "nat2bv"
Andrei Paskevich's avatar
Andrei Paskevich committed
66
      ]
67
68
69
70
71
72
73
74
  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 = {
75
  info_syn : syntax_map;
76
77
}

78
(** type *)
79
80
let rec print_type info fmt ty = match ty.ty_node with
  | Tyvar _ -> unsupported "smt : you must encode the polymorphism"
81
  | Tyapp (ts, l) ->
82
83
84
85
86
     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
87
88
     end

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

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 =
104
105
  fprintf fmt "(%a %a)" print_var vs
    (print_type info) vs.vs_ty
106
107
108
109
110
111

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
112
113
  | Tconst c ->
      let number_format = {
114
          Number.long_int_support = true;
115
          Number.extra_leading_zeros_support = false;
116
117
118
119
120
121
122
123
124
125
          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;
126
        } in
127
      Number.print number_format fmt c
128
129
  | Tvar v -> print_var fmt v
  | Tapp (ls, tl) -> begin match query_syntax info.info_syn ls.ls_name with
130
      | Some s -> syntax_arguments_typed s (print_term info)
131
        (print_type info) t fmt tl
132
133
134
      | None -> begin match tl with (* for cvc3 wich doesn't accept (toto ) *)
          | [] -> fprintf fmt "@[%a@]" print_ident ls.ls_name
          | _ -> fprintf fmt "@[(%a@ %a)@]"
135
              print_ident ls.ls_name (print_list space (print_term info)) tl
136
137
138
        end end
  | Tlet (t1, tb) ->
      let v, t2 = t_open_bound tb in
139
      fprintf fmt "@[(let ((%a %a))@ %a)@]" print_var v
140
141
142
143
144
145
146
147
148
        (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"
149
  | Tquant _ | Tbinop _ | Tnot _ | Ttrue | Tfalse -> raise (TermExpected t)
150

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

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

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

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

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

223
224
225
226
227
228
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
229

230
let print_logic_decl info fmt (ls,def) =
231
  if Mid.mem ls.ls_name info.info_syn then () else
232
  let vsl,expr = Decl.open_ls_defn def in
233
  fprintf fmt "@[<hov 2>(define-fun %a (%a) %a %a)@]@\n@\n"
234
235
236
237
238
    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
239
240
241
242
243
244
245

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 ->
246
247
      fprintf fmt "@[(assert@\n";
      fprintf fmt "@[;; %a@]@\n" print_ident pr.pr_name;
248
      (match pr.pr_name.id_loc with
249
250
251
        | None -> ()
        | Some loc -> fprintf fmt " @[;; %a@]@\n"
            Loc.gen_report_position loc);
252
253
254
255
256
      fprintf fmt "  @[(not@ %a))@]@\n" (print_fmla info) f;
      fprintf fmt "@[(check-sat)@]@\n"
  | Plemma| Pskip -> assert false

let print_decl info fmt d = match d.d_node with
257
258
259
260
261
262
  | Dtype ts ->
      print_type_decl info fmt ts
  | Ddata _ -> unsupportedDecl d
      "smtv2 : algebraic type are not supported"
  | Dparam ls ->
      print_param_decl info fmt ls
263
264
265
  | Dlogic dl ->
      print_list nothing (print_logic_decl info) fmt dl
  | Dind _ -> unsupportedDecl d
266
      "smtv2 : inductive definition are not supported"
267
268
269
  | Dprop (k,pr,f) ->
      if Mid.mem pr.pr_name info.info_syn then () else
      print_prop_decl info fmt k pr f
270

271
let print_decls =
272
  let print_decl sm fmt d =
273
    try print_decl {info_syn = sm} fmt d; sm, []
274
275
276
277
    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,[]))
278

279
let print_task args ?old:_ fmt task =
280
  (* In trans-based p-printing [forget_all] is a no-no *)
281
  (* forget_all ident_printer; *)
282
283
  print_prelude fmt args.prelude;
  print_th_prelude task fmt args.th_prelude;
284
285
286
287
288
289
290
291
  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."