|
1 (* Title: HOL/Nunchaku/Tools/nunchaku_model.ML |
|
2 Author: Jasmin Blanchette, VU Amsterdam |
|
3 Copyright 2015, 2016, 2017 |
|
4 |
|
5 Abstract syntax tree for Nunchaku models. |
|
6 *) |
|
7 |
|
8 signature NUNCHAKU_MODEL = |
|
9 sig |
|
10 type ident = Nunchaku_Problem.ident |
|
11 type ty = Nunchaku_Problem.ty |
|
12 type tm = Nunchaku_Problem.tm |
|
13 type name_pool = Nunchaku_Problem.name_pool |
|
14 |
|
15 type ty_entry = ty * tm list |
|
16 type tm_entry = tm * tm |
|
17 |
|
18 type nun_model = |
|
19 {type_model: ty_entry list, |
|
20 const_model: tm_entry list, |
|
21 skolem_model: tm_entry list} |
|
22 |
|
23 val str_of_nun_model: nun_model -> string |
|
24 |
|
25 val allocate_ugly: name_pool -> string * string -> string * name_pool |
|
26 |
|
27 val ugly_nun_model: name_pool -> nun_model -> nun_model |
|
28 |
|
29 datatype token = |
|
30 Ident of ident |
|
31 | Symbol of ident |
|
32 | Atom of ident * int |
|
33 | End_of_Stream |
|
34 |
|
35 val parse_tok: ''a -> ''a list -> ''a * ''a list |
|
36 val parse_ident: token list -> ident * token list |
|
37 val parse_id: ident -> token list -> token * token list |
|
38 val parse_sym: ident -> token list -> token * token list |
|
39 val parse_atom: token list -> (ident * int) * token list |
|
40 val nun_model_of_str: string -> nun_model |
|
41 end; |
|
42 |
|
43 structure Nunchaku_Model : NUNCHAKU_MODEL = |
|
44 struct |
|
45 |
|
46 open Nunchaku_Problem; |
|
47 |
|
48 type ty_entry = ty * tm list; |
|
49 type tm_entry = tm * tm; |
|
50 |
|
51 type nun_model = |
|
52 {type_model: ty_entry list, |
|
53 const_model: tm_entry list, |
|
54 skolem_model: tm_entry list}; |
|
55 |
|
56 val nun_SAT = str_of_ident "SAT"; |
|
57 |
|
58 fun str_of_ty_entry (ty, tms) = |
|
59 "type " ^ str_of_ty ty ^ " := {" ^ commas (map str_of_tm tms) ^ "}."; |
|
60 |
|
61 fun str_of_tm_entry (tm, value) = |
|
62 "val " ^ str_of_tm tm ^ " := " ^ str_of_tm value ^ "."; |
|
63 |
|
64 fun str_of_nun_model {type_model, const_model, skolem_model} = |
|
65 map str_of_ty_entry type_model @ "" :: map str_of_tm_entry const_model @ "" :: |
|
66 map str_of_tm_entry skolem_model |
|
67 |> cat_lines; |
|
68 |
|
69 fun fold_map_ty_entry_idents f (ty, atoms) = |
|
70 fold_map_ty_idents f ty |
|
71 ##>> fold_map (fold_map_tm_idents f) atoms; |
|
72 |
|
73 fun fold_map_tm_entry_idents f (tm, value) = |
|
74 fold_map_tm_idents f tm |
|
75 ##>> fold_map_tm_idents f value; |
|
76 |
|
77 fun fold_map_nun_model_idents f {type_model, const_model, skolem_model} = |
|
78 fold_map (fold_map_ty_entry_idents f) type_model |
|
79 ##>> fold_map (fold_map_tm_entry_idents f) const_model |
|
80 ##>> fold_map (fold_map_tm_entry_idents f) skolem_model |
|
81 #>> (fn ((type_model, const_model), skolem_model) => |
|
82 {type_model = type_model, const_model = const_model, skolem_model = skolem_model}); |
|
83 |
|
84 fun swap_name_pool ({nice_of_ugly, ugly_of_nice} : name_pool) = |
|
85 {nice_of_ugly = ugly_of_nice, ugly_of_nice = nice_of_ugly}; |
|
86 |
|
87 fun allocate_ugly pool (nice, ugly_sugg) = |
|
88 allocate_nice (swap_name_pool pool) (nice, ugly_sugg) ||> swap_name_pool; |
|
89 |
|
90 fun ugly_ident nice (pool as {ugly_of_nice, ...}) = |
|
91 (case Symtab.lookup ugly_of_nice nice of |
|
92 NONE => allocate_ugly pool (nice, nice) |
|
93 | SOME ugly => (ugly, pool)); |
|
94 |
|
95 fun ugly_nun_model pool model = |
|
96 fst (fold_map_nun_model_idents ugly_ident model pool); |
|
97 |
|
98 datatype token = |
|
99 Ident of ident |
|
100 | Symbol of ident |
|
101 | Atom of ident * int |
|
102 | End_of_Stream; |
|
103 |
|
104 val rev_str = String.implode o rev o String.explode; |
|
105 |
|
106 fun atom_of_str s = |
|
107 (case first_field "_" (rev_str s) of |
|
108 SOME (rev_suf, rev_pre) => |
|
109 let |
|
110 val pre = rev_str rev_pre; |
|
111 val suf = rev_str rev_suf; |
|
112 in |
|
113 (case Int.fromString suf of |
|
114 SOME j => Atom (ident_of_str pre, j) |
|
115 | NONE => raise Fail "ill-formed atom") |
|
116 end |
|
117 | NONE => raise Fail "ill-formed atom"); |
|
118 |
|
119 fun is_alnum_etc_char c = Char.isAlphaNum c orelse c = #"_" orelse c = #"/"; |
|
120 |
|
121 val multi_ids = |
|
122 [nun_arrow, nun_assign, nun_conj, nun_disj, nun_implies, nun_unparsable, nun_irrelevant]; |
|
123 |
|
124 val nun_anon_fun_prefix_exploded = String.explode nun_anon_fun_prefix; |
|
125 val [nun_dollar_char] = String.explode nun_dollar; |
|
126 |
|
127 fun next_token [] = (End_of_Stream, []) |
|
128 | next_token (c :: cs) = |
|
129 if Char.isSpace c then |
|
130 next_token cs |
|
131 else if c = nun_dollar_char then |
|
132 let val n = find_index (not o is_alnum_etc_char) cs in |
|
133 (if n = ~1 then (cs, []) else chop n cs) |
|
134 |>> (String.implode |
|
135 #> (if is_prefix (op =) nun_anon_fun_prefix_exploded cs then ident_of_str #> Ident |
|
136 else atom_of_str)) |
|
137 end |
|
138 else if is_alnum_etc_char c then |
|
139 let val n = find_index (not o is_alnum_etc_char) cs in |
|
140 (if n = ~1 then (cs, []) else chop n cs) |
|
141 |>> (cons c #> String.implode #> ident_of_str #> Ident) |
|
142 end |
|
143 else |
|
144 let |
|
145 fun next_multi id = |
|
146 let |
|
147 val s = str_of_ident id; |
|
148 val n = String.size s - 1; |
|
149 in |
|
150 if c = String.sub (s, 0) andalso |
|
151 is_prefix (op =) (String.explode (String.substring (s, 1, n))) cs then |
|
152 SOME (Symbol id, drop n cs) |
|
153 else |
|
154 NONE |
|
155 end; |
|
156 in |
|
157 (case get_first next_multi multi_ids of |
|
158 SOME res => res |
|
159 | NONE => (Symbol (ident_of_str (String.str c)), cs)) |
|
160 end; |
|
161 |
|
162 val tokenize = |
|
163 let |
|
164 fun toks cs = |
|
165 (case next_token cs of |
|
166 (End_of_Stream, []) => [] |
|
167 | (tok, cs') => tok :: toks cs'); |
|
168 in |
|
169 toks o String.explode |
|
170 end; |
|
171 |
|
172 fun parse_enum sep scan = scan ::: Scan.repeat (sep |-- scan); |
|
173 |
|
174 fun parse_tok tok = Scan.one (curry (op =) tok); |
|
175 |
|
176 val parse_ident = Scan.some (try (fn Ident id => id)); |
|
177 val parse_id = parse_tok o Ident; |
|
178 val parse_sym = parse_tok o Symbol; |
|
179 val parse_atom = Scan.some (try (fn Atom id_j => id_j)); |
|
180 |
|
181 val confusing_ids = [nun_else, nun_then, nun_with]; |
|
182 |
|
183 val parse_confusing_id = Scan.one (fn Ident id => member (op =) confusing_ids id | _ => false); |
|
184 |
|
185 fun parse_ty toks = |
|
186 (parse_ty_arg -- Scan.option (parse_sym nun_arrow -- parse_ty) |
|
187 >> (fn (ty, NONE) => ty |
|
188 | (lhs, SOME (Symbol id, rhs)) => NType (id, [lhs, rhs]))) toks |
|
189 and parse_ty_arg toks = |
|
190 (parse_ident >> (rpair [] #> NType) |
|
191 || parse_sym nun_lparen |-- parse_ty --| parse_sym nun_rparen) toks; |
|
192 |
|
193 val parse_choice_or_unique = |
|
194 (parse_tok (Ident nun_choice) || parse_tok (Ident nun_unique) |
|
195 || parse_tok (Ident nun_unique_unsafe)) |
|
196 -- parse_ty_arg |
|
197 >> (fn (Ident id, ty) => NConst (id, [ty], mk_arrows_ty ([ty, prop_ty], ty))); |
|
198 |
|
199 fun parse_tm toks = |
|
200 (parse_id nun_lambda |-- Scan.repeat parse_arg --| parse_sym nun_dot -- parse_tm >> nabss |
|
201 || parse_id nun_mu |-- parse_arg --| parse_sym nun_dot -- parse_tm |
|
202 >> (fn (var, body) => |
|
203 let val ty = safe_ty_of body in |
|
204 NApp (NConst (nun_mu, [ty], mk_arrow_ty (mk_arrow_ty (ty, ty), ty)), NAbs (var, body)) |
|
205 end) |
|
206 || parse_id nun_if |-- parse_tm --| parse_id nun_then -- parse_tm --| parse_id nun_else |
|
207 -- parse_tm |
|
208 >> (fn ((cond, th), el) => |
|
209 let val ty = safe_ty_of th in |
|
210 napps (NConst (nun_if, [ty], mk_arrows_ty ([prop_ty, ty, ty], ty)), [cond, th, el]) |
|
211 end) |
|
212 || parse_implies) toks |
|
213 and parse_implies toks = |
|
214 (parse_disj -- Scan.option (parse_sym nun_implies -- parse_implies) |
|
215 >> (fn (tm, NONE) => tm |
|
216 | (lhs, SOME (Symbol id, rhs)) => napps (NConst (id, [], dummy_ty), [lhs, rhs]))) toks |
|
217 and parse_disj toks = |
|
218 (parse_conj -- Scan.option (parse_sym nun_disj -- parse_disj) |
|
219 >> (fn (tm, NONE) => tm |
|
220 | (lhs, SOME (Symbol id, rhs)) => napps (NConst (id, [], dummy_ty), [lhs, rhs]))) toks |
|
221 and parse_conj toks = |
|
222 (parse_equals -- Scan.option (parse_sym nun_conj -- parse_conj) |
|
223 >> (fn (tm, NONE) => tm |
|
224 | (lhs, SOME (Symbol id, rhs)) => napps (NConst (id, [], dummy_ty), [lhs, rhs]))) toks |
|
225 and parse_equals toks = |
|
226 (parse_comb -- Scan.option (parse_sym nun_equals -- parse_comb) |
|
227 >> (fn (tm, NONE) => tm |
|
228 | (lhs, SOME (Symbol id, rhs)) => napps (NConst (id, [], dummy_ty), [lhs, rhs]))) toks |
|
229 and parse_comb toks = |
|
230 (parse_arg -- Scan.repeat (Scan.unless parse_confusing_id parse_arg) >> napps) toks |
|
231 and parse_arg toks = |
|
232 (parse_choice_or_unique |
|
233 || parse_ident >> (fn id => NConst (id, [], dummy_ty)) |
|
234 || parse_sym nun_irrelevant |
|
235 |-- Scan.option (parse_sym nun_lparen |-- parse_tm --| parse_sym nun_rparen) (* FIXME *) |
|
236 >> (fn _ => NConst (nun_irrelevant, [], dummy_ty)) |
|
237 || parse_sym nun_unparsable |-- parse_ty >> (fn ty => NConst (nun_unparsable, [], ty)) |
|
238 || parse_sym nun_lparen |-- parse_tm -- Scan.option (parse_sym nun_colon |-- parse_ty) |
|
239 --| parse_sym nun_rparen |
|
240 >> (fn (NConst (id, [], _), SOME ty) => NConst (id, [], ty) |
|
241 | (tm, _) => tm) |
|
242 || parse_atom >> (fn (id, j) => NAtom (j, NType (id, [])))) toks; |
|
243 |
|
244 val parse_witness_name = |
|
245 parse_ident >> (fn id => NConst (hd (space_explode "/" id), [], dummy_ty)); |
|
246 |
|
247 val parse_witness = |
|
248 parse_id nun__witness_of |-- parse_sym nun_lparen |-- (parse_id nun_forall || parse_id nun_exists) |
|
249 |-- Scan.option (parse_sym nun_lparen) |-- parse_witness_name |
|
250 --| Scan.repeat (Scan.one (curry (op <>) (Symbol nun_assign))); |
|
251 |
|
252 datatype entry = |
|
253 Type_Entry of ty_entry |
|
254 | Skolem_Entry of tm_entry |
|
255 | Const_Entry of tm_entry; |
|
256 |
|
257 val parse_entry = |
|
258 (parse_id nun_type |-- parse_ty --| parse_sym nun_assign --| parse_sym nun_lbrace -- |
|
259 parse_enum (parse_sym nun_comma) parse_tm --| parse_sym nun_rbrace |
|
260 >> Type_Entry |
|
261 || parse_id nun_val |-- parse_witness --| parse_sym nun_assign -- parse_tm >> Skolem_Entry |
|
262 || parse_id nun_val |-- parse_tm --| parse_sym nun_assign -- parse_tm >> Const_Entry) |
|
263 --| parse_sym nun_dot; |
|
264 |
|
265 val parse_model = |
|
266 parse_id nun_SAT |-- parse_sym nun_colon |-- parse_sym nun_lbrace |-- Scan.repeat parse_entry |
|
267 --| parse_sym nun_rbrace; |
|
268 |
|
269 fun add_entry entry ({type_model, const_model, skolem_model} : nun_model) = |
|
270 (case entry of |
|
271 Type_Entry e => |
|
272 {type_model = e :: type_model, const_model = const_model, skolem_model = skolem_model} |
|
273 | Skolem_Entry e => |
|
274 {type_model = type_model, const_model = const_model, skolem_model = e :: skolem_model} |
|
275 | Const_Entry e => |
|
276 {type_model = type_model, const_model = e :: const_model, skolem_model = skolem_model}); |
|
277 |
|
278 fun nun_model_of_str str = |
|
279 let val (entries, _) = parse_model (tokenize str) in |
|
280 {type_model = [], const_model = [], skolem_model = []} |
|
281 |> fold_rev add_entry entries |
|
282 end; |
|
283 |
|
284 end; |