1 | | % (c) 2009-2025 Lehrstuhl fuer Softwaretechnik und Programmiersprachen, |
2 | | % Heinrich Heine Universitaet Duesseldorf |
3 | | % This software is licenced under EPL 1.0 (http://www.eclipse.org/org/documents/epl-v10.html) |
4 | | |
5 | | :- module(bsyntaxtree, |
6 | | [is_texpr/1, % checks if the given argument is a typed expression |
7 | | |
8 | | get_texpr_expr/2, % get the expression part of a typed expression |
9 | | get_texpr_type/2, % get the type of a typed expression |
10 | | get_texpr_info/2, % get the list of information of a typed expression |
11 | | get_texpr_id/2, % get the id of a typed identifier, fails if it's not an identifier |
12 | | def_get_texpr_id/2, % same as above, but raises error if arg1 is not an identifier |
13 | | def_get_texpr_ids/2, % maplist of the above, i.e., translate a typed id list into a plain list of id names |
14 | | create_typed_id/3, % create a typed identifier |
15 | | create_typed_ids/3, % create a list of typed identifiers from list of names and types |
16 | | same_id/3, % true if two typed identifiers have the same id |
17 | | same_ids/2, % true if two lists of typed identifiers have the same ids |
18 | | same_ids_and_types/2, % also check types |
19 | | split_names_and_types/3, % split list of typed ids into ids and types |
20 | | get_texpr_exprs/2, % list variant of the above |
21 | | get_texpr_types/2, % list variant of the above |
22 | | get_texpr_infos/2, % list variant of the above |
23 | | get_texpr_ids/2, % list variant of the above |
24 | | get_texpr_pos/2, % get the position of a typed expression |
25 | | extract_pos_infos/2, % get the position info sub list of an info list |
26 | | copy_pos_infos/3, % copy position infos from one typed expression to another |
27 | | delete_pos_info/2, % delete position info from an info list |
28 | | propagate_pos_info_if_useful/3, % propagate position info from second list if useful |
29 | | merge_info/3, % merge two information lists as well as possible |
30 | | update_infos/3, % provide updates to an existing info list |
31 | | get_info_pos/2, % get the position directly from info field |
32 | | contains_info_pos/1, % true if info field contains position infos |
33 | | |
34 | | same_texpr/2, % check if two typed expressions are equal modulo Info fields |
35 | | different_texpr_values/2, % check if two type expressions are WD and definitely denote different values |
36 | | |
37 | | create_texpr/4, % creates a typed expression by giving expression, type and infos |
38 | | add_texpr_infos/3, % adds some more information to a typed expression at front |
39 | | add_texpr_info_if_new/3, % adds one info field to typed B expression info list at front if it is new |
40 | | add_texpr_infos_if_new/3, % ditto but list of infos can be added |
41 | | add_info_if_new/3, % adds to info list |
42 | | add_infos_if_new/3, % same for list of info items |
43 | | safe_create_texpr/3, % a version of create_texpr which extracts wd-info from sub-expressionssafe_create_texpr |
44 | | safe_create_texpr/4, |
45 | | texpr_contains_wd_condition/1, |
46 | | sub_expression_contains_wd_condition/1, % utility to check if sub-expression contains wd condition |
47 | | |
48 | | get_rodin_name/2, get_rodin_model_name/2, |
49 | | is_rodin_label_info/1, |
50 | | get_texpr_label/2, get_texpr_labels/2, |
51 | | get_info_labels/2, select_info_labels/3, |
52 | | add_labels_to_texpr/3, |
53 | | get_texpr_description/2, % get @desc pragma for typed expression |
54 | | add_texpr_description/3, % add an additional description by hand |
55 | | info_has_ignore_pragma/1, % check if an info list has an ignore pragma |
56 | | predicate_has_ignore_pragma/1, % ditto for the info list of a predicate |
57 | | always_well_defined/1, always_well_defined_or_disprover_mode/1, |
58 | | always_well_defined_or_wd_reorderings_allowed/1, |
59 | | always_well_defined_or_wd_improvements_allowed/1, |
60 | | finite_wd_set_value/1, finite_set_or_disprover_mode/1, |
61 | | is_truth/1, is_falsity/1, |
62 | | conjunct_predicates/2, |
63 | | conjunct_predicates_with_pos_info/3, conjunct_predicates_with_pos_info/2, |
64 | | is_a_conjunct/3, is_a_conjunct_without_label/3, decompose_conjunct/3, |
65 | | is_a_disjunct/3, is_an_implication/3, is_an_equivalence/3, is_a_negation/2, |
66 | | conjunction_to_list/2, |
67 | | conjunction_to_list_with_rodin_labels/2, % a variation which propagates labels down to conjuncts |
68 | | member_in_conjunction/2, select_member_in_conjunction/3, |
69 | | flatten_conjunctions/2, |
70 | | size_of_conjunction/2, |
71 | | member_in_conjunction_cse/3, |
72 | | disjunct_predicates/2, |
73 | | disjunct_predicates_with_pos_info/3, |
74 | | disjunction_to_list/2, |
75 | | is_a_disjunct_or_implication/4, |
76 | | is_a_conjunct_or_neg_disj/3, |
77 | | |
78 | | predicate_components/2, % split a predicate into components which use distinct identifiers |
79 | | predicate_components_in_scope/3, % ditto with an optional list of local variables |
80 | | predicate_components_with_restriction/4, |
81 | | predicate_identifiers/2, predicate_identifiers_in_scope/3, |
82 | | |
83 | | project_predicate_on_identifiers/5, |
84 | | |
85 | | find_identifier_uses_top_level/2, % not including global sets and constants |
86 | | find_identifier_uses/3, find_identifier_uses_if_necessary/3, |
87 | | find_identifier_uses_l/3, |
88 | | find_typed_identifier_uses/3, |
89 | | find_typed_identifier_uses/2, % not including global sets and constants |
90 | | find_typed_identifier_uses_l/3, |
91 | | get_global_identifiers/1, get_global_identifiers/2, |
92 | | occurs_in_expr/2, some_id_occurs_in_expr/2, |
93 | | single_usage_identifier/3, |
94 | | update_used_ids/3, |
95 | | check_computed_used_ids/2, |
96 | | |
97 | | create_exists/3, create_or_merge_exists/3, |
98 | | create_exists_or_let_predicate/3, |
99 | | create_exists_opt_liftable/3, |
100 | | create_exists_opt/3, create_exists_opt/4, create_exists_opt/5, |
101 | | create_forall/3, |
102 | | create_negation/2, is_negation_of/2, get_negated_operator_expr/2, |
103 | | create_implication/3, |
104 | | create_equivalence/3, |
105 | | is_equality/3, |
106 | | create_equality/3, split_equality/3, get_texpr_couple/3, |
107 | | create_couple/3, create_couple/2, nested_couple_to_list/2, |
108 | | create_comprehension_set/4, |
109 | | is_eventb_comprehension_set/4, is_eventb_comprehension_set/6, |
110 | | singleton_set_extension/2, |
111 | | is_membership/3, is_membership_or_equality/3, |
112 | | get_lambda_equality/4, |
113 | | is_pow_subset/2, is_pow1_subset/2, |
114 | | |
115 | | detect_global_predicates/4, |
116 | | |
117 | | definitely_not_empty_set/1, definitely_empty_set/1, definitely_not_empty_finite_value/1, |
118 | | get_integer/2, |
119 | | get_interval/3, |
120 | | |
121 | | replace_id_by_expr/4, |
122 | | replace_id_by_expr_with_count/5, % also count number of replacements |
123 | | replace_ids_by_exprs/4, |
124 | | remove_used_id_from_info/3, % remove an id from used_id info field if it exists |
125 | | remove_used_ids_from_info/3, % remove list of ids (order of args different !) |
126 | | |
127 | | rename_bt/3, % a simplified version of replace_ids_by_exprs, which assumes target of renamings are variables |
128 | | rename_bt_l/3, |
129 | | remove_bt/4, |
130 | | syntaxtransformation/5, |
131 | | syntaxtransformation_det/5, % faster, non-backtracking version |
132 | | |
133 | | map_over_bexpr/2, map_over_typed_bexpr/2, map_over_typed_bexpr/3, |
134 | | map_over_typed_bexpr_with_names/2, |
135 | | map_over_bexpr_top_down_acc/3, map_over_typed_bexpr_top_down_acc/3, |
136 | | reduce_over_bexpr/4, |
137 | | transform_bexpr/3, % transform a typed B expression bottom-up |
138 | | transform_bexpr_with_scoping/3, % ditto, but we also provide info about local ids |
139 | | transform_bexpr_td_with_scoping/3, % top-down with scoping |
140 | | transform_bexpr_with_bup_accs/5, transform_bexpr_with_acc/5, |
141 | | non_det_transform_bexpr_with_acc/5, % can be used to generate several transformed expressions |
142 | | uses_implementable_integers/1, |
143 | | min_max_integer_value_used/3, min_max_integer_value_used/5, |
144 | | syntaxtraversion/6, |
145 | | safe_syntaxelement/5, |
146 | | safe_syntaxelement_det/5, % a deterministic, non-backtracking version |
147 | | is_subst_syntaxelement/1, |
148 | | is_syntax_constant/1, |
149 | | |
150 | | expand_all_lets/2, |
151 | | |
152 | | remove_all_infos/2, extract_info/2, extract_info/3, extract_info_wo_used_ids/2, |
153 | | bsyntax_pattern/2, |
154 | | |
155 | | remove_all_infos_and_ground/2, |
156 | | |
157 | | check_if_typed_predicate/1, |
158 | | check_if_typed_expression/1, |
159 | | check_if_typed_substitution/1, |
160 | | |
161 | | strip_and_norm_ast/2, |
162 | | same_norm_texpr/2, |
163 | | get_texpr_functor/3, |
164 | | |
165 | | is_set_type/2, get_set_type/2, get_texpr_set_type/2, |
166 | | is_just_type/1, is_just_type/2, |
167 | | |
168 | | create_recursive_compset/6, |
169 | | unique_typed_id/3, |
170 | | mark_bexpr_as_symbolic/2, |
171 | | |
172 | | identifier_sub_ast/3, exchange_ast_position/5, |
173 | | |
174 | | has_declared_identifier/2, add_declaration_for_identifier/3, |
175 | | check_ast/1, check_ast/2, |
176 | | repair_used_ids/3, |
177 | | print_ast/1, |
178 | | rewrite_if_then_else_expr_to_b/2 |
179 | | ]). |
180 | | |
181 | | % meta_predicate annotations should appear before loading any code: |
182 | | |
183 | | :- meta_predicate map_over_full_bexpr_no_fail(1,?). |
184 | | |
185 | | :- meta_predicate map_over_bexpr(1,?). |
186 | | :- meta_predicate map_over_typed_bexpr(1,?). |
187 | | :- meta_predicate map_over_typed_bexpr(2,?,?). |
188 | | :- meta_predicate map_over_bexpr_top_down_acc(3,?,?). |
189 | | :- meta_predicate map_over_typed_bexpr_top_down_acc(3,?,?). |
190 | | |
191 | | :- meta_predicate reduce_over_bexpr(3,?,?,?). |
192 | | :- meta_predicate transform_bexpr(2,?,?). |
193 | | :- meta_predicate l_transform_bexpr(?,2,?). |
194 | | :- meta_predicate transform_bexpr_with_scoping(3,?,?). |
195 | | :- meta_predicate transform_bexpr_td_with_scoping(3,?,?). |
196 | | :- meta_predicate transform_bexpr_with_scoping2(3,?,?,?). |
197 | | :- meta_predicate l_transform_bexpr_with_scoping(?,3,?,?). |
198 | | :- meta_predicate transform_bexpr_with_bup_accs(4,?,?,?,?). |
199 | | :- meta_predicate l_transform_bexpr_with_bup_accs(?,4,?,?,?). |
200 | | :- meta_predicate transform_bexpr_with_acc(4,?,?,?,?). |
201 | | :- meta_predicate l_transform_bexpr_with_acc(?,4,?,?,?). |
202 | | :- meta_predicate non_det_transform_bexpr_with_acc(4,?,?,?,?). |
203 | | :- meta_predicate l_nd_transform_bexpr_with_acc(?,4,?,?,?). |
204 | | |
205 | | % ----------- |
206 | | |
207 | | |
208 | | :- use_module(tools). |
209 | | |
210 | | :- use_module(module_information,[module_info/2]). |
211 | | :- module_info(group,typechecker). |
212 | | :- module_info(description,'This module provides operations on the type-checked AST.'). |
213 | | |
214 | | :- use_module(library(lists)). |
215 | | :- use_module(library(ordsets)). |
216 | | :- use_module(library(avl)). |
217 | | :- use_module(library(terms)). |
218 | | |
219 | | :- use_module(self_check). |
220 | | :- use_module(error_manager). |
221 | | :- use_module(translate,[print_bexpr/1,translate_bexpression/2]). |
222 | | :- use_module(gensym,[gensym/2]). |
223 | | :- use_module(preferences,[get_preference/2,preference/2]). |
224 | | :- use_module(debug,[debug_mode/1,debug_format/3]). |
225 | | |
226 | | :- use_module(typing_tools,[is_finite_type_in_context/2,normalize_type/2]). |
227 | | :- use_module(tools_lists,[convlist_max/4]). |
228 | | |
229 | | :- set_prolog_flag(double_quotes, codes). |
230 | | |
231 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
232 | | % basic access to enriched syntax tree |
233 | | |
234 | | is_texpr(b(_,_,_)). |
235 | | |
236 | | get_texpr_expr(b(Name,_,_),R) :- !,R=Name. |
237 | | get_texpr_expr(E,_) :- add_error_fail(get_texpr_expr,'B Expression not properly wrapped: ',E). |
238 | | |
239 | | get_texpr_type(b(_,Type,_),R) :- !, R=Type. |
240 | | get_texpr_type(E,_) :- add_error_fail(get_texpr_type,'B Expression not properly wrapped: ',E). |
241 | | get_texpr_info(b(_,_,Info),R) :- !, R=Info. |
242 | | get_texpr_info(E,_) :- add_error_fail(get_texpr_info,'B Expression not properly wrapped: ',E). |
243 | | |
244 | | %! get_texpr_id(+Texpr,-Id) |
245 | | get_texpr_id(b(N,_,_),Id) :- !, N=identifier(Id). |
246 | | get_texpr_id(E,_) :- add_error_fail(get_texpr_id,'B Expression not properly wrapped: ',E). |
247 | | /* same as above: but must succeed */ |
248 | | def_get_texpr_id(b(identifier(Id),_,_),R) :- !,R=Id. |
249 | | def_get_texpr_id(b(E,_,_),_) :- !, |
250 | | add_error_fail(def_get_texpr_id,'Could not extract identifier from typed expression: ',E). |
251 | | def_get_texpr_id(ID,_) :- add_error_fail(def_get_texpr_id,'Could not extract identifier, not properly wrapped: ',ID). |
252 | | |
253 | | % translate a list of ids with the b/3 wrapper into a plain id list; throw error if not an identifier |
254 | | % used to also be called get_texpr_id_names |
255 | | def_get_texpr_ids(L,Ids) :- maplist(def_get_texpr_id,L,Ids). |
256 | | |
257 | | create_typed_id(IDName,Type,b(identifier(IDName),Type,[])). |
258 | | |
259 | | create_typed_ids([],[],[]). |
260 | | create_typed_ids([ID|TI],[Type|TT],[TID| TRes]) :- |
261 | | create_typed_id(ID,Type,TID), |
262 | | create_typed_ids(TI,TT,TRes). |
263 | | |
264 | | same_id(X,Y,ID) :- get_texpr_id(X,ID), get_texpr_id(Y,ID). |
265 | | |
266 | | same_ids([],[]). |
267 | | same_ids([X|Xs],[Y|Ys]) :- same_id(X,Y,_), same_ids(Xs,Ys). |
268 | | |
269 | | % check if two lists of identifiers have the same name and types |
270 | | same_ids_and_types([],[]). |
271 | | same_ids_and_types([b(identifier(Id),T1,_)|Xs],[b(identifier(Id),T2,_)|Ys]) :- unify_types_strict(T1,T2), |
272 | | same_ids_and_types(Xs,Ys). |
273 | | |
274 | | % split a list of typed identifiers into atomic ids and types |
275 | | split_names_and_types([],N,T) :- !, N=[], T=[]. |
276 | | split_names_and_types([Identifier|IdRest],[Name|NRest],[Type|TRest]) :- !, |
277 | | def_get_texpr_id(Identifier,Name), |
278 | | get_texpr_type(Identifier,Type), |
279 | | split_names_and_types(IdRest,NRest,TRest). |
280 | | split_names_and_types(TIDS,N,R) :- |
281 | | add_internal_error('Illegal call to:',split_names_and_types(TIDS,N,R)),fail. |
282 | | |
283 | | |
284 | | |
285 | | % check if two wrapped expressions are equal (modulo associated Info, e.g. source loc info) |
286 | | same_texpr(b(E1,Type,_),b(E2,Type,_)) :- % should we do a == check first ?? probably not as it may traverse the entire structure (see email exchange with SICStus 28.1.2015) |
287 | | same_functor(E1,E2), |
288 | | safe_syntaxelement_det(E1,Subs1,_Names1,_List1,Constant), |
289 | | safe_syntaxelement_det(E2,Subs2,_Names2,_List2,Constant2), |
290 | | Constant==Constant2, % in case we have values with variables inside ! |
291 | | same_sub_expressions(Subs1,Subs2). |
292 | | |
293 | | same_sub_expressions([],[]). |
294 | | same_sub_expressions([H1|T1],[H2|T2]) :- same_texpr(H1,H2), same_sub_expressions(T1,T2). |
295 | | |
296 | | % check if two wrapped expressions definitely denote a different value (and are well-defined) |
297 | | % only detects certain cases ! |
298 | | different_texpr_values(b(E1,Type,I1),b(E2,Type,I2)) :- |
299 | | different_value(E1,E2,CheckWD), |
300 | | (CheckWD=false -> true |
301 | | ; always_well_defined_or_wd_improvements_allowed(b(E1,Type,I1)), |
302 | | always_well_defined_or_wd_improvements_allowed(b(E2,Type,I2))). |
303 | | different_value(boolean_false,boolean_true,false) :- !. |
304 | | different_value(boolean_true,boolean_false,false) :- !. |
305 | | different_value(integer(X),IY,false) :- get_integer_aux(IY,Y),!, X\=Y. |
306 | | different_value(string(X),string(Y),false) :- !, X\=Y. |
307 | | different_value(value(VX),Y,false) :- !, different_val_from(VX,Y). |
308 | | different_value(empty_set,S,check_wd) :- !, non_empty_set(S). |
309 | | different_value(S,empty_set,check_wd) :- !, non_empty_set(S). |
310 | | % should we compare two set_extensions ? couples ? records ? reals? |
311 | | |
312 | | different_val_from(Var,_) :- var(Var),!,fail. |
313 | | different_val_from(int(X),IY) :- integer(X), get_integer_aux(IY,Y), X\=Y. |
314 | | different_val_from(fd(X,Gs),value(FY)) :- nonvar(X), nonvar(FY), FY=fd(Y,Gs), nonvar(Y), X\=Y. |
315 | | different_val_from(pred_false,boolean_true). |
316 | | different_val_from(pred_false,value(BY)) :- BY==pred_true. |
317 | | different_val_from(pred_true,boolean_false). |
318 | | different_val_from(pred_true,value(BY)) :- BY==pred_false. |
319 | | different_val_from(string(X),string(Y)) :- !, X\=Y. |
320 | | different_val_from(string(X),value(VY)) :- nonvar(VY), VY=string(Y), nonvar(Y), !, X\=Y. |
321 | | different_val_from(avl_set(node(_,_,_,_,_)),empty_set). |
322 | | |
323 | | non_empty_set(set_extension([_|_])). |
324 | | non_empty_set(sequence_extension([_|_])). |
325 | | |
326 | | |
327 | | get_texpr_exprs([],[]). |
328 | | get_texpr_exprs([E|Rest],[N|NRest]) :- get_texpr_expr(E,N),get_texpr_exprs(Rest,NRest). |
329 | | get_texpr_exprs(b(E,_,_),Res) :- add_internal_error('Illegal call:',get_texpr_infos(b(E,_,_),Res)), Res=[E]. |
330 | | get_texpr_types([],[]). |
331 | | get_texpr_types([E|Rest],[T|TRest]) :- get_texpr_type(E,T),get_texpr_types(Rest,TRest). |
332 | | get_texpr_types(b(_,T,_),Res) :- add_internal_error('Illegal call:',get_texpr_infos(b(_,T,_),Res)), Res=[T]. |
333 | | get_texpr_infos([],[]). |
334 | | get_texpr_infos([E|Rest],[I|IRest]) :- get_texpr_info(E,I),get_texpr_infos(Rest,IRest). |
335 | | get_texpr_infos(b(_,_,I),Res) :- add_internal_error('Illegal call:',get_texpr_infos(b(_,_,I),Res)), Res=[I]. |
336 | | get_texpr_ids([],[]). |
337 | | get_texpr_ids([E|Rest],[I|IRest]) :- get_texpr_id(E,I),get_texpr_ids(Rest,IRest). |
338 | | |
339 | | get_texpr_pos(TExpr,Pos) :- |
340 | | get_texpr_info(TExpr,Infos), |
341 | ? | ( member(nodeid(Pos1),Infos) -> !,Pos=Pos1 |
342 | | ; Pos = none). |
343 | | |
344 | | % similar to get_texpr_pos, but returns sub-list of infos relating to position |
345 | | extract_pos_infos(Infos,InfoRes) :- |
346 | ? | ( member(nodeid(Pos1),Infos) -> !,InfoRes=[nodeid(Pos1)] |
347 | | ; InfoRes = []). |
348 | | |
349 | | % copy position info from first arg to second argument |
350 | | copy_pos_infos(b(_,_,Infos1),Arg2,Res) :- |
351 | | member(nodeid(Pos1),Infos1),!, |
352 | | Arg2 = b(E,T,Infos2), Res = b(E,T,Infos3), |
353 | | delete_pos_info(Infos2,Infos2d), |
354 | | Infos3 = [nodeid(Pos1)|Infos2d]. |
355 | | copy_pos_infos(_,TE,TE). |
356 | | |
357 | | delete_pos_info(Infos1,Infos2) :- |
358 | | select(nodeid(_),Infos1,D),!, Infos2=D. |
359 | | %delete(Infos1,nodeid(_),Infos2). |
360 | | delete_pos_info(I,I). |
361 | | |
362 | | % propagate position info from second list to first one if it has better position info |
363 | | propagate_pos_info_if_useful(Infos,AuxInfos,NewInfos) :- |
364 | | member(nodeid(Pos2),AuxInfos), |
365 | | \+ derived_pos(Pos2),!, % potentially useful position info to propagate |
366 | | (select(nodeid(Pos1),Infos,Infos2) |
367 | | -> (derived_pos(Pos1) |
368 | | -> NewInfos = [nodeid(Pos2)|Infos2] % we have better position info now |
369 | | ; NewInfos = Infos % we already have a position info |
370 | | ) |
371 | | ; NewInfos = [nodeid(Pos2)|Infos] |
372 | | ). |
373 | | propagate_pos_info_if_useful(Infos,_,Infos). |
374 | | |
375 | | % derived position; not precise instrinsic label at top-level |
376 | | derived_pos(rodin_derived_context_pos(_,_,_)). |
377 | | |
378 | | |
379 | | get_info_pos(Infos,Pos) :- (member(nodeid(Pos1),Infos) -> Pos=Pos1 ; Pos=none). |
380 | | contains_info_pos(Infos) :- (member(nodeid(NI),Infos) -> NI \= none). |
381 | | |
382 | | create_texpr(Expr,Type,Info,b(Expr,Type,Info)). |
383 | | |
384 | | add_texpr_infos(b(Expr,Type,Old),Infos,b(Expr,Type,New)) :- !, |
385 | | append(Infos,Old,New). |
386 | | add_texpr_infos(Other,Infos,Res) :- |
387 | | add_internal_error('Illegal call, not BExpr:',add_texpr_infos(Other,Infos,Res)),fail. |
388 | | |
389 | | add_texpr_info_if_new(b(Expr,Type,Old),Info,b(Expr,Type,New)) :- !, |
390 | | add_info_if_new(Old,Info,New). |
391 | | add_texpr_info_if_new(Other,Infos,Res) :- |
392 | | add_internal_error('Illegal call, not BExpr:',add_texpr_info_if_new(Other,Infos,Res)),fail. |
393 | | % add multiple infos: |
394 | | add_texpr_infos_if_new(b(Expr,Type,Old),Infos,b(Expr,Type,New)) :- |
395 | | add_infos_if_new(Infos,Old,New). |
396 | | |
397 | | % add to info list: |
398 | | add_info_if_new(Old,Info,New) :- |
399 | | (member(Info,Old) -> New=Old ; New = [Info|Old]). |
400 | | |
401 | | add_infos_if_new([]) --> []. |
402 | | add_infos_if_new([Info|T]) --> add_info(Info), add_infos_if_new(T). |
403 | | add_info(Info,Old,New) :- |
404 | | (member(Info,Old) -> New=Old ; New = [Info|Old]). |
405 | | |
406 | | |
407 | | % try and extract the Rodin name of a predicate or expression |
408 | | get_rodin_name(Expression,Name) :- get_texpr_pos(Expression,rodinpos(Name,_)), Name \= []. |
409 | | get_rodin_name(Expression,Name) :- get_texpr_pos(Expression,rodinpos(_Model,Name,_)), Name \= []. % new rodinpos |
410 | | |
411 | | get_rodin_model_name(Expression,Model) :- |
412 | | get_texpr_pos(Expression,rodinpos(Model,Name,_)), Name \= []. % new rodinpos |
413 | | % Note: only precise position label, not rodin_derived_context_pos |
414 | | |
415 | | % try and extract the Rodin name or label pragma of a predicate or expression |
416 | | get_texpr_labels(TExpr,Label) :- |
417 | | get_texpr_info(TExpr,Infos), |
418 | | member(I,Infos), info_label(I,Label). |
419 | | get_info_labels(Infos,LabelList) :- |
420 | ? | member(I,Infos), info_label(I,LabelList). |
421 | | select_info_labels(LabelList,Infos,Rest) :- |
422 | | select(I,Infos,Rest), info_label(I,LabelList). |
423 | | info_label(nodeid(NodeID),[Name]) :- nodeid_info_label(NodeID,Name). |
424 | | info_label(label(LabelList),LabelList). |
425 | | |
426 | | nodeid_info_label(rodinpos(Name,_),Name) :- Name \= []. |
427 | | nodeid_info_label(rodinpos(Model,Name,_),FullName) :- Name \= [], % new rodinpos |
428 | | ajoin([Model,':',Name], FullName). % TO DO: if only one level; don't do this |
429 | | % TODO: provide separate way to access this derived information: |
430 | | %nodeid_info_label(rodin_derived_context_pos(Model,Context,Label),FullName) :- |
431 | | % ajoin([Model,'.',Context,':',Label], FullName). |
432 | | |
433 | | |
434 | | add_labels_to_texpr(E,[],R) :- !, R=E. % no labels to add |
435 | | add_labels_to_texpr(b(E,T,I),Labels,b(E,T,NewI)) :- |
436 | | (select(label(OldList),I,Rest) |
437 | | -> append(Labels,OldList,NewList), NewI=[label(NewList)|Rest] |
438 | | % TO DO: what if we have Rodin labels |
439 | | ; NewI = [label(Labels)|I] |
440 | | ). |
441 | | |
442 | | get_texpr_label(TExpr,Label) :- get_texpr_labels(TExpr,Labels), member(Label,Labels). |
443 | | |
444 | | get_texpr_description(TExpr,Description) :- |
445 | | get_texpr_info(TExpr,Infos), |
446 | | memberchk(description(Description),Infos). |
447 | | |
448 | | add_texpr_description(b(E,T,I),Description,b(E,T,[description(Description)|I])) :- |
449 | | (atom(Description) -> true ; |
450 | | add_error(add_texpr_description,'Non-atomic description:',Description)). |
451 | | |
452 | | % check if an info list has an ignore pragma |
453 | | info_has_ignore_pragma(Infos) :- |
454 | | member(description('prob-ignore'),Infos). |
455 | | % detect_prob_ignore ast_cleanup rule also generates this description annotation |
456 | | |
457 | | predicate_has_ignore_pragma(b(_E,pred,I)) :- |
458 | | %add_message(check_prob_ignore,'Pred: ',b(_E,pred,I),I), |
459 | | info_has_ignore_pragma(I). |
460 | | |
461 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
462 | | |
463 | | :- assert_must_succeed( (E = "1/2", |
464 | | bmachine:b_parse_machine_expression_from_codes(E,ET,Type,false,Err), |
465 | | Type==integer, Err==none, always_well_defined(ET) ) ). |
466 | | :- assert_must_succeed( (E = "3 mod 2", |
467 | | bmachine:b_parse_machine_expression_from_codes(E,ET,Type,false,Err), |
468 | | Type==integer, Err==none, always_well_defined(ET) ) ). |
469 | | :- assert_must_succeed( (E = "1/0", |
470 | | bmachine:b_parse_machine_expression_from_codes(E,ET,Type,false,Err), |
471 | | Type==integer, Err==none, \+ always_well_defined(ET) ) ). |
472 | | :- assert_must_succeed( (E = "2*(3 mod card({}))", |
473 | | bmachine:b_parse_machine_expression_from_codes(E,ET,Type,false,Err), |
474 | | Type==integer, Err==none, \+ always_well_defined(ET) ) ). |
475 | | :- assert_must_succeed( (E = "1/(2+1-3)", |
476 | | bmachine:b_parse_machine_expression_from_codes(E,ET,Type,false,Err), |
477 | | Type==integer, Err==none, \+ always_well_defined(ET) ) ). |
478 | | :- assert_must_succeed( (E = "max({1,2,3,0})", |
479 | | bmachine:b_parse_machine_expression_from_codes(E,ET,Type,false,Err), |
480 | | Type==integer, Err==none, always_well_defined(ET) ) ). |
481 | | :- assert_must_succeed( (E = "min({1,2,3,0})", |
482 | | bmachine:b_parse_machine_expression_from_codes(E,ET,Type,false,Err), |
483 | | Type==integer, Err==none, always_well_defined(ET) ) ). |
484 | | :- assert_must_succeed( (E = "min({1,2,3,0}-(0..4))", |
485 | | bmachine:b_parse_machine_expression_from_codes(E,ET,Type,false,Err), |
486 | | Type==integer, Err==none, \+ always_well_defined(ET) ) ). |
487 | | :- assert_must_succeed( (E = "2+max({1,2,3, 1/0})", |
488 | | bmachine:b_parse_machine_expression_from_codes(E,ET,Type,false,Err), |
489 | | Type==integer, Err==none,\+ always_well_defined(ET) ) ). |
490 | | :- assert_must_succeed( (E = "2-card({1,2,3})", |
491 | | bmachine:b_parse_machine_expression_from_codes(E,ET,Type,false,Err), |
492 | | Type==integer, Err==none, always_well_defined(ET) ) ). |
493 | | :- assert_must_succeed( (E = "2-card({1,2,3, 1/0})", |
494 | | bmachine:b_parse_machine_expression_from_codes(E,ET,Type,false,Err), |
495 | | Type==integer, Err==none,\+ always_well_defined(ET) ) ). |
496 | | :- assert_must_succeed( (E = "bool(2-size([1,2,3, 1/0])=3)", |
497 | | bmachine:b_parse_machine_expression_from_codes(E,ET,Type,false,Err), |
498 | | Type==boolean, Err==none, \+ always_well_defined(ET) ) ). |
499 | | :- assert_must_succeed( (E = "bool(2-size([1,2,3, 1/2, 3 mod 2, 3**2])=size([]))", |
500 | | bmachine:b_parse_machine_expression_from_codes(E,ET,Type,false,Err), |
501 | | Type==boolean, Err==none, always_well_defined(ET) ) ). |
502 | | |
503 | | always_well_defined_or_wd_reorderings_allowed(BE) :- % allow re-ordering to improve Left-to-right WD |
504 | | (preferences:preference(disprover_mode,true) -> true % we can assume all calls are well-defined |
505 | | ; preferences:preference(allow_improving_wd_mode,true) -> true |
506 | | ; preferences:preference(data_validation_mode,true) -> true |
507 | | ; always_well_defined_or_discharged(BE)). |
508 | | always_well_defined_or_wd_improvements_allowed(BE) :- % allow to remove useless calls which could be non-WD |
509 | | % example #x(x = f(...)) -> btrue or f[{}] --> {} |
510 | | always_well_defined_or_wd_reorderings_allowed(BE). % we currently use the same definition |
511 | | always_well_defined_or_disprover_mode(BE) :- |
512 | | (preferences:preference(disprover_mode,true) -> true % we can assume all calls are well-defined |
513 | | ; always_well_defined_or_discharged(BE)). |
514 | | |
515 | | always_well_defined_or_discharged(b(E,_,Infos)) :- !, |
516 | | (nonmember(contains_wd_condition,Infos) -> true |
517 | | ; always_wd(E) -> true % some special rules |
518 | | ; member(discharged_wd_po,Infos) -> true |
519 | | %; nl, functor(E,F,N), F \= function, print(non_wd(F,N)),nl,nl,fail |
520 | | ). |
521 | | always_well_defined_or_discharged(E) :- |
522 | | add_error_fail(always_well_defined,'Illegal call: ',always_well_defined_or_discharged(E)). |
523 | | |
524 | | % should ensure that there is no failure and no error raised |
525 | | always_well_defined(b(E,_,Infos)) :- !, |
526 | | (nonmember(contains_wd_condition,Infos) -> true |
527 | | ; always_wd(E) -> true % some special rules |
528 | | %; nl, functor(E,F,N), F \= function, print(non_wd(F,N)),nl,nl,fail |
529 | | ). |
530 | | always_well_defined(E) :- add_error_fail(always_well_defined,'Illegal call: ',always_well_defined(E)). |
531 | | |
532 | | |
533 | | :- assert_must_succeed( always_wd(div( b(integer(2),integer,[]), b(integer(2),integer,[]) )) ). |
534 | | :- assert_must_fail( always_wd(div( b(integer(2),integer,[]), b(integer(0),integer,[]) )) ). |
535 | | :- assert_must_succeed( always_wd(modulo( b(integer(2),integer,[]), b(integer(2),integer,[]) )) ). |
536 | | :- assert_must_fail( always_wd(modulo( b(integer(2),integer,[]), b(integer(0),integer,[]) )) ). |
537 | | :- assert_must_fail( always_wd(modulo( b(integer(2),integer,[]), b(integer(-2),integer,[]) )) ). |
538 | | :- assert_must_fail( always_wd(modulo( b(integer(-1),integer,[]), b(integer(2),integer,[]) )) ). |
539 | | :- assert_must_succeed( always_wd(power_of( b(integer(2),integer,[]), b(integer(3),integer,[]) )) ). |
540 | | :- assert_must_succeed( always_wd(power_of( b(integer(2),integer,[]), b(integer(0),integer,[]) )) ). |
541 | | :- assert_must_fail( always_wd(power_of( b(integer(2),integer,[]), b(integer(-1),integer,[]) )) ). |
542 | | |
543 | | % catch cases where the construct is currently so instantiated that we can determine that it is well-defined |
544 | | % can happen e.g. during closure compilation |
545 | | :- use_module(custom_explicit_sets,[check_unique_in_domain_of_avlset/2]). |
546 | | :- use_module(kernel_tools,[ground_value/1]). |
547 | | always_wd(power_of(X,Y)) :- get_integer(Y,Val), Val>=0, |
548 | | (eventb_mode -> get_integer(X,ValX), ValX >=0 |
549 | | ; always_well_defined(X)). |
550 | | always_wd(div(X,Y)) :- get_integer(Y,Val), Val\=0, always_well_defined(X). |
551 | | always_wd(modulo(X,Y)) :- get_integer(Y,Val), Val>0, % Z Live allows negative numbers here it seems, cf modulo2 |
552 | | (z_or_tla_minor_mode -> true % in Z, TLA we can have negative numbers here |
553 | | ; get_integer(X,ValX), ValX>=0). |
554 | | always_wd(function(X,Y)) :- nonvar(X), |
555 | | X= b(value(AVLSET),_,_), nonvar(AVLSET), AVLSET=avl_set(AVL), |
556 | | always_wd_avl_function(AVL,Y). |
557 | | always_wd(min(X)) :- non_empty_finite_wd_set_value(X). |
558 | | always_wd(max(X)) :- non_empty_finite_wd_set_value(X). |
559 | | always_wd(card(X)) :- finite_wd_set_value(X). |
560 | | always_wd(size(X)) :- finite_wd_seq_value(X). |
561 | | always_wd(first(X)) :- non_empty_wd_seq_value(X). |
562 | | always_wd(front(X)) :- non_empty_wd_seq_value(X). |
563 | | always_wd(last(X)) :- non_empty_wd_seq_value(X). |
564 | | always_wd(tail(X)) :- non_empty_wd_seq_value(X). % TO DO: add restrict_front, restrict_tail ? |
565 | | always_wd(general_intersection(X)) :- non_empty_finite_wd_set_value(X). |
566 | | always_wd(value(_)). % we have already computed the value and will raise WD error; to be 100 % safe we could restrict this to ground values |
567 | | % other candidates: size(_), first(_) last(_) tail(_) front(_) restrict_front(_,_) restrict_tail(_,_) rel_iterate(_,_) |
568 | | always_wd(typeset). |
569 | | % operators that are always wd on their own: |
570 | | always_wd(record_field(RecEx,FieldName)) :- ground(FieldName), |
571 | | always_well_defined(RecEx). |
572 | | always_wd(unary_minus(A)) :- always_well_defined(A). |
573 | | always_wd(unary_minus_real(A)) :- always_well_defined(A). |
574 | | always_wd(first_of_pair(A)) :- always_well_defined(A). |
575 | | always_wd(add(A,B)) :- always_well_defined(A),always_well_defined(B). |
576 | | always_wd(add_real(A,B)) :- always_well_defined(A),always_well_defined(B). |
577 | | always_wd(minus(A,B)) :- always_well_defined(A),always_well_defined(B). |
578 | | always_wd(minus_real(A,B)) :- always_well_defined(A),always_well_defined(B). |
579 | | always_wd(multiplication(A,B)) :- always_well_defined(A),always_well_defined(B). |
580 | | always_wd(multiplication_real(A,B)) :- always_well_defined(A),always_well_defined(B). |
581 | | always_wd(equal(A,B)) :- always_well_defined(A),always_well_defined(B). |
582 | | always_wd(not_equal(A,B)) :- always_well_defined(A),always_well_defined(B). |
583 | | always_wd(less_equal(A,B)) :- always_well_defined(A),always_well_defined(B). |
584 | | always_wd(less_equal_real(A,B)) :- always_well_defined(A),always_well_defined(B). |
585 | | always_wd(greater_equal(A,B)) :- always_well_defined(A),always_well_defined(B). |
586 | | always_wd(less(A,B)) :- always_well_defined(A),always_well_defined(B). |
587 | | always_wd(less_real(A,B)) :- always_well_defined(A),always_well_defined(B). |
588 | | always_wd(greater(A,B)) :- always_well_defined(A),always_well_defined(B). |
589 | | always_wd(couple(A,B)) :- always_well_defined(A),always_well_defined(B). |
590 | | % TO DO: add more/all other operators ? |
591 | | |
592 | | always_wd_avl_function(AVL,Y) :- nonvar(Y), Y= b(value(Val),_,_), |
593 | | ground_value(Val), !, |
594 | | % Warning: this does not check that the whole AVL is a function; just this particular lookup is ok |
595 | | check_unique_in_domain_of_avlset(Val,AVL). % ,print(ok),nl. |
596 | | always_wd_avl_function(AVL,Y) :- always_well_defined(Y), |
597 | | custom_explicit_sets:quick_definitely_maximal_total_function_avl(AVL). |
598 | | |
599 | | % non empty set with WD elements |
600 | | non_empty_finite_wd_set_value(b(E,_,_)) :- non_empty_fin_wd_set2(E). |
601 | | non_empty_fin_wd_set2(bool_set). |
602 | | non_empty_fin_wd_set2(value(X)) :- definitely_not_empty_finite_value(X). |
603 | | non_empty_fin_wd_set2(set_extension(S)) :- l_always_well_defined(S). % the set_extension could contain wd_errors !! |
604 | | non_empty_fin_wd_set2(sequence_extension(S)) :- l_always_well_defined(S). % ditto |
605 | | non_empty_fin_wd_set2(interval(A,B)) :- get_integer(A,IA), get_integer(B,IB), IA =< IB. |
606 | | % see not_empty_set_aux |
607 | | definitely_not_empty_finite_value(X) :- var(X),!,fail. |
608 | | definitely_not_empty_finite_value(avl_set(_)). |
609 | | definitely_not_empty_finite_value([_|_]). |
610 | | definitely_not_empty_finite_value(closure(P,T,B)) :- |
611 | | custom_explicit_sets:is_interval_closure(P,T,B,LOW,UP), integer(LOW),integer(UP), LOW =< UP. |
612 | | % TODO: pow_subset of finite values |
613 | | |
614 | | non_empty_wd_seq_value(b(E,_,_)) :- non_empty_seq2(E). |
615 | | non_empty_seq2(value(X)) :- definitely_not_empty_seq(X). |
616 | | non_empty_seq2(sequence_extension(S)) :- l_always_well_defined(S), S=[_|_]. |
617 | | |
618 | | definitely_not_empty_seq(X) :- var(X),!,fail. |
619 | | definitely_not_empty_seq(avl_set(A)) :- custom_explicit_sets:is_avl_sequence(A). |
620 | | definitely_not_empty_seq([El1|T]) :- T==[],nonvar(El1), El1=(IDX,_), IDX==int(1). % TO DO: add more cases ? |
621 | | |
622 | | |
623 | | finite_set_or_disprover_mode(Set) :- |
624 | | (preferences:preference(disprover_mode,true) -> true % we can assume all calls are well-defined |
625 | | ; finite_wd_set_value(Set)). |
626 | | |
627 | | :- use_module(typing_tools,[is_provably_finite_type/1]). |
628 | | % we could also use is_finite_type_in_context to allow deferred sets to be counted as finite |
629 | | finite_wd_set_value(b(E,T,_)) :- !, (finite_set2(E) -> true ; is_provably_finite_type(T)). |
630 | | finite_wd_set_value(E) :- add_internal_error('Not a BExpr: ',E),fail. |
631 | | finite_set2(empty_set). |
632 | | finite_set2(empty_sequence). |
633 | | finite_set2(value(X)) :- X==[] -> true ; definitely_not_empty_finite_value(X). |
634 | | finite_set2(set_extension(S)) :- l_always_well_defined(S). % the set_extension could contain wd_errors !! |
635 | | finite_set2(sequence_extension(S)) :- l_always_well_defined(S). % ditto |
636 | | |
637 | | finite_wd_seq_value(b(E,_,_)) :- finite_seq2(E). |
638 | | finite_seq2(empty_set). |
639 | | finite_seq2(empty_sequence). |
640 | | finite_seq2(value(X)) :- finite_seq_value(X). |
641 | | finite_seq2(sequence_extension(S)) :- l_always_well_defined(S). |
642 | | |
643 | | finite_seq_value(X) :- var(X),!,fail. |
644 | | finite_seq_value([]). |
645 | | finite_seq_value(avl_set(A)) :- custom_explicit_sets:is_avl_sequence(A). |
646 | | % it could be expensive to check if non empty list is a B sequence ?? |
647 | | |
648 | | l_always_well_defined([]). |
649 | | l_always_well_defined([H|T]) :- always_well_defined(H), l_always_well_defined(T). |
650 | | |
651 | | is_truth(b(F,pred,_)) :- is_truth_aux(F). |
652 | | is_truth_aux(truth). |
653 | | is_truth_aux(value(V)) :- V==pred_true. % can occur in CSE mode |
654 | | |
655 | | is_falsity(b(F,pred,_)) :- is_falsity_aux(F). |
656 | | is_falsity_aux(falsity). |
657 | | is_falsity_aux(value(V)) :- V==pred_false. % can occur in CSE mode |
658 | | |
659 | | % conjunction of a list of predicates |
660 | | % NOTE: bsyntaxtree:conjunct_predicates([P1,P2,P3],R). --> generates R = b(conjunct(b(conjunct(P1,P2),pred,[]),P3),pred,[]) |
661 | | conjunct_predicates(V,R) :- var(V),!, add_internal_error('Variable conjunction list: ',conjunct_predicates(V,R)),fail. |
662 | | conjunct_predicates([],b(truth,pred,[])). |
663 | | conjunct_predicates([P|Rest],Result) :- conjunct2(Rest,P,Result). |
664 | | conjunct2([],P,P). |
665 | | conjunct2([Q|Rest],P,Result) :- conjunct3(P,Q,R), conjunct2(Rest,R,Result). |
666 | | conjunct3(b(truth,_,_),P,P) :- !. |
667 | | conjunct3(P,b(truth,_,_),P) :- !. |
668 | | conjunct3(A,B,b(conjunct(A,B),pred,NewInfo)) :- extract_info(A,B,NewInfo). |
669 | | |
670 | | % disjunction of a list of predicates |
671 | | disjunct_predicates([],b(falsity,pred,[])). |
672 | | disjunct_predicates([P|Rest],Result) :- disjunct2(Rest,P,Result). |
673 | | disjunct2([],P,P). |
674 | | disjunct2([Q|Rest],P,Result) :- disjunct3(P,Q,R), disjunct2(Rest,R,Result). |
675 | | disjunct3(b(falsity,_,_),P,R) :- !, R=P. |
676 | | disjunct3(b(truth,T,I),_,R) :- !, R=b(truth,T,I). |
677 | | disjunct3(P,b(falsity,_,_),R) :- !, R=P. |
678 | | disjunct3(_,b(truth,T,I),R) :- !, R=b(truth,T,I). |
679 | | disjunct3(A,B,b(disjunct(A,B),pred,NewInfo)) :- extract_info(A,B,NewInfo). |
680 | | |
681 | | % conjunct two predicates and try and construct position information |
682 | | conjunct_predicates_with_pos_info(A,B,AB) :- is_truth(B),!, AB=A. |
683 | | conjunct_predicates_with_pos_info(A,B,AB) :- is_truth(A),!, AB=B. |
684 | | conjunct_predicates_with_pos_info(A,B,AB) :- |
685 | | conjunct_predicates([A,B],AB0), % this may contain position info if B is truth; hence we do check above |
686 | | (try_get_merged_position_info(A,B,ABI) |
687 | | -> add_texpr_infos(AB0,[ABI],AB) %,print(abi(ABI)),nl |
688 | | ; AB=AB0). |
689 | | |
690 | | % disjunct two predicates and try and construct position information |
691 | | disjunct_predicates_with_pos_info(A,B,AB) :- |
692 | | disjunct_predicates([A,B],AB0), |
693 | | (try_get_merged_position_info(A,B,ABI) |
694 | | -> add_texpr_infos(AB0,[ABI],AB) %,print(abi(ABI)),nl |
695 | | ; AB=AB0). |
696 | | |
697 | | try_get_merged_position_info(b(_,_,I1),b(_,_,I2),PosInfo) :- |
698 | | (try_get_merged_position_info_aux(I1,I2,MergedInfo) -> PosInfo = MergedInfo |
699 | | ; get_non_label_posinfo(Pos1,I1) -> PosInfo=nodeid(Pos1) |
700 | | ; get_non_label_posinfo(Pos2,I2) -> PosInfo=nodeid(Pos2) |
701 | | ). |
702 | | try_get_merged_position_info_aux(I1,I2,nodeid(pos(C,Filenumber,Srow,Scol,Erow,Ecol))) :- |
703 | | member(nodeid(pos(C1,Filenumber,Srow1,Scol1,Erow1,Ecol1)),I1), |
704 | | (number(C1),number(Srow1),number(Scol1),number(Erow1),number(Ecol1) |
705 | | -> true ; add_internal_error('Info field 1 not yet instantiated: ',try_get_merged_position_info(I1)),fail), |
706 | | !, |
707 | | member(nodeid(pos(C2,Filenumber,Srow2,Scol2,Erow2,Ecol2)),I2), |
708 | | (number(C2),number(Srow2),number(Scol2),number(Erow2),number(Ecol2) |
709 | | -> true ; add_internal_error('Info field 2 not yet instantiated: ',try_get_merged_position_info(I2)),fail), |
710 | | !, |
711 | | % merge position info if in same file |
712 | | (C1 =< C2 -> C=C1, Srow=Srow1,Scol=Scol1 ; C=C2, Srow=Srow2,Scol=Scol2), |
713 | | ((Erow1 > Erow2 ; Erow1=Erow2, Ecol1 >= Ecol2) |
714 | | -> Erow =Erow1, Ecol=Ecol1 |
715 | | ; Erow =Erow2, Ecol=Ecol2). |
716 | | |
717 | | % get position info which is not a label; label info should not be propagated to outer conjuncts/disjuncts/... |
718 | | get_non_label_posinfo(Pos,Infos) :- member(nodeid(Pos),Infos), |
719 | | \+ functor(Pos,rodinpos,_). |
720 | | |
721 | | get_texpr_non_label_posinfo(b(_,_,Infos),nodeid(Pos)) :- get_non_label_posinfo(Pos,Infos). |
722 | | |
723 | | % conjunct list of predicates and try and construct position information |
724 | | conjunct_predicates_with_pos_info([H|T],Res) :- is_truth(H),!, |
725 | | (T=[] -> Res = H ; conjunct_predicates_with_pos_info(T,Res)). |
726 | | conjunct_predicates_with_pos_info([H|T],Res) :- |
727 | | last_non_truth(T,none,Last), % the truth elements will be removed and are not relevant; get last relevant predicate |
728 | | Last \= none, |
729 | | try_get_merged_position_info(H,Last,MergedPosInfo), % try and merge position of first and last element |
730 | | !, |
731 | | conjunct_predicates([H|T],Res0), |
732 | | add_texpr_infos(Res0,[MergedPosInfo],Res). % Res0 should have no nodeid field |
733 | | conjunct_predicates_with_pos_info(L,Res) :- conjunct_predicates(L,Res). |
734 | | |
735 | | :- assert_must_succeed((bsyntaxtree:last_non_truth([a,b,c],none,L),L==c)). |
736 | | :- assert_must_succeed((bsyntaxtree:last_non_truth([a,b,c,b(truth,pred,[])],none,L),L==c)). |
737 | | |
738 | | % get last non-truth element and filter out all truth elements |
739 | | last_non_truth([],Acc,Acc). |
740 | | last_non_truth([H|T],NonTruth,Last) :- is_truth(H),!, last_non_truth(T,NonTruth,Last). |
741 | | last_non_truth([H|T],_,Last) :- last_non_truth(T,H,Last). |
742 | | |
743 | | |
744 | | texpr_contains_wd_condition(b(_,_,Info)) :- !, memberchk(contains_wd_condition,Info). |
745 | | texpr_contains_wd_condition(E) :- add_internal_error('Not a texpr: ',texpr_contains_wd_condition(E)). |
746 | | |
747 | | % a version of create_texpr which collects automatically important infos from sub-expressions |
748 | | safe_create_texpr(Expr,Type,b(Expr,Type,Info)) :- % |
749 | ? | (sub_expression_contains_wd_condition(Expr) -> Info = [contains_wd_condition] ; Info=[]). |
750 | | |
751 | | safe_create_texpr(Expr,Type,Info,b(Expr,Type,FullInfo)) :- % |
752 | | ((sub_expression_contains_wd_condition(Expr), nonmember(contains_wd_condition, Info)) -> FullInfo = [contains_wd_condition|Info] ; FullInfo=Info). |
753 | | |
754 | ? | sub_expression_contains_wd_condition(Expr) :- sub_expression_contains_wd_condition(Expr,_). |
755 | | sub_expression_contains_wd_condition(Expr,Sub) :- |
756 | | safe_syntaxelement_det(Expr,Subs,_Names,_L,_C), |
757 | ? | member(b(Sub,_,Infos),Subs), |
758 | | (var(Infos) |
759 | | -> add_internal_error('Typed expression not sufficiently instantiated (variable Infos): ',sub_expression_contains_wd_condition(Expr)), |
760 | | fail |
761 | | ; memberchk(contains_wd_condition,Infos)). |
762 | | |
763 | | % provide updated infos (e.g., reads(...)) and remove any old info fields with same functor |
764 | | update_infos([],Infos,Infos). |
765 | | update_infos([Update|T],OldInfos,NewInfos) :- |
766 | | functor(Update,F,N), |
767 | | functor(Old,F,N), |
768 | | delete(OldInfos,Old,OldInfos1), |
769 | | update_infos(T,[Update|OldInfos1],NewInfos). |
770 | | |
771 | | % merge two info lists and try to reconcile position information: |
772 | | merge_info(Info1,Info2,Res) :- |
773 | | merge_imp_info2(Info2,Info1,NewInfo), |
774 | | (try_get_merged_position_info_aux(Info1,Info2,NewPos) |
775 | | -> delete_pos_info(NewInfo,NI2), |
776 | | Res = [NewPos|NI2] |
777 | | ; Res = NewInfo). |
778 | | |
779 | | % extract important info but without used_ids: |
780 | | extract_info_wo_used_ids(b(_,_,Info1),Info) :- |
781 | | extract_pos_infos(Info1,PosInfos), |
782 | | extract_just_important_info_aux(Info1,[],I1), |
783 | | append(PosInfos,I1,Info). |
784 | | extract_info_wo_used_ids_and_pos(b(_,_,Info1),b(_,_,Info2),Info) :- |
785 | | extract_just_important_info_aux(Info1,[],I1), |
786 | | extract_just_important_info_aux(Info2,I1,Info). |
787 | | |
788 | | % extract important info from one sub-expression: |
789 | | extract_info(b(_,_,Info1),NewInfo) :- |
790 | | extract_imp_info1(Info1,I1),!, NewInfo = I1. |
791 | | extract_info(A,R) :- |
792 | | add_internal_error('Could not extract info: ',extract_info(A,R)), |
793 | | R=[]. |
794 | | % extract imortant info fields from two (sub-)expressions |
795 | | extract_info(b(_,_,Info1),b(_,_,Info2),NewInfo) :- |
796 | | merge_imp_info2(Info1,Info2,II),!, NewInfo = II. |
797 | | %:- use_module(library(ordsets),[ord_intersection/3]). |
798 | | % ord_intersection(Info1,Info2,NewInfo),!. |
799 | | % TO DO: should we merge nodeid position information !? |
800 | | extract_info(A,B,R) :- add_internal_error('Could not extract info: ',extract_info(A,B,R)), |
801 | | R=[]. |
802 | | |
803 | | % extract important info and used_ids |
804 | | extract_imp_info1([],[]). |
805 | | extract_imp_info1([H|T],Res) :- |
806 | | ((important_info(H); H=used_ids(_)) -> Res=[H|ET], extract_imp_info1(T,ET) |
807 | | ; extract_imp_info1(T,Res) |
808 | | ). |
809 | | |
810 | | % extract and merge important info and try to merge used_ids from two info lists |
811 | | merge_imp_info2(Info1,Info2,ResInfos) :- |
812 | | extract_imp_info1(Info1,I1), |
813 | | extract_imp_info1(Info2,I2), |
814 | | merge_aux(I1,I2,ResInfos). |
815 | | |
816 | | merge_aux([],I2,Res) :- !, delete(I2,used_ids(_),Res). % used_ids not valid for new construct |
817 | | merge_aux(I1,[],Res) :- !, delete(I1,used_ids(_),Res). % ditto |
818 | | merge_aux(I1,I2,ResInfos) :- |
819 | ? | (select(used_ids(Ids1),I1,II1) |
820 | ? | -> (select(used_ids(Ids2),I2,II2) |
821 | | -> ord_union(Ids1,Ids2,Ids3), |
822 | | append(II1,[used_ids(Ids3)|II2],II) |
823 | | ; append(II1,I2,II) |
824 | | ) |
825 | | ; delete(I2,used_ids(_),II2), |
826 | | append(I1,II2,II) |
827 | | ), |
828 | | sort(II,ResInfos). % TO DO: sort sublists ? and use ord_union? |
829 | | |
830 | | important_info(contains_wd_condition). |
831 | | important_info(prob_annotation(_)). |
832 | | important_info(allow_to_lift_exists). |
833 | | important_info(removed_typing). |
834 | | %important_info(lambda_result(_)). % should probably not be copied |
835 | | |
836 | | % variation of above which does not extract and merge used_ids: |
837 | | extract_just_important_info_aux([],Acc,Acc). |
838 | | extract_just_important_info_aux([H|T],Acc,Res) :- |
839 | | (important_info(H), \+ member(H,Acc) -> extract_just_important_info_aux(T,[H|Acc],Res) |
840 | | ; extract_just_important_info_aux(T,Acc,Res)). |
841 | | |
842 | | |
843 | | is_a_conjunct(b(conjunct(A,B),pred,_),A,B). |
844 | | % use is_a_conjunct_without_label if you want to avoid decomposing conjunction associated with a single label |
845 | | is_a_conjunct_without_label(b(conjunct(A,B),pred,I),A,B) :- \+ get_info_labels(I,_). |
846 | | % use decompose conjunct if you want to propagate labels down to the conjuncts |
847 | | decompose_conjunct(b(conjunct(A,B),pred,I),ResA,ResB) :- |
848 | | (get_info_labels(I,Labels) |
849 | | -> add_labels_to_texpr(A,Labels,ResA), add_labels_to_texpr(B,Labels,ResB) |
850 | | ; ResA=A, ResB=B). |
851 | | |
852 | | size_of_conjunction(C,Size) :- size_of_conjunction(C,0,Size). |
853 | | size_of_conjunction(C,Acc,Res) :- is_a_conjunct(C,A,B),!, |
854 | | size_of_conjunction(B,Acc,A1), |
855 | | size_of_conjunction(A,A1,Res). |
856 | | size_of_conjunction(_,Acc,Size) :- Size is Acc+1. |
857 | | |
858 | | conjunction_to_list(C,L) :- var(C),!, |
859 | | add_error_fail(conjunction_to_list,'Internal error: var :',conjunction_to_list(C,L)). |
860 | | conjunction_to_list(C,List) :- |
861 | | conjunction_to_list2(C,List,[]). |
862 | | conjunction_to_list2(X,I,O) :- X=b(E,_,_), |
863 | | (E=conjunct(LHS,RHS) -> conjunction_to_list2(LHS,I,Inter), |
864 | | conjunction_to_list2(RHS,Inter,O) |
865 | | ; E = truth -> I=O |
866 | | ; I = [X|O]). |
867 | | |
868 | | % a variation of conjunction_to_list which propagates Rodin and pragma label infos down |
869 | | % important for proof info; maybe we should only propagate Rodin labels ? |
870 | | conjunction_to_list_with_rodin_labels(C,L) :- var(C),!, |
871 | | add_error_fail(conjunction_to_list,'Internal error: var :',conjunction_to_list_with_rodin_labels(C,L)). |
872 | | conjunction_to_list_with_rodin_labels(C,List) :- |
873 | | conjunction_to_list_with_labels2(C,List,[]). |
874 | | conjunction_to_list_with_labels2(b(conjunct(A,B),pred,Infos),I,O) :- !, |
875 | | copy_rodin_label(Infos,A,B,LHS,RHS), |
876 | | conjunction_to_list_with_labels2(LHS,I,Inter), |
877 | | conjunction_to_list_with_labels2(RHS,Inter,O). |
878 | | conjunction_to_list_with_labels2(X,I,O) :- X=b(E,_,_), |
879 | | ( E = truth -> I=O |
880 | | ; I = [X|O]). |
881 | | |
882 | | |
883 | | copy_rodin_label(Infos,A,B,NewA,NewB) :- member(Pos,Infos), is_rodin_label_info(Pos),!, |
884 | | add_rodin_label_info(A,Pos,NewA), |
885 | | add_rodin_label_info(B,Pos,NewB). |
886 | | copy_rodin_label(_,A,B,A,B). |
887 | | |
888 | | add_rodin_label_info(b(E,T,I),Pos,b(E,T,I2)) :- |
889 | | (member(Pos,I), is_rodin_label_info(Pos) -> I2=I |
890 | | ; I2 = [Pos|I]). |
891 | | |
892 | | is_rodin_label_info(nodeid(Pos)) :- functor(Pos,rodinpos,_). |
893 | | |
894 | | |
895 | | flatten_conjunctions(List,FlattenedList) :- flatten_conj_aux(List,FlattenedList,[]). |
896 | | flatten_conj_aux([]) --> !, []. |
897 | | flatten_conj_aux([H|T]) --> !, flatten_conj_aux(H),flatten_conj_aux(T). |
898 | | flatten_conj_aux(C) --> {is_a_conjunct(C,LHS,RHS)}, |
899 | | !, |
900 | | flatten_conj_aux(LHS), flatten_conj_aux(RHS). |
901 | | flatten_conj_aux(Truth) --> {is_truth(Truth)},!,[]. |
902 | | flatten_conj_aux(C) --> [C]. |
903 | | |
904 | | member_in_conjunction(M,Conj) :- is_a_conjunct(Conj,LHS,RHS),!, |
905 | ? | (member_in_conjunction(M,LHS) ; member_in_conjunction(M,RHS)). |
906 | | member_in_conjunction(M,M). |
907 | | |
908 | | % a version of member_in_conjunction which can deal with lazy_let_pred : |
909 | | % member_in_conjunction_cse(FullConjunctWithLets,InnerConjunctNotALet, Conjunction) |
910 | | member_in_conjunction_cse(M,InnerConj,Conj) :- is_a_conjunct(Conj,LHS,RHS),!, |
911 | | (member_in_conjunction_cse(M,InnerConj,LHS) ; member_in_conjunction_cse(M,InnerConj,RHS)). |
912 | | member_in_conjunction_cse(Conj,InnerConj,b(lazy_let_pred(ID,Share,Body),pred,Info)) :- |
913 | | Conj = b(lazy_let_pred(ID,Share,BConj),pred,Info),!, |
914 | | member_in_conjunction_cse(BConj,InnerConj,Body). |
915 | | member_in_conjunction_cse(M,M,M). |
916 | | |
917 | | % not terribly efficient way to select and remove a conjunct from a predicate |
918 | | select_member_in_conjunction(M,Conj,Rest) :- is_a_conjunct(Conj,LHS,RHS),!, |
919 | | (select_member_in_conjunction(M,LHS,RL), conjunct_predicates([RL,RHS],Rest) |
920 | | ; select_member_in_conjunction(M,RHS,RR), conjunct_predicates([LHS,RR],Rest)). |
921 | | select_member_in_conjunction(M,M,b(truth,pred,[])). |
922 | | |
923 | | is_a_disjunct(b(disjunct(A,B),pred,_),A,B). |
924 | | is_a_negation(b(negation(A),pred,_),A). |
925 | | |
926 | | disjunction_to_list(C,L) :- var(C),!, |
927 | | add_error_fail(disjunction_to_list,'Internal error: var :',disjunction_to_list(C,L)). |
928 | | disjunction_to_list(C,List) :- |
929 | | disjunction_to_list2(C,List,[]). |
930 | | disjunction_to_list2(C,I,O) :- is_a_disjunct(C,LHS,RHS),!, |
931 | | disjunction_to_list2(LHS,I,Inter), |
932 | | disjunction_to_list2(RHS,Inter,O). |
933 | | disjunction_to_list2(X,[X|R],R). |
934 | | |
935 | | is_an_implication(b(implication(A,B),pred,_),A,B). |
936 | | |
937 | | is_an_equivalence(b(equivalence(A,B),pred,_),A,B). |
938 | | |
939 | | |
940 | | is_a_disjunct_or_implication(b(DI,pred,_),Type,A,B) :- is_a_disj_or_impl_aux(DI,Type,A,B). |
941 | | is_a_disj_or_impl_aux(disjunct(A,B),'disjunction',A,B). |
942 | | is_a_disj_or_impl_aux(implication(A,B),'implication',NA,B) :- |
943 | | create_negation(A,NA). |
944 | | is_a_disj_or_impl_aux(negation(b(conjunct(A,B),pred,_)),'negated conjunction',NA,NB) :- |
945 | | create_negation(A,NA),create_negation(B,NB). |
946 | | |
947 | | % a more liberal version of is_a_conjunct/2 which also detects negated disjunctions/implications |
948 | | is_a_conjunct_or_neg_disj(b(DI,pred,I),A,B) :- is_conjunct_aux(DI,I,A,B). |
949 | | |
950 | | is_conjunct_aux(conjunct(LHS,RHS),_,LHS,RHS). |
951 | | is_conjunct_aux(negation(DISJ),_,NegLHS,NegRHS) :- |
952 | | is_a_disjunct_or_implication(DISJ,_Type,LHS,RHS), |
953 | | create_negation(LHS,NegLHS), |
954 | | create_negation(RHS,NegRHS). |
955 | | is_conjunct_aux(equal(TA,TB),I,b(equal(TA1,TB1),pred,I),b(equal(TA2,TB2),pred,I)) :- |
956 | | % split TA1|->TA2 = TB1|->TB2, cf, split_equality/3; useful for enumeration order analysis |
957 | | get_texpr_couple(TA,TA1,TA2), |
958 | | get_texpr_couple(TB,TB1,TB2). |
959 | | % print('Splitting equality in is_a_conjunct_or_neg_disj: '), translate:print_bexpr(b(equal(TA,TB),pred,I)),nl. |
960 | | |
961 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
962 | | % remove all info fields by fresh variables |
963 | | % typically the result will be unified with AST terms which contain full info fields |
964 | | remove_all_infos(TExpr,TNExpr) :- |
965 | | var(TExpr),!,TExpr=TNExpr. |
966 | | % in contrast to remove_all_infos_and_ground we provide no special treatment of values with closures here; |
967 | | % there could be a problem if we unify with a free variable as value |
968 | | remove_all_infos(TExpr,TNExpr) :- |
969 | | get_texpr_expr(TExpr,Expr), |
970 | | get_texpr_type(TExpr,Type), |
971 | | syntaxtransformation(Expr,Subs,_,NSubs,NExpr), |
972 | | create_texpr(NExpr,Type,_,TNExpr), |
973 | | maplist(remove_all_infos,Subs,NSubs). |
974 | | |
975 | | % replace all info fields |
976 | | remove_all_infos_and_ground(TExpr,TNExpr) :- |
977 | | var(TExpr),!,TExpr=TNExpr. |
978 | | remove_all_infos_and_ground(b(value(Value),Type,_),TNExpr) :- |
979 | | % special case for closure(_,_,_) since it is not covered by syntraxtransformation/5 |
980 | | % most useful for intervals |
981 | | !, |
982 | | remove_all_infos_from_bvalue(Value,NValue), |
983 | | TNExpr = b(value(NValue),Type,[]). |
984 | | remove_all_infos_and_ground(TExpr,TNExpr) :- |
985 | | get_texpr_expr(TExpr,Expr), |
986 | | get_texpr_type(TExpr,Type), |
987 | | syntaxtransformation(Expr,Subs,_,NSubs,NExpr), |
988 | | create_texpr(NExpr,Type,[],TNExpr), |
989 | | maplist(remove_all_infos_and_ground,Subs,NSubs). |
990 | | |
991 | | remove_all_infos_from_bvalue(Var,Res) :- var(Var),!, Res=Var. |
992 | | remove_all_infos_from_bvalue((A,B),(RA,RB)) :- !, |
993 | | remove_all_infos_from_bvalue(A,RA), |
994 | | remove_all_infos_from_bvalue(B,RB). |
995 | | remove_all_infos_from_bvalue(closure(P,T,Body),Res) :- !, |
996 | | remove_all_infos_and_ground(Body,RBody), |
997 | | Res = closure(P,T,RBody). |
998 | | % TODO: we could provide more cases like records, sets as lists, freetype values |
999 | | remove_all_infos_from_bvalue(Val,Val). |
1000 | | |
1001 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1002 | | |
1003 | | % a version of create_exists_opt which also detects top-level disjunctions |
1004 | | % and marks the exists as generated and as allow_to_lift_exists |
1005 | | create_exists_opt_liftable(Ids,b(disjunct(A,B),pred,Info1),NewPred) :- !, |
1006 | | create_exists_opt_liftable(Ids,A,PA), |
1007 | | create_exists_opt_liftable(Ids,B,PB), |
1008 | | disjunct_predicates_with_pos_info(PA,PB,b(NP,pred,Info2)), |
1009 | | NewPred=b(NP,pred,NewInfo), |
1010 | | extract_just_important_info_aux(Info1,Info2,NewInfo). % copy symbolic or other relevant info |
1011 | | create_exists_opt_liftable(Ids,Pred,NewPred) :- conjunction_to_list(Pred,L), |
1012 | | create_exists_opt(Ids,L,[allow_to_lift_exists],NewPred,_Modified). |
1013 | | |
1014 | | % create_exists_opt(TIds,Preds,NewPred) |
1015 | | % creating an existential quantification with some optimisations. |
1016 | | % TIds: The typed identifiers that are quantified |
1017 | | % Preds: A list of predicates |
1018 | | % NewPred: The (optimised) quantified expression |
1019 | | % Basically two optimisations are performed: |
1020 | | % - identifiers that are not used at all are removed from the quantifier |
1021 | | % - predicates that do not use one of the quantified identifiers are moved |
1022 | | % outside the quantification, resulting in a predicate of the form "P & #x.Q(x)" |
1023 | | |
1024 | | create_exists_opt(TIds,Preds,NewPred) :- |
1025 | | create_exists_opt(TIds,Preds,[],NewPred,_). |
1026 | | |
1027 | | create_exists_opt(TIds,Preds,NewPred,Modified) :- |
1028 | | create_exists_opt(TIds,Preds,[],NewPred,Modified). |
1029 | | |
1030 | | create_exists_opt([],Preds,_,NewPred,Modified) :- !, Modified = false, |
1031 | | conjunct_predicates(Preds,NewPred). |
1032 | | create_exists_opt(TIds,Preds,AdditionalInfos,Res,Mod) :- |
1033 | | get_texpr_ids(TIds,UnsortedIds), sort(UnsortedIds,Ids), |
1034 | | (create_exists_opt1(TIds,Ids,Preds,AdditionalInfos,NewPred2,Modified) -> Res = NewPred2, Mod=Modified |
1035 | | ; add_internal_error('Call failed:',create_exists_opt(TIds,Preds,AdditionalInfos,_,_)),fail). |
1036 | | %create_exists_opt1(TIds,_,Preds,AdditionalInfos,NewPred,Modified) :- preference(data_validation_mode,true), |
1037 | | % % do not lift predicates outside of existential quantifiers and change order; see rule_avec_DV.mch ClearSy example (N_ITERa_avec_DV_sans_DV) and test 1945 |
1038 | | create_exists_opt1(TIds,Ids,Preds,AdditionalInfos,NewPred2,Modified) :- |
1039 | | create_exists_opt2(Preds,first,Ids,[],Inner,Outer,UsedIds), |
1040 | | % Inner: quantified part, Outer: part which does not have to be quantified |
1041 | | ( Inner = [] -> AllPreds=Outer % no exists needed |
1042 | | ; % Inner = [_|_] -> |
1043 | | create_filtered_exists(TIds,UsedIds,Inner,AdditionalInfos,Exists,IModified), |
1044 | | append(Outer,[Exists],AllPreds) |
1045 | | ), |
1046 | | (Outer=[_|_] -> Modified=true % TO DO: check if TIds=UsedTIds |
1047 | | ; IModified==true -> Modified=true |
1048 | | ; UsedIds == Ids -> Modified= false |
1049 | | ; Modified=true), |
1050 | | conjunct_predicates(AllPreds,NewPred2). |
1051 | | |
1052 | | % create an exists for the used Ids only |
1053 | | create_filtered_exists(TIds,UsedIds,Inner,AdditionalInfos,Exists,_) :- |
1054 | | ceo_filter_used_ids(TIds,UsedIds,UsedTIds), % filter out unused variables |
1055 | | conjunct_predicates_with_pos_info(Inner,I), % we could store used_ids info |
1056 | | create_exists_detect_tautology_aux(UsedTIds,I,AdditionalInfos,Exists). |
1057 | | % remove_typing also added in create_exists_detect_tautology_aux |
1058 | | |
1059 | | |
1060 | | % return Inner: predicates inside quantifier and Outer: predicates that can be moved out of the quantifier |
1061 | | create_exists_opt2([],_,_Ids,UsedIds,[],[],UsedIds) :- !. |
1062 | | create_exists_opt2([Pred|Prest],First,Ids,UsedIdsIn,Inner,Outer,UsedIdsOut) :- !, |
1063 | | find_identifier_uses_if_necessary(Pred, [], LocalUses), % TODO: add used_ids(LocalUses) to Pred |
1064 | | ord_intersection(Ids,LocalUses,ExistsIdsUsed), |
1065 | | ( ExistsIdsUsed = [], % Pred uses none of the quantified ids: we can move it out |
1066 | | (First==first -> true |
1067 | | ; preference(data_validation_mode,false), % see test 1945; step 39 in trace replay |
1068 | | always_well_defined_or_disprover_mode(Pred) % TODO: we should probably also check this ! |
1069 | | ) |
1070 | | -> |
1071 | | Inner = Irest, |
1072 | | Outer = [Pred|Orest], % move Pred out of existential quantifier as it does not depend on quantified variables |
1073 | | % format('MOVED out of #(~w): ',[Ids]),translate:print_bexpr(Pred), format(' Uses ~w [~w]~n',[LocalUses,ExistsIdsUsed]), |
1074 | | create_exists_opt2(Prest,first,Ids,UsedIdsIn,Irest,Orest,UsedIdsOut) |
1075 | | ; |
1076 | | update_used_ids(Pred,LocalUses,Pred2), |
1077 | | Inner = [Pred2|Irest], |
1078 | | Outer = Orest, |
1079 | | ord_union(UsedIdsIn,ExistsIdsUsed,Urest), |
1080 | | create_exists_opt2(Prest,not_first_anymore,Ids,Urest,Irest,Orest,UsedIdsOut) |
1081 | | ). |
1082 | | create_exists_opt2(Pred,First,Ids,UsedIdsIn,Inner,Outer,UsedIdsOut) :- |
1083 | | add_error(create_exists_opt,'Expecting predicate list: ',Pred), |
1084 | | create_exists_opt2([Pred],First,Ids,UsedIdsIn,Inner,Outer,UsedIdsOut). |
1085 | | |
1086 | | % construct exists optimized: keep only used TIds |
1087 | | ceo_filter_used_ids([],_UsedIds,[]). |
1088 | | ceo_filter_used_ids([TId|Irest],UsedIds,Filtered) :- |
1089 | | get_texpr_id(TId,Id), |
1090 | | ( ord_member(Id,UsedIds) -> Filtered = [TId|Frest] % id used: keep it |
1091 | | ; Filtered = Frest), |
1092 | | ceo_filter_used_ids(Irest,UsedIds,Frest). |
1093 | | |
1094 | | % a version of create_exists which also detects x=E and x:E, x>E, not(x>E) tautologies |
1095 | | % we could replace this by a more generic prover |
1096 | | create_exists_detect_tautology_aux([TID],b(member(LHS,RHS),pred,_),_,Truth) :- |
1097 | | get_texpr_id(LHS,ID), get_texpr_id(TID,ID), |
1098 | | definitely_not_empty_set(RHS), |
1099 | | always_well_defined_or_disprover_mode(RHS), |
1100 | | !, % replace #x.(x:RHS) by TRUTH |
1101 | | debug_format(19,'Detected tautology exists membership over ~w~n',[ID]), |
1102 | | Truth=b(truth,pred,[]). |
1103 | | create_exists_detect_tautology_aux([TID],b(Pred,_,_),_,Truth) :- |
1104 | | is_comparison(Pred,pos_neg(pos,TID),L,R), get_texpr_id(TID,ID), |
1105 | | ((LHS,RHS)=(L,R) ; (LHS,RHS)=(R,L)), |
1106 | | get_texpr_id(LHS,ID), |
1107 | | \+ occurs_in_expr(ID,RHS), |
1108 | | always_well_defined_or_disprover_mode(RHS), |
1109 | | !, % replace #x.(x COMP E) by TRUTH |
1110 | | debug_format(19,'Detected tautology comparison over ~w~n',[ID]), |
1111 | | Truth=b(truth,pred,[]). |
1112 | | %create_exists_detect_tautology_aux(Ids,b(disjunct(A,B),pred,Info1),AdditionalInfos,NewPred) :- !, |
1113 | | % create_exists(Ids,A,PA), create_exists(Ids,B,PB), |
1114 | | % disjunct_predicates_with_pos_info(PA,PB,b(NP,pred,Info2)), |
1115 | | % NewPred=b(NP,pred,NewInfo), |
1116 | | % extract_just_important_info_aux(Info1,Info2,NewInfo). % copy symbolic or other relevant info |
1117 | | create_exists_detect_tautology_aux(Ids,Pred,AdditionalInfos,NewPred2) :- |
1118 | | create_exists_or_let_predicate(Ids,Pred,NewPred), |
1119 | | add_texpr_infos_if_new(NewPred,[removed_typing|AdditionalInfos],NewPred2). |
1120 | | % removed_typing to avoid spurious exists_body_warning, see test 1681, 625 |
1121 | | |
1122 | | |
1123 | | is_eventb_comprehension_set(b(comprehension_set(TopIds,Body),_,Info),Ids,PRED,EXPR) :- |
1124 | | is_eventb_comprehension_set(TopIds,Body,Info,Ids,PRED,EXPR). |
1125 | | is_eventb_comprehension_set([TID1],Body,Info,Ids,PRED,EXPR) :- |
1126 | | Body = b(exists(Ids,InnerBody),pred,_), |
1127 | | conjunction_to_list(InnerBody,Inner), |
1128 | | append(Inner1,[b(equal(TID2,EXPR),pred,EqInfo)],Inner), |
1129 | | (member(was(event_b_comprehension_set),Info) -> true ; |
1130 | | member(prob_annotation('LAMBDA-EQUALITY'),EqInfo) % relevant for TLA2B |
1131 | | ), |
1132 | | same_id(TID1,TID2,_), |
1133 | | conjunct_predicates(Inner1,PRED), |
1134 | | % we check that TID1 is not being used in P1 and not just rely on was(event_b_comprehension_set) |
1135 | | not_occurs_in_expr(PRED,TID1). |
1136 | | |
1137 | | % ------------------- |
1138 | | |
1139 | | is_equal(b(equal(LHS,RHS),pred,_),A,B) :- |
1140 | | ((A,B)=(LHS,RHS) ; (A,B)=(RHS,LHS)). |
1141 | | |
1142 | | :- use_module(typing_tools,[type_has_at_least_two_elements/1]). |
1143 | | is_comparison(greater(A,B),_,A,B). |
1144 | | is_comparison(less(A,B),_,A,B). |
1145 | | is_comparison(greater_equal(A,B),_,A,B). |
1146 | | is_comparison(less_equal(A,B),_,A,B). |
1147 | | is_comparison(equal(A,B),pos_neg(P,TID),A,B) :- |
1148 | | % for neg: we need to make sure there is more than one value in the type (otherwise we cannot make equal false) |
1149 | | % for pos: assuming the RHS expression above is well-defined there must be at least one element; no need to check non_empty_type(Type) |
1150 | | (P=pos -> true ; get_texpr_type(TID,Type),type_has_at_least_two_elements(Type)). |
1151 | | is_comparison(not_equal(A,B),pos_neg(P,TID),A,B) :- % ditto but with pos and neg reversed |
1152 | | (P=neg -> true ; get_texpr_type(TID,Type),type_has_at_least_two_elements(Type)). |
1153 | | is_comparison(negation(b(Comp,pred,_)),PosNeg,A,B) :- negate(PosNeg,P2), |
1154 | | is_comparison(Comp,P2,A,B). |
1155 | | negate(pos_neg(pos,T),pos_neg(neg,T)). |
1156 | | negate(pos_neg(neg,T),pos_neg(pos,T)). |
1157 | | |
1158 | | |
1159 | | |
1160 | | % is true if a predicate Pred can be split into two parts: |
1161 | | % Outer which does not depend on LocalIds (can be lifted out) and Inner which does |
1162 | | detect_global_predicates(LocalIds,Pred,Outer,Inner) :- |
1163 | | get_texpr_ids(LocalIds,UnsortedIds), sort(UnsortedIds,Ids), |
1164 | | conjunction_to_list(Pred,Preds), |
1165 | | split_predicate_local_global(Preds,Ids,OuterL,InnerL), |
1166 | | OuterL \= [], |
1167 | | conjunct_predicates(OuterL,Outer), |
1168 | | conjunct_predicates(InnerL,Inner). |
1169 | | split_predicate_local_global([],_Ids,[],[]). |
1170 | | split_predicate_local_global([P|Ps],Ids,Outer,Inner) :- |
1171 | | (is_local_predicate(Ids,P) |
1172 | | -> Inner = [P|Is], split_predicate_local_global(Ps,Ids,Outer,Is) |
1173 | | ; Outer = [P|Os], split_predicate_local_global(Ps,Ids,Os,Inner)). |
1174 | | is_local_predicate(Ids,Pred) :- |
1175 | | find_identifier_uses_if_necessary(Pred, [], LocalUses), |
1176 | | ord_intersect(Ids,LocalUses). |
1177 | | |
1178 | | %:- use_module(b_global_sets,[b_global_set/1]). |
1179 | | definitely_not_empty_set(b(SET,T,_)) :- not_empty_set_aux(SET,T). |
1180 | | not_empty_set_aux(bool_set,_). |
1181 | | not_empty_set_aux(integer_set(_),_). |
1182 | | not_empty_set_aux(float_set,_). |
1183 | | not_empty_set_aux(real_set,_). |
1184 | | not_empty_set_aux(string_set,_). |
1185 | | not_empty_set_aux(set_extension(X),_) :- dif(X,[]). |
1186 | | not_empty_set_aux(sequence_extension(X),_) :- dif(X,[]). |
1187 | | not_empty_set_aux(pow_subset(_),_). % always contains at least the empty set |
1188 | | not_empty_set_aux(fin_subset(_),_). % ditto |
1189 | | not_empty_set_aux(seq(_),_). % ditto |
1190 | | not_empty_set_aux(seq1(_),_). % ditto |
1191 | | not_empty_set_aux(pow1_subset(A),_) :- definitely_not_empty_set(A). |
1192 | | not_empty_set_aux(fin1_subset(A),_) :- definitely_not_empty_set(A). |
1193 | | not_empty_set_aux(seq1(A),_) :- definitely_not_empty_set(A). |
1194 | | not_empty_set_aux(iseq1(A),_) :- definitely_not_empty_set(A). |
1195 | | not_empty_set_aux(cartesian_product(A,B),_) :- definitely_not_empty_set(A), definitely_not_empty_set(B). |
1196 | | not_empty_set_aux(partial_function(_A,_B),_). % always contains at least the empty set |
1197 | | not_empty_set_aux(partial_injection(_A,_B),_). % ditto |
1198 | | not_empty_set_aux(relations(_A,_B),_). % ditto |
1199 | | not_empty_set_aux(total_function(A,B),_) :- |
1200 | | (definitely_not_empty_set(B) -> true |
1201 | | ; definitely_empty_set(A)). % if A is empty, then the set of total functions is {{}} |
1202 | | % TODO: add a few more function rules |
1203 | | not_empty_set_aux(value(S),_) :- not_empty_value(S). |
1204 | | |
1205 | | %not_empty_set_aux(identifier(X),set(global(X))) :- bmachine:b_get_machine_set(X). % what if we have a local variable ? ENSURE THAT WE DO NOT ALLOW identifier X to stand for global set X; see ExistentialGlobalSetIDTest in Tester % also: b_global_set not yet computed when ast_cleanup runs on startup ! |
1206 | | % TO DO: determine which identifier(X) refer to global set names |
1207 | | not_empty_set_aux(interval(A,B),_) :- get_integer(A,IA), get_integer(B,IB), IA =< IB. |
1208 | | |
1209 | | :- use_module(b_global_sets,[b_non_empty_global_set/1]). |
1210 | | not_empty_value(S) :- var(S),!,fail. |
1211 | | not_empty_value(avl_set(_)). |
1212 | | not_empty_value([_|_]). |
1213 | | not_empty_value(global_set(G)) :- b_non_empty_global_set(G). % always true |
1214 | | %TODO: closure? |
1215 | | |
1216 | | definitely_empty_set(b(ES,_,_)) :- is_empty_set_aux(ES). |
1217 | | is_empty_set_aux(empty_set). |
1218 | | is_empty_set_aux(empty_sequence). |
1219 | | is_empty_set_aux(domain(D)) :- definitely_empty_set(D). |
1220 | | is_empty_set_aux(range(D)) :- definitely_empty_set(D). |
1221 | | is_empty_set_aux(domain_subtraction(_,Rel)) :- definitely_empty_set(Rel). |
1222 | | is_empty_set_aux(domain_restriction(Dom,Rel)) :- (definitely_empty_set(Dom) -> true ; definitely_empty_set(Rel)). |
1223 | | is_empty_set_aux(range_restriction(Rel,Ran)) :- (definitely_empty_set(Ran) -> true ; definitely_empty_set(Rel)). |
1224 | | is_empty_set_aux(range_subtraction(Rel,_)) :- definitely_empty_set(Rel). |
1225 | | is_empty_set_aux(interval(A,B)) :- get_integer(A,IA), get_integer(B,IB), IA > IB. |
1226 | | is_empty_set_aux(intersection(A,B)) :- (definitely_empty_set(A) -> true ; definitely_empty_set(B)). |
1227 | | is_empty_set_aux(value(V)) :- V==[]. |
1228 | | |
1229 | | |
1230 | | get_integer(b(B,_,_),I) :- get_integer_aux(B,I). |
1231 | | get_integer_aux(integer(I),I). |
1232 | | get_integer_aux(value(V),I) :- get_integer_value(V,I). |
1233 | | get_integer_value(V,I) :- nonvar(V),V=int(I), integer(I). |
1234 | | |
1235 | | |
1236 | | |
1237 | | :- use_module(probsrc(custom_explicit_sets),[avl_is_interval/3]). |
1238 | | get_interval(b(I,set(integer),_),Low,Up) :- |
1239 | | is_interval_aux(I,Low,Up). |
1240 | | is_interval_aux(interval(Low,Up),Low,Up). |
1241 | | is_interval_aux(value(CS),Low,Up) :- nonvar(CS), CS=avl_set(AVL), % occurs in Leftpad_i.imp |
1242 | | Low = b(integer(LI),integer,[]), Up = b(integer(UI),integer,[]), |
1243 | | avl_is_interval(AVL,LI,UI). |
1244 | | is_interval_aux(set_extension(List),Low,Up) :- print(l(List)),nl, |
1245 | | sort(List,SList), |
1246 | | SList = [Low|Rest], get_integer(Low,LI), |
1247 | | last(SList,Up), get_integer(Up,UI), |
1248 | | length(List,Len), |
1249 | | Len is UI-LI+1, |
1250 | | maplist(get_integer,Rest,_). |
1251 | | |
1252 | | % a simple let-detection |
1253 | | create_exists_or_let_predicate([H|T],b(conjunct(LHS,RHS),pred,I),NewPred) :- get_texpr_id(H,ID), |
1254 | ? | is_equal(LHS,TID,IDEXPR), % TO DO: should we do a more complicated check here ? exist technique useful for SLOT-24 codespeed test |
1255 | | get_texpr_id(TID,ID), \+ occurs_in_expr(ID,IDEXPR), |
1256 | | maplist(not_occurs_in_expr(IDEXPR),T), |
1257 | | !, |
1258 | | NewPred = b(let_predicate([TID],[IDEXPR],Body),pred,I), |
1259 | | %print('LET: '),translate:print_bexpr(NewPred),nl, |
1260 | | create_exists_or_let_predicate(T,RHS,Body). |
1261 | | create_exists_or_let_predicate(Ids,Pred,NewPred) :- create_exists(Ids,Pred,NewPred). |
1262 | | |
1263 | | not_occurs_in_expr(IDEXPR,TID) :- get_texpr_id(TID,ID), \+ occurs_in_expr(ID,IDEXPR). |
1264 | | |
1265 | | create_exists([],Pred,NewPred) :- !,Pred=NewPred. |
1266 | | create_exists(Ids,Pred,NewPred) :- |
1267 | | find_identifier_uses_for_quantifier_body(Ids,Pred, Used), |
1268 | | extract_info_wo_used_ids(Pred,NewImportantInfo), |
1269 | | create_texpr(exists(Ids,Pred),pred,[used_ids(Used)|NewImportantInfo],NewPred). |
1270 | | |
1271 | | % a version of create_exists which can merge with an already present exists if possible |
1272 | | % possibly more expensive as identfiers used are recomputed for the moment (TODO: reuse used_ids and subtract) |
1273 | | create_or_merge_exists(IDs, Condition, Exists):- |
1274 | | get_texpr_expr(Condition,exists(InnerVars,InnerCond)),!, |
1275 | | % fuse two exists together |
1276 | | append(IDs,InnerVars,Vars), |
1277 | | create_or_merge_exists(Vars,InnerCond,Exists). |
1278 | | create_or_merge_exists(IDs, Condition, Exists):- |
1279 | | create_exists(IDs,Condition,Exists). |
1280 | | |
1281 | | |
1282 | | create_forall([],Pred,NewPred) :- !,Pred=NewPred. |
1283 | | create_forall(Ids,Pred,NewPred) :- |
1284 | | find_identifier_uses_for_quantifier_body(Ids,Pred, Used), |
1285 | | split_forall_body(Pred,LHS,RHS), |
1286 | | extract_info_wo_used_ids_and_pos(LHS,RHS,NewImportantInfo), |
1287 | | create_texpr(forall(Ids,LHS,RHS),pred,[used_ids(Used)|NewImportantInfo],NewPred). |
1288 | | split_forall_body(b(implication(LHS,RHS),_,_),LHS,RHS) :- !. |
1289 | | split_forall_body(RHS,b(truth,pred,[]),RHS). |
1290 | | |
1291 | | create_implication(b(truth,pred,_),P,Res) :- !, Res=P. |
1292 | | create_implication(b(falsity,pred,_),P,Res) :- !, create_negation(P,Res). |
1293 | | create_implication(Lhs,Rhs,b(implication(Lhs,Rhs),pred,NewInfo)) :- |
1294 | | extract_info(Lhs,Rhs,NewInfo). |
1295 | | |
1296 | | create_equivalence(Lhs,Rhs, b(equivalence(Lhs,Rhs),pred,NewInfo)) :- |
1297 | | extract_info(Lhs,Rhs,NewInfo). |
1298 | | |
1299 | | create_negation(b(P,pred,I),Res) :- create_negation_aux(P,I,R),!,Res=R. |
1300 | | create_negation(Pred,b(negation(Pred),pred,NewInfo)) :- |
1301 | | extract_info(Pred,Infos), |
1302 | | (get_texpr_non_label_posinfo(Pred,Pos) -> NewInfo = [Pos|Infos] ; NewInfo=Infos). |
1303 | | |
1304 | | create_negation_aux(truth,I,R) :- !, R=b(falsity,pred,I). |
1305 | | create_negation_aux(falsity,I,R) :- !, R=b(truth,pred,I). |
1306 | | create_negation_aux(negation(Pred),_,R) :- R=Pred. % not(not(P)) = P |
1307 | | %create_negation_aux(equal(A,B),I,R) :- !, R=b(not_equal(A,B),pred,I). |
1308 | | %create_negation_aux(not_equal(A,B),I,R) :- !, R=b(equal(A,B),pred,I). |
1309 | | % we could add some rules about negating member <-> not_member, ... but be careful with effects on is_negation_of |
1310 | | |
1311 | | % check if something is the negation of something else (quite stupid at the moment) |
1312 | | % used, e.g., to detect IF-THEN-ELSE constructs in b_ast_cleanup |
1313 | | is_negation_of(P,NP) :- |
1314 | | create_negation(P,NotP), % works both with not(A),A or A,not(A) |
1315 | | same_texpr(NotP,NP). |
1316 | | is_negation_of(b(P,pred,_),b(NP,pred,_)) :- is_negation_aux(P,NP). |
1317 | | |
1318 | | is_negation_aux(equal(A,B),NP) :- is_negation_of_equality(NP,A,B). |
1319 | | is_negation_aux(not_equal(A,B),NP) :- is_negation_of_disequality(NP,A,B). |
1320 | | is_negation_aux(subset(XA,SA),not_subset(XB,SB)) :- same_texpr(XA,XB), same_texpr(SA,SB). |
1321 | | is_negation_aux(not_subset(XA,SA),subset(XB,SB)) :- same_texpr(XA,XB), same_texpr(SA,SB). |
1322 | | is_negation_aux(subset_strict(XA,SA),not_subset_strict(XB,SB)) :- same_texpr(XA,XB), same_texpr(SA,SB). |
1323 | | is_negation_aux(not_subset_strict(XA,SA),subset_strict(XB,SB)) :- same_texpr(XA,XB), same_texpr(SA,SB). |
1324 | | is_negation_aux(member(XA,SA),not_member(XB,SB)) :- same_texpr(XA,XB), same_texpr(SA,SB). |
1325 | | is_negation_aux(not_member(XA,SA),member(XB,SB)) :- same_texpr(XA,XB), same_texpr(SA,SB). |
1326 | | is_negation_aux(less(A,B),greater_equal(AA,BB)) :- same_texpr(A,AA), same_texpr(B,BB). |
1327 | | is_negation_aux(less(A,B),less_equal(BB,AA)) :- same_texpr(A,AA), same_texpr(B,BB). |
1328 | | is_negation_aux(less_equal(B,A),less(AA,BB)) :- same_texpr(A,AA), same_texpr(B,BB). |
1329 | | is_negation_aux(less_equal(A,B),greater(AA,BB)) :- same_texpr(A,AA), same_texpr(B,BB). |
1330 | | is_negation_aux(greater_equal(A,B),NP) :- is_negation_aux(less_equal(B,A),NP). |
1331 | | is_negation_aux(greater(A,B),NP) :- is_negation_aux(less(B,A),NP). |
1332 | | is_negation_aux(less_equal_real(B,A),less_real(AA,BB)) :- same_texpr(A,AA), same_texpr(B,BB). |
1333 | | is_negation_aux(less_real(B,A),less_equal_real(AA,BB)) :- same_texpr(A,AA), same_texpr(B,BB). |
1334 | | is_negation_aux(negation(A),negation(B)) :- is_negation_of(A,B). |
1335 | | is_negation_aux(truth,falsity). |
1336 | | is_negation_aux(falsity,truth). |
1337 | | % TO DO: detect more ?? x < y <=> not ( x > y-1 ) |
1338 | | |
1339 | | is_negation_of_equality(not_equal(AA,BB),A,B) :- same_texpr(A,AA), same_texpr(B,BB). |
1340 | | is_negation_of_equality(equal(AA,BB),A,B) :- same_texpr(A,AA), neg_value(BB,B). |
1341 | | |
1342 | | neg_value(b(boolean_true,_,_),b(boolean_false,_,_)). |
1343 | | neg_value(b(boolean_false,_,_),b(boolean_true,_,_)). |
1344 | | |
1345 | | is_negation_of_disequality(equal(AA,BB),A,B) :- same_texpr(A,AA), same_texpr(B,BB). |
1346 | | is_negation_of_disequality(not_equal(AA,BB),A,B) :- same_texpr(A,AA), neg_value(BB,B). |
1347 | | |
1348 | | |
1349 | | % another version which is simpler can can be used to get the negation of some operators |
1350 | | |
1351 | | get_negated_operator_expr(b(E,pred,_),Res) :- negate_expr_aux(E,Res). |
1352 | | negate_expr_aux(falsity,truth). |
1353 | | negate_expr_aux(truth,falsity). |
1354 | | negate_expr_aux(member(X,S),not_member(X,S)). |
1355 | | negate_expr_aux(not_member(X,S),member(X,S)). |
1356 | | negate_expr_aux(subset(X,S),not_subset(X,S)). |
1357 | | negate_expr_aux(not_subset(X,S),subset(X,S)). |
1358 | | negate_expr_aux(subset_strict(X,S),not_subset_strict(X,S)). |
1359 | | negate_expr_aux(not_subset_strict(X,S),subset_strict(X,S)). |
1360 | | negate_expr_aux(equal(X,S),not_equal(X,S)). |
1361 | | negate_expr_aux(not_equal(X,S),equal(X,S)). |
1362 | | negate_expr_aux(less(X,S),greater_equal(X,S)). |
1363 | | negate_expr_aux(greater_equal(X,S),less(X,S)). |
1364 | | negate_expr_aux(less_equal(X,S),greater(X,S)). |
1365 | | negate_expr_aux(greater(X,S),less_equal(X,S)). |
1366 | | negate_expr_aux(less_equal_real(X,S),less_real(S,X)). |
1367 | | negate_expr_aux(less_real(X,S),less_equal_real(S,X)). |
1368 | | % TO DO: negation() |
1369 | | |
1370 | | |
1371 | | % a liberal version for finding equalities |
1372 | | is_equality(TP,TA,TB) :- get_texpr_expr(TP,P), is_equality_aux(P,TA,TB). |
1373 | | |
1374 | | is_equality_aux(Var,TA,TB) :- var(Var),!, add_internal_error('Illegal call: ', is_equality_aux(Var,TA,TB)),fail. |
1375 | | is_equality_aux(equal(TA,TB),TA,TB). |
1376 | | is_equality_aux(not_equal(TA,TB),NTA,NTB) :- |
1377 | | (negate_boolean_value(TB,NTB) -> NTA=TA |
1378 | | ; NTB=TB, negate_boolean_value(TA,NTA)). % TA /= TRUE ---> TA = FALSE |
1379 | | is_equality_aux(partition(TA,[TB]),TA,TB). |
1380 | | is_equality_aux(member(TA,TSet),TA,TB) :- singleton_set_extension(TSet,TB). % TA:{TB} |
1381 | | is_equality_aux(negation(TExpr),TA,TB) :- get_negated_operator_expr(TExpr,NT), is_equality_aux(NT,TA,TB). |
1382 | | |
1383 | | negate_boolean_value(b(B,T,I),b(NB,T,I)) :- neg_bool_aux(B,NB). |
1384 | | neg_bool_aux(boolean_true,boolean_false). |
1385 | | neg_bool_aux(boolean_false,boolean_true). |
1386 | | % TODO: should we also detect value(pred_true), .... |
1387 | | |
1388 | | singleton_set_extension(b(SONE,Type,_),El) :- singleton_set_extension_aux(SONE,Type,El). |
1389 | | singleton_set_extension_aux(set_extension([El]),_,El). |
1390 | | singleton_set_extension_aux(value(Set),set(Type),b(value(El),Type,[])) :- custom_explicit_sets:singleton_set(Set,El). |
1391 | | singleton_set_extension_aux(sequence_extension([El]),_,Couple) :- |
1392 | | ONE = b(integer(1),integer,[]), |
1393 | | create_couple(ONE,El,Couple). |
1394 | | |
1395 | | |
1396 | | % detect various forms of membership: |
1397 | | is_membership(b(Expr,pred,_),TID,Set) :- is_membership_aux(Expr,TID,Set). |
1398 | | is_membership_aux(member(TID,Set),TID,Set). |
1399 | | is_membership_aux(subset(SONE,Set),TID,Set) :- singleton_set_extension(SONE,TID). % {TID} <: Set |
1400 | | |
1401 | | % detect even more forms of membership: |
1402 | | is_membership_or_equality(b(Expr,pred,_),TID,Set) :- |
1403 | | (is_membership_aux(Expr,TID,Set) -> true ; is_mem_eq_aux(Expr,TID,Set)). |
1404 | | |
1405 | | is_mem_eq_aux(equal(TID,VAL),TID,Set) :- % x=VAL <==> x:{VAL} |
1406 | | get_texpr_type(VAL,Type), |
1407 | | safe_create_texpr(set_extension([VAL]),set(Type),Set). |
1408 | | |
1409 | | % extract a lambda equality from a body; we suppose the equality is the last conjunct |
1410 | | get_lambda_equality(b(equal(TID,ResultExpr),pred,_),ID,[],ResultExpr) :- get_texpr_id(TID,ID). |
1411 | | get_lambda_equality(b(conjunct(LHS,RHS),pred,_),ID,[LHS|T],ResultExpr) :- |
1412 | | get_lambda_equality(RHS,ID,T,ResultExpr). |
1413 | | |
1414 | | % --------------------------------- |
1415 | | |
1416 | | is_pow_subset(B,Set) :- |
1417 | | ( B = b(pow_subset(Set),_,_) |
1418 | | ; B = b(fin_subset(Set),_,_), |
1419 | | finite_wd_set_value(Set) |
1420 | | ). |
1421 | | is_pow1_subset(B,Set) :- |
1422 | | ( B = b(pow1_subset(Set),_,_) |
1423 | | ; B = b(fin1_subset(Set),_,_), |
1424 | | finite_wd_set_value(Set) |
1425 | | ). |
1426 | | |
1427 | | % --------------------------------- |
1428 | | |
1429 | | get_texpr_couple(b(couple(TA1,TA2),_,_),TA1,TA2). |
1430 | | |
1431 | | % detect TA1|->TA2 = TB1|->TB2 and split into two |
1432 | | split_equality(b(equal(TA,TB),pred,I),b(equal(TA1,TB1),pred,I),b(equal(TA2,TB2),pred,I)) :- |
1433 | | get_texpr_couple(TA,TA1,TA2), |
1434 | | get_texpr_couple(TB,TB1,TB2). |
1435 | | |
1436 | | create_equality(b(_,TA,_),b(_,TB,_),_) :- TA \= TB, \+ unify_types_strict(TA,TB),!, |
1437 | | add_internal_error('Creating equality with incompatible types:',equal(TA,TB)),fail. |
1438 | | create_equality(A,B,Equality) :- |
1439 | | safe_create_texpr(equal(A,B),pred,Equality). |
1440 | | |
1441 | | create_couple(A,B,b(couple(A,B),couple(TA,TB),Infos)) :- |
1442 | | get_texpr_type(A,TA), get_texpr_type(B,TB), |
1443 | | extract_info(A,B,Infos). |
1444 | | |
1445 | | % couplise_list for typed expression list |
1446 | | create_couple([A],Couple) :- !,A=Couple. |
1447 | | create_couple([A,B|Rest],Couple) :- |
1448 | | create_couple(A,B,Couple1), |
1449 | | create_couple([Couple1|Rest],Couple). |
1450 | | |
1451 | | % derive typing from Ids |
1452 | | create_comprehension_set(Ids,Pred,Info,CompSet) :- |
1453 | | get_texpr_types(Ids,Types), |
1454 | | couplise_list(Types,ElementType), |
1455 | | create_texpr(comprehension_set(Ids,Pred),set(ElementType),Info,CompSet). |
1456 | | |
1457 | | |
1458 | | :- assert_must_succeed(bsyntaxtree:nested_couple_to_list(b(couple(b(couple(a,b),x,[]),c),xx,[]),[a,b,c])). |
1459 | | :- assert_must_succeed(bsyntaxtree:nested_couple_to_list(b(couple(a,c),x,[]),[a,c])). |
1460 | | :- assert_must_succeed(bsyntaxtree:nested_couple_to_list(b(couple(a,b(couple(b,c),x,[])),xx,[]),[a,b(couple(b,c),x,[])])). |
1461 | | nested_couple_to_list(NC,L) :- nested_couple_to_list_dcg(NC,L,[]). |
1462 | | nested_couple_to_list_dcg(b(couple(A,B),_,_)) --> !, |
1463 | | nested_couple_to_list_dcg(A), [B]. |
1464 | | nested_couple_to_list_dcg(E) --> [E]. |
1465 | | |
1466 | | % -------------------------------------- |
1467 | | |
1468 | | |
1469 | | % check if identifier(s) occur in typed expressions |
1470 | | |
1471 | | occurs_in_expr(ID,TExpr) :- var(ID),!, |
1472 | | add_internal_error('Variable id: ',occurs_in_expr(ID,TExpr)),fail. |
1473 | | occurs_in_expr(ID,TExpr) :- ID=b(_,_,_),!, add_internal_error('Non-atomic identifier: ',occurs_in_expr(ID,TExpr)),fail. |
1474 | | occurs_in_expr(ID,TExpr) :- ID=[_|_],!, |
1475 | | add_internal_error('List instead of identifier: ',occurs_in_expr(ID,TExpr)),fail. |
1476 | | occurs_in_expr(ID,TExpr) :- occurs_in_expr1(TExpr,ID). |
1477 | | |
1478 | | % treat a few common operators here; possibly avoid traversing whole term if we find ID in a sub-tree |
1479 | | occurs_in_expr1(TExpr,ID) :- TExpr = b(Expr,_,_),!, |
1480 | | occurs_in_expr2(Expr,TExpr,ID). |
1481 | | occurs_in_expr1(TExpr,ID) :- add_internal_error('Illegal typed expression:',occurs_in_expr1(TExpr,ID)). |
1482 | | |
1483 | | occurs_in_expr2(add(A,B),_,ID) :- !, |
1484 | | (occurs_in_expr1(A,ID) -> true ; occurs_in_expr1(B,ID)). |
1485 | | occurs_in_expr2(conjunct(A,B),_,ID) :- !, |
1486 | | (occurs_in_expr1(A,ID) -> true ; occurs_in_expr1(B,ID)). |
1487 | | occurs_in_expr2(couple(A,B),_,ID) :- !, |
1488 | | (occurs_in_expr1(A,ID) -> true ; occurs_in_expr1(B,ID)). |
1489 | | occurs_in_expr2(member(A,B),_,ID) :- !, |
1490 | | (occurs_in_expr1(A,ID) -> true ; occurs_in_expr1(B,ID)). |
1491 | | occurs_in_expr2(equal(A,B),_,ID) :- !, |
1492 | | (occurs_in_expr1(A,ID) -> true ; occurs_in_expr1(B,ID)). |
1493 | | occurs_in_expr2(function(A,B),_,ID) :- !, |
1494 | | (occurs_in_expr1(A,ID) -> true ; occurs_in_expr1(B,ID)). |
1495 | | occurs_in_expr2(image(A,B),_,ID) :- !, |
1496 | | (occurs_in_expr1(A,ID) -> true ; occurs_in_expr1(B,ID)). |
1497 | | occurs_in_expr2(intersection(A,B),_,ID) :- !, |
1498 | | (occurs_in_expr1(A,ID) -> true ; occurs_in_expr1(B,ID)). |
1499 | | occurs_in_expr2(interval(A,B),_,ID) :- !, |
1500 | | (occurs_in_expr1(A,ID) -> true ; occurs_in_expr1(B,ID)). |
1501 | | occurs_in_expr2(not_equal(A,B),_,ID) :- !, |
1502 | | (occurs_in_expr1(A,ID) -> true ; occurs_in_expr1(B,ID)). |
1503 | | occurs_in_expr2(assertion_expression(A,_Msg,B),_,ID) :- !, |
1504 | | (occurs_in_expr1(A,ID) -> true ; occurs_in_expr1(B,ID)). |
1505 | | occurs_in_expr2(domain(A),_,ID) :- !, occurs_in_expr1(A,ID). |
1506 | | occurs_in_expr2(range(A),_,ID) :- !, occurs_in_expr1(A,ID). |
1507 | | occurs_in_expr2(record_field(A,_FieldName),_,ID) :- !, occurs_in_expr1(A,ID). |
1508 | | occurs_in_expr2(identifier(ID1),_,ID) :- !, |
1509 | | ID1 = ID. |
1510 | | occurs_in_expr2(integer(_),_,_ID) :- !,fail. |
1511 | | occurs_in_expr2(string(_),_,_ID) :- !,fail. |
1512 | | occurs_in_expr2(value(_),_,_ID) :- !,fail. |
1513 | | occurs_in_expr2(truth,_,_ID) :- !,fail. |
1514 | | occurs_in_expr2(if_then_else(A,B,C),_,ID) :- !, |
1515 | | (occurs_in_expr1(A,ID) -> true ; occurs_in_expr1(B,ID) -> true ; occurs_in_expr1(C,ID)). |
1516 | | occurs_in_expr2(rec(Fields),_,ID) :- !, |
1517 | | l_field_occurs_in_expr1(Fields,ID). |
1518 | | occurs_in_expr2(set_extension(Elements),_,ID) :- !, |
1519 | | l_occurs_in_expr1(Elements,ID). |
1520 | | occurs_in_expr2(sequence_extension(Elements),_,ID) :- !, |
1521 | | l_occurs_in_expr1(Elements,ID). |
1522 | | occurs_in_expr2(Expr,_,ID) :- |
1523 | | syntaxelement(Expr,List,[], [], [], _), % no bound quantifiers; TO DO: treat bound quantifiers |
1524 | | !, |
1525 | | l_occurs_in_expr1(List,ID). |
1526 | | occurs_in_expr2(_E,TExpr,ID) :- |
1527 | | %functor(_E,F,N), print(occurs_in_expr2(F,N,ID)),nl, |
1528 | | (find_identifier_uses_if_necessary(TExpr,[],Used) |
1529 | | -> %check_sorted(Used), |
1530 | | %add_message(bsyntaxtree,'Occurs check: ',ID:Used,TExpr), translate:nested_print_bexpr(TExpr),nl, |
1531 | | ord_member(ID,Used) |
1532 | | ; add_failed_call_error(find_identifier_uses(TExpr,[],_)),fail). |
1533 | | % TO DO: optimize so that we only look for ID; we don't have to keep track of other IDs |
1534 | | |
1535 | | l_occurs_in_expr1([H|T],ID) :- !, |
1536 | | (occurs_in_expr1(H,ID) -> true ; l_occurs_in_expr1(T,ID)). |
1537 | | l_occurs_in_expr1(L,ID) :- L \= [], |
1538 | | add_internal_error('Illegal typed expression list:',l_occurs_in_expr1(L,ID)). |
1539 | | l_field_occurs_in_expr1([field(_,H)|T],ID) :- !, |
1540 | | (occurs_in_expr1(H,ID) -> true ; l_field_occurs_in_expr1(T,ID)). |
1541 | | l_field_occurs_in_expr1(L,ID) :- L \= [], |
1542 | | add_internal_error('Illegal record field list:',l_field_occurs_in_expr1(L,ID)). |
1543 | | |
1544 | | %check_sorted(List) :- sort(List,SL), (SL \= List -> add_internal_error('Not sorted:',List) ; true). |
1545 | | |
1546 | | some_id_occurs_in_expr([H|T],TExpr) :- (var(H) ; \+ atomic(H) ; var(T) ; T=[H2|_], H2 @< H), |
1547 | | add_internal_error('Must be (sorted) atomic identifiers: ',some_id_occurs_in_expr([H|T],TExpr)), |
1548 | | fail. |
1549 | | some_id_occurs_in_expr([Id],TExpr) :- !, % use version without complete find_identifier_uses |
1550 | | occurs_in_expr(Id,TExpr). |
1551 | | some_id_occurs_in_expr(SortedIDs,TExpr) :- |
1552 | | find_identifier_uses_if_necessary(TExpr,[],Used), |
1553 | | list_to_ord_set(Used,UsedSorted), |
1554 | | ord_intersect(UsedSorted,SortedIDs). |
1555 | | |
1556 | | % ----------------------------- |
1557 | | |
1558 | | % find used identifiers in typed expressions |
1559 | | |
1560 | | % a special version for quantifier bodies, attempting to reuse used_ids info |
1561 | | find_identifier_uses_for_quantifier_body(TIds,Body,Res) :- |
1562 | | get_texpr_ids(TIds,Ids), |
1563 | | list_to_ord_set(Ids,Ignore), |
1564 | | find_identifier_uses_if_necessary(Body,Ignore,Res). |
1565 | | |
1566 | | % only run find_identifier_uses if necessary because no used_ids Info field present |
1567 | | % TO DO: we could consider using used_ids within find_typed_identifier_uses: drawback: we would need to store types |
1568 | | find_identifier_uses_if_necessary(Expr,Ignore,Res) :- |
1569 | | get_texpr_info(Expr,I), |
1570 | ? | member(used_ids(UIds),I),!, %print('+'),nl, |
1571 | | find_with_reuse(Expr,UIds,Ignore,Res). |
1572 | | find_identifier_uses_if_necessary(Expr,Ignore,Res) :- find_identifier_uses(Expr,Ignore,Res). |
1573 | | |
1574 | | find_with_reuse(Expr,UIds,Ignore,Res) :- preference(prob_safe_mode,true), |
1575 | | !, |
1576 | | (is_ordset(Ignore) -> true ; add_internal_error('Not ordset: ',Ignore)), |
1577 | | (is_ordset(UIds) -> true ; add_internal_error('Not ordset: ',UIds)), |
1578 | | ord_subtract(UIds,Ignore,Res0), |
1579 | | find_identifier_uses(Expr,Ignore,Res1), |
1580 | | (Res1=Res0 -> true |
1581 | | ; ord_subtract(Res1,Res0,Miss), % missing |
1582 | | ord_subtract(Res0,Res1,Res01), % too much |
1583 | | (Miss=[] -> add_message(find_identifier_uses_if_necessary,'Suboptimal used_ids: ',Res01,Expr) |
1584 | | ; add_internal_error('Incorrect used_ids:',used_ids(missing(Miss),toomuch(Res01),usedids(UIds), |
1585 | | ignore(Ignore),real(Res1))), |
1586 | | translate:print_bexpr(Expr),nl |
1587 | | ) |
1588 | | ), |
1589 | | Res=Res1. |
1590 | | find_with_reuse(_,UIds,Ignore,Res) :- |
1591 | | %(is_ordset(Ignore) -> true ; add_internal_error('Not ordset: ',Ignore)), |
1592 | | ord_subtract(UIds,Ignore,Res). |
1593 | | |
1594 | | |
1595 | | find_identifier_uses_top_level(TExpr,Ids) :- |
1596 | | get_global_identifiers(Ignored), % ignore all global sets and global constants; |
1597 | | % hence find_identifier_uses_top_level/2 usually should only be called for top level expressions |
1598 | | find_identifier_uses(TExpr,Ignored,Ids). |
1599 | | |
1600 | | :- use_module(tools,[safe_sort/3]). |
1601 | | find_identifier_uses(TExpr,Ignored,Ids) :- |
1602 | | %tools_printing:print_term_summary(find_identifier_uses(TExpr,Ignored,Ids)),nl, |
1603 | | check_is_texpr(TExpr,find_identifier_uses), |
1604 | | (find_typed_identifier_uses(TExpr,Ignored,TIds) |
1605 | | -> get_texpr_ids(TIds,RIds), |
1606 | | % in case of type errors, or when type checking is not yet complete, we can have multiple entries of the same identifier with different types ! |
1607 | | sort(RIds,Ids) % was remove_dups, but remove_dups just calls sort; TODO: implement get_sorted_texpr_ids |
1608 | | ; add_internal_error('Call failed:',find_typed_identifier_uses(TExpr,Ignored,_)), |
1609 | | Ids=[] |
1610 | | ). |
1611 | | find_identifier_uses_l(TExprs,Ignored,Ids) :- |
1612 | | find_typed_identifier_uses_l(TExprs,Ignored,TIds), |
1613 | | get_texpr_ids(TIds,RIds), |
1614 | | sort(RIds,Ids). % see above |
1615 | | |
1616 | | check_is_texpr(X,Context) :- |
1617 | | (get_texpr_expr(X,_) -> true ; add_internal_error('Expected TExpr: ', check_is_texpr(X,Context))). |
1618 | | |
1619 | | find_typed_identifier_uses(TExpr,Ids) :- |
1620 | | get_global_identifiers(Ignored), % ignore all global sets and global constants; hence find_typed_identifier_uses/2 usually should only be called for top level expressions |
1621 | | find_typed_identifier_uses(TExpr,Ignored,Ids). |
1622 | | |
1623 | | find_typed_identifier_uses(TExpr,Ignored,Ids) :- var(TExpr),!, |
1624 | | add_internal_error('Variable typed expression: ', find_typed_identifier_uses(TExpr,Ignored,Ids)), |
1625 | | Ids = []. |
1626 | | find_typed_identifier_uses(TExpr,Ignored,Ids) :- |
1627 | | find_typed_identifier_uses_l([TExpr],Ignored,Ids). |
1628 | | |
1629 | | find_typed_identifier_uses2(TExpr,Ignored,Ids,Rest) :- |
1630 | | get_texpr_expr(TExpr,Expr), |
1631 | | safe_syntaxelement_det(Expr,Subs,TNames,_,_), % QSubs=[], |
1632 | | ( uses_an_identifier(Expr,Id,TExpr,Ignored) -> |
1633 | | ( ord_member(Id,Ignored) -> Ids=Rest |
1634 | | ; |
1635 | | get_texpr_type(TExpr,Type), |
1636 | | normalize_type(Type,NType), % replace seq by set; |
1637 | | % warning: when type-check not yet complete we have variables here |
1638 | | create_texpr(identifier(Id),NType,[],TId), |
1639 | | %print(adding(Id,NType,Ignored)),nl, |
1640 | | Ids = [TId|Rest] |
1641 | | ) |
1642 | | % ; (Expr = becomes_such(TIds,_)), nl,print(uses_primes(Expr)),nl,fail |
1643 | | ; indirectly_uses_identifiers(Expr,Ignored,IndirectIds) -> |
1644 | | add_typed_ids(IndirectIds,Ids,Rest2), |
1645 | | find_typed_identifier_uses2_l(Subs,Ignored,Rest2,Rest) |
1646 | | ; TNames = [] -> find_typed_identifier_uses2_l(Subs,Ignored,Ids,Rest) |
1647 | | ; |
1648 | | %find_typed_identifier_uses2_l(QSubs,Ignored,Ids,Ids2), % useless here as QSubs=[] |
1649 | | get_texpr_ids(TNames,Names), |
1650 | | list_to_ord_set(Names,SNames), ord_union(SNames,Ignored,Ignored2), |
1651 | | find_typed_identifier_uses2_l(Subs,Ignored2,Ids,Rest)). |
1652 | | find_typed_identifier_uses2_l([],_) --> !, []. |
1653 | | find_typed_identifier_uses2_l([Expr|Rest],Ignored) --> !, |
1654 | | find_typed_identifier_uses2(Expr,Ignored), |
1655 | | find_typed_identifier_uses2_l(Rest,Ignored). |
1656 | | find_typed_identifier_uses2_l(E,Ignored) --> |
1657 | | {add_internal_error('Illegal arguments (not a list):',find_typed_identifier_uses2_l(E,Ignored)),fail}. |
1658 | | |
1659 | | %Note: above we do not remap uses of Id$0 to Id in becomes_such; |
1660 | | % this is done in find_read_vars_for_becomes_such in b_read_write_info |
1661 | | |
1662 | | |
1663 | | uses_an_identifier(Expr,Id) :- uses_an_identifier(Expr,Id,none,[]). |
1664 | | |
1665 | | uses_an_identifier(identifier(Id),Id,_,_). |
1666 | | uses_an_identifier(lazy_lookup_pred(Id),Id,_,_). |
1667 | | uses_an_identifier(lazy_lookup_expr(Id),Id,_,_). |
1668 | | uses_an_identifier(value(_),Id,b(_,_,Info),Ignored) :- Ignored \= [], |
1669 | | member(was_identifier(Id),Info), |
1670 | | member('$examine_value_was_identifier_info',Ignored),!. |
1671 | | |
1672 | | % uses multiple ids and we also need to inspect subs (operation call arguments) |
1673 | | indirectly_uses_identifiers(operation_call_in_expr(Operation,_),Ignored,IndirectIds) :- |
1674 | | get_texpr_info(Operation,Info), |
1675 | | (memberchk(reads(Vars),Info) |
1676 | | -> (var(Vars) % can happen during initial computation of read_write info for recursive operation calls in expr |
1677 | | -> add_message(bsyntaxtree,'Operation reads info not yet computed (probably recursive call): ',Operation,Info), |
1678 | | fail % Assume this is a direct recursive call which adds no used ids, |
1679 | | % case happens in test 1960 for recursive call to Fact; TODO: more robust solution or disallow recursion |
1680 | | ; true) |
1681 | | ; add_warning(bsyntaxtree,'Operation call contains no read infos:',Operation,Info),fail), |
1682 | | ord_subtract(Vars,Ignored,IndirectIds), |
1683 | | IndirectIds \= []. |
1684 | | %indirectly_uses_identifiers(external_pred_call(FunName,_),Ignored,IndirectIds) :- |
1685 | | % expects_state(FunName), TODO: check for which external functions/predicates we need to add ids |
1686 | | |
1687 | | |
1688 | | % this is to convert untyped ids in operation call reads infos to typed ids |
1689 | | add_typed_ids([]) --> []. |
1690 | | add_typed_ids([Id|T]) --> {var_cst_type(Id,Type)},!, |
1691 | | {create_texpr(identifier(Id),Type,[],TId)}, [TId], add_typed_ids(T). |
1692 | | add_typed_ids([Id|T]) --> {debug_println(19,ignoring_used_id(Id))}, add_typed_ids(T). |
1693 | | |
1694 | | :- use_module(bmachine,[bmachine_is_precompiled/0, b_is_variable/2,b_is_constant/2]). |
1695 | | var_cst_type(Name,Type) :- bmachine_is_precompiled,!, |
1696 | | (b_is_variable(Name,Type) ; b_is_constant(Name,Type)),!. |
1697 | | var_cst_type(_,any). % TODO: provide a better solution; maybe only allow untyped find_identifier_uses ?? |
1698 | | |
1699 | | % ------------- |
1700 | | |
1701 | | find_typed_identifier_uses_l(TExprs,Ignored,Ids) :- |
1702 | | check_atomic_ids(Ignored), |
1703 | | list_to_ord_set(Ignored,SIgnored), |
1704 | | find_typed_identifier_uses2_l(TExprs,SIgnored,Unsorted,[]),!, |
1705 | | safe_sort(find_typed_identifier_uses,Unsorted,Ids), |
1706 | | (preference(prob_safe_mode,true) -> check_typed_ids(Ids) ; true). |
1707 | | find_typed_identifier_uses_l(TExprs,Ignored,Ids) :- |
1708 | | add_internal_error('Call failed:',find_typed_identifier_uses_l(TExprs,Ignored,Ids)), |
1709 | | fail. |
1710 | | |
1711 | | check_typed_ids([]) :- !. |
1712 | | check_typed_ids([b(identifier(ID),T,_)|Tail]) :- !, check_ids3(Tail,ID,T). |
1713 | | check_typed_ids(Other) :- add_internal_error('Unexpected typed id list:',check_typed_ids(Other)). |
1714 | | |
1715 | | |
1716 | | check_atomic_ids([]) :- !. |
1717 | | check_atomic_ids([Id|_]) :- atomic(Id),!. |
1718 | | check_atomic_ids(Other) :- add_internal_error('Expected atomic id list:',check_atomic_ids(Other)). |
1719 | | |
1720 | | |
1721 | | check_ids3([],_,_) :- !. |
1722 | | check_ids3([b(identifier(ID),T,_)|Tail],ID1,T1) :- !, |
1723 | | (ID=ID1 -> add_internal_error('Identifier appears multiple times with types:',id(ID,T1,T)) ; true), |
1724 | | check_ids3(Tail,ID,T). |
1725 | | check_ids3(Other,ID1,T1) :- add_internal_error('Unexpected typed id list:',check_ids3(Other,ID1,T1)). |
1726 | | |
1727 | | |
1728 | | update_used_ids(b(Pred,T,OInfo),UsedIds,b(Pred,T,[used_ids(UsedIds)|NInfo])) :- |
1729 | | delete(OInfo,used_ids(_),NInfo). |
1730 | | |
1731 | | % check if some pre-computed used ids are valid wrt find_typed_identifier_uses |
1732 | | check_computed_used_ids(TExpr,CompUsedIds) :- |
1733 | | find_identifier_uses(TExpr,[],RealUsedIds), |
1734 | | (RealUsedIds=CompUsedIds -> print(ok(CompUsedIds)),nl |
1735 | | ; add_error(range,'Unexpected used ids:',CompUsedIds,TExpr), |
1736 | | format('Real: ~w~nComp: ~w~n',[RealUsedIds,CompUsedIds]),trace |
1737 | | ). |
1738 | | |
1739 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1740 | | % break predicate into components with disjunct identifiers |
1741 | | % Pred: a predicate |
1742 | | % Components: a list of terms component/2 where the first argument |
1743 | | % is a predicate, the second is the set of used identifiers |
1744 | | predicate_components(Pred,Res) :- predicate_components_in_scope(Pred,[],Res). |
1745 | | predicate_components_in_scope(Pred,LocalVars,Res) :- |
1746 | | predicate_components_with_restriction(Pred,LocalVars,all,Res). |
1747 | | |
1748 | | predicate_components_with_restriction(Pred,LocalVars,RestrictionList,Res) :- |
1749 | | conjunction_to_list(Pred,Preds), |
1750 | | l_predicate_identifiers(Preds,LocalVars,PredIds), |
1751 | | (RestrictionList=all -> R=all ; list_to_ord_set(RestrictionList,R)), |
1752 | | try_find_and_remove_equalities(PredIds,PredIds2), |
1753 | | % print(find_components(R)),nl,nl, |
1754 | | %%(member(pred(P,Ids,X),PredIds2), nl,print(pred(Ids,X)),nl,translate:print_bexpr(P),nl,fail ; true), |
1755 | | find_components(PredIds2,R,Components), |
1756 | | !, |
1757 | | %maplist(print_component,Components), |
1758 | | Components=Res. |
1759 | | predicate_components_with_restriction(Pred,_,_,[component(Pred,[])]) :- |
1760 | | add_internal_error('predicate_components failed: ',predicate_components_with_restriction(Pred,_,_,_)). |
1761 | | |
1762 | | % print_component(component(Pred,Ids)) :- format('Component over ~w :~n',[Ids]), translate:print_bexpr(Pred),nl. |
1763 | | |
1764 | | % get the list of used identifiers for each predicate |
1765 | | l_predicate_identifiers([],_LocalVars,[]). |
1766 | | l_predicate_identifiers([Pred|PRest],LocalVars,[pred(Pred,Ids,_Selected)|IRest]) :- |
1767 | | predicate_identifiers_in_scope(Pred,LocalVars,Ids), % Do not ignore local variables; used instead of enumerate set elements |
1768 | | l_predicate_identifiers(PRest,LocalVars,IRest). |
1769 | | |
1770 | | |
1771 | | try_find_and_remove_equalities(PredAndIds,PredAndIds2) :- |
1772 | | preferences:get_preference(partition_predicates_inline_equalities,true), |
1773 | | \+ preferences:get_preference(use_solver_on_load,kodkod), |
1774 | ? | find_and_remove_equalities(PredAndIds,RR), |
1775 | | !, PredAndIds2=RR. |
1776 | | try_find_and_remove_equalities(Ps,Ps). |
1777 | | |
1778 | | :- use_module(debug,[debug_println/2]). |
1779 | | % find and apply obvious equalities so that they do not interfere with partitioning into components |
1780 | | % example: c = 1 & f: 1..c --> A & g: 1..c --> B |
1781 | | % TO DO: preprocess and do one pass to detect potential equalities |
1782 | | find_and_remove_equalities([],[]). |
1783 | | find_and_remove_equalities(List,[pred(P,PIds,Sel)|FT]) :- |
1784 | ? | select(pred(P,PIds,Sel),List,Rest), |
1785 | | %PIds = [Id], |
1786 | | identifier_equality(P,Id,Value), |
1787 | | %(value_which_can_be_replaced(Value) -> true ; nl,print('Not replaced: '),translate:print_bexpr(Value),nl,fail), |
1788 | | (get_texpr_id(Value,Id2) |
1789 | | -> Id2 \= Id %,print(inline_id(Id,Id2)),nl |
1790 | | % Note: this inlining does *not* help with partitioning; but does help ProB detect common predicates/expressions |
1791 | | ; PIds=[Id],value_which_can_be_replaced(Value)), |
1792 | | debug_println(9,replace_simple_equality(Id,PIds)), |
1793 | | maplist(apply_to_pred(Id,Value),Rest,RT), |
1794 | | !, |
1795 | ? | find_and_remove_equalities(RT,FT). |
1796 | | % TO DO: detect equalityes x = EXPR, where EXPR does not contain x and where x occurs in no other predicate |
1797 | | % we can then annotate x as not to enumerate |
1798 | | find_and_remove_equalities(R,R). |
1799 | | |
1800 | | identifier_equality(b(equal(LHS,RHS),_,_),Id,EqTerm) :- |
1801 | | (get_texpr_id(LHS,Id) -> EqTerm = RHS |
1802 | | ; get_texpr_id(RHS,Id) -> EqTerm = LHS). |
1803 | | % TO DO: should we detect other equalities? |
1804 | | |
1805 | | value_which_can_be_replaced(b(E,T,_)) :- value_which_can_be_replaced2(E,T). |
1806 | | %(value_which_can_be_replaced2(E,T) -> true ; print(not_val(E)),nl,fail). |
1807 | | value_which_can_be_replaced2(value(_),_). |
1808 | | value_which_can_be_replaced2(integer(_),_). |
1809 | | %value_which_can_be_replaced2(identifier(I),global(G)) :- b_global_constant(G), id_not_used_anywhere(I). |
1810 | | value_which_can_be_replaced2(integer_set(_),_). |
1811 | | value_which_can_be_replaced2(unary_minus(A),_) :- value_which_can_be_replaced(A). |
1812 | | value_which_can_be_replaced2(add(A,B),_) :- value_which_can_be_replaced(A), value_which_can_be_replaced(B). |
1813 | | % we could compute the value |
1814 | | value_which_can_be_replaced2(minus(A,B),_) :- value_which_can_be_replaced(A), value_which_can_be_replaced(B). |
1815 | | value_which_can_be_replaced2(multiplication(A,B),_) :- value_which_can_be_replaced(A), value_which_can_be_replaced(B). |
1816 | | value_which_can_be_replaced2(div(A,B),_) :- |
1817 | | get_integer(B,IB), IB \= 0, |
1818 | | value_which_can_be_replaced(A). |
1819 | | value_which_can_be_replaced2(floored_div(A,B),T) :- value_which_can_be_replaced2(div(A,B),T). |
1820 | | % should we add: with WD check: division, modulo, .... ? see also simple2 in b_ast_cleanup |
1821 | | value_which_can_be_replaced2(max_int,_). |
1822 | | value_which_can_be_replaced2(min_int,_). |
1823 | | value_which_can_be_replaced2(float_set,_). |
1824 | | value_which_can_be_replaced2(real(_),_). |
1825 | | value_which_can_be_replaced2(real_set,_). |
1826 | | value_which_can_be_replaced2(string(_),_). |
1827 | | value_which_can_be_replaced2(string_set,_). |
1828 | | value_which_can_be_replaced2(boolean_true,_). |
1829 | | value_which_can_be_replaced2(boolean_false,_). |
1830 | | value_which_can_be_replaced2(bool_set,_). |
1831 | | value_which_can_be_replaced2(empty_set,_). |
1832 | | value_which_can_be_replaced2(empty_sequence,_). |
1833 | | value_which_can_be_replaced2(couple(A,B),_) :- value_which_can_be_replaced(A), value_which_can_be_replaced(B). |
1834 | | value_which_can_be_replaced2(interval(A,B),_) :- value_which_can_be_replaced(A), value_which_can_be_replaced(B). |
1835 | | value_which_can_be_replaced2(set_extension(L),_) :- maplist(value_which_can_be_replaced,L). |
1836 | | value_which_can_be_replaced2(sequence_extension(L),_) :- maplist(value_which_can_be_replaced,L). |
1837 | | value_which_can_be_replaced2(cartesian_product(A,B),_) :- % typing equations, like t_float = INTEGER*NATURAL1 |
1838 | | simple_value_set(A), simple_value_set(B). |
1839 | | value_which_can_be_replaced2(pow_subset(A),_) :- simple_value_set(A). |
1840 | | %value_which_can_be_replaced2(identifier(_),_). % TO DO: check that this is not the LHS identifier which we replace !! |
1841 | | % identifiers can also be replaced: we check above that the only identifier in the predicate is the equality identifier |
1842 | | % TO DO: enable this but then we need to fix replace_id_by_expr2 to updated the used_ids info ! + we can have scoping issues !?; see test 1358 |
1843 | | |
1844 | | % TO DO: also allow inlining of prj1/prj2 of simple_value_set: |
1845 | | % not_val(comprehension_set([b(identifier(_zzzz_unary),integer,[generated(first)]),b(identifier(_zzzz_binary),integer,[generated(first)]),b(identifier(_lambda_result_),integer,[lambda_result])],b(equal(b(identifier(_lambda_result_),integer,[lambda_result]),b(identifier(_zzzz_unary),integer,[generated(first)])),pred,[prob_annotation(LAMBDA),lambda_result]))) |
1846 | | % not_val(comprehension_set([b(identifier(_zzzz_unary),integer,[generated(second)]),b(identifier(_zzzz_binary),integer,[generated(second)]),b(identifier(_lambda_result_),integer,[lambda_result])],b(equal(b(identifier(_lambda_result_),integer,[lambda_result]),b(identifier(_zzzz_binary),integer,[generated(second)])),pred,[prob_annotation(LAMBDA),lambda_result]))) |
1847 | | |
1848 | | % TO DO: maybe check if it is an infinite type which cannot be evaluated anyway |
1849 | | simple_value_set(b(E,_,_)) :- simple_value_set2(E). |
1850 | | %simple_value_set2(bool_set). % Warning: we could have a finite construct which gets evaluated multiple times |
1851 | | simple_value_set2(string_set). |
1852 | | simple_value_set2(integer_set(_)). |
1853 | | simple_value_set2(float_set). |
1854 | | simple_value_set2(real_set). |
1855 | | simple_value_set2(cartesian_product(A,B)) :- simple_value_set(A), simple_value_set(B). |
1856 | | simple_value_set2(pow_subset(A)) :- simple_value_set(A). |
1857 | | % POW, records struct(_) set ? |
1858 | | |
1859 | | % apply a substiution of ID/Expr on a pred(EXPR,VarList,X) term |
1860 | | % Expr must either be a variable or contain no variables at all |
1861 | | apply_to_pred(ID,Expr,pred(E1,PIds1,X),pred(E2,PIds3,X)) :- |
1862 | ? | (select(ID,PIds1,PIds2) |
1863 | | -> replace_id_by_expr(E1,ID,Expr,E2), %,print(applied(ID)),nl,translate:print_bexpr(E2),nl |
1864 | | % TO DO: replace_id_by_expr does not seem to update used_ids info !! check_used_ids_info fails for test 1358 if we allow identifiers inside Expr |
1865 | | (get_texpr_id(Expr,NewID) |
1866 | | -> ord_add_element(PIds2,NewID,PIds3) |
1867 | | ; PIds3 = PIds2) |
1868 | | %, format('Apply ~w -> ~w : ',[ID,NewID]),translate:print_bexpr(E2),nl |
1869 | | ; E1=E2,PIds1=PIds3). |
1870 | | |
1871 | | |
1872 | | % project a predicate : keep only those Predicates that are directly or |
1873 | | % indirectly relevant for Ids; FullIds are all identifiers used by ProjectedPredicate |
1874 | | project_predicate_on_identifiers(Pred,Ids,ProjectedPredicate,FullIds, RestList) :- |
1875 | | (debug_mode(on) |
1876 | | -> print('project: '),print_bexpr(Pred),nl, print(' on : '), print(Ids),nl |
1877 | | ; true), |
1878 | | conjunction_to_list(Pred,Preds), |
1879 | | l_predicate_identifiers(Preds,[],PredIds), % TO DO: allow LocalVariables to be passed |
1880 | | % print(predids(PredIds)),nl, |
1881 | | try_find_and_remove_equalities(PredIds,PredIds2), |
1882 | | extract_all_predicates(Ids,all,Ids,PredIds2,ProjectedPredicates, RestList,FullIds), |
1883 | | conjunct_predicates(ProjectedPredicates,ProjectedPredicate), |
1884 | | (debug_mode(on) |
1885 | | -> print('*result: '),print_bexpr(ProjectedPredicate),nl, |
1886 | | print(' on : '), print(FullIds),nl |
1887 | | ; true). |
1888 | | |
1889 | | %print_preds([]). |
1890 | | %print_preds([pred(P,_IDs,_)|T]) :- translate:print_bexpr(P), nl, print(' '), print_preds(T). |
1891 | | |
1892 | | :- use_module(b_global_sets,[b_get_global_constants/1, b_get_enumerated_set_constants/1, b_get_global_sets/1]). |
1893 | | predicate_identifiers(Pred,Ids) :- predicate_identifiers_in_scope(Pred,[],Ids). |
1894 | | predicate_identifiers_in_scope(Pred,LocalVariables,Ids) :- |
1895 | | get_global_identifiers(IS), |
1896 | | list_to_ord_set(LocalVariables,LV), |
1897 | | ord_subtract(IS,LV,Ignore2), % Do not ignore any local variable; it will be used instead of enumerate set element |
1898 | | find_identifier_uses_if_necessary(Pred,Ignore2,Ids1), % Ignore enumerated set names |
1899 | | list_to_ord_set(Ids1,Ids). |
1900 | | |
1901 | | get_global_identifiers(IDs) :- get_global_identifiers(IDs,all). |
1902 | | % get global set and constant identifiers which you usually want to exclude for find_identifier_uses |
1903 | | get_global_identifiers(IDs,Option) :- |
1904 | | (Option=ignore_promoted_constants |
1905 | | % do not include those constants that have been automatically promoted as enumerated set elements |
1906 | | -> b_get_enumerated_set_constants(EnumeratedSetCsts) |
1907 | | ; b_get_global_constants(EnumeratedSetCsts) |
1908 | | ), |
1909 | | % b_global_sets:b_get_global_enumerated_sets(GSets), % is there a reason to exclude deferred sets ??; cardinality inference,... are all done before partitioning ? |
1910 | | b_get_global_sets(GSets), |
1911 | | append(GSets,EnumeratedSetCsts,GE), |
1912 | | list_to_ord_set(GE,IDs). |
1913 | | |
1914 | | % find_components(ListOf_pred, Restrict, Out:ListOfComponents) |
1915 | | % role of Restrict: all if we do normal partition or List of VariableIDs on which we restrict our attention to (for Existential quantifier construction) |
1916 | | find_components([],_,[]). |
1917 | | find_components([pred(P,PIds,true)|PRest],Restrict,[component(Pred,Ids)|CRest]) :- |
1918 | | % find all predicates which are using identifiers occuring in PIds |
1919 | | % (and additionally those which use common identifiers ) |
1920 | | ord_restrict(Restrict,PIds,InterIDs), |
1921 | | %format('Treating predicate with ids ~w; restr. intersect = ~w~n',[PIds,InterIDs]), |
1922 | | ( InterIDs =[] -> |
1923 | | % we simply copy this predicate into a single component; not with the scope of Restricted IDs |
1924 | | % print(skip(PIds,P)),nl, % |
1925 | | Pred=P, Ids=PIds, PRest=Rest |
1926 | | ; |
1927 | | extract_all_predicates(InterIDs,Restrict,PIds,PRest,Preds,Rest,Ids), |
1928 | | %length([P|Preds],Len), format('Detected component with ~w conjuncts over ~w~n',[Len,Ids]), |
1929 | | conjunct_predicates_with_pos_info([P|Preds],Pred) |
1930 | | ), |
1931 | | find_components(Rest,Restrict,CRest). |
1932 | | extract_all_predicates([],_,_,Preds,Found,Rest,[]) :- !, % selecting done at end: keep same order of conjuncts |
1933 | | select_predicates(Preds,Found,Rest). |
1934 | | extract_all_predicates(Ids,Restrict,OldIds,Preds,Found,Rest,ResultIds) :- |
1935 | | % search for all predicates that directly use one of the |
1936 | | % identifiers in "Ids" |
1937 | | select_all_using_preds(Preds,Ids,FoundIds), |
1938 | | ord_subtract(FoundIds,OldIds,NewIds), |
1939 | | ord_restrict(Restrict,NewIds,NewIdsToExtract), |
1940 | | ord_union(OldIds,FoundIds,OldIds2), |
1941 | | % now recursively do this which the new identifiers that we have found |
1942 | | extract_all_predicates(NewIdsToExtract,Restrict,OldIds2,Preds,Found,Rest,RestIds), |
1943 | | ord_union([Ids,NewIds,RestIds],ResultIds). |
1944 | | |
1945 | | % mark all predicates which intersect with ComponentIds and compute new ids to be added to the component |
1946 | | select_all_using_preds([],_,[]). |
1947 | | select_all_using_preds([pred(_P,PIds,Selected)|PRest],ComponentIds,NewFoundIds) :- |
1948 | | ( (Selected==true ; ord_disjoint(PIds,ComponentIds)) -> |
1949 | | NewFoundIds1 = [] |
1950 | | ; % we select the predicate for the component |
1951 | | ord_subtract(PIds,ComponentIds,NewFoundIds1), |
1952 | | Selected=true |
1953 | | ), |
1954 | | select_all_using_preds(PRest,ComponentIds,NewFoundIds2), |
1955 | | ord_union(NewFoundIds1,NewFoundIds2,NewFoundIds). |
1956 | | |
1957 | | % ord_intersection with special case for all term |
1958 | | ord_restrict(all,Ids,Res) :- !, Res=Ids. |
1959 | | ord_restrict(Restrict,Ids,Res) :- ord_intersection(Ids,Restrict,Res). |
1960 | | |
1961 | | select_predicates(Predicates,FoundPreds,OtherPreds) :- |
1962 | | split_list(is_selected_predicate,Predicates,FoundPredIds,OtherPreds), |
1963 | | maplist(extract_found_predicate,FoundPredIds,FoundPreds). |
1964 | | is_selected_predicate(pred(_P,_PIds,Selected)) :- ground(Selected). |
1965 | | extract_found_predicate(pred(P,_PIds,_Selected),P). |
1966 | | |
1967 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1968 | | % replace (simultaneously) multiple identifiers by expressions |
1969 | | % this could be used to replace the predicate replace_id_by_expr by mapping everything in a |
1970 | | % singleton list. however, that would involve list operations instead of unifications |
1971 | | parse_pred(Codes,TExpr) :- %format('Parsing ~s~n',[Codes]), |
1972 | | bmachine:b_parse_machine_predicate_from_codes_open(no_quantifier,Codes,[],[],TExpr). |
1973 | | parse_expr(Codes,TExpr) :- bmachine:b_parse_machine_expression_from_codes(Codes,[],TExpr,_Type,true,_Error). |
1974 | | test_result(1,b(equal(b(comprehension_set([b(identifier(__FRESH____),integer,_)], |
1975 | | b(greater(b(identifier(__FRESH____2),integer,_),b(identifier(x),integer,_)),pred,_)),set(integer),_), |
1976 | | b(empty_set,set(integer),_)),pred,_)). |
1977 | | |
1978 | | :- assert_must_succeed((bsyntaxtree:parse_pred("{x|x:INTEGER & x>y}={}",T1), replace_ids_by_exprs(T1,[],[],T1))). |
1979 | | :- assert_must_succeed((bsyntaxtree:parse_pred("{x|x:INTEGER & x>y}={}",T1), bsyntaxtree:parse_expr("100",T2), |
1980 | | replace_ids_by_exprs(T1,[y],[T2],R),bsyntaxtree:parse_pred("{x|x>100}={}",T3),same_texpr(R,T3) )). |
1981 | | :- assert_must_succeed((bsyntaxtree:parse_pred("{x|x:INTEGER & x>y}={}",T1), |
1982 | | replace_ids_by_exprs(T1,[y],[b(identifier(x),integer,[])],R), |
1983 | | bsyntaxtree:test_result(1,R),bsyntaxtree:parse_pred("{x|x:INTEGER & x>x}={}",T3),\+ same_texpr(R,T3) )). |
1984 | | :- assert_must_succeed((bsyntaxtree:parse_pred("{x,y|x:INTEGER & y:INTEGER & x>v & y>w}={}",T1), |
1985 | | replace_ids_by_exprs(T1,[v,w],[b(identifier(w),integer,[]),b(identifier(v),integer,[])],R), |
1986 | | bsyntaxtree:parse_pred("{x,y|x:INTEGER & y:INTEGER & x>w & y>v}={}",T3), same_texpr(R,T3) )). |
1987 | | :- assert_must_succeed((gensym:reset_gensym, bsyntaxtree:parse_pred("{x,y|x:INTEGER & y:INTEGER & x>v & y>w}={}",T1), |
1988 | | replace_ids_by_exprs(T1,[v,w],[b(identifier(w),integer,[]),b(identifier(x),integer,[])],R), |
1989 | | translate:translate_bexpression(R,TR), |
1990 | | TR = '{`__FRESH____1`,y|`__FRESH____1` > w & y > x} = {}')). %'{__FRESH____1,y|(__FRESH____1 : INTEGER & y : INTEGER) & (__FRESH____1 > w & y > x)} = {}' )). |
1991 | | |
1992 | | replace_ids_by_exprs(TExpr,[TId],[Inserted],Replaced) :- !, % better, more robust and efficient version |
1993 | | check_ids([TId],[Id]), |
1994 | | replace_id_by_expr(TExpr,Id,Inserted,Replaced). |
1995 | | replace_ids_by_exprs(TExpr,[],[],Replaced) :- !, Replaced=TExpr. % Nothing to do |
1996 | | replace_ids_by_exprs(TExpr,Ids,Exprs,Replaced) :- |
1997 | | check_ids(Ids,Ids2), % convert to atomic identifiers |
1998 | | find_identifier_uses_l(Exprs,[],ExprsUsedIds), |
1999 | | sort(ExprsUsedIds,SExprsUsedIds), |
2000 | | generate_rename_list(Ids2,Exprs,RenameList), |
2001 | | %print(replace(RenameList,SExprsUsedIds)),nl, |
2002 | | replace_ids_by_exprs2(RenameList,SExprsUsedIds,TExpr,Replaced,_). %, nl,print(done),nl. |
2003 | | % a version of replace_ids_by_exprs2 for maplist: |
2004 | | %replace_ids_by_exprs1(RenameList,SExprsUsedIds,TExpr,Replaced) :- |
2005 | | % replace_ids_by_exprs2(RenameList,SExprsUsedIds,TExpr,Replaced,_). %, print('Rep: '), translate:print_bexpr(Replaced),nl. |
2006 | | |
2007 | | generate_rename_list([],[],[]). |
2008 | | generate_rename_list([ID1|T],[Expr1|TE],[rename(ID1,Expr1)|RT]) :- generate_rename_list(T,TE,RT). |
2009 | | |
2010 | | check_ids([],[]). |
2011 | | check_ids([H|T],[ID|IT]) :- (atomic(H) -> ID=H ; def_get_texpr_id(H,ID)), check_ids(T,IT). |
2012 | | replace_ids_by_exprs2(RenameList,ExprsUsedIds,TExpr,Replaced,WDC) :- |
2013 | | remove_bt(TExpr,Expr,NewExpr,TNewExpr), |
2014 | ? | ( Expr = identifier(Id), member(rename(Id,Inserted),RenameList) -> |
2015 | | Replaced = Inserted, |
2016 | | get_texpr_info(Inserted,Infos), |
2017 | | (memberchk(contains_wd_condition,Infos) |
2018 | | -> WDC = true ; WDC = false) % WDC = true means we have added a wd-condition where previously there was none |
2019 | | ; contains_no_ids(Expr) -> Replaced=TExpr, WDC=false |
2020 | | ; |
2021 | | syntaxtransformation_det(Expr,Subs1,Names,NSubs,NewExpr), |
2022 | | find_variable_clashes(Names,ExprsUsedIds,RenameNames), % check for variable caputure |
2023 | | (RenameNames = [] |
2024 | | -> Subs = Subs1 % no variable capture occured |
2025 | | ; %format('*** VARIABLE CAPTURE : ~w~n~n',[RenameNames]), |
2026 | | rename_bt_l(Subs1,RenameNames,Subs) % replace affected names by fresh ids in sub arguments (will also change list of quantified variables itself) |
2027 | | ), |
2028 | | %l_replace_ids_by_exprs2(QSubs,RenameList,ExprsUsedIds,NQSubs,WDC1), % QSubs are like RHS of let expression, where Names are not in scope |
2029 | | remove_hidden_names(Names,RenameList,UpdatedRenameList), |
2030 | | ( UpdatedRenameList = [] -> % all Ids are now hidden for the inner expressions |
2031 | | NSubs=Subs, WDC=false |
2032 | | ; |
2033 | | l_replace_ids_by_exprs2(Subs,UpdatedRenameList,ExprsUsedIds,NSubs,WDC) |
2034 | | ), |
2035 | | TNewExpr = b(E1,T1,Info1), |
2036 | | rename_update_used_ids_info(RenameList,Info1,Info2), |
2037 | | add_wd_if_needed(WDC,b(E1,T1,Info2),Replaced) |
2038 | | ). |
2039 | | |
2040 | | contains_no_ids(integer(_)). |
2041 | | contains_no_ids(string(_)). |
2042 | | contains_no_ids(value(_)). |
2043 | | |
2044 | | |
2045 | | % check if we have to rename any quantified variable to avoid variable capture of RHS of renamings |
2046 | | % example, suppose we rename x/y+1 and we enter {y|y>x} we have to generate {fresh|fresh>y+1} and *not* {y|y>y+1} |
2047 | | find_variable_clashes([],_,[]). |
2048 | | find_variable_clashes([Name|Names],ExprsUsedIds,[rename(ID,FRESHID)|Renaming] ) :- |
2049 | | def_get_texpr_id(Name,ID), |
2050 | | ord_member(ID,ExprsUsedIds), % the quantified name is also introduced by the renaming |
2051 | | !, |
2052 | | gensym('__FRESH__',FRESHID), |
2053 | | find_variable_clashes(Names,ExprsUsedIds,Renaming). |
2054 | | find_variable_clashes([_|Names],ExprsUsedIds,Renaming) :- |
2055 | | find_variable_clashes(Names,ExprsUsedIds,Renaming). |
2056 | | |
2057 | | |
2058 | | l_replace_ids_by_exprs2([],_,_,[],false). |
2059 | | l_replace_ids_by_exprs2([H|T],UpdatedRenameList,ExprsUsedIds,[IH|IT],WDC) :- |
2060 | | replace_ids_by_exprs2(UpdatedRenameList,ExprsUsedIds,H,IH,WDC1), |
2061 | | l_replace_ids_by_exprs2(T,UpdatedRenameList,ExprsUsedIds,IT,WDC2), |
2062 | | and_wdc(WDC1,WDC2,WDC). |
2063 | | |
2064 | | % remove any identifiers that are now "invisible" because they are masked by quantified names |
2065 | | % e.g., when we enter #x.(P) then a renaming of x will be "hidden" inside P |
2066 | | remove_hidden_names([],RenameList,RenameList). |
2067 | | remove_hidden_names([Name|Names],RenameList,NewRenameList) :- |
2068 | | def_get_texpr_id(Name,ID), |
2069 | | delete(RenameList,rename(ID,_),RenameList1), |
2070 | | !, % only one rename should exist |
2071 | | %print(del(ID,RenameList1)),nl, |
2072 | | remove_hidden_names(Names,RenameList1,NewRenameList). |
2073 | | |
2074 | | find_rhs_ids(rename(Id,TExpr),rename_ids(Id,InsUsedIds)) :- find_identifier_uses(TExpr,[],InsUsedIds). |
2075 | | |
2076 | | % apply a rename list to the used_ids,... information fields |
2077 | | % this is more tricky than applying a single identifier, as we first have to deleted all ids |
2078 | | % and remember which ones were deleted, and only then insert the corresponding ids |
2079 | | % e.g., we could have a RenameList = [rename(p,q),rename(q,p)] ; see test 1776 M1_Internal_v3.mch |
2080 | | rename_update_used_ids_info(RenameList,IIn,IOut) :- |
2081 | | l_find_rhs_ids(RenameList,RenameList2), |
2082 | | %maplist(apply_rename_list(RenameList2),IIn,IOut). |
2083 | | l_apply_rename_list(IIn,RenameList2,IOut). |
2084 | | |
2085 | | l_find_rhs_ids([],[]). |
2086 | | l_find_rhs_ids([R1|T],[NR1|NTR]) :- |
2087 | | find_rhs_ids(R1,NR1), |
2088 | | l_find_rhs_ids(T,NTR). |
2089 | | |
2090 | | l_apply_rename_list([],_,[]). |
2091 | | l_apply_rename_list([Info1|T],RenameList2,[NewInfo1|NTI]) :- |
2092 | | apply_rename_list(RenameList2,Info1,NewInfo1), |
2093 | | l_apply_rename_list(T,RenameList2,NTI). |
2094 | | |
2095 | | apply_rename_list(RenameList,I,NI) :- |
2096 | | apply_rename_list2(I,RenameList,NI). |
2097 | | apply_rename_list2(used_ids(IDS),RenameList,used_ids(NewIDS)) :- !, apply_rename_list_to_ids(RenameList,IDS,[],NewIDS). |
2098 | | apply_rename_list2(reads(IDS),RenameList,reads(NewIDS)) :- !, apply_rename_list_to_ids(RenameList,IDS,[],NewIDS). |
2099 | | apply_rename_list2(modifies(IDS),RenameList,modifies(NewIDS)) :- !, apply_rename_list_to_ids(RenameList,IDS,[],NewIDS). |
2100 | | apply_rename_list2(Info,_,Info). |
2101 | | |
2102 | | % apply a rename list to a sorted list of ids |
2103 | | apply_rename_list_to_ids([],Acc,ToInsert,Res) :- ord_union(Acc,ToInsert,Res). |
2104 | | apply_rename_list_to_ids([rename_ids(Id,NewIds)|T],Acc,ToInsert,Res) :- |
2105 | | (ord_delete_existing_element(Acc,Id,Acc2) % the Id occurs and is deleted |
2106 | | -> ord_union(NewIds,ToInsert,ToInsert2), |
2107 | | apply_rename_list_to_ids(T,Acc2,ToInsert2,Res) |
2108 | | ; apply_rename_list_to_ids(T,Acc,ToInsert,Res)). |
2109 | | |
2110 | | ord_delete_existing_element(List,El,ResList) :- % ord_del_element also succeeds if El is not in the list ! |
2111 | | ord_intersection([El],List,[El],ResList). |
2112 | | % ----------------------- |
2113 | | % remove an Identifier from used_ids Info field if it exists |
2114 | | remove_used_id_from_info(I,ID_to_remove,NI) :- |
2115 | | update_used_ids_info(I,ID_to_remove,[],NI). |
2116 | | |
2117 | | remove_used_ids_from_info([],I,I). |
2118 | | remove_used_ids_from_info([ID_to_remove|T],I,NI) :- remove_used_id_from_info(I,ID_to_remove,I2), |
2119 | | remove_used_ids_from_info(T,I2,NI). |
2120 | | |
2121 | | % remove a single Identifier from used_ids Info field if it exists and insert sorted list of ids instead |
2122 | | % a simpler version of rename_update_used_ids_info for a single identifier |
2123 | | update_used_ids_info([],_,_,[]). |
2124 | | update_used_ids_info([InfoField|T],ID_to_remove,IDsInserted,[NewInfoField|NT]) :- |
2125 | | (update_id_from_info_field(ID_to_remove,IDsInserted,InfoField,R) |
2126 | | -> NewInfoField=R |
2127 | | ; NewInfoField=InfoField), |
2128 | | update_used_ids_info(T,ID_to_remove,IDsInserted,NT). |
2129 | | |
2130 | | update_id_from_info_field(ID_to_remove,IDsInserted,I,NI) :- |
2131 | | update_id_from_info_field2(I,ID_to_remove,IDsInserted,NI). |
2132 | | update_id_from_info_field2(used_ids(IDS),ID,IDsInserted,used_ids(NewIDS)) :- update_id(IDS,ID,IDsInserted,NewIDS). |
2133 | | update_id_from_info_field2(reads(IDS),ID,IDsInserted,reads(NewIDS)) :- update_id(IDS,ID,IDsInserted,NewIDS). |
2134 | | update_id_from_info_field2(modifies(IDS),ID,IDsInserted,modifies(NewIDS)) :- update_id(IDS,ID,IDsInserted,NewIDS). |
2135 | | |
2136 | | update_id(IDS,ID_to_remove,IDsInserted,NewIDS) :- |
2137 | | ord_delete_existing_element(IDS,ID_to_remove,IDS2), % the Id occurs and is deleted |
2138 | | ord_union(IDsInserted,IDS2,NewIDS). |
2139 | | %if ord_del_element fails we do not add IDsInserted: we assume the used_ids info is correct and ID_to_remove does not occur ! |
2140 | | % We could use this info to avoid traversing subtree ! |
2141 | | % print(projecting_away_unknown_id(ID_to_remove,IDS)),nl, |
2142 | | |
2143 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
2144 | | |
2145 | | :- assert_must_succeed((gensym:reset_gensym, bsyntaxtree:exists_ast(A), replace_id_by_expr(A,y,b(identifier(x),integer,[]),RA),translate:translate_bexpression(RA,TR), |
2146 | | TR = 'r = {`__FRESH____1`|`__FRESH____1` : 1 .. x & `__FRESH____1` mod 2 = 1}' )). |
2147 | | :- assert_must_succeed((bsyntaxtree:parse_pred("{x|x:INTEGER & x>y}={}",T1), |
2148 | | replace_id_by_expr(T1,y,b(identifier(x),integer,[]),R), |
2149 | | bsyntaxtree:test_result(1,R),bsyntaxtree:parse_pred("{x|x:INTEGER & x>x}={}",T3), |
2150 | | \+ same_texpr(R,T3) )). |
2151 | | :- assert_must_succeed((bsyntaxtree:parse_pred("{x|x:INTEGER & x>y}={}",T1), bsyntaxtree:parse_expr("100",T2), |
2152 | | replace_id_by_expr(T1,y,T2,R),bsyntaxtree:parse_pred("{x|x>100}={}",T3),same_texpr(R,T3) )). |
2153 | | |
2154 | | % replace an identifier Id by an expression Inserted |
2155 | | replace_id_by_expr(TExpr,Id,Inserted,Replaced) :- |
2156 | | replace_id_by_expr_with_count(TExpr,Id,Inserted,Replaced,_). |
2157 | | |
2158 | | replace_id_by_expr_with_count(TExpr,Id,Inserted,Replaced,NrReplacements) :- \+ atomic(Id),!, |
2159 | | add_internal_error('Id not atomic: ',replace_id_by_expr(TExpr,Id,Inserted,Replaced)), |
2160 | | Replaced = TExpr, NrReplacements=0. |
2161 | | replace_id_by_expr_with_count(TExpr,Id,Inserted,Replaced,NrReplacements) :- |
2162 | | %find_all_relevant_quantified_vars(Id,TExpr,QVars), |
2163 | | find_identifier_uses(Inserted,[],SInsUsedIds), % SInsUsedIds is sorted |
2164 | | replace_id_by_expr2(Id,Inserted,SInsUsedIds,TExpr,Replaced,_WDC,0,NrReplacements). |
2165 | | |
2166 | | replace_id_by_expr2(Id,Inserted,InsUsedIds,TExpr,Replaced,WDC,InR,OutR) :- |
2167 | | remove_bt(TExpr,Expr,NewExpr,TNewExpr), |
2168 | | ( Expr = identifier(Id) -> % TODO: count number of replacements |
2169 | | Replaced = Inserted, |
2170 | | OutR is InR+1, |
2171 | | get_texpr_info(Inserted,Infos), |
2172 | | (memberchk(contains_wd_condition,Infos) |
2173 | | -> WDC = true ; WDC = false) % WDC = true means we have added a wd-condition where previously there was none |
2174 | | ; contains_no_ids(Expr) -> Replaced=TExpr, WDC=false, OutR=InR |
2175 | | ; |
2176 | | syntaxtransformation_det(Expr,Subs,Names,NSubs,NewExpr), |
2177 | | get_texpr_id(TId,Id), |
2178 | | ( memberchk(TId,Names) -> % the Id is now hidden for the inner expressions |
2179 | | NSubs=Subs, WDC=false, OutR = InR |
2180 | | ; (InsUsedIds \= [], |
2181 | | get_texpr_ids(Names,Ns),sort(Ns,SNs), |
2182 | | ord_intersection(SNs,InsUsedIds,Captured), |
2183 | | Captured \= [] %, print(inter(SNs,InsUsedIds,Captured)),nl |
2184 | | ) |
2185 | | % The Names introduced clash with variables used in the Inserted expression |
2186 | | -> findall(rename(X,FRESHID),(member(X,Captured),gensym:gensym('__FRESH__',FRESHID)),RenameList), |
2187 | | %print(rename(RenameList)),nl, |
2188 | | rename_bt_l(Subs,RenameList,RenSubs), |
2189 | | l_replace_id_by_expr2(RenSubs,Id,Inserted,InsUsedIds,NSubs,WDC,InR,OutR) |
2190 | | ; |
2191 | | l_replace_id_by_expr2(Subs,Id,Inserted,InsUsedIds,NSubs,WDC,InR,OutR) |
2192 | | ), |
2193 | | TNewExpr = b(E1,T1,Info1), |
2194 | | update_used_ids_info(Info1,Id,InsUsedIds,Info2), |
2195 | | %(E1 = exists(P,_) -> print(exists(P,Id,Info1,Info2)),nl ; true), |
2196 | | add_wd_if_needed(WDC,b(E1,T1,Info2),Replaced) |
2197 | | ). |
2198 | | |
2199 | | l_replace_id_by_expr2([],_,_,_,[],false,R,R). |
2200 | | l_replace_id_by_expr2([H|T],Id,Inserted,InsUsedIds,[IH|IT],WDC,InR,OutR) :- |
2201 | | replace_id_by_expr2(Id,Inserted,InsUsedIds,H,IH,WDC1,InR,InR2), |
2202 | | l_replace_id_by_expr2(T,Id,Inserted,InsUsedIds,IT,WDC2,InR2,OutR), |
2203 | | and_wdc(WDC1,WDC2,WDC). |
2204 | | |
2205 | | % conjunct wd condition added flag |
2206 | | and_wdc(true,_,R) :- !,R=true. |
2207 | | and_wdc(_,true,R) :- !, R=true. |
2208 | | and_wdc(_,_,false). |
2209 | | |
2210 | | % add contains_wd_condition if a change occured during replacement of id by expression |
2211 | | add_wd_if_needed(true,b(E,T,Infos),Replaced) :- |
2212 | | nonmember(contains_wd_condition,Infos), |
2213 | | !, |
2214 | | Replaced = b(E,T,[contains_wd_condition|Infos]). |
2215 | | add_wd_if_needed(_,T,T). |
2216 | | |
2217 | | |
2218 | | |
2219 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
2220 | | |
2221 | | |
2222 | | % syntaxtransformation_fixed/7 is the same as syntaxtransformation/5 with the exception |
2223 | | % that we distinguish between subexpressions that have the newly introduced identifiers (Names) |
2224 | | % in scope (OSubs) and those who don't (OExprs). The only expressions where the latter case is relevant |
2225 | | % are let_expression and let_predicate. |
2226 | | % TODO: This is a quick'n dirty fix for only some cases. |
2227 | | % NO LONGER REQUIRED: let_expression and let_predicate now obey another semantic, not the Z semantics anymore |
2228 | | %syntaxtransformation_fixed(OExpr,OExprs,OSubs,Names,NExprs,NSubs,NExpr) :- |
2229 | | %syntaxtransformation_fixed(Expr,[],Subs,Names,[],NSubs,NExpr) :- |
2230 | | % syntaxtransformation_det(Expr,Subs,Names,NSubs,NExpr). |
2231 | | |
2232 | | |
2233 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
2234 | | % rename identifier |
2235 | | |
2236 | | % r = {x|x : 1..y & x mod 2 = 1} |
2237 | | exists_ast(AST) :- AST = |
2238 | | b(equal(b(identifier(r),set(integer),[nodeid(none)]), |
2239 | | b(comprehension_set([b(identifier(x),integer,[nodeid(none)])], |
2240 | | b(conjunct(b(member(b(identifier(x),integer,[nodeid(none)]), |
2241 | | b(interval(b(integer(1),integer,[nodeid(none)]),b(identifier(y),integer,[nodeid(none)])), |
2242 | | set(integer),[nodeid(none)])),pred,[nodeid(none)]), |
2243 | | b(equal(b(modulo(b(identifier(x),integer,[nodeid(none)]), |
2244 | | b(integer(2),integer,[nodeid(none)])),integer,[contains_wd_condition,nodeid(none)]), |
2245 | | b(integer(1),integer,[nodeid(none)])),pred, |
2246 | | [contains_wd_condition,nodeid(none)])),pred,[contains_wd_condition,nodeid(none)])), |
2247 | | set(integer),[contains_wd_condition,nodeid(none)])), |
2248 | | pred,[contains_wd_condition,nodeid(none)]). |
2249 | | |
2250 | | :- assert_must_succeed((bsyntaxtree:exists_ast(A), rename_bt(A,[rename(x,xx)],RA), RA==A )). |
2251 | | :- assert_must_succeed((bsyntaxtree:exists_ast(A), rename_bt(A,[rename(r,v)],RA), |
2252 | | translate:translate_bexpression(RA,TR), TR='v = {x|x : 1 .. y & x mod 2 = 1}' )). |
2253 | | :- assert_must_succeed((gensym:reset_gensym, bsyntaxtree:exists_ast(A), rename_bt(A,[rename(y,x)],RA), RA \= A, |
2254 | | translate:translate_bexpression(RA,TR), |
2255 | | TR = 'r = {`__FRESH____1`|`__FRESH____1` : 1 .. x & `__FRESH____1` mod 2 = 1}' )). |
2256 | | |
2257 | | % a simplified version of replace_ids_by_exprs, which assumes target of renamings are variables |
2258 | | rename_bt(Expr,[],Res) :- !,Res=Expr. |
2259 | | rename_bt(OExpr,Renamings,NExpr) :- |
2260 | | create_texpr(Old,Type,OInfo,OExpr), |
2261 | | create_texpr(New,Type,NInfo,NExpr), |
2262 | | rename_in_infos(OInfo,Renamings,NInfo), |
2263 | | rename_bt2(Old,Renamings,New). |
2264 | | rename_bt2(identifier(Old),Renamings,identifier(New)) :- |
2265 | | !, rename_id(Old,Renamings,New). |
2266 | | rename_bt2(lazy_lookup_expr(Old),Renamings,lazy_lookup_expr(New)) :- |
2267 | | !, rename_id(Old,Renamings,New). |
2268 | | rename_bt2(lazy_lookup_pred(Old),Renamings,lazy_lookup_pred(New)) :- |
2269 | | !, rename_id(Old,Renamings,New). |
2270 | | rename_bt2(OExpr,Renamings,NExpr) :- |
2271 | | syntaxtransformation(OExpr,Subs,TNames,NSubs,NExpr), |
2272 | | get_texpr_exprs(TNames,Names), |
2273 | | remove_renamings(Names,Renamings,NRenamings), |
2274 | | rename_bt_l(Subs,NRenamings,NSubs). |
2275 | | rename_bt_l([],_,[]). |
2276 | | rename_bt_l([Old|ORest],Renamings,[New|NRest]) :- |
2277 | | rename_bt(Old,Renamings,New), |
2278 | | rename_bt_l(ORest,Renamings,NRest). |
2279 | | |
2280 | | remove_renamings([],Renamings,Renamings). |
2281 | | remove_renamings([identifier(Name)|Rest],Old,New) :- |
2282 | ? | ( select(rename(Name,_),Old,Inter1) -> true % Name no longer visible to renaming |
2283 | | ; Old = Inter1), |
2284 | | (member(rename(_OldName,Name),Inter1) -> |
2285 | | gensym('__FRESH__',FRESHID), |
2286 | | %print(variable_capture_in_rename(Name,from(OldName),FRESHID)),nl, |
2287 | | Inter2 = [rename(Name,FRESHID)|Inter1] |
2288 | | ; Inter2 = Inter1), |
2289 | | remove_renamings(Rest,Inter2,New). |
2290 | | |
2291 | | rename_in_infos(Old,Renamings,New) :- |
2292 | | ( has_info_to_rename(Old) -> |
2293 | | maplist(rename_in_infos2(Renamings),Old,New) |
2294 | | ; |
2295 | | Old = New). |
2296 | | rename_in_infos2(Renamings,OInfo,NInfo) :- |
2297 | | ( infos_to_rename(OInfo,OIds,SortedNIds,NInfo) -> |
2298 | | rename_ids(OIds,Renamings,NIds), |
2299 | | sort(NIds,SortedNIds) |
2300 | | ; |
2301 | | OInfo = NInfo). |
2302 | | |
2303 | | rename_ids([],_,[]). |
2304 | | rename_ids([OId|Orest],Renamings,[NId|Nrest]) :- |
2305 | | rename_id(OId,Renamings,NId), |
2306 | | rename_ids(Orest,Renamings,Nrest). |
2307 | | rename_id(Old,Renamings,New) :- |
2308 | | ( memberchk(rename(Old,New),Renamings) -> true % we could use ord_member if we sort ! |
2309 | | ; Old=New). |
2310 | | |
2311 | | has_info_to_rename(Infos) :- |
2312 | ? | member(I,Infos),infos_to_rename(I,_,_,_),!. |
2313 | | |
2314 | | infos_to_rename(modifies(O),O,N,modifies(N)). |
2315 | | infos_to_rename(reads(O),O,N,reads(N)). |
2316 | | infos_to_rename(non_det_modifies(O),O,N,non_det_modifies(N)). |
2317 | | infos_to_rename(modifies_locals(O),O,N,modifies_locals(N)). |
2318 | | infos_to_rename(reads_locals(O),O,N,reads_locals(N)). |
2319 | | infos_to_rename(used_ids(O),O,N,used_ids(N)). |
2320 | | %infos_to_rename(lambda_result(O),[O],[N],lambda_result(N)). % whould we no longer assume that we have lambda result, as predicate has possibly changed!? |
2321 | | |
2322 | | |
2323 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
2324 | | % remove type information for transformations |
2325 | | |
2326 | | remove_bt(b(Expr,Type,Infos),Expr,NExpr,b(NExpr,Type,Infos)). |
2327 | | |
2328 | | remove_bt_and_used_ids(b(OldExpr,T,Infos),OldExpr,NewExpr,b(NewExpr,T,NewInfos)) :- |
2329 | | delete(Infos,used_ids(_),NewInfos). % invalidate used_ids info |
2330 | | |
2331 | | %remove_bt_l([],[],[],[]). |
2332 | | %remove_bt_l([OT|OTRest],[O|ORest],[N|NRest],[NT|NTRest]) :- |
2333 | | % remove_bt(OT,O,N,NT), |
2334 | | % remove_bt_l(OTRest,ORest,NRest,NTRest). |
2335 | | |
2336 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
2337 | | % traversations |
2338 | | % Takes a predicate or expression or substitution and extracts: |
2339 | | % the expression itself Expr, its type Type, the syntaxnode information Infos |
2340 | | % + the subexpressions as a list Subs and the local identifiers declared |
2341 | | syntaxtraversion(b(Expr,Type,Infos),Expr,Type,Infos,Subs,Names) :- !, |
2342 | | safe_syntaxelement(Expr,Subs,Names,_,_). |
2343 | | syntaxtraversion(IExpr,Expr,Type,Infos,Subs,Names) :- |
2344 | | add_internal_error('Not properly wrapped', syntaxtraversion(IExpr,Expr,Type,Infos,Subs,Names)), |
2345 | | fail. |
2346 | | |
2347 | | |
2348 | | map_over_full_bexpr_no_fail(P,BExpr) :- |
2349 | | syntaxtraversion(BExpr,Expr,_,_,Subs,_TNames), |
2350 | | call(P,Expr), % the predicate should not fail |
2351 | | (Subs=[] -> true ; maplist(map_over_full_bexpr_no_fail(P),Subs)). |
2352 | | |
2353 | | map_over_bexpr(P,BExpr) :- |
2354 | | syntaxtraversion(BExpr,Expr,_,_,Subs,_TNames), |
2355 | | (call(P,Expr) % should probably fail so that by backtrack we recurse |
2356 | | ; |
2357 | | member(Sub,Subs), map_over_bexpr(P,Sub) |
2358 | | ). |
2359 | | % same as above but gets typed expressions: |
2360 | | map_over_typed_bexpr(P,BExpr) :- |
2361 | | syntaxtraversion(BExpr,_Expr,_,_,Subs,_TNames), |
2362 | | (call(P,BExpr) |
2363 | | ; |
2364 | ? | member(Sub,Subs), map_over_typed_bexpr(P,Sub) |
2365 | | ). |
2366 | | % same as above but returns value: |
2367 | | map_over_typed_bexpr(P,BExpr,Result) :- |
2368 | | syntaxtraversion(BExpr,_Expr,_,_,Subs,_TNames), |
2369 | | (call(P,BExpr,Result) |
2370 | | ; |
2371 | ? | member(Sub,Subs), map_over_typed_bexpr(P,Sub,Result) |
2372 | | ). |
2373 | | % this one gets TNames (locally introduced variables as parameter) |
2374 | | map_over_typed_bexpr_with_names(P,BExpr) :- |
2375 | | syntaxtraversion(BExpr,_Expr,_,_,Subs,TNames), |
2376 | | (call(P,BExpr,TNames) |
2377 | | ; |
2378 | | member(Sub,Subs), map_over_typed_bexpr_with_names(P,Sub) |
2379 | | ). |
2380 | | |
2381 | | % same as map_over_expr but provides an accumulator passed top-down to children; needs to be used by failure driven loop |
2382 | | |
2383 | | map_over_bexpr_top_down_acc(P,BExpr,TDAcc) :- |
2384 | | syntaxtraversion(BExpr,Expr,_,_,Subs,_TNames), |
2385 | | (call(P,Expr,TDAcc,NewAcc) |
2386 | | -> member(Sub,Subs), map_over_bexpr_top_down_acc(P,Sub,NewAcc) |
2387 | | ; member(Sub,Subs), map_over_bexpr_top_down_acc(P,Sub,TDAcc) |
2388 | | ). |
2389 | | % now a version which gets the typed predicate as argument |
2390 | | |
2391 | | map_over_typed_bexpr_top_down_acc(P,BExpr,TDAcc) :- |
2392 | | syntaxtraversion(BExpr,_Expr,_,_,Subs,_TNames), |
2393 | | (call(P,BExpr,TDAcc,NewAcc) |
2394 | | -> member(Sub,Subs), map_over_typed_bexpr_top_down_acc(P,Sub,NewAcc) |
2395 | | ; member(Sub,Subs), map_over_typed_bexpr_top_down_acc(P,Sub,TDAcc) |
2396 | | ). |
2397 | | |
2398 | | % predicate P has 3 arguments: (Expr,ValueSoFar,NewValue) |
2399 | | reduce_over_bexpr(P,BExpr,InitialValue,ResultValue) :- |
2400 | | syntaxtraversion(BExpr,Expr,_,_,Subs,_TNames), |
2401 | | call(P,Expr,InitialValue,I1), % print(reduce(P,Expr,InitialValue,I1)),nl, |
2402 | | scanlist(reduce_over_bexpr(P),Subs,I1,ResultValue). |
2403 | | |
2404 | | % apply a predicate over a syntax tree (bottom-up) |
2405 | | |
2406 | | transform_bexpr(Pred,b(Expr,Type,Info),NewBExpr) :- !, |
2407 | | syntaxtransformation(Expr,Subs,_Names,NSubs,NewExpr1), |
2408 | | l_transform_bexpr(Subs,Pred,NSubs), |
2409 | | (call(Pred,b(NewExpr1,Type,Info),NewBExpr) -> true ; NewBExpr = b(NewExpr1,Type,Info)). |
2410 | | transform_bexpr(Pred,Expr,NewBExpr) :- |
2411 | | add_internal_error('Expression not properly wrapped:',transform_bexpr(Pred,Expr,NewBExpr)), |
2412 | | fail. |
2413 | | |
2414 | | l_transform_bexpr([],_,[]). |
2415 | | l_transform_bexpr([SubH|T],Pred,[TSubH|TT]) :- |
2416 | | transform_bexpr(Pred,SubH,TSubH), |
2417 | | l_transform_bexpr(T,Pred,TT). |
2418 | | |
2419 | | % apply a predicate over a syntax tree (bottom-up), and provide scoping info about local ids |
2420 | | |
2421 | | transform_bexpr_with_scoping(Pred,BExpr,NewBExpr) :- |
2422 | | transform_bexpr_with_scoping2(Pred,BExpr,NewBExpr,[]). |
2423 | | transform_bexpr_with_scoping2(Pred,b(Expr,Type,Info),NewBExpr,LocalIds) :- |
2424 | | syntaxtransformation(Expr,Subs,Names,NSubs,NewExpr1), |
2425 | | get_texpr_ids(Names,QuantifiedNewIds), list_to_ord_set(QuantifiedNewIds,SQuantifiedNewIds), |
2426 | | ord_union(LocalIds,SQuantifiedNewIds,NewLocalIds), |
2427 | | l_transform_bexpr_with_scoping(Subs,Pred,NSubs,NewLocalIds), |
2428 | | (call(Pred,b(NewExpr1,Type,Info),NewBExpr,LocalIds) -> true ; NewBExpr = b(NewExpr1,Type,Info)). |
2429 | | |
2430 | | l_transform_bexpr_with_scoping([],_,[],_). |
2431 | | l_transform_bexpr_with_scoping([SubH|T],Pred,[TSubH|TT],LocalIds) :- |
2432 | | transform_bexpr_with_scoping2(Pred,SubH,TSubH,LocalIds), |
2433 | | l_transform_bexpr_with_scoping(T,Pred,TT,LocalIds). |
2434 | | |
2435 | | % transform a predicate top-down with scoping infos |
2436 | | % if Pred succeeds the top-down traversal stops |
2437 | | transform_bexpr_td_with_scoping(Pred,BExpr,NewBExpr) :- |
2438 | | transform_bexpr_td_with_scoping2(Pred,BExpr,NewBExpr,[]). |
2439 | | transform_bexpr_td_with_scoping2(Pred,b(Expr,Type,Info),b(NewExpr1,Type,Info),LocalIds) :- |
2440 | ? | (call(Pred,Expr,NewExpr1,LocalIds) |
2441 | | -> true |
2442 | | ; syntaxtransformation(Expr,Subs,Names,NSubs,NewExpr1), |
2443 | | get_texpr_ids(Names,QuantifiedNewIds), list_to_ord_set(QuantifiedNewIds,SQuantifiedNewIds), |
2444 | | ord_union(LocalIds,SQuantifiedNewIds,NewLocalIds), |
2445 | | l_transform_bexpr_td_with_scoping(Subs,Pred,NSubs,NewLocalIds) |
2446 | | ). |
2447 | | |
2448 | | l_transform_bexpr_td_with_scoping([],_,[],_). |
2449 | | l_transform_bexpr_td_with_scoping([SubH|T],Pred,[TSubH|TT],LocalIds) :- |
2450 | | transform_bexpr_td_with_scoping2(Pred,SubH,TSubH,LocalIds), |
2451 | | l_transform_bexpr_td_with_scoping(T,Pred,TT,LocalIds). |
2452 | | |
2453 | | |
2454 | | % apply a predicate over a syntax tree (bottom-up) with Accumulator result |
2455 | | % Accumulator is constructed bottom up; Pred receives *all* accumulators of sub expressions |
2456 | | |
2457 | | transform_bexpr_with_bup_accs(Pred,b(Expr,Type,Info),NewBExpr,EmptyAcc,Acc) :- |
2458 | | syntaxtransformation(Expr,Subs,_Names,NSubs,NewExpr1), |
2459 | | l_transform_bexpr_with_bup_accs(Subs,Pred,NSubs,EmptyAcc,SubAccs), |
2460 | | (call(Pred,b(NewExpr1,Type,Info),NewBExpr,SubAccs,Acc) -> true |
2461 | | ; NewBExpr = b(NewExpr1,Type,Info), Acc = EmptyAcc). |
2462 | | |
2463 | | l_transform_bexpr_with_bup_accs([],_,[],_,[]). |
2464 | | l_transform_bexpr_with_bup_accs([SubH|T],Pred,[TSubH|TT],EmptyAcc,[Acc1|RestAcc]) :- |
2465 | | transform_bexpr_with_bup_accs(Pred,SubH,TSubH,EmptyAcc,Acc1), |
2466 | | l_transform_bexpr_with_bup_accs(T,Pred,TT,EmptyAcc,RestAcc). |
2467 | | |
2468 | | % apply a predicate over a syntax tree (bottom-up) with Accumulator result |
2469 | | % a single Accumulator is passed along |
2470 | | |
2471 | | transform_bexpr_with_acc(_Pred,E,NewBExpr,InAcc,Acc) :- var(E),!, |
2472 | | NewBExpr=E, Acc=InAcc. |
2473 | | transform_bexpr_with_acc(Pred,b(Expr,Type,Info),NewBExpr,InAcc,Acc) :- |
2474 | | syntaxtransformation(Expr,Subs,_Names,NSubs,NewExpr1), |
2475 | | l_transform_bexpr_with_acc(Subs,Pred,NSubs,InAcc,SubAcc), |
2476 | | (call(Pred,b(NewExpr1,Type,Info),NewBExpr,SubAcc,Acc) -> true |
2477 | | ; NewBExpr = b(NewExpr1,Type,Info), Acc = SubAcc). |
2478 | | |
2479 | | l_transform_bexpr_with_acc([],_,[],Acc,Acc). |
2480 | | l_transform_bexpr_with_acc([SubH|T],Pred,[TSubH|TT],InAcc,ResAcc) :- |
2481 | | transform_bexpr_with_acc(Pred,SubH,TSubH,InAcc,Acc1), |
2482 | | l_transform_bexpr_with_acc(T,Pred,TT,Acc1,ResAcc). |
2483 | | |
2484 | | % a non-deterministic version of this |
2485 | | non_det_transform_bexpr_with_acc(_Pred,E,NewBExpr,InAcc,Acc) :- var(E),!, |
2486 | | NewBExpr=E, Acc=InAcc. |
2487 | | non_det_transform_bexpr_with_acc(Pred,b(Expr,Type,Info),NewBExpr,InAcc,Acc) :- |
2488 | | syntaxtransformation(Expr,Subs,_Names,NSubs,NewExpr1), |
2489 | | l_nd_transform_bexpr_with_acc(Subs,Pred,NSubs,InAcc,SubAcc), |
2490 | | if(call(Pred,b(NewExpr1,Type,Info),NewBExpr,SubAcc,Acc), |
2491 | | true, |
2492 | | (NewBExpr = b(NewExpr1,Type,Info), Acc = SubAcc)). |
2493 | | |
2494 | | l_nd_transform_bexpr_with_acc([],_,[],Acc,Acc). |
2495 | | l_nd_transform_bexpr_with_acc([SubH|T],Pred,[TSubH|TT],InAcc,ResAcc) :- |
2496 | | non_det_transform_bexpr_with_acc(Pred,SubH,TSubH,InAcc,Acc1), |
2497 | | l_nd_transform_bexpr_with_acc(T,Pred,TT,Acc1,ResAcc). |
2498 | | |
2499 | | |
2500 | | % ------------------------- |
2501 | | |
2502 | | min_max_integer_value_used(BExpr,Min,Max) :- |
2503 | | min_max_integer_value_used(BExpr,none,none,Min,Max). |
2504 | | min_max_integer_value_used(BExpr,IMin,IMax,Min,Max) :- |
2505 | | reduce_over_bexpr(min_max_aux,BExpr,minmax(IMin,IMax),minmax(Min,Max)). |
2506 | | |
2507 | | min_max_aux(sequence_extension(L),minmax(Min,Max),minmax(NMin,NMax)) :- !, |
2508 | | length(L,Len), % we use implicitly numbers from 1..Len |
2509 | | (number(Min),1>Min -> NMin=Min ; NMin=1), |
2510 | | (number(Max),Len<Max -> NMax=Max ; NMax=Len). |
2511 | | min_max_aux(integer(N),minmax(Min,Max),minmax(NMin,NMax)) :- !, |
2512 | | (number(Min),N>Min -> NMin=Min ; NMin=N), |
2513 | | (number(Max),N<Max -> NMax=Max ; NMax=N). |
2514 | | min_max_aux(_,V,V). |
2515 | | |
2516 | | % check if a B expression uses something like NAT,NAT1,INT, MAXINT or MININT. |
2517 | | uses_implementable_integers(BExpr) :- |
2518 | | map_over_bexpr(uses_implementable_integers_aux,BExpr). |
2519 | | |
2520 | | uses_implementable_integers_aux(maxint). |
2521 | | uses_implementable_integers_aux(minint). |
2522 | | uses_implementable_integers_aux(integer_set(X)) :- |
2523 | | (X='NAT1' ; X='NAT' ; X='INT'). |
2524 | | |
2525 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
2526 | | % some checks |
2527 | | check_if_typed_predicate(b(Pred,X,_)) :- ground(X), X=pred, % at runtime there can be value(X) with variables inside ! |
2528 | | syntaxelement(Pred,_,_,_,_,TypePred), (TypePred=pred -> true ; TypePred = pred/only_typecheck). |
2529 | | check_if_typed_expression(b(Expr,Type,_)) :- |
2530 | | syntaxelement(Expr,_,_,_,_,TypeExpr), |
2531 | | (TypeExpr=expr -> true ; TypeExpr = expr/only_typecheck), |
2532 | | Type \== pred, Type \== subst, ground(Type). |
2533 | | check_if_typed_substitution(b(Subst,X,_)) :- ground(X), X=subst, |
2534 | | syntaxelement(Subst,_,_,_,_,subst). |
2535 | | |
2536 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
2537 | | % transformations |
2538 | | |
2539 | | syntaxtransformation(Expr,Subs,Names,NSubs,NExpr) :- |
2540 | | functor(Expr,F,Arity), |
2541 | | functor(NExpr,F,Arity), |
2542 | | safe_syntaxelement(Expr,Subs,Names,Lists,Constant), |
2543 | | all_same_length(Lists,NLists), |
2544 | | syntaxelement(NExpr,NSubs,_,NLists,Constant,_). |
2545 | | % a faster non-backtracking version: |
2546 | | syntaxtransformation_det(Expr,Subs,Names,NSubs,NExpr) :- |
2547 | | functor(Expr,F,Arity), |
2548 | | functor(NExpr,F,Arity), |
2549 | | safe_syntaxelement_det(Expr,Subs,Names,Lists,Constant), |
2550 | | all_same_length(Lists,NLists), |
2551 | | syntaxelement(NExpr,NSubs,_,NLists,Constant,_). |
2552 | | |
2553 | | |
2554 | | safe_syntaxelement(Expr,Subs,Names,Lists,Constant) :- |
2555 | | ( syntaxelement(Expr,SubsX,NamesX,Lists,ConstantX,_) -> |
2556 | | Subs=SubsX, Names=NamesX, Constant=ConstantX |
2557 | | %(Subs,Names,Constant)=(SubsX,NamesX,ConstantX) |
2558 | | ; |
2559 | | functor(Expr,F,Arity), |
2560 | | add_error_fail(bsyntaxtree,'Uncovered syntax element: ', F/Arity) |
2561 | | ). |
2562 | | % a faster non-backtracking version of safe_syntaxelement, assuming Subs, Names, ... are fresh vars |
2563 | | safe_syntaxelement_det(Expr,Subs,Names,Lists,Constant) :- |
2564 | | (syntaxelement(Expr,Subs,Names,Lists,Constant,_) -> true |
2565 | | ; functor(Expr,F,Arity), |
2566 | | add_error_fail(bsyntaxtree,'Uncovered syntax element: ', F/Arity)). |
2567 | | |
2568 | | is_subst_syntaxelement(Subst) :- |
2569 | | syntaxelement(Subst,_,_,_,_,subst). |
2570 | | |
2571 | | % check if we have a syntax node without parameters |
2572 | | is_syntax_constant(Expr) :- atom(Expr), syntaxelement(Expr,_,_,_,_,_). |
2573 | | |
2574 | | % syntaxelement(Expr,SubExprs,Identifiers,Lists,Constant,Type): |
2575 | | % Expr: the expression itself |
2576 | | % SubExprs: a list of sub-expressions |
2577 | | % Identifiers: a list of identifiers that are newly introduced (e.g. by a quantifier) |
2578 | | % Lists: A list of lists in the expression, to prevent infinite loops when having variable parts |
2579 | | % Constant: A part of the expression that is not a sub-expression (e.g. the number in integer(...)) |
2580 | | % Type: Fundamental type of the element (predicate, expression, etc) |
2581 | | |
2582 | | % predicates |
2583 | | syntaxelement(truth, [], [], [], [], pred). |
2584 | | syntaxelement(falsity, [], [], [], [], pred). |
2585 | | syntaxelement(unknown_truth_value(Msg),[], [], [], Msg, pred). % artificial, e.g., created by well_def_analyser |
2586 | | syntaxelement(conjunct(A,B), [A,B],[], [], [], pred). |
2587 | | %syntaxelement(conjunct(As), As, [], [], [], pred). % TO DO: support associative version of conjunct |
2588 | | syntaxelement(negation(A), [A], [], [], [], pred). |
2589 | | syntaxelement(disjunct(A,B), [A,B],[], [], [], pred). |
2590 | | syntaxelement(implication(A,B), [A,B],[], [], [], pred). |
2591 | | syntaxelement(equivalence(A,B), [A,B],[], [], [], pred). |
2592 | | syntaxelement(equal(A,B), [A,B],[], [], [], pred). |
2593 | | syntaxelement(not_equal(A,B), [A,B],[], [], [], pred). |
2594 | | syntaxelement(member(A,B), [A,B],[], [], [], pred). |
2595 | | syntaxelement(not_member(A,B), [A,B],[], [], [], pred). |
2596 | | syntaxelement(subset(A,B), [A,B],[], [], [], pred). |
2597 | | syntaxelement(subset_strict(A,B), [A,B],[], [], [], pred). |
2598 | | syntaxelement(not_subset(A,B), [A,B],[], [], [], pred). |
2599 | | syntaxelement(not_subset_strict(A,B),[A,B],[], [], [], pred). |
2600 | | syntaxelement(less_equal(A,B), [A,B],[], [], [], pred). |
2601 | | syntaxelement(less(A,B), [A,B],[], [], [], pred). |
2602 | | syntaxelement(less_equal_real(A,B), [A,B],[], [], [], pred). |
2603 | | syntaxelement(less_real(A,B), [A,B],[], [], [], pred). |
2604 | | syntaxelement(greater_equal(A,B), [A,B],[], [], [], pred). |
2605 | | syntaxelement(greater(A,B), [A,B],[], [], [], pred). |
2606 | | syntaxelement(forall(Ids,D,P), [D,P|Ids],Ids,[Ids], [], pred). |
2607 | | syntaxelement(exists(Ids,P), [P|Ids], Ids,[Ids], [], pred). |
2608 | | syntaxelement(finite(A), [A], [], [], [], pred/only_typecheck). |
2609 | | syntaxelement(partition(S,Es), [S|Es],[],[Es],[],pred). |
2610 | | syntaxelement(kodkod(PId,Ids), Ids,[],[Ids],PId, pred). |
2611 | | syntaxelement(external_pred_call(F,Args),Args,[],[Args],F,pred). |
2612 | | |
2613 | | % expressions |
2614 | | syntaxelement(value(V), [], [], [], V, expr). |
2615 | | syntaxelement(operation_call_in_expr(Id,As), As, [], [As], Id, expr). % Do not treat Id as a sub-expression for find_identifier_uses, ... |
2616 | | %syntaxelement(operation_call_in_expr(Id,As), [Id|As], [], [As], [], expr). % was like this, but changed to avoid op(.) ids in find_identifier_uses |
2617 | | syntaxelement(boolean_true, [], [], [], [], expr). |
2618 | | syntaxelement(boolean_false, [], [], [], [], expr). |
2619 | | syntaxelement(max_int, [], [], [], [], expr). |
2620 | | syntaxelement(min_int, [], [], [], [], expr). |
2621 | | syntaxelement(empty_set, [], [], [], [], expr). |
2622 | | syntaxelement(bool_set, [], [], [], [], expr). |
2623 | | syntaxelement(float_set, [], [], [], [], expr). |
2624 | | syntaxelement(real(I), [], [], [], I, expr). |
2625 | | syntaxelement(real_set, [], [], [], [], expr). |
2626 | | syntaxelement(string_set, [], [], [], [], expr). |
2627 | | syntaxelement(convert_bool(A), [A], [], [], [], expr). |
2628 | | syntaxelement(convert_real(A), [A], [], [], [], expr). |
2629 | | syntaxelement(convert_int_floor(A), [A], [], [], [], expr). |
2630 | | syntaxelement(convert_int_ceiling(A), [A], [], [], [], expr). |
2631 | | syntaxelement(add(A,B), [A,B],[], [], [], expr). |
2632 | | syntaxelement(add_real(A,B), [A,B],[], [], [], expr). |
2633 | | syntaxelement(minus(A,B), [A,B],[], [], [], expr). |
2634 | | syntaxelement(minus_real(A,B), [A,B],[], [], [], expr). |
2635 | | syntaxelement(minus_or_set_subtract(A,B),[A,B],[], [], [], expr/only_typecheck). |
2636 | | syntaxelement(unary_minus(A), [A], [], [], [], expr). |
2637 | | syntaxelement(unary_minus_real(A), [A], [], [], [], expr). |
2638 | | syntaxelement(multiplication(A,B), [A,B],[], [], [], expr). |
2639 | | syntaxelement(multiplication_real(A,B),[A,B],[], [], [], expr). |
2640 | | syntaxelement(mult_or_cart(A,B), [A,B],[], [], [], expr/only_typecheck). |
2641 | | syntaxelement(cartesian_product(A,B), [A,B],[], [], [], expr). |
2642 | | syntaxelement(div(A,B), [A,B],[], [], [], expr). |
2643 | | syntaxelement(div_real(A,B), [A,B],[], [], [], expr). |
2644 | | syntaxelement(floored_div(A,B), [A,B],[], [], [], expr). |
2645 | | syntaxelement(modulo(A,B), [A,B],[], [], [], expr). |
2646 | | syntaxelement(power_of(A,B), [A,B],[], [], [], expr). |
2647 | | syntaxelement(power_of_real(A,B), [A,B],[], [], [], expr). |
2648 | | syntaxelement(successor, [], [], [], [], expr). |
2649 | | syntaxelement(predecessor, [], [], [], [], expr). |
2650 | | syntaxelement(max(A), [A], [], [], [], expr). |
2651 | | syntaxelement(max_real(A), [A], [], [], [], expr). |
2652 | | syntaxelement(min(A), [A], [], [], [], expr). |
2653 | | syntaxelement(min_real(A), [A], [], [], [], expr). |
2654 | | syntaxelement(card(A), [A], [], [], [], expr). |
2655 | | syntaxelement(couple(A,B), [A,B],[], [], [], expr). |
2656 | | syntaxelement(pow_subset(A), [A], [], [], [], expr). |
2657 | | syntaxelement(pow1_subset(A), [A], [], [], [], expr). |
2658 | | syntaxelement(fin_subset(A), [A], [], [], [], expr). |
2659 | | syntaxelement(fin1_subset(A), [A], [], [], [], expr). |
2660 | | syntaxelement(interval(A,B), [A,B],[], [], [], expr). |
2661 | | syntaxelement(union(A,B), [A,B],[], [], [], expr). |
2662 | | syntaxelement(intersection(A,B), [A,B],[], [], [], expr). |
2663 | | syntaxelement(set_subtraction(A,B), [A,B],[], [], [], expr). |
2664 | | syntaxelement(general_union(A), [A], [], [], [], expr). |
2665 | | syntaxelement(general_intersection(A), [A] , [], [], [], expr). |
2666 | | syntaxelement(relations(A,B), [A,B],[], [], [], expr). |
2667 | | syntaxelement(identity(A), [A], [], [], [], expr). |
2668 | | syntaxelement(event_b_identity, [], [], [], [], expr). % for Rodin 1.0, TO DO: Daniel please check |
2669 | | syntaxelement(reverse(A), [A], [], [], [], expr). |
2670 | | syntaxelement(first_projection(A,B), [A,B],[], [], [], expr/only_typecheck). |
2671 | | syntaxelement(first_of_pair(A), [A], [], [], [], expr). |
2672 | | syntaxelement(event_b_first_projection(A),[A], [], [], [], expr/only_typecheck). |
2673 | | syntaxelement(event_b_first_projection_v2,[], [], [], [], expr/only_typecheck). % for Rodin 1.0, TO DO: Daniel please check |
2674 | | syntaxelement(second_projection(A,B), [A,B],[], [], [], expr/only_typecheck). |
2675 | | syntaxelement(event_b_second_projection_v2,[], [], [], [], expr/only_typecheck). % for Rodin 1.0, TO DO: Daniel please check |
2676 | | syntaxelement(second_of_pair(A), [A], [], [], [], expr). |
2677 | | syntaxelement(event_b_second_projection(A),[A], [], [], [], expr/only_typecheck). |
2678 | | syntaxelement(composition(A,B), [A,B],[], [], [], expr). |
2679 | | syntaxelement(ring(A,B), [A,B],[], [], [], expr/only_typecheck). |
2680 | | syntaxelement(direct_product(A,B), [A,B],[], [], [], expr). |
2681 | | syntaxelement(parallel_product(A,B), [A,B],[], [], [], expr). |
2682 | | syntaxelement(trans_function(A), [A], [], [], [], expr). |
2683 | | syntaxelement(trans_relation(A), [A], [], [], [], expr). |
2684 | | syntaxelement(iteration(A,B), [A,B],[], [], [], expr). |
2685 | | syntaxelement(reflexive_closure(A), [A], [], [], [], expr). |
2686 | | syntaxelement(closure(A), [A], [], [], [], expr). |
2687 | | syntaxelement(domain(A), [A], [], [], [], expr). |
2688 | | syntaxelement(range(A), [A], [], [], [], expr). |
2689 | | syntaxelement(image(A,B), [A,B],[], [], [], expr). |
2690 | | syntaxelement(domain_restriction(A,B), [A,B],[], [], [], expr). |
2691 | | syntaxelement(domain_subtraction(A,B), [A,B],[], [], [], expr). |
2692 | | syntaxelement(range_restriction(A,B), [A,B],[], [], [], expr). |
2693 | | syntaxelement(range_subtraction(A,B), [A,B],[], [], [], expr). |
2694 | | syntaxelement(overwrite(A,B), [A,B],[], [], [], expr). |
2695 | | syntaxelement(partial_function(A,B), [A,B],[], [], [], expr). |
2696 | | syntaxelement(total_function(A,B), [A,B],[], [], [], expr). |
2697 | | syntaxelement(partial_injection(A,B), [A,B],[], [], [], expr). |
2698 | | syntaxelement(total_injection(A,B), [A,B],[], [], [], expr). |
2699 | | syntaxelement(partial_surjection(A,B), [A,B],[], [], [], expr). |
2700 | | syntaxelement(total_surjection(A,B), [A,B],[], [], [], expr). |
2701 | | syntaxelement(total_bijection(A,B), [A,B],[], [], [], expr). |
2702 | | syntaxelement(partial_bijection(A,B), [A,B],[], [], [], expr). |
2703 | | syntaxelement(total_relation(A,B), [A,B],[], [], [], expr). |
2704 | | syntaxelement(surjection_relation(A,B),[A,B],[], [], [], expr). |
2705 | | syntaxelement(total_surjection_relation(A,B),[A,B],[], [], [], expr). |
2706 | | syntaxelement(seq(A), [A], [], [], [], expr). |
2707 | | syntaxelement(seq1(A), [A], [], [], [], expr). |
2708 | | syntaxelement(iseq(A), [A], [], [], [], expr). |
2709 | | syntaxelement(iseq1(A), [A], [], [], [], expr). |
2710 | | syntaxelement(perm(A), [A], [], [], [], expr). |
2711 | | syntaxelement(empty_sequence, [], [], [], [], expr). |
2712 | | syntaxelement(size(A), [A], [], [], [], expr). |
2713 | | syntaxelement(first(A), [A], [], [], [], expr). |
2714 | | syntaxelement(last(A), [A], [], [], [], expr). |
2715 | | syntaxelement(front(A), [A], [], [], [], expr). |
2716 | | syntaxelement(tail(A), [A], [], [], [], expr). |
2717 | | syntaxelement(rev(A), [A], [], [], [], expr). |
2718 | | syntaxelement(concat(A,B), [A,B],[], [], [], expr). |
2719 | | syntaxelement(insert_front(A,B), [A,B],[], [], [], expr). |
2720 | | syntaxelement(insert_tail(A,B), [A,B],[], [], [], expr). |
2721 | | syntaxelement(restrict_front(A,B), [A,B],[], [], [], expr). |
2722 | | syntaxelement(restrict_tail(A,B), [A,B],[], [], [], expr). |
2723 | | syntaxelement(general_concat(A), [A], [], [], [], expr). |
2724 | | syntaxelement(function(A,B), [A,B],[], [], [], expr). |
2725 | | syntaxelement(external_function_call(F,Args),Args,[],[Args],F,expr). |
2726 | | syntaxelement(identifier(I), [], [], [], I, expr). |
2727 | | syntaxelement(lazy_lookup_expr(I), [], [], [], I, expr). |
2728 | | syntaxelement(lazy_lookup_pred(I), [], [], [], I, pred). |
2729 | | syntaxelement(integer(I), [], [], [], I, expr). |
2730 | | syntaxelement(integer_set(T), [], [], [], T, expr). |
2731 | | syntaxelement(string(S), [], [], [], S, expr). |
2732 | | syntaxelement(set_extension(L), L, [], [L], [], expr). |
2733 | | syntaxelement(sequence_extension(L), L, [], [L], [], expr). |
2734 | | syntaxelement(comprehension_set(Ids,P),[P|Ids], Ids,[Ids], [], expr). |
2735 | | syntaxelement(event_b_comprehension_set(Ids,E,P),[E,P|Ids], Ids,[Ids], [], expr/only_typecheck). |
2736 | | syntaxelement(lambda(Ids,P,E), [P,E|Ids],Ids,[Ids], [], expr). |
2737 | | syntaxelement(general_sum(Ids,P,E), [P,E|Ids],Ids,[Ids], [], expr). |
2738 | | syntaxelement(general_product(Ids,P,E), [P,E|Ids],Ids,[Ids], [], expr). |
2739 | | syntaxelement(quantified_union(Ids,P,E), [P,E|Ids],Ids,[Ids], [], expr). |
2740 | | syntaxelement(quantified_intersection(Ids,P,E), [P,E|Ids],Ids,[Ids], [], expr). |
2741 | | syntaxelement(struct(Rec), [Rec], [], [], [], expr). |
2742 | | syntaxelement(rec(Fields), FContent, [], [FContent], FNames, expr) :- syntaxfields(Fields,FContent, FNames). |
2743 | | syntaxelement(record_field(R,I), [R], [], [], I, expr). |
2744 | | syntaxelement(assertion_expression(Cond,ErrMsg,Expr), [Cond,Expr], [], [], ErrMsg, expr). |
2745 | | syntaxelement(typeset, [], [], [], [], expr/only_typecheck). |
2746 | | |
2747 | | syntaxelement(tree(A), [A], [], [], [], expr). |
2748 | | syntaxelement(btree(A), [A], [], [], [], expr). |
2749 | | syntaxelement(const(A,B), [A,B],[], [], [], expr). |
2750 | | syntaxelement(top(A), [A], [], [], [], expr). |
2751 | | syntaxelement(sons(A), [A], [], [], [], expr). |
2752 | | syntaxelement(prefix(A), [A], [], [], [], expr). |
2753 | | syntaxelement(postfix(A), [A], [], [], [], expr). |
2754 | | syntaxelement(sizet(A), [A], [], [], [], expr). |
2755 | | syntaxelement(mirror(A), [A], [], [], [], expr). |
2756 | | syntaxelement(rank(A,B), [A,B],[], [], [], expr). |
2757 | | syntaxelement(father(A,B), [A,B],[], [], [], expr). |
2758 | | syntaxelement(son(A,B,C), [A,B,C],[], [], [], expr). |
2759 | | syntaxelement(subtree(A,B), [A,B],[], [], [], expr). |
2760 | | syntaxelement(arity(A,B), [A,B],[], [], [], expr). |
2761 | | syntaxelement(bin(A), [A],[], [], [], expr). |
2762 | | syntaxelement(bin(A,B,C), [A,B,C],[], [], [], expr). |
2763 | | syntaxelement(infix(A), [A], [], [], [], expr). |
2764 | | syntaxelement(left(A), [A], [], [], [], expr). |
2765 | | syntaxelement(right(A), [A], [], [], [], expr). |
2766 | | |
2767 | | % substitutions |
2768 | | syntaxelement(skip, [], [], [], [], subst). |
2769 | | syntaxelement(precondition(A,B), [A,B],[], [], [], subst). |
2770 | | syntaxelement(assertion(A,B), [A,B],[], [], [], subst). |
2771 | | syntaxelement(witness_then(A,B), [A,B],[], [], [], subst). |
2772 | | syntaxelement(if_elsif(A,B), [A,B],[], [], [], subst/elsif). |
2773 | | syntaxelement(while(A,B,C,D), [A,B,C,D],[], [], [], subst). |
2774 | | % used only internally in the interpreter, contains last value of variant: |
2775 | | syntaxelement(while1(A,B,C,D,E), [A,B,C,D],[], [], E, subst). |
2776 | | syntaxelement(select_when(A,B), [A,B],[], [], [], subst/when). |
2777 | | syntaxelement(block(S),[S],[],[],[], subst/only_typecheck). |
2778 | | syntaxelement(assign(Lhs,Rhs),Exprs,[],[Lhs,Rhs], [], subst) :- append(Lhs,Rhs,Exprs). |
2779 | | syntaxelement(assign_single_id(Id,Rhs),[Id,Rhs],[],[], [], subst). |
2780 | | syntaxelement(any(Ids,P,S),[P,S|Ids],Ids,[Ids], [], subst). |
2781 | | syntaxelement(var(Ids,S), [S|Ids], Ids,[Ids], [], subst). |
2782 | | syntaxelement(if(Ifs), Ifs, [], [Ifs], [], subst). |
2783 | | syntaxelement(parallel(Ss), Ss, [], [Ss], [], subst). |
2784 | | syntaxelement(sequence(Ss), Ss, [], [Ss], [], subst). |
2785 | | syntaxelement(becomes_element_of(Ids,E), [E|Ids], [], [Ids], [], subst). |
2786 | | syntaxelement(becomes_such(Ids,P), [P|Ids], [], [Ids], [], subst). % Ids are new value, Ids$0 is old value |
2787 | | syntaxelement(evb2_becomes_such(Ids,P), [P|Ids], [], [Ids], [], subst/only_typecheck). |
2788 | | syntaxelement(let(Ids,P,S), [P,S|Ids], Ids, [Ids], [], subst). |
2789 | | syntaxelement(operation_call(Id,Rs,As), [Id|Exprs], [], [Rs,As], [], subst) :- append(Rs,As,Exprs). |
2790 | | syntaxelement(case(E,Eithers,Else), [E,Else|Eithers], [], [Eithers], [], subst). |
2791 | | syntaxelement(case_or(Es,S), [S|Es], [], [Es], [], subst/caseor). |
2792 | | syntaxelement(choice(Ss), Ss, [], [Ss], [], subst). |
2793 | | syntaxelement(select(Whens), Whens, [], [Whens], [], subst). |
2794 | | syntaxelement(select(Whens,Else), [Else|Whens], [], [Whens], [], subst). |
2795 | | syntaxelement(operation(I,Rs,As,B), [I,B|Ids], Ids, [Rs,As], [], subst) :- append(Rs,As,Ids). |
2796 | | syntaxelement(external_subst_call(F,Args),Args,[],[Args],F,subst). |
2797 | | |
2798 | | % elements of a VALUES clause |
2799 | | syntaxelement(values_entry(I,E),[I,E],[],[],[],values_entry). |
2800 | | |
2801 | | % syntax for Event-B events |
2802 | | syntaxelement(rlevent(I,Sec,St,Ps,G,Ts,As,VWs,PWs,Ums,Rs), Subs, [], [Ps,Ts,As,VWs,PWs,Ums,Rs], [I,Sec], subst) :- |
2803 | | append([[St],Ps,[G],Ts,As,VWs,PWs,Ums,Rs],Subs). |
2804 | | syntaxelement(witness(I,P), [I,P], [], [], [], witness). |
2805 | | |
2806 | | % extended syntax for Z |
2807 | | syntaxelement(let_predicate(Ids,As,Pred), Exprs, Ids, [Ids,As], [], pred) :- append([Ids,As,[Pred]],Exprs). |
2808 | | syntaxelement(let_expression(Ids,As,Expr), Exprs, Ids, [Ids,As], [], expr) :- append([Ids,As,[Expr]],Exprs). |
2809 | | syntaxelement(let_expression_global(Ids,As,Expr), Exprs, Ids, [Ids,As], [], expr) :- % version used by b_compiler |
2810 | | append([Ids,As,[Expr]],Exprs). |
2811 | | syntaxelement(lazy_let_expr(TID,A,Expr), [TID, A, Expr], [TID], [[TID],[A]], [], expr). |
2812 | | syntaxelement(lazy_let_pred(TID,A,Expr), [TID, A, Expr], [TID], [[TID],[A]], [], pred). |
2813 | | syntaxelement(lazy_let_subst(TID,A,Expr), [TID, A, Expr], [TID], [[TID],[A]], [], subst). |
2814 | | syntaxelement(if_then_else(If,Then,Else),[If,Then,Else], [], [], [], expr). |
2815 | | syntaxelement(compaction(A), [A], [], [], [], expr). |
2816 | | syntaxelement(mu(A), [A], [], [], [], expr). |
2817 | | syntaxelement(bag_items(A), [A], [], [], [], expr). |
2818 | | |
2819 | | syntaxelement(freetype_set(Id), [], [], [], Id, expr). |
2820 | | syntaxelement(freetype_case(Type,Case,Expr), [Expr], [], [], [Type,Case], pred). |
2821 | | syntaxelement(freetype_constructor(Type,Case,Expr), [Expr], [], [], [Type,Case], expr). |
2822 | | syntaxelement(freetype_destructor(Type,Case,Expr), [Expr], [], [], [Type,Case], expr). |
2823 | | |
2824 | | syntaxelement(ordinary, [], [], [], [], status). |
2825 | | syntaxelement(anticipated(Variant), [Variant], [], [], [], status). |
2826 | | syntaxelement(convergent(Variant), [Variant], [], [], [], status). |
2827 | | |
2828 | | % Just one ID expected |
2829 | | syntaxelement(recursive_let(Id,C),[Id,C],[Id],[],[], expr). % Note: Id is not really introduced ! |
2830 | | |
2831 | | |
2832 | | % fields of records |
2833 | | %syntaxfields(Fields,C,_) :- var(Fields),var(C),var(N),!, add_internal_error('Illegal call: ',syntaxfields(Fields,C,N)),fail. |
2834 | | syntaxfields([],[],[]). |
2835 | | syntaxfields([field(N,C)|Rest],[C|CRest],[N|NRest]) :- syntaxfields(Rest,CRest,NRest). |
2836 | | |
2837 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
2838 | | % helper for declaration of quantified identifiers |
2839 | | |
2840 | | % has_declared_identifier/2 returns a list of identifiers which are declared in |
2841 | | % this AST node. The main difference to the Names variable when doing a |
2842 | | % syntaxtraversion/6 or similiar is that the identifiers are described by |
2843 | | % predicates. |
2844 | | has_declared_identifier(TExpr,Ids) :- |
2845 | | get_texpr_expr(TExpr,Expr), |
2846 | | ( default_declaration(Expr,_,Ids,_) |
2847 | | ; non_default_declaration(Expr,Ids)). |
2848 | | |
2849 | | add_declaration_for_identifier(b(Expr,Type,Infos),Decl,b(NExpr,Type,NewInfos)) :- |
2850 | | %delete(Infos,used_ids(_),NewInfos), % we cannot |
2851 | | ( default_declaration(Expr,Predicate,Ids,Constant) -> |
2852 | | same_functor(Expr,NExpr), |
2853 | | conjunct_predicates([Decl,Predicate],NPredicate), |
2854 | | default_declaration(NExpr,NPredicate,Ids,Constant) |
2855 | | ; non_default_declaration(Expr,Ids) -> |
2856 | | add_non_default_declaration(Expr,Decl,NExpr) |
2857 | | ), |
2858 | | add_used_ids(Infos,Ids,Decl,NewInfos). |
2859 | | |
2860 | | % add used ids of a predicate within quantification of Ids to current used_ids info; if it is there |
2861 | | add_used_ids(Infos,Ids,Pred,NewInfos) :- update_used_ids(Infos,OldUsed,NewInfos,NewUsed), |
2862 | | !, % a field needs updating |
2863 | | find_identifier_uses(Pred,[],NewIds), get_texpr_ids(Ids,UnsortedIds),sort(UnsortedIds,SIds), |
2864 | | ord_subtract(NewIds,SIds,NewIds2), |
2865 | | ord_union(NewIds2,OldUsed,NewUsed). |
2866 | | add_used_ids(I,_,_,I). |
2867 | | |
2868 | | % just update used_ids field (e.g., when just computed to store it for later) |
2869 | | update_used_ids(Infos,OldUsed,NewInfos,NewUsed) :- select(OldInfo,Infos,I1), |
2870 | | used_ids_like_info(OldInfo,F,OldUsed),!, |
2871 | | used_ids_like_info(NewInfo,F,NewUsed),NewInfos = [NewInfo|I1]. |
2872 | | |
2873 | | % info fields which contain used_ids information |
2874 | | used_ids_like_info(used_ids(UsedIds),used_ids,UsedIds). |
2875 | | used_ids_like_info(reads(UsedIds),reads,UsedIds). |
2876 | | |
2877 | | :- use_module(probsrc(btypechecker), [prime_identifiers/2]). |
2878 | | |
2879 | | % default_declaration(Expr,Predicate,Ids,Constant) |
2880 | | default_declaration(forall(Ids,D,P),D,Ids,P). |
2881 | | default_declaration(exists(Ids,P),P,Ids,[]). |
2882 | | default_declaration(comprehension_set(Ids,P),P,Ids,[]). |
2883 | | default_declaration(event_b_comprehension_set(Ids,E,P),P,Ids,E). % translated !? |
2884 | | default_declaration(lambda(Ids,P,E),P,Ids,E). |
2885 | | default_declaration(general_sum(Ids,P,E),P,Ids,E). |
2886 | | default_declaration(general_product(Ids,P,E),P,Ids,E). |
2887 | | default_declaration(quantified_union(Ids,P,E),P,Ids,E). |
2888 | | default_declaration(quantified_intersection(Ids,P,E),P,Ids,E). |
2889 | | default_declaration(any(Ids,P,S),P,Ids,S). |
2890 | | default_declaration(becomes_such(Ids,P),P,Ids,[]). |
2891 | | default_declaration(evb2_becomes_such(Ids,P),P,Primed,[]) :- |
2892 | | nl,print(evb2(Ids,Primed)),nl,nl, % no longer used, as it is translated to becomes_such |
2893 | | prime_identifiers(Ids,Primed). |
2894 | | default_declaration(rlevent(I,Sec,St,Ps,G,Ts,As,VWs,PWs,Ums,Rs),G,Ps, |
2895 | | [I,Sec,St,Ps,Ts,As,VWs,PWs,Ums,Rs]). |
2896 | | default_declaration(let_predicate(Ids,Ps,Body),Ps,Ids,Body) :- print(let(Ids)),nl. % TODO: check format of Ps |
2897 | | default_declaration(let_expression(Ids,Ps,Body),Ps,Ids,Body) :- print(let(Ids)),nl. % TODO: check format of Ps |
2898 | | default_declaration(let_expression_global(Ids,Ps,Body),Ps,Ids,Body) :- print(let(Ids)),nl. % TODO: check format of Ps |
2899 | | % TODO: lazy let ? |
2900 | | |
2901 | | non_default_declaration(operation(_I,Rs,As,_TBody),Ids) :- |
2902 | | append(Rs,As,Ids). |
2903 | | |
2904 | | add_non_default_declaration(operation(I,Rs,As,TBody),Decl,operation(I,Rs,As,NTBody)) :- |
2905 | | ( get_guard_and_copy(TBody,P,NP,NTBody) -> |
2906 | | conjunct_predicates([Decl,P],NP) |
2907 | | ; create_texpr(precondition(Decl,TBody),subst,[],NTBody)). |
2908 | | |
2909 | | get_guard_and_copy(TBody,P,NP,NTBody) :- remove_bt(TBody,Body,NBody,NTBody), |
2910 | | get_guard_copy2(Body,P,NP,NBody). |
2911 | | |
2912 | | get_guard_copy2(precondition(P,S),P,NP,precondition(NP,S)). |
2913 | | get_guard_copy2(rlevent(I,Sec,St,Ps, G,Ts,As,VWs,PWs,Ums,Rs), G, NG, |
2914 | | rlevent(I,Sec,St,Ps,NG,Ts,As,VWs,PWs,Ums,Rs)). |
2915 | | |
2916 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
2917 | | % pattern definitions (not yet finished) |
2918 | | |
2919 | | bsyntax_pattern(Expr,TExpr) :- |
2920 | | var(Expr),!,Expr=TExpr. |
2921 | | bsyntax_pattern(-Expr,TExpr) :- |
2922 | | !,remove_all_infos(Expr,TExpr). |
2923 | | bsyntax_pattern(Expr,TExpr) :- |
2924 | | functor(Expr,b,3),!,Expr=TExpr. |
2925 | | bsyntax_pattern(Expr:Type/Info,TExpr) :- |
2926 | | !,bsyntax_pattern2(Expr,Type,Info,TExpr). |
2927 | | bsyntax_pattern(Expr:Type,TExpr) :- |
2928 | | !,bsyntax_pattern2(Expr,Type,_Info,TExpr). |
2929 | | bsyntax_pattern(Expr/Info,TExpr) :- |
2930 | | !,bsyntax_pattern2(Expr,_Type,Info,TExpr). |
2931 | | bsyntax_pattern(Expr,TExpr) :- |
2932 | | !,bsyntax_pattern2(Expr,_Type,_Info,TExpr). |
2933 | | |
2934 | | bsyntax_pattern2(Pattern,Type,Info,TExpr) :- |
2935 | | functor(Pattern,Functor,Arity), |
2936 | | functor(R,Functor,Arity), |
2937 | | create_texpr(R,Type,Info,TExpr), |
2938 | | syntaxelement(Pattern,PSubs,_,PLists,Const,EType), |
2939 | | syntaxelement(R,RSubs,_,RLists,Const,EType), |
2940 | | ( EType==pred -> Type=pred |
2941 | | ; EType==subst -> Type=subst |
2942 | | ; true), |
2943 | | all_same_length(PLists,RLists), |
2944 | | maplist(bsyntax_pattern,PSubs,RSubs). |
2945 | | |
2946 | | all_same_length([],[]). |
2947 | | all_same_length([A|Arest],[B|Brest]) :- |
2948 | | ( var(A),var(B) -> |
2949 | | add_error_fail(bsyntaxtree,'At least one list should contain nonvar elements for all_same_length',[A,B]) |
2950 | | ; |
2951 | | same_length(A,B)), |
2952 | | all_same_length(Arest,Brest). |
2953 | | |
2954 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
2955 | | % strip an AST into a more compact form (without b/3 terms) |
2956 | | |
2957 | | strip_and_norm_ast(TExpr,SNExpr) :- |
2958 | | get_texpr_expr(TExpr,Expr), |
2959 | | strip_and_norm_ast_aux(Expr,SNExpr). |
2960 | | |
2961 | | :- use_module(tools,[safe_univ_no_cutoff/2]). |
2962 | | strip_and_norm_ast_aux(Expr,Res) :- |
2963 | | comm_assoc_subs(Expr,Op,Subs,[]), !, % associative & commutative operator detected |
2964 | | maplist(strip_and_norm_ast_aux,Subs,NSubs), % Subs are already unwrapped |
2965 | | sort(NSubs,Sorted), % in case there are associative operators that are not commutative: insert is_commutative check |
2966 | | safe_univ_no_cutoff(Res,[Op|Sorted]). |
2967 | | strip_and_norm_ast_aux(Expr,Res) :- |
2968 | | assoc_subs(Expr,Op,Subs,[]), !, % associative operator detected |
2969 | | maplist(strip_and_norm_ast_aux,Subs,NSubs), % Subs are already unwrapped |
2970 | | safe_univ_no_cutoff(Res,[Op|NSubs]). |
2971 | | strip_and_norm_ast_aux(Expr,SNExpr) :- |
2972 | | syntaxtransformation(Expr,Subs,_,NSubs,SExpr), |
2973 | | strip_and_norm_ast_l(Subs,NSubs), |
2974 | | norm_strip(SExpr,SNExpr). |
2975 | | |
2976 | | strip_and_norm_ast_l([],[]). |
2977 | | strip_and_norm_ast_l([TExpr|Trest],[NExpr|Nrest]) :- |
2978 | | strip_and_norm_ast(TExpr,NExpr), |
2979 | | strip_and_norm_ast_l(Trest,Nrest). |
2980 | | |
2981 | | norm_strip(greater_equal(A,B),less_equal(B,A)) :- !. |
2982 | | norm_strip(greater(A,B),less(B,A)) :- !. |
2983 | | norm_strip(set_extension(NL),set_extension(SNL)) :- !, |
2984 | | sort(NL,SNL). |
2985 | | norm_strip(Old,New) :- |
2986 | | functor(Old,Functor,2), |
2987 | | is_commutative(Functor),!, |
2988 | | arg(1,Old,OA), |
2989 | | arg(2,Old,OB), |
2990 | | ( OA @> OB -> New =.. [Functor,OB,OA] |
2991 | | ; New=Old). |
2992 | | norm_strip(Old,Old). |
2993 | | % TO DO: flatten associative operators into lists ! |
2994 | | |
2995 | | comm_assoc_subs(conjunct(TA,TB),conjunct) --> !, |
2996 | | {get_texpr_expr(TA,A), get_texpr_expr(TB,B)}, |
2997 | | comm_assoc_subs(A,conjunct), comm_assoc_subs(B,conjunct). |
2998 | | comm_assoc_subs(disjunct(TA,TB),disjunct) --> !, |
2999 | | {get_texpr_expr(TA,A), get_texpr_expr(TB,B)}, |
3000 | | comm_assoc_subs(A,disjunct), comm_assoc_subs(B,disjunct). |
3001 | | comm_assoc_subs(add(TA,TB),add) --> !, |
3002 | | {get_texpr_expr(TA,A), get_texpr_expr(TB,B)}, |
3003 | | comm_assoc_subs(A,add), comm_assoc_subs(B,add). |
3004 | | comm_assoc_subs(multiplication(TA,TB),multiplication) --> !, |
3005 | | {get_texpr_expr(TA,A), get_texpr_expr(TB,B)}, |
3006 | | comm_assoc_subs(A,multiplication), comm_assoc_subs(B,multiplication). |
3007 | | comm_assoc_subs(union(TA,TB),union) --> !, |
3008 | | {get_texpr_expr(TA,A), get_texpr_expr(TB,B)}, |
3009 | | comm_assoc_subs(A,union), comm_assoc_subs(B,union). |
3010 | | comm_assoc_subs(intersection(TA,TB),intersection) --> !, |
3011 | | {get_texpr_expr(TA,A), get_texpr_expr(TB,B)}, |
3012 | | comm_assoc_subs(A,intersection), comm_assoc_subs(B,intersection). |
3013 | | comm_assoc_subs(Expr,Op) --> {nonvar(Op)},[Expr]. % base case for other operators |
3014 | | |
3015 | | % detect just associative operators |
3016 | | assoc_subs(concat(TA,TB),concat) --> !, |
3017 | | {get_texpr_expr(TA,A), get_texpr_expr(TB,B)}, |
3018 | | assoc_subs(A,concat), assoc_subs(B,concat). |
3019 | | assoc_subs(composition(TA,TB),composition) --> !, |
3020 | | {get_texpr_expr(TA,A), get_texpr_expr(TB,B)}, |
3021 | | assoc_subs(A,composition), assoc_subs(B,composition). |
3022 | | assoc_subs(Expr,Op) --> {nonvar(Op)},[Expr]. % base case for other operators |
3023 | | |
3024 | | is_commutative(conjunct). |
3025 | | is_commutative(disjunct). |
3026 | | is_commutative(equivalence). |
3027 | | is_commutative(equal). |
3028 | | is_commutative(not_equal). |
3029 | | is_commutative(add). |
3030 | | is_commutative(multiplication). |
3031 | | is_commutative(union). |
3032 | | is_commutative(intersection). |
3033 | | |
3034 | | % check if two type expressions are same modulo info fields and reordering of commutative operators |
3035 | | % same_texpr does not reorder wrt commutativity. |
3036 | | same_norm_texpr(TExpr1,TExpr2) :- |
3037 | | strip_and_norm_ast(TExpr1,N1), |
3038 | | strip_and_norm_ast(TExpr2,N1). |
3039 | | |
3040 | | |
3041 | | % small utility to get functor of texpr: |
3042 | | get_texpr_functor(b(E,_,_),F,N) :- !, functor(E,F,N). |
3043 | | get_texpr_functor(E,_,+) :- add_error_fail(get_texpr_functor,'Not a typed expression: ',E). |
3044 | | |
3045 | | % ------------------------- |
3046 | | |
3047 | | % check if a ProB type is a set type: |
3048 | | is_set_type(set(Type),Type). |
3049 | | is_set_type(seq(Type),couple(integer,Type)). |
3050 | | % should we have a rule for any ?? : in all cases using is_set_type any seems not possible; better that we generate error message in get_set_type or get_texpr_set_type |
3051 | | % is_set_type(any,any). |
3052 | | |
3053 | | get_set_type(TypeX,Res) :- |
3054 | ? | (is_set_type(TypeX,SetType) -> Res=SetType ; add_error_fail(get_set_type,'Not a set type: ',TypeX)). |
3055 | | |
3056 | | get_texpr_set_type(X,Res) :- get_texpr_type(X,TypeX), |
3057 | | get_set_type(TypeX,Res). |
3058 | | |
3059 | | |
3060 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
3061 | | % check if a set contains all elements of a type, i.e., maximal type |
3062 | | is_just_type(Expr) :- is_just_type(Expr,[]). |
3063 | | % is_just_type(+Expr,+RTT): |
3064 | | % like is_just_type/1 but RTT is a list of identifiers (without type information) |
3065 | | % of variables or constants that are known to be types, too. |
3066 | | % E.g. is_just_type(a ** INTEGER) would fail but is_just_type(a ** INTEGER,[a]) would |
3067 | | % succeed. |
3068 | | is_just_type(b(E,T,I),RTT) :- is_just_type3(E,T,I,RTT). |
3069 | | |
3070 | | |
3071 | | is_just_type3(identifier(G),set(Type),Infos,RefsToTypes) :- |
3072 | | ( Type = global(G), |
3073 | | memberchk(given_set,Infos) % no accidental local variable G that hides global G |
3074 | | ; memberchk(G,RefsToTypes) -> true |
3075 | | %; Type = freetype(G), |
3076 | | % memberchk(given_set,Infos) % no accidental local variable G that hides global G |
3077 | | % TODO: we do not know if the Freetype has restrictions (which are encoded in the PROPERTIES) |
3078 | | ),!. |
3079 | | is_just_type3(freetype_set(_),_,_,_). |
3080 | | is_just_type3(pow_subset(E),_,_,RTT) :- is_just_type(E,RTT). |
3081 | | is_just_type3(fin_subset(E),T,_,RTT) :- |
3082 | | is_finite_type_in_context(proving,T), % animation or proving |
3083 | | is_just_type(E,RTT). |
3084 | | is_just_type3(integer_set('INTEGER'),set(integer),_,_). |
3085 | | is_just_type3(bool_set,set(boolean),_,_). |
3086 | | is_just_type3(real_set,set(real),_,_). |
3087 | | is_just_type3(string_set,set(string),_,_). |
3088 | | is_just_type3(cartesian_product(A,B),_,_,RTT) :- |
3089 | | is_just_type(A,RTT),is_just_type(B,RTT). |
3090 | | is_just_type3(mult_or_cart(A,B),_,_,RTT) :- % is_just_type/1 could be called before the cleanup |
3091 | | is_just_type(A,RTT),is_just_type(B,RTT). % of an expression has finished |
3092 | | is_just_type3(relations(A,B),_,_,RTT) :- |
3093 | | is_just_type(A,RTT),is_just_type(B,RTT). |
3094 | | is_just_type3(struct(b(rec(Fields),_,_)),_,_,RTT) :- |
3095 | | maplist(field_is_just_type(RTT),Fields). |
3096 | | is_just_type3(typeset,_,_,_). |
3097 | | is_just_type3(comprehension_set(_,b(truth,_,_)),_,_,_). |
3098 | | is_just_type3(value(Val),ST,_,_) :- is_set_type(ST,Type), is_maximal_value(Val,Type). % also see: quick_is_definitely_maximal_set(Val). |
3099 | | |
3100 | | field_is_just_type(RTT,field(_,Set)) :- is_just_type(Set,RTT). |
3101 | | |
3102 | | is_maximal_value(V,_) :- var(V),!,fail. |
3103 | | is_maximal_value(global_set(GS),Type) :- (GS=='INTEGER' -> true ; Type==global(GS)). % we could call is_maximal_global_set(GS) or b_global_set (but requires compiled) |
3104 | | |
3105 | | % Generate a custom matching / visitor predicate |
3106 | | % bsyntaxtree:gen_visitor(bexpr_variables_aux,bexpr_variables) |
3107 | | /* |
3108 | | gen_visitor(Pred, BodyPred) :- syntaxelement(Expr,SubsX,_NamesX,_Lists,_ConstantX,_), |
3109 | | print_clause(Pred,BodyPred,Expr,SubsX), |
3110 | | fail. |
3111 | | gen_visitor(Pred, BodyPred) :- nl. |
3112 | | |
3113 | | print_clause(Pred,BodyPred,Expr,SubsX) :- E=..[Op|SubsX], format('~w(~w) :- ',[Pred,Expr]). |
3114 | | */ |
3115 | | |
3116 | | /* |
3117 | | * create_recursive_compset(+Ids,+Cond,+Type,+Infos,-RecId,-TCompSet) |
3118 | | * creates a recursive comprehension set: |
3119 | | * Ids is the list of the introduced typed identifiers |
3120 | | * Cond is the condition (a typed predicate) |
3121 | | * Infos are additional informations for the comprehension set syntax element |
3122 | | * RecId is the identifier (untyped, an atom) that can be used in Cond to refer to the |
3123 | | * comprehension set recursively. Usually RecId is used in Cond as a variable |
3124 | | * TCompSet is the generated recursive comprehension set, the recursion parameter is introduced |
3125 | | * by a recusive(Id,CompSet) syntax element |
3126 | | */ |
3127 | | create_recursive_compset(Ids,Cond,Type,Infos,RecId,TCompSet) :- |
3128 | | unique_id("recursive.",RecId), |
3129 | | add_symbolic_annotation(Infos,RInfos), |
3130 | | create_texpr(comprehension_set(Ids,Cond),Type,RInfos,TCompSet1), |
3131 | | create_typed_id(RecId,Type,TRecId), |
3132 | | create_texpr(recursive_let(TRecId,TCompSet1),Type,[],TCompSet). |
3133 | | |
3134 | | unique_typed_id(Prefix,Type,TId) :- |
3135 | | unique_id(Prefix,Id), |
3136 | | create_typed_id(Id,Type,TId). |
3137 | | |
3138 | | |
3139 | | mark_bexpr_as_symbolic(b(E,T,I),b(E2,T,RI)) :- |
3140 | | add_symbolic_annotation(I,RI), |
3141 | | mark_aux(E,E2). |
3142 | | mark_aux(union(A,B),R) :- !, R=union(SA,SB), |
3143 | | mark_bexpr_as_symbolic(A,SA), mark_bexpr_as_symbolic(B,SB). |
3144 | | % union is currently the only operator that is kept symbolically |
3145 | | mark_aux(A,A). |
3146 | | |
3147 | | add_symbolic_annotation([H|I],R) :- H == prob_annotation('SYMBOLIC'),!, R=[H|I]. |
3148 | | add_symbolic_annotation(I,R) :- !, R=[prob_annotation('SYMBOLIC')|I]. |
3149 | | |
3150 | | % identifier_sub_ast(+TExpr,+Identifier,-SubPosition): |
3151 | | % Find occurences of an identifier "Identifier" in an expression "TExpr" |
3152 | | % Returns a list of positions (beginning with 0) that describes the position of a sub-expression |
3153 | | % that contains all occurrences of Identifier in TExpr. |
3154 | | % E.g. [1,0,1] means "second sub-expression of TExpr, then the first sub-expression of that, |
3155 | | % then the second sub-expression of that". |
3156 | | % When an identifier has multiple occurences, the position of the sub-expression is returned |
3157 | | % where all occurences of it are located. |
3158 | | % If the identifier is not found, the call fails. |
3159 | | % Sub-expressions are meant like the ones syntaxtraversion or syntaxtransformation return. |
3160 | | identifier_sub_ast(TExpr,Identifier,SubPosition) :- |
3161 | | syntaxtraversion(TExpr,Expr,_Type,_Infos,AllSubs,Names), |
3162 | | identifier_sub_ast_aux(Expr,AllSubs,Names,Identifier,SubPosition). |
3163 | | identifier_sub_ast_aux(identifier(Identifier),[],[],Identifier,[]) :- !. |
3164 | | identifier_sub_ast_aux(_Expr,AllSubs,Names,Identifier,SubPosition) :- |
3165 | | get_texpr_id(TId,Identifier),nonmember(TId,Names), |
3166 | | % For each sub-expression E in the list AllSubs create a term Pos-E |
3167 | | % where Pos is E's position (starting with 0) in AllSubs |
3168 | | foldl(annotate_pos,AllSubs,AllAnnotatedSubs,0,_), |
3169 | | % Introduced identifiers occur alsa as sub-expressions, remove those |
3170 | | foldl(select_sub,Names,AllAnnotatedSubs,RealAnnSubs), |
3171 | | convlist_max(identifier_sub_ast_aux2(Identifier),2,RealAnnSubs,SubPositions), % find at most 2 sols |
3172 | | ( SubPositions = [SubPosition] -> true |
3173 | | ; SubPositions = [_,_|_] -> % More then one occurrences - make this the found node |
3174 | | SubPosition = []). |
3175 | | identifier_sub_ast_aux2(Identifier,Pos-TExpr,[Pos|SubPosition]) :- |
3176 | | identifier_sub_ast(TExpr,Identifier,SubPosition). |
3177 | | annotate_pos(TExpr,I-TExpr,I,I2) :- I2 is I+1. |
3178 | | select_sub(Name,AnnotatedSubs,Result) :- |
3179 | | selectchk(_Pos-Name,AnnotatedSubs,Result). |
3180 | | |
3181 | | |
3182 | | |
3183 | | % exchange_ast_position(+SubPosition,+OldTExpr,-OldInner,+NewInner,-NewTExpr): |
3184 | | % exchanges a sub-expression in the expression "OldTExpr". |
3185 | | % SubPosition is a list of positions like identifier_sub_ast/3 returns it. |
3186 | | % OldInner is the sub-expression found in OldTExpr. |
3187 | | % NewInner is the new sub-expression. |
3188 | | % NewTExpr is the new expression that originates from replacing OldInner by NewInner. |
3189 | | exchange_ast_position([],Old,Old,New,New). |
3190 | | exchange_ast_position([Pos|RestPos],OldTExpr,OldInner,NewInner,NewTExpr) :- |
3191 | | remove_bt_and_used_ids(OldTExpr,OldExpr,NewExpr,NewTExpr), % also invalidates used_ids info |
3192 | | syntaxtransformation(OldExpr,Subs,_Names,NSubs,NewExpr), |
3193 | | nth0(Pos,Subs, OldSelected,Rest), |
3194 | | nth0(Pos,NSubs,NewSelected,Rest), |
3195 | | exchange_ast_position(RestPos,OldSelected,OldInner,NewInner,NewSelected). |
3196 | | |
3197 | | |
3198 | | % ----------------------- |
3199 | | % utility to expand / inline all let expressions and let predicates: |
3200 | | % useful for tools that cannot handle the lets |
3201 | | |
3202 | | expand_all_lets(Expr,NewExpr) :- |
3203 | | transform_bexpr(tl_expand_lets,Expr,NewExpr). |
3204 | | |
3205 | | tl_expand_lets(b(E,_,_),Res) :- tl_expand_lets2(E,Res). |
3206 | | tl_expand_lets2(let_expression(Ids,Exprs,Body),NewBody) :- % expand LET expression |
3207 | | replace_ids_by_exprs(Body,Ids,Exprs,NewBody). |
3208 | | tl_expand_lets2(let_predicate(Ids,Exprs,Body),NewBody) :- % expand LET predicate |
3209 | | replace_ids_by_exprs(Body,Ids,Exprs,NewBody). |
3210 | | |
3211 | | % ----------------------- |
3212 | | |
3213 | | :- public check_used_ids/2. |
3214 | | % a simple checker, only checks used_ids info fields for entire typed expression: |
3215 | | check_used_ids(TExpr,PP) :- %format('CHECK AST for ~w~n',[PP]), |
3216 | | map_over_typed_bexpr(check_used_ids_texpr_fail(PP),TExpr). |
3217 | | check_used_ids(_,_). |
3218 | | check_used_ids_texpr_fail(PP,E) :- check_used_ids_texpr(PP,E),!,fail. |
3219 | | check_used_ids_texpr(PP,b(P,T,I)) :- member(used_ids(UIds1),I),!, |
3220 | | (find_identifier_uses(b(P,T,I),[],UIds2) -> true |
3221 | | ; add_internal_error('find_identifier_uses failed',PP),fail), |
3222 | | (UIds1==UIds2 -> true |
3223 | | ; format('*** Wrong used_ids Info (~w)!!~n Used_ids: ~w~n Comp_ids: ~w~n',[PP,UIds1,UIds2]), |
3224 | | translate:print_bexpr(b(P,T,I)),nl, |
3225 | | add_error(check_used_ids,'Wrong used_ids: ',PP,I) |
3226 | | ). |
3227 | | check_used_ids_texpr(_,_). |
3228 | | |
3229 | | % repair any broken used_ids info in typed expression TExpr and re-compute used_ids if necessary |
3230 | | % PP is a program point, will be reported in case of an error |
3231 | | repair_used_ids(PP,TExpr,Res) :- |
3232 | | (transform_bexpr(bsyntaxtree:repair_used_ids_info(PP),TExpr,NewTExpr) -> Res=NewTExpr |
3233 | | ; add_internal_error('Repairing used_ids failed:',PP), |
3234 | | Res=TExpr). |
3235 | | |
3236 | | % we could also simply call recompute_used_ids_inf; but it would not generate any messages |
3237 | | repair_used_ids_info(PP,b(P,T,I),b(P,T,NI)) :- %functor(P,FF,_), print(repair(FF)),nl, |
3238 | | select(used_ids(OldUsed),I,I2),!, |
3239 | | (find_identifier_uses(b(P,T,I),[],NewUsed) |
3240 | | -> (NewUsed=OldUsed -> NI=I |
3241 | | ; NI = [used_ids(NewUsed)|I2], |
3242 | | add_message(repair_used_ids,'Updating used_ids for: ',b(P,T,I),I2) |
3243 | | ) |
3244 | | ; add_internal_error('find_identifier_uses failed',PP), |
3245 | | NI=I |
3246 | | ). |
3247 | | repair_used_ids_info(PP,b(P,T,I),b(P,T,NI)) :- |
3248 | | requires_used_ids(P), |
3249 | | (find_identifier_uses(b(P,T,I),[],NewUsed) -> true |
3250 | | ; add_internal_error('find_identifier_uses failed',PP),fail |
3251 | | ), |
3252 | | !, |
3253 | | NI=[used_ids(NewUsed)|I]. |
3254 | | repair_used_ids_info(_,B,B). |
3255 | | |
3256 | | requires_used_ids(exists(_,_)). |
3257 | | requires_used_ids(forall(_,_,_)). |
3258 | | |
3259 | | % a simple checker to see if an AST is well-formed: |
3260 | | % can be tested e.g. as follows: b_get_invariant_from_machine(I), check_ast(I). |
3261 | | % called in prob_safe_mode by clean_up_section |
3262 | | |
3263 | | check_ast(TE) :- check_ast(false,TE). |
3264 | | check_ast(AllowVars,TExpr) :- %nl,print('CHECK AST'),nl, |
3265 | | map_over_typed_bexpr(check_ast_texpr(AllowVars),TExpr). |
3266 | | check_ast(_,_). |
3267 | | |
3268 | | :- use_module(typing_tools,[valid_ground_type/1]). |
3269 | | %check_ast_texpr(X) :- print(check(X)),nl,fail. |
3270 | | check_ast_texpr(AllowVars,AST) :- AST = b(E,Type,Infos), |
3271 | | (debug:debug_level_active_for(9) -> write(' check_ast: '),print_bexpr(AST), write(' :: '), write(Type), nl ; true), |
3272 | | (check_expr(E,Type,Infos) -> true |
3273 | | ; add_error(check_ast_texpr,'Invalid Expr: ', AST) %, trace, check_expr(E,Type,Infos) |
3274 | | ), |
3275 | | (check_type(Type,AllowVars) -> true |
3276 | | ; add_error(check_ast_texpr,'Invalid Type for: ',AST,Infos)), |
3277 | | safe_functor(E,F), |
3278 | | check_ast_typing(E,Type,Infos), |
3279 | | (check_infos(Infos,F) -> true ; add_error(check_ast_texpr,'Invalid Infos: ',AST)), |
3280 | | check_special_rules(E,Type,Infos), |
3281 | | fail. % to force backtracking in map_over_typed_bexpr |
3282 | | |
3283 | | |
3284 | | check_special_rules(operation_call_in_expr(Operation,_),_,OInfos) :- !, |
3285 | | get_texpr_info(Operation,Info), % reads info important for used_ids computation |
3286 | | (memberchk(reads(_V),Info) -> true |
3287 | | ; add_error(check_ast_texpr,'Missing reads info: ',Operation,OInfos)). |
3288 | | |
3289 | | |
3290 | | safe_functor(V,R) :- var(V),!,R='$VAR'. |
3291 | | safe_functor(E,F/N) :- functor(E,F,N). |
3292 | | |
3293 | | % check whether the type term is ok |
3294 | | check_type(X,AllowVars) :- var(X),!, |
3295 | | (AllowVars==true -> true ; add_error(check_type,'Variable type: ',X),fail). |
3296 | | check_type(pred,_) :- !. |
3297 | | check_type(subst,_) :- !. |
3298 | | check_type(op(Paras,Returns),AllowVars) :- !, |
3299 | | maplist(check_normal_type(AllowVars),Paras), |
3300 | | maplist(check_normal_type(AllowVars),Returns). |
3301 | | check_type(T,AllowVars) :- check_normal_type(AllowVars,T). |
3302 | | |
3303 | | check_normal_type(AllowVars,T) :- |
3304 | | (AllowVars \== true -> valid_ground_type(T) |
3305 | | ; ground(T) -> valid_ground_type(T) |
3306 | | ; true). % TO DO: call valid_ground_type but pass AllowVars |
3307 | | |
3308 | | :- use_module(probsrc(btypechecker), [lookup_type_for_expr/2, unify_types_werrors/4]). |
3309 | | % check whether type is compatible with operators |
3310 | | check_ast_typing(member(A,B),Type,Pos) :- !, |
3311 | | get_texpr_type(B,TB), check_set_type(TB,member,Pos), |
3312 | | check_type(Type,pred,member), |
3313 | | get_texpr_type(A,TA), |
3314 | | unify_types_werrors(set(TA),TB,Pos,member). |
3315 | | check_ast_typing(not_equal(A,B),Type,Pos) :- !, check_ast_typing(equal(A,B),Type,Pos). |
3316 | | check_ast_typing(equal(A,B),Type,Pos) :- !, |
3317 | | get_texpr_type(B,TB), |
3318 | | get_texpr_type(A,TA), |
3319 | | unify_types_werrors(TA,TB,Pos,'='), |
3320 | | (non_value_type(TA) |
3321 | | -> add_error(check_ast_typing,'Binary predicate has to have values as arguments:',TA,Pos) |
3322 | | ; Type=pred -> true |
3323 | | ; add_error(check_ast_typing,'Illegal type for binary predicate:',Type,Pos) |
3324 | | ). |
3325 | | check_ast_typing(greater_equal(A,B),Type,_) :- !, |
3326 | | get_texpr_type(A,TA),check_type(TA,integer,greater_equal), |
3327 | | get_texpr_type(B,TB),check_type(TB,integer,greater_equal), check_type(Type,pred,member). |
3328 | | check_ast_typing(Expr,Type,Pos) :- |
3329 | | syntaxtransformation(Expr,Subs,Names,NSubs,NewExpr), |
3330 | | check_names(Names,Pos), |
3331 | | (lookup_type(NewExpr,T) -> true |
3332 | | ; add_warning(check_ast_typing,'Unable to lookup type for: ',NewExpr), |
3333 | | fail |
3334 | | ), |
3335 | | !, |
3336 | | (unify_types_werrors(Type,T,Pos,'check_ast') |
3337 | | -> maplist(check_sub_type(Expr,Pos),Subs,NSubs) |
3338 | | ; add_error(check_ast_typing,'Type mismatch for expression:',Expr,Pos) |
3339 | | ). |
3340 | | check_ast_typing(_,subst,_) :- !. % ignore subst for the moment |
3341 | | check_ast_typing(operation(_TName,_Res,_Params,_TBody),_,_) :- !. % ignore operations for the moment |
3342 | | check_ast_typing(Expr,_,Pos) :- |
3343 | | syntaxtransformation(Expr,_,_Names,_,_NewExpr),!, |
3344 | | add_message(check_ast_typing,'Cannot lookup type for expression: ',Expr,Pos). |
3345 | | check_ast_typing(Expr,_,Pos) :- |
3346 | | add_message(check_ast_typing,'No applicable type rule for expression: ',Expr,Pos). |
3347 | | |
3348 | | non_value_type(X) :- var(X),!,fail. |
3349 | | non_value_type(pred). |
3350 | | non_value_type(subst). |
3351 | | non_value_type(op(_)). |
3352 | | |
3353 | | |
3354 | | check_names([],_). |
3355 | | check_names([H|T],Pos) :- |
3356 | | (member(H,T) -> add_error(check_ast_name,'Duplicate name:',H,Pos) ; check_names(T,Pos)). |
3357 | | |
3358 | | check_sub_type(OuterExpr,Pos,Arg,Type) :- get_texpr_type(Arg,T),!, |
3359 | | (unify_types_werrors(Type,T,Pos,'check_sub_type') -> true |
3360 | | ; add_error(check_ast_typing,'Type mismatch for sub-expression:',Arg,Pos), |
3361 | | write('Outer expression: '),translate:print_bexpr(OuterExpr),nl, |
3362 | | write('Outer type: '),write(Type),nl, |
3363 | | write('Arg type: '),write(T),nl,print(type(T)),nl, tools_printing:print_term_summary(Arg),nl,trace |
3364 | | ). |
3365 | | check_sub_type(_,Pos,Arg,_) :- |
3366 | | add_error(check_ast_typing,'Cannot extract type: ',Arg,Pos). |
3367 | | |
3368 | | lookup_type(identifier(_),_) :- !. % ignore typing issues for identifiers |
3369 | | lookup_type(Expr,Type) :- lookup_type_for_expr(Expr,Type). |
3370 | | |
3371 | | check_set_type(Var,_,_) :- var(Var),!. |
3372 | | check_set_type(set(_),_,_) :- !. |
3373 | | check_set_type(seq(_),_,_) :- !. |
3374 | | check_set_type(Type,Func,Pos) :- add_error(check_ast_typing,'Invalid type for operator: ',Func:Type,Pos). |
3375 | | |
3376 | | check_type(Type,Type,_) :- !. |
3377 | | check_type(Type,_,Func) :- add_error(check_ast_typing,'Unexpected type for operator: ',Func:Type). |
3378 | | |
3379 | | check_infos(X,F) :- var(X),!, add_error(check_infos,'Info field list not terminated: ',F:X),fail. |
3380 | | check_infos([],_). |
3381 | | check_infos([H|_],F) :- \+ ground(H),!, add_error(check_infos,'Info field not ground: ',F:H),fail. |
3382 | | check_infos([[H|T]|_],F) :- !, add_error(check_infos,'Info field contains nested list: ',F:[H|T]),fail. |
3383 | | check_infos([cse_used_ids(H)|T],F) :- member(cse_used_ids(H2),T),!, |
3384 | | add_error(check_infos,'Multiple cse_used_ids entries: ',F:[H,H2]),fail. |
3385 | | check_infos([used_ids(H)|T],F) :- member(used_ids(H2),T),!, |
3386 | | add_error(check_infos,'Multiple used_ids entries: ',F:[H,H2]),fail. |
3387 | | check_infos([nodeid(N1)|T],F) :- member(nodeid(N2),T),!, |
3388 | | add_error(check_infos,'Multiple nodeid entries: ',F:[N1,N2],[nodeid(N1)]),fail. |
3389 | | check_infos([removed_typing|T],F) :- member(removed_typing,T),!, |
3390 | | add_error(check_infos,'Multiple removed_typing entries: ',F,T),fail. |
3391 | | check_infos([_|T],F) :- check_infos(T,F). |
3392 | | |
3393 | | check_expr(Expr,Type,Infos) :- nonmember(contains_wd_condition,Infos), |
3394 | | sub_expression_contains_wd_condition(Expr,Sub), |
3395 | | TE = b(Expr,Type,Infos), |
3396 | | (Type = subst |
3397 | | -> fail % AST cleanup is not called for substitutions; WD-info not available for substitutions at the moment |
3398 | | ; translate_bexpression(TE,PS)), |
3399 | | functor(Expr,Functor,_), |
3400 | | functor(Sub,SubFunctor,_), |
3401 | | tools:ajoin(['Node for AST node ',Functor,' does not contain WD info from Subexpression ',SubFunctor,' :'],Msg), |
3402 | | add_warning(check_expr,Msg,PS,TE). |
3403 | | % well_def_analyser:nested_print_wd_bexpr(TE),nl. |
3404 | | % TODO: check when we have an unnecessary WD condition |
3405 | | check_expr(Expr,Type,Infos) :- nonmember(contains_wd_condition,Infos), |
3406 | | always_not_wd_top(Expr), |
3407 | | add_warning(check_expr,'AST is not well-defined but does not contain WD info: ',b(Expr,Type,Infos),Infos). |
3408 | | check_expr(member(LHS,RHS),Type,Infos) :- is_just_type(RHS), |
3409 | | get_preference(optimize_ast,true), |
3410 | | !, |
3411 | | TE = b(member(LHS,RHS),Type,Infos), |
3412 | | translate:translate_bexpression(TE,PS), |
3413 | | add_warning(check_expr,'AST contains redundant typing predicate: ',PS,TE). |
3414 | | check_expr(identifier(ID),_,_) :- illegal_id(ID),!, |
3415 | | add_error(check_infos,'Illegal identifier: ', identifier(ID)). |
3416 | | check_expr(lazy_lookup_expr(ID),_,_) :- illegal_id(ID),!, |
3417 | | add_error(check_infos,'Illegal identifier: ', lazy_lookup_expr(ID)). |
3418 | | check_expr(lazy_lookup_pred(ID),_,_) :- illegal_id(ID),!, |
3419 | | add_error(check_infos,'Illegal identifier: ', lazy_lookup_pred(ID)). |
3420 | | check_expr(exists(Parameters,Condition),pred,Infos) :- !, |
3421 | | check_used_ids(exists,Parameters,Condition,Infos,_Used). |
3422 | | check_expr(forall(Parameters,LHS,RHS),pred,Infos) :- !, |
3423 | | create_implication(LHS,RHS,Condition), |
3424 | | check_used_ids(forall,Parameters,Condition,Infos,_Used). % |
3425 | | check_expr(value(V),Type,_) :- !, check_bvalue(V,Type). |
3426 | | check_expr(_,_,_). |
3427 | | |
3428 | | % will check all used_ids fields (not just for exists and forall) |
3429 | | :- public check_used_ids_in_ast/1. |
3430 | | check_used_ids_in_ast(closure(_,_,TExpr)) :- !, (map_over_typed_bexpr(check_used_ids_aux,TExpr) ; true). |
3431 | | check_used_ids_in_ast(TExpr) :- map_over_typed_bexpr(check_used_ids_aux,TExpr). |
3432 | | check_used_ids_in_ast(_). |
3433 | | |
3434 | | check_used_ids_aux(AST) :- AST = b(_,_,Infos), |
3435 | | member(used_ids(_),Infos),!, |
3436 | | find_identifier_uses_if_necessary(AST,[],_), % will perform check |
3437 | | fail. |
3438 | | |
3439 | | % -------------------- |
3440 | | |
3441 | | :- use_module(specfile,[eventb_mode/0, z_or_tla_minor_mode/0]). |
3442 | | % check if an expression is definitely not WD; looking at the top-level operator only |
3443 | | always_not_wd_top(function(X,_)) :- definitely_empty_set(X). % TODO: detect a few more cases, e.g., arg not in dom |
3444 | | always_not_wd_top(power_of(X,Y)) :- (get_integer(Y,VY), VY < 0 -> true |
3445 | | ; eventb_mode, get_integer(X,VX), VX < 0). |
3446 | | always_not_wd_top(div(_,Val)) :- get_integer(Val,VV), VV==0. |
3447 | | always_not_wd_top(modulo(X,Y)) :- |
3448 | | (get_integer(Y,VY), VY=<0 |
3449 | | -> true % there seems to be a def for Z in Z Live, cf modulo2 |
3450 | | ; get_integer(X,VX), VX<0, \+ z_or_tla_minor_mode). |
3451 | | always_not_wd_top(min(X)) :- definitely_empty_set(X). |
3452 | | always_not_wd_top(max(X)) :- definitely_empty_set(X). |
3453 | | always_not_wd_top(size(X)) :- definitely_not_sequence(X). % TODO: detect infinite sets; also for card(_) |
3454 | | always_not_wd_top(first(X)) :- definitely_not_non_empty_sequence(X). |
3455 | | always_not_wd_top(front(X)) :- definitely_not_non_empty_sequence(X). |
3456 | | always_not_wd_top(last(X)) :- definitely_not_non_empty_sequence(X). |
3457 | | always_not_wd_top(tail(X)) :- definitely_not_non_empty_sequence(X). |
3458 | | always_not_wd_top(general_intersection(X)) :- definitely_empty_set(X). |
3459 | | |
3460 | | definitely_not_non_empty_sequence(X) :- |
3461 | | (definitely_empty_set(X) -> true ; definitely_not_sequence(X)). |
3462 | | |
3463 | | :- use_module(avl_tools,[avl_min_pair/3]). |
3464 | | definitely_not_sequence(b(value(A),_,_)) :- nonvar(A), A=avl_set(AVL), |
3465 | | avl_min_pair(AVL,int(StartIndex),_), StartIndex \= 1. |
3466 | | % TODO: treat set_extension |
3467 | | |
3468 | | :- use_module(b_ast_cleanup,[check_used_ids_info/4]). |
3469 | | check_used_ids(Quantifier,Parameters,Condition,Infos,Used) :- |
3470 | | select(used_ids(Used),Infos,Rest) |
3471 | | -> check_used_ids_info(Parameters,Condition,Used,Quantifier), %% comment in to check used_ids field |
3472 | | (member(used_ids(_),Rest) |
3473 | | -> add_internal_error('Multiple used_ids info fields:',Parameters:Infos) ; true) |
3474 | | ; |
3475 | | add_internal_error( |
3476 | | 'Expected information of used identifiers information',Quantifier:Parameters:Infos). |
3477 | | |
3478 | | illegal_id(ID) :- var(ID),!. |
3479 | | illegal_id(op(ID)) :- !, \+ atom(ID). |
3480 | | illegal_id(ID) :- \+ atom(ID). |
3481 | | |
3482 | | :- use_module(btypechecker, [unify_types_strict/2, couplise_list/2]). |
3483 | | :- use_module(avl_tools,[check_is_non_empty_avl/1]). |
3484 | | % TO DO: we could check type more |
3485 | | check_bvalue(V,_) :- var(V),!. |
3486 | | check_bvalue(avl_set(A),Type) :- !, unify_types_strict(Type,set(_)), |
3487 | | check_is_non_empty_avl(A). |
3488 | | check_bvalue(closure(_,T,B),Type) :- !, |
3489 | | couplise_list(T,CT), unify_types_strict(set(CT),Type), |
3490 | | check_ast(B). |
3491 | | check_bvalue(_,_). |
3492 | | |
3493 | | % ----------------------- |
3494 | | |
3495 | | |
3496 | | indent_ws(X) :- X<1,!. |
3497 | | indent_ws(X) :- print(' '), X1 is X-1, indent_ws(X1). |
3498 | | |
3499 | | print_ast_td(b(E,T,I),Level,L1) :- |
3500 | | indent_ws(Level), |
3501 | | (E=identifier(_) |
3502 | | -> format('~w (~w) -> ~w~n',[E,T,I]) |
3503 | | ; functor(E,F,N), |
3504 | | format('~w/~w (~w) -> ~w~n',[F,N,T,I]) |
3505 | | ), |
3506 | | L1 is Level+1. |
3507 | | print_ast(TExpr) :- |
3508 | | (map_over_typed_bexpr_top_down_acc(print_ast_td,TExpr,0),fail ; true). |
3509 | | |
3510 | | % --------------------- |
3511 | | |
3512 | | :- dynamic count_id_usage/2. |
3513 | | single_usage_id_count(Expr) :- uses_an_identifier(Expr,Id), |
3514 | | retract(count_id_usage(Id,Count)), |
3515 | | !, |
3516 | | Count=0, |
3517 | | C1 is Count+1, |
3518 | | assertz(count_id_usage(Id,C1)). |
3519 | | single_usage_id_count(_). |
3520 | | |
3521 | | % check if an identifier is used at most once |
3522 | | single_usage_identifier(ID,ExprOrPredicates,Count) :- |
3523 | | retractall(count_id_usage(_,_)), |
3524 | | assertz(count_id_usage(ID,0)), |
3525 | | % TO DO: take care of naming; do not count occurences when we enter scope defining ID |
3526 | | maplist(single_usage_cnt,ExprOrPredicates), |
3527 | | retract(count_id_usage(ID,Count)). |
3528 | | |
3529 | | single_usage_cnt(ExprOrPredicate) :- map_over_full_bexpr_no_fail(single_usage_id_count,ExprOrPredicate). |
3530 | | |
3531 | | gen_fresh_id_if_necessary(Default,Expr,FreshID) :- |
3532 | | occurs_in_expr(Default,Expr),!, |
3533 | | gensym('__FRESH_ID__',FreshID). % assumes _Fresh_XXX not used |
3534 | | gen_fresh_id_if_necessary(Default,_,Default). |
3535 | | |
3536 | | %% rewrite_if_then_else_expr_to_b(IfThenElseExpr, NExpr). |
3537 | | % Rewrite if-then-else expr to B as understood by Atelier-B. |
3538 | | % {d,x| d:BOOL & If => x=Then & not(if) => x=Else}(TRUE) |
3539 | | rewrite_if_then_else_expr_to_b(if_then_else(If,Then,Else), NExpr) :- |
3540 | | get_texpr_type(Then,Type), |
3541 | | ARG = b(boolean_true,boolean,[]), AT=boolean, % we could use unit type or BOOL here |
3542 | | gen_fresh_id_if_necessary('_zzzz_unary',b(if_then_else(If,Then,Else),Type,[]),AID1), |
3543 | | gen_fresh_id_if_necessary('_zzzz_binary',b(if_then_else(If,Then,Else),Type,[]),AID2), |
3544 | | safe_create_texpr(identifier(AID1), AT, [], Id1), % a dummy argument |
3545 | | safe_create_texpr(identifier(AID2), Type, [], Id2), % The result |
3546 | | safe_create_texpr(equal(Id2,Then), pred, [], Eq1), |
3547 | | safe_create_texpr(equal(Id2,Else), pred, [], Eq2), |
3548 | | safe_create_texpr(implication(If,Eq1), pred, [], Pred1), |
3549 | | safe_create_texpr(negation(If), pred, [], NIf), |
3550 | | safe_create_texpr(implication(NIf,Eq2), pred, [], Pred2), |
3551 | | safe_create_texpr(conjunct(Pred1,Pred2), pred, [], Pred), |
3552 | | safe_create_texpr(comprehension_set([Id1,Id2],Pred), set(couple(AT,Type)), [], FUN), |
3553 | | NExpr = function(FUN,ARG). |