1 % (c) 2009-2024 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(bmachine_eventb,[check_event_b_project/4
6 ,deferred_set_equality_without_enumeration_axioms/2
7 ,is_eventb_additional_info/1
8 ,raw_event/11
9 ,stored_operator_direct_definition/8 % stored operator defs, mainly for bvisual2
10 ,stored_operator/2 % a simpler form
11 ,some_operator_uses_reals/0 % true if some operator definitely uses reals
12 %,get_operator_arity_from_callback/3 % not yet used
13 ]).
14
15 :- use_module(library(lists)).
16 :- use_module(library(ordsets)).
17 :- use_module(library(avl)).
18 :- use_module(library(codesio),[read_from_codes/2]).
19
20 :- use_module(error_manager).
21 :- use_module(tools,[remove_all/3,foldl/4,foldl/5,foldl/6,ajoin_with_sep/3,unique_id/2]).
22 :- use_module(self_check).
23 :- use_module(btypechecker).
24 :- use_module(b_ast_cleanup).
25 :- use_module(bsyntaxtree).
26 :- use_module(debug).
27 :- use_module(bmachine_construction).
28 :- use_module(preferences,[get_preference/2]).
29 :- use_module(input_syntax_tree,[extract_raw_identifiers/2,create_fresh_identifier/3]).
30 :- use_module(translate,[translate_bexpression/2]).
31 :- use_module(kernel_freetypes,[create_freetype_typeid/3]).
32 :- use_module(pragmas,[extract_pragmas_from_event_b_extensions/2,apply_pragmas_to_event_b_machine/3]).
33 :- use_module(input_syntax_tree,[map_over_raw_expr/3]).
34
35 :- use_module(module_information,[module_info/2]).
36 :- module_info(group,typechecker).
37 :- module_info(description,'This module contains the rules for loading a Event-B machine or context. ').
38
39 :- set_prolog_flag(double_quotes, codes).
40
41 :- use_module(specfile,[eventb_mode/0]).
42 deferred_set_equality_without_enumeration_axioms(Set,ExtSet) :-
43 eventb_mode,
44 deferred_set_eq_wo_enumeration_axioms(Set,ExtSet),
45 % there is a single equality Set = {id1,...,idn} and no partition or not enough disequalities
46 % quite often the user forgot to add those disequalities
47 \+ (deferred_set_eq_wo_enumeration_axioms(Set,ExtS2), ExtS2 \= ExtSet).
48
49 :- dynamic deferred_set_eq_wo_enumeration_axioms/2.
50
51 check_event_b_project(RawModels,RawContextes,Extensions,MachineWithPragmas) :-
52 retractall(deferred_set_eq_wo_enumeration_axioms(_,_)),
53 catch( check_event_b_project1(RawModels,RawContextes,Extensions,MachineWithPragmas),
54 typecheck_errors(Errors),
55 ( add_all_perrors(Errors), NoError=false )), % a cut here does not work !
56 !, NoError=true.
57 check_event_b_project(_,_,_,_) :-
58 add_internal_error('Checking Event-B Model failed; Please submit bug report.',check_event_b_project(_,_,_,_)),
59 fail.
60 check_event_b_project1([],RawContextes,Extensions,MachineWithPragmas) :-
61 !,
62 check_theory_extensions(Extensions,Freetypes,Ops,InitEnv), % Theories
63 check_contextes(InitEnv,RawContextes,Contextes),
64 convert_event_b(context,Freetypes,Ops,Contextes,[],[],Machine),
65 extract_pragmas_from_event_b_extensions(Extensions,Pragmas),
66 apply_pragmas_to_event_b_machine(Pragmas,Machine,MachineWithPragmas).
67 check_event_b_project1(RawModels,RawContextes,Extensions,MachineWithPragmas) :-
68 compute_animation_chain(RawModels,AnimationChain),
69 check_event_b_project2(RawModels,RawContextes,Extensions,
70 AnimationChain,Machine),
71 extract_pragmas_from_event_b_extensions(Extensions,Pragmas),
72 apply_pragmas_to_event_b_machine(Pragmas,Machine,MachineWithPragmas).
73
74 check_event_b_project2(RawModels,RawContextes,Extensions,AnimationChain,Machine) :-
75 RawModels=[event_b_model(_,Main,_)|_],
76 check_theory_extensions(Extensions,Freetypes,Ops,InitEnv), % related to Theory plugin
77 % generate type-checked contextes
78 check_contextes(InitEnv,RawContextes,Contextes),
79 % generate type-checked models
80 check_models(InitEnv,RawModels,Contextes,Models),
81 % merge all the constants/vars/predicates and events into one machine
82 convert_event_b(Main,Freetypes,Ops,Contextes,Models,AnimationChain,Machine).
83
84 % the filter chain contains the name of all models that
85 % should be contained in the animation
86 compute_animation_chain(Models,AnimationChain) :-
87 get_preference(number_skipped_refined_machines,NS), % TODO: also use it for constants if possible
88 get_preference(number_animated_abstractions,N),
89 debug_println(9,compute_animation_chain(N,skipping(NS))),
90 (NS=0 -> NonSkippedModels = Models
91 ; append_length(SkippedModels,NonSkippedModels,Models,NS),
92 NonSkippedModels = [_|_]
93 -> extract_model_names(SkippedModels,SkippedNames),
94 add_message(bmachine_eventb,'Skipping animation of refinement machines: ',SkippedNames)
95 ; last(Models,AnimatedModel),
96 NonSkippedModels = [AnimatedModel],
97 extract_model_names(NonSkippedModels,[AName]),
98 ajoin(['Cannot skip ',NS,' refinement machines; animating topmost machine only: '],Msg),
99 add_warning(bmachine_eventb,Msg,AName)
100 ),
101 length(NonSkippedModels,L),
102 N1 is min(N+1,L),
103 prefix_length(NonSkippedModels, AnimatedModels, N1),
104 extract_model_names(AnimatedModels,AnimationChain).
105 extract_model_names([],[]).
106 extract_model_names([event_b_model(_,Name,_)|MRest],[Name|NRest]) :-
107 extract_model_names(MRest,NRest).
108
109 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
110 % context
111
112 check_contextes(InitEnv,RawContextes,Contextes) :-
113 debug_println(9,'Checking Contextes'),
114 % make sure that a extended context is treated before
115 % the extending context
116 topological_sort(RawContextes,SortedContextes),
117 check_contextes2(SortedContextes,InitEnv,[],Contextes).
118 check_contextes2([],_,_,[]).
119 check_contextes2([RawContext|Rrest],InitEnv,PrevContextes,[Context|Crest]) :-
120 check_context(RawContext,InitEnv,PrevContextes,Context),
121 check_contextes2(Rrest,InitEnv,[Context|PrevContextes],Crest).
122
123 check_context(RawContext,InitEnv,PrevContextes,Context) :-
124 extract_ctx_sections(RawContext,Name,Extends,
125 RawSets,RawConstants,RawAbstractConstants,RawAxioms,RawTheorems),
126 Context = context(Name,Extends,Sets,Constants,AbstractConstants,Axioms,Theorems),
127
128 debug_format(9,'Checking context ~w~n',[Name]),
129 % create deferred sets
130 create_sets(RawSets,Name,Sets),
131 % and constants
132 IdInfos = [loc(Name,constants),section(Name)],
133 create_identifiers(RawConstants,IdInfos,Constants),
134 create_identifiers(RawAbstractConstants,IdInfos,AbstractConstants),
135
136 % with the constants and set of seen contextes,
137 create_ctx_env(Extends,PrevContextes,InitEnv,PrevEnv),
138 % and the sets and constants
139 add_unique_variables(Sets,PrevEnv,SetEnv),
140 add_unique_variables(Constants,SetEnv,EnvT),
141 add_unique_variables(AbstractConstants,EnvT,Env),
142
143 % now typecheck the axioms and theorems,
144 % this should determine the constant's types
145 debug_format(9,'Typechecking axioms and theorems for ~w~n',[Name]),
146 typecheck_together([RawAxioms,RawTheorems],Env,[Axioms,Theorems],axioms).
147
148 extract_ctx_sections(RawContext,Name,Extends,RawSets,RawConstants,RawAbstractConstants,RawAxioms,RawTheorems) :-
149 RawContext = event_b_context(_Pos,Name,Sections),
150 optional_rawmachine_section(extends,Sections,[],Extends),
151 optional_rawmachine_section(sets,Sections,[],RawSets),
152 optional_rawmachine_section(constants,Sections,[],RawConstants),
153 optional_rawmachine_section(abstract_constants,Sections,[],RawAbstractConstants),
154 optional_rawmachine_section(axioms,Sections,[],RawAxioms),
155 optional_rawmachine_section(theorems,Sections,[],RawTheorems).
156
157
158 create_sets([],_,[]).
159 create_sets([RawSet|RSrest],CtxName,[Set|Srest]) :-
160 ext2int_with_pragma(RawSet,deferred_set(SetName),_,set(global(SetName)),
161 identifier(SetName),[section(CtxName),given_set],Set),
162 create_sets(RSrest,CtxName,Srest).
163
164 create_identifiers([],_,[]).
165 create_identifiers([RawIdentifier|RIrest],Infos,[Identifier|Irest]) :-
166 ext2int_with_pragma(RawIdentifier,I,_,_,I,Infos,Identifier),
167 I=identifier(_),
168 create_identifiers(RIrest,Infos,Irest).
169
170 create_ctx_env(Extends, Contextes, Old, New) :-
171 % find all seen contextes (and their extended contextes,
172 % and again their extended contextes, ...)
173 transitive_contextes(Extends,Contextes,TransExt),
174 % and all variables of extended machines
175 add_env_vars_for_extended2(TransExt,Contextes,Old,New).
176 transitive_contextes(Extends,Contextes,All) :-
177 findall(E, transext(Extends,Contextes,E), All1), sort(All1, All).
178 transext(Extends,_,E) :- member(E,Extends).
179 transext(Extends,Contextes,E) :-
180 member(Name,Extends),
181 internal_context_extends(Context,Name,NewExtends),
182 member(Context,Contextes),
183 transext(NewExtends,Contextes,E).
184 % add_env_vars_for_extended2(Names,Contextes,OldEnv,NewEnv):
185 % Names: a list of the names of the contextes whose constants and sets
186 % should be added to the type environment
187 % Contextes: a list of all existing contextes
188 % OldEnv: the input environment
189 % NewEnv: the input environment plus the constants and sets
190 add_env_vars_for_extended2([],_,Env,Env).
191 add_env_vars_for_extended2([Name|Erest],Contextes,Old,New) :-
192 internal_context_sets(Context,Name,Sets),
193 internal_context_constants(Context,Name,Constants),
194 internal_context_abstract_constants(Context,Name,AbstractConstants),
195 member(Context,Contextes),!,
196 add_unique_variables(Sets,Old,Env1),
197 add_unique_variables(Constants,Env1,Env2),
198 add_unique_variables(AbstractConstants,Env2,Env),
199 add_env_vars_for_extended2(Erest,Contextes,Env,New).
200
201 % copy&paste from bmachine_construction
202 add_unique_variables([],Env,Env).
203 add_unique_variables([Var|Rest],Old,New) :-
204 def_get_texpr_id(Var,Name),
205 get_texpr_type(Var,Type),
206 get_texpr_info(Var,Infos),
207 ( env_lookup_type(Name,Old,_) ->
208 add_error(bmachine_eventb,'Identifier declared twice',Name),
209 fail
210 ; true),
211 env_store(Name,Type,Infos,Old,Env),
212 add_unique_variables(Rest,Env,New).
213
214 % add the primed (') versions of the variables to the
215 % type environment
216 add_primed_variables(Variables,OrigEnv,NewEnv) :-
217 prime_variables(Variables,Primed),
218 add_unique_variables(Primed,OrigEnv,NewEnv).
219
220
221 :- use_module(btypechecker,[prime_identifiers/2,prime_id/2,is_primed_id/1,prime_identifiers0/2]).
222
223 % add a prime (') to each typed identifier
224 prime_variables(V,PV) :- prime_identifiers(V,PV).
225 % add a prime (') to a typed identifier
226 %prime_variable(V,P) :- btypechecker:prime_identifier(V,P).
227
228
229 % unprime_id( ListoPrimedIds, CorrespondingIds, PossiblyPrimedID, UnprimedID)
230 unprime_id(AtomicIds0,AtomicIds,Id0,Id) :- nth1(N,AtomicIds0,Id0),!, nth1(N,AtomicIds,Id).
231 unprime_id(_,_,Id,Id).
232
233 check_for_errors(Errors) :-
234 % TO DO: extract and add warnings in list
235 Errors = [_|_],!,throw(typecheck_errors(Errors)).
236 check_for_errors([]).
237
238 typecheck_l(Untyped,Env,Type,Typed,Context) :-
239 all_same_type(Untyped,Type,Types),
240 btype_ground_dl(Untyped,Env,[],Types,Typed1,Errors,[]),
241 check_for_errors(Errors),
242 maplist(update_eventb_position_infos(Context),Typed1,Typed2),
243 clean_up_l_with_optimizations(Typed2,[],Typed,Context),!.
244 typecheck_l(Untyped,Env,Type,Typed,Context) :-
245 add_failed_call_error(typecheck_l(Untyped,Env,Type,Typed,Context)),fail.
246 all_same_type([],_,[]).
247 all_same_type([_|R],E,[E|T]) :- all_same_type(R,E,T).
248
249 typecheck(Untyped,Env,Type,Typed,Context) :-
250 typecheck_with_freevars(Untyped,Env,[],Type,Typed,Context).
251 typecheck_with_freevars(Untyped,Env,Freevars,Type,Typed,Context) :-
252 btype_ground_dl([Untyped],Env,Freevars,[Type],[Typed1],Errors,[]),
253 update_eventb_position_infos(Context,Typed1,Typed2),
254 clean_up_pred_or_expr_with_path(Freevars,Typed2,Typed,Context),
255 check_for_errors(Errors).
256
257
258 :- use_module(probsrc(bsyntaxtree),[transform_bexpr/3, get_rodin_name/2, get_rodin_model_name/2]).
259 :- public add_eventb_pos_aux/5.
260 add_eventb_pos_aux(Model,LabelName,Context,b(E,T,I),b(E,T,NewInfo)) :-
261 nonmember(nodeid(_),I),
262 NewInfo = [nodeid(rodin_derived_context_pos(Model,Context,LabelName))|I].
263 % TO DO: we could also try and improve ordinary rodinpos infos by adding context (useful if label names not unique)
264
265 % try and improve position information using the context
266 update_eventb_position_infos(Context,TE,Res) :-
267 get_rodin_model_name(TE,Model), get_rodin_name(TE,LabelName),
268 transform_bexpr(add_eventb_pos_aux(Model,LabelName,Context),TE,NewTE),!,
269 Res=NewTE.
270 update_eventb_position_infos(Context,b(conjunct(A,B),pred,I),b(conjunct(A2,B2),pred,I)) :- !, % useful for guard labels
271 update_eventb_position_infos(Context,A,A2),
272 update_eventb_position_infos(Context,B,B2).
273 update_eventb_position_infos(_,TE,TE).
274
275
276 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
277 % models
278
279 check_models(InitEnv,RawModels,Contextes,Models) :-
280 debug_println(9,'CHECKING MODELS'),
281 topological_sort(RawModels,SortedModels),
282 check_models2(SortedModels,InitEnv,[],Contextes,Models).
283
284 check_models2([],_,_,_,[]).
285 check_models2([RawModel|RMrest],InitEnv,PrevModels,Contextes,[Model|Mrest]) :-
286 (check_model(RawModel,InitEnv,PrevModels,Contextes,Model) -> true
287 ; add_failed_call_error(check_model(RawModel,InitEnv,PrevModels,Contextes,Model)),
288 fail),
289 check_models2(RMrest,InitEnv,[Model|PrevModels],Contextes,Mrest).
290
291 check_model(RawModel,InitEnv,PrevModels,Contextes,Model) :-
292 extract_model_sections(RawModel,Name,Refines,Sees,
293 RawVariables,RawInvariant,
294 RawTheorems,RawVariant,RawEvents),
295 Model = model(Name,Refines,Sees,ConcreteVariables,NewVariables,Invariant,Theorems,Events),
296 get_refined_model(Refines,PrevModels,RefinedModel),
297
298 get_all_abstract_variables(Refines,PrevModels,AbstractionVariables),
299 length(PrevModels,Level),
300 IdInfos = [loc(Name,variables),section(Name),level(Level)],
301 create_identifiers(RawVariables,IdInfos,ConcreteVariables),
302 split_abstract_vars(AbstractionVariables,ConcreteVariables,
303 NewVariables,DroppedAbstractVars),
304
305 create_ctx_env(Sees,Contextes,InitEnv,CtxEnv),
306 add_unique_variables(ConcreteVariables,CtxEnv,ModelEnv),
307 add_unique_variables(DroppedAbstractVars,ModelEnv,InvEnv),
308 % add primed versions of the concrete variables to
309 % permit before-after predicates in the witnesses
310 add_primed_variables(ConcreteVariables,InvEnv,BeforeAfterEnv),
311
312 typecheck_together([RawInvariant,RawTheorems],InvEnv,[Invariant,Theorems],invariant),
313
314 typecheck_variant(RawVariant,InvEnv,Variant),
315
316 get_abstract_events(RefinedModel,AbstractEvents),
317
318 check_events(RawEvents,Name,ModelEnv,BeforeAfterEnv,InvEnv,
319 DroppedAbstractVars,ConcreteVariables,AbstractEvents,
320 NewVariables,Variant,Events).
321
322 % Context is just an information term about the context (axioms, ...)
323 typecheck_together(Raws,Env,Typed,Context) :-
324 maplist(same_length, Raws, Typed),
325 append(Raws,RawL), append(Typed,TypedL),
326 typecheck_l(RawL,Env,pred,TypedL,Context).
327
328 typecheck_variant(-, _Env, -) :- !.
329 typecheck_variant(RawVariant, Env, Variant) :-
330 typecheck(RawVariant, Env, Type, Variant,variant),
331 ( Type==integer -> true
332 ; functor(Type,set,1) -> true
333 ;
334 add_error(bmachine_eventb,'Invalid type of variant ',Type),
335 fail).
336
337 remove_linking_parts([],_AnimationChain,[]).
338 remove_linking_parts([Inv|Irest],AnimationChain,Invariants) :-
339 ( abstraction_var_occures(Inv,AnimationChain) ->
340 Invariants = RestInvariants
341 ;
342 Invariants = [Inv|RestInvariants]),
343 remove_linking_parts(Irest,AnimationChain,RestInvariants).
344
345 abstraction_var_occures(TExpr,AnimationChain) :-
346 get_texpr_expr(TExpr,identifier(_)),!,
347 get_texpr_section(TExpr,Section),
348 \+ member(Section,AnimationChain).
349 abstraction_var_occures(TExpr,AnimationChain) :-
350 syntaxtraversion(TExpr,_,_,_,Subs,_),
351 abstraction_var_occures_l(Subs,AnimationChain).
352 abstraction_var_occures_l([Sub|_],AnimationChain) :-
353 abstraction_var_occures(Sub,AnimationChain),!.
354 abstraction_var_occures_l([_|Srest],AnimationChain) :-
355 abstraction_var_occures_l(Srest,AnimationChain).
356
357 get_texpr_section(TExpr,Section) :-
358 get_texpr_info(TExpr,Info),member(section(Section),Info),!.
359
360 extract_model_sections(RawModel,Name,Refines,Sees,Variables,Invariant,Theorems,Variant,Events) :-
361 RawModel = event_b_model(_Pos,Name,Sections),
362 optional_rawmachine_section(refines,Sections,-,Refines),
363 optional_rawmachine_section(sees,Sections,[],Sees),
364 optional_rawmachine_section(variables,Sections,[],Variables),
365 optional_rawmachine_section(invariant,Sections,[],Invariant),
366 optional_rawmachine_section(theorems,Sections,[],Theorems),
367 optional_rawmachine_section(variant,Sections,-,Variant),
368 optional_rawmachine_section(events,Sections,[],Events).
369
370 %get_abstraction_variables(-,[]).
371 %get_abstraction_variables(Model,Variables) :-
372 % internal_model_vars(Model,_Name,Variables).
373
374 get_abstract_events(-,[]).
375 get_abstract_events(Model,Events) :- internal_model_events(Model,_Name,Events).
376
377 get_refined_model(-,_Models,-) :- !.
378 get_refined_model(Name,Models,Model) :-
379 internal_model(M,Name),
380 ( memberchk(M,Models) ->
381 M=Model
382 ;
383 add_error(bmachine_eventb,'Unable to find refined model ',Name),
384 fail).
385
386 split_abstract_vars(AbstractVars,ConcreteVars,NewVars,DroppedVars) :-
387 split_abstract_vars2(AbstractVars,ConcreteVars,DroppedVars),
388 find_new_variables(ConcreteVars,AbstractVars,NewVars).
389 split_abstract_vars2([],_,[]).
390 split_abstract_vars2([AbstractVar|AVrest],ConcreteVars,Dropped) :-
391 ( find_identifier_in_list(AbstractVar,ConcreteVars,ConcreteVar) ->
392 % Both variables have the same type
393 get_texpr_type(AbstractVar,Type),
394 get_texpr_type(ConcreteVar,Type),
395 Dropped = DroppedRest
396 ;
397 Dropped = [AbstractVar|DroppedRest]),
398 split_abstract_vars2(AVrest,ConcreteVars,DroppedRest).
399 find_new_variables([],_,[]).
400 find_new_variables([ConcreteVar|CVrest],AbstractVars,NewVars) :-
401 ( find_identifier_in_list(ConcreteVar,AbstractVars,_AbstractVar) -> NewVars = Nrest
402 ; NewVars = [ConcreteVar|Nrest]),
403 find_new_variables(CVrest,AbstractVars,Nrest).
404
405 % find_identifier_in_list(TypedIdToFind,List,Elem):
406 % search for a typed identifier Elem in List wich
407 % has the same id as TypedIdToFind, but type and informations
408 % may be different
409 find_identifier_in_list(TypedIdToFind,List,Found) :-
410 def_get_texpr_id(TypedIdToFind,Id),
411 get_texpr_id(Found,Id),
412 member(Found,List).
413
414 get_all_abstract_variables(Refines,AbstractModels,AbstractVariables) :-
415 get_all_abstract_variables2(Refines,AbstractModels,_EncounteredIds,AbstractVariables,[]).
416 get_all_abstract_variables2(-,_AbstractModels,EncounteredIds) -->
417 {!,empty_avl(EncounteredIds)}.
418 get_all_abstract_variables2(Name,AbstractModels,EncounteredIds) -->
419 {get_refined_model(Name,AbstractModels,Model),
420 internal_model_refines(Model,_,Refines)},
421 get_all_abstract_variables2(Refines,AbstractModels,EncounteredIdsAbs),
422 get_all_abstract_variables3(Model,EncounteredIdsAbs,EncounteredIds).
423 get_all_abstract_variables3(Model,EncounteredIdsIn,EncounteredIdsOut,
424 FoundVarsIn,FoundVarsOut) :-
425 internal_model_vars(Model,_,Vars),
426 extract_new_variables(Vars,EncounteredIdsIn,NewVars),
427 get_texpr_ids(NewVars,NewIds),
428 add_all_to_avl(NewIds,EncounteredIdsIn,EncounteredIdsOut),
429 add_all(NewVars,FoundVarsIn,FoundVarsOut).
430 add_all_to_avl([],Avl,Avl).
431 add_all_to_avl([H|T],In,Out) :-
432 avl_store(H,In,1,Inter),
433 add_all_to_avl(T,Inter,Out).
434 add_all([],L,L).
435 add_all([H|T],[H|L1],L2) :- add_all(T,L1,L2).
436 extract_new_variables([],_EncounteredIdsIn,[]).
437 extract_new_variables([Var|Vrest],EncounteredIds,NewVars) :-
438 get_texpr_id(Var,Id),
439 ( avl_fetch(Id,EncounteredIds) ->
440 NewVars = NewRest
441 ;
442 NewVars = [Var|NewRest]),
443 extract_new_variables(Vrest,EncounteredIds,NewRest).
444
445
446
447
448
449 check_events([],_ModelName,_Env,_GEnv,_InvEnv,_Dropped,_ConcreteVars,_AbstractEvents,_NewVars,_Variant,[]).
450 check_events([RawEvent|RawRest],ModelName,Env,GEnv,InvEnv,DroppedVars,ConcreteVars,AbstractEvents,NewVars,Variant,[Event|Erest]) :-
451 (check_event(RawEvent,ModelName,Env,GEnv,InvEnv,DroppedVars,ConcreteVars,AbstractEvents,NewVars,Variant,Event)
452 -> true
453 ; add_failed_call_error(check_event(RawEvent,ModelName,Env,GEnv,InvEnv,
454 DroppedVars,ConcreteVars,AbstractEvents,NewVars,Variant,Event))),
455 check_events(RawRest,ModelName,Env,GEnv,InvEnv,DroppedVars,ConcreteVars,AbstractEvents,NewVars,Variant,Erest).
456
457
458 check_event(RawEvent,ModelName,Env,GEnv,InvEnv,DroppedVars,ConcreteVars,AbstractEvents,NewVariables,Variant,
459 tc_event(EvName,ModelName,Status,TParameters,TGuard,TTheorems,MActions,
460 TVarWitnesses,TParamWitnesses,Unmodifiables,Refines,Desc) % type_checked internal event term
461 ) :-
462 raw_event(RawEvent,_,EvName,RawStatus,Refines,Params,Guards,Theorems,Actions,Witnesses,Desc),
463 check_status(RawStatus, Variant, Status, Refines, AbstractEvents, eventlocation(ModelName,EvName)),
464 get_abstract_parameters(Refines,AbstractEvents,AbstractParameters),
465 create_identifiers(Params,[loc(ModelName,event(EvName))],TParameters),
466 split_abstract_vars(AbstractParameters,TParameters,
467 _NewParameters,DroppedParameters1),
468 annotate_dropped_parameters(DroppedParameters1,Refines,AbstractEvents,DroppedParameters),
469 conjunct_guards(Guards,Guard), % TODO: we could see if the guards appear at the abstract level with same label and use the abstract machine name, see M2_test_extends_grd_labels
470 maplist(adapt_becomes_such,Actions,Actions1),
471 % add new parameters to the typing environments:
472 add_identifiers_to_environment(TParameters,Env,Subenv),
473 add_identifiers_to_environment(TParameters,GEnv,SubGenv),
474 add_identifiers_to_environment(TParameters,InvEnv,SubTheoremsEnv), % theorems can access dropped abstract variables; just like the invariant
475 typecheck(Guard,Subenv,pred,TGuard,event(EvName,guard)),
476 typecheck_l(Theorems,SubTheoremsEnv,pred,TTheorems,event(EvName,theorems)),
477 typecheck_l(Actions1,Subenv,subst,TActions,event(EvName,actions)),
478 check_witnesses(Witnesses,SubGenv,DroppedParameters,DroppedVars,TVarWitnesses,TParamWitnesses),
479 % add checks that some variables may not be modified, e.g
480 % if skip is refined
481 get_abstract_actions(Refines,AbstractEvents,AbstractActions),
482 add_modified_vars_to_actions(TActions,MActions1),
483 add_unmodified_assignments(AbstractActions,MActions1,ConcreteVars,MActions),
484 add_equality_check(MActions,AbstractActions,NewVariables,ConcreteVars,Unmodifiables).
485
486
487
488 % --------------
489
490 % add assignments of the form x:=x if a not dropped abstract variable
491 % is modified by the abstract event, but not the dropped event
492 add_unmodified_assignments(AbstractActions,ConcreteActions,ConcreteVars,NewActions) :-
493 get_modified_vars_of_actions(AbstractActions,AbstractModified),
494 get_modified_vars_of_actions(ConcreteActions,ConcreteModified),
495 remove_all(AbstractModified,ConcreteModified,OnlyAbstractModified),
496 findall( Var,
497 ( member(Id,OnlyAbstractModified), get_texpr_id(Var,Id), memberchk(Var,ConcreteVars)),
498 ToKeep),
499 ( ToKeep = [] -> NewActions = ConcreteActions
500 ; ToKeep = [_|_] ->
501 create_texpr(assign(ToKeep,ToKeep),subst,[],Action1),
502 add_modified_vars_to_action(Action1,Action),
503 NewActions = [Action|ConcreteActions]).
504
505 check_status(RawStatus, Variant, TConv, Refines, AbstractEvents, Location) :-
506 remove_pos(RawStatus,Status),
507 check_status2(Status, Variant, Refines, AbstractEvents, Location, Conv, Infos),
508 create_texpr(Conv, status, Infos, TConv).
509 check_status2(ordinary, _Variant, _Refines, _AbstractEvents, _Location, ordinary, []).
510 check_status2(convergent, _Variant, Refines, AbstractEvents, _Location, ordinary, [convergence_proved]) :-
511 % if the refined event is also convergent, we can (or must because the
512 % variant may be missing in the refinement) omit the check for decreasing the
513 % variant. We do this by treating the event as ordinary.
514 convergence_ensured_by_abstract_event(Refines, AbstractEvents),!.
515 check_status2(convergent, Variant, _Refines, _AbstractEvents, Location, convergent(RVariant), [convergence_proved]) :-
516 variant_must_be_set(Variant,Location,RVariant).
517 check_status2(anticipated, Variant, _Refines, _AbstractEvents, _Location, anticipated(RVariant), []) :-
518 get_variant(Variant,RVariant).
519
520 :- use_module(tools_strings,[ajoin/2]).
521 variant_must_be_set(-,Location,RVariant) :- !,
522 Location = eventlocation(Model,Name),
523 ajoin(['No variant defined for ', Name, ' in model ', Model],Msg),
524 add_error(bmachine_eventb,Msg),
525 get_variant(-,RVariant).
526 % removed fail to allow animation
527 variant_must_be_set(V,_,V).
528
529 % get_variant(ModelVariant,Variant) checks profides a default variant (0) if
530 % the model does not have a variant
531 get_variant(-,V) :- !, create_texpr(integer(0),integer,[default_variant],V).
532 get_variant(V,V).
533
534 convergence_ensured_by_abstract_event(Refines, AbstractEvents) :-
535 % find a refined event which status is convergent
536 internal_event_status(Event,Ref,Status),
537 get_texpr_info(Status,StatusInfo),
538 member(Event, AbstractEvents),
539 member(Ref, Refines),
540 member(convergence_proved,StatusInfo),!.
541
542 annotate_dropped_parameters([],_,_,[]).
543 annotate_dropped_parameters([P|PRest],Refines,AbstractEvents,[A|ARest]) :-
544 def_get_texpr_id(P,Id),
545 add_texpr_infos(P,[droppedby(DropList)],A),
546 findall(Event, event_drops_param(Event,Refines,AbstractEvents,Id), DropList),
547 annotate_dropped_parameters(PRest,Refines,AbstractEvents,ARest).
548 event_drops_param(Event,Refines,AbstractEvents,Id) :-
549 get_texpr_id(Pattern,Id),
550 member(Event,Refines),
551 get_event_parameters(Event,AbstractEvents,AbParams),
552 member(Pattern,AbParams).
553
554 get_abstract_parameters([],_,R) :- !,R=[].
555 get_abstract_parameters([Refines|Rest],Events,Params) :- !,
556 get_event_parameters(Refines,Events,LocalParams),
557 append(LocalParams,RestParams,Params),
558 get_abstract_parameters(Rest,Events,RestParams).
559 get_abstract_parameters(Refines,_,Params) :- add_error(get_abstract_parameters,'Illegal Refines List: ',Refines),
560 Params=[].
561 get_event_parameters(Refines,Events,Params) :-
562 internal_event_params(Event,Refines,Params),
563 member(Event,Events),!.
564
565 get_abstract_actions([],_,[]).
566 get_abstract_actions([Refines|Rest],Events,Actions) :-
567 get_event_action(Refines,Events,LocalActions),
568 append(LocalActions,RestActions,Actions),
569 get_abstract_actions(Rest,Events,RestActions).
570 get_event_action(Refines,Events,Actions) :-
571 internal_event_actions(Event,Refines,Actions),
572 member(Event,Events),!.
573
574 check_witnesses([],_Env,_DroppedParams,_DroppedVars,[],[]).
575 check_witnesses([Witness|Rest],Env,DroppedParams,DroppedVars,TVarWitnesses,TParamWitnesses) :-
576 check_witness(Witness,Env,DroppedParams,DroppedVars,TWitness,WType),
577 ( WType = droppedvar ->
578 TVarWitnesses = [TWitness|TWVRest],
579 TParamWitnesses = TWPRest
580 ; WType = droppedparam(_DropList) ->
581 TVarWitnesses = TWVRest,
582 TParamWitnesses = [TWitness|TWPRest]),
583 check_witnesses(Rest,Env,DroppedParams,DroppedVars,TWVRest,TWPRest).
584 check_witness(witness(_Pos,RawId,Pred),Env,DroppedParams,DroppedVars,TWitness,WType) :-
585 RawId = identifier(_,WitnessId),
586 get_witness_identifier(WitnessId,DroppedParams,DroppedVars,TId,Info,WType),
587 get_texpr_type(TId,Type),
588 env_store(WitnessId,Type,Info,Env,Subenv),
589 typecheck(Pred,Subenv,pred,TPred,witness),
590 create_texpr(witness(TId,TPred),witness,[],TWitness).
591 get_witness_identifier(PrimedId,_DroppedParams,DroppedVars,TPrimeId,[],droppedvar) :-
592 prime_id(Id,PrimedId),
593 get_texpr_id(TId,Id),
594 member(TId,DroppedVars),!,
595 prime_variables([TId],[TPrimeId]).
596 get_witness_identifier(Id,DroppedParams,_DroppedVars,TId,Info,droppedparam(DropList)) :-
597 get_texpr_id(TId,Id),
598 member(TId,DroppedParams),!,
599 get_texpr_info(TId,Info),
600 member(droppedby(DropList),Info),!.
601
602 conjunct_guards([],truth(none)).
603 conjunct_guards([H|T],Result) :- conjunct_guards2(T,H,Result).
604 conjunct_guards2([],G,G).
605 conjunct_guards2([H|T],G,Result) :- conjunct_guards2(T,conjunct(none,G,H),Result).
606
607 /*
608 parallel_actions(Actions,Pos,Action) :-
609 ( Actions = [] -> Action = skip(Pos)
610 ; Actions = [S] -> Action = S
611 ; Action = parallel(Pos,Actions)).
612 */
613
614 % eventb becomes_such uses primed identifiers: distinguish it from normal becomes_such
615 % ast_cleanup will translate it back to becomes_such, but with $0 instead of primes (so that it conforms to classical B)
616 adapt_becomes_such(becomes_such(Pos,Ids,Pred),evb2_becomes_such(Pos,Ids,Pred)) :- !.
617 adapt_becomes_such(Subst,Subst).
618
619 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
620 % convert B project to classical B machine
621
622 :- use_module(bmachine_structure,[create_machine/2]).
623
624 convert_event_b(Main,Freetypes,Ops,Contextes,Models,AnimationChain,Machine) :-
625 debug_println(9,'Converting to classical B'),
626 select_models(AnimationChain,Models,AnimatedModels),
627 % todo: access to private elements of bmachine_construction
628 create_machine(Main,Empty),
629 convert_event_b2(Freetypes,Ops,AnimatedModels,Contextes,AnimationChain,
630 Empty,Machine),!.
631 convert_event_b(Main,Freetypes,Ops,Contextes,Models,AnimationChain,Machine) :-
632 add_failed_call_error(convert_event_b(Main,Freetypes,Ops,Contextes,Models,AnimationChain,Machine)),
633 fail.
634 convert_event_b2(Freetypes,Ops,AnimatedModels,Contextes,AnimationChain) -->
635 append_to_section(freetypes,Freetypes),
636 %{format('Appending freetypes: ~w~n',[Freetypes])},
637 append_to_section(operators,Ops),
638 %{format('Appending operators: ~w~n',[Ops])},
639 create_constants(AnimatedModels,Contextes,AnimatedContextNames),
640 {append(AnimatedContextNames,AnimationChain,AnimatedSectionNames)},
641 create_variables(AnimatedModels,AnimatedSectionNames),
642 create_events(AnimatedModels,AnimatedSectionNames),
643 create_animated_section_info(AnimatedContextNames,AnimationChain).
644
645 create_animated_section_info(Contextes,Models) -->
646 {reverse(Models,FromAbstractToConcrete),
647 maplist(mark_as_model,FromAbstractToConcrete,MarkedModels),
648 maplist(mark_as_context,Contextes,MarkedContextes),
649 append(MarkedContextes,MarkedModels,Sections)},
650 append_to_section(meta,[animated_sections(Sections)]).
651
652 mark_as_model(Name,model(Name)).
653 mark_as_context(Name,context(Name)).
654
655 /*
656 get_operation_identifiers([],[]).
657 get_operation_identifiers([TExpr|Rest],[Id|IdRest]) :-
658 get_texpr_expr(TExpr,operation(Id,_,_,_)),
659 get_operation_identifiers(Rest,IdRest).
660 */
661
662 create_variables(Models,AnimatedSectionNames) -->
663 {collect_model_infos(Models,AnimatedSectionNames,Variables,Invariants,Theorems)},
664 append_to_section(abstract_variables,Variables),
665 conjunct_to_section(invariant,Invariants),
666 append_to_section(assertions,Theorems).
667
668 select_contexts([],_Contexts,[]).
669 select_contexts([Name|NRest],Contexts,[Context|CRest]) :-
670 internal_context(Context,Name),
671 memberchk(Context,Contexts),
672 select_contexts(NRest,Contexts,CRest).
673
674 select_models([],_Models,[]).
675 select_models([Name|NRest],Models,[Model|MRest]) :-
676 internal_model(Model,Name), memberchk(Model,Models),
677 select_models(NRest,Models,MRest).
678
679 % collect_model_infos(Models,Variables,Invariants,Theorems):
680 % collect all variables, invariants and theorems of the given models
681 collect_model_infos([],_,[],[],[]) :- !.
682 collect_model_infos(Models,AnimatedSectionNames,Vars,Invs,Thms) :-
683 collect_model_infos2(Models,AnimatedSectionNames,AllVars,Vars1,Invs,Thms),
684 % add to every variable the information in which models
685 % it is present
686 add_var_model_occurrences(Vars1,AllVars,Vars).
687 collect_model_infos2([],_,[],[],[],[]).
688 collect_model_infos2([Model|MRest],AnimatedSectionNames,Vars,NewVars,Invs,Thms) :-
689 internal_model_vars(Model,_,LVars), append(LVars,RVars,Vars),
690 % use only newly introduced variables of a model, to prevent
691 % double declarations
692 % in case of a limited animation chain, it is important to introduce
693 % all variables for the most abstract model
694 (MRest == [] -> LNewVars = LVars ; internal_model_newvars(Model,_,LNewVars)),
695 append(LNewVars,RNewVars,NewVars),
696 internal_model_invs(Model,_,LInvs1), append_stripped_predicates(LInvs1,AnimatedSectionNames,RInvs,Invs),
697 internal_model_thms(Model,_,LThms1), append_stripped_predicates(LThms1,AnimatedSectionNames,RThms,Thms),
698 collect_model_infos2(MRest,AnimatedSectionNames,RVars,RNewVars,RInvs,RThms).
699 add_var_model_occurrences([],_,[]).
700 add_var_model_occurrences([Var|Vrest],AllVars,[MVar|Mrest]) :-
701 add_var_model_occurrence(Var,AllVars,MVar),
702 add_var_model_occurrences(Vrest,AllVars,Mrest).
703 add_var_model_occurrence(Var,AllVars,MVar) :-
704 findall(Section,
705 ( find_identifier_in_list(Var,AllVars,M),
706 get_texpr_info(M,Infos),
707 member(section(Section),Infos)),
708 Sections),
709 reverse(Sections,FromAbstractToConcrete),
710 add_texpr_infos(Var,[occurrences(FromAbstractToConcrete)],MVar).
711 append_stripped_predicates(PredsIn,AnimatedSectionNames,RestPreds,Preds) :-
712 remove_linking_parts(PredsIn,AnimatedSectionNames,LPreds),
713 append(LPreds,RestPreds,Preds).
714
715 all_used_contextes(AnimatedModels,Contextes,Sees) :-
716 ( AnimatedModels = [] ->
717 all_context_names(Contextes,Sees)
718 ;
719 collect_sees(AnimatedModels,Sees)).
720 all_context_names([],[]).
721 all_context_names([Context|Crest],[Name|Nrest]) :-
722 internal_context(Context,Name),
723 all_context_names(Crest,Nrest).
724 collect_sees([],[]).
725 collect_sees([Model|MRest],Sees) :-
726 internal_model_sees(Model,_,LocalSees), append(LocalSees,RestSees,Sees),
727 collect_sees(MRest,RestSees).
728
729 create_constants(AnimatedModels,Contextes,AnimatedContextNames) -->
730 {all_used_contextes(AnimatedModels,Contextes,Sees),
731 get_constants(Sees,Contextes,DefSets,EnumSets,EnumElems,Constants,AbstractConstants,Axioms,Theorems,AnimatedContextNames)},
732 append_to_section(deferred_sets,DefSets),
733 append_to_section(enumerated_sets,EnumSets),
734 append_to_section(enumerated_elements,EnumElems),
735 append_to_section(concrete_constants,Constants),
736 append_to_section(abstract_constants,AbstractConstants),
737 conjunct_to_section(properties,Axioms),
738 append_to_section(assertions,Theorems).
739
740 get_constants(Sees,Contextes,DefSets,EnumSets,EnumElems,Constants,AbstractConstants,Axioms,Theorems,AllContextNames) :-
741 transitive_contextes(Sees,Contextes,AllContextNames),
742 select_contexts(AllContextNames,Contextes,AllContextes),
743 collect_context_infos(AllContextes,Sets,Constants1,AbstractConstants,Axioms1,Theorems),
744 enumerated_deferred_sets(Sets,Constants1,Axioms1,DefSets,Constants,Axioms,
745 EnumSets,EnumElems).
746
747 collect_context_infos([],[],[],[],[],[]).
748 collect_context_infos([context(Name,_Ex,LSets1,LCsts1,LAbsCsts1,LAxms,LThms)|Rest],Sets,Constants,AbstractConstants,Axioms,Theorems) :-
749 add_context_occurrences(LSets1,Name,LSets),
750 add_context_occurrences(LCsts1,Name,LCsts),
751 add_context_occurrences(LAbsCsts1,Name,LAbsCsts),
752 append(LSets,RSets,Sets),
753 append(LCsts,RCsts,Constants),
754 append(LAbsCsts,RAbsCsts,AbstractConstants),
755 append(LAxms,RAxms,Axioms),
756 append(LThms,RThms,Theorems),
757 collect_context_infos(Rest,RSets,RCsts,RAbsCsts,RAxms,RThms).
758 add_context_occurrences([],_,[]).
759 add_context_occurrences([Constant|Crest],Name,[CC|CCrest]) :-
760 add_texpr_infos(Constant,[occurrences([Name])],CC),
761 add_context_occurrences(Crest,Name,CCrest).
762
763
764 % merge the events and write them to a machine
765 create_events(AnimatedModels,AnimatedSectionNames) -->
766 {get_events(AnimatedModels,AnimatedSectionNames,Events,Initialisation,Promoted)},
767 append_to_section(operation_bodies,Events),
768 bmachine_construction:write_section(initialisation,Initialisation),
769 append_to_section(promoted,Promoted).
770
771 % merge the events of multiple refinement levels
772 get_events([],_,[],Initialisation,[]) :- !,
773 create_texpr(skip,subst,[],Initialisation).
774 get_events(AnimatedModels,AnimatedSectionNames,Events,Initialisation,Promoted) :-
775 get_events_to_animate(AnimatedModels,AnimEvents),
776 merge_refinement_levels(AnimEvents,AnimatedModels,AnimatedSectionNames,MergedEvents,Promoted1),
777 remove_initialisation(Promoted1,Promoted2),
778 add_op_parenthesis(Promoted2,Promoted),
779 select_initialisation(MergedEvents,PreOps,Initialisation),
780 create_operations(PreOps,Events).
781 remove_initialisation(In,Out) :-
782 get_texpr_id(Expr,'INITIALISATION'),
783 select(Expr,In,Out),!.
784 remove_initialisation(In,Out) :-
785 % add_error(check_event_b_project,'Model has no INITIALISATION'), %err msg already generated below
786 Out=In.
787 add_op_parenthesis([],[]).
788 add_op_parenthesis([Old|ORest],[New|NRest]) :-
789 def_get_texpr_id(Old,Id),
790 rename_bt(Old,[rename(Id,op(Id))],New),
791 add_op_parenthesis(ORest,NRest).
792
793 select_initialisation(In,Ops,Init) :-
794 select(eventop('INITIALISATION',Section,[],Init1,op([],[]),_),In,Ops),!,
795 add_texpr_infos(Init1,[eventb(Section)],Init).
796 select_initialisation(In,Ops,Init) :-
797 add_error(select_initialisation,'Model has no INITIALISATION'),
798 Init = b(skip,subst,[]), % replace skip by non-det assign
799 Ops=In.
800 create_operations([],[]).
801 create_operations([E|ERest],[O|ORest]) :-
802 create_operation(E,O),
803 create_operations(ERest,ORest).
804 create_operation(eventop(Name,Section,Parameters,Subst,Type,Refines),Operation) :-
805 create_texpr(identifier(op(Name)),Type,[],Id),
806 get_texpr_info(Subst,SubstInfo),
807 Mod=modifies(_),memberchk(Mod,SubstInfo),
808 Reads=reads(_),memberchk(Reads,SubstInfo),
809 (Refines == [] -> RefInfo = RestInfo ; RefInfo = [refines(Refines)|RestInfo]),
810 (extract_description(Subst,Desc) -> RestInfo = [description(Desc)] ; RestInfo=[]), % we could also do a findall
811 create_texpr(operation(Id,[],Parameters,Subst),Type,[eventb(Section),Mod,Reads|RefInfo],Operation).
812
813 :- use_module(probsrc(bsyntaxtree),[get_texpr_description/2, get_texpr_labels/2]).
814 extract_description(Subst,Desc) :-
815 get_texpr_description(Subst,Desc).
816 extract_description(Subst,Desc) :- get_direct_abstract_event(Subst,ASubst),
817 extract_description(ASubst,Desc).
818
819 get_direct_abstract_event(b(RefLvlEvent,subst,_),AbsEvent) :-
820 RefLvlEvent = rlevent(_Name,_Sect,_Stat,_Paras,_Grd,_Thm,_Act,_VWit,_PWit,_Unmod,AbsEvents),
821 member(AbsEvent,AbsEvents).
822
823 get_events_to_animate([Model|_],Events) :- internal_model_events(Model,_,Events).
824
825 merge_refinement_levels([],_,_,[],[]).
826 merge_refinement_levels([Event|ERest],AnimModels,AnimatedSectionNames,[Merged|MRest],[Prom|PRest]) :-
827 merge_refinement_levels2(Event,AnimModels,AnimatedSectionNames,Merged,Prom),
828 merge_refinement_levels(ERest,AnimModels,AnimatedSectionNames,MRest,PRest).
829
830 merge_refinement_levels2(Event,AnimatedLevels,AnimatedSectionNames,
831 eventop(Name,Section,Parameters,Subst,OpType,Refines),Prom) :-
832 AnimatedLevels = [CurrentLevel|_Abstractions],
833 internal_model(CurrentLevel,Section),
834 internal_event_params(Event,Name,Parameters),
835 internal_event_refined(Event,Name,Refines),
836 %merge_parameters(Refines,Parameters,_Abstractions,MergedParameters),
837 merge_events_to_subst(Name,AnimatedLevels,AnimatedSectionNames,[],Subst1),
838 optimise_events(Subst1,Subst),
839 get_texpr_types(Parameters,Types),OpType = op(Types,[]),
840 create_texpr(identifier(Name),OpType,[],Prom).
841
842 gen_description_term(Desc,description(Desc)).
843
844 merge_events_to_subst(Name,[CurrentLevel|Abstractions],AnimatedSectionNames,RefinedParameters,TEvent) :-
845 create_texpr(RefLevelEvent,subst,[modifies(Vars),reads(Reads)|RestInfos],TEvent),
846 RefLevelEvent = rlevent(Name,Section,Status,Params,Guard,Theorems,Actions,
847 VWitnesses,PWitnesses,Unmodifiables,AbstractEvents),
848 InternalEvent = tc_event(Name,Section,Status,AllParams,Guard,Theorems,Actions,
849 VWitnesses1,PWitnesses1,Unmodifiables,Refines,Desc),
850 get_event_from_model(Name,CurrentLevel,InternalEvent),
851 strip_witnesses(VWitnesses1,AnimatedSectionNames,VWitnesses),
852 strip_witnesses(PWitnesses1,AnimatedSectionNames,PWitnesses),
853 remove_refined_parameters(AllParams,RefinedParameters,Params),
854 maplist(gen_description_term,Desc,RestInfos),
855 ( Abstractions = [] ->
856 AbstractEvents = []
857 ;
858 append(RefinedParameters,Params,NewRefinedParameters),
859 merge_events_to_subst_l(Refines,Abstractions,AnimatedSectionNames,NewRefinedParameters,AbstractEvents1),
860 normalise_merged_events(AbstractEvents1,AbstractEvents)
861 ),
862 collect_modified_vars(Actions,AbstractEvents,Vars),
863 collect_read_vars(Status,AllParams,Guard,Theorems,Actions,VWitnesses,PWitnesses,Unmodifiables,AbstractEvents,Reads).
864 merge_events_to_subst_l([],_,_,_,[]).
865 merge_events_to_subst_l([Name|NRest],Abstractions,AnimatedSectionNames,RefinedParameters,[TEvent|TRest]) :-
866 merge_events_to_subst(Name,Abstractions,AnimatedSectionNames,RefinedParameters,TEvent),
867 merge_events_to_subst_l(NRest,Abstractions,AnimatedSectionNames,RefinedParameters,TRest).
868
869 % removes a witness completely if the witnessed variable belongs
870 % to a refinement level that is not animated or removes part of the
871 % witness-predicate if references to not animated levels are made.
872 strip_witnesses([],_AnimatedSectionNames,[]).
873 strip_witnesses([Witness|WRest],AnimatedSectionNames,Result) :-
874 strip_witness(Witness,AnimatedSectionNames,StrippedWitness),
875 append(StrippedWitness,SWRest,Result),
876 strip_witnesses(WRest,AnimatedSectionNames,SWRest).
877 strip_witness(Witness,AnimatedSectionNames,StrippedWitness) :-
878 get_texpr_expr(Witness,witness(W,P)),
879 ( abstraction_var_occures(W,AnimatedSectionNames) ->
880 % The abstract variable is not animated, skip the complete witness
881 StrippedWitness = []
882 ;
883 conjunction_to_list(P,Preds),
884 remove_linking_parts(Preds,AnimatedSectionNames,SPreds),
885 conjunct_predicates(SPreds,SP),
886 get_texpr_type(Witness,Type),
887 get_texpr_info(Witness,Info),
888 create_texpr(witness(W,SP),Type,Info,TWitness),
889 StrippedWitness = [TWitness]).
890
891 remove_refined_parameters([],_RefinedParameters,[]).
892 remove_refined_parameters([Param|APRest],RefinedParameters,Parameters) :-
893 ( find_identifier_in_list(Param,RefinedParameters,_RefParam) ->
894 Parameters = PRest
895 ;
896 Parameters = [Param|PRest]),
897 remove_refined_parameters(APRest,RefinedParameters,PRest).
898
899 /* currently commented out :
900 merge_parameters([],Parameters,_Abstractions,Parameters).
901 merge_parameters([_|_],Parameters,[],Parameters) :- !.
902 merge_parameters([Refines|Rest],OldParameters,Abstractions,Parameters) :-
903 Abstractions = [Abstract|FurtherAbstractions],
904 get_event_from_model(Refines,Abstract,Event),
905 internal_event_params(Event,_,NewParameters),
906 internal_event_refined(Event,_,NewRefines),
907 add_unique_parameters(NewParameters,OldParameters,Parameters2),
908 merge_parameters(NewRefines,Parameters2,FurtherAbstractions,Parameters3),
909 merge_parameters(Rest,Parameters3,Abstractions,Parameters).
910 add_unique_parameters([],Parameters,Parameters).
911 add_unique_parameters([P|PRest],InParameters,OutParameters) :-
912 ( find_identifier_in_list(P,InParameters,_) ->
913 !,Parameters = InParameters
914 ;
915 Parameters = [P|InParameters]),
916 add_unique_parameters(PRest,Parameters,OutParameters).
917 */
918
919 get_event_from_model(Name,Model,Event) :-
920 internal_model_events(Model,_,Events),
921 internal_event(Event,Name),
922 member(Event,Events),!.
923
924 collect_modified_vars(Actions,Events,Vars) :-
925 get_modified_vars_of_actions(Actions,M1),
926 append_modified_vars_of_events(Events,M2),
927 append(M1,M2,M3),sort(M3,Vars).
928 get_modified_vars_of_actions([],[]).
929 get_modified_vars_of_actions([Action|Arest],Vars) :-
930 get_modified_vars_of_action(Action,Vlocal),
931 append(Vlocal,Vrest,Vars),
932 get_modified_vars_of_actions(Arest,Vrest).
933 get_modified_vars_of_action(Action,Vars) :-
934 get_texpr_info(Action,Infos),
935 member(modifies(Vars), Infos),!.
936
937 add_modified_vars_to_actions([],[]).
938 %add_modified_vars_to_actions([TAction|ARest],MRest) :-
939 % get_texpr_expr(TAction,skip),!, % remove skip actions % for Daniel: is this better than keeping them ??
940 % add_modified_vars_to_actions(ARest,MRest).
941 add_modified_vars_to_actions([TAction|ARest],[MAction|MRest]) :-
942 (add_modified_vars_to_action(TAction,MAction) ->true
943 ; add_internal_error('Call failed: ',add_modified_vars_to_action(TAction,MAction)),
944 MAction = TAction),
945 add_modified_vars_to_actions(ARest,MRest).
946 add_modified_vars_to_action(TAction,MAction) :-
947 get_lhs_ids(TAction,Vars),
948 maplist(prime_id,Vars,Primed),
949 add_texpr_infos(TAction,[assigned_after(Primed),modifies(Vars)],MAction).
950
951 get_lhs_ids(TAction,Ids) :-
952 get_lhs_tids(TAction,Vars),
953 get_texpr_ids(Vars,Ids).
954 get_lhs_tids(TAction,Vars) :-
955 get_texpr_expr(TAction,Action),
956 split_lhs_rhs(Action,Lhs,_),
957 extract_lhs_ids(Lhs,Vars).
958
959 split_lhs_rhs(skip,[],[]). % not needed as skip removed above
960 split_lhs_rhs(assign(Ids,Exprs),Ids,Exprs).
961 split_lhs_rhs(assign_single_id(Id,Expr),[Id],[Expr]).
962 split_lhs_rhs(becomes_element_of(Ids,Expr),Ids,[Expr]).
963 split_lhs_rhs(becomes_such(Ids,Pred),Ids,[Pred]).
964 split_lhs_rhs(evb2_becomes_such(Ids,Pred),Ids,[Pred]).
965 extract_lhs_ids([],[]).
966 extract_lhs_ids([TId|TRest],[Var|VRest]) :-
967 extract_lhs_id(TId,Var),
968 extract_lhs_ids(TRest,VRest).
969 extract_lhs_id(Id,Var) :-
970 get_texpr_id(Id,_),!,Var=Id.
971 extract_lhs_id(Func,Var) :-
972 get_texpr_expr(Func,function(Id,_)),
973 get_texpr_id(Id,Var).
974
975 append_modified_vars_of_events(Events,Vars) :-
976 append_modified_vars_of_events2(Events,Unsorted),
977 sort(Unsorted,Vars).
978 append_modified_vars_of_events2([],[]).
979 append_modified_vars_of_events2([TEvent|ERest],Vars) :-
980 get_modified_vars_of_event(TEvent,Local),
981 append(Local,VRest,Vars),
982 append_modified_vars_of_events2(ERest,VRest).
983 get_modified_vars_of_event(TEvent,Local) :-
984 get_texpr_info(TEvent,Info),
985 memberchk(modifies(Local),Info).
986
987 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
988 % get all the variables that are accessed in an event (cf also get_accessed_vars2 in b_read_write_info.pl)
989 collect_read_vars(Status,AllParams,Guard,Theorems,Actions,VWitnesses,PWitnesses,Unmodifiables,AbstractEvents,Reads) :-
990 find_variant_reads([],Status,VariantVars), % the variant cannot use params (!?)
991 get_texpr_ids(AllParams,Params), % access to parameters is not reading a variable
992 find_identifier_uses(Guard,Params,GrdVars),
993 find_identifier_uses_l(Theorems,Params,ThmVars),
994 find_identifier_uses_l(Unmodifiables,Params,UnmodVars), % for check_if_invalid_vars_are_modified we need read access
995 maplist(find_all_action_reads(Params),Actions,ActVars0), ord_union(ActVars0, ActVars),
996 maplist(find_all_witness_reads(Params),VWitnesses,VWitVars0), ord_union(VWitVars0,VWitVars),
997 maplist(find_all_witness_reads(Params),PWitnesses,PWitVars0), ord_union(PWitVars0,PWitVars),
998 join_abstract_reads(AbstractEvents,AbstrVars),
999 ord_union([VariantVars,GrdVars,ThmVars,UnmodVars,ActVars,VWitVars,PWitVars,AbstrVars],Reads).
1000
1001 find_variant_reads(Ignore,TVariant,Res) :-
1002 get_texpr_expr(TVariant,Variant),
1003 (find_variant_reads2(Variant,Ignore,Vars) -> Res=Vars
1004 ; add_internal_error('Illegal variant: ',find_variant_reads2(Variant,Ignore,_)),Res=[]).
1005 find_variant_reads2(convergent(TExpr),Ignore,Vars) :- find_identifier_uses(TExpr,Ignore,Vars).
1006 find_variant_reads2(anticipated(TExpr),Ignore,Vars) :- find_identifier_uses(TExpr,Ignore,Vars).
1007 find_variant_reads2(ordinary,_,[]).
1008
1009 %find_all_identifiers(Ignore,Expr,Vars) :-
1010 % find_identifier_uses(Expr,Ignore,Vars). % Just switch arguments to allow the use of maplist
1011 find_all_action_reads(Ignore,TAction,Res) :-
1012 get_texpr_expr(TAction,Action),
1013 (find_action_reads2(Action,Ignore,Vars) -> Res=Vars
1014 ; add_internal_error('Illegal action: ',find_action_reads2(Action,Ignore,_)),Res=[]).
1015 find_action_reads2(skip,_,Vars) :- Vars=[].
1016 find_action_reads2(assign(_,Exprs),Ignore,Vars) :- find_identifier_uses_l(Exprs,Ignore,Vars).
1017 find_action_reads2(assign_single_id(_,Expr),Ignore,Vars) :- find_identifier_uses(Expr,Ignore,Vars).
1018 find_action_reads2(becomes_element_of(_,Expr),Ignore,Vars) :- find_identifier_uses(Expr,Ignore,Vars).
1019 find_action_reads2(becomes_such(Ids,Pred),Ignore,Vars1) :-
1020 % all references to Ids are to the state after: not a read
1021 get_texpr_ids(Ids,AtomicIds),
1022 append(AtomicIds,Ignore,Ignore0),sort(Ignore0,Ignore1),
1023 find_identifier_uses(Pred,Ignore1,Vars),
1024 prime_identifiers0(Ids,Ids0), % Ids with $0 afterwards
1025 get_texpr_ids(Ids0,AtomicIds0),
1026 maplist(unprime_id(AtomicIds0,AtomicIds),Vars,Vars1).
1027 %find_action_reads2(evb2_becomes_such(Ids,Pred),Ignore,Vars) :-
1028 % prime_variables(Ids,PIds),get_texpr_ids(PIds,Primes),
1029 % append(Primes,Ignore,Ignore0),sort(Ignore0,Ignore1),
1030 % find_identifier_uses(Pred,Ignore1,Vars).
1031 find_all_witness_reads(Ignore,Witness,Vars) :-
1032 get_texpr_expr(Witness,witness(I,P)),
1033 get_texpr_id(I,Id),
1034 sort([Id|Ignore],Ignore2),
1035 find_identifier_uses(P,Ignore2,Vars1),
1036 % a small hack to remove the primed variables that refer to the after-state
1037 % without the need to put all variables in the Ingore list:
1038 exclude(is_primed_id,Vars1,Vars).
1039
1040 join_abstract_reads([],[]) :- !.
1041 join_abstract_reads(AbstractEvents,Reads) :-
1042 maplist(get_read_from_info,AbstractEvents,AbsReads),
1043 ord_union(AbsReads,ReadBySome),
1044 maplist(get_modifies_from_info,AbstractEvents,AbsModifies),
1045 ord_union(AbsModifies,ModifiedBySome),
1046 ord_intersection(AbsModifies,ModifiedByAll),
1047 ord_subtract(ModifiedBySome,ModifiedByAll,ModifiedByNotAll),
1048 ord_union(ReadBySome,ModifiedByNotAll,Reads).
1049 get_read_from_info(AbstrEvents,Reads) :-
1050 get_texpr_info(AbstrEvents,Info),memberchk(reads(Reads),Info).
1051 get_modifies_from_info(AbstrEvents,Modifies) :-
1052 get_texpr_info(AbstrEvents,Info),memberchk(modifies(Modifies),Info).
1053
1054 add_equality_check(Actions,AbstractActions,NewVars,Variables,Unmodifiables) :-
1055 get_modified_vars_of_actions(Actions,Modified),
1056 get_modified_vars_of_actions(AbstractActions,AbstractModified),
1057 unmodifiables(Modified,AbstractModified,NewVars,Variables,Unmodifiables).
1058 unmodifiables([],_AbstractModified,_NewVars,_Variables,[]).
1059 unmodifiables([UM|Modified],AbstractModified,NewVars,Variables,Unmodifiables) :-
1060 ( is_modifiable(UM,AbstractModified,NewVars) ->
1061 Unmodifiables = UMrest
1062 ;
1063 get_texpr_id(TUM,UM),
1064 member(TUM,Variables),!,
1065 Unmodifiables = [TUM|UMrest]),
1066 unmodifiables(Modified,AbstractModified,NewVars,Variables,UMrest).
1067 % the abstract event modifies it, so we can do it, too
1068 is_modifiable(UM,AbstractModified,_NewVars) :- member(UM,AbstractModified),!.
1069 % the variables is newly introduced, so we can modifiy it
1070 is_modifiable(UM,_AbstractModified,NewVars) :-
1071 get_texpr_id(TUM,UM), member(TUM,NewVars).
1072
1073 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1074 % normalising merged events means that if two refined events A and B
1075 % change a different set of variables then the event A gets an additional
1076 % assignment of the form x:=x with x as a variable that is changed in B
1077 % but not in A.
1078 % This can happen even though merged events have the same assignments because
1079 % they again can refine events that have different assignments.
1080
1081 % None or one refined event do not have to be normalised
1082 normalise_merged_events([],[]) :- !.
1083 normalise_merged_events([E],[E]) :- !.
1084 normalise_merged_events(Events,Normalised) :-
1085 append_modified_vars_of_events(Events,AllModifiedVars),
1086 find_typed_version_in_events(AllModifiedVars,Events,TypedVars),
1087 normalise_merged_events2(Events,AllModifiedVars,TypedVars,Normalised).
1088 normalise_merged_events2([],_AllModifiedVars,_TypedVars,[]).
1089 normalise_merged_events2([Event|Erest],AllModifiedVars,TypedVars,[Normalised|Nrest]) :-
1090 normalise_merged_event(Event,AllModifiedVars,TypedVars,Normalised),
1091 normalise_merged_events2(Erest,AllModifiedVars,TypedVars,Nrest).
1092 normalise_merged_event(Event,AllModifiedVars,TypedVars,Normalised) :-
1093 get_modified_vars_of_event(Event,Modified),
1094 remove_all(AllModifiedVars,Modified,MissingVars),
1095 add_missing_assignments(MissingVars,Event,AllModifiedVars,TypedVars,Normalised).
1096 add_missing_assignments([],Event,_,_,Event) :- !.
1097 add_missing_assignments(MissingVars,TEvent,AllModifiedVars,TypedVars,Normalised) :-
1098 get_texpr_expr(TEvent,Event),
1099 get_texpr_type(TEvent,Type),
1100 get_texpr_info(TEvent,Infos),
1101 selectchk(modifies(_),Infos,RestInfos), % TO DO: also add reads Information
1102 create_texpr(NewEvent,Type,[modifies(AllModifiedVars)|RestInfos],Normalised),
1103 Event = rlevent(Name,Sec,St,Prm,Grd,Thm,Actions,VWit,PWit,Unmod,AbsEvents),
1104 NewEvent = rlevent(Name,Sec,St,Prm,Grd,Thm,NewActions,VWit,PWit,Unmod,AbsEvents),
1105 append(Actions,NewAssignments,NewActions),
1106 create_missing_assignments(MissingVars,TypedVars,NewAssignments).
1107 create_missing_assignments([],_TypedVars,[]).
1108 create_missing_assignments([MissingVar|Mrest],TypedVars,[Assign|Arest]) :-
1109 create_missing_assignment(MissingVar,TypedVars,Assign),
1110 create_missing_assignments(Mrest,TypedVars,Arest).
1111 create_missing_assignment(Var,TypedVars,Assignment) :-
1112 get_texpr_id(TId,Var),
1113 memberchk(TId,TypedVars),
1114 prime_id(Var,Primed),
1115 create_texpr(assign([TId],[TId]),subst,[assigned_after(Primed),modifies(Var)],Assignment).
1116
1117 find_typed_version_in_events([],_Events,[]).
1118 find_typed_version_in_events([Name|Nrest],Events,[Typed|Trest]) :-
1119 find_typed_version_in_events2(Name,Events,Typed),
1120 find_typed_version_in_events(Nrest,Events,Trest).
1121 find_typed_version_in_events2(Name,Events,Typed) :-
1122 get_texpr_id(Typed,Name),
1123 member(Event,Events),
1124 get_texpr_expr(Event,rlevent(_Name,_Sec,_St,_Prm,_Grd,_Thm,Actions,_VWit,_PWit,_Unmod,AbsEvents)),
1125 find_typed_version_in_events3(Name,Actions,AbsEvents,Typed),!.
1126 find_typed_version_in_events3(_Name,Actions,_AbsEvents,Typed) :-
1127 member(Action,Actions),
1128 get_lhs_tids(Action,Vars),
1129 member(Typed,Vars),!.
1130 find_typed_version_in_events3(Name,_Actions,AbsEvents,Typed) :-
1131 find_typed_version_in_events2(Name,AbsEvents,Typed).
1132
1133 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1134 % optimisation of guards:
1135 % A guard in a refinement does not need to be evaluated in in an abstract event
1136 % again. This happens quiet frequently, especially if "extends" is used.
1137 % The same applies for assignments: If in a refinement an action is performed,
1138 % we do not have to check if the same action can be performed in a more abstract
1139 % level.
1140 optimise_events(TEvent,NTEvent) :-
1141 empty_avl(Empty),
1142 optimise_events2(Empty,TEvent,NTEvent).
1143 optimise_events2(KnownElements,TEvent,NTEvent) :-
1144 create_texpr(Event,Type,Infos,TEvent),
1145 create_texpr(NewEvent,Type,Infos,NTEvent),
1146 Event = rlevent(Name,Section,Status,Params,OldGuard,OldTheorems,OldActions,
1147 VWitnesses,PWitnesses,Unmodifiables,OldAbstractEvents),
1148 NewEvent = rlevent(Name,Section,Status,Params,NewGuard,NewTheorems,NewActions,
1149 VWitnesses,PWitnesses,Unmodifiables,NewAbstractEvents),
1150 optimise_guards(OldGuard,OldTheorems,KnownElements,NewGuard,NewTheorems,KnownElements1),
1151 optimise_formulas(OldActions,KnownElements1,NewActions,NewKnownElements),
1152 maplist(optimise_events2(NewKnownElements),OldAbstractEvents,NewAbstractEvents).
1153 optimise_guards(OldGuard,OldTheorems,KnownElements,NewGuard,NewTheorems,NewKnownElements) :-
1154 conjunction_to_list(OldGuard,OldGuards),
1155 optimise_formulas(OldGuards,KnownElements,NewGuards,KnownElements1),
1156 % If no elements were removed, we just use the old guard
1157 (OldGuards=NewGuards -> OldGuard=NewGuard ; conjunct_predicates(NewGuards,NewGuard)),
1158 optimise_formulas(OldTheorems,KnownElements1,NewTheorems,NewKnownElements).
1159 % optimise_formulas(+AllFormulas,+KnownElements,-NewFormulas,-NewNormed)
1160 % AllFormulas: A list of formulas
1161 % KnownElementes: A list of normed versions of already encountered elements
1162 % NewFormulas: A sub-list of AllFormulas which are new (not in KnownElements)
1163 % NewKnownElements: The updated list of already encountered elements
1164 % If no formulas are removed, it is guaranteed that NewFormulas=AllFormulas
1165 optimise_formulas(AllFormulas,KnownElements,NewFormulas,NewKnownElements) :-
1166 % convert formulas to a list: Formula/Normed where Normed is a normalised form
1167 maplist(add_stripped_ast,AllFormulas,AllFormNormed),
1168 % remove the already known formulas
1169 exclude(is_duplicate_formula(KnownElements),AllFormNormed,NewFormNormed),
1170 % split the list [Form/Normed] into [Form] and [Normed]
1171 maplist(unzipslash,NewFormNormed,NewFormulas1,NewNormed),
1172 ( AllFormNormed = NewFormNormed -> % No formulas removed, keep everything as it is
1173 NewFormulas = AllFormulas
1174 ;
1175 NewFormulas = NewFormulas1
1176 ),
1177 foldl(add_to_known_elements,NewNormed,KnownElements,NewKnownElements).
1178 add_stripped_ast(Formula,Formula/Stripped) :-
1179 strip_and_norm_ast(Formula,Stripped).
1180 is_duplicate_formula(KnownElements,_Formula/Stripped) :-
1181 avl_fetch(Stripped,KnownElements). % remark: if some ast_cleanup operations introduce fresh identifiers (e.g., comp_result) then we may not detect formulas as identical here !
1182 unzipslash(A/B,A,B).
1183 add_to_known_elements(New,In,Out) :-
1184 avl_store(New,In,true,Out).
1185
1186 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1187 % internal event handling (just data structure)
1188 internal_event(tc_event(Name,_Section,_Status,_Params,_Grd,_Thm,_Act,_VWit,_PWit,_Unmod,_Ref,_),Name).
1189 internal_event_status(tc_event(Name,_Section,Status,_Params,_Grd,_Thm,_Act,_VWit,_PWit,_Unmod,_Ref,_),Name,Status).
1190 internal_event_params(tc_event(Name,_Section,_Status,Params,_Grd,_Thm,_Act,_VWit,_PWit,_Unmod,_Ref,_),Name,Params).
1191 %internal_event_guards(tc_event(Name,_Section,_Status,_Params,Grd,_Thm,_Act,_VWit,_PWit,_Unmod,_Ref,_),Name,Grd).
1192 internal_event_actions(tc_event(Name,_Section,_Status,_Params,_Grd,_Thm,Act,_VWit,_PWit,_Unmod,_Ref,_),Name,Act).
1193 internal_event_refined(tc_event(Name,_Section,_Status,_Params,_Grd,_Thm,_Act,_VWit,_PWit,_Unmod,Ref,_),Name,Ref).
1194 %internal_event_description(tc_event(_,_,_,_,_,_,_,_,_,_,_,DescList),Desc) :- member(Desc,DescList).
1195
1196 internal_context(context(Name,_Extends,_Sets,_Constants,_AbstractConstants,_Axioms,_Theorems),Name).
1197 internal_context_extends(context(Name,Extends,_Sets,_Constants,_AbstractConstants,_Axioms,_Theorems),Name,Extends).
1198 internal_context_sets(context(Name,_Extends,Sets,_Constants,_AbstractConstants,_Axioms,_Theorems),Name,Sets).
1199 internal_context_constants(context(Name,_Extends,_Sets,Constants,_AbstractConstants,_Axioms,_Theorems),Name,Constants).
1200 internal_context_abstract_constants(context(Name,_Extends,_Sets,_Constants,AbstractConstants,_Axioms,_Theorems),Name,AbstractConstants).
1201
1202 internal_model(model(Name,_Refines,_Sees,_Variables,_NewVariables,_Invariants,_Theorems,_Events),Name).
1203 internal_model_refines(model(Name,Refines,_Sees,_Variables,_NewVariables,_Invariants,_Theorems,_Events),Name,Refines).
1204 internal_model_sees(model(Name,_Refines,Sees,_Variables,_NewVariables,_Invariants,_Theorems,_Events),Name,Sees).
1205 internal_model_vars(model(Name,_Refines,_Sees,Variables,_NewVariables,_Invariants,_Theorems,_Events),Name,Variables).
1206 internal_model_newvars(model(Name,_Refines,_Sees,_Variables,NewVariables,_Invariants,_Theorems,_Events),Name,NewVariables).
1207 internal_model_invs(model(Name,_Refines,_Sees,_Variables,_NewVariables,Invariants,_Theorems,_Events),Name,Invariants).
1208 internal_model_thms(model(Name,_Refines,_Sees,_Variables,_NewVariables,_Invariants,Theorems,_Events),Name,Theorems).
1209 internal_model_events(model(Name,_Refines,_Sees,_Variables,_NewVariables,_Invariants,_Theorems,Events),Name,Events).
1210
1211 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1212 % analyse deferred sets and generate enumerated sets if possible
1213
1214
1215
1216
1217 %% :- include(bmachine_eventb_common).
1218 %% code below used to be in separate file, as there was the single-level and multi-level mode:
1219
1220
1221
1222 extract_name(event_b_model(_,Name,_Sections),Res) :- !, Res=Name.
1223 extract_name(event_b_context(_,Name,_Sections),Res) :- !, Res=Name.
1224 extract_name(MODEL,_) :- add_error(extract_name,'Could not extract model name: ',MODEL),fail.
1225
1226 extract_sections(event_b_model(_,_Name,Sections),Sections).
1227 extract_sections(event_b_context(_,_Name,Sections),Sections).
1228
1229 % topological sort
1230
1231 topological_sort(List,Sorted) :-
1232 get_dependencies(List,Dependencies),
1233 topolsort(Dependencies,[],SortedNames),
1234 get_sorted(SortedNames,List,Sorted),!.
1235 topological_sort(List,Sorted) :- add_failed_call_error(topological_sort(List,Sorted)),fail.
1236
1237 get_dependencies([],[]).
1238 get_dependencies([E|Rest],[dep(Name,Deps)|Drest]) :-
1239 extract_name(E,Name),
1240 findall(D,dependency(E,D),Deps1),
1241 sort(Deps1,Deps),
1242 get_dependencies(Rest,Drest).
1243
1244 dependency(Elem,Dependend) :-
1245 extract_sections(Elem,Sections),
1246 ( rawmachine_section(extends,Sections,Extends),
1247 member(Dependend,Extends)
1248 ; rawmachine_section(refines,Sections,Dependend)).
1249
1250 topolsort([],_,[]) :- !.
1251 topolsort(Deps,Fulfilled,[First|Rest]) :-
1252 select(dep(First,Before),Deps,Drest),
1253 is_sublist(Before,Fulfilled),!,
1254 sort([First|Fulfilled],NewFulfilled),
1255 topolsort(Drest,NewFulfilled,Rest).
1256 is_sublist([],_).
1257 is_sublist([H|T],[F|R]) :-
1258 (H=F -> is_sublist(T,R) ; is_sublist([H|T],R)).
1259
1260 get_sorted([],_,[]).
1261 get_sorted([Name|Nrest],Elems,[First|Srest]) :-
1262 member(First,Elems),
1263 extract_name(First,Name),!,
1264 get_sorted(Nrest,Elems,Srest).
1265
1266 % copy&paste from bmachine_construction
1267 rawmachine_section(Elem,List,Result) :-
1268 functor(Pattern,Elem,2),
1269 arg(2,Pattern,Result),
1270 member(Pattern,List),!.
1271
1272 optional_rawmachine_section(Elem,List,Default,Result) :-
1273 ( rawmachine_section(Elem,List,Result1) -> true
1274 ; Result1=Default),
1275 Result1=Result.
1276
1277 % ----------------------------------------
1278
1279
1280 % older versions of the .eventb files do not have a status included
1281 raw_event(event(Pos,Name,RawRefines,Params,Guards,Actions,Witnesses), % event/7
1282 Pos,Name,ordinary(none),Refines,Params,Guards,[],Actions,Witnesses,[]) :-
1283 (\+((RawRefines==[] ; RawRefines=[_|_]))
1284 -> add_error(b_machine_eventb,'Outdated .eventb format, ignoring refines:',RawRefines),
1285 Refines = []
1286 ; Refines=RawRefines).
1287 raw_event(event(Pos,Name,Status,Refines,Params,Guards,Actions,Witnesses), % event/8
1288 Pos,Name,Status,Refines,Params,Guards,[],Actions,Witnesses,[]).
1289 raw_event(event(Pos,Name,Status,Refines,Params,Guards,Theorems,Actions,Witnesses), % event/9
1290 Pos,Name,Status,Refines,Params,Guards,Theorems,Actions,Witnesses,[]).
1291 raw_event(description_event(_,Desc,Event),
1292 Pos,Name,Status,Refines,Params,Guards,Theorems,Actions,Witnesses,[DescText|TD]) :-
1293 unwrap_desc_pragma(Desc,DescText),
1294 raw_event(Event, Pos,Name,Status,Refines,Params,Guards,Theorems,Actions,Witnesses,TD),
1295 debug_format(19,'New style event ~w with description "~w"~n',[Name,DescText]).
1296
1297 % new parser now has specific position info here:
1298 unwrap_desc_pragma(description_text(_Pos,Desc),Res) :- !, Res=Desc.
1299 unwrap_desc_pragma(D,D).
1300
1301 % code common to bmachine_eventb.pl and bmachine_eventb_ml.pl
1302
1303 :- use_module(bmachine_structure,[select_section/5]).
1304 append_to_section(Section,List,Old,New) :-
1305 % todo: access to private elements of bmachine_construction
1306 select_section(Section,OldList,NewList,Old,New),
1307 append(OldList,List,NewList).
1308 conjunct_to_section(Section,Preds,Old,New) :-
1309 % todo: access to private elements of bmachine_construction
1310 select_section(Section,OldPred,NewPred,Old,New),
1311 conjunct_predicates([OldPred|Preds],NewPred).
1312
1313 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1314 % analyse Event-B deferred sets and generate enumerated sets if possible
1315
1316 enumerated_deferred_sets(Sets,Constants,Axioms,NewSets,NewConstants,NewAxioms,TSet,TElements) :-
1317 conjunct_predicates(Axioms,Axiom),
1318 conjunction_to_list(Axiom,Axiom2),
1319 enumerated_deferred_sets2(Sets,Constants,Axiom2,NewSets,NewConstants,NewAxioms,TSet,TElements).
1320
1321 enumerated_deferred_sets2([],Csts,Axioms,[],Csts,Axioms,[],[]).
1322 enumerated_deferred_sets2([Set|SetRest],Csts,Axioms,NewSets,NewCsts,NewAxioms,[TSet|TSetRest],TElementsAll) :-
1323 % case 1: the set is an enumerated set
1324 enumerated_deferred_set(Set,Csts,Axioms,ICsts,IAxioms,TSet,TElements),!,
1325 append(TElements,TElementsRest,TElementsAll),
1326 enumerated_deferred_sets2(SetRest,ICsts,IAxioms,NewSets,NewCsts,NewAxioms,TSetRest,TElementsRest).
1327 enumerated_deferred_sets2([Set|SetRest],Csts,Axioms,[Set|NewSets],NewCsts,NewAxioms,TSets,TElements) :-
1328 % case 2: the set is a normal deferred set
1329 enumerated_deferred_sets2(SetRest,Csts,Axioms,NewSets,NewCsts,NewAxioms,TSets,TElements).
1330
1331 enumerated_deferred_set(Set,Constants,Axioms,NewConstants,NewAxioms,Set,TElements) :-
1332 %% print(checking_for_enumerated_deferred_sets(Axioms)),nl,
1333 has_enumeration_axioms(Set,Elements,Axioms,NewAxioms),
1334 %% print(found_enumerated_set(Set)),nl, %%
1335 % remove Elem1,...,ElemN from the constants
1336 remove_constants(Elements,Constants,NewConstants),
1337 % add enumerated set information to the elements
1338 get_texpr_type(Set,SType),
1339 (SType=set(global(Type)) -> true
1340 ; add_error_and_fail(enumerated_deferred_set,'Unexpected Set: ',(Set:SType))),
1341 (typeset_enumerated(Elements,Type,TElements) -> true
1342 ; add_error_and_fail(enumerated_deferred_set,'Could not typeset: ',(Type,Elements))).
1343
1344
1345 has_enumeration_axioms(Set,Elements,AxiomsIn,AxiomsOut) :-
1346 has_partition_axioms(Set,Elements,AxiomsIn,AxiomsOut),!.
1347 has_enumeration_axioms(Set,Elements,AxiomsIn,AxiomsOut) :-
1348 % there in an axiom Set = {Elem1,...,ElemN}
1349 select_equal_extension_set_of_ids(Set,AxiomsIn,Axioms1,ExtSet,Elements),
1350 % check if all axioms needed for an enumeration are
1351 % present, and remove them
1352 % second case: All elements of the set are mutually unequal
1353
1354 % generate the unequalities we have to check for
1355 generate_unequals(Elements,Unequals),
1356 % check if they are all in the axioms, and remove them from the axioms
1357 (all_unequals_present(Unequals,Axioms1,AxiomsOut) -> true
1358 ; assertz(deferred_set_eq_wo_enumeration_axioms(Set,ExtSet)),
1359 write('Deferred set with equality but *not* recognized as enumerated set: '),
1360 translate:print_bexpr(Set), write(' = '), translate:print_bexpr(ExtSet),nl,
1361 fail
1362 ).
1363
1364 has_partition_axioms(Set,PartitionElements,AxiomsIn,AxiomsOut) :-
1365 % print(checking_for_enumeration_axioms(Set)),nl,
1366 % first case: A partion predicate is present with
1367 % all elements of the set as its arguments
1368 % ( e.g. partition(S,{a},{b},...) )
1369
1370 % create a pattern for the partition:
1371 get_texpr_id(Set,SetId),get_texpr_id(SetRef,SetId),
1372 create_texpr(partition(SetRef,Singletons),pred,_,Partition),
1373 % remove the partition from the axioms
1374 % print(looking_for_partition(SetId,Partition)),nl,nl,
1375 select(Partition,AxiomsIn,AxiomsOut1),
1376 %%print(found_partition(SetID,Partition)),nl,
1377 % check if all arguments are singletons and get the
1378 % singleton elements
1379 all_singletons(Singletons,PartitionElements,AxiomsOut1,AxiomsOut2,Recursive),
1380 (Recursive==true
1381 -> AxiomsOut=AxiomsIn /* then we still need the partition axioms */
1382 ; AxiomsOut=AxiomsOut2).
1383 %% ,print(all_singletons(Singletons)),nl.
1384 %% print(singletons(PartitionElements)),nl,
1385 % check if all arguments and the identifiers
1386 % of the set are the same
1387 % same_elements(Elements,PartitionElements).
1388
1389
1390 % all elements of a list are singletons, the second argument
1391 % returns the list of elements without the set around it
1392 all_singletons([],[],Ax,Ax,_).
1393 all_singletons([Set|SRest],[Expr|ERest],AxiomsIn,AxiomsOut,Recursive) :-
1394 get_texpr_expr(Set,set_extension([Expr])),!,
1395 all_singletons(SRest,ERest,AxiomsIn,AxiomsOut,Recursive).
1396 all_singletons([ID1|SRest],Result,AxiomsIn,AxiomsOut,Recursive) :-
1397 ID1 = b(identifier(_ID),set(global(_)),_Info),
1398 Recursive=true,
1399 % print(trying_to_look_for_recursive_partition(_ID)),nl, %%
1400 has_enumeration_axioms(ID1,PartitionElements,AxiomsIn,AxiomsOut1),
1401 % print(recursive_partition(ID,PartitionElements)),nl,
1402 append(PartitionElements,ERest,Result),
1403 all_singletons(SRest,ERest,AxiomsOut1,AxiomsOut,_).
1404
1405 % the two lists of typed identifiers have the same identifiers
1406 %same_elements(ElemsA,ElemsB) :-
1407 % get_texpr_ids(ElemsA,IdsA),sort(IdsA,A),
1408 % get_texpr_ids(ElemsB,IdsB),sort(IdsB,B),
1409 % A=B.
1410
1411 typeset_enumerated([],_Type,[]).
1412 typeset_enumerated([Elem|Erest],Type,[TElem|Trest]) :-
1413 create_texpr(identifier(Id),global(Type),Infos,Elem),
1414 create_texpr(identifier(Id),global(Type),[enumerated_set_element|Infos],TElem),
1415 typeset_enumerated(Erest,Type,Trest).
1416
1417 remove_constants([],Cst,Cst).
1418 remove_constants([TId|Erest],In,Out) :-
1419 get_texpr_id(TId,Id),
1420 get_texpr_id(Pattern,Id),
1421 select(Pattern,In,Env),
1422 remove_constants(Erest,Env,Out).
1423
1424 % find an equality Set = {id1,...,idk}
1425 select_equal_extension_set_of_ids(Set,In,Out,Ext,Elements) :-
1426 get_texpr_id(Set,SetId),
1427 get_texpr_id(Expr,SetId),
1428 create_texpr(set_extension(Elements),_,_,Ext),
1429 create_texpr(Equal,_,_,TEqual),
1430 ( Equal = equal(Expr,Ext); Equal = equal(Ext,Expr) ),
1431 select(TEqual,In,Out),!.
1432
1433 generate_unequals(Elements,Unequals) :-
1434 get_texpr_ids(Elements,Ids),
1435 findall(unequal(A,B),two_ids(Ids,A,B),Unequals).
1436 two_ids([A|Rest],A,B) :- member(B,Rest).
1437 two_ids([_|Rest],A,B) :- two_ids(Rest,A,B).
1438
1439 all_unequals_present([],Axioms,Axioms).
1440 all_unequals_present([unequal(A,B)|Rest],InAxioms,OutAxioms) :-
1441 remove_unequalities(InAxioms,A,B,IntAxioms,0,N), N>0,!, % at least one occurrence
1442 all_unequals_present(Rest,IntAxioms,OutAxioms).
1443
1444 remove_unequalities([],_,_,[],N,N).
1445 remove_unequalities([TAxiom|T],A,B,Rest,NrRemoved,R) :-
1446 get_texpr_id(AExpr,A), get_texpr_id(BExpr,B),
1447 get_texpr_expr(TAxiom,Axiom),
1448 is_unequality(Axiom,AExpr,BExpr),!, N1 is NrRemoved+1,
1449 remove_unequalities(T,A,B,Rest,N1,R).
1450 remove_unequalities([Axiom|T],A,B,[Axiom|TR],N,R) :- % not an unequality between A and B
1451 remove_unequalities(T,A,B,TR,N,R).
1452
1453 is_unequality(not_equal(A,B),A,B) :- !.
1454 is_unequality(not_equal(B,A),A,B) :- !.
1455 is_unequality(negation(TEqual),A,B) :-
1456 get_texpr_expr(TEqual,Equal),
1457 is_direct_equality(Equal,A,B).
1458 is_direct_equality(equal(A,B),A,B) :- !.
1459 is_direct_equality(equal(B,A),A,B) :- !.
1460
1461 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1462 % creating a type environment with information about theories inside
1463
1464 check_theory_extensions(Infos,Freetypes,Ops,TheoryEnv) :-
1465 findall( T, (member(T,Infos),is_eventb_additional_info(T)), Theories),
1466 default_theory_ops(InitialEnv),
1467 foldl(check_theory,Theories,FreetypesL,OpsL,InitialEnv,TheoryEnv),
1468 append(FreetypesL,Freetypes),
1469 append(OpsL,Ops).
1470 is_eventb_additional_info(Term) :-
1471 nonvar(Term),functor(Term,theory,Arity),
1472 memberchk(Arity,[3,4,5,7]).
1473 default_theory_ops(Env) :-
1474 env_empty(Empty),
1475 cond_operator(Id,Op),
1476 env_store_operator(Id,Op,Empty,Env).
1477 cond_operator('COND',bmachine_eventb:axiomatic_definition('COND',Params,DirectDef,[PT])) :-
1478 PT = '__IFTHENELSETYPE',
1479 TypeExpr = identifier(none,PT),
1480 Params = [argument('THEN',TypeExpr),
1481 argument('ELSE',TypeExpr),
1482 argument('IF',set_extension(none,[truth(none)]))],
1483 DirectDef = if_then_else(none,identifier(none,'IF'),
1484 identifier(none,'THEN'),identifier(none,'ELSE')).
1485 check_theory(Theory,Freetypes,Ops,Env,OutEnv) :-
1486 get_theory_name(Theory,Proj,Name),
1487 debug_format(19,'Checking theory ~w:~w~n',[Proj,Name]),
1488 (check_theory2(Theory,Env,_DefSets,Freetypes,Ops) -> true
1489 ; add_internal_error('Theory check failed:',Theory),fail),
1490 store_operator_list(Ops,Env,OutEnv),
1491 check_theory_axioms(Theory,OutEnv,_).
1492
1493 store_operator_list(Ops,Env,OutEnv) :-
1494 keys_and_values(Ops,Ids,Operators),
1495 foldl(env_store_operator,Ids,Operators,Env,OutEnv).
1496
1497 check_theory2(theory(PT,Datatypes,OP),Env,DefSets,Freetypes,Ops) :-
1498 % just to be backward-compatible to a version without axiomatic definitions
1499 check_theory2(theory(PT,Datatypes,OP,[]),Env,DefSets,Freetypes,Ops).
1500 check_theory2(theory(PT,Datatypes,OP,AxDefs),Env,DefSets,Freetypes,Ops) :-
1501 % just to be backward-compatible to a version without operator mapping
1502 % definitions
1503 check_theory2(theory(PT,Datatypes,OP,AxDefs,[]),Env,DefSets,Freetypes,Ops).
1504 check_theory2(theory(PT,Datatypes,OP,AxDefs,Mappings),Env,DefSets,Freetypes,Ops) :-
1505 check_theory2(theory(unknown,unknown,PT,Datatypes,OP,AxDefs,Mappings),Env,DefSets,Freetypes,Ops).
1506 check_theory2(theory(TheoryId,_Imported,TypeParameters,Datatypes,OP,AxDefs,Mappings),Env,DefSets,Freetypes,AllOps) :-
1507 %print_theory_axioms(TheoryId,TypeParameters,AxDefs),
1508 extract_freetypes(TheoryId,Env,Datatypes,Freetypes,FreetypeOps),
1509 (Mappings \= [_|_]
1510 -> generate_default_mappings(AxDefs,TheoryId,ML)
1511 ; debug_format(19,'Mappings in .ptm file: ~w~n',[Mappings]),
1512 ML=Mappings), % some older .eventb files seem to have none here, e.g., Theory/SumProduct_m1_mch.eventb
1513 debug_println(9,operator_mappings(ML)),
1514 findall(VirtualDefSet,unmapped_axiomatic_def_set(VirtualDefSet,AxDefs,ML),DefSets),
1515 maplist(store_virtual_deferred_set(TheoryId,TypeParameters),DefSets,DefSetOps),
1516 foldl(handle_mappings(TheoryId,TypeParameters),ML,MappedOpsL,OP/AxDefs,OP1/AxDefs1),
1517 append(MappedOpsL,MappedOps),
1518 maplist(store_operator(TheoryId,TypeParameters),OP1,DefinedOps),
1519 maplist(store_axiomatic_operator(TheoryId,TypeParameters),AxDefs1,AxOpsL),
1520 append(AxOpsL,AxOps),
1521 append([DefSetOps,FreetypeOps,MappedOps,DefinedOps,AxOps],AllOps1),
1522 % The operators are used for call-backs, a module prefix is mandatory
1523 maplist(prefix_with_module,AllOps1,AllOps).
1524
1525 unmapped_axiomatic_def_set(VirtualDefSet,AxDefs,ML) :-
1526 member(axiomatic_def_block(_AxDefId,AxTypes,_,_),AxDefs),
1527 member(VirtualDefSet,AxTypes), nonmember(tag(VirtualDefSet,_),ML).
1528
1529 % axiomatic blocks can contain new types; these seem to be just deferred sets (cf R0-MovingTrains_mch.eventb)
1530 store_virtual_deferred_set(TheoryId,TypeParameters,DefSet,Res) :- Parameters=[],RawWDCond=truth(none),
1531 ((DefSet='Real' ; DefSet='REAL') % in case no .ptm file exists, e.g., for Abrial's Real theory
1532 -> DirectDef=real_set(none),
1533 add_message(bmachine_eventb,'Translating axiomatic type to REAL: ',DefSet)
1534 ; DirectDef=string_set(none),
1535 add_message(bmachine_eventb,'Translating axiomatic type to STRING: ',DefSet)
1536 ), % TODO: translate to propert def. set!
1537 store_operator(TheoryId,TypeParameters,operator(DefSet,Parameters,RawWDCond,[DirectDef],[]),Res).
1538
1539 prefix_with_module(Id-Op,Id-(bmachine_eventb:Op)).
1540
1541 :- public print_theory_axioms/3.
1542 print_theory_axioms(TheoryId,TypeParameters,AxDefs) :- member(axiomatic_def_block(Id,Types,_OpDefsIn,Axioms),AxDefs),
1543 format('~nAxDef Block ~w (~w) in theory ~w (~w)~n',[Id,Types,TheoryId,TypeParameters]),
1544 translate:l_print_raw_bexpr(Axioms),
1545 fail.
1546 print_theory_axioms(_,_,_).
1547
1548
1549 check_theory_axioms(theory(TheoryId,_Imported,TypeParameters,_Datatypes,_OP,AxDefs,_Mappings),Env,TheoryAxioms) :-
1550 fail, % disabled; for tests 2295, 2379, 2382 there are unsupported axiomatic operators in the axioms
1551 maplist(create_deferred_set,TypeParameters,RawIds),
1552 create_sets(RawIds,TheoryId,Sets),
1553 add_unique_variables(Sets,Env,Env2),
1554 member(axiomatic_def_block(AxDefId,_Types,_OpDefsIn,RawAxioms),AxDefs),
1555 get_theory_name(TheoryId,Proj,Name), format('Typechecking block ~w in ~w:~w~n',[AxDefId,Proj,Name]),
1556 typecheck_l(RawAxioms,Env2,pred,TheoryAxioms,theory_axioms),
1557 translate:l_print_bexpr_or_subst(TheoryAxioms),nl,
1558 fail.
1559 check_theory_axioms(_,_Env,[]).
1560
1561 create_deferred_set(Atom,deferred_set(unknown,Atom)).
1562
1563 get_theory_name(theory_name(Project,TheoryName),ResP,ResN) :- !,
1564 ResP=Project, ResN=TheoryName.
1565 get_theory_name(Theory,ResP,ResN) :-
1566 functor(Theory,theory,_), arg(1,Theory,TN),!,
1567 get_theory_name(TN,ResP,ResN).
1568 get_theory_name(N,'','') :- format('Could not extract theory name: ~w~n',[N]).
1569
1570 store_operator(TheoryId,TypeParameters,operator(Id,Parameters,RawWDCond,DirectDef,RecursiveDef),Id-Op) :-
1571 store_operator2(TheoryId,TypeParameters,Id,DirectDef,RecursiveDef,Parameters,RawWDCond,TypeParameters,Op).
1572
1573 store_operator2(_,_,_,_,RecursiveDef,Parameters,_WD,TypeParameters,Op) :-
1574 RecursiveDef=[_|_],!,
1575 Op=recursive_operator(Parameters,RecursiveDef,TypeParameters).
1576 store_operator2(TheoryId,_,Id,[Def],_,Parameters,Raw_WDCond,TypeParameters,Op) :- !,
1577 %format('Storing direct definition operator ~w with WD: ~w~n',[Id,Raw_WDCond]),
1578 store_operator_definition(TheoryId,Id,Parameters,Def,Raw_WDCond,TypeParameters,direct_definition), % store for bvisual2
1579 Op=direct_definition(Parameters,Raw_WDCond,Def,TypeParameters).
1580 store_operator2(TheoryId,TypeParas,_Id,_,Parameters,_,_WD,_,Op) :-
1581 get_theory_name(TheoryId,Project,Theory),
1582 Op = unsupported_operator(Project,Theory,TypeParas,Parameters,
1583 'Only operators with direct or recursive definition are currently supported').
1584
1585 :- dynamic stored_operator_direct_definition/8.
1586 % store definition for bvisual2, ...; not used in typechecker or interpreter
1587 store_operator_definition(TheoryId,Id,Parameters,Def,Raw_WDCond,TypeParameters,Kind) :-
1588 get_theory_name(TheoryId,Proj,Theory),
1589 assertz(stored_operator_direct_definition(Id,Proj,Theory,Parameters,Def,Raw_WDCond,TypeParameters,Kind)).
1590
1591 reset_stored_defs :- retractall(stored_operator_direct_definition(_,_,_,_,_,_,_,_)),
1592 retractall(some_operator_uses_reals).
1593
1594 stored_operator(Id,Kind) :-
1595 stored_operator_direct_definition(Id,_,_,_,_,_,_,Kind).
1596
1597 :- dynamic some_operator_uses_reals/0.
1598 check_if_operator_expr_uses_reals(Raw) :-
1599 \+some_operator_uses_reals,
1600 raw_term_uses_reals(Raw),
1601 !,
1602 assert(some_operator_uses_reals). % this may be important for type checking later
1603 check_if_operator_expr_uses_reals(_).
1604
1605 raw_term_uses_reals(real_set(_)).
1606 raw_term_uses_reals(float_set(_)).
1607 raw_term_uses_reals(real(_,_)).
1608 raw_term_uses_reals(external_pred_call_auto(_,ExtFun,_)) :- ext_fun_uses_reals(ExtFun).
1609 raw_term_uses_reals(external_function_call_auto(_,ExtFun,_)) :- ext_fun_uses_reals(ExtFun).
1610 % TODO: detect more and detect nested usage
1611 :- use_module(external_functions, [external_fun_type/3]).
1612 ext_fun_uses_reals(ExtFun) :- external_fun_type(ExtFun,_,Types), member(R,Types),R==real.
1613
1614 :- use_module(eventhandling,[register_event_listener/3]).
1615 :- register_event_listener(clear_specification,reset_stored_defs,
1616 'Reset stored Event-B operators.').
1617
1618 % extract inductive data types as freetypes
1619 extract_freetypes(TheoryId,ParamEnv,DataTypes,Freetypes,FreetypeOps) :-
1620 maplist(extract_freetype(TheoryId,DataTypes,ParamEnv),DataTypes,Freetypes,FreetypeOpsL),
1621 append(FreetypeOpsL,FreetypeOps).
1622 extract_freetype(TheoryId,AllDataTypes,Env,
1623 datatype(Id,TypeParams,Constructors),
1624 freetype(FreetypeId,Cases),
1625 [Id-freetype_operator(FreetypeId,Types,TypeParams,Usage)|CaseOps]) :-
1626 debug_format(19,'Converting data type ~w with type parameters ~w to freetype~n',[Id,TypeParams]),
1627 foldl(add_datatype_to_env,AllDataTypes,Env,Env1),
1628 foldl(add_type_parameter,TypeParams,Types,Env1,ParamEnv),
1629 create_freetype_typeid(Id,Types,FreetypeId),
1630 Type = freetype(FreetypeId),
1631 extract_used_type_parameters(Constructors,TypeParams,Usage),
1632 %store_eventb_operator(Id,freetype_operator_as_identifier(Id),ParamEnv,ParamEnv2), % now done in add_datatype_to_env
1633 WD=truth(none),
1634 maplist(get_raw_id,TypeParams,TypeParaIds),
1635 store_operator_definition(TheoryId,Id,TypeParaIds,identifier(none,'Datatype'),WD,TypeParaIds,datatype_definition), % store for bvisual2
1636 maplist(extract_case(TheoryId,ParamEnv,Type,Types),Constructors,Cases,CaseOpsL),
1637 append(CaseOpsL,CaseOps).
1638 get_raw_id(identifier(_,ID),R) :- !, R=ID.
1639 get_raw_id(I,I).
1640
1641 add_datatype_to_env(datatype(Id,Params,_ConstructorList),In,Out) :-
1642 length(Params,NumberOfParams),
1643 functor(FreetypeId,Id,NumberOfParams),
1644 debug_format(19,'Generating freetype ~w/~w for inductive datatype from Rodin theory~n',[Id,NumberOfParams]),
1645 env_store(Id,set(freetype(FreetypeId)),[],In,In2),
1646 store_eventb_operator(Id,freetype_operator_as_identifier(Id),In2,Out).
1647
1648 add_type_parameter(TypeParam,Type,In,Out) :-
1649 extract_id(TypeParam,ParameterId),
1650 debug_format(19,'Generating paramater type ~w for Rodin theory~n',[ParameterId]),
1651 env_store(ParameterId,set(Type),[],In,Out).
1652 extract_id(identifier(_,Id),Id).
1653 % constructor without parameters
1654 extract_case(_TheoryId,_ParamEnv,freetype(TypeId),_Types, constructor(Id,[]),
1655 case(Id,constant([Id])),Ops) :- !,
1656 Ops=[Id-constructor_operator(TypeId,[])].
1657 % constructor with parameters
1658 extract_case(TheoryId,ParamEnv,Freetype,ParamTypes,constructor(Id,Destructors),
1659 case(Id,Type),
1660 [Id-constructor_operator(FreetypeId,Types)|DestructOps]) :-
1661 maplist(extract_destructor(TheoryId,ParamEnv,Freetype,ParamTypes,Id,Type),
1662 Destructors,Projections,TypesAndOps),
1663 maplist(split_type_and_op,TypesAndOps,Types,DestructOps),
1664 Freetype=freetype(FreetypeId),
1665 debug_format(19,'Generated constructor ~w ~w for freetype ~w~n',[Id,Types, FreetypeId]),
1666 combine_typelist_with_prj(Types,Type,Projections).
1667 extract_destructor(TheoryId,Env,freetype(FreetypeId),ParamTypes,Case,CType,
1668 destructor(Name,RawTypeExpr),Projection,Type-Name-Op) :-
1669 typecheck_with_freevars(RawTypeExpr,Env,ParamTypes,set(Type),_,destructor(FreetypeId)),
1670 Op = destructor_operator(Name,FreetypeId,Projection,Case,CType),
1671 debug_format(19,'Generated destructor ~w (type ~w) for case ~w of freetype ~w~n', [Name,Type, Case, FreetypeId]),
1672
1673 WD = truth(none),
1674 functor(FreetypeId,FF,_),
1675 ajoin(['Destructor for ', FF],InfoID),
1676 store_operator_definition(TheoryId,Name,[argument(Case,CType)],identifier(none,InfoID),WD,ParamTypes,
1677 destructor(FreetypeId,Type)).
1678
1679 split_type_and_op(Type-Name-Op,Type,Name-Op).
1680
1681
1682 :- assert_must_succeed(( combine_typelist_with_prj([a,b],T,P),
1683 T == couple(a,b), P == [[prj1],[prj2]] )).
1684 :- assert_must_succeed(( combine_typelist_with_prj([a,b,c],T,P),
1685 T == couple(a,couple(b,c)),
1686 P == [[prj1],[prj2,prj1],[prj2,prj2]] )).
1687 :- assert_must_succeed(( combine_typelist_with_prj([a,b,c,d],T,P),
1688 T == couple(couple(a,b),couple(c,d)),
1689 P == [[prj1,prj1],[prj1,prj2],[prj2,prj1],[prj2,prj2]] )).
1690 combine_typelist_with_prj([T],R,Projections) :- !,R=T,Projections=[[]].
1691 combine_typelist_with_prj(Types,couple(TypeL,TypeR),Projections) :-
1692 split_list_in_middle(Types,TypesLeft,TypesRight),
1693 same_length(TypesLeft,PrjLeft),same_length(TypesRight,PrjRight),
1694 append(PrjLeft,PrjRight,Projections),
1695 maplist(cons(prj1),PrjLeft1,PrjLeft),
1696 maplist(cons(prj2),PrjRight1,PrjRight),
1697 combine_typelist_with_prj(TypesLeft,TypeL,PrjLeft1),
1698 combine_typelist_with_prj(TypesRight,TypeR,PrjRight1).
1699 split_list_in_middle(List,Left,Right) :-
1700 length(List,N),
1701 Half is floor(N / 2),
1702 append_length(Left,Right,List,Half).
1703
1704 combine_exprlist_to_couple([T],R) :- !,T=R.
1705 combine_exprlist_to_couple(Exprs,R) :-
1706 split_list_in_middle(Exprs,ExprsLeft,ExprsRight),
1707 combine_exprlist_to_couple(ExprsLeft,TL),
1708 combine_exprlist_to_couple(ExprsRight,TR),
1709 get_texpr_types([TL,TR],[TypeL,TypeR]),
1710 create_texpr(couple(TL,TR),couple(TypeL,TypeR),[],R).
1711
1712 combine_exprlist_to_cprod([T],R) :- !,T=R.
1713 combine_exprlist_to_cprod(Exprs,R) :-
1714 split_list_in_middle(Exprs,ExprsLeft,ExprsRight),
1715 combine_exprlist_to_cprod(ExprsLeft,TL),
1716 combine_exprlist_to_cprod(ExprsRight,TR),
1717 get_texpr_types([TL,TR],[set(TypeL),set(TypeR)]),
1718 create_texpr(cartesian_product(TL,TR),set(couple(TypeL,TypeR)),[],R).
1719
1720 extract_used_type_parameters(Constructors,TypeParams,Usages) :-
1721 maplist(extract_id,TypeParams,TypeParamIds),
1722 convlist(used_type_parameters_of_constructor(TypeParamIds),Constructors,Usages).
1723 used_type_parameters_of_constructor(TypeParamIds,constructor(Id,Destructors),
1724 used_param_types(Id,UsedParamTypes,DestructorExprs)) :-
1725 maplist(destructor_expr,Destructors,DestructorExprs),
1726 maplist(used_type_parameters_of_destructor(TypeParamIds),
1727 DestructorExprs,UsedParamTypeL),
1728 UsedParamTypeL = [_|_], % store the information only for constructors that actually use
1729 % type parameters
1730 ord_union(UsedParamTypeL,UsedParamTypes).
1731 used_type_parameters_of_destructor(TypeParamIds,TypeExpr,UsedTypes) :-
1732 extract_raw_identifiers(TypeExpr,UsedIds),
1733 findall( N, (nth1(N,TypeParamIds,T),memberchk(T,UsedIds)), UsedTypes1),
1734 sort(UsedTypes1,UsedTypes).
1735 destructor_expr(destructor(_,Expr),Expr).
1736 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1737 % callback predicates for operators
1738
1739 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1740
1741 :- public unsupported_operator/13.
1742 % called by btypechecker:lookup_eventb_operator
1743 unsupported_operator(Project,Theory,_TypeParas,Params,_Msg,OpName,Args,Pos,_Env,ExPr,Result,TRin,TRout) :-
1744 match_args_and_params(Args,Params,NewArgs),
1745 get_typed_default_operator(OpName,NewArgs,ExPr,NewOpName,Result),!,
1746 add_default_operator_warning(OpName,NewOpName,Theory,Project,Pos),
1747 TRin=TRout.
1748 unsupported_operator(_,_,_,_Parameters,Msg,Id,_Args,Pos,_Env,ExPr,Result,TRin,TRout) :-
1749 %format('Unsupported ~w~n args:~w',[Id,_Args]),
1750 store_typecheck_error(Msg,Pos,TRin,TRout),
1751 failure_syntax_element(ExPr,Id,F,Type), % just to make sure that the result
1752 create_texpr(F,Type,[],Result). % is nonvar, to prevent later errors
1753 failure_syntax_element(expr,Id,identifier(Id),_).
1754 failure_syntax_element(pred,_Id,falsity,pred).
1755
1756 % in contrast to the default mappings handled earlier,
1757 % this code as access to the actual arguments and their types
1758 % and is called once for each use of the operator
1759 get_typed_default_operator(Op,[A,B],ExPr,NewOp,Result) :-
1760 get_texpr_type(A,TA), get_texpr_type(B,TB),
1761 (nonvar(TA) ; nonvar(TB)),
1762 binary_typed_operator_to_ast(Op,TA,TB,ExPr,NewOp,NewType),
1763 ResExpr =.. [NewOp,A,B],
1764 create_texpr(ResExpr,NewType,[],Result).
1765
1766
1767 binary_typed_operator_to_ast(Op,T,T,expr,NewOp,T) :- binary_expr_op(Op,T,NewOp).
1768 %binary_typed_operator_to_ast(Op,T,T,pred,NewOp,pred) :- binary_pred_op(Op,T,NewOp).
1769
1770 binary_expr_op(pow,integer,power_of).
1771 binary_expr_op(pow,real,power_of_real).
1772 binary_expr_op(power_of,integer,power_of).
1773 binary_expr_op(power_of,real,power_of_real).
1774 binary_expr_op(div,integer,floored_div).
1775 binary_expr_op(div,real,div_real).
1776
1777 %binary_pred_op('less',real,less_real).
1778
1779
1780 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1781
1782 :- use_module(probsrc(bsyntaxtree),[safe_create_texpr/4, is_truth/1,
1783 add_texpr_infos_if_new/3, conjunct_predicates_with_pos_info/3]).
1784 :- use_module(probsrc(bsyntaxtree_quantifiers),[create_z_let/6]).
1785
1786 % get params and type parameters from operator callback registered in the typechecker environment
1787 % for use by btypechecker:lookup_eventb_operator
1788 % it would be a bit cleaner to store infos separately from callback or get rid of the call back completely
1789 get_operator_arity_from_callback(direct_definition(Params,_WD,_DirectDef,_PT),direct_definition,Arity) :-
1790 length(Params,Arity).
1791 get_operator_arity_from_callback(axiomatic_definition(_TagName,Params,_DirectDef,_PT),axiomatic_definition,Arity) :-
1792 length(Params,Arity).
1793 get_operator_arity_from_callback(recursive_operator(Params,_Cases,_PT),recursive_operator,Arity) :-
1794 length(Params,Arity).
1795 get_operator_arity_from_callback(freetype_operator(_FId1,Types1,_PT,_Usage1),freetype_operator,Arity) :-
1796 length(Types1,Arity).
1797 get_operator_arity_from_callback(freetype_operator_as_identifier(_RecId),freetype_operator_as_identifier,0).
1798 get_operator_arity_from_callback(freetype_operator_as_function(_RecId,_RType),freetype_operator_as_function,1).
1799 get_operator_arity_from_callback(freetype_operator_as_set(_RecId),freetype_operator_as_function,0).
1800 get_operator_arity_from_callback(constructor_operator(_FId,_TP),constructor_operator,0).
1801 get_operator_arity_from_callback(destructor_operator(_Name,_FId,_Projections,_Case,_CType1),destructor_operator,1).
1802 get_operator_arity_from_callback(make_inductive_natural(_ArgId,_ZeroOp,_SuccOp),make_inductive_natural,1).
1803 get_operator_arity_from_callback(unsupported_operator(_Project,_Theory,_TP,Paras,_Msg),unsupported_operator,Len) :-
1804 length(Paras,Len).
1805
1806 %%%%%%%%%%%%%%%%%%
1807
1808 % Theory plug-in: direct definitions
1809 :- public direct_definition/12.
1810 % called by btypechecker:lookup_eventb_operator
1811 direct_definition(Params, % e.g. [argument(a,bool_set(none))]
1812 RawWD, % Raw AST of WD condition (currently only implicit WDs from body; not yet user-defined ones)
1813 DirectDef, % Raw AST of DirectDefinition Body, e.g., convert_bool(none,negation(none,equal(none,identifier(none,a),boolean_true(none))))
1814 PT,
1815 OpId, TArgs, Pos,
1816 Env, % environment of operators
1817 ExPr,Result,TRin,TRout) :-
1818 (Params,DirectDef) = (NewParams,NewDirectDefBody), %gen_fresh_params(Params,DirectDef,NewParams,NewDirectDefBody),
1819 apply_direct_definition(OpId,TArgs,NewParams,
1820 NewDirectDefBody,RawWD,
1821 PT,Env,Pos,TLetIds,TLetValues,
1822 TDef,InferredType,TWDPred,
1823 TRin,TRout),
1824 NewInfos = [nodeid(Pos),was(extended_expr(OpId))],
1825 (is_truth(TWDPred) -> add_texpr_infos_if_new(TDef,NewInfos,LetBody)
1826 ; get_preference(find_abort_values,false) -> LetBody=TDef % currently tests 1201, 2232 would fail
1827 % TODO: should we disable the inclusion of the WD condition for older .eventb files?
1828 ; InferredType=pred
1829 -> ajoin(['Well-definedness error for predicate operator ',OpId],MsgStr),
1830 TMsg = b(string(MsgStr),string,[]),
1831 safe_create_texpr(convert_bool(TWDPred),boolean,[nodeid(Pos)],WDBool), % we require an expression argument
1832 safe_create_texpr(external_pred_call('ASSERT_TRUE',[WDBool,TMsg]),pred,NewInfos,TAssert),
1833 conjunct_predicates_with_pos_info(TAssert,TDef,LetBody)
1834 ; ajoin(['Well-definedness error for expression operator ',OpId],MsgStr),
1835 safe_create_texpr(assertion_expression(TWDPred,MsgStr,TDef),InferredType,NewInfos,LetBody)
1836 ),
1837 %write(op(OpId,InferredType)),nl, translate:print_bexpr(LetBody),nl,
1838 create_z_let(ExPr,TLetIds,TLetValues,LetBody,NewInfos,Result).
1839
1840
1841 :- public axiomatic_definition/12.
1842 % just a "dummy" interface predicate for better pretty-printing of operators in translate_eventb_operator
1843 axiomatic_definition(_TagName, Params, DirectDef, PT,
1844 Id, TArgs, Pos, Env, ExPr,Result,TRin,TRout) :-
1845 direct_definition(Params, truth(none), DirectDef, PT, Id, TArgs, Pos, Env, ExPr,Result,TRin,TRout).
1846
1847 % Example: ddef([argument(R,pow_subset(none,identifier(none,T)))],seq(none,identifier(none,R)),[T],seq)
1848
1849 % this code not needed as we now systematically rename in create_z_let
1850 %:- use_module(input_syntax_tree,[raw_replace/3]).
1851 %gen_fresh_params(Params,DirectDef,NewParams,NewDirectDefBody) :-
1852 % maplist(alpha_rename,Params,NewParams,RenameList), %print(replaces(RenameList)),nl,
1853 % raw_replace(DirectDef,RenameList,NewDirectDefBody).
1854 %:- use_module(gensym,[gensym/2]).
1855 %alpha_rename(argument(OldID,Type),argument(FreshID,Type),replace(OldID,identifier(none,FreshID))) :-
1856 % gensym(OldID,FreshID).
1857
1858 % Args are the arguments of the operator where it is used
1859 % Params are the parameters in the operator definition
1860 apply_direct_definition(OpId,TArgs,Params,DirectDef,RawWD,PT,Env,_Pos,
1861 TLetIds,TLetValues,TDef,Type,TWDPred,TRin,TRout) :-
1862 match_args_and_params(TArgs,Params,NewTArgs),!, %TArgs are the concrete arguments in the operator call
1863 create_typed_ids(PT,ParametricTypes,TPT),
1864 add_identifiers_to_environment(TPT,Env,SubEnv),
1865 % type check the arguments given in the operator usage
1866 get_texpr_types(NewTArgs,ArgTypes),
1867 typecheck_arguments(Params,SubEnv,ArgTypes,TParams,TRin,TR2),
1868 % type check the direct definition of the operator. To do this we need the parameters of the operators
1869 % in the type environment. Their type is determined by the arguments of the operator call.
1870 add_identifiers_to_environment(TParams,SubEnv,DefEnv),
1871 btype(apply_direct_definition,DirectDef,DefEnv,Type,TDef,TR2,TR3),
1872 debug_format(9,'Inferred type of direct definition ~w application: ~w~n',[OpId,Type]),
1873 append(TParams,TPT,TLetIds),
1874 maplist(create_typeset,ParametricTypes,TypeValues),
1875 append(NewTArgs,TypeValues,TLetValues),
1876 btype(apply_direct_definition,RawWD,DefEnv,_PredType,TWDPred,TR3,TRout). % now type check WD predicate
1877 apply_direct_definition(OpId,TArgs,Arguments,_DirectDef,_WD,_PT,_Env,Pos,
1878 _TParams,_,_TDef,_,_TWD,TRin,TRout) :-
1879 length(TArgs,Len1),
1880 length(Arguments,Len2),
1881 write(targs(TArgs)),nl,
1882 write(args(Arguments)),nl,
1883 ajoin(['Wrong number of arguments (',Len1,') for call to operator ',OpId,
1884 ', expected ',Len2],Msg),
1885 store_typecheck_error(Msg,Pos,TRin,TRout).
1886
1887
1888 match_args_and_params(TArgs,Params,NewTArgs) :-
1889 same_length(TArgs,Params),!, NewTArgs=TArgs.
1890 match_args_and_params([TArg],Params,NewTArgs) :- % can happen when calling operator in REPL using maplets
1891 nested_couple_to_list(TArg,NewTArgs),
1892 same_length(NewTArgs,Params).
1893
1894 split_arg_and_typedef(argument(Id,TypeExpr),Id,TypeExpr).
1895 map_to_set_type(Type,set(Type)).
1896 typecheck_arguments(Params,Env,ArgTypes,TParams,TRin,TRout) :-
1897 % type check the parameters' type expressions of the operator definition, they should have the same type
1898 % as the arguments (except being a set)
1899 % E.g. an operator "o" has one argument "arg" and type expression "T**BOOL" (with T being a parameter type of the theory),
1900 % then for "o(5|->TRUE)" we have "couple(integer,boolean)" as the argument's type,
1901 % we add "T" to the type environment (with type set(_)),
1902 % then we type check the parameter expression "T**BOOL", expecting the type set(coule(integer,boolean)),
1903 % the type check results in T being of type set(integer).
1904 maplist(split_arg_and_typedef,Params,ParamIds,ParamTypeExprs),
1905 same_length(Params,ArgTypes),
1906 maplist(map_to_set_type,ArgTypes,SetArgTypes),
1907 btype_l(ParamTypeExprs,Env,SetArgTypes,_TParamTypeExprs,TRin,TRout),
1908 create_typed_ids(ParamIds,ArgTypes,TParams).
1909 create_typeset(Type,TExpr) :- create_texpr(typeset,Type,[],TExpr).
1910
1911
1912
1913 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1914 % Theory plug-in: Recursive operators
1915 :- public recursive_operator/11.
1916 % called by btypechecker:lookup_eventb_operator
1917 recursive_operator(Arguments,Cases,PT,
1918 Id,TArgs,_Pos,Env,ExPr,Result,TRin,TRout) :-
1919 % parameter types
1920 create_typed_ids(PT,ParametricTypes,TPT),
1921 add_identifiers_to_environment(TPT,Env,Env1),
1922 maplist(create_typeset,ParametricTypes,LetValues), % needed for the LET
1923 typecheck_arguments(Arguments,Env1,ArgTypes,TParamIds,TRin,TR1),
1924 % TArgs: A,B,Cf
1925 % TArg: A|->B|->C
1926 get_texpr_types(TArgs,ArgTypes),
1927 create_couple(TArgs,TArg),
1928 length(TArgs,NumberOfArgs),OpInfo = [theory_operator(Id,NumberOfArgs)],
1929 unique_id("opresult.",ResultId),create_typed_id(ResultId,Type,TResultId),
1930 % TODO: infer ExPr if variable from extended_formula
1931 ( ExPr=expr -> % Result: Comp(x|->y|->z)
1932 % we need to append a result parameter in the comprehension set
1933 create_texpr(function(TCompSet,TArg),Type,OpInfo,InnerResult),
1934 append(TParamIds,[TResultId],CompSetIds),append(ArgTypes,[Type],CompSetTypes),
1935 % make sure that we do not run into an infinite loop
1936 store_eventb_operator(Id,freetype_operator_as_function(RecId,Type),Env1,Env2)
1937 ; ExPr=pred -> % Result: x|->y|->z : Comp
1938 create_texpr(member(TArg,TCompSet),pred,OpInfo,InnerResult),
1939 CompSetIds = TParamIds,ArgTypes=CompSetTypes,
1940 % make sure that we do not run into an infinite loop
1941 store_eventb_operator(Id,freetype_operator_as_set(RecId),Env1,Env2)
1942 ),
1943 couplise_list(CompSetTypes,CompSetType),
1944 % Comp: {i,r| Cond}
1945 create_recursive_compset(CompSetIds,Cond,set(CompSetType),[],RecId,TCompSet),
1946 % Params: a,b,c
1947 % i = a|->b|->c
1948 add_identifiers_to_environment(TParamIds,Env2,Subenv),
1949 foldl(recursive_operator_case(Subenv,TResultId),Cases,TCases,TR1,TRout),
1950 conjunct_predicates(TCases,Cond),
1951 create_z_let(ExPr,TPT,LetValues,InnerResult,OpInfo,Result).
1952
1953
1954 recursive_operator_case(Env,TResultId,case(ParamId,_,Expression,Formula),Cond,TRin,TRout) :-
1955 % Add free identifiers of case to environment
1956 extract_free_identifiers(Expression,TFreeIdentifiers,Env,Subenv),
1957 % IsCase => CaseCheck
1958 create_texpr(implication(IsCase,TCaseCheck),pred,[],Cond),
1959 % IsCase: ParamId = constructor(x,y,z)
1960 typecheck_parameter(ParamId,Env,TParamId),
1961 recop_create_is_case(Expression,Subenv,IsCase,TParamId,FT,Case,TRin,TR1),
1962 % CaseCheck: #x,y,z | Destruction & Predicate
1963 recop_create_in_case(Formula,TParamId,TResultId,Subenv,TFreeIdentifiers,FT,Case,TCaseCheck,TR1,TRout).
1964 extract_free_identifiers(typeof(_Pos,ExtExpr,_TypeExpr),TIds,In,Out) :-
1965 extract_free_identifiers(ExtExpr,TIds,In,Out).
1966 extract_free_identifiers(extended_expr(_Pos,_Case,Exprs,Preds),TIds,In,Out) :-
1967 append(Exprs,Preds,Ids),
1968 maplist(extract_free_identifier,Ids,TIds),
1969 add_identifiers_to_environment(TIds,In,Out).
1970 extract_free_identifier(identifier(_Pos,Id),TId) :-
1971 create_typed_id(Id,_,TId).
1972 typecheck_parameter(ParamId,Env,TParamId) :-
1973 env_lookup_type(ParamId,Env,ParamType),
1974 create_typed_id(ParamId,ParamType,TParamId).
1975 %env_store_type(Id,Type,In,Out) :-
1976 % % Version without Info field
1977 % env_store(Id,Type,[],In,Out).
1978 recop_create_is_case(typeof(_,Expr,_TypeExpr),Env,IsCase,TParamId,FT,Case,TRin,TRout) :-
1979 recop_create_is_case(Expr,Env,IsCase,TParamId,FT,Case,TRin,TRout).
1980 recop_create_is_case(Expression,Env,IsCase,TParamId,FT,Case,TRin,TRout) :-
1981 Expression = extended_expr(_,Case,_,_),
1982 get_texpr_type(TParamId,freetype(FT)),
1983 btype(recop_create_is_case,Expression,Env,freetype(FT),_TCons,TRin,TRout),
1984 create_texpr(freetype_case(FT,Case,TParamId),pred,[],IsCase).
1985 recop_create_in_case(Formula,TParamId,TResultId,Subenv,TFreeIdentifiers,FT,Case,Cond,TRin,TRout) :-
1986 % Predicate
1987 btype(recop_create_in_case,Formula,Subenv,Type,TFormula,TRin,TRout),
1988 ( Type=pred -> Predicate = TFormula
1989 ;
1990 get_texpr_types([TResultId,TFormula],[TypeA,TypeB]),
1991 unify_types_strict(TypeA,TypeB),
1992 create_texpr(equal(TResultId,TFormula),pred,[],Predicate)),
1993 % Destruction: x->y|->z = destructor(ParamId)
1994 ( TFreeIdentifiers = [] ->
1995 Cond = Predicate
1996 ; TFreeIdentifiers = [_|_] ->
1997 get_texpr_types(TFreeIdentifiers,FTypes),
1998 combine_typelist_with_prj(FTypes,FType,Projections),
1999 unique_id("destructed",DId),create_typed_id(DId,FType,TDId),
2000 create_texpr(freetype_destructor(FT,Case,TParamId),FType,[],Destructor),
2001 maplist(create_inner_let(TDId),Projections,TLetExpressions),
2002 create_z_let(pred,TFreeIdentifiers,TLetExpressions,Predicate,[],InnerLets),
2003 create_z_let(pred,[TDId], [Destructor], InnerLets,[],Cond)
2004 ).
2005
2006 create_inner_let(TOrig,Projections,TExpr) :-
2007 apply_projections(Projections,TOrig,TExpr).
2008
2009 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2010 % Theory plug-in: datatype sets
2011 :- public freetype_operator/12.
2012 % called by btypechecker:lookup_eventb_operator
2013 freetype_operator(FreetypeId1,Types1,TypeParams1,Usage1,
2014 Id,TArgs,_Pos,Env,_ExPr,Result,TR,TR) :-
2015 % make a fresh copy to prevent that several instances of the freetype propagate
2016 % their types to each other (resulting in spurious typing errors)
2017 copy_term(freetype(FreetypeId1,Types1,TypeParams1,Usage1),
2018 freetype(FreetypeId, Types, TypeParams, Usage)),
2019 maplist(map_to_set_type,Types,SetTypes),
2020 get_texpr_types(TArgs,SetTypes),
2021 create_freetype_compset(TArgs,Id,FreetypeId,TypeParams,Usage,Env,Result).
2022 create_freetype_compset(TArgs,SetId,FreetypeId,TypeParams,Usage,Env,Result) :-
2023 find_constructors_with_complex_types(TArgs,Usage,Constructors),
2024 ( Constructors = [] ->
2025 create_texpr(freetype_set(FreetypeId),set(freetype(FreetypeId)),[],Result)
2026 ;
2027 create_freetype_compset2(TArgs,SetId,Constructors,FreetypeId,TypeParams,Env,Result)).
2028 create_freetype_compset2(TArgs,SetId,Constructors,FreetypeId,TypeParams,Env,Result) :-
2029 btypechecker:add_ext_variables(TypeParams,Env,TParams,Subenv,TRin,TRout),
2030 get_texpr_types(TParams,Types),get_texpr_types(TArgs,Types),
2031 Type=freetype(FreetypeId),
2032 create_texpr(identifier(freetype_element),Type,[],TId),
2033 do_prettyprint_freetype(FreetypeId,TArgs,PP),
2034 create_recursive_compset([TId],Let,set(Type),[freetype(PP)],RecId,Result),
2035 store_eventb_operator(SetId,freetype_operator_as_identifier(RecId),Subenv,Subenv2),
2036 foldl(create_cons_check(FreetypeId,Subenv2,TId),Constructors,Checks,TRin,TRout),
2037 conjunct_predicates(Checks,Cond),
2038 create_z_let(pred,TParams,TArgs,Cond,[],Let).
2039 create_cons_check(FreetypeId,Env,TId,cons(Case,Exprs),Check,TRin,TRout) :-
2040 btype_l(Exprs,Env,_Types,TExprs,TRin,TRout),
2041 combine_exprlist_to_cprod(TExprs,Set),
2042 get_texpr_type(Set,set(Type)),
2043 create_texpr(freetype_case(FreetypeId,Case,TId),pred,[],CheckCase),
2044 create_texpr(freetype_destructor(FreetypeId,Case,TId),Type,[],Value),
2045 create_texpr(member(Value,Set),pred,[],Membercheck),
2046 create_texpr(implication(CheckCase,Membercheck),pred,[],Check).
2047 % this is used to pretty-print the resulting comprehension set
2048 do_prettyprint_freetype(Id,Params,R) :-
2049 maplist(translate_bexpression,Params,Strs),
2050 ajoin_with_sep(Strs,',',S),
2051 functor(Id,I,_),
2052 ajoin([I,'(',S,')'],R).
2053
2054 find_constructors_with_complex_types(TArgs,Usage,Constructors) :-
2055 find_complex_type_params(TArgs,ComplexTP),
2056 findall(cons(Id,DestructorExprs),
2057 ( member(used_param_types(Id,UsedParamTypes,DestructorExprs),Usage),
2058 ord_intersect(UsedParamTypes,ComplexTP)),
2059 Constructors).
2060 % returns the indeces of the type arguments that are not only types
2061 find_complex_type_params(TArgs,ComplexTP) :-
2062 findall(N,(nth1(N,TArgs,TArg),\+ is_just_type(TArg)),ComplexTP1),
2063 sort(ComplexTP1,ComplexTP).
2064
2065 :- public freetype_operator_as_identifier/9.
2066 freetype_operator_as_identifier(RecId,Id,TArgs,_Pos,_Env,_ExPr,Result,TR,TR) :-
2067 get_texpr_types(TArgs,SetTypes),
2068 maplist(map_to_set_type,Types,SetTypes),
2069 create_freetype_typeid(Id,Types,FreetypeId),
2070 create_recursion_ref(RecId,set(freetype(FreetypeId)),Result).
2071
2072 :- public freetype_operator_as_function/10.
2073 freetype_operator_as_function(RecId,RType,_Id,TArgs,_Pos,_Env,_ExPr,Result,TR,TR) :-
2074 create_couple(TArgs,TArg), get_texpr_type(TArg,Type),
2075 create_recursion_ref(RecId,set(couple(Type,RType)),TFunction),
2076 create_texpr(function(TFunction,TArg),RType,[],Result).
2077
2078 :- public freetype_operator_as_set/9.
2079 freetype_operator_as_set(RecId,_Id,TArgs,_Pos,_Env,_ExPr,Result,TR,TR) :-
2080 create_couple(TArgs,TArg), get_texpr_type(TArg,Type),
2081 create_recursion_ref(RecId,set(Type),TSet),
2082 create_texpr(member(TArg,TSet),pred,[],Result).
2083
2084 create_recursion_ref(RecId,Type,TId) :-
2085 create_texpr(identifier(RecId),Type,[for_recursion],TId).
2086
2087 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2088 % Theory plug-in: datatype constructors
2089 :- public constructor_operator/10. % TO DO: ensure by another mechanism that Spider detects that this is called
2090 % called by btypechecker:lookup_eventb_operator
2091 constructor_operator(FreetypeId1,[],Id,[],_Pos,_Env,_ExPr,Result,TRin,TRout) :-
2092 !, copy_term(FreetypeId1,FreetypeId),
2093 create_texpr(value(freeval(FreetypeId,Id,term(Id))),
2094 freetype(FreetypeId),[],Result),
2095 TRin = TRout.
2096 constructor_operator(FreetypeId1,ParamTypes1,
2097 Id,TArgs,_Pos,_Env,_ExPr,Result,TR,TR) :-
2098 copy_term(constructor(FreetypeId1,ParamTypes1),constructor(FreetypeId,ParamTypes)),
2099 get_texpr_types(TArgs,ParamTypes),
2100 combine_exprlist_to_couple(TArgs,TArg),
2101 %format('Generated freetype constructor call ~w for Rodin theory datatype ~w~n',[Id,FreetypeId]),
2102 create_texpr(freetype_constructor(FreetypeId,Id,TArg),freetype(FreetypeId),[],Result).
2103
2104 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2105 % Theory plug-in: datatype destructors
2106 :- public destructor_operator/13. % TO DO: ensure by another mechanism that Spider detects that this is called
2107 % called by btypechecker:lookup_eventb_operator
2108 destructor_operator(OpName,FreetypeId1,Projections,Case,CType1,
2109 _Id,[TArg],_Pos,_Env,_ExPr,Result,TR,TR) :-
2110 copy_term(destructor(FreetypeId1,CType1),destructor(FreetypeId,CType)),
2111 get_texpr_type(TArg,freetype(FreetypeId)),
2112 debug_format(19,'Generated freetype destructor ~w call ~w for Rodin theory datatype ~w~n',[OpName,Case,FreetypeId]),
2113 create_texpr(freetype_destructor(FreetypeId,Case,TArg),CType,[],Destructed),
2114 apply_projections(Projections,Destructed,Result0),
2115 add_texpr_infos(Result0,[was(extended_expr(OpName))],Result).
2116
2117 % create an projection expression (or a combination of arbitrary many) to
2118 % access a part of a couple. The input is a list of prj1/prj2 atoms,
2119 % e.g. [prj1,prj1,prj2]: Take the first of the first of the second element.
2120 apply_projections(Projections,Expr,Result) :-
2121 reverse(Projections,Prjs),
2122 apply_projections1(Prjs,Expr,Result).
2123 apply_projections1([],Expr,Expr).
2124 apply_projections1([P|Rest],Expr,Result) :-
2125 get_texpr_type(Inner,couple(A,B)),
2126 apply_projections2(P,A,B,Result,Inner),
2127 apply_projections1(Rest,Expr,Inner).
2128 apply_projections2(prj1,A,_B,Result,Inner) :-
2129 create_texpr(first_of_pair(Inner),A,[],Result).
2130 apply_projections2(prj2,_A,B,Result,Inner) :-
2131 create_texpr(second_of_pair(Inner),B,[],Result).
2132
2133 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2134 % Theory plug-in: axiomatic definitions of operators
2135 store_axiomatic_operator(Id,TypeParas,axiomatic_def_block(_Id,_Types,OpDefs,_Axioms),Ops) :-
2136 % in case we do not recognize the operator, we store an error message
2137 % that is shown as soon the operator is used somewhere
2138 get_theory_name(Id,Project,Theory), % extract project and theory name
2139 maplist(store_axdef_error(Project,Theory,TypeParas),OpDefs,Ops).
2140 store_axdef_error(Project,Theory,TypeParas,
2141 opdef(Id,Arguments,_WD),Id-unsupported_operator(Project,Theory,TypeParas,Arguments,Msg)) :-
2142 % The opdef information from the Rodin export is missing the result type
2143 % TODO fix this so that we could still typecheck and delay the error message until the operator is used
2144 length(Arguments,Len), %write(opdef(Id,Arguments)),nl,
2145 ajoin(['Axiomatic defined operator \"',Id,'\" of arity ', Len,' not recognized. Be sure to add a ',
2146 Theory,'.ptm file to your Theory project ',
2147 Project],Msg).
2148
2149 % generate default mappings for axiomatic operators in case no .ptm file is provided and the args match
2150 is_axiomatic_def(Id,Arguments,axiomatic_def_block(_Id,_Types,OpDefs,_Axioms)) :-
2151 member(opdef(Id,Arguments,_WD),OpDefs).
2152 is_axiomatic_def(Id,[],axiomatic_def_block(_Id,Types,_OpDefs,_Axioms)) :-
2153 member(Id,Types).
2154
2155 generate_default_mappings(AxDefs,TheoryId,DefMappings) :-
2156 findall(tag(OpName,NewOpName), (member(Block,AxDefs),
2157 is_axiomatic_def(OpName,Args,Block),
2158 default_operator(OpName,NewOpName,TheoryId,Args)), DefMappings).
2159
2160 default_operator(OpName,NewOpName,TheoryId,A) :-
2161 get_theory_name(TheoryId,Project,Theory),
2162 get_default_operator(OpName,NewOpName,A,Theory),
2163 add_default_operator_warning(OpName,NewOpName,Theory,Project,unknown).
2164 get_default_operator('\x211D\','REAL',Args,_) :- !,
2165 Args=[]. % Real unicode symbol, in .ptm file the Prolog internal name cannot use unicode
2166 get_default_operator('SUM','SIGMA',[argument(_,ArgT)],_) :- !,
2167 relation_to_integer_type(ArgT). % from StandardLibrary SUMandPRODUCT
2168 get_default_operator('PRODUCT','PI',[argument(_,ArgT)],_) :- !, relation_to_integer_type(ArgT).
2169 get_default_operator(cls,closure1,[argument(_,ArgT)],'closure') :- !,
2170 % from Standard Library theory "closure"; but it uses a direct_definition and this rewriting does not trigger!
2171 binary_relation_type(ArgT).
2172 get_default_operator(Name,NewName,[_,_],_) :- binary_external_function(Name,NewName),!.
2173 get_default_operator(Name,NewName,[_,_],_) :- binary_external_predicate(Name,NewName),!.
2174 get_default_operator(Name,Name,Args,_) :- default_operator_aux(Name,Args).
2175
2176 add_default_operator_warning(OpName,NewOpName,Theory,Project,Pos) :-
2177 ajoin(['operator "',OpName,'" internal {',NewOpName,'}'],Decl),
2178 (get_preference(auto_detect_theory_ops,true)
2179 -> MW = 'message'
2180 ; MW = 'warning set AUTO_DETECT_THEORY_MAPPING to TRUE or'
2181 ),
2182 ajoin(['Automatically translating axiomatic operator ',OpName,
2183 '; to get rid of this ', MW, ' add a ',
2184 Theory,'.ptm file to your project ',
2185 Project, ' with this line: '],Msg),
2186 (get_preference(auto_detect_theory_ops,true)
2187 -> add_message(bmachine_eventb,Msg,Decl,Pos)
2188 ; add_warning(bmachine_eventb,Msg,Decl,Pos)
2189 ).
2190
2191 default_operator_aux(choose,Args) :- !, Args = [argument(_,pow_subset(_,_))].
2192 default_operator_aux(mu,Args) :- !, Args=[argument(_,pow_subset(_,_))].
2193 default_operator_aux(closure,[argument(_,ArgT)]) :- !,
2194 binary_relation_type(ArgT).
2195 default_operator_aux(closure1,[argument(_,ArgT)]) :- !,
2196 binary_relation_type(ArgT).
2197 default_operator_aux(OpName,[]) :- constant_operator_raw_term(OpName,_).
2198 default_operator_aux(OpName,[A1]) :- unary_operator_raw_term(OpName,A1,_).
2199 default_operator_aux(OpName,[A1,A2]) :-
2200 binary_operator_raw_term(OpName,A1,A2,_,_),
2201 \+ binary_expr_op(OpName,_,_). % we have typed default rules; delay decision until typing info is available
2202
2203
2204 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2205 % Theory plug-in: Tagged operators that can be replaced by internal constructs
2206 handle_mappings(TheoryId,PT,tag(Opname,Tag),Ops,OPin/AxDefsin,OPout/AxDefsOut) :- !,
2207 ( extract_operator(Opname,Operator,OPin/AxDefsin,OPout/AxDefsOut,Kind) ->
2208 (Tag=[_|_] -> debug_format(19,"Mapping Theory Operator ~s -> ~w~n",[Tag,Opname])
2209 ; debug_format(19,"Mapping Theory Operator ~w -> ~w~n",[Tag,Opname])),
2210 (store_operator_by_tag(Tag,Opname,Operator,TheoryId,PT,Ops,Kind)
2211 -> true
2212 ;
2213 ajoin(['Error mapping theory operator ',Opname,
2214 ' to ProB tag (the *.ptm file maybe incorrect or you need a newer version of ProB):'],Msg),
2215 add_error(bmachine_eventb,Msg,Tag))
2216 ;
2217 ajoin(['ProB theory mapping: operator ',Opname,' not found, mapping to ',Tag,' ignored.'],Msg),
2218 add_warning(bmachine_eventb,Msg),
2219 OPin/AxDefsin=OPout/AxDefsOut,Ops=[]
2220 ).
2221 handle_mappings(_TheoryID,_ParamTypes,Mapping,[],X,X) :-
2222 functor(Mapping,Functor,Arity),
2223 ajoin(['ProB theory mapping: unexpected entry of type ',Functor,'/',Arity,', entry ignored.'],Msg),
2224 add_error(bmachine_eventb,Msg).
2225
2226 extract_operator(Opname,Operator,OPin/AxDefs,OPout/AxDefs,Kind) :-
2227 % a regular non-axiomatic operator (direct definition or recursive definition):
2228 Operator = operator(Opname,_Parameters,_WD,DirectDef,_RecursiveDef),
2229 selectchk(Operator,OPin,OPout),!,
2230 % TODO: we could try and infer/store type of operator from Definition and check against axiomatic one
2231 (DirectDef=[] -> Kind='RECURSIVE-DEF-OVERRIDE' ; Kind = 'DIRECT-DEF-OVERRIDE'),
2232 debug_format(19,'Overriding non-axiomatic operator ~w with new definition from .ptm file~n',[Opname]).
2233 extract_operator(Opname,Operator,OP/AxDefsIn,OP/AxDefsOut,'AXIOMATIC-DEF') :-
2234 Operator = axdef(Opname,Parameters,WD,block(Id,Types,Axioms)), % block/3 does not seem to be used
2235 select(axiomatic_def_block(Id,Types,OpDefsIn,Axioms),AxDefsIn,
2236 axiomatic_def_block(Id,Types,OpDefsOut,Axioms),AxDefsOut),
2237 select(opdef(Opname,Parameters,WD),OpDefsIn,OpDefsOut),!.
2238 extract_operator(Opname,Operator,OP/AxDefsIn,OP/AxDefsOut,'AXIOMATIC-TYPE') :-
2239 % we treat a type of an axiomatic definition also as a potential operator that can be mapped
2240 Operator = axdef(Opname,[],WD,block(Id,TypesOut,Axioms)), WD=[],
2241 select(axiomatic_def_block(Id,TypesIn,OpDefs,Axioms),AxDefsIn,
2242 axiomatic_def_block(Id,TypesOut,OpDefs,Axioms),AxDefsOut),
2243 select(Opname,TypesIn,TypesOut),!.
2244
2245 % two versions are supported: The older one expects an atom Tag, the new one a string
2246 % The string version is then parsed as a Prolog term.
2247 % as of 2023 we also support the bexpr(RawExpr) tag generated from $Expr$ in the .ptm file
2248 store_operator_by_tag(Tag,Opname,Operator,TheoryID,PT,Ops,Kind) :-
2249 is_list(Tag),!, % A string
2250 append(Tag,".",Tag1), % read_from_codes/2 needs a full-stop at the end
2251 read_from_codes(Tag1,Term),
2252 store_operator_by_tag(Term,Opname,Operator,TheoryID,PT,Ops,Kind).
2253 store_operator_by_tag(Tag,Opname,Operator,TheoryID,PT,Ops,Kind) :-
2254 store_operator_by_tag1(Tag,Opname,Operator,PT,Ops),
2255 get_operator_parameters(Operator,Parameters),
2256 pretty_print_tag(Tag,PrettyTag),
2257 store_operator_definition(TheoryID,Opname,Parameters,
2258 function(none,identifier(none,Kind),[identifier(none,PrettyTag)]),truth(none),[],
2259 axiomatic). % for bvisual2: todo pass type params PT
2260
2261 :- use_module(translate,[translate_raw_bexpr_with_limit/3]).
2262 pretty_print_tag(bexpr(Raw),TS) :- translate_raw_bexpr_with_limit(Raw,100,TS),!. % TODO: unicode
2263 pretty_print_tag(Tag,Tag).
2264
2265 store_operator_by_tag1(Tag,Opname,Operator,PT,Ops) :-
2266 debug_format(19,'Storing tag ~w for operator ~w~n',[Tag,Opname]),
2267 % SIGMA or PI
2268 aggregation_operator(Tag,Functor),!,
2269 get_operator_parameters(Operator,Parameters),
2270 ( Parameters = [Arg] ->
2271 create_raw_aggregation_op(Functor,Arg,ClassicalBOp),
2272 Ops=[Opname-axiomatic_definition(Tag,[Arg],ClassicalBOp,PT)]
2273 ;
2274 parameter_error(Parameters,1,Opname),Ops=[]
2275 ).
2276 store_operator_by_tag1(mkinat,OpName,Operator,PT,Ops) :- !,
2277 store_operator_by_tag1(mkinat(iZero,iSucc),OpName,Operator,PT,Ops).
2278 store_operator_by_tag1(mkinat(ZeroOp,SuccOp),OpName,Operator,_PT,Ops) :- !,
2279 get_operator_parameters(Operator,Parameters),
2280 ( Parameters = [argument(Arg,_ArgType)] ->
2281 Ops=[OpName-make_inductive_natural(Arg,ZeroOp,SuccOp)]
2282 ;
2283 parameter_error(Parameters,1,OpName),Ops=[]
2284 ).
2285 store_operator_by_tag1(BOperator,Opname,Operator,PT,Ops) :-
2286 unary_operator_raw_term(BOperator,Arg1,Expr), !,
2287 check_if_operator_expr_uses_reals(Expr),
2288 get_operator_parameters(Operator,Parameters),
2289 ( Parameters = [argument(Arg1,_ArgType)] ->
2290 Ops=[Opname-axiomatic_definition(BOperator,Parameters,Expr,PT)]
2291 ; Parameters = [] -> % The Rodin theory operator is a constant without arguments
2292 Arg1='OpArg1',
2293 CArgs = [identifier(none,Arg1)],
2294 % try and generate lambda if we have an expression and relation for predicate
2295 % we assume they are all expressions:
2296 CurryExpr = lambda(none,CArgs,truth(none),Expr),
2297 % TODO: use ArgType1 in CurryExpr
2298 add_message(bmachine_eventb,'Lifting ProB unary operator to lambda expression (Rodin theory operator has no arguments): ',BOperator),
2299 Ops=[Opname-axiomatic_definition(BOperator,Parameters,CurryExpr,PT)]
2300 ;
2301 parameter_error(Parameters,1,Opname),Ops=[]
2302 ).
2303 store_operator_by_tag1(BOperator,Opname,Operator,PT,Ops) :-
2304 binary_operator_raw_term(BOperator,Arg1,Arg2,Expr,Kind), !,
2305 check_if_operator_expr_uses_reals(Expr),
2306 get_operator_parameters(Operator,Parameters),
2307 ( Parameters = [argument(Arg1,_ArgType1), argument(Arg2,_ArgType2)] ->
2308 Ops=[Opname-axiomatic_definition(BOperator,Parameters,Expr,PT)]
2309 ; Parameters = [] -> % The Rodin theory operator is a constant without arguments
2310 Arg1='OpArg1', Arg2='OpArg2',
2311 CArgs = [identifier(none,Arg1),identifier(none,Arg2)],
2312 % try and generate lambda if we have an expression and relation for predicate
2313 (Kind=expression
2314 -> CurryExpr = lambda(none,CArgs,truth(none),Expr)
2315 ; CurryExpr = comprehension_set(none,CArgs,Expr)
2316 ),
2317 % TODO: use ArgType1/2 in CurryExpr
2318 add_message(bmachine_eventb,'Lifting ProB binary operator to lambda expression (Rodin theory operator has no arguments): ',BOperator),
2319 Ops=[Opname-axiomatic_definition(BOperator,Parameters,CurryExpr,PT)]
2320 ;
2321 parameter_error(Parameters,2,Opname),Ops=[]
2322 ).
2323 store_operator_by_tag1(BOperator,Opname,Operator,PT,Ops) :-
2324 constant_operator_raw_term(BOperator,Expr), !,
2325 check_if_operator_expr_uses_reals(Expr),
2326 get_operator_parameters(Operator,Parameters),
2327 map_over_raw_expr(Expr,detect_external_fun_calls,RewrittenExpr),
2328 length(Parameters,NrParas),
2329 %format('Mapping operator ~w (~w paras: ~w) to: ',[Opname,NrParas,Parameters]), translate:print_raw_bexpr(RewrittenExpr),nl,
2330 ( Parameters = [] ->
2331 Ops=[Opname-axiomatic_definition(BOperator,Parameters,RewrittenExpr,PT)]
2332 ; can_be_predicate(RewrittenExpr,NrParas),
2333 maplist(argument_to_raw_id,Parameters,ParIds),
2334 couplise_raw_list(ParIds,ParCouple) ->
2335 % the operator is a predicate operator, in the .ptm file is a set comprehension defining it
2336 MembershipTest = member(none,ParCouple,RewrittenExpr),
2337 debug_println(19,created_membership_for_predicate_operator_call(Opname)),
2338 Ops=[Opname-axiomatic_definition(BOperator,Parameters,MembershipTest,PT)]
2339 ; % Create function application for set comprehensions / lambdas as parameters expected in Rodin
2340 can_be_function(RewrittenExpr,NrParas),
2341 maplist(argument_to_raw_id,Parameters,ParIds),
2342 couplise_raw_list(ParIds,ParCouple) ->
2343 Fapp = function(none,RewrittenExpr,ParCouple),
2344 debug_println(19,created_function_application_for_operator_call(Opname)),
2345 Ops=[Opname-axiomatic_definition(BOperator,Parameters,Fapp,PT)]
2346 ; %unreachable at the moment:
2347 parameter_error(Parameters,0,Opname),Ops=[]
2348 ).
2349
2350 argument_to_raw_id(argument(Arg,_),identifier(none,Arg)).
2351
2352 % TODO: maybe store/lookup type of operator and check if it is a predicate operator
2353 can_be_predicate(comprehension_set(_,Paras,_),NrParas) :-
2354 length(Paras,NrParas).
2355 can_be_predicate(symbolic_comprehension_set(Pos,Paras,B),NrParas) :-
2356 can_be_predicate(comprehension_set(Pos,Paras,B),NrParas).
2357 can_be_predicate(event_b_comprehension_set(Pos,Paras,B,_E),NrParas) :-
2358 can_be_predicate(comprehension_set(Pos,Paras,B),NrParas).
2359 can_be_predicate(symbolic_event_b_comprehension_set(Pos,Paras,B,E),NrParas) :-
2360 can_be_predicate(event_b_comprehension_set(Pos,Paras,B,E),NrParas).
2361
2362
2363 % TODO: check if NrParas compatible
2364 can_be_function(comprehension_set(_,_,_),_NrParas) :- !.
2365 can_be_function(lambda(_,_,_,_),_) :- !.
2366 can_be_function(symbolic_comprehension_set(_,_,_),_) :- !.
2367 can_be_function(event_b_comprehension_set(_,_,_),_NrParas) :- !.
2368 can_be_function(symbolic_event_b_comprehension_set(_,_,_,_),_) :- !.
2369 can_be_function(sequence_extension(_,_),_) :- !.
2370 can_be_function(E,_) :- functor(E,F,N), add_message(bmachine_eventb,'Attempting function application for:',F/N).
2371
2372 couplise_raw_list([Arg],Res) :- !, Res=Arg.
2373 couplise_raw_list([A,B],Res) :- !, Res=couple(none,A,B).
2374 couplise_raw_list([A,B|Rest],Result) :-
2375 couplise_raw_list([couple(A,B)|Rest],Result).
2376
2377
2378 :- use_module(external_functions, [get_external_function_type/3]).
2379 % traverse raw AST to detect calls to external functions which would not be visible in regular typechecking
2380 % these expressions come from the .ptm files where we want to be able to have access to external functions
2381 % TODO: also allow access to external predicates and external constants like REULER
2382 detect_external_fun_calls(function(Pos,TID,Args),external_function_call_auto(Pos,ID,NewArgs)) :-
2383 TID = identifier(_IdPos,ID),
2384 get_external_function_type(ID,ExpectedArgTypes,_OutputType), % TODO: check visible
2385 length(Args,Len),
2386 length(ExpectedArgTypes,ExtExpectedLen),
2387 (Len=ExtExpectedLen -> true
2388 ; parameter_error(Args,ExtExpectedLen,ID),fail),
2389 !,
2390 debug_println(19,detected_external_function_call(ID,Len)),
2391 map_over_args(Args,NewArgs). % we need to inspect tree of arguments as well, map_over_raw_expr works top-down
2392
2393 map_over_args([],[]).
2394 map_over_args([Arg1|T],[NewArg1|NT]) :- map_over_raw_expr(Arg1,detect_external_fun_calls,NewArg1),
2395 map_over_args(T,NT).
2396
2397
2398 % TO DO ternary operator ?? son/3 if_then_else
2399
2400 % construct a raw term with arguments for replacement in AST
2401 % first argument is functor name as it appears in the theory mapping file *.ptm
2402 binary_operator_raw_term(Functor,Arg1,Arg2,Term,Kind) :-
2403 binary_operator_to_ast(Functor,ASTFunctor,Kind), % TODO: return Kind
2404 Term =.. [ASTFunctor,none,identifier(none,Arg1),identifier(none,Arg2)].
2405 binary_operator_raw_term(Functor,Arg1,Arg2,Term,predicate) :-
2406 binary_external_predicate(Functor,ASTFunctor),
2407 Term = external_pred_call_auto(none, ASTFunctor, [identifier(none,Arg1),identifier(none,Arg2)]).
2408 binary_operator_raw_term(Functor,Arg1,Arg2,Term,expression) :-
2409 binary_external_function(Functor,ASTFunctor),
2410 Term = external_function_call_auto(none, ASTFunctor, [identifier(none,Arg1),identifier(none,Arg2)]).
2411
2412 binary_operator_to_ast(BOP,ASTFunctor,expression) :-
2413 binary_expr_operator_to_ast(BOP,ASTFunctor).
2414 binary_operator_to_ast(BOP,ASTFunctor,predicate) :-
2415 binary_pred_operator_to_ast(BOP,ASTFunctor).
2416 binary_expr_operator_to_ast('^',concat).
2417 binary_expr_operator_to_ast(concat,concat).
2418 %binary_expr_operator_to_ast(div,floored_div). % now dealt with in get_typed_default_operator
2419 binary_expr_operator_to_ast(restrict_front,restrict_front).
2420 binary_expr_operator_to_ast(restrict_tail,restrict_tail).
2421 % binary tree operators
2422 binary_expr_operator_to_ast(arity,arity).
2423 binary_expr_operator_to_ast(bin,bin).
2424 binary_expr_operator_to_ast(const,const).
2425 binary_expr_operator_to_ast(father,father).
2426 binary_expr_operator_to_ast(rank,rank).
2427 binary_expr_operator_to_ast(subtree,subtree).
2428 % real operators
2429 binary_expr_operator_to_ast(rdiv,div_real).
2430 binary_expr_operator_to_ast(plus,add_real).
2431 binary_expr_operator_to_ast(power_of_real,power_of_real).
2432 binary_expr_operator_to_ast(power_of,power_of). % also in get_typed_default_operator
2433 binary_expr_operator_to_ast(pow,power_of). % ditto
2434 binary_expr_operator_to_ast(minus,minus_real).
2435 binary_expr_operator_to_ast(mul,multiplication_real).
2436 binary_expr_operator_to_ast(mult,multiplication_real).
2437 % real predicates:
2438 binary_pred_operator_to_ast(less,less_real).
2439 binary_pred_operator_to_ast(less_equal,less_equal_real).
2440 binary_pred_operator_to_ast('smr',less_real). % from Rodin Real Theory v.2.1
2441 binary_pred_operator_to_ast(leq,less_equal_real). % from Rodin Real Theory v.2.1
2442 % Note: there is currently no greater_real and greater_equal_real
2443
2444 binary_external_predicate('\x22D7\','RGT'). % 8919 - greater with dot
2445 binary_external_predicate(greater,'RGT').
2446 binary_external_predicate(greater_equal,'RGEQ').
2447 binary_external_predicate('\x22D6\','RLT'). % 8918 - less with dot
2448 %binary_external_predicate(less,'RLT').
2449 %binary_external_predicate(less_equal,'RLEQ').
2450 binary_external_predicate(geq,'RGEQ').
2451 %binary_external_predicate(leq,'RLEQ'). % from Rodin Real Theory v.2.1
2452 %binary_external_predicate(smr,'RLT'). % ditto
2453 binary_external_predicate(gtr,'RGT'). % ditto
2454 binary_external_predicate(inv,'RINV'). % ditto
2455 binary_external_predicate(FUN,FUN) :-
2456 treat_as_external_pred(FUN).
2457
2458 treat_as_external_pred('REQ').
2459 treat_as_external_pred('RGT').
2460 treat_as_external_pred('RGEQ').
2461 treat_as_external_pred('RLT').
2462 treat_as_external_pred('RLEQ').
2463 treat_as_external_pred('RNEQ').
2464
2465 treat_as_external_pred('LESS'). % Prolog term order
2466 treat_as_external_pred('LEQ_SYM_BREAK').
2467 treat_as_external_pred('STRING_IS_INT').
2468 treat_as_external_pred('STRING_IS_NUMBER').
2469 treat_as_external_pred('STRING_IS_DECIMAL').
2470 treat_as_external_pred('STRING_IS_ALPHANUMERIC'). % TODO: provide more external predicates
2471
2472 binary_external_function('\x2295\','RADD'). % Unicode + with circle
2473 binary_external_function('\x2296\','RSUB').
2474 binary_external_function('\x2297\','RMUL'). % has a pre-defined Rodin meaning as direct product
2475 binary_external_function('\x2298\','RDIV').
2476 binary_external_function('\x2299\','RMUL'). % dot with circle
2477 binary_external_function(FUN,FUN) :- visible_external_function(FUN,2),
2478 \+ treat_as_external_pred(FUN).
2479
2480 :- use_module(tools,[arg_is_number/2]).
2481 % Already parsed B expression:
2482 constant_operator_raw_term(bexpr(Tree),Tree).
2483 % some types not available in Event-B:
2484 constant_operator_raw_term('FLOAT',float_set(none)).
2485 constant_operator_raw_term('REAL',real_set(none)).
2486 constant_operator_raw_term('\x211D\',real_set(none)). % unicode Real symbol 8477 in decimal
2487 constant_operator_raw_term('STRING',string_set(none)).
2488 % direct encodings:
2489 %constant_operator_raw_term('RONE',real(none,'1.0')).
2490 %constant_operator_raw_term('RZERO',real(none,'1.0')).
2491 constant_operator_raw_term(empty_string,string(none,'')).
2492 constant_operator_raw_term('EMPTY_STRING',string(none,'')).
2493 % some synonyms:
2494 constant_operator_raw_term(zero,T) :- T = real(none,'0.0'). %constant_operator_raw_term('RZERO',T).
2495 constant_operator_raw_term(one,T) :- T = real(none,'1.0'). %constant_operator_raw_term('RONE',T).
2496 constant_operator_raw_term(two,T) :- T=real(none,'2.0').
2497 constant_operator_raw_term(pi,T) :- constant_operator_raw_term('RPI',T).
2498 constant_operator_raw_term(euler,T) :- constant_operator_raw_term('REULER',T).
2499 constant_operator_raw_term(Name,external_function_call_auto(none,Name,[])) :-
2500 visible_external_function(Name,0).
2501 constant_operator_raw_term(Atom,T) :-
2502 arg_is_number(Atom,Number),
2503 (integer(Number) -> T=integer(none,Number)
2504 ; atom(Atom), % otherwise we would need to convert it to an atom for the AST
2505 T=real(none,Atom)).
2506 % This case shouldn't be needed anymore.
2507 % The theorymapping library now parses formulas ahead of time
2508 % and sends the parsed AST in a bexpr/1 term.
2509 constant_operator_raw_term(Atom,Tree) :-
2510 atom(Atom), atom_codes(Atom,Codes),
2511 %format('Tag string: ~s~n',[Codes]),
2512 get_formula_codes(Codes,FCodes),
2513 %format('Stripped delimiter: ~s~n',[FCodes]),
2514 parsercall:parse_formula(FCodes,Tree).
2515 % TODO: allow B formulas also for binary/unary operators
2516
2517 get_formula_codes([Del|T],Codes) :- delimiter(Del),!,skip_last(T,Codes,Del). % strip leading and trailing delimiter
2518 skip_last([H],[],Last) :- !, Last=H.
2519 skip_last([H|T],[H|ST],Last) :- skip_last(T,ST,Last).
2520
2521 %delimiter(0'").
2522 delimiter(36). % dollar $
2523 %delimiter(39). % simple quote
2524
2525
2526 :- use_module(external_function_declarations,[external_function_library/4]).
2527 visible_external_function(Name,Arity) :-
2528 external_function_library(Name,Arity,expression,Lib),
2529 visible_lib(Lib).
2530
2531 visible_lib('LibraryMath.def').
2532 visible_lib('LibraryRandom.def').
2533 visible_lib('LibraryReals.def').
2534 visible_lib('LibraryStrings.def').
2535 visible_lib('CHOOSE.def').
2536 visible_lib('SCCS.def').
2537 visible_lib('SORT.def').
2538 % visible_lib('LibrarySoftfloats.def'). % comment in to make Softfloats available for theory mapping
2539
2540
2541 % construct a raw term with argument for replacement in AST
2542 % first argument is functor name as it appears in the theory mapping file *.ptm
2543 unary_operator_raw_term(Functor,Arg,Term) :-
2544 unary_operator_to_ast(Functor,ASTFunctor),
2545 Term =.. [ASTFunctor,none,identifier(none,Arg)].
2546 unary_operator_raw_term(Functor,Arg,Term) :-
2547 unary_external_function(Functor,AstFunctor),
2548 Term = external_function_call_auto(none, AstFunctor, [identifier(none,Arg)]).
2549 unary_operator_to_ast(closure,reflexive_closure). % reflexive_closure corresponds to closure B operator !
2550 unary_operator_to_ast(closure1,closure).
2551 unary_operator_to_ast(conc,general_concat).
2552 unary_operator_to_ast(fnc,trans_function).
2553 unary_operator_to_ast(rel,trans_relation).
2554 unary_operator_to_ast(succ,successor). % also exist in Event-B
2555 unary_operator_to_ast(pred,predecessor). % also exist in Event-B
2556 unary_operator_to_ast(bool,convert_bool). % also exist in Event-B
2557 unary_operator_to_ast(id,identity). % exists in similar way in Event-B
2558 unary_operator_to_ast(union,general_union).
2559 unary_operator_to_ast(inter,general_intersection).
2560 % real operators
2561 unary_operator_to_ast(real,convert_real).
2562 unary_operator_to_ast(floor,convert_int_floor).
2563 unary_operator_to_ast(ceiling,convert_int_ceiling).
2564 unary_operator_to_ast(minus,unary_minus_real). % minus also maps to binary minus
2565 unary_operator_to_ast(max,max_real).
2566 unary_operator_to_ast(min,min_real).
2567 unary_operator_to_ast(F,F) :- unary_operator(F). % operators that have same name in B and AST
2568
2569
2570 unary_external_function(choose,'CHOOSE').
2571 unary_external_function(length,'STRING_LENGTH').
2572 unary_external_function(inv,'RINV').
2573 unary_external_function(Functor,Functor) :- visible_external_function(Functor,1).
2574
2575 % sequence operators
2576 unary_operator(seq).
2577 unary_operator(seq1).
2578 unary_operator(iseq).
2579 unary_operator(iseq1).
2580 unary_operator(perm).
2581 unary_operator(first).
2582 unary_operator(size).
2583 unary_operator(front).
2584 unary_operator(tail).
2585 unary_operator(rev).
2586 unary_operator(last).
2587 unary_operator(mu).
2588 % tree operators
2589 unary_operator(tree).
2590 unary_operator(btree).
2591 unary_operator(top).
2592 unary_operator(sons).
2593 unary_operator(bin).
2594 unary_operator(left).
2595 unary_operator(right).
2596 unary_operator(sizet).
2597 unary_operator(prefix).
2598 unary_operator(postfix).
2599 %unary_operator(infix). % not yet supported
2600 %unary_operator(mirror). % not yet supported
2601 % general operators
2602 unary_operator(min). % also exist in Event-B
2603 unary_operator(max). % also exist in Event-B
2604 unary_operator(domain).
2605 unary_operator(range).
2606 % z operators
2607 unary_operator(compaction).
2608 unary_operator(bag_items).
2609
2610 % in the SUMandPRODUCT theory provided on https://prob.hhu.de/w/index.php?title=Event-B_Theories
2611 % the SIGMA and PI operators work on relations TYPE <-> INTEGER
2612 % we actually create SIGMA(I,N).(I|->N:Arg | N) or PI
2613 % However, we now also support SIGMA and PI to work directly on integer sets
2614 aggregation_operator('SIGMA',general_sum).
2615 aggregation_operator('PI',general_product).
2616
2617 integer_set_type(pow_subset(_,integer_set(_))).
2618 relation_to_integer_type(pow_subset(_,cartesian_product(_,_,integer_set(_)))).
2619 binary_relation_type(pow_subset(_,cartesian_product(_,_A,_B))).
2620
2621
2622 create_raw_aggregation_op(Op,argument(Arg,ArgType),Result) :-
2623 integer_set_type(ArgType),!,
2624 % we have an operator acting directly on sets of integers
2625 % we translate it as SIGMA(N).(N:Arg|N)
2626 A = identifier(none,Arg), % User-given argument
2627 create_fresh_identifier('_agg_op1',[A],I1), % starting with _ ensures user cannot create such an id
2628 N = identifier(none,I1), % N is the integer to sum or multiply
2629 Pred = member(none,N,A), % I|->N : Arg
2630 Result =.. [Op,none,[N],Pred,N]. % SIGMA(I,N).(I|->N:Arg | N) (or PI)
2631 create_raw_aggregation_op(Op,argument(Arg,_ArgType),Result) :-
2632 % this construction will immediately wrap _agg_op1/2 inside Sigma or Pi, and thus _agg_op1/2 will not be visibile outside
2633 A = identifier(none,Arg), % User-given argument
2634 create_fresh_identifier('_agg_op1',[A],I1), % starting with _ ensures user cannot create such an id
2635 create_fresh_identifier('_agg_op2',[A],I2), % (in Camille at least)
2636 I = identifier(none,I1), % I is the (not used) index variable
2637 N = identifier(none,I2), % N is the integer to sum or multiply
2638 Pred = member(none,couple(none,I,N),A), % I|->N : Arg
2639 Result =.. [Op,none,[I,N],Pred,N]. % SIGMA(I,N).(I|->N:Arg | N) (or PI)
2640
2641 parameter_error(RodinParameters,ExpectedByProB,Opname) :-
2642 length(RodinParameters,N),
2643 ajoin(['ProB theory mapping: ProB translation expects ',ExpectedByProB,' parameter(s) for operator ',
2644 Opname,' but Rodin definition has ',N],Msg),
2645 add_error(bmachine_eventb,Msg).
2646
2647 get_operator_parameters(operator(_Opname,Parameters,_WD,_DirectDef,_RecursiveDef),Parameters).
2648 get_operator_parameters(axdef(_Opname,Parameters,_WD,_Block),Parameters).
2649
2650 store_eventb_operator(Id,Op,Ein,Eout) :-
2651 env_store_operator(Id,bmachine_eventb:Op,Ein,Eout).
2652
2653
2654 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2655 % Operator for constructing inductive natural numbers (mkinat in Rodin .ptm theory mapping file)
2656 :- public make_inductive_natural/11.
2657 % called by btypechecker:lookup_eventb_operator
2658 make_inductive_natural(ArgId,ZeroOp,SuccOp,
2659 Id,[TParam],_Pos,Env,expr,Result,TRin,TRout) :-
2660 unique_id("opresult.",ResultId),
2661 create_typed_id(ResultId,NatType,TResult),
2662 create_typed_id(ArgId,integer,TArgId),
2663 % prepare environment:
2664 add_identifiers_to_environment([TArgId,TResult],Env,Env1),
2665 % we create a recursive function by using a (as recursive annotated) comprehension
2666 % set. We can refer to the compset with RecId.
2667 create_recursive_compset([TArgId,TResult],Cond,set(couple(integer,NatType)),[],RecId,TCompSet),
2668 % used for recursive call:
2669 env_store(RecId,set(couple(integer,NatType)),[],Env1,SubEnv),
2670 % just type iZero to retrieve its type:
2671 IZero=extended_expr(none,ZeroOp,[],[]),
2672 btype(make_inductive_natural,IZero,SubEnv,NatType,_,TRin,TR1),
2673 % Arg=0 => Result=iZero
2674 RawCase1=implication(none,
2675 equal(none,identifier(none,ArgId),integer(none,0)),
2676 equal(none,identifier(none,ResultId),IZero)),
2677 btype(make_inductive_natural,RawCase1,SubEnv,pred,Case1,TR1,TR2),
2678 % Arg>0 => Result=iSucc( recursive_call(Arg-1) )
2679 RawCase2=implication(none,
2680 greater(none,identifier(none,ArgId),integer(none,0)),
2681 equal(none,identifier(none,ResultId),extended_expr(none,SuccOp,[Minus1],[]))),
2682 Minus1=function(none,identifier(none,RecId),minus(none,identifier(none,ArgId),integer(none,1))),
2683 btype(make_inductive_natural,RawCase2,SubEnv,pred,Case2,TR2,TRout),
2684 % {Arg,Result | Arg=0=>Result=iZero & Arg>0=>Result=iSucc( RC(Arg-1) )}
2685 conjunct_predicates([Case1,Case2],Cond),
2686 % {Arg,Result | Arg=0=>Result=iZero & Arg>0=>Result=iSucc( RC(Arg-1) )}(TParam)
2687 create_texpr(function(TCompSet,TParam),NatType,[theory_operator(Id,1)],Result).