File: jc_pattern.ml

package info (click to toggle)
why 2.13-2
  • links: PTS, VCS
  • area: main
  • in suites: lenny
  • size: 12,608 kB
  • ctags: 16,817
  • sloc: ml: 102,672; java: 7,173; ansic: 4,439; makefile: 1,409; sh: 585
file content (190 lines) | stat: -rw-r--r-- 7,179 bytes parent folder | download
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
190
(**************************************************************************)
(*                                                                        *)
(*  The Why platform for program certification                            *)
(*  Copyright (C) 2002-2008                                               *)
(*    Romain BARDOU                                                       *)
(*    Jean-François COUCHOT                                               *)
(*    Mehdi DOGGUY                                                        *)
(*    Jean-Christophe FILLIÂTRE                                           *)
(*    Thierry HUBERT                                                      *)
(*    Claude MARCHÉ                                                       *)
(*    Yannick MOY                                                         *)
(*    Christine PAULIN                                                    *)
(*    Yann RÉGIS-GIANAS                                                   *)
(*    Nicolas ROUSSET                                                     *)
(*    Xavier URBAIN                                                       *)
(*                                                                        *)
(*  This software is free software; you can redistribute it and/or        *)
(*  modify it under the terms of the GNU General Public                   *)
(*  License version 2, as published by the Free Software Foundation.      *)
(*                                                                        *)
(*  This software is distributed in the hope that it will be useful,      *)
(*  but WITHOUT ANY WARRANTY; without even the implied warranty of        *)
(*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                  *)
(*                                                                        *)
(*  See the GNU General Public License version 2 for more details         *)
(*  (enclosed in the file GPL).                                           *)
(*                                                                        *)
(**************************************************************************)

open Jc_pervasives
open Jc_name
open Jc_ast
open Jc_env
open Jc_interp_misc
open Output

module type TAssertionMaker = sig
  type t
  val make_subtag: term -> struct_info -> t
  val make_or: t -> t -> t
  val make_and: t -> t -> t
  val make_not: t -> t
  val make_false: t
  val make_true: t
  val make_eq: jc_type -> term -> term -> t
end

module Pattern(AM: TAssertionMaker) = struct
  (** [pattern arg ty pat] translates the pattern [pat] applied to the term
    [arg] which have a [jc_type] of [ty].
    Returns [notcond, cond, vars] where:
    [notcond] is an assertion equivalent to "the pattern cannot be applied";
    [cond] is an assertion equivalent to "the pattern can be applied" and giving
      the values of each binded variable;
    [vars] is a list of [name, user_name, ty] where [user_name] is a variable
      binded by the pattern, [name] its unique name used in [cond], and
      [ty] its [jc_type]. *)
  let rec pattern arg ty pat = match pat#node with
    | JCPstruct(st, fpl) ->
	let subtag = AM.make_subtag arg st in
	List.fold_left
	  (fun (accnotcond, acccond, accvars) (fi, pat) ->
	     let arg = make_select_fi fi arg in
	     let ty = fi.jc_field_info_type in
	     let notcond, cond, vars = pattern arg ty pat in
	     AM.make_or accnotcond notcond,
	     AM.make_and acccond cond,
	     accvars @ vars)
	  (AM.make_not subtag, subtag, [])
	  fpl
    | JCPvar vi ->
	AM.make_false,
	AM.make_eq ty (LVar vi.jc_var_info_final_name) arg,
	[vi.jc_var_info_final_name, ty]
    | JCPor(p1, p2) ->
      (* typing ensures that both patterns bind the same variables *)
	let notcond1, cond1, vars = pattern arg ty p1 in
	let notcond2, cond2, _ = pattern arg ty p2 in
	AM.make_and notcond1 notcond2,
	AM.make_or cond1 cond2,
	vars
    | JCPas(p, vi) ->
	let notcond, cond, vars = pattern arg ty p in
	notcond,
	AM.make_and
	  cond
	  (AM.make_eq ty (LVar vi.jc_var_info_final_name) arg),
	(vi.jc_var_info_final_name, ty)::vars
    | JCPany | JCPconst JCCvoid ->
	AM.make_false,
	AM.make_true,
	[]
    | JCPconst c ->
	let eq = AM.make_eq ty arg (LConst (const c)) in
	AM.make_not eq,
	eq,
	[]
end

module MakeAssertion = struct
  type t = Output.assertion

  let make_subtag x st =
    make_subtag (make_typeof st x) (LVar (tag_name st))
  let make_or a b = LOr(a, b)
  let make_and a b = LAnd(a, b)
  let make_not a = LNot a
  let make_false = LFalse
  let make_true = LTrue
  let make_eq _ = make_eq
end
module PatternAssertion = Pattern(MakeAssertion)

module MakeTerm = struct
  type t = Output.term

  let make_subtag x st =
    make_subtag_bool (make_typeof st x) (LVar (tag_name st))
  let make_or = make_or_term
  let make_and = make_and_term
  let make_not = make_not_term
  let make_false = LConst(Prim_bool false)
  let make_true = LConst(Prim_bool false)
  let make_eq = make_eq_term
end
module PatternTerm = Pattern(MakeTerm)

let make_blackbox_annot pre ty reads writes post exn_posts =
  BlackBox(Annot_type(pre, ty, reads, writes, post, exn_posts))

let pattern_list_expr translate_body arg r ty pbl =
  List.fold_left
    (fun accbody (pat, body) ->
       let notcond, cond, vars = PatternAssertion.pattern arg ty pat in
       let body = translate_body body in
       let reads =
	 let ef = Jc_effect.pattern empty_effects (*LabelHere region*) pat in
	 all_effects ef
       in
       let writes = List.map fst vars in
       let post = LIf(LVar "result", cond, notcond) in
       let bbox = make_blackbox_annot LTrue bool_type reads writes post [] in
       let branch = List.fold_left
	 (fun acc (name, ty) -> Let_ref(name, any_value ty, acc))
	 (If(bbox, body, accbody))
	 vars
       in
       branch)
    Absurd
    (List.rev pbl)

let pattern_list_term translate_body arg ty pbl default =
  (* Right now, all binders are put at the predicate level, so there might
     be problems (though variables are renamed so it should be ok).
     Will be better when (if) Why has Let binders at the term level. *)
  List.fold_left
    (fun (accbody, acclets) (pat, body) ->
       let _, cond, vars = PatternTerm.pattern arg ty pat in
       let body, lets1 = translate_body body in
       let body = make_if_term cond body accbody in
       let lets2 = List.map
	 (fun (n, ty) -> JCforall(n, tr_base_type ty))
	 vars
       in
       body, lets1@lets2)
    (default, [])
    (List.rev pbl)

let pattern_list_assertion translate_body arg ty pbl default =
  List.fold_left
    (fun (accbody, accnotcond) (pat, body) ->
       (* not previous case => (forall vars, arg matches pattern => body) *)
       let notcond, cond, vars = PatternAssertion.pattern arg ty pat in
       let body = translate_body body in
       let case =
	 List.fold_left
	   (fun acc (n, ty) -> LForall(n, tr_base_type ty, acc))
	   (LImpl(cond, body))
	   vars
       in
       let full_case = LImpl(accnotcond, case) in
       LAnd(accbody, full_case), LAnd(accnotcond, notcond))
    (default, LTrue)
    pbl

(*
  Local Variables: 
  compile-command: "unset LANG; make -j -C .. bin/jessie.byte"
  End:
*)