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