1 (********************************************************************)
3 (* The Why3 Verification Platform / The Why3 Development Team *)
4 (* Copyright 2010-2024 -- Inria - CNRS - Paris-Saclay University *)
6 (* This software is distributed under the terms of the GNU Lesser *)
7 (* General Public License version 2.1, with the special exception *)
8 (* on linking described in file LICENSE. *)
10 (********************************************************************)
22 let bls = ["true";"false"]
25 let san = sanitizer char_to_alpha char_to_alnumus
in
26 create_ident_printer
bls ~sanitizer
:san
29 let san = sanitizer char_to_lalpha char_to_alnumus
in
30 create_ident_printer
bls ~sanitizer
:san
32 let print_symbol fmt id
=
33 let san = Strings.uncapitalize
in
34 pp_print_string fmt
(id_unique ~sanitizer
:san ident_printer id
)
36 let print_tvar fmt
{tv_name
= id
} =
37 let san = Strings.capitalize
in
38 pp_print_string fmt
(id_unique ~sanitizer
:san ident_printer id
)
40 let print_var fmt
{vs_name
= id
} =
41 let san = Strings.capitalize
in
42 pp_print_string fmt
(id_unique ~sanitizer
:san ident_printer id
)
45 pp_print_string fmt
(id_unique
pr_printer pr
.pr_name
)
47 let forget_var v
= forget_id
ident_printer v
.vs_name
48 let forget_tvar v
= forget_id
ident_printer v
.tv_name
50 type tptp_format
= FOF
| TFF0
| TFF1
52 type tptp_number
= TPTP
| MetiTarski
55 info_syn
: syntax_map
;
56 info_fmt
: tptp_format
;
57 info_num
: tptp_number
;
58 info_srt
: ty
Mty.t
ref;
59 info_urg
: string list
ref;
60 info_rules
: Decl.Spr.t
;
63 let complex_type = Wty.memoize
3 (fun ty
->
64 let s = Pp.string_of_wnl
Pretty.print_ty ty
in
65 create_tysymbol
(id_fresh
s) [] NoDef
)
67 let rec print_type info fmt ty
= match ty
.ty_node
with
68 | Tyvar _
when info
.info_fmt
= TFF0
->
69 unsupported
"TFF0 does not support polymorphic types"
70 | Tyvar tv
-> print_tvar fmt tv
72 begin match query_syntax info
.info_syn ts
.ts_name
, tl
with
73 | Some
s, _
-> syntax_arguments
s (print_type info
) fmt tl
74 | None
, [] -> print_symbol fmt ts
.ts_name
75 | None
, _
when info
.info_fmt
= TFF0
->
76 begin match Mty.find_opt ty
!(info
.info_srt
) with
77 | Some ty
-> print_type info fmt ty
79 let ts = complex_type ty
in let cty = ty_app
ts [] in
80 let us = Pp.sprintf
"@[<hov 2>tff(%s, type,@ %a:@ $tType).@]@\n@\n"
81 (id_unique
pr_printer ts.ts_name
) print_symbol ts.ts_name
in
82 info
.info_srt
:= Mty.add ty
cty !(info
.info_srt
);
83 info
.info_urg
:= us :: !(info
.info_urg
);
84 print_type info fmt
cty
87 fprintf fmt
"@[%a(%a)@]" print_symbol ts.ts_name
88 (print_list comma
(print_type info
)) tl
91 let print_type info fmt ty
= try print_type info fmt ty
92 with Unsupported
s -> raise
(UnsupportedType
(ty
,s))
95 Number.long_int_support
= `Default
;
96 Number.negative_int_support
=
97 `Custom
(fun fmt f
-> fprintf fmt
"-%t" f
);
98 Number.dec_int_support
= `Default
;
99 Number.hex_int_support
= `Unsupported
;
100 Number.oct_int_support
= `Unsupported
;
101 Number.bin_int_support
= `Unsupported
;
102 Number.negative_real_support
= `Default
;
103 Number.dec_real_support
= `Default
;
104 Number.hex_real_support
= `Unsupported
;
105 Number.frac_real_support
=
107 ((fun fmt i
-> fprintf fmt
"$to_real(%s)" i
),
108 (fun fmt i n
-> fprintf fmt
"$quotient($to_real(%s),$to_real(%s))" i n
));
111 let number_format_metitarski = {
113 Number.frac_real_support
=
115 ((fun fmt i
-> pp_print_string fmt i
),
116 (fun fmt i n
-> fprintf fmt
"(%s / %s)" i n
));
119 let print_const info fmt c
=
120 let supported = match info
.info_num
with
121 | TPTP
-> number_format
122 | MetiTarski
-> number_format_metitarski in
123 Constant.(print
supported unsupported_escape
) fmt c
125 let rec print_app info fmt ls tl oty
=
126 match query_syntax info
.info_syn ls
.ls_name
with
127 | Some
s -> syntax_arguments
s (print_term info
) fmt tl
129 let sbs = ls_app_inst ls tl oty
in
130 if Mtv.is_empty
sbs && tl
= [] then
131 print_symbol fmt ls
.ls_name
133 let cm = if Mtv.is_empty
sbs || tl
= [] then "" else ", " in
134 fprintf fmt
"%a(%a%s%a)"
135 print_symbol ls
.ls_name
136 (print_iter2
Mtv.iter comma nothing nothing
(print_type info
)) sbs
138 (print_list comma
(print_term info
)) tl
141 and print_term info fmt t
= match t
.t_node
with
145 print_app info fmt ls tl t
.t_ty
147 print_const info fmt c
149 let v,t2
= t_open_bound tb
in
150 fprintf fmt
"$let_tt(%a@ =@ %a,@ %a)"
151 print_symbol v.vs_name
(print_term info
) t1
(print_term info
) t2
;
154 fprintf fmt
"$ite_t(%a,@ %a,@ %a)"
155 (print_fmla info
) f1
(print_term info
) t1
(print_term info
) t2
156 | Tcase _
-> unsupportedTerm t
157 "TPTP does not support pattern matching, use eliminate_algebraic"
158 | Teps _
-> unsupportedTerm t
159 "TPTP does not support epsilon-terms"
160 | Tquant _
| Tbinop _
| Tnot _
| Ttrue
| Tfalse
-> raise
(TermExpected t
)
162 and print_fmla info fmt f
= match f
.t_node
with
164 print_app info fmt ls tl f
.t_ty
165 | Tbinop
(op
, f1
, f2
) ->
166 let s = match op
with
167 | Tand
-> "&" | Tor
-> "|" | Timplies
-> "=>" | Tiff
-> "<=>" in
168 fprintf fmt
"(%a@ %s %a)" (print_fmla info
) f1
s (print_fmla info
) f2
170 fprintf fmt
"~@ %a" (print_fmla info
) f
172 pp_print_string fmt
"$true"
174 pp_print_string fmt
"$false"
176 let q = match q with Tforall
-> "!" | Texists
-> "?" in
177 let vl, _tl
, f
= t_open_quant fq
in
178 let print_vsty fmt vs
=
179 if info
.info_fmt
= FOF
then print_var fmt vs
180 else fprintf fmt
"%a:@,%a" print_var vs
(print_type info
) vs
.vs_ty
in
181 fprintf fmt
"%s[%a]:@ %a" q
182 (print_list comma
print_vsty) vl (print_fmla info
) f
;
183 List.iter
forget_var vl
185 let v,t2
= t_open_bound tb
in
186 fprintf fmt
"$let_tf(%a@ =@ %a,@ %a)"
187 print_symbol v.vs_name
(print_term info
) t1
(print_fmla info
) t2
;
190 fprintf fmt
"$ite_f(%a,@ %a,@ %a)"
191 (print_fmla info
) f1
(print_fmla info
) t1
(print_fmla info
) t2
192 | Tcase _
-> unsupportedTerm f
193 "TPTP does not support pattern matching, use eliminate_algebraic"
194 | Tvar _
| Tconst _
| Teps _
-> raise
(FmlaExpected f
)
196 let print_tvarg fmt tv
= fprintf fmt
"%a : $tType" print_tvar tv
197 let print_tvargs fmt tvs
= print_iter1
Stv.iter comma
print_tvarg fmt tvs
199 let star fmt _
= fprintf fmt
" *@ "
201 let print_fmla info fmt f
=
202 let tvs = t_ty_freevars
Stv.empty f
in
203 if Stv.is_empty
tvs then print_fmla info fmt f
else
204 fprintf fmt
"![%a]:@ %a" print_tvargs tvs (print_fmla info
) f
;
205 Stv.iter
forget_tvar tvs
207 let print_decl info fmt d
= match d
.d_node
with
208 | Dtype _
when info
.info_fmt
= FOF
-> ()
209 | Dtype
{ ts_def
= Alias _
} -> ()
210 | Dtype
{ ts_args
= _
::_
} when info
.info_fmt
= TFF0
-> ()
211 | Dtype
ts when query_syntax info
.info_syn
ts.ts_name
<> None
-> ()
213 let print_arg fmt _
= pp_print_string fmt
"$tType" in
214 let print_sig fmt
ts = match ts.ts_args
with
215 | [] -> pp_print_string fmt
"$tType"
216 | [_
] -> fprintf fmt
"$tType >@ $tType"
217 | tl
-> fprintf fmt
"(%a) >@ $tType" (print_list
star print_arg) tl
219 fprintf fmt
"@[<hov 2>tff(%s, type,@ %a:@ %a).@]@\n@\n"
220 (id_unique
pr_printer ts.ts_name
)
221 print_symbol ts.ts_name
print_sig ts
222 | Dparam _
when info
.info_fmt
= FOF
-> ()
223 | Dparam ls
when query_syntax info
.info_syn ls
.ls_name
<> None
-> ()
225 let print_type = print_type info
in
226 let print_val fmt
= function
227 | Some ty
-> print_type fmt ty
228 | None
-> fprintf fmt
"$o" in
229 let print_sig fmt ls
= match ls
.ls_args
with
230 | [] -> print_val fmt ls
.ls_value
231 | [ty
] -> fprintf fmt
"%a >@ %a"
232 print_type ty
print_val ls
.ls_value
233 | tl
-> fprintf fmt
"(%a) >@ %a"
234 (print_list
star print_type) tl
print_val ls
.ls_value
in
235 let print_sig fmt ls
=
236 let tvs = List.fold_left ty_freevars
Stv.empty ls
.ls_args
in
237 let tvs = oty_freevars
tvs ls
.ls_value
in
238 if Stv.is_empty
tvs then
240 else if ls
.ls_args
= [] then
241 fprintf fmt
"!>[%a]:@ %a" print_tvargs tvs print_sig ls
243 fprintf fmt
"!>[%a]:@ (%a)" print_tvargs tvs print_sig ls
;
244 Stv.iter
forget_tvar tvs
246 fprintf fmt
"@[<hov 2>tff(%s, type,@ %a:@ %a).@]@\n@\n"
247 (id_unique
pr_printer ls
.ls_name
)
248 print_symbol ls
.ls_name
print_sig ls
249 | Ddata _
-> unsupportedDecl d
250 "TPTP does not support algebraic datatypes, use eliminate_algebraic"
251 | Dlogic _
-> unsupportedDecl d
252 "Definitions are not supported, use eliminate_definition"
253 | Dind _
-> unsupportedDecl d
254 "TPTP does not support inductive predicates, use eliminate_inductive"
255 | Dprop
(Paxiom
, pr
, _
) when Mid.mem pr
.pr_name info
.info_syn
-> ()
256 | Dprop
(Paxiom
, pr
, f
) ->
258 Format.eprintf "Dprop for %s: rewrite rules:" pr.pr_name.id_string;
259 Spr.iter (fun pr -> Format.eprintf " %s" pr.pr_name.id_string) info.info_rules;
262 let annotation = if Spr.mem pr info
.info_rules
then ",rewrite" else "" in
263 let head = if info
.info_fmt
= FOF
then "fof" else "tff" in
264 fprintf fmt
"@[<hov 2>%s(%a, axiom,@ %a%s).@]@\n@\n"
265 head print_pr pr
(print_fmla info
) f
annotation
266 | Dprop
(Pgoal
, pr
, f
) ->
267 let head = if info
.info_fmt
= FOF
then "fof" else "tff" in
268 fprintf fmt
"@[<hov 2>%s(%a, conjecture,@ %a).@]@\n"
269 head print_pr pr
(print_fmla info
) f
270 | Dprop
(Plemma
, _
, _
) -> assert false
272 let print_decls fm nm
=
274 Format.eprintf "rewrite rules:";
275 Spr.iter (fun pr -> Format.eprintf " %s" pr.pr_name.id_string) rew_rules;
278 let print_decl (sm
,fm
,rr
,ct
) fmt d
=
279 let info = { info_syn
= sm
;
285 try print_decl info fmt d
;
286 (sm
,fm
,rr
,!(info.info_srt
)), !(info.info_urg
)
287 with Unsupported
s -> raise
(UnsupportedDecl
(d
,s)) in
288 let print_decl = Printer.sprint_decl
print_decl in
289 let print_decl task acc
= print_decl task
.Task.task_decl acc
in
290 Discriminate.on_syntax_map
(fun sm
->
291 Trans.on_tagged_pr
Compute.meta_rewrite
(fun rr
->
292 Trans.fold
print_decl ((sm
,fm
,rr
,Mty.empty
),[])))
294 let print_task fm nm
=
295 let print_decls = print_decls fm nm
in
296 fun args ?old
:_ fmt task
->
297 (* In trans-based p-printing [forget_all] is a no-no *)
298 (* forget_all ident_printer; *)
299 print_prelude fmt args
.prelude
;
300 print_th_prelude task fmt args
.th_prelude
;
301 let rec print = function
302 | x
:: r
-> print r
; Pp.string fmt x
304 print (snd
(Trans.apply
print_decls task
));
305 pp_print_flush fmt
()
308 register_printer
"tptp-tff0" (print_task TFF0 TPTP
) ~desc
:"TPTP TFF0 format";
309 register_printer
"tptp-tff1" (print_task TFF1 TPTP
) ~desc
:"TPTP TFF1 format";
310 register_printer
"tptp-fof" (print_task FOF TPTP
) ~desc
:"TPTP FOF format"
313 register_printer
"metitarski" (print_task FOF MetiTarski
)
314 ~desc
:"MetiTarski TPTP format"
316 (** DFG input format for SPASS >= 3.8
317 (with the help of Daniel Wand)
320 - type arguments for polymorphic functions and predicates
324 let is_type info d
= match d
.d_node
with
325 | Dtype
ts -> query_syntax
info.info_syn
ts.ts_name
= None
326 | Ddata _
-> unsupportedDecl d
"no data types"
328 let is_function info d
= match d
.d_node
with
330 ls
.ls_value
<> None
&& query_syntax
info.info_syn ls
.ls_name
= None
332 let is_predicate info d
= match d
.d_node
with
334 ls
.ls_value
= None
&& query_syntax
info.info_syn ls
.ls_name
= None
337 let ls_arity fmt d
= match d
.d_node
with
339 let ntv = Stv.cardinal
(ls_ty_freevars ls
) in
340 let na = List.length ls
.ls_args
in
341 if ntv = 0 then fprintf fmt
"(%a, %d)" print_symbol ls
.ls_name
na
342 else fprintf fmt
"(%a, %d+%d)" print_symbol ls
.ls_name
ntv na
344 let type_arity fmt d
= match d
.d_node
with
346 let ntv = List.length
ts.ts_args
in
347 if ntv = 0 then print_symbol fmt
ts.ts_name
348 else fprintf fmt
"(%a, %d)" print_symbol ts.ts_name
ntv
351 let ls_type kind
info fmt d
= match d
.d_node
with
353 fprintf fmt
"%s(@[%a" kind
print_symbol ls
.ls_name
;
354 let tvs = ls_ty_freevars ls
in
355 if not
(Stv.is_empty
tvs) then
356 fprintf fmt
", [%a]" (print_list comma
print_tvar) (Stv.elements
tvs);
357 begin match ls
.ls_value
, ls
.ls_args
with
360 fprintf fmt
", %a" (print_list comma
(print_type info)) ls
.ls_args
361 | Some ty
, [] -> fprintf fmt
", %a" (print_type info) ty
363 fprintf fmt
", (%a) %a" (print_list comma
(print_type info))
364 ls
.ls_args
(print_type info) ty
366 fprintf fmt
"@]).@\n";
367 Stv.iter
forget_tvar tvs
370 let rec print_app info fmt ls tl oty
=
371 match query_syntax
info.info_syn ls
.ls_name
with
372 | Some
s -> syntax_arguments
s (print_term
info) fmt tl
374 print_symbol fmt ls
.ls_name
;
375 let sbs = ls_app_inst ls tl oty
in
376 if not
(Mtv.is_empty
sbs) then
378 (print_iter2
Mtv.iter comma nothing nothing
(print_type info)) sbs;
381 (print_list comma
(print_term
info)) tl
383 and print_term
info fmt t
= match t
.t_node
with
387 print_app info fmt ls tl t
.t_ty
389 Constant.(print number_format unsupported_escape
) fmt c
390 | Tlet
_ -> unsupportedTerm t
391 "DFG does not support let, use eliminate_let"
392 | Tif
_ -> unsupportedTerm t
393 "DFG does not support if, use eliminate_if"
394 | Tcase
_ -> unsupportedTerm t
395 "TPTP does not support pattern matching, use eliminate_algebraic"
396 | Teps
_ -> unsupportedTerm t
397 "TPTP does not support epsilon-terms"
398 | Tquant
_ | Tbinop
_ | Tnot
_ | Ttrue
| Tfalse
-> raise
(TermExpected t
)
400 let rec print_fmla info fmt f
= match f
.t_node
with
402 print_app info fmt ls tl f
.t_ty
403 | Tbinop
(op
, f1
, f2
) ->
404 let s = match op
with
405 | Tand
-> "and" | Tor
-> "or"
406 | Timplies
-> "implies" | Tiff
-> "equiv" in
407 fprintf fmt
"%s(%a,@ %a)" s (print_fmla info) f1
(print_fmla info) f2
409 fprintf fmt
"not(%a)" (print_fmla info) f
411 pp_print_string fmt
"true"
413 pp_print_string fmt
"false"
415 let q = match q with Tforall
-> "forall" | Texists
-> "exists" in
416 let vl, _tl
, f
= t_open_quant fq
in
417 let print_vsty fmt vs
=
418 fprintf fmt
"%a:@,%a" print_var vs
(print_type info) vs
.vs_ty
in
419 fprintf fmt
"%s([%a],@ %a)" q
420 (print_list comma
print_vsty) vl (print_fmla info) f
;
421 List.iter
forget_var vl
422 | Tlet
_ -> unsupportedTerm f
423 "DFG does not support let, use eliminate_let"
424 | Tif
_ -> unsupportedTerm f
425 "DFG does not support if, use eliminate_if"
426 | Tcase
_ -> unsupportedTerm f
427 "DFG does not support pattern matching, use eliminate_algebraic"
428 | Tvar
_ | Tconst
_ | Teps
_ -> raise
(FmlaExpected f
)
430 let print_axiom info fmt d
= match d
.d_node
with
431 | Dprop
(Paxiom
, pr
, _) when Mid.mem pr
.pr_name
info.info_syn
-> ()
432 | Dprop
(Paxiom
, pr
, f
) ->
433 fprintf fmt
"@[<hov 2>formula(%a, %a).@]@\n"
434 (print_fmla info) f
print_pr pr
437 let print_dfg args ?old
:_ fmt task
=
438 forget_all
ident_printer;
439 forget_all
pr_printer;
440 fprintf fmt
"@[begin_problem(why3).@\n@\n";
441 print_prelude fmt args
.prelude
;
442 print_th_prelude task fmt args
.th_prelude
;
443 fprintf fmt
"list_of_descriptions.@\n";
445 "name({**}). author({**}). status(unknown). description({**}).@\n";
446 fprintf fmt
"end_of_list.@\n@\n";
448 info_syn
= get_syntax_map task
;
452 info_srt
= ref Mty.empty
;
453 info_rules
= Spr.empty
;
455 let dl = Task.task_decls task
in
456 let tl = List.filter
(is_type info) dl in
457 let fl = List.filter
(is_function info) dl in
458 let pl = List.filter
(is_predicate info) dl in
460 fprintf fmt
"list_of_symbols.@\n";
461 fprintf fmt
"functions [@[%a@]].@\n" (print_list comma
ls_arity) fl;
462 fprintf fmt
"predicates [@[%a@]].@\n" (print_list comma
ls_arity) pl;
463 fprintf fmt
"sorts [@[%a@]].@\n" (print_list comma
type_arity) tl;
464 fprintf fmt
"end_of_list.@\n@\n";
466 fprintf fmt
"list_of_declarations.@\n";
467 List.iter
(ls_type "function" info fmt
) fl;
468 List.iter
(ls_type "predicate" info fmt
) pl;
469 fprintf fmt
"end_of_list.@\n@\n";
471 fprintf fmt
"list_of_formulae(axioms).@\n";
472 List.iter
(print_axiom info fmt
) dl;
473 fprintf fmt
"end_of_list.@\n@\n";
474 fprintf fmt
"list_of_formulae(conjectures).@\n";
476 let f = Task.task_goal_fmla task
in
477 fprintf fmt
"@[<hov 2>formula(%a, %a)@].@\n" (print_fmla info) f
478 print_pr (Task.task_goal task
);
479 fprintf fmt
"end_of_list.@\n@\n";
480 fprintf fmt
"end_problem.@\n"
483 register_printer
"dfg" print_dfg ~desc
:"First-order monomorphic DFG format"